├── USBASP.png ├── ISP_KANDA.jpg ├── GPS-final-1.jpg ├── GPS-final-2.jpg ├── GPS-prototype-ATMEGA.jpg ├── GPS-locator-SIM800L-ATMEGA328P-version.png ├── USBASP-10-pin-wiring-to-AVR-Atmega328-chip.png ├── GPS-locator-ATTINY2313-4313-SIM800L-version.png ├── compileattiny ├── compileattinyb ├── compileattiny.bat ├── compileattinyb.bat ├── compileatmega ├── compileatmegab ├── compileatmega.bat ├── compileatmegab.bat ├── main3.hex ├── main3b.hex ├── main.hex ├── mainb.hex ├── README.md ├── main3.c ├── main3b.c ├── main.c └── mainb.c /USBASP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcore1976/gpstracker/HEAD/USBASP.png -------------------------------------------------------------------------------- /ISP_KANDA.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcore1976/gpstracker/HEAD/ISP_KANDA.jpg -------------------------------------------------------------------------------- /GPS-final-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcore1976/gpstracker/HEAD/GPS-final-1.jpg -------------------------------------------------------------------------------- /GPS-final-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcore1976/gpstracker/HEAD/GPS-final-2.jpg -------------------------------------------------------------------------------- /GPS-prototype-ATMEGA.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcore1976/gpstracker/HEAD/GPS-prototype-ATMEGA.jpg -------------------------------------------------------------------------------- /GPS-locator-SIM800L-ATMEGA328P-version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcore1976/gpstracker/HEAD/GPS-locator-SIM800L-ATMEGA328P-version.png -------------------------------------------------------------------------------- /USBASP-10-pin-wiring-to-AVR-Atmega328-chip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcore1976/gpstracker/HEAD/USBASP-10-pin-wiring-to-AVR-Atmega328-chip.png -------------------------------------------------------------------------------- /GPS-locator-ATTINY2313-4313-SIM800L-version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcore1976/gpstracker/HEAD/GPS-locator-ATTINY2313-4313-SIM800L-version.png -------------------------------------------------------------------------------- /compileattiny: -------------------------------------------------------------------------------- 1 | rm *.elf 2 | rm *.o 3 | rm *.hex 4 | avr-gcc -mmcu=attiny2313 -std=gnu99 -Wall -Os -o main3.elf main3.c -w 5 | avr-objcopy -j .text -j .data -O ihex main3.elf main3.hex 6 | avr-size --mcu=attiny2313 --format=avr main3.elf 7 | sudo avrdude -c usbasp -p t2313 -U lfuse:w:0x64:m -U flash:w:"main3.hex":a 8 | 9 | -------------------------------------------------------------------------------- /compileattinyb: -------------------------------------------------------------------------------- 1 | rm *.elf 2 | rm *.o 3 | rm *.hex 4 | avr-gcc -mmcu=attiny2313 -std=gnu99 -Wall -Os -o main3b.elf main3b.c -w 5 | avr-objcopy -j .text -j .data -O ihex main3b.elf main3b.hex 6 | avr-size --mcu=attiny2313 --format=avr main3b.elf 7 | sudo avrdude -c usbasp -p t2313 -U lfuse:w:0x64:m -U flash:w:"main3b.hex":a 8 | 9 | -------------------------------------------------------------------------------- /compileattiny.bat: -------------------------------------------------------------------------------- 1 | del main3.elf 2 | del main3.o 3 | del main3.hex 4 | avr-gcc -mmcu=attiny2313 -std=gnu99 -Wall -Os -o main3.elf main3.c -w 5 | avr-objcopy -j .text -j .data -O ihex main3.elf main3.hex 6 | avr-size --mcu=attiny2313 --format=avr main3.elf 7 | avrdude -c usbasp -p t2313 -U lfuse:w:0x64:m -U flash:w:"main3.hex":a 8 | 9 | -------------------------------------------------------------------------------- /compileattinyb.bat: -------------------------------------------------------------------------------- 1 | del main3b.elf 2 | del main3b.o 3 | del main3b.hex 4 | avr-gcc -mmcu=attiny2313 -std=gnu99 -Wall -Os -o main3b.elf main3b.c -w 5 | avr-objcopy -j .text -j .data -O ihex main3b.elf main3b.hex 6 | avr-size --mcu=attiny2313 --format=avr main3b.elf 7 | avrdude -c usbasp -p t2313 -U lfuse:w:0x64:m -U flash:w:"main3b.hex":a 8 | 9 | -------------------------------------------------------------------------------- /compileatmega: -------------------------------------------------------------------------------- 1 | rm *.elf 2 | rm *.o 3 | rm *.hex 4 | avr-gcc -mmcu=atmega328p -std=gnu99 -Wall -Os -o main.elf main.c -w 5 | avr-objcopy -j .text -j .data -O ihex main.elf main.hex 6 | avr-size --mcu=atmega328p --format=avr main.elf 7 | # fuse = 62 for internal 8Meg with div 8 = 1MHz 8 | sudo avrdude -c usbasp -p m328p -U lfuse:w:0x62:m -U flash:w:"main.hex":a 9 | 10 | -------------------------------------------------------------------------------- /compileatmegab: -------------------------------------------------------------------------------- 1 | rm *.elf 2 | rm *.o 3 | rm *.hex 4 | avr-gcc -mmcu=atmega328p -std=gnu99 -Wall -Os -o mainb.elf mainb.c -w 5 | avr-objcopy -j .text -j .data -O ihex mainb.elf mainb.hex 6 | avr-size --mcu=atmega328p --format=avr mainb.elf 7 | # fuse = 62 for internal 8Meg with div 8 = 1MHz 8 | sudo avrdude -c usbasp -p m328p -U lfuse:w:0x62:m -U flash:w:"mainb.hex":a 9 | 10 | -------------------------------------------------------------------------------- /compileatmega.bat: -------------------------------------------------------------------------------- 1 | del main.elf 2 | del main.o 3 | del main.hex 4 | avr-gcc -mmcu=atmega328p -std=gnu99 -Wall -Os -o main.elf main.c -w 5 | avr-objcopy -j .text -j .data -O ihex main.elf main.hex 6 | avr-size --mcu=atmega328p --format=avr main.elf 7 | # fuse = 62 for internal 8Meg with div 8 = 1MHz 8 | avrdude -c usbasp -p m328p -U lfuse:w:0x62:m -U flash:w:"main.hex":a 9 | 10 | -------------------------------------------------------------------------------- /compileatmegab.bat: -------------------------------------------------------------------------------- 1 | del mainb.elf 2 | del mainb.o 3 | del mainb.hex 4 | avr-gcc -mmcu=atmega328p -std=gnu99 -Wall -Os -o mainb.elf mainb.c -w 5 | avr-objcopy -j .text -j .data -O ihex mainb.elf mainb.hex 6 | avr-size --mcu=atmega328p --format=avr mainb.elf 7 | # fuse = 62 for internal 8Meg with div 8 = 1MHz 8 | avrdude -c usbasp -p m328p -U lfuse:w:0x62:m -U flash:w:"mainb.hex":a 9 | 10 | -------------------------------------------------------------------------------- /main3.hex: -------------------------------------------------------------------------------- 1 | :1000000017C1F1C22EC12DC12CC12BC12AC129C1DA 2 | :1000100028C127C126C125C124C123C122C121C1B4 3 | :1000200020C11FC11EC141542B43495047534D4C61 4 | :100030004F433D312C310D0A002B53415042523A6F 5 | :1000400020312C310041542B53415042523D302C31 6 | :10005000310D0A0041542B53415042523D322C3154 7 | :100060000D0A0041542B53415042523D312C310D69 8 | :100070000A0041542B53415042523D332C312C2223 9 | :10008000505744222C22696E7465726E6574220D7D 10 | :100090000A0041542B53415042523D332C312C2203 11 | :1000A00055534552222C22696E7465726E65742216 12 | :1000B0000D0A0041542B53415042523D332C312CF8 13 | :1000C0002241504E222C22696E7465726E65742234 14 | :1000D0000D0A0041542B53415042523D332C312CD8 15 | :1000E00022434F4E54595045222C224750525322FE 16 | :1000F0000D0A00204C4154543D00205554430A2021 17 | :100100004C4F4E473D000D0A002C000D0A2068742C 18 | :1001100074703A2F2F6D6170732E676F6F676C6507 19 | :100120002E636F6D2F6D6170733F713D00415426DA 20 | :10013000570D0A0041542B4950523D393630300D8D 21 | :100140000A0041542B4353434C4B3D300D0A0041B0 22 | :10015000542B4353434C4B3D320D0A0041542B4327 23 | :1001600046554E3D310D0A0041542B4346554E3DF8 24 | :10017000340D0A0041542B434C49503D310D0A00C7 25 | :10018000220A0D0041542B434D4744413D22444532 26 | :100190004C20414C4C220D0A0041542B434D4753F7 27 | :1001A0003D220041542B434D47463D310D0A00414D 28 | :1001B00054480A0D0041542B43464752493D310AE9 29 | :1001C0000D0041542B4350494E3D223131313122F3 30 | :1001D0000A0D00415445300A0D0041542B4350494B 31 | :1001E0004E3F0A0D002B4350494E3A2053494D20B3 32 | :1001F00050494E002B4350494E3A205245414459F4 33 | :100200000041542B435245473F0A0D002B435245B2 34 | :10021000473A20302C35002B435245473A20302CAA 35 | :10022000310052494E47004F4B0041540A0D000027 36 | :1002300011241FBECFEDCDBF10E0A0E6B0E0E2EA92 37 | :10024000F7E002C005900D92AC3AB107D9F710E083 38 | :10025000ACEAB0E001C01D92A43CB107E1F7CED1F9 39 | :100260009EC2CECE82E08BB912B88CE089B988E10B 40 | :100270008AB986E083B908955D9BFECF8CB9089555 41 | :100280005F9BFECF8CB10895CF93DF93AC01DC016F 42 | :1002900090E020E03D91FB01E90FF11D80813813D2 43 | :1002A00020C090E0892F820FFA01E80FF11D308104 44 | :1002B000C92FD0E031110BC0FB0101900020E9F7FC 45 | :1002C0003197E61BF70BCE17DF0759F40FC0FB0180 46 | :1002D000EC0FFD1F8081882379F33813EDCF9F5FEA 47 | :1002E000E1CF2F5F2832B1F680E001C081E0DF91DD 48 | :1002F000CF910895CF93DF93EC018991882311F07A 49 | :10030000BBDFFBCFDF91CF910895CF93DF93EC015B 50 | :10031000CE01FE012491222329F02196FC01849133 51 | :10032000ABDFF6CFDF91CF9108951092C300A8DF25 52 | :10033000282F30E02A30310579F02D30310561F079 53 | :10034000E091C300F0E0ED57FF4F80838091C30040 54 | :100350008F5F8093C300EBCF8091C300882339F374 55 | :10036000E091C300F0E0ED57FF4F10821092C30000 56 | :1003700081E008951092C0001092C1001092C30055 57 | :100380007FDF8C32E9F77CDFE091C000F0E0E05ADB 58 | :10039000FF4F80839091C0009F5F9093C0008C328C 59 | :1003A00091F7E091C000F0E0E15AFF4F1082109207 60 | :1003B000C00066DFE091C100F0E0E659FF4F8083A6 61 | :1003C0009091C1009F5F9093C1008C3291F7E091B2 62 | :1003D000C100F0E0E759FF4F10821092C10050DFDA 63 | :1003E000282F30E0E091C300F0E0ED57FF4F80830D 64 | :1003F0008091C3008F5F8093C3002D30310519F0C9 65 | :100400002A30310561F7E091C300F0E0EE57FF4F6D 66 | :1004100010821092C30034DF81E008951092C20070 67 | :100420002FDF8232E9F72CDFE091C200F0E0EC58D8 68 | :10043000FF4F80839091C2009F5F9093C2008232F1 69 | :1004400091F7E091C200F0E0ED58FF4F108210925A 70 | :10045000C20016DF90E08A30910511F00D97C9F7C0 71 | :1004600081E00895882361F026E033E14EEA4A9561 72 | :10047000F1F73A95E1F72A95D1F700C08150F2CF14 73 | :100480000895CF938AE292E040DF4FDF882379F02E 74 | :1004900043E050E067E272E08CEA90E077D16CEAEA 75 | :1004A00070E083E890E0F0DEC1E0813009F0C0E068 76 | :1004B00081E0D8DFCC2331F383ED91E026DF81E0CA 77 | :1004C000CF910895CF9382E0CDDF8AED91E01DDFDB 78 | :1004D0002CDF8823C1F34DE050E064EF71E08CEA3B 79 | :1004E00090E054D16CEA70E083E890E0CDDEC82F54 80 | :1004F0004FE050E065EE71E08CEA90E047D16CEAA5 81 | :1005000070E083E890E0C0DE813029F482EC91E075 82 | :10051000FCDE81E0A7DFC130B1F681E0CF91089524 83 | :10052000CF9384EB9FDF81E092E0EFDEFEDE882355 84 | :10053000E1F04BE050E067E172E08CEA90E026D118 85 | :100540006CEA70E083E890E09FDEC82F4BE050E05B 86 | :100550006CE072E08CEA90E019D16CEA70E083E81C 87 | :1005600090E092DE813079F410C081E07BDF88E694 88 | :1005700091E0CBDECCE38CE375DFC150E1F78CE595 89 | :1005800091E0C3DECECFC13061F681E0CF91089516 90 | :1005900081E068DF83ED90E0B8DE81E063DF83EB2C 91 | :1005A00090E0B3DE81E05EDF82E990E0AEDE81E0E4 92 | :1005B00059DF82E790E0A9DE81E054DF81E0089511 93 | :1005C00085B7806585BF85B7806285BF85B78C7F1D 94 | :1005D00085BF8BB780648BBFF8947894889585B776 95 | :1005E0008F7D85BF08951F920F920FB60F92112431 96 | :1005F0001BBE0F900FBE0F901F90189533DE8AE040 97 | :1006000031DF3FDF82E02EDF84E391E07EDE82E0B7 98 | :1006100029DF85EB91E079DE82E024DF8DE291E055 99 | :1006200074DE83E01FDF4EDF7BDFB2DF84E791E023 100 | :100630006CDE82E017DF85E490E067DE82E012DFA7 101 | :1006400083EA91E062DE82E00DDF84E891E05DDE26 102 | :1006500083E008DF8FE491E058DE82E003DFB0DF63 103 | :1006600064DE882369F345E050E062E272E08CEAE0 104 | :1006700090E08CD06CEA70E083E890E005DE813099 105 | :1006800091F4CCDE8AE292E040DE81E0EBDE82E4AF 106 | :1006900091E03BDE81E0E6DE8FEA91E036DE81E04C 107 | :1006A000E1DEC3E01DC08AE292E02FDE81E0DADE07 108 | :1006B00082E491E02ADE81E0B5CF4CE050E069E3CE 109 | :1006C00070E08CEA90E062D06CEA70E083E890E041 110 | :1006D000DBDD91E08130A1F4C150A1F0911115C092 111 | :1006E00085E490E012DE82E0BDDE83E690E00DDE80 112 | :1006F00085E0B8DE84E590E008DE17DE8111DDCF0D 113 | :1007000090E0EACF913009F03FC081E0ABDE86E2B5 114 | :1007100090E0FBDD2FDE81E0A5DE83EA91E0F5DDF0 115 | :1007200081E0A0DE89E991E0F0DD84E790E0E2DDA0 116 | :1007300080E891E0EADD81E095DE83E890E0DADDB3 117 | :100740008AEF90E0E2DD80E690E0D4DD83EF90E098 118 | :10075000DCDD8AE690E0CEDD8BE091E0D6DD8AE656 119 | :1007600090E0C8DD89E091E0D0DD80E690E0C2DD78 120 | :1007700086E091E0CADD81E075DE8AE17DDD85E01D 121 | :1007800071DE85E490E0C1DD8AE059CFFB01DC0138 122 | :1007900002C005900D9241505040D8F70895F8944A 123 | :0207A000FFCF89 124 | :1007A2003132333435363738393031323334353605 125 | :1007B20037383930313233343536373839303132EF 126 | :1007C20033343531323334353637383930313233E8 127 | :1007D20034353637383930313233343536373839C3 128 | :0C07E200303132333435363738393000CE 129 | :00000001FF 130 | -------------------------------------------------------------------------------- /main3b.hex: -------------------------------------------------------------------------------- 1 | :1000000016C12EC12DC12CC12BC12AC129C128C1A5 2 | :1000100027C126C125C124C123C122C121C120C1BC 3 | :100020001FC11EC11DC141542B43495047534D4C64 4 | :100030004F433D312C310D0A002B53415042523A6F 5 | :1000400020312C310041542B53415042523D302C31 6 | :10005000310D0A0041542B53415042523D322C3154 7 | :100060000D0A0041542B53415042523D312C310D69 8 | :100070000A0041542B53415042523D332C312C2223 9 | :10008000505744222C22696E7465726E6574220D7D 10 | :100090000A0041542B53415042523D332C312C2203 11 | :1000A00055534552222C22696E7465726E65742216 12 | :1000B0000D0A0041542B53415042523D332C312CF8 13 | :1000C0002241504E222C22696E7465726E65742234 14 | :1000D0000D0A0041542B53415042523D332C312CD8 15 | :1000E00022434F4E54595045222C224750525322FE 16 | :1000F0000D0A00204C4154543D00205554430A2021 17 | :100100004C4F4E473D000D0A002C000D0A2068742C 18 | :1001100074703A2F2F6D6170732E676F6F676C6507 19 | :100120002E636F6D2F6D6170733F713D00415426DA 20 | :10013000570D0A0041542B4950523D393630300D8D 21 | :100140000A0041542B4353434C4B3D300D0A0041B0 22 | :10015000542B4353434C4B3D320D0A0041542B4327 23 | :1001600046554E3D310D0A0041542B4346554E3DF8 24 | :10017000340D0A0041542B434C49503D310D0A00C7 25 | :10018000220A0D0041542B434D4744413D22444532 26 | :100190004C20414C4C220D0A0041542B434D4753F7 27 | :1001A0003D220041542B434D47463D310D0A00414D 28 | :1001B00054480A0D0041542B4350494E3D223131E1 29 | :1001C0003131220A0D00415445300A0D0041542BB3 30 | :1001D0004350494E3F0A0D002B4350494E3A20539D 31 | :1001E000494D2050494E002B4350494E3A2052452C 32 | :1001F0004144590041542B435245473D300A0D00BC 33 | :1002000041542B435245473F0A0D002B435245476B 34 | :100210003A20302C35002B435245473A20302C31C0 35 | :100220000052494E47004F4B0041540A0D00112423 36 | :100230001FBECFEDCDBF10E0A0E6B0E0E4EBF7E0ED 37 | :1002400002C005900D92AC3AB107D9F710E0ACEAC4 38 | :10025000B0E001C01D92A43CB107E1F7BAD1A8C239 39 | :10026000CFCE82E08BB912B88CE089B988E18AB927 40 | :1002700086E083B908955D9BFECF8CB908955F9B9E 41 | :10028000FECF8CB10895CF93DF93AC01DC0190E0F9 42 | :1002900020E03D91FB01E90FF11D8081381320C062 43 | :1002A00090E0892F820FFA01E80FF11D3081C92FEC 44 | :1002B000D0E031110BC0FB0101900020E9F731972C 45 | :1002C000E61BF70BCE17DF0759F40FC0FB01EC0F4D 46 | :1002D000FD1F8081882379F33813EDCF9F5FE1CF35 47 | :1002E0002F5F2832B1F680E001C081E0DF91CF912D 48 | :1002F0000895CF93DF93EC018991882311F0BBDF40 49 | :10030000FBCFDF91CF910895CF93DF93EC01CE0126 50 | :10031000FE012491222329F02196FC018491ABDF78 51 | :10032000F6CFDF91CF9108951092C300A8DF282F58 52 | :1003300030E02A30310579F02D30310561F0E0915F 53 | :10034000C300F0E0ED57FF4F80838091C3008F5FC3 54 | :100350008093C300EBCF8091C300882339F3E091F1 55 | :10036000C300F0E0ED57FF4F10821092C30081E010 56 | :1003700008951092C0001092C1001092C3007FDF58 57 | :100380008C32E9F77CDFE091C000F0E0E05AFF4FEB 58 | :1003900080839091C0009F5F9093C0008C3291F752 59 | :1003A000E091C000F0E0E15AFF4F10821092C000CF 60 | :1003B00066DFE091C100F0E0E659FF4F8083909145 61 | :1003C000C1009F5F9093C1008C3291F7E091C10012 62 | :1003D000F0E0E759FF4F10821092C10050DF282F44 63 | :1003E00030E0E091C300F0E0ED57FF4F8083809153 64 | :1003F000C3008F5F8093C3002D30310519F02A3080 65 | :10040000310561F7E091C300F0E0EE57FF4F108235 66 | :100410001092C30034DF81E008951092C2002FDFF4 67 | :100420008A33E9F72CDF8232E9F729DFE091C20055 68 | :10043000F0E0EC58FF4F80839091C2009F5F909353 69 | :10044000C200823291F7E091C200F0E0ED58FF4F18 70 | :1004500010821092C20013DF90E08A30910511F0F3 71 | :100460000D97C9F781E00895882361F026E033E114 72 | :100470004EEA4A95F1F73A95E1F72A95D1F700C08F 73 | :100480008150F2CF089589E292E03EDF4DDF88236C 74 | :10049000D1F343E050E066E272E08CEA90E07FD175 75 | :1004A0006CEA70E083E890E0EEDE813061F7DCDF3B 76 | :1004B00086EC91E029DF81E0D7DF81E00895CF93DA 77 | :1004C00082E0D2DF8DEC91E01FDF2EDF8823C1F3C5 78 | :1004D0004DE050E067EE71E08CEA90E060D16CEAAC 79 | :1004E00070E083E890E0CFDEC82F4FE050E068ED89 80 | :1004F00071E08CEA90E053D16CEA70E083E890E020 81 | :10050000C2DE813019F485EB91E0FEDEC130C1F628 82 | :1005100081E0CF910895CF9383E0A6DF8CE591E051 83 | :10052000F3DE8CE3A1DF80E092E0EEDEFDDE8823E7 84 | :1005300099F34BE050E066E172E08CEA90E02FD155 85 | :100540006CEA70E083E890E09EDEC82F4BE050E05C 86 | :100550006BE072E08CEA90E022D16CEA70E083E814 87 | :1005600090E091DE8130D1F0C130C1F088E691E0B9 88 | :10057000CBDE81E079DF8FE491E0C6DECEE18CE373 89 | :1005800073DFC150E1F789E292E0BEDE81E06CDF0B 90 | :1005900082E491E0B9DE81E067DFBECF81E0CF91F8 91 | :1005A000089584E061DF83ED90E0AEDE81E05CDF02 92 | :1005B00083EB90E0A9DE81E057DF82E990E0A4DEE2 93 | :1005C00081E052DF82E790E09FDE81E04DDF81E055 94 | :1005D000089547DE8A98929A8AE046DF54DF84E3E2 95 | :1005E00091E092DE82E040DF84EF91E08DDE82E0F8 96 | :1005F0003BDF8DE291E088DE83E036DF60DF8BDF7A 97 | :10060000C0E0D0E083EA91E07FDE82E02DDF84E885 98 | :1006100091E07ADEC6DF84E791E076DE82E024DFD7 99 | :1006200085E490E071DE82E01FDF8FE491E06CDE14 100 | :1006300082E01ADF829B1AC0219681E015DFC83064 101 | :1006400087E0D807B9F789E292E05EDE81E00CDF4F 102 | :1006500082E491E059DE5FDF81E006DF8FE491E024 103 | :1006600053DE82E001DFC0E0D0E0E4CF5DDE88232E 104 | :1006700059F145E050E061E272E08CEA90E08FD001 105 | :100680006CEA70E083E890E0FEDD813089F4C5DE3D 106 | :1006900089E292E039DE81E0E7DE82E491E034DE57 107 | :1006A00081E0E2DE8FEA91E02FDE81E0DDDE0CC04A 108 | :1006B00089E292E029DE81E0D7DE82E491E024DE67 109 | :1006C00082E0D2DEFCDE9ECF13E085E490E01CDE0B 110 | :1006D00082E0CADE83E690E017DE85E0C5DE84E5D1 111 | :1006E00090E012DE21DE882379F04CE050E069E3EF 112 | :1006F00070E08CEA90E053D06CEA70E083E890E020 113 | :10070000C2DD91E0813009F090E0115019F0992399 114 | :10071000E1F203C0913009F03FC081E0A5DE86E23E 115 | :1007200090E0F2DD26DE81E09FDE83EA91E0ECDD01 116 | :1007300081E09ADE89E991E0E7DD84E790E0D9DDA8 117 | :1007400080E891E0E1DD81E08FDE83E890E0D1DDBB 118 | :100750008AEF90E0D9DD80E690E0CBDD83EF90E09A 119 | :10076000D3DD8AE690E0C5DD8BE091E0CDDD8AE661 120 | :1007700090E0BFDD89E091E0C7DD80E690E0B9DD83 121 | :1007800086E091E0C1DD81E06FDE8AE174DD8AE020 122 | :100790006BDE85E490E0B8DD8AE066DE33CFFB01F6 123 | :1007A000DC0102C005900D9241505040D8F70895E9 124 | :0407B000F894FFCFEB 125 | :1007B40031323334353637383930313233343536F3 126 | :1007C40037383930313233343536373839303132DD 127 | :1007D40033343531323334353637383930313233D6 128 | :1007E40034353637383930313233343536373839B1 129 | :0C07F400303132333435363738393000BC 130 | :00000001FF 131 | -------------------------------------------------------------------------------- /main.hex: -------------------------------------------------------------------------------- 1 | :100000000C9458010C9435040C9475010C947501F2 2 | :100010000C9475010C9475010C9475010C94750188 3 | :100020000C9475010C9475010C9475010C94750178 4 | :100030000C9475010C9475010C9475010C94750168 5 | :100040000C9475010C9475010C9475010C94750158 6 | :100050000C9475010C9475010C9475010C94750148 7 | :100060000C9475010C94750141542B4342430D0AC5 8 | :100070000041542B43495047534D4C4F433D312C85 9 | :10008000310D0A002B53415042523A20312C31009D 10 | :1000900041542B53415042523D302C310D0A004106 11 | :1000A000542B53415042523D322C310D0A004154E1 12 | :1000B0002B53415042523D312C310D0A0041542BFB 13 | :1000C00053415042523D332C312C22505744222C64 14 | :1000D00022696E7465726E6574220D0A0041542B9C 15 | :1000E00053415042523D332C312C2255534552221C 16 | :1000F0002C22696E7465726E6574220D0A0041547B 17 | :100100002B53415042523D332C312C2241504E2230 18 | :100110002C22696E7465726E6574220D0A0041545A 19 | :100120002B53415042523D332C312C22434F4E54DD 20 | :10013000595045222C2247505253220D0A000A42A0 21 | :100140004154544552595B6D565D3D00204C41541D 22 | :1001500049545544453D00205554430A204C4F4EC8 23 | :10016000475449545544453D000D0A002C000D0AE2 24 | :1001700020687474703A2F2F6D6170732E676F6FE3 25 | :10018000676C652E636F6D2F6D6170733F713D00FD 26 | :1001900041542B434E45544C494748543D300D0A79 27 | :1001A00000415426570D0A0041542B4950523D3905 28 | :1001B0003630300D0A0041542B4353434C4B3D30F5 29 | :1001C0000D0A0041542B4353434C4B3D320D0A0062 30 | :1001D00041542B4346554E3D310D0A0041542B43AB 31 | :1001E00046554E3D340D0A0041542B434C49503D79 32 | :1001F000310D0A00220A0D0041542B434D47444162 33 | :100200003D2244454C20414C4C220D0A0041542BC8 34 | :10021000434D47533D220041542B434D47463D310A 35 | :100220000D0A004154480A0D0041542B43464752E1 36 | :10023000493D310A0D0041542B4350494E3D223176 37 | :10024000313131220A0D00415445300A0D0041542C 38 | :100250002B4350494E3F0A0D002B4350494E3A2044 39 | :1002600053494D2050494E002B4350494E3A20529D 40 | :10027000454144590041542B435245473D300A0DF6 41 | :100280000041542B435245473F0A0D002B43524532 42 | :10029000473A20302C35002B435245473A20302C2A 43 | :1002A000310052494E47004F4B0041540A0D0000A7 44 | :1002B00011241FBECFEFD8E0DEBFCDBF11E0A0E01C 45 | :1002C000B1E0EAE2FBE002C005900D92A639B10769 46 | :1002D000D9F711E0A6E9B1E001C01D92A33CB10736 47 | :1002E000E1F70E9440040C9493050C94000082E016 48 | :1002F0008093C0001092C5008CE08093C400E1ECB4 49 | :10030000F0E0808188608083808180618083E2EC7E 50 | :10031000F0E080818660808308959091C00095FF11 51 | :10032000FCCF8093C60008958091C00087FFFCCF6A 52 | :100330008091C6000895CF93DF93AC01DC0190E07B 53 | :1003400020E03D91FB01E90FF11D8081381320C0B1 54 | :1003500090E0892F820FFA01E80FF11D3081C92F3B 55 | :10036000D0E031110BC0FB0101900020E9F731977B 56 | :10037000E61BF70BCE17DF0759F40FC0FB01EC0F9C 57 | :10038000FD1F8081882379F33813EDCF9F5FE1CF84 58 | :100390002F5F2035B1F680E001C081E0DF91CF9181 59 | :1003A0000895CF93DF93EC018991882319F00E947F 60 | :1003B0008D01FACFDF91CF910895CF93DF93EC01B8 61 | :1003C000CE01FE012491222331F02196FC0184917B 62 | :1003D0000E948D01F5CFDF91CF910895CF931092B8 63 | :1003E000C201C0E50E949401282F30E02A30310577 64 | :1003F00079F02D30310561F0E091C201F0E0EA5B67 65 | :10040000FE4F80838091C2018F5F8093C2010DC037 66 | :100410008091C201882349F0E091C201F0E0EA5BDB 67 | :10042000FE4F10821092C20102C0C150D9F681E085 68 | :10043000CF910895CF931092BF011092C0011092F6 69 | :10044000C201C0E00E949401CF5F8C3219F0C43128 70 | :10045000C9F75EC0C43109F45BC00E949401E09109 71 | :10046000BF01F0E0E65FFE4F80839091BF019F5F88 72 | :100470009093BF01CF5F8C3249F4E091BF01F0E06F 73 | :10048000E75FFE4F10821092BF0105C0C63429F706 74 | :10049000F4CFC63480F40E949401E091C001F0E0F2 75 | :1004A000E25EFE4F80839091C0019F5F9093C001F8 76 | :1004B000CF5F8C3271F7E091C001F0E0E35EFE4F58 77 | :1004C00010821092C00105C02A303105A9F0C6344F 78 | :1004D00098F40E949401282F30E0E091C201F0E0EE 79 | :1004E000EA5BFE4F80838091C2018F5F8093C201DF 80 | :1004F000CF5F2D30310541F7E091C201F0E0EB5BB9 81 | :10050000FE4F10821092C2010E94940181E001C04E 82 | :1005100080E0CF910895CF931092C101C0E00E9476 83 | :100520009401CF5F8A3311F0C035C9F70E9494015E 84 | :10053000CF5F823211F0C035C8F30E949401E09180 85 | :10054000C101F0E0EE5CFE4F80839091C1019F5F9E 86 | :100550009093C101CF5F823249F4E091C101F0E094 87 | :10056000EF5CFE4F10821092C10107C0C03528F326 88 | :10057000F4CF0D9749F0C03538F40E94940190E013 89 | :10058000CF5F8A309105A9F781E0CF910895CF938D 90 | :1005900010929601C0E00E949401CF5F8C3211F05E 91 | :1005A000C634C9F70E949401CF5F8C3211F0C63473 92 | :1005B000C8F30E949401282F30E0E0919601F0E00A 93 | :1005C000E050FF4F8083809196018F5F809396016A 94 | :1005D000CF5F2A30310529F02D30310511F0C634B6 95 | :1005E00040F3E0919601F0E0E150FF4F108210924D 96 | :1005F000960181E0CF910895882361F026E033E1F0 97 | :100600004EEA4A95F1F73A95E1F72A95D1F700C0FD 98 | :100610008150F2CF0895CF938AEA92E00E94DD01E3 99 | :100620000E94EE01882389F043E050E067EA72E01F 100 | :1006300087E991E00E948A0567E971E086E491E02C 101 | :100640000E949B01C1E0813009F0C0E081E00E947E 102 | :10065000FC02CC2309F387E492E00E94DD0181E0F3 103 | :100660000E94FC0281E0CF910895CF9382E00E9426 104 | :10067000FC028EE492E00E94DD010E94EE018823DC 105 | :10068000A9F34DE050E068E672E087E991E00E944E 106 | :100690008A0567E971E086E491E00E949B01C82F1A 107 | :1006A0004FE050E069E572E087E991E00E948A0539 108 | :1006B00067E971E086E491E00E949B01813049F492 109 | :1006C0000E94FC0286E392E00E94DD0181E00E942C 110 | :1006D000FC02C13059F681E0CF910895CF93DF93AA 111 | :1006E00081E00E94FC0281E892E00E94DD010E940C 112 | :1006F000EE01811102C0C0E367C04BE050E067E942 113 | :1007000072E087E991E00E948A0567E971E086E47A 114 | :1007100091E00E949B01813009F469C04BE050E0F8 115 | :100720006CE872E087E991E00E948A0567E971E070 116 | :1007300086E491E00E949B018130E9F658C04BE0CD 117 | :1007400050E067E972E087E991E00E948A0567E975 118 | :1007500071E086E491E00E949B01D82F4BE050E0CD 119 | :100760006CE872E087E991E00E948A0567E971E030 120 | :1007700086E491E00E949B018130C9F1D130B9F14A 121 | :1007800081E00E94FC028CED91E00E94DD0181E09D 122 | :100790000E94FC0283EC91E00E94DD01DEE18CE32B 123 | :1007A0000E94FC02D150D9F78AEA92E00E94DD0152 124 | :1007B00081E00E94FC0286EB91E00E94DD0181E075 125 | :1007C0000E94FC02C15099F081E00E94FC0280ED81 126 | :1007D00091E00E94DD0188E70E94FC0281E892E03E 127 | :1007E0000E94DD010E94EE01882361F3A8CF81E021 128 | :1007F000DF91CF91089581E00E94FC028EE191E0AB 129 | :100800000E94DD0181E00E94FC028EEF90E00E94D8 130 | :10081000DD0181E00E94FC028DED90E00E94DD018F 131 | :1008200081E00E94FC028DEB90E00E94DD0181E0FE 132 | :100830000E94FC0281E0089583B7817F846083BFBA 133 | :1008400083B7816083BF52985A9AF894E9E6F0E042 134 | :1008500080818D7F808380818E7F8083E89A7894E9 135 | :10086000889583B78E7F83BF08951F920F920FB62E 136 | :100870000F921124E8980F900FBE0F901F901895BB 137 | :100880000E9477018AE00E94FC020E940B0382E032 138 | :100890000E94FC0288EA91E00E94DD0181E00E9452 139 | :1008A000FC0289E292E00E94DD0181E00E94FC02EC 140 | :1008B00085E792E00E94DD0181E00E94FC0281EA6E 141 | :1008C00091E00E94DD0183E00E94FC020E9435035A 142 | :1008D00082E00E94FC0280ED91E00E94DD0188E749 143 | :1008E0000E94FC020E946E030E94FB0387E192E0DB 144 | :1008F0000E94DD0181E00E94FC0288EF91E00E94ED 145 | :10090000DD0182E00E94FC0288EE91E00E94DD01A0 146 | :1009100081E00E94FC0280E991E00E94DD0181E01B 147 | :100920000E94FC0283EC91E00E94DD0182E00E94C3 148 | :10093000FC020E941C040E94EE018823B9F245E0EB 149 | :1009400050E062EA72E087E991E00E948A0567E977 150 | :1009500071E086E491E00E949B018130C9F40E941D 151 | :100960008B028AEA92E00E94DD0181E00E94FC0293 152 | :1009700086EB91E00E94DD0181E00E94FC0283E2AF 153 | :1009800092E00E94DD0181E00E94FC02C3E02DC0E4 154 | :100990008AEA92E00E94DD0181E00E94FC0286EB7F 155 | :1009A00091E00E94DD0181E00E94FC020E9435037B 156 | :1009B0000E946E0380E990E00E94DD0182E0A7C002 157 | :1009C0004CE050E064E870E087E991E00E948A051D 158 | :1009D00067E971E086E491E00E949B0191E081303B 159 | :1009E00011F5C15011F1911123C081E00E94FC0268 160 | :1009F00080E990E00E94DD0181E00E94FC020E94FB 161 | :100A0000FB0381E00E94FC028EEA90E00E94DD017F 162 | :100A10008AE00E94FC028FE990E00E94DD010E94C2 163 | :100A2000EE018111CDCF90E0DCCF913009F06EC0A6 164 | :100A300081E00E94FC0288E690E00E94DD010E94B5 165 | :100A4000C70281E00E94FC0281E790E00E94DD0184 166 | :100A50000E941A02811104C087E30E94FC024FC069 167 | :100A600081E00E94FC0287E192E00E94DD0181E0CA 168 | :100A70000E94FC028DE092E00E94DD0182E391E0A1 169 | :100A80000E94D10184EF91E00E94DD0181E00E948B 170 | :100A9000FC0286E491E00E94D10187E591E00E948A 171 | :100AA000DD018AE091E00E94D1018CE491E00E9496 172 | :100AB000DD018EE191E00E94D1018EE391E00E9480 173 | :100AC000DD0180E091E00E94D1018EE691E00E947C 174 | :100AD000DD018EE191E00E94D1018CE691E00E945F 175 | :100AE000DD018AE091E00E94D10189E691E00E9457 176 | :100AF000DD0181E00E94FC028AE10E948D0185E017 177 | :100B00000E94FC0280E990E00E94DD018AE00E94E0 178 | :100B1000FC02ECCEFB01DC0102C005900D924150BD 179 | :0A0B20005040D8F70895F894FFCF75 180 | :100B2A003132333435363738393031323334353679 181 | :100B3A003738393031323334353637383930313263 182 | :100B4A00333435363738393031323334353637384D 183 | :100B5A00393031323334353637383930313233344B 184 | :100B6A00353637383930313233343536373839302B 185 | :100B7A003132333435363738393031323334353629 186 | :100B8A003738393031323334353637383930313213 187 | :100B9A0033343536373839303132333435363738FD 188 | :100BAA0039303132333435363738393031323334FB 189 | :060BBA00353637383930F2 190 | :00000001FF 191 | -------------------------------------------------------------------------------- /mainb.hex: -------------------------------------------------------------------------------- 1 | :100000000C9458010C9444040C9475010C947501E3 2 | :100010000C9475010C9475010C9475010C94750188 3 | :100020000C9475010C9475010C9475010C94750178 4 | :100030000C9475010C9475010C9475010C94750168 5 | :100040000C9475010C9475010C9475010C94750158 6 | :100050000C9475010C9475010C9475010C94750148 7 | :100060000C9475010C94750141542B4342430D0AC5 8 | :100070000041542B43495047534D4C4F433D312C85 9 | :10008000310D0A002B53415042523A20312C31009D 10 | :1000900041542B53415042523D302C310D0A004106 11 | :1000A000542B53415042523D322C310D0A004154E1 12 | :1000B0002B53415042523D312C310D0A0041542BFB 13 | :1000C00053415042523D332C312C22505744222C64 14 | :1000D00022696E7465726E6574220D0A0041542B9C 15 | :1000E00053415042523D332C312C2255534552221C 16 | :1000F0002C22696E7465726E6574220D0A0041547B 17 | :100100002B53415042523D332C312C2241504E2230 18 | :100110002C22696E7465726E6574220D0A0041545A 19 | :100120002B53415042523D332C312C22434F4E54DD 20 | :10013000595045222C2247505253220D0A000A42A0 21 | :100140004154544552595B6D565D3D00204C41541D 22 | :1001500049545544453D00205554430A204C4F4EC8 23 | :10016000475449545544453D000D0A002C000D0AE2 24 | :1001700020687474703A2F2F6D6170732E676F6FE3 25 | :10018000676C652E636F6D2F6D6170733F713D00FD 26 | :1001900041542B434E45544C494748543D300D0A79 27 | :1001A00000415426570D0A0041542B4950523D3905 28 | :1001B0003630300D0A0041542B4353434C4B3D30F5 29 | :1001C0000D0A0041542B4353434C4B3D320D0A0062 30 | :1001D00041542B4346554E3D310D0A0041542B43AB 31 | :1001E00046554E3D340D0A0041542B434C49503D79 32 | :1001F000310D0A00220A0D0041542B434D47444162 33 | :100200003D2244454C20414C4C220D0A0041542BC8 34 | :10021000434D47533D220041542B434D47463D310A 35 | :100220000D0A004154480A0D0041542B43464752E1 36 | :10023000493D310A0D0041542B4350494E3D223176 37 | :10024000313131220A0D00415445300A0D0041542C 38 | :100250002B4350494E3F0A0D002B4350494E3A2044 39 | :1002600053494D2050494E002B4350494E3A20529D 40 | :10027000454144590041542B435245473D300A0DF6 41 | :100280000041542B435245473F0A0D002B43524532 42 | :10029000473A20302C35002B435245473A20302C2A 43 | :1002A000310052494E47004F4B0041540A0D0000A7 44 | :1002B00011241FBECFEFD8E0DEBFCDBF11E0A0E01C 45 | :1002C000B1E0E6E8FBE002C005900D92A639B10767 46 | :1002D000D9F711E0A6E9B1E001C01D92A33CB10736 47 | :1002E000E1F70E944F040C94C1050C94000082E0D9 48 | :1002F0008093C0001092C5008CE08093C400E1ECB4 49 | :10030000F0E0808188608083808180618083E2EC7E 50 | :10031000F0E080818660808308959091C00095FF11 51 | :10032000FCCF8093C60008958091C00087FFFCCF6A 52 | :100330008091C6000895CF93DF93AC01DC0190E07B 53 | :1003400020E03D91FB01E90FF11D8081381320C0B1 54 | :1003500090E0892F820FFA01E80FF11D3081C92F3B 55 | :10036000D0E031110BC0FB0101900020E9F731977B 56 | :10037000E61BF70BCE17DF0759F40FC0FB01EC0F9C 57 | :10038000FD1F8081882379F33813EDCF9F5FE1CF84 58 | :100390002F5F2035B1F680E001C081E0DF91CF9181 59 | :1003A0000895CF93DF93EC018991882319F00E947F 60 | :1003B0008D01FACFDF91CF910895CF93DF93EC01B8 61 | :1003C000CE01FE012491222331F02196FC0184917B 62 | :1003D0000E948D01F5CFDF91CF910895CF931092B8 63 | :1003E000C201C0E50E949401282F30E02A30310577 64 | :1003F00079F02D30310561F0E091C201F0E0EA5B67 65 | :10040000FE4F80838091C2018F5F8093C2010DC037 66 | :100410008091C201882349F0E091C201F0E0EA5BDB 67 | :10042000FE4F10821092C20102C0C150D9F681E085 68 | :10043000CF910895CF931092BF011092C0011092F6 69 | :10044000C201C0E00E949401CF5F8C3219F0C43128 70 | :10045000C9F75EC0C43109F45BC00E949401E09109 71 | :10046000BF01F0E0E65FFE4F80839091BF019F5F88 72 | :100470009093BF01CF5F8C3249F4E091BF01F0E06F 73 | :10048000E75FFE4F10821092BF0105C0C63429F706 74 | :10049000F4CFC63480F40E949401E091C001F0E0F2 75 | :1004A000E25EFE4F80839091C0019F5F9093C001F8 76 | :1004B000CF5F8C3271F7E091C001F0E0E35EFE4F58 77 | :1004C00010821092C00105C02A303105A9F0C6344F 78 | :1004D00098F40E949401282F30E0E091C201F0E0EE 79 | :1004E000EA5BFE4F80838091C2018F5F8093C201DF 80 | :1004F000CF5F2D30310541F7E091C201F0E0EB5BB9 81 | :10050000FE4F10821092C2010E94940181E001C04E 82 | :1005100080E0CF910895CF931092C101C0E00E9476 83 | :100520009401CF5F8A3311F0C035C9F70E9494015E 84 | :10053000CF5F823211F0C035C8F30E949401E09180 85 | :10054000C101F0E0EE5CFE4F80839091C1019F5F9E 86 | :100550009093C101CF5F823249F4E091C101F0E094 87 | :10056000EF5CFE4F10821092C10107C0C03528F326 88 | :10057000F4CF0D9749F0C03538F40E94940190E013 89 | :10058000CF5F8A309105A9F781E0CF910895CF938D 90 | :1005900010929601C0E00E949401CF5F8C3211F05E 91 | :1005A000C634C9F70E949401CF5F8C3211F0C63473 92 | :1005B000C8F30E949401282F30E0E0919601F0E00A 93 | :1005C000E050FF4F8083809196018F5F809396016A 94 | :1005D000CF5F2A30310529F02D30310511F0C634B6 95 | :1005E00040F3E0919601F0E0E150FF4F108210924D 96 | :1005F000960181E0CF910895882361F026E033E1F0 97 | :100600004EEA4A95F1F73A95E1F72A95D1F700C0FD 98 | :100610008150F2CF0895611571058105910549F06A 99 | :1006200020E12A95F1F700C0615071098109910913 100 | :10063000F2CF0895CF938AEA92E00E94DD010E94F2 101 | :10064000EE01882389F043E050E067EA72E087E931 102 | :1006500091E00E94B80567E971E086E491E00E94AC 103 | :100660009B01C1E0813009F0C0E081E00E94FC0202 104 | :10067000CC2309F387E492E00E94DD0181E00E942F 105 | :10068000FC0281E0CF910895CF9382E00E94FC02AA 106 | :100690008EE492E00E94DD010E94EE018823A9F31E 107 | :1006A0004DE050E068E672E087E991E00E94B8050D 108 | :1006B00067E971E086E491E00E949B01C82F4FE05A 109 | :1006C00050E069E572E087E991E00E94B80567E9CA 110 | :1006D00071E086E491E00E949B01813049F40E9420 111 | :1006E000FC0286E392E00E94DD0181E00E94FC02B0 112 | :1006F000C13059F681E0CF910895CF93DF9381E027 113 | :100700000E94FC0281E892E00E94DD010E94EE015D 114 | :10071000811102C0C0E367C04BE050E067E972E0BE 115 | :1007200087E991E00E94B80567E971E086E491E00D 116 | :100730000E949B01813009F469C04BE050E06CE8F5 117 | :1007400072E087E991E00E94B80567E971E086E40C 118 | :1007500091E00E949B018130E9F658C04BE050E0E7 119 | :1007600067E972E087E991E00E94B80567E971E006 120 | :1007700086E491E00E949B01D82F4BE050E06CE8AA 121 | :1007800072E087E991E00E94B80567E971E086E4CC 122 | :1007900091E00E949B018130C9F1D130B9F181E033 123 | :1007A0000E94FC028CED91E00E94DD0181E00E943C 124 | :1007B000FC0283EC91E00E94DD01DEE18CE30E940B 125 | :1007C000FC02D150D9F78AEA92E00E94DD0181E073 126 | :1007D0000E94FC0286EB91E00E94DD0181E00E9414 127 | :1007E000FC02C15099F081E00E94FC0280ED91E092 128 | :1007F0000E94DD0188E70E94FC0281E892E00E94ED 129 | :10080000DD010E94EE01882361F3A8CF81E0DF9132 130 | :10081000CF91089581E00E94FC028EE191E00E9458 131 | :10082000DD0181E00E94FC028EEF90E00E94DD017C 132 | :1008300081E00E94FC028DED90E00E94DD0181E0EC 133 | :100840000E94FC028DEB90E00E94DD0181E00E949D 134 | :10085000FC0281E0089583B7817F846083BF83B702 135 | :10086000816083BF52985A9AF894E9E6F0E080815B 136 | :100870008D7F808380818E7F8083E89A78948895AD 137 | :1008800083B78E7F83BF08951F920F920FB60F928A 138 | :100890001124E8980F900FBE0F901F9018950E949A 139 | :1008A000770152985A9A8AE00E94FC020E941A0329 140 | :1008B00082E00E94FC0288EA91E00E94DD0181E072 141 | :1008C0000E94FC0289E292E00E94DD0181E00E9428 142 | :1008D000FC0285E792E00E94DD0181E00E94FC02BB 143 | :1008E00081EA91E00E94DD0183E00E94FC020E9407 144 | :1008F000440381E00E94FC0280ED91E00E94DD0152 145 | :1009000088E70E94FC020E947D030E940A0487E19E 146 | :1009100092E00E94DD0181E00E94FC0288EF91E0FC 147 | :100920000E94DD0182E00E94FC0288EE91E00E94BC 148 | :10093000DD0181E00E94FC0280E991E00E94DD017E 149 | :1009400081E00E94FC0283EC91E00E94DD0182E0E4 150 | :100950000E94FC0280E8C82E88EAD82E82E1E82EA8 151 | :10096000FF24F3944A9B1AC061E070E080E090E0BD 152 | :100970000E940B0381E0C81AD108E108F10891F741 153 | :100980008AEA92E00E94DD0181E00E94FC0286EB8F 154 | :1009900091E00E94DD010E947D03D2CF0E94EE0112 155 | :1009A0008823D9F145E050E062EA72E087E991E0FE 156 | :1009B0000E94B80567E971E086E491E00E949B011E 157 | :1009C0008130C1F40E948B028AEA92E00E94DD012C 158 | :1009D00081E00E94FC0286EB91E00E94DD0181E053 159 | :1009E0000E94FC0283E292E00E94DD0181E00E940D 160 | :1009F000FC0213C08AEA92E00E94DD0181E00E94BD 161 | :100A0000FC0286EB91E00E94DD0181E00E94FC0285 162 | :100A10000E9444030E947D037ACFC3E081E00E94DC 163 | :100A2000FC0280E990E00E94DD0181E00E94FC026E 164 | :100A30000E940A0481E00E94FC028EEA90E00E947B 165 | :100A4000DD018AE00E94FC028FE990E00E94DD0156 166 | :100A50000E94EE01882389F04CE050E064E870E0E9 167 | :100A600087E991E00E94B80567E971E086E491E0CA 168 | :100A70000E949B0191E0813009F090E0C15019F093 169 | :100A8000992361F203C0913009F06EC081E00E94A9 170 | :100A9000FC0288E690E00E94DD010E94C70281E02E 171 | :100AA0000E94FC0281E790E00E94DD010E941A0290 172 | :100AB000811104C087E30E94FC024FC081E00E94C4 173 | :100AC000FC0287E192E00E94DD0181E00E94FC02CD 174 | :100AD0008DE092E00E94DD0182E391E00E94D1016D 175 | :100AE00084EF91E00E94DD0181E00E94FC0286E437 176 | :100AF00091E00E94D10187E591E00E94DD018AE04A 177 | :100B000091E00E94D1018CE491E00E94DD018EE130 178 | :100B100091E00E94D1018EE391E00E94DD0180E02E 179 | :100B200091E00E94D1018EE691E00E94DD018EE10C 180 | :100B300091E00E94D1018CE691E00E94DD018AE003 181 | :100B400091E00E94D10189E691E00E94DD0181E0FF 182 | :100B50000E94FC028AE10E948D0185E00E94FC0255 183 | :100B600080E990E00E94DD018AE00E94FC02CFCE85 184 | :100B7000FB01DC0102C005900D9241505040D8F7B6 185 | :060B80000895F894FFCF78 186 | :100B8600313233343536373839303132333435361D 187 | :100B96003738393031323334353637383930313207 188 | :100BA60033343536373839303132333435363738F1 189 | :100BB60039303132333435363738393031323334EF 190 | :100BC60035363738393031323334353637383930CF 191 | :100BD60031323334353637383930313233343536CD 192 | :100BE60037383930313233343536373839303132B7 193 | :100BF60033343536373839303132333435363738A1 194 | :100C0600393031323334353637383930313233349E 195 | :060C160035363738393095 196 | :00000001FF 197 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DIY ultra cheap GPS bike/car tracker based on ATMEL ATTINY 2313/4313 or ATMEGA 328P (arduino uno chip) and SIM800L module from China vendor SIMCOM. The description of SIM800L module is here : https://lastminuteengineers.com/sim800l-gsm-module-arduino-tutorial/ 2 | 3 | The device when called by mobile phone polls cell-id info from nearest 2G cell, uses GPRS to query Google servers for GPS location of that cell and sends back text message to your phone with current location link to Google map with timestamp. 4 | 5 | BILL OF MATERIALS (with the cost as in 2018): 6 | 7 | - SIM800L (3.5 USD on Aliexpress, but notice this module DOES NOT have GPS so we are polling info from base stations - if you want better accuracy from real GPS you need to use SIM808 board - all details described in this project - https://github.com/mcore1976/sim808gpstracker ) 8 | - ATMEL ATTINY2313 (2USD) or ATMEGA 328P (arduino uno) or ARDUINO MINI PRO 3.3V board instead 9 | - LM7805 (0.5USD) - optional if you intend to connect to car/bike battery directly 10 | - 6x 1N4007 (0.3 USD) - optional - for CAR/BIKE battery or USB Powerbank 11 | - 2x 1000uF / 16V capacitor ( 0.5 USD) - when powered from 3xAA battery pack only 1 capacitor is needed 12 | - 100nF / 12V (or higher) capacitor (0.2 USD) 13 | - universal PCB, pins & connector (2 USD) 14 | 15 | 16 | SOURCE FILE OPTIONS : 17 | 18 | The code is written in avr-gcc and was uploaded via USBASP. Both binary output versions are provided : for ATTINY 2313(2313A/2313V) and ATMEGA 328P. 19 | 20 | main.c ( compilation script : compileatmega / compileatmega.bat ) - file for ATMEGA328P when MCU goes into POWERDOWN mode - the lowest power consumption (<3mA) 21 | 22 | mainb.c ( compilation script : compileatmegab / compileatmegab.bat ) - file for ATMEGA328P when MCU periodically checks SIM800L 2G network status (once per 30 min and does radio switchoff for 30 min if necessary) - this version is most stable now but power consumption is slightly higher (~6mA) 23 | 24 | main3.c ( compilation script : compileattiny / compileattiny.bat ) - file for ATTINY2313 when MCU goes int o POWERDOWN mode - the lowest power consumption (<2mA) 25 | 26 | main3b.c ( compilation script : compileattinyb / compileattinyb.bat ) - file for ATTINY2313 when MCU periodically checks SIM800L 2G network status (once per 30 min and does radio switchoff for 30 min if necessary)- this version is most stable now but power consumption is slightly higher (5mA) 27 | 28 | In the code you have to put correct APN, USERNAME and PASSWORD of GPRS access from your Mobile Network Operator before compiling - replace word "internet" below wit correct words for your MNO (check with your network provider hoe to configure GPRS access): 29 | 30 | constchar SAPBR2[] PROGMEM = {"AT+SAPBR=3,1,"APN","internet"\r\n"}; // Put your mobile operator APN name here 31 | 32 | constchar SAPBR3[] PROGMEM = {"AT+SAPBR=3,1,"USER","internet"\r\n"}; // Put your mobile operator APN username here 33 | 34 | constchar SAPBR4[] PROGMEM = {"AT+SAPBR=3,1,"PWD","internet"\r\n"}; // Put your mobile operator APN password here 35 | 36 | COMPILATION ON LINUX PC : 37 | 38 | The script attached in repository ( "compileatmega" or "compileattiny" ) can be used to upload data to the chip if you have Linux machine with following packages : "gcc-avr", "binutils-avr" (or sometimes just "binutils"), "avr-libc", "avrdude" and optionally "gdb-avr"(debugger only if you really need it) . For example in Ubuntu download these packages using command : "sudo apt-get install gcc-avr binutils-avr avr-libc gdb-avr avrdude". 39 | After this is done you can run from directory you downloaded the github files appropriate compilation script by commands 40 | - "sudo chmod +rx compileatmega*" and "sudo ./compileatmega" ( "sudo ./compileatmegab" ) 41 | - "sudo chmod +rx compileattiny*" and "sudo ./compileattiny" ( "sudo ./compileattinyb" ) 42 | 43 | COMPILATION ON WINDOWS PC : 44 | 45 | If you have Windows 10 machine please follow this tutorial to download and install full AVR-GCC environment for Windows : http://fab.cba.mit.edu/classes/863.16/doc/projects/ftsmin/windows_avr.html with latest compiler from Microchip/Atmel. 46 | 47 | After it is done please use "compileattinyX.bat" or "compileatmegaX.bat" for compilation inside directory where you have downloaded "mainXX.c" files. You have to be logged as Windows Administrator to use avrdude software. 48 | 49 | PROGRAMMING THE ATTINY / ATMEGA / ARDUINO - connecting cables to the chip : 50 | 51 | Link to video how to program the chip : https://www.youtube.com/watch?v=7klgyNzZ2TI 52 | 53 | To upload program code to the chip using cheapest USBASP programmer (less than 2 USD on eBay/Aliexpress) look at this page : 54 | http://www.learningaboutelectronics.com/Articles/Program-AVR-chip-using-a-USBASP-with-10-pin-cable.php , because we are not using ARDUINO bootloader here (especially for chips like ATTINY) 55 | 56 | If you are having problems with C code compilation and USBASR programmer you may also look at these tutorials : 57 | 58 | http://www.linuxandubuntu.com/home/setting-up-avr-gcc-toolchain-and-avrdude-to-program-an-avr-development-board-in-ubuntu 59 | 60 | https://blog.podkalicki.com/how-to-compile-and-burn-the-code-to-avr-chip-on-linuxmacosxwindows/ 61 | 62 | Some people do not like to use universal PCB and are having problems with soldering. You may use "Arduino Pro Mini 3.3V" board (or clone) instead with some pins and cables connected to SIM800L module. 63 | There are two options for this board - 5V voltage and 3.3V voltage. Pay attention to it when selecting the board so it could match SIM800L board 3.3V TTL logic. 64 | To use "Arduino Pro Mini" you will have to connect USBASP programmer with KANDA socket (look here : https://www.atnel.pl/download/blog/ISP_KANDA.jpg ) to appropriate pins of this board : SCK (pin 13), MISO (pin 12), MOSI (pin 11), RESET (pin RST), pin VCC, pin GND - like shown here when changing/uploading bootloader https://www.arduino.cc/en/Hacking/MiniBootloader 65 | Description of this board "Arduino Pro Mini" is here : https://www.theengineeringprojects.com/2018/06/introduction-to-arduino-pro-mini.html 66 | 67 | This GPS tracker solution is not based on ARDUINO FRAMEWORK (it does not use ARDUINO bootloader and we are getting rid of it here), it uses pure C code instead so USBASP programmer is still needed. 68 | 69 | 70 | OTHER INFORMATION : 71 | 72 | For smallest chip ATTINY2313 the code takes about 2KB of Flash memory so the chip memory gets completely full. However old ATTINY2313 chips takes less space on PCB and are a bit cheaper than ATMEGA328P. 73 | Considering the SIM800L capability if more Flash memory is available (like in ATMEGA328P), the chip could even upload the GPS data to some EMAIL/FTP/HTTP server to get car tracking history. 74 | In source files above same functions are available for ATTINY2313 and ATMEGA328P 75 | 76 | The tracker has ultra low power consumption because it is utilizing SLEEP MODE on SIM8XX/9XX module and POWER DOWN feature on ATTINY/ATMEGA MCU (current in standby is below 2mA, but only when signal RI/RING from SIM800L is connected to MCU) and connects to GPRS/polls GPS only upon request. Also the LED on the SIM800L is switched off to further reduce current consumption. 77 | This will give you something like at least 1 month of work time on smallest USB powerbanks like 2000mAh or 3xAA battery ( I personally do recommend to use 3xAA because powerbanks have LED and converters that drain extra current). 78 | The ATTINY/ATMEGA wakes up (or activates the code to check GPS location) when SIM8xx PIN RING goes to GND (in case of incoming call or SMS or MODULE RESTART - "Call Ready" message from URC). 79 | 80 | When SIM8xx module sends SMS/GPRS data it it may draw a lot of current ( up to 2A ) in short peaks so it is crucial to use good cables and thick copper lines for GND and VCC on PCB. This is the main issue people face when dealing with SIM8xx/9xx modules. The voltage may additionaly drop during this situation so that is why such big capacitor is in use. 81 | In the design there are 1N4007 diodes connected in serial+parallel to ensure that voltage is dropped to correct levels (when powered from car/bike battery or USB 5V powerbank) which is around 4,4V for SIM8XX module (5V would damage SIM800L) and 2A current can be handled. Also we have to secure that during current peaks the voltage will not drop below 3V for SIM800L ( otherwise SIM800L would restart itself during SMS/GPRS sending). 82 | 83 | The tracker can be powered 3 ways ( and depending on powering method you can get rid of LM7805 or some 1N4007 diodes to simplify the design): 84 | 85 | a) powering directly from car/bike battery - ensure that proper cables are used (must sustain 2Amps) and attach small heatsink to LM7805 TO220 case. It will not get hot all the time but ensure that current/heat protection within LM7805 would not activate. In such case the tracker will consume in standby something like 12mA due to LM7805 drop (conversion from 12V to 5V). You may try to put some replacement of LM7805 like switching power supply step-down converter - DC-DC buck converter based on LM2596 - it generates less heat. 86 | 87 | b) powering from USB 5V Powerbanks - it is good to use the cheapest USB powerbanks that do not have current sensor. Remember that GPS tracker will draw VERY LOW current ( lower than 2mA). Some advanced powerbanks tend to switch off USB 5V when they find out that there is very little current consumed. If you have Powerbank with signalling LED then I suggest to get rid of this LED to reduce power drain on Powerbank. 88 | 89 | c) Powering from 3 x AA battery pack (LR6). Estimated working time on set of batteries is more than 1 month due to low current ( less than 2mA). Batteries must be connected directly to VCC on ATTINY-ATMEGA/SIM8XX without any diodes - this is the simplest design. Batteries will give something like 4.5V of powering voltage which is perfect for SIM800L. Avoid Ni-Mh Accumulators. They give only 1.2V each. 90 | 91 | The solution has been field tested and works without a glitch. 92 | 93 | You can see how it works : 94 | here : https://www.youtube.com/watch?v=t7mvomytDq4 95 | and here : https://www.youtube.com/watch?v=546j1f_qA50 96 | -------------------------------------------------------------------------------- /main3.c: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | * GPS car tracker on ATTINY2313 / ATTINY2313A + SIM800L module version 2.0 3 | * by Adam Loboda - adam.loboda@wp.pl 4 | * accuracy is nearest GSM cell around locator 5 | * baudrate 9600 6 | * please configure SIM800L to fixed 9600 first by AT+IPR=9600 command 7 | * to ensure stability ans save config via AT&W command 8 | * because of sleepmode use on ATTINY2313 : INT0 pin (#6) of ATTINY2313/4313 9 | * must be connected to RI/RING ping on SIM800L module 10 | * RING low voltage state initiates interrupt INT0 and wakes up ATTINY 11 | * --------------------------------------------------------------------------- 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define UART_NO_DATA 0x0100 26 | // internal RC 8MHz oscillator with DIVISION by 8, gives 0.2% error rate for 9600 bps UART speed 27 | // for 1Meg : -U lfuse:w:0x64:m -U hfuse:w:0xdf:m 28 | #define F_CPU 1000000UL 29 | 30 | #define BAUD 9600 31 | // there is FCPU = 8MHz with division by 8 clock = 1MHz, and we are using U2X bit for better accuracy 32 | // UBRR formula for U2X = 1 33 | #define MYUBBR ((F_CPU / (BAUD * 8L)) - 1) 34 | 35 | const char AT[] PROGMEM = { "AT\n\r" }; // wakeup from sleep mode 36 | const char ISOK[] PROGMEM = { "OK" }; 37 | const char ISRING[] PROGMEM = { "RING" }; 38 | const char ISREG1[] PROGMEM = { "+CREG: 0,1" }; // registered in HPLMN 39 | const char ISREG2[] PROGMEM = { "+CREG: 0,5" }; // registered in ROAMING NETWORK 40 | const char SHOW_REGISTRATION[] PROGMEM = {"AT+CREG?\n\r"}; 41 | const char PIN_IS_READY[] PROGMEM = {"+CPIN: READY"}; 42 | const char PIN_MUST_BE_ENTERED[] PROGMEM = {"+CPIN: SIM PIN"}; 43 | 44 | const char SHOW_PIN[] PROGMEM = {"AT+CPIN?\n\r"}; 45 | const char ECHO_OFF[] PROGMEM = {"ATE0\n\r"}; 46 | const char ENTER_PIN[] PROGMEM = {"AT+CPIN=\"1111\"\n\r"}; 47 | const char CFGRIPIN[] PROGMEM = {"AT+CFGRI=1\n\r"}; 48 | const char HANGUP[] PROGMEM = {"ATH\n\r"}; 49 | const char SMS1[] PROGMEM = {"AT+CMGF=1\r\n"}; 50 | const char SMS2[] PROGMEM = {"AT+CMGS=\""}; // for other networks if they show +XX in CLIP 51 | const char DELSMS[] PROGMEM = {"AT+CMGDA=\"DEL ALL\"\r\n"}; 52 | 53 | const char CRLF[] PROGMEM = {"\"\n\r"}; 54 | const char CLIP[] PROGMEM = {"AT+CLIP=1\r\n"}; 55 | 56 | // Flightmode ON OFF - for saving battery in underground garage 57 | const char FLIGHTON[] PROGMEM = { "AT+CFUN=4\r\n" }; 58 | const char FLIGHTOFF[] PROGMEM = { "AT+CFUN=1\r\n" }; 59 | 60 | // Sleepmode ON OFF 61 | const char SLEEPON[] PROGMEM = { "AT+CSCLK=2\r\n" }; 62 | const char SLEEPOFF[] PROGMEM = { "AT+CSCLK=0\r\n" }; 63 | 64 | // Fix UART speed to 9600 bps 65 | const char SET9600[] PROGMEM = { "AT+IPR=9600\r\n" }; 66 | 67 | // Save settings to SIM800L 68 | const char SAVECNF[] PROGMEM = { "AT&W\r\n" }; 69 | 70 | // Disable SIM800L LED for further reduction of power consumption 71 | //const char DISABLELED[] PROGMEM = { "AT+CNETLIGHT=0\r\n" }; 72 | 73 | // for sending SMS predefined text 74 | const char GOOGLELOC1[] PROGMEM = {"\r\n http://maps.google.com/maps?q="}; 75 | const char GOOGLELOC2[] PROGMEM = {","}; 76 | const char GOOGLELOC3[] PROGMEM = {"\r\n"}; 77 | const char LONG[] PROGMEM = {" UTC\n LONG="}; 78 | const char LATT[] PROGMEM = {" LATT="}; 79 | 80 | // definition of APN used for GPRS communication 81 | // please put correct APN, USERNAME and PASSWORD here appropriate 82 | // for your Mobile Network provider 83 | const char SAPBR1[] PROGMEM = {"AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r\n"}; 84 | const char SAPBR2[] PROGMEM = {"AT+SAPBR=3,1,\"APN\",\"internet\"\r\n"}; // Put your mobile operator APN name here 85 | const char SAPBR3[] PROGMEM = {"AT+SAPBR=3,1,\"USER\",\"internet\"\r\n"}; // Put your mobile operator APN username here 86 | const char SAPBR4[] PROGMEM = {"AT+SAPBR=3,1,\"PWD\",\"internet\"\r\n"}; // Put your mobile operator APN password here 87 | // PDP context commands 88 | const char SAPBROPEN[] PROGMEM = {"AT+SAPBR=1,1\r\n"}; // open IP bearer 89 | const char SAPBRQUERY[] PROGMEM = {"AT+SAPBR=2,1\r\n"}; // query IP bearer 90 | const char SAPBRCLOSE[] PROGMEM = {"AT+SAPBR=0,1\r\n"}; // close bearer 91 | const char SAPBRSUCC[] PROGMEM = {"+SAPBR: 1,1"}; // bearer was succesfull we are not checking IP assigned 92 | const char CHECKGPS[] PROGMEM = {"AT+CIPGSMLOC=1,1\r\n"}; // check GPS position of nearest GSM CELL via Google API 93 | 94 | 95 | #define BUFFER_SIZE 40 96 | // buffers for number of phone, responses from modem, longtitude & latitude data 97 | volatile static uint8_t response[BUFFER_SIZE] = "1234567890123456789012345678901234567890"; 98 | volatile static uint8_t response_pos = 0; 99 | volatile static uint8_t phonenumber[15] = "123456789012345"; 100 | volatile static uint8_t phonenumber_pos = 0; 101 | volatile static uint8_t latitude[10] = "1234567890"; 102 | volatile static uint8_t latitude_pos = 0; 103 | volatile static uint8_t longtitude[10] = "1234567890"; 104 | volatile static uint8_t longtitude_pos = 0; 105 | volatile static uint8_t buf[20]; // buffer to copy string from PROGMEM 106 | 107 | // ********************************************************************************************************* 108 | // init_uart 109 | // ********************************************************************************************************* 110 | void init_uart(void) { 111 | // set U2X bit so we can get 9600baud with lowest error rate 0.2% 112 | UCSRA = (1 << U2X); 113 | // set baud rate 114 | UBRRH = (uint8_t)(MYUBBR >> 8); 115 | UBRRL = (uint8_t)(MYUBBR); 116 | // enable receive and transmit and NO INTERRUPT 117 | UCSRB = (1 << RXEN) | (1 << TXEN) ; 118 | // set frame format 119 | UCSRC = (0 << USBS) | (3 << UCSZ0); // asynchron 8n1 120 | // UCSRC = (1 << USBS) | (3 << UCSZ0); 121 | } 122 | 123 | 124 | // ********************************************************************************************************* 125 | // send_uart 126 | // Sends a single char to UART without ISR 127 | // ********************************************************************************************************* 128 | void send_uart(uint8_t c) { 129 | // wait for empty data register 130 | while (!(UCSRA & (1< 0) // this is EoL 212 | { response[response_pos] = NULL; 213 | response_pos = 0; 214 | wholeline = 1; }; 215 | // just skip this CRLF character and wait for valuable one 216 | 217 | }; 218 | // if buffer is empty exit from function there is nothing to read from 219 | i++; 220 | } while ( wholeline == 0); 221 | 222 | return 1; 223 | } 224 | 225 | 226 | // ********************************************************************************************************* 227 | // READ CELL GPS from AT+CIPGSMLOC output and put output to 'lattitude' and 'longtitude' buffers 228 | // ********************************************************************************************************* 229 | uint8_t readcellgps() 230 | { 231 | uint16_t char1; 232 | uint8_t i; 233 | // wait for first COMMA, set positions to start of each buffer 234 | longtitude_pos = 0; 235 | latitude_pos = 0; 236 | response_pos = 0; 237 | 238 | // wait for first COMMA sign 239 | do { 240 | char1 = receive_uart(); 241 | } while ( char1 != ',' ); 242 | 243 | // if COMMA detected start to copy the response - LONGTITUDE first 244 | do { 245 | char1 = receive_uart(); 246 | longtitude[longtitude_pos] = char1; 247 | longtitude_pos++; 248 | } while ( char1 != ',' ); 249 | longtitude[longtitude_pos-1] = NULL; 250 | longtitude_pos=0; 251 | 252 | // if COMMA detected start to copy the response - LATITUDE second 253 | do { 254 | char1 = receive_uart(); 255 | latitude[latitude_pos] = char1; 256 | latitude_pos++; 257 | } while ( char1 != ',' ); 258 | // put end of string to latitude 259 | latitude[latitude_pos-1] = NULL; 260 | latitude_pos=0; 261 | 262 | // Now copy DATE & TIME UTC to response buffer and wait for CRLF to finish 263 | do { 264 | char1 = receive_uart(); 265 | response[response_pos] = char1; 266 | response_pos++; 267 | } while ( (char1 != '\r') && (char1 != '\n') ); // WAIT FOR CR LF 268 | response[response_pos-1] = NULL; 269 | response_pos=0; 270 | char1 = receive_uart(); // read last CR or LF and exit 271 | return 1; 272 | } 273 | 274 | 275 | // ********************************************************************************************************* 276 | // read PHONE NUMBER from AT+CLIP output and copy it to buffer for SMS sending 277 | // ********************************************************************************************************* 278 | uint8_t readphonenumber() 279 | { 280 | uint16_t char1; 281 | // wait for first quotation 282 | phonenumber_pos = 0; 283 | // wait for first quotation sign 284 | do { 285 | char1 = receive_uart(); 286 | } while ( char1 != '\"' ); 287 | // if quotation detected start to copy the response - phonenumber 288 | do { 289 | char1 = receive_uart(); 290 | phonenumber[phonenumber_pos] = char1; 291 | phonenumber_pos++; 292 | } while ( char1 != '\"' ); // until end of quotation 293 | // put NULL to end the string phonenumber 294 | phonenumber[phonenumber_pos-1] = NULL; 295 | phonenumber_pos=0; 296 | // wait for CRLF for new response to empty RX buffer 297 | do { 298 | char1 = receive_uart(); 299 | } while ( char1 != 0x0a && char1 != 0x0d ); 300 | return 1; 301 | } 302 | 303 | 304 | 305 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 306 | // delay procedure ASM based because _delay_ms() is working bad for 8 MHz clock MCU 307 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 308 | 309 | // delay partucular number of seconds 310 | 311 | void delay_sec(uint8_t i) 312 | { 313 | while(i > 0) 314 | { 315 | // Generated by delay loop calculator 316 | // at http://www.bretmulvey.com/avrdelay.html 317 | // 318 | // Delay 1 000 000 cycles 319 | // 1s at 1 MHz 320 | 321 | asm volatile ( 322 | " ldi r18, 6" "\n" 323 | " ldi r19, 19" "\n" 324 | " ldi r20, 174" "\n" 325 | "1: dec r20" "\n" 326 | " brne 1b" "\n" 327 | " dec r19" "\n" 328 | " brne 1b" "\n" 329 | " dec r18" "\n" 330 | " brne 1b" "\n" 331 | " rjmp 1f" "\n" 332 | "1:" "\n" 333 | ); 334 | 335 | i--; // decrease another second 336 | 337 | }; // repeat until i not zero 338 | 339 | } 340 | 341 | 342 | ////////////////////////////////////////// 343 | // SIM800L initialization procedures 344 | ////////////////////////////////////////// 345 | 346 | // ********************************************************************************************************* 347 | // wait for first AT in case SIM800L is starting up 348 | // ********************************************************************************************************* 349 | uint8_t checkat() 350 | { 351 | uint8_t initialized2; 352 | 353 | // wait for first OK while sending AT - autosensing speed on SIM800L, but we are working 9600 bps 354 | // SIM 800L can be set by AT+IPR=9600 to fix this speed 355 | // which I do recommend by connecting SIM800L to PC using putty and FTD232 cable 356 | 357 | initialized2 = 0; 358 | do { 359 | uart_puts_P(AT); 360 | if (readline()>0) 361 | { 362 | memcpy_P(buf, ISOK, sizeof(ISOK)); 363 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 364 | }; 365 | delay_sec(1); 366 | } while (initialized2 == 0); 367 | 368 | // send ECHO OFF 369 | uart_puts_P(ECHO_OFF); 370 | 371 | return initialized2; 372 | } 373 | 374 | // ********************************************************************************************************* 375 | // check if PIN is needed and enter PIN 1111 376 | // ********************************************************************************************************* 377 | uint8_t checkpin() 378 | { 379 | 380 | uint8_t initialized2; 381 | // readline and wait for PIN CODE STATUS if needed send PIN 1111 to SIM card if required 382 | initialized2 = 0; 383 | do { 384 | delay_sec(2); 385 | uart_puts_P(SHOW_PIN); 386 | if (readline()>0) 387 | { 388 | memcpy_P(buf, PIN_IS_READY, sizeof(PIN_IS_READY)); 389 | if (is_in_rx_buffer(response, buf ) == 1) initialized2 = 1; 390 | memcpy_P(buf, PIN_MUST_BE_ENTERED, sizeof(PIN_MUST_BE_ENTERED)); 391 | if (is_in_rx_buffer(response, buf) == 1) 392 | { uart_puts_P(ENTER_PIN); // ENTER PIN 1111 393 | delay_sec(1); 394 | }; 395 | }; 396 | 397 | } while (initialized2 == 0); 398 | return initialized2; 399 | } 400 | 401 | 402 | // ********************************************************************************************************* 403 | // check if registered to the network 404 | // ********************************************************************************************************* 405 | uint8_t checkregistration() 406 | { 407 | uint8_t initialized2, nbrminutes; 408 | // readline and wait for STATUS NETWORK REGISTRATION from SIM800L 409 | // first 2 networks preferred from SIM list are OK 410 | initialized2 = 0; 411 | nbrminutes = 0; 412 | do { 413 | // give reasonable time to search for GSM network - 3 minutes is sufficient 414 | delay_sec(180); 415 | // check now if registered 416 | uart_puts_P(SHOW_REGISTRATION); 417 | if (readline()>0) 418 | { 419 | memcpy_P(buf, ISREG1, sizeof(ISREG1)); 420 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 421 | memcpy_P(buf, ISREG2, sizeof(ISREG2)); 422 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 423 | } 424 | // if not registered or something wrong turn off RADIO for some time (battery) and turn it on again 425 | // this is not to drain battery in underground garage 426 | else 427 | { 428 | delay_sec(1); 429 | uart_puts_P(FLIGHTON); // enable airplane mode - turn off radio for 60 minutes 430 | for (nbrminutes=0; nbrminutes<60; nbrminutes++) delay_sec(60); 431 | uart_puts_P(FLIGHTOFF); // disable airplane mode - turn on radio and start to search for networks 432 | }; 433 | // end of DO loop 434 | } while (initialized2 == 0); 435 | 436 | return initialized2; 437 | }; 438 | 439 | 440 | // ********************************************************************************************************* 441 | // provision GPRS APNs and passwords - we are not checking if any error not to get deadlocks 442 | // ********************************************************************************************************* 443 | uint8_t provisiongprs() 444 | { 445 | // connection to GPRS for AGPS basestation data - provision APN and username 446 | delay_sec(1); 447 | uart_puts_P(SAPBR1); 448 | delay_sec(1); 449 | uart_puts_P(SAPBR2); 450 | // only if username password in APN is needed 451 | delay_sec(1); 452 | uart_puts_P(SAPBR3); 453 | delay_sec(1); 454 | uart_puts_P(SAPBR4); 455 | delay_sec(1); 456 | return 1; 457 | } 458 | 459 | ////////////////////////////////////////////////////////////////// 460 | // POWER SAVING mode handling to reduce the battery consumption 461 | ////////////////////////////////////////////////////////////////// 462 | 463 | void sleepnow(void) 464 | { 465 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 466 | 467 | sleep_enable(); 468 | 469 | MCUCR &= ~(_BV(ISC01) | _BV(ISC00)); //INT0 on low level - INT0 must be connected to RING pin on SIM800L 470 | GIMSK |= _BV(INT0); //enable INT0 471 | 472 | cli(); //stop interrupts to ensure the BOD timed sequence executes as required 473 | 474 | sei(); //ensure interrupts enabled so we can wake up again 475 | 476 | sleep_cpu(); //go to sleep 477 | 478 | sleep_disable(); //wake up here 479 | } 480 | 481 | // when interrupt from INT0 disable next interrupts from RING pin of SIM800L 482 | ISR(INT0_vect) 483 | { 484 | GIMSK = 0; //disable external interrupts (only need one to wake up) 485 | } 486 | 487 | 488 | 489 | // ********************************************************************************************************* 490 | // 491 | // MAIN PROGRAM 492 | // 493 | // ********************************************************************************************************* 494 | 495 | int main(void) { 496 | 497 | uint8_t initialized, attempt = 0; 498 | 499 | //char buf[20]; // buffer to copy string from PROGMEM 500 | 501 | 502 | // initialize 9600 baud 8N1 RS232 503 | init_uart(); 504 | 505 | // delay 10 seconds for safe SIM800L startup and network registration 506 | delay_sec(10); 507 | 508 | 509 | // try to communicate with SIM800L over AT 510 | initialized = checkat(); 511 | delay_sec(2); 512 | 513 | // Fix UART speed to 9600 bps to disable autosensing 514 | uart_puts_P(SET9600); 515 | delay_sec(2); 516 | 517 | // configure RI PIN activity for URC ( unsolicited messages like restart of the modem or battery low) 518 | uart_puts_P(CFGRIPIN); 519 | delay_sec(2); 520 | 521 | // Save settings to SIM800L 522 | uart_puts_P(SAVECNF); 523 | delay_sec(3); 524 | 525 | // check pin status, registration status and provision APN settings 526 | checkpin(); 527 | checkregistration(); 528 | provisiongprs(); 529 | 530 | // read phone number of incoming voice call by CLIP, will be needed for SMS sending 531 | uart_puts_P(CLIP); 532 | delay_sec(2); 533 | //and close the beare just in case it was open 534 | uart_puts_P(SAPBRCLOSE); 535 | delay_sec(2); 536 | 537 | // neverending LOOP 538 | 539 | while (1) { 540 | 541 | do { 542 | 543 | // delete all SMSes and SMS confirmation to keep SIM800L memory empty 544 | uart_puts_P(SMS1); 545 | delay_sec(2); 546 | uart_puts_P(DELSMS); 547 | delay_sec(3); 548 | 549 | // WAIT FOR RING message - incoming voice call and send SMS or restart RADIO module if no signal 550 | initialized = 0; 551 | 552 | // Disable LED blinking on SIM800L 553 | // uart_puts_P(DISABLELED); 554 | // delay_sec(2); 555 | 556 | // enter SLEEP MODE of SIM800L for power saving ( will be interrupted by incoming voice call or SMS ) 557 | uart_puts_P(SLEEPON); 558 | delay_sec(2); 559 | 560 | // enter SLEEP MODE on ATTINY2313 for power saving 561 | sleepnow(); // sleep function called here 562 | 563 | // THERE WAS RI / INT0 INTERRUPT AND SOMETHING WAS SEND OVER SERIAL WE NEED TO GET OFF SLEEPMODE AND READ SERIAL PORT 564 | if (readline()>0) 565 | { 566 | memcpy_P(buf, ISRING, sizeof(ISRING)); 567 | if (is_in_rx_buffer(response, buf) == 1) 568 | { initialized = 1; 569 | // read phonenumber for text message from CLIP output 570 | readphonenumber(); 571 | // disable SLEEPMODE , hangup a call and proceed with sending SMS 572 | uart_puts_P(AT); 573 | delay_sec(1); 574 | uart_puts_P(SLEEPOFF); 575 | delay_sec(1); 576 | uart_puts_P(HANGUP); 577 | delay_sec(1); 578 | } // end of IF 579 | 580 | // if some other message than RING check if network is avaialble and SIM800L is operational 581 | else 582 | { 583 | // disable SLEEPMODE 584 | uart_puts_P(AT); 585 | delay_sec(1); 586 | uart_puts_P(SLEEPOFF); 587 | delay_sec(1); 588 | // check status of all functions 589 | checkpin(); 590 | checkregistration(); 591 | provisiongprs(); 592 | // read phone number of incoming voice call by CLIP, will be needed for SMS sending 593 | uart_puts_P(CLIP); 594 | delay_sec(2); 595 | //and close the beare just in case it was open 596 | uart_puts_P(SAPBRCLOSE); 597 | delay_sec(2); 598 | // there was something different than RING so we need to go back to the beginning 599 | initialized = 0; 600 | }; // end of ELSE 601 | 602 | }; // END of READLINE IF 603 | 604 | } while ( initialized == 0); // end od DO-WHILE, go to begging and enter SLEEPMODE again 605 | 606 | // clear the flag we gonna need it later 607 | initialized = 0; 608 | 609 | // Create connection to GPRS network - 3 attempts if needed, if not succesfull restart the modem 610 | attempt = 0; 611 | do { 612 | 613 | //and close the bearer first maybe there was an error or something 614 | uart_puts_P(SAPBRCLOSE); 615 | 616 | // make GPRS network attach and open IP bearer 617 | delay_sec(2); 618 | uart_puts_P(SAPBROPEN); 619 | 620 | // query PDP context for IP address after several seconds 621 | // check if GPRS attach was succesfull, do it several times if needed 622 | initialized = 0; 623 | delay_sec(5); 624 | uart_puts_P(SAPBRQUERY); 625 | if (readline()>0) 626 | { 627 | // checking for properly attached 628 | memcpy_P(buf, SAPBRSUCC, sizeof(SAPBRSUCC)); 629 | if (is_in_rx_buffer(response, buf) == 1) initialized = 1; 630 | // other responses simply ignored as there was no attach 631 | }; 632 | // increase attempt counter and repeat until not attached 633 | attempt++; 634 | } while ( (attempt < 3) && (initialized == 0) ); 635 | 636 | 637 | // if GPRS was succesfull the it is time send cell info to Google and query the GPS location 638 | if (initialized == 1) 639 | { 640 | // GET CELL ID OF BASE STATION and query Google for coordinates then send over SMS with google map loc 641 | delay_sec(1); 642 | uart_puts_P(CHECKGPS); 643 | // parse GPS coordinates from the answer to SMS buffer 644 | readcellgps(); 645 | // send a SMS in plain text format 646 | delay_sec(1); 647 | uart_puts_P(SMS1); 648 | delay_sec(1); 649 | // compose an SMS from fragments - interactive mode CTRL Z at the end 650 | uart_puts_P(SMS2); 651 | uart_puts(phonenumber); // send phone number received from CLIP 652 | uart_puts_P(CRLF); 653 | delay_sec(1); 654 | // put info about DATE,TIME, LONG, LATT 655 | uart_puts(response); // send Date & Time info from AGPS cell info 656 | uart_puts_P(LONG); // send LONGTITUDE 657 | uart_puts(longtitude); // from buffer 658 | uart_puts_P(LATT); // send LATITUDE 659 | uart_puts(latitude); // from buffer 660 | // put link to GOOGLE MAPS 661 | uart_puts_P(GOOGLELOC1); // send http **** 662 | uart_puts(latitude); // send Cellinfo 663 | uart_puts_P(GOOGLELOC2); // send comma 664 | uart_puts(longtitude); // send Cellinfo 665 | uart_puts_P(GOOGLELOC3); // send CRLF 666 | delay_sec(1); 667 | send_uart(26); // ctrl Z to end SMS 668 | 669 | //and close the bearer 670 | delay_sec(5); 671 | uart_puts_P(SAPBRCLOSE); 672 | } /// end of commands when GPRS is working 673 | 674 | 675 | delay_sec(10); 676 | // go to the beginning and enter sleepmode on SIM800L and ATTINY2313 again for power saving 677 | 678 | // end of neverending loop 679 | }; 680 | 681 | 682 | // end of MAIN code 683 | } 684 | 685 | -------------------------------------------------------------------------------- /main3b.c: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------------------------------- 2 | * GPS car tracker on ATTINY2313 / ATTINY2313A + SIM800L module version 3.0 3 | * by Adam Loboda - adam.loboda@wp.pl 4 | * accuracy is nearest GSM cell around locator 5 | * baudrate 9600 6 | * please configure SIM800L to fixed 9600 first by AT+IPR=9600 command 7 | * to ensure stability ans save config via AT&W command 8 | * in this program ATTINY never goes to sleep - but RI/RING PIN must be connected too INT0 PIND2 9 | * FCPU clock is lowered to 1MHz so we get total power consumption ~5mA 10 | * (SIM800L takes 2mA of it) and working time is 2 weeks on 3xAA batteries 11 | * ---------------------------------------------------------------------------------------------- 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define UART_NO_DATA 0x0100 26 | // internal RC 8MHz oscillator with DIVISION by 8, gives 0.2% error rate for 9600 bps UART speed 27 | // for 1Meg : -U lfuse:w:0x64:m -U hfuse:w:0xdf:m 28 | #define F_CPU 1000000UL 29 | 30 | const char AT[] PROGMEM = { "AT\n\r" }; 31 | const char ISOK[] PROGMEM = { "OK" }; 32 | const char ISRING[] PROGMEM = { "RING" }; 33 | const char ISREG1[] PROGMEM = { "+CREG: 0,1" }; // registered in HPLMN 34 | const char ISREG2[] PROGMEM = { "+CREG: 0,5" }; // registered in ROAMING NETWORK 35 | const char SHOW_REGISTRATION[] PROGMEM = {"AT+CREG?\n\r"}; 36 | const char DISREGURC[] PROGMEM = {"AT+CREG=0\n\r"}; // we do not want URC for lost coverage... 37 | const char PIN_IS_READY[] PROGMEM = {"+CPIN: READY"}; 38 | const char PIN_MUST_BE_ENTERED[] PROGMEM = {"+CPIN: SIM PIN"}; 39 | 40 | const char SHOW_PIN[] PROGMEM = {"AT+CPIN?\n\r"}; 41 | const char ECHO_OFF[] PROGMEM = {"ATE0\n\r"}; 42 | const char ENTER_PIN[] PROGMEM = {"AT+CPIN=\"1111\"\n\r"}; 43 | const char HANGUP[] PROGMEM = {"ATH\n\r"}; 44 | const char SMS1[] PROGMEM = {"AT+CMGF=1\r\n"}; 45 | const char SMS2[] PROGMEM = {"AT+CMGS=\""}; 46 | const char DELSMS[] PROGMEM = {"AT+CMGDA=\"DEL ALL\"\r\n"}; 47 | 48 | 49 | const char CRLF[] PROGMEM = {"\"\n\r"}; 50 | const char CLIP[] PROGMEM = {"AT+CLIP=1\r\n"}; 51 | 52 | // Flightmode ON OFF - for saving battery in underground garage 53 | const char FLIGHTON[] PROGMEM = { "AT+CFUN=4\r\n" }; 54 | const char FLIGHTOFF[] PROGMEM = { "AT+CFUN=1\r\n" }; 55 | 56 | // Sleepmode ON OFF 57 | const char SLEEPON[] PROGMEM = { "AT+CSCLK=2\r\n" }; 58 | const char SLEEPOFF[] PROGMEM = { "AT+CSCLK=0\r\n" }; 59 | 60 | // Fix UART speed to 9600 bps 61 | const char SET9600[] PROGMEM = { "AT+IPR=9600\r\n" }; 62 | 63 | // Save settings to SIM800L 64 | const char SAVECNF[] PROGMEM = { "AT&W\r\n" }; 65 | 66 | // for sending SMS predefined text 67 | const char GOOGLELOC1[] PROGMEM = {"\r\n http://maps.google.com/maps?q="}; 68 | const char GOOGLELOC2[] PROGMEM = {","}; 69 | const char GOOGLELOC3[] PROGMEM = {"\r\n"}; 70 | const char LONG[] PROGMEM = {" UTC\n LONG="}; 71 | const char LATT[] PROGMEM = {" LATT="}; 72 | 73 | // definition of APN used for GPRS communication 74 | // please put correct APN, USERNAME and PASSWORD here appropriate 75 | // for your Mobile Network provider 76 | const char SAPBR1[] PROGMEM = {"AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r\n"}; 77 | const char SAPBR2[] PROGMEM = {"AT+SAPBR=3,1,\"APN\",\"internet\"\r\n"}; // Put your mobile operator APN name here 78 | const char SAPBR3[] PROGMEM = {"AT+SAPBR=3,1,\"USER\",\"internet\"\r\n"}; // Put your mobile operator APN username here 79 | const char SAPBR4[] PROGMEM = {"AT+SAPBR=3,1,\"PWD\",\"internet\"\r\n"}; // Put your mobile operator APN password here 80 | // PDP context commands 81 | const char SAPBROPEN[] PROGMEM = {"AT+SAPBR=1,1\r\n"}; // open IP bearer 82 | const char SAPBRQUERY[] PROGMEM = {"AT+SAPBR=2,1\r\n"}; // query IP bearer 83 | const char SAPBRCLOSE[] PROGMEM = {"AT+SAPBR=0,1\r\n"}; // close bearer 84 | const char SAPBRSUCC[] PROGMEM = {"+SAPBR: 1,1"}; // bearer was succesfull we are not checking IP assigned 85 | const char CHECKGPS[] PROGMEM = {"AT+CIPGSMLOC=1,1\r\n"}; // check GPS position of nearest GSM CELL via Google Api 86 | 87 | 88 | 89 | 90 | #define BAUD 9600 91 | // there is FCPU = 8MHz with division by 8 clock = 1MHz, and we are using U2X bit for better accuracy 92 | // UBRR formula for U2X = 1 93 | #define MYUBBR ((F_CPU / (BAUD * 8L)) - 1) 94 | 95 | #define BUFFER_SIZE 40 96 | // buffers for number of phone, responses from modem, longtitude & latitude data 97 | volatile static uint8_t response[BUFFER_SIZE] = "1234567890123456789012345678901234567890"; 98 | volatile static uint8_t response_pos = 0; 99 | volatile static uint8_t phonenumber[15] = "123456789012345"; 100 | volatile static uint8_t phonenumber_pos = 0; 101 | volatile static uint8_t latitude[10] = "1234567890"; 102 | volatile static uint8_t latitude_pos = 0; 103 | volatile static uint8_t longtitude[10] = "1234567890"; 104 | volatile static uint8_t longtitude_pos = 0; 105 | volatile static uint8_t buf[20]; // buffer to copy string from PROGMEM 106 | 107 | 108 | // ----------------------------------------------------------------------------------------------------------- 109 | // init_uart 110 | // ----------------------------------------------------------------------------------------------------------- 111 | void init_uart(void) { 112 | 113 | // set U2X bit so we can get 9600baud with lowest error rate 0.2% 114 | UCSRA = (1 << U2X); 115 | // set baud rate 116 | UBRRH = (uint8_t)(MYUBBR >> 8); 117 | UBRRL = (uint8_t)(MYUBBR); 118 | // enable receive and transmit and NO INTERRUPT 119 | UCSRB = (1 << RXEN) | (1 << TXEN) ; 120 | // set frame format 121 | UCSRC = (0 << USBS) | (3 << UCSZ0); // asynchron 8n1 122 | // UCSRC = (1 << USBS) | (3 << UCSZ0); 123 | 124 | } 125 | 126 | 127 | 128 | // ----------------------------------------------------------------------------------------------------------- 129 | // send_uart 130 | // Sends a single char to UART without ISR 131 | // ----------------------------------------------------------------------------------------------------------- 132 | void send_uart(uint8_t c) { 133 | // wait for empty data register 134 | while (!(UCSRA & (1< 0) // this is EoL 221 | { response[response_pos] = NULL; 222 | response_pos = 0; 223 | wholeline = 1; }; 224 | // just skip this CRLF character and wait for valuable one 225 | 226 | }; 227 | // if buffer is empty exit from function there is nothing to read from 228 | i++; 229 | } while ( wholeline == 0); 230 | return(1); 231 | } 232 | 233 | 234 | // ----------------------------------------------------------------------------------------------------------- 235 | // READ CELL GPS from AT+CIPGSMLOC output and put output to 'lattitude' and 'longtitude' buffers 236 | // ----------------------------------------------------------------------------------------------------------- 237 | uint8_t readcellgps() 238 | { 239 | uint16_t char1; 240 | uint8_t i; 241 | // wait for first COMMA, set positions to start of each buffer 242 | longtitude_pos = 0; 243 | latitude_pos = 0; 244 | response_pos = 0; 245 | 246 | // wait for first COMMA sign 247 | do { 248 | char1 = receive_uart(); 249 | } while ( char1 != ',' ); 250 | 251 | // if COMMA detected start to copy the response - LONGTITUDE first 252 | do { 253 | char1 = receive_uart(); 254 | longtitude[longtitude_pos] = char1; 255 | longtitude_pos++; 256 | } while ( char1 != ',' ); 257 | longtitude[longtitude_pos-1] = NULL; 258 | longtitude_pos=0; 259 | 260 | // if COMMA detected start to copy the response - LATITUDE second 261 | do { 262 | char1 = receive_uart(); 263 | latitude[latitude_pos] = char1; 264 | latitude_pos++; 265 | } while ( char1 != ',' ); 266 | // put end of string to latitude 267 | latitude[latitude_pos-1] = NULL; 268 | latitude_pos=0; 269 | 270 | // Now copy DATE & TIME UTC to response buffer and wait for CRLF to finish 271 | do { 272 | char1 = receive_uart(); 273 | response[response_pos] = char1; 274 | response_pos++; 275 | } while ( (char1 != '\r') && (char1 != '\n') ); // WAIT FOR CR LF 276 | response[response_pos-1] = NULL; 277 | response_pos=0; 278 | char1 = receive_uart(); // read last CR or LF and exit 279 | 280 | return (1); 281 | } 282 | 283 | // -------------------------------------------------------------------------------------------- 284 | // read PHONE NUMBER from AT+CLIP output and copy it to buffer for SMS sending 285 | // -------------------------------------------------------------------------------------------- 286 | uint8_t readphonenumber() 287 | { 288 | uint16_t char1; 289 | // wait for first quotation 290 | phonenumber_pos = 0; 291 | 292 | // wait for ':' sign 293 | do { 294 | char1 = receive_uart(); 295 | } while ( char1 != ':' ); 296 | 297 | // wait for first quotation sign 298 | do { 299 | char1 = receive_uart(); 300 | } while ( char1 != '\"' ); 301 | // if quotation detected start to copy the response - phonenumber 302 | do { 303 | char1 = receive_uart(); 304 | phonenumber[phonenumber_pos] = char1; 305 | phonenumber_pos++; 306 | } while ( char1 != '\"' ); // until end of quotation 307 | // put NULL to end the string phonenumber 308 | phonenumber[phonenumber_pos-1] = NULL; 309 | phonenumber_pos=0; 310 | // wait for CRLF for new response to empty RX buffer 311 | do { 312 | char1 = receive_uart(); 313 | } while ( char1 != 0x0a && char1 != 0x0d ); 314 | return (1); 315 | } 316 | 317 | 318 | 319 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 320 | // delay procedure ASM based because _delay_ms() is working bad for 8 MHz clock MCU 321 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 322 | 323 | // -------------------------------------------------------------------------------------------- 324 | // delay partucular number of seconds (up to UINT8 = 255 seconds) 325 | // -------------------------------------------------------------------------------------------- 326 | 327 | void delay_sec(uint8_t i) 328 | { 329 | while(i > 0) 330 | { 331 | // Generated by delay loop calculator 332 | // at http://www.bretmulvey.com/avrdelay.html 333 | // 334 | // Delay 1 000 000 cycles 335 | // 1s at 1 MHz 336 | 337 | asm volatile ( 338 | " ldi r18, 6" "\n" 339 | " ldi r19, 19" "\n" 340 | " ldi r20, 174" "\n" 341 | "1: dec r20" "\n" 342 | " brne 1b" "\n" 343 | " dec r19" "\n" 344 | " brne 1b" "\n" 345 | " dec r18" "\n" 346 | " brne 1b" "\n" 347 | " rjmp 1f" "\n" 348 | "1:" "\n" 349 | ); 350 | 351 | 352 | i--; // decrease another second 353 | 354 | }; // repeat until i not zero 355 | 356 | } 357 | 358 | 359 | ////////////////////////////////////////// 360 | // SIM800L initialization procedures 361 | ////////////////////////////////////////// 362 | 363 | // -------------------------------------------------------------------------------------------- 364 | // wait for first AT in case SIM800L is starting up 365 | // -------------------------------------------------------------------------------------------- 366 | uint8_t checkat() 367 | { 368 | uint8_t initialized2; 369 | 370 | // wait for first OK while sending AT - autosensing speed on SIM800L, but we are working 9600 bps 371 | // SIM 800L can be set by AT+IPR=9600 to fix this speed 372 | // which I do recommend by connecting SIM800L to PC using putty and FTD232 cable 373 | 374 | initialized2 = 0; 375 | do { 376 | uart_puts_P(AT); 377 | if (readline()>0) 378 | { 379 | memcpy_P(buf, ISOK, sizeof(ISOK)); 380 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 381 | }; 382 | } while (initialized2 == 0); 383 | delay_sec(1); 384 | // send ECHO OFF 385 | uart_puts_P(ECHO_OFF); 386 | delay_sec(1); 387 | return 1; 388 | } 389 | 390 | // -------------------------------------------------------------------------------------------- 391 | // check if PIN is needed and enter PIN 1111 392 | // -------------------------------------------------------------------------------------------- 393 | uint8_t checkpin() 394 | { 395 | 396 | uint8_t initialized2; 397 | // readline and wait for PIN CODE STATUS if needed send PIN 1111 to SIM card if required 398 | initialized2 = 0; 399 | do { 400 | delay_sec(2); 401 | uart_puts_P(SHOW_PIN); 402 | if (readline()>0) 403 | { 404 | memcpy_P(buf, PIN_IS_READY, sizeof(PIN_IS_READY)); 405 | if (is_in_rx_buffer(response, buf ) == 1) initialized2 = 1; 406 | memcpy_P(buf, PIN_MUST_BE_ENTERED, sizeof(PIN_MUST_BE_ENTERED)); 407 | if (is_in_rx_buffer(response, buf) == 1) 408 | { 409 | uart_puts_P(ENTER_PIN); // ENTER PIN 1111 410 | }; 411 | }; 412 | 413 | } while (initialized2 == 0); 414 | return (1); 415 | } 416 | 417 | // -------------------------------------------------------------------------------------------- 418 | // check if registered to the network 419 | // -------------------------------------------------------------------------------------------- 420 | uint8_t checkregistration() 421 | { 422 | uint8_t initialized2, nbrminutes; 423 | 424 | // readline and wait for STATUS NETWORK REGISTRATION from SIM800L 425 | // first 2 networks preferred from SIM list are OK 426 | initialized2 = 0; 427 | nbrminutes = 0; 428 | do { 429 | // give reasonable time to search for 2G network 430 | // maybe on the move, so 1 minute would be fine 431 | delay_sec(3); 432 | uart_puts_P(FLIGHTOFF); // disable airplane mode - turn on radio and start to search for networks 433 | delay_sec(60); 434 | // check if network was found 435 | uart_puts_P(SHOW_REGISTRATION); 436 | if (readline()>0) 437 | { 438 | memcpy_P(buf, ISREG1, sizeof(ISREG1)); 439 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 440 | memcpy_P(buf, ISREG2, sizeof(ISREG2)); 441 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 442 | // if no network after 3 minutes of searching we are doing backoff for 1 hour 443 | if (initialized2 == 0) 444 | { 445 | // if not registered or something wrong turn off RADIO for minutes 446 | // this is not to drain battery in underground garage 447 | uart_puts_P(FLIGHTON); // enable airplane mode - turn off radio 448 | delay_sec(1); 449 | // enter SLEEP MODE of SIM800L for power saving when no coverage 450 | uart_puts_P(SLEEPON); 451 | // now wait XX min before turning on radio again, here XX = 30 min 452 | for (nbrminutes = 0; nbrminutes<30; nbrminutes++) 453 | { 454 | delay_sec(60); 455 | }; 456 | // Wake up SIM800L and search for network again 457 | uart_puts_P(AT); 458 | delay_sec(1); 459 | uart_puts_P(SLEEPOFF); 460 | delay_sec(1); 461 | }; 462 | }; // end of READLINE IF 463 | // end of DO loop 464 | } while (initialized2 == 0); 465 | 466 | return (1); 467 | }; 468 | 469 | // -------------------------------------------------------------------------------------------- 470 | // provision GPRS APNs and passwords - we are not checking if any error not to get deadlocks 471 | // -------------------------------------------------------------------------------------------- 472 | uint8_t provisiongprs() 473 | { 474 | // connection to GPRS for AGPS basestation data - provision APN and username 475 | delay_sec(4); 476 | uart_puts_P(SAPBR1); 477 | delay_sec(1); 478 | uart_puts_P(SAPBR2); 479 | // only if username password in APN is needed 480 | delay_sec(1); 481 | uart_puts_P(SAPBR3); 482 | delay_sec(1); 483 | uart_puts_P(SAPBR4); 484 | delay_sec(1); 485 | return (1); 486 | } 487 | 488 | 489 | // ********************************************************************************************************* 490 | // 491 | // MAIN PROGRAM 492 | // 493 | // ********************************************************************************************************* 494 | 495 | int main(void) { 496 | 497 | uint8_t initialized, attempt = 0; 498 | uint16_t nbrseconds = 0; 499 | 500 | // initialize 9600 baud 8N1 RS232 501 | init_uart(); 502 | 503 | // Set PORTD2 / INT0 pin for input (this clears bit DDD2 in the DDR) 504 | // to check SIM800L RI/RING pin status 505 | DDRD &= ~(1 << PD2); // switch on pin INT0 as input (PD2) 506 | PORTD |= (1 << PD2); // enable pull-up resistor 507 | 508 | 509 | // delay 10 seconds for safe SIM800L startup and network registration 510 | delay_sec(10); 511 | 512 | 513 | // try to communicate with SIM800L over AT 514 | checkat(); 515 | 516 | // Fix UART speed to 9600 bps to disable autosensing 517 | uart_puts_P(SET9600); 518 | delay_sec(2); 519 | 520 | // disable reporting of registration status 521 | uart_puts_P(DISREGURC); 522 | delay_sec(2); 523 | 524 | // Save settings to SIM800L 525 | uart_puts_P(SAVECNF); 526 | delay_sec(3); 527 | 528 | // check pin status, registration status 529 | checkpin(); 530 | checkregistration(); 531 | 532 | 533 | 534 | // neverending LOOP 535 | 536 | while (1) { 537 | 538 | do { 539 | 540 | // delete all SMSes and SMS confirmation to keep SIM800L memory empty 541 | uart_puts_P(SMS1); 542 | delay_sec(2); 543 | uart_puts_P(DELSMS); 544 | 545 | // provision GPRS settings for contacting Google API 546 | provisiongprs(); 547 | 548 | // read phone number of incoming voice call by CLIP, will be needed for SMS sending 549 | uart_puts_P(CLIP); 550 | delay_sec(2); 551 | 552 | //and close the bearer just in case it was open 553 | uart_puts_P(SAPBRCLOSE); 554 | delay_sec(2); 555 | 556 | 557 | // WAIT FOR RING message - incoming voice call and send SMS or restart RADIO module if no signal 558 | initialized = 0; 559 | 560 | // enter SLEEP MODE of SIM800L for power saving ( will be interrupted by incoming voice call or SMS ) 561 | uart_puts_P(SLEEPON); 562 | delay_sec(2); 563 | 564 | // while SIM800L sleeping we will be checking SIM800L RI/RING pin status in 1 sec intervals 565 | // because SMS RI LOW state is only 120milisec, we are unable to notice it at all... 566 | // and periodically wake up SIM800L to see coverage status - once per 1 hour 567 | 568 | while(initialized == 0) 569 | { 570 | // check if RI/RING INT0 pin is LOW ? 571 | if ((PIND & (1 << PD2)) == 0) 572 | { initialized = 1; } // if RI = LOW we neeed to get out of WHILE LOOP and process CALL/SMS 573 | else 574 | { // RING signal is HIGH - wait for an hour to check 2G radio status 575 | 576 | nbrseconds++; // increase number of seconds waited 577 | 578 | delay_sec(1); // wait another second 579 | 580 | if (nbrseconds == 1800) 581 | { // if 1800 sec passed, we need to check 2G network coverage 582 | nbrseconds = 0; 583 | // wakeup SIM800L module 584 | uart_puts_P(AT); 585 | delay_sec(1); 586 | uart_puts_P(SLEEPOFF); 587 | // check 2G coverage 588 | checkregistration(); 589 | delay_sec(1); 590 | uart_puts_P(SLEEPON); 591 | delay_sec(2); 592 | // clear the flag that we are still waiting for RING and RI LOW 593 | initialized = 0; 594 | }; 595 | } // end of ELSE and IF checking PIN D2 (INT0/RING) status 596 | }; // end of WHILE for checking 2G coverage 597 | 598 | 599 | // THERE WAS URC message : incoming CALL / SMS or SIM800L restarted itself ? 600 | if (readline()>0) 601 | { 602 | memcpy_P(buf, ISRING, sizeof(ISRING)); 603 | if (is_in_rx_buffer(response, buf) == 1) 604 | { initialized = 1; 605 | readphonenumber(); 606 | // disable SLEEPMODE , hangup a call and proceed with sending SMS 607 | uart_puts_P(AT); 608 | delay_sec(1); 609 | uart_puts_P(SLEEPOFF); 610 | delay_sec(1); 611 | uart_puts_P(HANGUP); 612 | delay_sec(1); 613 | } // end of IF 614 | 615 | // if some other message than RING (f.ex. SMS) simply ignore it and re-provision settings 616 | else 617 | { 618 | 619 | // disable SLEEPMODE and reconfigure all settings 620 | uart_puts_P(AT); 621 | delay_sec(1); 622 | uart_puts_P(SLEEPOFF); 623 | delay_sec(2); 624 | // check the pin maybe SIM800L restarted itself 625 | checkpin(); 626 | // there was something different than RING so keep flag off 627 | // and go to the start of big loop to reprovision CLIP, APN and go to sleep again 628 | initialized = 0; 629 | }; // end of ELSE 630 | 631 | }; // END of READLINE IF 632 | 633 | } while ( initialized == 0); // end od DO-WHILE, go to beggining and enter SLEEPMODE again 634 | 635 | initialized = 0; 636 | 637 | // Create connection to GPRS network - 3 attempts if needed, if not succesfull restart the modem 638 | attempt = 0; 639 | do { 640 | 641 | //and close the bearer first maybe there was an error or something 642 | uart_puts_P(SAPBRCLOSE); 643 | delay_sec(2); 644 | 645 | // make GPRS network attach and open IP bearer 646 | uart_puts_P(SAPBROPEN); 647 | delay_sec(5); 648 | 649 | // query PDP context for IP address after several seconds 650 | // check if GPRS attach was succesfull, do it several times if needed 651 | initialized = 0; 652 | uart_puts_P(SAPBRQUERY); 653 | if (readline()>0) 654 | { 655 | // checking for properly attached 656 | memcpy_P(buf, SAPBRSUCC, sizeof(SAPBRSUCC)); 657 | if (is_in_rx_buffer(response, buf) == 1) initialized = 1; 658 | // other responses simply ignored as there was no attach 659 | }; 660 | // increase attempt counter and repeat until not attached 661 | attempt++; 662 | } while ( (attempt < 3) && (initialized == 0) ); 663 | 664 | 665 | // if GPRS was succesfull the it is time send cell info to Google and query the GPS location 666 | if (initialized == 1) 667 | { 668 | // GET CELL ID OF BASE STATION and query Google for coordinates then send over SMS with google map loc 669 | delay_sec(1); 670 | uart_puts_P(CHECKGPS); 671 | 672 | // parse GPS coordinates from the answer to SMS buffer 673 | readcellgps(); 674 | 675 | // send a SMS in plain text format 676 | delay_sec(1); 677 | uart_puts_P(SMS1); 678 | delay_sec(1); 679 | // compose an SMS from fragments - interactive mode CTRL Z at the end 680 | uart_puts_P(SMS2); 681 | uart_puts(phonenumber); // send phone number received from CLIP 682 | uart_puts_P(CRLF); 683 | delay_sec(1); 684 | // put info about DATE,TIME, LONG, LATT 685 | uart_puts(response); // send Date & Time info from AGPS cell info 686 | uart_puts_P(LONG); // send LONGTITUDE 687 | uart_puts(longtitude); // from buffer 688 | uart_puts_P(LATT); // send LATITUDE 689 | uart_puts(latitude); // from buffer 690 | // put link to GOOGLE MAPS 691 | uart_puts_P(GOOGLELOC1); // send http **** 692 | uart_puts(latitude); // send Cellinfo 693 | uart_puts_P(GOOGLELOC2); // send comma 694 | uart_puts(longtitude); // send Cellinfo 695 | uart_puts_P(GOOGLELOC3); // send CRLF 696 | delay_sec(1); 697 | send_uart(26); // ctrl Z to end SMS 698 | 699 | //and close the bearer 700 | delay_sec(10); 701 | uart_puts_P(SAPBRCLOSE); 702 | } /// end of commands when GPRS is working 703 | 704 | 705 | delay_sec(10); 706 | // go to the beginning and enter sleepmode on SIM800L and ATTINY2313 again for power saving 707 | 708 | // end of neverending loop 709 | }; 710 | 711 | 712 | // end of MAIN code 713 | } 714 | 715 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | * GPS car tracker on ATMEGA328P + SIM800L module version 2.1 3 | * by Adam Loboda - adam.loboda@wp.pl 4 | * a) accuracy is nearest GSM cell around locator 5 | * b) baudrate UART is 9600 as most stable using RC internal clock 6 | * c) ATMEGA clock was lowered to 1MHz (8 MHz div 8) for lower power consumption 7 | * 8 | * other considerations: 9 | * 10 | * please configure SIM800L to fixed 9600 first by AT+IPR=9600 command 11 | * to ensure stability ans save config via AT&W command 12 | * you may do it by connecting FTDI232 serial port converter to PC 13 | * and using putty enter commands directly to SIM800L 14 | * 15 | * because of sleepmode use on ATMEGA328P : INT0 pin (#4) of ATMEGA328P 16 | * must be connected to RI/RING ping on SIM800L module 17 | * RING falling edge initiates interrupt INT0 and wakes up ATMEGA328 18 | * 19 | * other connections to be made : 20 | * SIM800L RXD to ATMEGA328 TXD PIN #3, 21 | * SIM800L TXD to ATMEGA328 RXD PIN #2 22 | * ATMEGA328 VCC (PIN #7) to SIM800L VCC and +4.4V 23 | * ATMEGA328 GND (PIN #8 and PIN #22) to SIM800L GND and 0V 24 | * the rest is the same as on ATTINY2313 schematic 25 | * --------------------------------------------------------------------------- 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #define UART_NO_DATA 0x0100 40 | // internal RC oscillator 8MHz with divison by 8 and U2X0 = 1, gives 0.2% error rate for 9600 bps UART speed 41 | // and lower current consumption 42 | // for 1MHz : -U lfuse:w:0x62:m on ATMEGA328P 43 | #define F_CPU 1000000UL 44 | 45 | #define BAUD 9600 46 | // formula for 1MHz clock and U2X0 = 1 double UART speed 47 | #define MYUBBR ((F_CPU / (BAUD * 8L)) - 1) 48 | 49 | 50 | 51 | const char AT[] PROGMEM = { "AT\n\r" }; 52 | const char ISOK[] PROGMEM = { "OK" }; 53 | const char ISRING[] PROGMEM = { "RING" }; 54 | const char ISREG1[] PROGMEM = { "+CREG: 0,1" }; // SIM registered in HPLMN 55 | const char ISREG2[] PROGMEM = { "+CREG: 0,5" }; // SIM registeref in ROAMING NETWORK 56 | const char SHOW_REGISTRATION[] PROGMEM = {"AT+CREG?\n\r"}; // check registration status 57 | const char DISREGURC[] PROGMEM = {"AT+CREG=0\n\r"}; // we disable realtime reporting of 2G network status 58 | 59 | const char PIN_IS_READY[] PROGMEM = {"+CPIN: READY"}; 60 | const char PIN_MUST_BE_ENTERED[] PROGMEM = {"+CPIN: SIM PIN"}; 61 | 62 | const char SHOW_PIN[] PROGMEM = {"AT+CPIN?\n\r"}; 63 | const char ECHO_OFF[] PROGMEM = {"ATE0\n\r"}; 64 | const char ENTER_PIN[] PROGMEM = {"AT+CPIN=\"1111\"\n\r"}; // put PINCODE of your SIMCARD here if you have different than 1111... 65 | const char CFGRIPIN[] PROGMEM = {"AT+CFGRI=1\n\r"}; 66 | const char HANGUP[] PROGMEM = {"ATH\n\r"}; 67 | 68 | const char SMS1[] PROGMEM = {"AT+CMGF=1\r\n"}; 69 | const char SMS2[] PROGMEM = {"AT+CMGS=\""}; 70 | const char DELSMS[] PROGMEM = {"AT+CMGDA=\"DEL ALL\"\r\n"}; 71 | 72 | const char CRLF[] PROGMEM = {"\"\n\r"}; 73 | const char CLIP[] PROGMEM = {"AT+CLIP=1\r\n"}; 74 | 75 | 76 | // Flightmode ON OFF - for saving battery while in underground garage with no GSM signal 77 | const char FLIGHTON[] PROGMEM = { "AT+CFUN=4\r\n" }; 78 | const char FLIGHTOFF[] PROGMEM = { "AT+CFUN=1\r\n" }; 79 | 80 | // Sleepmode ON OFF, SIM800L supports mode #2 81 | const char SLEEPON[] PROGMEM = { "AT+CSCLK=2\r\n" }; 82 | const char SLEEPOFF[] PROGMEM = { "AT+CSCLK=0\r\n" }; 83 | 84 | // Fix UART speed to 9600 bps 85 | const char SET9600[] PROGMEM = { "AT+IPR=9600\r\n" }; 86 | 87 | // Save settings to SIM800L 88 | const char SAVECNF[] PROGMEM = { "AT&W\r\n" }; 89 | 90 | // Disable SIM800L LED for further reduction of power consumption 91 | const char DISABLELED[] PROGMEM = { "AT+CNETLIGHT=0\r\n" }; 92 | 93 | // for sending SMS predefined text 94 | const char GOOGLELOC1[] PROGMEM = {"\r\n http://maps.google.com/maps?q="}; 95 | const char GOOGLELOC2[] PROGMEM = {","}; 96 | const char GOOGLELOC3[] PROGMEM = {"\r\n"}; 97 | const char LONG[] PROGMEM = {" UTC\n LONGTITUDE="}; 98 | const char LATT[] PROGMEM = {" LATITUDE="}; 99 | const char BATT[] PROGMEM = {"\nBATTERY[mV]="}; 100 | 101 | // definition of APN used for GPRS communication 102 | // please put correct APN, USERNAME and PASSWORD here appropriate 103 | // for your Mobile Network provider 104 | const char SAPBR1[] PROGMEM = {"AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r\n"}; 105 | const char SAPBR2[] PROGMEM = {"AT+SAPBR=3,1,\"APN\",\"internet\"\r\n"}; // Put your mobile operator APN name here 106 | const char SAPBR3[] PROGMEM = {"AT+SAPBR=3,1,\"USER\",\"internet\"\r\n"}; // Put your mobile operator APN username here 107 | const char SAPBR4[] PROGMEM = {"AT+SAPBR=3,1,\"PWD\",\"internet\"\r\n"}; // Put your mobile operator APN password here 108 | // PDP context commands 109 | const char SAPBROPEN[] PROGMEM = {"AT+SAPBR=1,1\r\n"}; // open IP bearer 110 | const char SAPBRQUERY[] PROGMEM = {"AT+SAPBR=2,1\r\n"}; // query IP bearer 111 | const char SAPBRCLOSE[] PROGMEM = {"AT+SAPBR=0,1\r\n"}; // close bearer 112 | const char SAPBRSUCC[] PROGMEM = {"+SAPBR: 1,1"}; // bearer was succesfull we are not checking IP assigned 113 | 114 | // check statuses & cells 115 | const char CHECKGPS[] PROGMEM = {"AT+CIPGSMLOC=1,1\r\n"}; // check GPS position of nearest GSM CELL via Google API 116 | const char CHECKBATT[] PROGMEM = {"AT+CBC\r\n"}; // check battery voltage 117 | 118 | 119 | // buffers for number of phone, responses from modem, longtitude & latitude data 120 | #define BUFFER_SIZE 80 121 | volatile static uint8_t response[BUFFER_SIZE] = "12345678901234567890123456789012345678901234567890123456789012345678901234567890"; 122 | volatile static uint8_t response_pos = 0; 123 | volatile static uint8_t phonenumber[20] = "12345678901234567890"; 124 | volatile static uint8_t phonenumber_pos = 0; 125 | volatile static uint8_t latitude[20] = "12345678901234567890"; 126 | volatile static uint8_t latitude_pos = 0; 127 | volatile static uint8_t longtitude[20] = "12345678901234567890"; 128 | volatile static uint8_t longtitude_pos = 0; 129 | volatile static uint8_t buf[40]; // buffer to copy string from PROGMEM 130 | volatile static uint8_t battery[10] = "1234567890"; // for battery voltage checking 131 | volatile static uint8_t battery_pos = 0; 132 | 133 | 134 | // ---------------------------------------------------------------------------------------------- 135 | // init_uart 136 | // ---------------------------------------------------------------------------------------------- 137 | void init_uart(void) { 138 | // double speed by U2X0 flag = 1 to have 0.2% error rate on 9600 baud 139 | UCSR0A = (1<>8); 142 | UBRR0L = (uint8_t)(MYUBBR); 143 | UCSR0B|=(1< 0) // this is EoL 246 | { response[response_pos] = NULL; 247 | response_pos = 0; 248 | wholeline = 1; }; 249 | // just skip this CRLF character and wait for valuable one 250 | 251 | }; 252 | // if buffer is empty exit from function there is nothing to read from 253 | i++; 254 | } while ( (wholeline == 0) && (i<80) ); 255 | 256 | return (1); 257 | } 258 | 259 | 260 | // -------------------------------------------------------------------------------------------------------- 261 | // READ CELL GPS from AT+CIPGSMLOC output and put output to 'lattitude' and 'longtitude' buffers 262 | // -------------------------------------------------------------------------------------------------------- 263 | uint8_t readcellgps() 264 | { 265 | uint16_t char1; 266 | uint8_t i; 267 | // wait for first COMMA, set positions to start of each buffer 268 | longtitude_pos = 0; 269 | latitude_pos = 0; 270 | response_pos = 0; 271 | 272 | // i counter of received chars... not to get deadlock. 80 chars max as a safe fuse 273 | i = 0; 274 | 275 | // wait for first COMMA sign after +CIPGSMLOC: message 276 | do { 277 | char1 = receive_uart(); 278 | i++; 279 | } while ( (char1 != ',') && (i<20)); 280 | 281 | // if 'i' fuse == 20 chars and no comma sign return with 0, probably module restarted itself 282 | if (i == 20) return(0); 283 | 284 | 285 | // if COMMA detected start to copy the response - LONGTITUDE first 286 | do { 287 | char1 = receive_uart(); 288 | longtitude[longtitude_pos] = char1; 289 | longtitude_pos++; 290 | i++; 291 | } while ( (char1 != ',') && (i<70) ); 292 | longtitude[longtitude_pos-1] = NULL; 293 | longtitude_pos=0; 294 | 295 | // if COMMA detected start to copy the response - LATITUDE second 296 | do { 297 | char1 = receive_uart(); 298 | latitude[latitude_pos] = char1; 299 | latitude_pos++; 300 | i++; 301 | } while ( (char1 != ',') && (i<70) ); 302 | // put end of string to latitude 303 | latitude[latitude_pos-1] = NULL; 304 | latitude_pos=0; 305 | 306 | // Now copy DATE & TIME UTC to response buffer and wait for CRLF to finish 307 | do { 308 | char1 = receive_uart(); 309 | response[response_pos] = char1; 310 | response_pos++; 311 | i++; 312 | } while ( (char1 != '\r') && (char1 != '\n') && (i<70) ); // WAIT FOR CR LF 313 | response[response_pos-1] = NULL; 314 | response_pos=0; 315 | char1 = receive_uart(); // read last CR or LF and exit 316 | 317 | return (1); 318 | } 319 | 320 | // ---------------------------------------------------------------------------------------- 321 | // read PHONE NUMBER from AT+CLIP output and copy it to buffer for SMS sending 322 | // ---------------------------------------------------------------------------------------- 323 | uint8_t readphonenumber() 324 | { 325 | uint16_t char1; 326 | uint8_t i; 327 | // wait for first quotation 328 | phonenumber_pos = 0; 329 | i = 0; 330 | 331 | // wait for "CLIP:" and space 332 | do { 333 | char1 = receive_uart(); 334 | i++; 335 | } while ( (char1 != ':') && (i<80) ); 336 | 337 | // wait for first quotation sign, 'i' protection of buffer overload 338 | do { 339 | char1 = receive_uart(); 340 | i++; 341 | } while ( (char1 != '\"') && (i<80) ); 342 | // if quotation detected start to copy the response - phonenumber 343 | do { 344 | char1 = receive_uart(); 345 | phonenumber[phonenumber_pos] = char1; 346 | phonenumber_pos++; 347 | i++; 348 | } while ( (char1 != '\"') && (i<80) ); // until end of quotation 349 | // put NULL to end the string phonenumber 350 | phonenumber[phonenumber_pos-1] = NULL; 351 | phonenumber_pos=0; 352 | // wait for CRLF for new response to empty RX buffer 353 | do { 354 | char1 = receive_uart(); 355 | i++; 356 | } while ( (char1 != 0x0a) && (char1 != 0x0d) && (i<80) ); 357 | return (1); 358 | } 359 | 360 | // ---------------------------------------------------------------------------------------- 361 | // Read BATTERY VOLTAGE in milivolts from AT+CBC output and put results to 'battery' buffer 362 | // ---------------------------------------------------------------------------------------- 363 | 364 | uint8_t readbattery() 365 | { 366 | uint16_t char1; 367 | uint8_t i; 368 | 369 | i = 0; 370 | battery_pos = 0; 371 | 372 | // wait for first COMMA sign 373 | do { 374 | char1 = receive_uart(); 375 | i++; 376 | } while ( (char1 != ',') && (i<70) ); 377 | 378 | // wait for second COMMA sign 379 | do { 380 | char1 = receive_uart(); 381 | i++; 382 | } while ( (char1 != ',') && (i<70) ); 383 | 384 | // if 2 COMMA detected start to copy battery voltage to buffer 385 | do { 386 | char1 = receive_uart(); 387 | battery[battery_pos] = char1; 388 | battery_pos++; 389 | i++; 390 | } while ( (char1 != 0x0a) && (char1 != 0x0d) && (i<70) ); 391 | 392 | battery[battery_pos-1] = NULL; 393 | battery_pos=0; 394 | 395 | return (1); 396 | } 397 | 398 | 399 | 400 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 401 | // delay procedure ASM based because _delay_ms() is working bad for 1 MHz clock MCU 402 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 403 | 404 | // delay partucular number of i seconds, i < 255 405 | 406 | void delay_sec(uint8_t i) 407 | { 408 | while(i > 0) 409 | { 410 | // Delay 1 000 000 cycles 411 | // 1s at 1 MHz 412 | 413 | asm volatile ( 414 | " ldi r18, 6" "\n" 415 | " ldi r19, 19" "\n" 416 | " ldi r20, 174" "\n" 417 | "1: dec r20" "\n" 418 | " brne 1b" "\n" 419 | " dec r19" "\n" 420 | " brne 1b" "\n" 421 | " dec r18" "\n" 422 | " brne 1b" "\n" 423 | " rjmp 1f" "\n" 424 | "1:" "\n" 425 | ); 426 | 427 | i--; // decrease another second 428 | 429 | }; // repeat until i not zero 430 | 431 | } 432 | 433 | 434 | 435 | ////////////////////////////////////////// 436 | // SIM800L initialization procedures 437 | ////////////////////////////////////////// 438 | 439 | // ------------------------------------------------------------------------------- 440 | // wait for first AT in case SIM800L is starting up 441 | // ------------------------------------------------------------------------------- 442 | uint8_t checkat() 443 | { 444 | uint8_t initialized2; 445 | 446 | // wait for first OK while sending AT - autosensing speed on SIM800L, but we are working 9600 bps 447 | // SIM 800L can be set by AT+IPR=9600 to fix this speed 448 | // which I do recommend by connecting SIM800L to PC using putty and FTD232 cable 449 | 450 | initialized2 = 0; 451 | do { 452 | uart_puts_P(AT); 453 | if (readline()>0) 454 | { 455 | memcpy_P(buf, ISOK, sizeof(ISOK)); 456 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 457 | }; 458 | delay_sec(1); 459 | } while (initialized2 == 0); 460 | 461 | // send ECHO OFF 462 | uart_puts_P(ECHO_OFF); 463 | delay_sec(1); 464 | 465 | return (1); 466 | } 467 | 468 | // ------------------------------------------------------------------------------- 469 | // check if PIN is needed and enter PIN 1111 470 | // ------------------------------------------------------------------------------- 471 | uint8_t checkpin() 472 | { 473 | 474 | uint8_t initialized2; 475 | // readline and wait for PIN CODE STATUS if needed send PIN 1111 to SIM card if required 476 | initialized2 = 0; 477 | do { 478 | delay_sec(2); 479 | uart_puts_P(SHOW_PIN); 480 | if (readline()>0) 481 | { 482 | memcpy_P(buf, PIN_IS_READY, sizeof(PIN_IS_READY)); 483 | if (is_in_rx_buffer(response, buf ) == 1) initialized2 = 1; 484 | memcpy_P(buf, PIN_MUST_BE_ENTERED, sizeof(PIN_MUST_BE_ENTERED)); 485 | if (is_in_rx_buffer(response, buf) == 1) 486 | { 487 | delay_sec(1); 488 | uart_puts_P(ENTER_PIN); // ENTER PIN 1111 489 | delay_sec(1); 490 | }; 491 | }; 492 | 493 | } while (initialized2 == 0); 494 | 495 | return (1); 496 | } 497 | 498 | 499 | // ------------------------------------------------------------------------------- 500 | // check if registered to the network 501 | // ------------------------------------------------------------------------------- 502 | uint8_t checkregistration() 503 | { 504 | uint8_t initialized2, attempt2, nbrminutes; 505 | initialized2 = 0; 506 | attempt2 = 0; 507 | nbrminutes = 0; 508 | 509 | // check if already registered first and quit immediately if true 510 | delay_sec(1); 511 | uart_puts_P(SHOW_REGISTRATION); 512 | if (readline()>0) 513 | { 514 | memcpy_P(buf, ISREG1, sizeof(ISREG1)); 515 | if (is_in_rx_buffer(response, buf) == 1) return(1); 516 | memcpy_P(buf, ISREG2, sizeof(ISREG2)); 517 | if (is_in_rx_buffer(response, buf) == 1) return(1); 518 | } 519 | 520 | do { 521 | // give reasonable time to look for 2G coverage and then check, maybe on the move... 522 | delay_sec(1); 523 | uart_puts_P(FLIGHTOFF); // DISABLE airplane mode - just in case... 524 | delay_sec(120); 525 | uart_puts_P(SHOW_REGISTRATION); 526 | // readline and wait for STATUS NETWORK REGISTRATION from SIM800L 527 | // first 2 networks preferred from SIM list are OK 528 | 529 | if (readline()>0) 530 | { 531 | memcpy_P(buf, ISREG1, sizeof(ISREG1)); 532 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 533 | memcpy_P(buf, ISREG2, sizeof(ISREG2)); 534 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 535 | 536 | // if 2G network not found make backoff for 1 hour - maybe in underground garage or something... 537 | if (initialized2 == 0) 538 | { 539 | // if not registered or something wrong turn off RADIO for minutes 540 | // this is not to drain battery in underground garage 541 | delay_sec(1); 542 | uart_puts_P(FLIGHTON); // enable airplane mode - turn off radio 543 | delay_sec(1); 544 | // enter SLEEP MODE of SIM800L for power saving when no coverage 545 | uart_puts_P(SLEEPON); 546 | // now wait XX min before turning on radio again, here XX = 30 min 547 | for (nbrminutes = 0; nbrminutes<30; nbrminutes++) 548 | { 549 | delay_sec(60); 550 | }; 551 | 552 | // send first dummy AT command 553 | uart_puts_P(AT); 554 | delay_sec(1); 555 | 556 | uart_puts_P(SLEEPOFF); // switch off to SLEEPMODE = 0 557 | delay_sec(1); 558 | 559 | }; // end of no-coverage IF 560 | 561 | 562 | }; // end of READLINE-IF 563 | 564 | attempt2++; // increase number of attempts 565 | // end of DO loop 566 | } while ( (initialized2 == 0) && (attempt2 < 48) ); // stop after 24 hours of searching 2G network 567 | 568 | return (1); 569 | }; 570 | 571 | 572 | 573 | // --------------------------------------------------------------------------------------------- 574 | // provision GPRS APNs and passwords - we are not checking if any error not to get deadlocks 575 | // --------------------------------------------------------------------------------------------- 576 | uint8_t provisiongprs() 577 | { 578 | // connection to GPRS for AGPS basestation data - provision APN and username 579 | delay_sec(1); 580 | uart_puts_P(SAPBR1); 581 | delay_sec(1); 582 | uart_puts_P(SAPBR2); 583 | // only if username password in APN is needed 584 | delay_sec(1); 585 | uart_puts_P(SAPBR3); 586 | delay_sec(1); 587 | uart_puts_P(SAPBR4); 588 | delay_sec(1); 589 | return 1; 590 | } 591 | 592 | 593 | 594 | 595 | // ------------------------------------------------------------------------------- 596 | // POWER SAVING mode handling to reduce the battery consumption 597 | // Required connection between SIM800L RI/RING pin and ATMEGA328P INT0/D2 pin 598 | // ------------------------------------------------------------------------------- 599 | 600 | void sleepnow(void) 601 | { 602 | 603 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 604 | 605 | sleep_enable(); 606 | 607 | DDRD &= ~(1 << DDD2); // Clear the PD2 pin 608 | // PD2 (PCINT0 pin) is now an input 609 | 610 | PORTD |= (1 << PORTD2); // turn On the Pull-up 611 | // PD2 is now an input with pull-up enabled 612 | 613 | // stop interrupts for configuration period 614 | cli(); 615 | 616 | // update again INT0 conditions 617 | EICRA &= ~(1 << ISC01); // set INT0 to trigger on low level 618 | EICRA &= ~(1 << ISC00); // set INT0 to trigger on low level 619 | EIMSK |= (1 << INT0); // Turns on INT0 (set bit) 620 | 621 | sei(); //ensure interrupts enabled so we can wake up again 622 | 623 | sleep_cpu(); //go to sleep 624 | 625 | // MCU ATTMEGA328P sleeps here until INT0 interrupt 626 | 627 | sleep_disable(); //wake up here 628 | 629 | } 630 | 631 | // when interrupt from INT0 disable next interrupts from RING pin of SIM800L and go back to main code 632 | ISR(INT0_vect) 633 | { 634 | 635 | EIMSK &= ~(1 << INT0); // Turns off INT0 (clear bit) 636 | } 637 | 638 | 639 | 640 | 641 | // ********************************************************************************************************* 642 | // 643 | // MAIN PROGRAM 644 | // 645 | // ********************************************************************************************************* 646 | 647 | int main(void) { 648 | 649 | uint8_t initialized, attempt = 0; 650 | uint8_t cellgpsavailable = 0; 651 | 652 | // initialize 9600 baud 8N1 RS232 653 | init_uart(); 654 | 655 | // delay 10 seconds for safe SIM800L startup and network registration 656 | delay_sec(10); 657 | 658 | // try to communicate with SIM800L over AT 659 | checkat(); 660 | delay_sec(2); 661 | 662 | // Fix UART speed to 9600 bps to disable autosensing 663 | uart_puts_P(SET9600); 664 | delay_sec(1); 665 | 666 | // configure RI PIN activity for URC ( unsolicited messages like restart of the modem or battery low) 667 | uart_puts_P(CFGRIPIN); 668 | delay_sec(1); 669 | 670 | // disable reporting of 2G registration URC 671 | uart_puts_P(DISREGURC); 672 | delay_sec(1); 673 | 674 | // Save settings to SIM800L 675 | uart_puts_P(SAVECNF); 676 | delay_sec(3); 677 | 678 | // check pin status, registration status and provision APN settings 679 | checkpin(); 680 | delay_sec(2); 681 | 682 | // disable flighmode 683 | uart_puts_P(FLIGHTOFF); 684 | delay_sec(120); 685 | 686 | // check if attached to 2G network 687 | checkregistration(); 688 | provisiongprs(); 689 | 690 | 691 | // neverending LOOP 692 | while (1) { 693 | 694 | do { 695 | 696 | // WAIT FOR RING message - incoming voice call and send SMS or restart RADIO module if no signal 697 | initialized = 0; 698 | cellgpsavailable = 0; 699 | 700 | // delete all SMSes and SMS confirmation to keep SIM800L memory empty 701 | uart_puts_P(SMS1); 702 | delay_sec(1); 703 | uart_puts_P(DELSMS); 704 | delay_sec(2); 705 | 706 | 707 | // read phone number of incoming voice call by CLIP, will be needed for SMS sending 708 | uart_puts_P(CLIP); 709 | delay_sec(1); 710 | 711 | 712 | // Disable LED blinking on SIM800L 713 | uart_puts_P(DISABLELED); 714 | delay_sec(1); 715 | 716 | // enter SLEEP MODE of SIM800L for power saving ( will be interrupted by incoming voice call or SMS ) 717 | uart_puts_P(SLEEPON); 718 | delay_sec(2); 719 | 720 | // enter SLEEP MODE on ATMEGA328P for power saving, requires RING/RI SIM800L pin connected to ATMEGA 721 | sleepnow(); // sleep function called here 722 | 723 | // THERE WAS RI / INT0 INTERRUPT AND SOMETHING WAS SEND OVER SERIAL WE NEED TO GET OFF SLEEPMODE AND READ SERIAL PORT 724 | if (readline()>0) 725 | { 726 | memcpy_P(buf, ISRING, sizeof(ISRING)); 727 | if (is_in_rx_buffer(response, buf) == 1) 728 | { initialized = 1; 729 | readphonenumber(); 730 | // disable SLEEPMODE , hangup a call and proceed with sending SMS 731 | uart_puts_P(AT); 732 | delay_sec(1); 733 | uart_puts_P(SLEEPOFF); 734 | delay_sec(1); 735 | uart_puts_P(HANGUP); 736 | delay_sec(1); 737 | } // end of IF 738 | 739 | 740 | // if some other message than RING check if network is avaialble and SIM800L is operational 741 | else 742 | { 743 | // disable SLEEPMODE 744 | uart_puts_P(AT); 745 | delay_sec(1); 746 | uart_puts_P(SLEEPOFF); 747 | delay_sec(1); 748 | // check status of all functions 749 | checkpin(); 750 | checkregistration(); 751 | // read phone number of incoming voice call by CLIP, will be needed for SMS sending 752 | //and close the beare just in case it was open 753 | uart_puts_P(SAPBRCLOSE); 754 | delay_sec(2); 755 | // there was something different than RING so we need to go back to the beginning - clear the flag 756 | initialized = 0; 757 | }; // end of ELSE 758 | 759 | }; // END of READLINE IF 760 | 761 | } while ( initialized == 0); // end od DO-WHILE, go to beggining and enter SLEEPMODE again 762 | 763 | // clear the flag we gonna need it later 764 | initialized = 0; 765 | 766 | // Create connection to GPRS network - 3 attempts if needed, if not succesfull restart the modem 767 | attempt = 0; 768 | do { 769 | 770 | //and close the bearer first maybe there was an error or something 771 | delay_sec(1); 772 | uart_puts_P(SAPBRCLOSE); 773 | 774 | // now after this time network should be fine, provision APN settings 775 | delay_sec(1); 776 | provisiongprs(); 777 | delay_sec(1); 778 | 779 | // make GPRS network attach and open IP bearer 780 | uart_puts_P(SAPBROPEN); 781 | 782 | // query PDP context for IP address after several seconds 783 | // check if GPRS attach was succesfull, do it several times if needed 784 | initialized = 0; 785 | delay_sec(10); 786 | uart_puts_P(SAPBRQUERY); 787 | if (readline()>0) 788 | { 789 | // checking for properly attached 790 | memcpy_P(buf, SAPBRSUCC, sizeof(SAPBRSUCC)); 791 | if (is_in_rx_buffer(response, buf) == 1) initialized = 1; 792 | // other responses simply ignored as there was no attach 793 | }; 794 | // increase attempt counter and repeat until not attached 795 | attempt++; 796 | } while ( (attempt < 3) && (initialized == 0) ); 797 | 798 | 799 | // if GPRS was succesfull the it is time send cell info to Google and query the GPS location 800 | if (initialized == 1) 801 | { 802 | 803 | // check battery voltage 804 | delay_sec(1); 805 | uart_puts_P(CHECKBATT); 806 | readbattery(); 807 | 808 | // GET CELL ID OF BASE STATION and query Google for coordinates then send over SMS with google map loc 809 | delay_sec(1); 810 | uart_puts_P(CHECKGPS); 811 | 812 | // parse GPS coordinates from the SIM808 answer to 'longtitude' & 'latitude' buffers 813 | // if possible otherwise some backup scenario 814 | cellgpsavailable=readcellgps(); 815 | // if negative result please allow 60 sec fo SIM808 reboot 816 | if ( cellgpsavailable == 0 ) 817 | { 818 | delay_sec(55); 819 | } 820 | else // proceed with SMS sending 821 | { 822 | delay_sec(1); 823 | // send a SMS in plain text format 824 | uart_puts_P(SMS1); 825 | delay_sec(1); 826 | // compose an SMS from fragments - interactive mode CTRL Z at the end 827 | uart_puts_P(SMS2); 828 | uart_puts(phonenumber); // send phone number received from CLIP 829 | uart_puts_P(CRLF); 830 | delay_sec(1); 831 | // put info about DATE,TIME, LONG, LATITUDE 832 | uart_puts(response); // send Date & Time info from AGPS cell info 833 | uart_puts_P(LONG); // send LONGTITUDE 834 | uart_puts(longtitude); // from buffer 835 | uart_puts_P(LATT); // send LATITUDE 836 | uart_puts(latitude); // from buffer 837 | // put battery info 838 | uart_puts_P(BATT); // send BATTERY INFO 839 | uart_puts(battery); // from buffer 840 | // put link to GOOGLE MAPS 841 | uart_puts_P(GOOGLELOC1); // send http **** 842 | uart_puts(latitude); // send latitude value 843 | uart_puts_P(GOOGLELOC2); // send comma 844 | uart_puts(longtitude); // send longtitude value 845 | uart_puts_P(GOOGLELOC3); // send CRLF 846 | delay_sec(1); 847 | // end the SMS message 848 | send_uart(26); // ctrl Z to end SMS 849 | 850 | }; // End of cellgpsavailable IF 851 | 852 | //and close the bearer 853 | delay_sec(5); 854 | uart_puts_P(SAPBRCLOSE); 855 | 856 | } /// end of commands when GPRS is working 857 | 858 | // now go to the beginning and enter sleepmode on SIM800L and ATMEGA328P again for power saving 859 | delay_sec(10); 860 | 861 | // end of neverending loop 862 | }; 863 | 864 | 865 | // end of MAIN code 866 | } 867 | 868 | -------------------------------------------------------------------------------- /mainb.c: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------- 2 | * GPS car tracker on ATMEGA328P + SIM800L module version 3.0 3 | * by Adam Loboda - adam.loboda@wp.pl 4 | * accuracy is nearest GSM cell around locator 5 | * baudrate UART is 9600 as most stable using RC internal clock (lowered to 1MHz) 6 | * 7 | * please configure SIM800L to fixed 9600 first by AT+IPR=9600 command 8 | * to ensure stability ans save config via AT&W command 9 | * 10 | * this version doe not use sleepmode use on ATMEGA328P 11 | * but RI/RING ping on SIM800L module must be connected to INT0 pin on ATMEGA328P 12 | * as we are checking its status if LOW = incoming CALL 13 | * works more stable however current consumption is ~4-5mA 14 | * 15 | * connections to be made : 16 | * SIM800L RXD to ATMEGA328 TXD PIN #3, 17 | * SIM800L TXD to ATMEGA328 RXD PIN #2 18 | * SIM800L RING to ATMEGA328 INT0/PD2 PIN #4 19 | * ATMEGA328 VCC (PIN #7) to SIM800L VCC and +4.4V 20 | * ATMEGA328 GND (PIN #8 and PIN #22) to SIM800L GND and 0V 21 | * the rest is the same as on ATTINY2313 schematic 22 | * --------------------------------------------------------------------------------- 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #define UART_NO_DATA 0x0100 37 | // internal RC oscillator 8MHz with divison by 8 and U2X0 = 1, gives 0.2% error rate for 9600 bps UART speed 38 | // and lower current consumption 39 | // for 1MHz : -U lfuse:w:0x62:m on ATMEGA328P 40 | #define F_CPU 1000000UL 41 | 42 | 43 | #define BAUD 9600 44 | // formula for 1MHz clock and U2X0 = 1 double UART speed 45 | #define MYUBBR ((F_CPU / (BAUD * 8L)) - 1) 46 | 47 | 48 | const char AT[] PROGMEM = { "AT\n\r" }; // SPACE for wakeup from sleep mode 49 | const char ISOK[] PROGMEM = { "OK" }; 50 | 51 | const char ISRING[] PROGMEM = { "RING" }; 52 | const char ISREG1[] PROGMEM = { "+CREG: 0,1" }; // SIM registered in HPLMN 53 | const char ISREG2[] PROGMEM = { "+CREG: 0,5" }; // SIM registered in ROAMING NETWORK 54 | const char SHOW_REGISTRATION[] PROGMEM = {"AT+CREG?\n\r"}; 55 | const char DISREGURC[] PROGMEM = {"AT+CREG=0\n\r"}; // we disable realtime reporting of 2G network status 56 | 57 | const char PIN_IS_READY[] PROGMEM = {"+CPIN: READY"}; 58 | const char PIN_MUST_BE_ENTERED[] PROGMEM = {"+CPIN: SIM PIN"}; 59 | 60 | const char SHOW_PIN[] PROGMEM = {"AT+CPIN?\n\r"}; 61 | const char ECHO_OFF[] PROGMEM = {"ATE0\n\r"}; 62 | const char ENTER_PIN[] PROGMEM = {"AT+CPIN=\"1111\"\n\r"}; // put PINCODE of your SIMCARD here instead of 1111... 63 | 64 | const char CFGRIPIN[] PROGMEM = {"AT+CFGRI=1\n\r"}; 65 | 66 | const char HANGUP[] PROGMEM = {"ATH\n\r"}; 67 | 68 | const char SMS1[] PROGMEM = {"AT+CMGF=1\r\n"}; 69 | const char SMS2[] PROGMEM = {"AT+CMGS=\""}; 70 | const char DELSMS[] PROGMEM = {"AT+CMGDA=\"DEL ALL\"\r\n"}; 71 | 72 | const char CRLF[] PROGMEM = {"\"\n\r"}; 73 | const char CLIP[] PROGMEM = {"AT+CLIP=1\r\n"}; 74 | 75 | 76 | // Flightmode ON OFF - for saving battery while in underground garage with no GSM signal 77 | const char FLIGHTON[] PROGMEM = { "AT+CFUN=4\r\n" }; 78 | const char FLIGHTOFF[] PROGMEM = { "AT+CFUN=1\r\n" }; 79 | 80 | // Sleepmode ON OFF 81 | const char SLEEPON[] PROGMEM = { "AT+CSCLK=2\r\n" }; 82 | const char SLEEPOFF[] PROGMEM = { "AT+CSCLK=0\r\n" }; 83 | 84 | // Fix UART speed to 9600 bps 85 | const char SET9600[] PROGMEM = { "AT+IPR=9600\r\n" }; 86 | 87 | // Save settings to SIM800L 88 | const char SAVECNF[] PROGMEM = { "AT&W\r\n" }; 89 | 90 | // Disable SIM800L LED for further reduction of power consumption 91 | const char DISABLELED[] PROGMEM = { "AT+CNETLIGHT=0\r\n" }; 92 | 93 | // for sending SMS predefined text 94 | const char GOOGLELOC1[] PROGMEM = {"\r\n http://maps.google.com/maps?q="}; 95 | const char GOOGLELOC2[] PROGMEM = {","}; 96 | const char GOOGLELOC3[] PROGMEM = {"\r\n"}; 97 | const char LONG[] PROGMEM = {" UTC\n LONGTITUDE="}; 98 | const char LATT[] PROGMEM = {" LATITUDE="}; 99 | const char BATT[] PROGMEM = {"\nBATTERY[mV]="}; 100 | 101 | // definition of APN used for GPRS communication 102 | // please put correct APN, USERNAME and PASSWORD here appropriate 103 | // for your Mobile Network provider 104 | const char SAPBR1[] PROGMEM = {"AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r\n"}; 105 | const char SAPBR2[] PROGMEM = {"AT+SAPBR=3,1,\"APN\",\"internet\"\r\n"}; // Put your mobile operator APN name here 106 | const char SAPBR3[] PROGMEM = {"AT+SAPBR=3,1,\"USER\",\"internet\"\r\n"}; // Put your mobile operator APN username here 107 | const char SAPBR4[] PROGMEM = {"AT+SAPBR=3,1,\"PWD\",\"internet\"\r\n"}; // Put your mobile operator APN password here 108 | // PDP context commands 109 | const char SAPBROPEN[] PROGMEM = {"AT+SAPBR=1,1\r\n"}; // open IP bearer 110 | const char SAPBRQUERY[] PROGMEM = {"AT+SAPBR=2,1\r\n"}; // query IP bearer 111 | const char SAPBRCLOSE[] PROGMEM = {"AT+SAPBR=0,1\r\n"}; // close bearer 112 | const char SAPBRSUCC[] PROGMEM = {"+SAPBR: 1,1"}; // bearer was succesfull we are not checking IP assigned 113 | 114 | // check statuses & cells 115 | const char CHECKGPS[] PROGMEM = {"AT+CIPGSMLOC=1,1\r\n"}; // check GPS position of nearest GSM CELL via Google API 116 | const char CHECKBATT[] PROGMEM = {"AT+CBC\r\n"}; // check battery voltage 117 | 118 | 119 | 120 | // buffers for number of phone, responses from modem, longtitude & latitude data 121 | #define BUFFER_SIZE 80 122 | volatile static uint8_t response[BUFFER_SIZE] = "12345678901234567890123456789012345678901234567890123456789012345678901234567890"; 123 | volatile static uint8_t response_pos = 0; 124 | volatile static uint8_t phonenumber[20] = "12345678901234567890"; 125 | volatile static uint8_t phonenumber_pos = 0; 126 | volatile static uint8_t latitude[20] = "12345678901234567890"; 127 | volatile static uint8_t latitude_pos = 0; 128 | volatile static uint8_t longtitude[20] = "12345678901234567890"; 129 | volatile static uint8_t longtitude_pos = 0; 130 | volatile static uint8_t buf[40]; // buffer to copy string from PROGMEM 131 | volatile static uint8_t battery[10] = "1234567890"; // for battery voltage checking 132 | volatile static uint8_t battery_pos = 0; 133 | 134 | 135 | // ---------------------------------------------------------------------------------------------- 136 | // init_uart 137 | // ---------------------------------------------------------------------------------------------- 138 | void init_uart(void) { 139 | // double speed by U2X0 flag = 1 to have 0.2% error rate on 9600 baud 140 | UCSR0A = (1<>8); 143 | UBRR0L = (uint8_t)(MYUBBR); 144 | UCSR0B|=(1< 0) // this is EoL 246 | { response[response_pos] = NULL; 247 | response_pos = 0; 248 | wholeline = 1; }; 249 | // just skip this CRLF character and wait for valuable one 250 | 251 | }; 252 | // if buffer is empty exit from function there is nothing to read from 253 | i++; 254 | } while ( (wholeline == 0) && (i<80) ); 255 | 256 | return (1); 257 | } 258 | 259 | 260 | // -------------------------------------------------------------------------------------------------------- 261 | // READ CELL GPS from AT+CIPGSMLOC output and put output to 'lattitude' and 'longtitude' buffers 262 | // -------------------------------------------------------------------------------------------------------- 263 | uint8_t readcellgps() 264 | { 265 | uint16_t char1; 266 | uint8_t i; 267 | // wait for first COMMA, set positions to start of each buffer 268 | longtitude_pos = 0; 269 | latitude_pos = 0; 270 | response_pos = 0; 271 | 272 | // i counter of received chars... not to get deadlock. 80 chars max as a safe fuse 273 | i = 0; 274 | 275 | // wait for first COMMA sign after +CIPGSMLOC: message 276 | do { 277 | char1 = receive_uart(); 278 | i++; 279 | } while ( (char1 != ',') && (i<20)); 280 | 281 | // if 'i' fuse == 20 chars and no comma sign return with 0, probably module restarted itself 282 | if (i == 20) return(0); 283 | 284 | 285 | // if COMMA detected start to copy the response - LONGTITUDE first 286 | do { 287 | char1 = receive_uart(); 288 | longtitude[longtitude_pos] = char1; 289 | longtitude_pos++; 290 | i++; 291 | } while ( (char1 != ',') && (i<70) ); 292 | longtitude[longtitude_pos-1] = NULL; 293 | longtitude_pos=0; 294 | 295 | // if COMMA detected start to copy the response - LATITUDE second 296 | do { 297 | char1 = receive_uart(); 298 | latitude[latitude_pos] = char1; 299 | latitude_pos++; 300 | i++; 301 | } while ( (char1 != ',') && (i<70) ); 302 | // put end of string to latitude 303 | latitude[latitude_pos-1] = NULL; 304 | latitude_pos=0; 305 | 306 | // Now copy DATE & TIME UTC to response buffer and wait for CRLF to finish 307 | do { 308 | char1 = receive_uart(); 309 | response[response_pos] = char1; 310 | response_pos++; 311 | i++; 312 | } while ( (char1 != '\r') && (char1 != '\n') && (i<70) ); // WAIT FOR CR LF 313 | response[response_pos-1] = NULL; 314 | response_pos=0; 315 | char1 = receive_uart(); // read last CR or LF and exit 316 | 317 | return (1); 318 | } 319 | 320 | // ---------------------------------------------------------------------------------------- 321 | // read PHONE NUMBER from AT+CLIP output and copy it to buffer for SMS sending 322 | // ---------------------------------------------------------------------------------------- 323 | uint8_t readphonenumber() 324 | { 325 | uint16_t char1; 326 | uint8_t i; 327 | // wait for first quotation 328 | phonenumber_pos = 0; 329 | i = 0; 330 | 331 | // wait for "CLIP:" and space 332 | do { 333 | char1 = receive_uart(); 334 | i++; 335 | } while ( (char1 != ':') && (i<80) ); 336 | 337 | // wait for first quotation sign, 'i' protection of buffer overload 338 | do { 339 | char1 = receive_uart(); 340 | i++; 341 | } while ( (char1 != '\"') && (i<80) ); 342 | // if quotation detected start to copy the response - phonenumber 343 | do { 344 | char1 = receive_uart(); 345 | phonenumber[phonenumber_pos] = char1; 346 | phonenumber_pos++; 347 | i++; 348 | } while ( (char1 != '\"') && (i<80) ); // until end of quotation 349 | // put NULL to end the string phonenumber 350 | phonenumber[phonenumber_pos-1] = NULL; 351 | phonenumber_pos=0; 352 | // wait for CRLF for new response to empty RX buffer 353 | do { 354 | char1 = receive_uart(); 355 | i++; 356 | } while ( (char1 != 0x0a) && (char1 != 0x0d) && (i<80) ); 357 | return (1); 358 | } 359 | 360 | // ---------------------------------------------------------------------------------------- 361 | // Read BATTERY VOLTAGE in milivolts from AT+CBC output and put results to 'battery' buffer 362 | // ---------------------------------------------------------------------------------------- 363 | 364 | uint8_t readbattery() 365 | { 366 | uint16_t char1; 367 | uint8_t i; 368 | 369 | i = 0; 370 | battery_pos = 0; 371 | 372 | // wait for first COMMA sign 373 | do { 374 | char1 = receive_uart(); 375 | i++; 376 | } while ( (char1 != ',') && (i<70) ); 377 | 378 | // wait for second COMMA sign 379 | do { 380 | char1 = receive_uart(); 381 | i++; 382 | } while ( (char1 != ',') && (i<70) ); 383 | 384 | // if 2 COMMA detected start to copy battery voltage to buffer 385 | do { 386 | char1 = receive_uart(); 387 | battery[battery_pos] = char1; 388 | battery_pos++; 389 | i++; 390 | } while ( (char1 != 0x0a) && (char1 != 0x0d) && (i<70) ); 391 | 392 | battery[battery_pos-1] = NULL; 393 | battery_pos=0; 394 | 395 | return (1); 396 | } 397 | 398 | 399 | 400 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 401 | // delay procedure ASM based because _delay_ms() is working bad for 1 MHz clock MCU 402 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 403 | 404 | // delay partucular number of i seconds, i < 255 405 | 406 | void delay_sec(uint8_t i) 407 | { 408 | while(i > 0) 409 | { 410 | // Delay 1 000 000 cycles 411 | // 1s at 1 MHz 412 | 413 | asm volatile ( 414 | " ldi r18, 6" "\n" 415 | " ldi r19, 19" "\n" 416 | " ldi r20, 174" "\n" 417 | "1: dec r20" "\n" 418 | " brne 1b" "\n" 419 | " dec r19" "\n" 420 | " brne 1b" "\n" 421 | " dec r18" "\n" 422 | " brne 1b" "\n" 423 | " rjmp 1f" "\n" 424 | "1:" "\n" 425 | ); 426 | 427 | i--; // decrease another second 428 | 429 | }; // repeat until i not zero 430 | 431 | } 432 | 433 | 434 | 435 | 436 | // 437 | // delay multiplication of 50 microseconds 438 | // 439 | 440 | void delay_50usec(uint32_t i) 441 | { 442 | while(i > 0) 443 | { 444 | // Generated by delay loop calculator 445 | // at http://www.bretmulvey.com/avrdelay.html 446 | // Delay 50 cycles 447 | // 50us at 1 MHz 448 | 449 | asm volatile ( 450 | " ldi r18, 16" "\n" 451 | "1: dec r18" "\n" 452 | " brne 1b" "\n" 453 | " rjmp 1f" "\n" 454 | "1:" "\n" 455 | ); 456 | 457 | 458 | 459 | i--; // decrease another 50usec if needed 460 | 461 | }; // repeat until i not zero 462 | 463 | } 464 | 465 | 466 | 467 | 468 | ////////////////////////////////////////// 469 | // SIM800L initialization procedures 470 | ////////////////////////////////////////// 471 | 472 | // ------------------------------------------------------------------------------- 473 | // wait for first AT in case SIM800L is starting up 474 | // ------------------------------------------------------------------------------- 475 | uint8_t checkat() 476 | { 477 | uint8_t initialized2; 478 | 479 | // wait for first OK while sending AT - autosensing speed on SIM800L, but we are working 9600 bps 480 | // SIM 800L can be set by AT+IPR=9600 to fix this speed 481 | // which I do recommend by connecting SIM800L to PC using putty and FTD232 cable 482 | 483 | initialized2 = 0; 484 | do { 485 | uart_puts_P(AT); 486 | if (readline()>0) 487 | { 488 | memcpy_P(buf, ISOK, sizeof(ISOK)); 489 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 490 | }; 491 | delay_sec(1); 492 | } while (initialized2 == 0); 493 | 494 | // send ECHO OFF 495 | uart_puts_P(ECHO_OFF); 496 | delay_sec(1); 497 | 498 | return (1); 499 | } 500 | 501 | // ------------------------------------------------------------------------------- 502 | // check if PIN is needed and enter PIN 1111 503 | // ------------------------------------------------------------------------------- 504 | uint8_t checkpin() 505 | { 506 | 507 | uint8_t initialized2; 508 | // readline and wait for PIN CODE STATUS if needed send PIN 1111 to SIM card if required 509 | initialized2 = 0; 510 | do { 511 | delay_sec(2); 512 | uart_puts_P(SHOW_PIN); 513 | if (readline()>0) 514 | { 515 | memcpy_P(buf, PIN_IS_READY, sizeof(PIN_IS_READY)); 516 | if (is_in_rx_buffer(response, buf ) == 1) initialized2 = 1; 517 | memcpy_P(buf, PIN_MUST_BE_ENTERED, sizeof(PIN_MUST_BE_ENTERED)); 518 | if (is_in_rx_buffer(response, buf) == 1) 519 | { 520 | delay_sec(1); 521 | uart_puts_P(ENTER_PIN); // ENTER PIN 1111 522 | delay_sec(1); 523 | }; 524 | }; 525 | 526 | } while (initialized2 == 0); 527 | 528 | return (1); 529 | } 530 | 531 | 532 | // ------------------------------------------------------------------------------- 533 | // check if registered to the network 534 | // ------------------------------------------------------------------------------- 535 | uint8_t checkregistration() 536 | { 537 | uint8_t initialized2, attempt2, nbrminutes; 538 | initialized2 = 0; 539 | attempt2 = 0; 540 | nbrminutes = 0; 541 | 542 | // check if already registered first and quit immediately if true 543 | delay_sec(1); 544 | uart_puts_P(SHOW_REGISTRATION); 545 | if (readline()>0) 546 | { 547 | memcpy_P(buf, ISREG1, sizeof(ISREG1)); 548 | if (is_in_rx_buffer(response, buf) == 1) return(1); 549 | memcpy_P(buf, ISREG2, sizeof(ISREG2)); 550 | if (is_in_rx_buffer(response, buf) == 1) return(1); 551 | } 552 | 553 | do { 554 | // give reasonable time to look for 2G coverage and then check, maybe on the move... 555 | delay_sec(1); 556 | uart_puts_P(FLIGHTOFF); // DISABLE airplane mode - just in case... 557 | delay_sec(120); 558 | uart_puts_P(SHOW_REGISTRATION); 559 | // readline and wait for STATUS NETWORK REGISTRATION from SIM800L 560 | // first 2 networks preferred from SIM list are OK 561 | 562 | if (readline()>0) 563 | { 564 | memcpy_P(buf, ISREG1, sizeof(ISREG1)); 565 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 566 | memcpy_P(buf, ISREG2, sizeof(ISREG2)); 567 | if (is_in_rx_buffer(response, buf) == 1) initialized2 = 1; 568 | 569 | // if 2G network not found make backoff for 1 hour - maybe in underground garage or something... 570 | if (initialized2 == 0) 571 | { 572 | // if not registered or something wrong turn off RADIO for minutes 573 | // this is not to drain battery in underground garage 574 | delay_sec(1); 575 | uart_puts_P(FLIGHTON); // enable airplane mode - turn off radio 576 | delay_sec(1); 577 | // enter SLEEP MODE of SIM800L for power saving when no coverage 578 | uart_puts_P(SLEEPON); 579 | // now wait XX min before turning on radio again, here XX = 30 min 580 | for (nbrminutes = 0; nbrminutes<30; nbrminutes++) 581 | { 582 | delay_sec(60); 583 | }; 584 | 585 | // send first dummy AT command 586 | uart_puts_P(AT); 587 | delay_sec(1); 588 | 589 | uart_puts_P(SLEEPOFF); // switch off to SLEEPMODE = 0 590 | delay_sec(1); 591 | 592 | }; // end of no-coverage IF 593 | 594 | 595 | }; // end of READLINE-IF 596 | 597 | attempt2++; // increase number of attempts 598 | // end of DO loop 599 | } while ( (initialized2 == 0) && (attempt2 < 48) ); // stop after 24 hours of searching 2G network 600 | 601 | return (1); 602 | }; 603 | 604 | 605 | 606 | // --------------------------------------------------------------------------------------------- 607 | // provision GPRS APNs and passwords - we are not checking if any error not to get deadlocks 608 | // --------------------------------------------------------------------------------------------- 609 | uint8_t provisiongprs() 610 | { 611 | // connection to GPRS for AGPS basestation data - provision APN and username 612 | delay_sec(1); 613 | uart_puts_P(SAPBR1); 614 | delay_sec(1); 615 | uart_puts_P(SAPBR2); 616 | // only if username password in APN is needed 617 | delay_sec(1); 618 | uart_puts_P(SAPBR3); 619 | delay_sec(1); 620 | uart_puts_P(SAPBR4); 621 | delay_sec(1); 622 | return 1; 623 | } 624 | 625 | 626 | // -------------------------------------------------------------------------------------- 627 | // POWER SAVING mode on ATMEGA handling to reduce the battery consumption 628 | // only if RI/RING signal from SIM800L is connected to ATMEGA 328P pin INT0 629 | // otherwise program will HANG ! 630 | // it is for FUTURE use... now not used in this program 631 | // -------------------------------------------------------------------------------------- 632 | 633 | void sleepnow(void) 634 | { 635 | 636 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 637 | 638 | sleep_enable(); 639 | 640 | DDRD &= ~(1 << DDD2); // Clear the PD2 pin 641 | // PD2 (PCINT0 pin) is now an input 642 | 643 | PORTD |= (1 << PORTD2); // turn On the Pull-up 644 | // PD2 is now an input with pull-up enabled 645 | 646 | // stop interrupts for configuration period 647 | cli(); 648 | 649 | // update again INT0 conditions 650 | EICRA &= ~(1 << ISC01); // set INT0 to trigger on low level 651 | EICRA &= ~(1 << ISC00); // set INT0 to trigger on low level 652 | EIMSK |= (1 << INT0); // Turns on INT0 (set bit) 653 | 654 | sei(); //ensure interrupts enabled so we can wake up again 655 | 656 | sleep_cpu(); //go to sleep 657 | 658 | // MCU ATTMEGA328P sleeps here until INT0 interrupt 659 | 660 | sleep_disable(); //wake up here 661 | 662 | } 663 | 664 | // when interrupt from INT0 disable next interrupts from RING pin of SIM800L and go back to main code 665 | ISR(INT0_vect) 666 | { 667 | 668 | EIMSK &= ~(1 << INT0); // Turns off INT0 (clear bit) 669 | } 670 | 671 | 672 | 673 | 674 | // ********************************************************************************************************* 675 | // 676 | // MAIN PROGRAM 677 | // 678 | // ********************************************************************************************************* 679 | 680 | int main(void) { 681 | 682 | uint8_t initialized, attempt = 0; 683 | uint8_t cellgpsavailable = 0; 684 | uint32_t nbr50useconds = 0; 685 | 686 | initialized = 0; 687 | attempt = 0; 688 | 689 | // initialize 9600 baud 8N1 RS232 690 | init_uart(); 691 | 692 | DDRD &= ~(1 << DDD2); // Clear the PD2 pin 693 | // PD2 (PCINT0 pin) is now an input 694 | 695 | PORTD |= (1 << PORTD2); // turn On the Pull-up 696 | // PD2 is now an input with pull-up enabled 697 | 698 | // delay 10 seconds for safe SIM808 startup and network registration 699 | delay_sec(10); 700 | 701 | 702 | // try to communicate with SIM800L over AT 703 | checkat(); 704 | delay_sec(2); 705 | 706 | // Fix UART speed to 9600 bps to disable autosensing 707 | uart_puts_P(SET9600); 708 | delay_sec(1); 709 | 710 | // configure RI PIN activity for URC ( unsolicited messages like restart of the modem or battery low) 711 | uart_puts_P(CFGRIPIN); 712 | delay_sec(1); 713 | 714 | // disable reporting of 2G registration URC 715 | uart_puts_P(DISREGURC); 716 | delay_sec(1); 717 | 718 | // Save settings to SIM800L 719 | uart_puts_P(SAVECNF); 720 | delay_sec(3); 721 | 722 | // check pin status, registration status and provision APN settings 723 | checkpin(); 724 | delay_sec(1); 725 | 726 | // disable flighmode 727 | uart_puts_P(FLIGHTOFF); 728 | delay_sec(120); 729 | 730 | // check if attached to 2G network 731 | checkregistration(); 732 | provisiongprs(); 733 | 734 | 735 | // neverending LOOP 736 | while (1) { 737 | 738 | do { 739 | 740 | // WAIT FOR RING message - incoming voice call and send SMS or restart RADIO module if no signal 741 | initialized = 0; 742 | cellgpsavailable = 0; 743 | nbr50useconds = 0UL; 744 | 745 | // delete all SMSes and SMS confirmation to keep SIM800L memory empty 746 | uart_puts_P(SMS1); 747 | delay_sec(1); 748 | uart_puts_P(DELSMS); 749 | delay_sec(2); 750 | 751 | // read phone number of incoming voice call by CLIP, will be needed for SMS sending 752 | uart_puts_P(CLIP); 753 | delay_sec(1); 754 | 755 | // Disable LED blinking on SIM800L 756 | uart_puts_P(DISABLELED); 757 | delay_sec(1); 758 | 759 | // enter SLEEP MODE of SIM800L for power saving ( will be interrupted by incoming voice call or SMS ) 760 | uart_puts_P(SLEEPON); 761 | delay_sec(2); 762 | 763 | 764 | // while SIM800L is sleeping we will be probing SIM800L RI/RING pin status in 50 microseconds intervals 765 | // no to lose any serial port character on 9600 bps speed 766 | // RI is held LOW by SIM800L until call is completely answered / disconnected 767 | // The module SIM800L will be periodically woken up to see coverage status - once per 15-30 min 768 | 769 | while(initialized == 0) 770 | { 771 | // check if RING/INT0/D2 PIN IS LOW - if yes exit WHILE LOOP and proceed witch Call/SMS 772 | if ((PIND & (1 << PD2)) == 0) 773 | {initialized = 1; // RING pin change detected so proceed outside the loop 774 | } 775 | else 776 | { // RING signal is HIGH 777 | nbr50useconds++; // increase number of 50useconds waited 778 | delay_50usec(1UL); // wait another 50usec 779 | // if something like 15min ~ 30min passed 780 | // we need to check if there is need to turn off 2G for longer time 781 | if (nbr50useconds == 18000000UL) 782 | { // if specified amount of second passed 50usec x Y, we need to check 2G network coverage 783 | nbr50useconds = 0; 784 | // wakeup SIM800L module 785 | uart_puts_P(AT); 786 | delay_sec(1); 787 | uart_puts_P(SLEEPOFF); 788 | // check 2G coverage 789 | checkregistration(); 790 | // enter SLEEP MODE of SIM800L again 791 | delay_sec(1); 792 | uart_puts_P(SLEEPON); 793 | delay_sec(2); 794 | // clear the flag that there was no RING 795 | initialized = 0; 796 | }; 797 | }; // end of checking PIN D2 (INT0) 798 | }; // end of WHILE for checking 2G coverage 799 | 800 | 801 | // THERE WAS RI / INT0 INTERRUPT or URC from SERIAL PORT so ATMEGA needs to handle this 802 | if (readline()>0) 803 | { 804 | memcpy_P(buf, ISRING, sizeof(ISRING)); 805 | if (is_in_rx_buffer(response, buf) == 1) 806 | { 807 | // read CALLER MSISDN from output of CLIP 808 | readphonenumber(); 809 | 810 | // disable SLEEPMODE , hangup a call and proceed with sending SMS 811 | uart_puts_P(AT); 812 | delay_sec(1); 813 | uart_puts_P(SLEEPOFF); 814 | delay_sec(1); 815 | uart_puts_P(HANGUP); 816 | delay_sec(1); 817 | 818 | // enable FLAG that RING was received 819 | initialized = 1; 820 | 821 | } // end of IF 822 | 823 | 824 | // if some other message than RING check if network is avaialble and SIM800L is operational 825 | // maybe SIM800L restarted itself or SMS received 826 | // probably never reach this ELSE statement... but just in case... 827 | else 828 | { 829 | 830 | // disable SLEEPMODE 831 | uart_puts_P(AT); 832 | delay_sec(1); 833 | uart_puts_P(SLEEPOFF); 834 | delay_sec(1); 835 | 836 | // check status of all functions 837 | checkpin(); 838 | checkregistration(); 839 | 840 | // there was something different than RING so we need to go back to the beginning 841 | // clear SMS list and enter sleepmode again on SIM800L 842 | initialized = 0; 843 | }; // end of ELSE 844 | 845 | }; // END of READLINE IF 846 | 847 | } while ( initialized == 0); // end od DO-WHILE, go to begging and enter SLEEPMODE again 848 | 849 | // clear the flag we need it later 850 | initialized = 0; 851 | 852 | // Create connection to GPRS network - 3 attempts if needed, if not succesfull restart the modem 853 | attempt = 0; 854 | do { 855 | 856 | //and close the bearer first maybe there was an error or something 857 | delay_sec(1); 858 | uart_puts_P(SAPBRCLOSE); 859 | delay_sec(1); 860 | 861 | // provision GPRS APN setting again just in case 862 | provisiongprs(); 863 | delay_sec(1); 864 | 865 | // make GPRS network attach and open IP bearer 866 | uart_puts_P(SAPBROPEN); 867 | delay_sec(10); 868 | 869 | // query PDP context for IP address after several seconds 870 | // check if GPRS attach was succesfull, do it several times if needed 871 | 872 | uart_puts_P(SAPBRQUERY); 873 | if (readline()>0) 874 | { 875 | // checking for properly attached 876 | memcpy_P(buf, SAPBRSUCC, sizeof(SAPBRSUCC)); 877 | if (is_in_rx_buffer(response, buf) == 1) initialized = 1; 878 | // other responses simply ignored as there was no attach 879 | }; 880 | // increase attempt counter and repeat until not attached 881 | attempt++; 882 | } while ( (attempt < 3) && (initialized == 0) ); 883 | 884 | 885 | // if GPRS was succesfull the it is time send cell info to Google and query the GPS location 886 | if (initialized == 1) 887 | { 888 | 889 | // check battery voltage 890 | delay_sec(1); 891 | uart_puts_P(CHECKBATT); 892 | readbattery(); 893 | 894 | // GET CELL ID OF BASE STATION and query Google for coordinates then send over SMS with google map loc 895 | delay_sec(1); 896 | uart_puts_P(CHECKGPS); 897 | 898 | // parse GPS coordinates from the SIM808 answer to 'longtitude' & 'latitude' buffers 899 | // if possible otherwise some backup scenario 900 | cellgpsavailable=readcellgps(); 901 | // if negative result please allow 60 sec fo SIM808 reboot 902 | if ( cellgpsavailable == 0 ) 903 | { 904 | delay_sec(55); 905 | } 906 | else // proceed with SMS sending 907 | { 908 | delay_sec(1); 909 | // send a SMS in plain text format 910 | uart_puts_P(SMS1); 911 | delay_sec(1); 912 | // compose an SMS from fragments - interactive mode CTRL Z at the end 913 | uart_puts_P(SMS2); 914 | uart_puts(phonenumber); // send phone number received from CLIP 915 | uart_puts_P(CRLF); 916 | delay_sec(1); 917 | // put info about DATE,TIME, LONG, LATITUDE 918 | uart_puts(response); // send Date & Time info from AGPS cell info 919 | uart_puts_P(LONG); // send LONGTITUDE 920 | uart_puts(longtitude); // from buffer 921 | uart_puts_P(LATT); // send LATITUDE 922 | uart_puts(latitude); // from buffer 923 | // put battery info 924 | uart_puts_P(BATT); // send BATTERY INFO 925 | uart_puts(battery); // from buffer 926 | // put link to GOOGLE MAPS 927 | uart_puts_P(GOOGLELOC1); // send http **** 928 | uart_puts(latitude); // send latitude value 929 | uart_puts_P(GOOGLELOC2); // send comma 930 | uart_puts(longtitude); // send longtitude value 931 | uart_puts_P(GOOGLELOC3); // send CRLF 932 | delay_sec(1); 933 | // end the SMS message 934 | send_uart(26); // ctrl Z to end SMS 935 | 936 | }; // End of cellgpsavailable IF 937 | 938 | //and close the bearer 939 | delay_sec(5); 940 | uart_puts_P(SAPBRCLOSE); 941 | 942 | } /// end of commands when GPRS is working 943 | 944 | // now go to the beginning and enter sleepmode on SIM800L and ATMEGA328P again for power saving 945 | delay_sec(10); 946 | 947 | // end of neverending loop 948 | }; 949 | 950 | // end of MAIN code 951 | } 952 | 953 | --------------------------------------------------------------------------------