Page History: SMS (Text) Gateway with MicroMite
Compare Page Revisions
Page Revision: 2016/12/28 07:49
This SMS gateway attaches to your LAN via WiFi (Want to provide wired LAN through ENC28J60 one day). It takes a SIM card for your favourite GSM operator and connects to that mobile network. It then bridges the two and permits messages to be passed between them. Security is pretty low at the moment, but firewall external access for now.
Program-wise, there is nothing exotic about it - no CFunctions or anything, it is a good demonstration of using the building blocks in MMBasic to provide an intelligent (and for me) really useful tool that sees daily use. It represents about two months of evolving code with tears, tantrums, a few late nights and a lot of head scratching... READ THE DATASHEETS - over and over until they make sense.
It exposes a web API allowing text messages to be sent via a web browser or any HTTP client (i.e. your own programs). These are then forwarded in real time to the GSM network. The API is multi-session and up to 5 simultaneous connections to the API are supported. Sending of SMS messages is single session but because sending is handled on the main thread it naturally pauses the parsing while a text is sent so it providing an implicit queuing system. Messages seem to take about 5 seconds-ish to actually go from the GSM module, so the real time response (i.e. confirmation from the API) is entirely do-able. My own webpage code waits for the response and parses the reply from the API.
Inbound SMS messages are largely ignored (and deleted from the SIM) as of Version 1.1 except for a specially crafted message from an "admin" mobile number. Upon receipt it activates a relay for 10 seconds, sending a message to the effect either side of the activation. For my application, I connected a mains extension through the Normally Closed contacts of a relay module. This feeds the mains power to the PSU for my fibre router. This router suffers from mystery lockups every few months. By sending my "crafted" message, I can remotely bounce the router through a controlled 10 second power cycle from anywhere on the planet. As a frequent traveler, I have tired of trying to talk "remote hands" through the procedure, even though to me it is trivial. Used this feature recently from Madeira when my network went dark. The gateway pings out to the internet at regular intervals (I ping one of my ISPs DNS serves - be careful who you ping - they might not like it) and alerts after a set number of fails, so I might not even know I have lost connectivity but this gateway will tell me. It then confirms when the internet connectivity comes back.
It is a bit rough round the edges, but it does it's job well.
Future improvements:
- Full 2-way messaging convergence is the long-term target with this device. Pass inbound SMS to an API (web page on [remote] server) - will use the ESP8266 in client mode and is fairly straightforward, but will need to craft the HTTP chatter to/from the server. Those "to evict Tom from the big brother house, text TOM to ..." systems would be very easy to implement once this is done. The web page on the server would be responsible for the data processing once the SMS hase been off-loaded from the gateway.
- Some kind of validation (password/encryption).
Software is stable but still evolving but for now it demonstrates a reasonably robust working solution. It has run continuously for weeks with no problems - in fact the only problems I did have were with a weak Vodafone signal that meant the M590 was constantly trying to register on the network. Recently went to a Virgin SIM on a £6 a month unlimited texts deal and it has never failed yet!
Full functionality list and software will follow, Circuit diagram is below - there are numerous connectors for modules cheaply available on eBay - the whole thing should cost you less than £20.
The LCD is currently unused (although a header is there) and rich logging is provided through the CH340G USB interface which connects to the console of the micromite. The idea being eventually that it becomes a self-contained module and an LCD display will provide status etc. There's no need to leave it plugged in to putty all the time (but I do coz I love logs).
Circuit Diagram The M590 module has a dodgy voltage dropper in the form of a single diode, and the power rail is marked as +5V. It relies on the forward voltage of the 1N4001 to bring the power in line with the M590's working spec - a practice expressly forbidden in the documentation, but hey what do the Chinese care so long as they can sell stuff. This caused me lots of problems early on with the modem section resetting out-of-the-blue. I replaced the diode with a wire link (in the photo, between the SIM and M590) and drove it from the 3.3V - it is perfectly happy now it's working in accordance with the spec :o/ beware cheap modules I guess. I also modified the module by bringing the "EMERGPDOWN" pin of the M590 (effectively a reset) out to the header so I can reset the thing. Normally this isn't available on these modules and you have a power toggle signal that mimics the power button on a mobile... problem is because it is a toggle, you can never be certain of the state of the module. As I found out when it was running from 5v, you can get weird outages, toggle the power to try and resolve it and find you have actively turned the thing off (because it was actually on but not responding)... horrible arrangement.
Completed working unit (yet to be cased nicely). Power is from a 5V3A "wallwart", 5v for the relay module and LCD, everything else is 3.3v from a 3A DC-DC converter module which gives a juicy power rail - specifically for the GSM module which can draw up to 1A with a weak mobile signal and the ESP8266 can draw 280mA, so bags of power for everything.
Sending a text message from a web page...... received on the SMS Gateway API... Output from the console log
...and the same text received on my mobile phone.Here is a procession of recieved SMS messages. this shows a typical life cycle together with some power cycling.
Here is the source code... remember this is very specific to my application, you'll have to pick through it if you want to use it and add/remove any bits you like. Please use the discuss option to ask questions, that way everyone sees the thread and you will likely answer the same questions they have ;o)
'Preamble
OPTION BASE 0
CONST Secs=1000
CONST Mins=Secs*60
CONST Hrs=Mins*60
CONST GSM=1,GSMRST=16
CONST LAN=2,LANRST=2
CONST RL1=15,RL1Time=10000
CONST DailySMS="05:59" ' Set to "-1" to prevent the daily test SMS
CONST PA=CHR$(34)+"8.8.8.8"+CHR$(34) ' the internet connectivity ping address, e.g. something close in your ISP
CONST PingCTRRecharge=3
CONST DownReminder=5
CONST WDTime=60000
CONST AdminPH$="+447xxxxyyyyyy" ' the "admin" mobile phone e.g. yours.
CONST ContMsg="101561019110156BOUNCE" ' the control message to activate the slave relay... suitably cryptic for you.
CONST PingTMRRecharge=180 'secs
CONST GSMTMRRecharge=60 'Secs
CONST IP=CHR$(34)+"192.168.0.14"+CHR$(34) ' the static address to assign to the LAN interface ...
CONST GW=CHR$(34)+"192.168.0.1"+CHR$(34) ' ... and it's gateway...
CONST MS=CHR$(34)+"255.255.255.0"+CHR$(34)' ... and its netmask
CONST AP=CHR$(34)+"XYZ"+CHR$(34) ' your WiFi SSID (name of your wifi lan)...
CONST PW=CHR$(34)+"######"+CHR$(34) ' ... and its password - sorry this is plain text, later versions will hide this
'H/W Init
WATCHDOG OFF
PIN(LANRST)=1
SETPIN LANRST,DOUT
PIN(GSMRST)=0 'hold GSM in reset to prevent booting
SETPIN GSMRST,DOUT,OC
PIN(RL1)=1
SETPIN RL1,DOUT,OC
'S/W Init
DIM STRING A$,B$,D$
DIM STRING LNBuf$
DIM STRING LANRxLN$,LANTxLN$,TChr$ LENGTH 1,LCDLN1$ LENGTH 16,LCDLN2$ LENGTH 16
DIM INTEGER h,m,C,Z,TOFg,Chan,Conn(4),PingTMR,PingCtr,RL1TMR,DailySMSFg
DIM INTEGER LANf,GSMf,DistSMSCount,OBSMSCount,IBSMSCount
DIM FLOAT x
CLog "SMS Gateway V1.1",0
SetClock
IF MM.WATCHDOG then
CLog "*** RESTART FORCED BY WATCHDOG ***",0
END IF
a$=Replace$(DS$(),":","")
a$=Replace$(a$,"-","")
LCDLN2$= MID$(a$,3,6) + MID$(a$,10,4) + STRING$(6," ")
TChr$=" "
BuildLCD
CLog "System coming up",0
'timer inits
PingTMR=PingTMRRecharge
GSMPollTMR=GSMTMRRecharge
PingCtr=1
RL1TMR=-1
CLog "Starting LAN Interface",0
TIMER=0
Open "COM2:9600,1024" As #LAN
ESP8266Reset
CLog "... LAN up in "+STR$(TIMER)+"mS",0
CLog "Starting GSM Interface",0
Chan=TIMER
Open "COM1:9600,8192" As #GSM
M590Reset
CLog "... GSM up in "+STR$(TIMER-Chan)+"mS",0
CLog "Starting Core timer thread",0
SETTICK 1*Secs,CoreTMR,4
CLog "Boot took "+STR$(TIMER)+"mS",0
CLog "System Running",0
z=GSMSend(AdminPH$,"SMS Gateway has started")
Main:
WATCHDOG=WDTime
IF LEFT$(TIME$,5)=DailySMS THEN
IF DailySMSFg=0 THEN
z=GSMSend(AdminPH$,"SMS Gateway daily test. " + DATE$ + " " + TIME$)
DailySMSFg=1
END IF
ELSE
DailySMSFg=0
END IF
IF RL1TMR=0 then
RL1TMR=-1
A$="Slave socket power ON"
PIN(RL1)=1
CLog A$,0
z=GSMSend(AdminPH$,A$)
CLog "{response="+str$(z)+"}",0
END IF
IF PingTMR<=0 THEN
PingTMR=PingTMRRecharge
SetClock 'convenient place
CLog "Internet connectivity...",0
A$=ESP8266Exec$("AT+PING="+PA,4000,0)
IF A$="OK" THEN
CLog "... good",0
LANf=0:DistSMSCount=0
PingCtr=PingCTRRecharge
IF PingCtr<=0 THEN
'send "UP" sms
CLog "*** back up message",0
z=GSMSend(AdminPH$,"Internet UP")
END IF
ELSE
LANf=LANf+1:IF LANf>9 THEN LANf=9
CLog "Internet Down",0
PingCtr=PingCtr-1
IF PingCtr=0 THEN
'send "DOWN" sms
CLog "*** Internet down message",0
z=GSMSend(AdminPH$,"Internet DOWN, please check")
ELSE
CLog "... for "+STR$(PingCtr),0
x=ABS(PingCtr)/DownReminder
IF x=INT(x) AND x>0 THEN 'whole ten minute periods
'send "STILL DOWN" sms
DistSMSCount=DistSMSCount+1:IF DistSMSCount>99 THEN DistSMSCount=99
CLog "*** Still down message",0
z=GSMSend(AdminPH$,"Internet remains DOWN, please check")
END IF
END IF
END IF
END IF
IF GSMPollTMR<=0 THEN
GSMPollTMR=GSMTMRRecharge
CLog "GSM connectivity...",0
A$="AT+CREG?"
A$=M590Exec$(A$,2,0,"+CREG: 0,1|+CREG: 0,4")
IF A$="T/O" OR A$="ERROR" THEN
CLog A$,0
GSMf=GSMf+1:IF GSMf>9 THEN GSMf=9
CLog "GSM registration Down",0
ELSE
CLog A$,0
CLog "... good",0
GSMf=0
END IF
FlushIO(GSM)
'check recieved messages
A$="AT+CMGL=4"
CLog A$,0
PRINT#GSM,A$
PAUSE 500
'messages look like this:
'+CMGL: 1,"REC UNREAD","+447000123456","","16/10/07,22:11:35+04"
'message body
DO
A$=GetIO$(GSM,2)
IF A$<>"" then CLog A$,0
IF A$="OK" THEN EXIT DO
'IF A$="ERROR" THEN ' get extended info
' PRINT #GSM,"AT+CEER"
' PAUSE 500
' DO
' A$=GetIO$(GSM,2)
' CLog A$,0
' LOOP UNTIL A$="OK" or A$="T/O"
' EXIT DO
'END IF
IF INSTR(A$,"+CMGL:") THEN 'the envelope
B$=GetIO$(GSM,2) 'the message
CLog B$,0
A$=Replace$(A$,CHR$(34),"")
z=Split(A$,",")
' 1 2 3 4 5 6
'+CMGL: 1,REC UNREAD,telno,,16/10/07,22:11:35+04
IF SP$(2)="REC UNREAD" THEN
IF RTRim$(SP$(3))=AdminPH$ THEN
IF UCASE$(B$)=ContMsg THEN
A$="Slave socket power OFF"
CLog A$,0
PIN(RL1)=0
RL1TMR=10
z=GSMSend(AdminPH$,A$)
CLog "{response="+str$(z)+"}",0
END IF
END IF
END IF
END IF
LOOP
A$="AT+CMGD=1,1"
A$=M590Exec$(A$,2,0,"OK")
FlushIO(GSM)
END IF
'Console INPUT - Parse any commands here
'Web API parsing
LANRxLN$=GetIO$(LAN,1)
IF LANRxLN$="" OR LANRxLN$="T/O" THEN GOTO Main
CLog LANRxLN$,0
IF MID$(LANRxLN$,2,8)=",CONNECT" THEN 'new inbound web connection
Chan=VAL(LANRxLN$)
IF Chan>=0 AND Chan<=4 THEN
Conn(Chan)=1
CLog "Inbound connect channel "+STR$(Chan),0
GOTO IPEXIT
END IF
END IF
IF MID$(LANRxLN$,2,7)=",CLOSED" THEN ' web connection closed
Chan=VAL(LANRxLN$)
IF Chan>=0 AND Chan<=4 THEN
IF Conn(Chan)=0 THEN A$="Abnormally " ELSE A$=""
CLog "Closed channel "+STR$(Chan),0
Conn(Chan)=0
GOTO IPEXIT
END IF
END IF
IF LEFT$(LANRxLN$,5)="+IPD," THEN ' web connection payload
Chan=VAL(MID$(LANRxLN$,6,1))
IF Chan>4 THEN GOTO IPDerrEXIT
IF Conn(Chan)<>1 THEN GOTO IPDerrEXIT 'channel not open
z=INSTR(LANRxLN$,":GET /smssend?") '+IPD,0,nnn:GET /smssend?tel=?msg= HTTP/1.1
do:a$=GetIO$(LAN,2):loop until a$="Connection: Keep-Alive" ' empty the rest of the envelope
IF z=>8 AND Z<=11 THEN
b$=MID$(LANRxLN$,z+13)
z=INSTR(b$," HTTP/")
IF z<21 THEN GOTO IPDerrEXIT
b$=LEFT$(b$,z-1) 'remove the HTTP bit
b$=Replace$(b$,"+"," ") ' + to spaces
args=Split(b$,"?")
IF args <3 THEN GOTO IPDerrEXIT
Tel$="":Msg$=""
FOR n=2 TO args 'args=1 is a dummy
SELECT CASE LEFT$(ucase$(SP$(n)),4)
CASE "TEL="
Tel$=LTrim$(RTrim$(MID$(sp$(n),5)))
CASE "MSG="
Msg$=LTrim$(RTrim$(MID$(sp$(n),5)))
END SELECT
NEXT
IF Tel$="" OR Msg$="" THEN GOTO IPDerrEXIT
ERASE SP$
Msg$=URLDecode$(Msg$)
CLog "O/B SMS "+Tel$+":"+Msg$,0
z=GSMSend(Tel$,Msg$)
IF z=0 THEN
B$="OK: Message Queued for sending":GOTO IPOKEXIT
ELSE
B$="ERROR: Gateway failed to send message {"+STR$(z)+"}"
GOTO IPOKEXIT
END IF
' other web API commands parsd here
'z=INSTR(LANRxLN$,":GET /stat ") '+IPD,0,nnn:GET /stat HTTP/1.1
'IF z=>8 AND Z<=11 THEN
'other API calls go here...
'z=INSTR(LANRxLN$,":GET /whatever?")
'IF z<>0 THEN
'etc...
' B$="OK: STAT="+LCDLN1$+LCDLN2$
' GOTO IPOKEXIT
END IF
GOTO IPDerrEXIT 'default action IF we don't find an API call
END IF
GOTO IPEXIT
IPDerrEXIT:
B$="ERROR: Malformed request {"+LANRxLN$+"}"
IPOKEXIT:
PRINT #LAN,"AT+CIPSENDEX="+STR$(Chan)+",255"
PAUSE 100
PRINT#LAN,B$+"\0"
PAUSE 100
PRINT#LAN,"AT+CIPCLOSE="+STR$(Chan)
Conn(Chan)=0
IPEXIT:
GOTO Main
END
'------------------ ESP8266 WiFi Modem SUBsys -------------
SUB ESP8266Reset
LOCAL STRING A$
LOCAL INTEGER N
PULSE LANRST,10
PAUSE 400
LANExec "ATE0",2,0
LANExec "AT+CWAUTOCONN=0",2,0
LANExec "AT+CWMODE=1",2,0
LANExec "AT+CWQAP",4,0
LANExec "AT+RFVDD",2,0
LANExec "AT+CWJAP="+AP+","+PW,10,1
LANExec "AT+CIPSTA="+IP+","+GW+","+MS,2,0
LANExec "AT+CIFSR",2,0
LANExec "AT+CWAUTOCONN=1",2,0
LANExec "AT+CIPMUX=1",2,0
LANExec "AT+CIPSERVER=1,19090",2,0
LANTxLN$="":LANRxLN$=""
FOR N=0 TO 4:Conn(N)=0:NEXT
END SUB
SUB LANExec(CM$,T,Suppress) 'temp - will go when we have better handling of the startup
LOCAL STRING A$
A$=ESP8266Exec$(CM$,T,Suppress)
IF Suppress<2 THEN CLog A$,0
END SUB
FUNCTION ESP8266Exec$(Com$,TimeOut,Obf)
LOCAL STRING A$ LENGTH 1,LN$
LOCAL INTEGER C
CLog Com$,obf
PRINT #LAN,Com$
DO
LN$=GetIO$(LAN,TimeOut)
IF LN$="T/O" THEN ESP8266Exec$="T/O":EXIT DO
IF LN$<>"" THEN
IF Obf<2 THEN CLog "["+LN$+"]",0
IF LN$="OK" OR LN$=">" OR LN$="SEND OK" THEN ESP8266Exec$=LN$:EXIT DO
IF INSTR(LN$,"ERROR") THEN ESP8266Exec$="ERROR ["+LNBuf$+"]":EXIT DO
END IF
LOOP
END FUNCTION
'------------------ M590 GSM Modem SUBsys -----------------------
SUB M590Reset
LOCAL STRING A$
LOCAL INTEGER N
PIN(GSMRST)=0 'can't use pulse because it should already be lo
PAUSE 500 'BOOT is active LO and at least 300mS
PIN(GSMRST)=1
ClearTOTimer
DO
IF TOFg THEN GOTO GSMFail
A$=GetIO$(GSM,5)
CLog A$,0
LOOP UNTIL A$="MODEM:STARTUP"
'ClearTOTimer
'PRINT#GSM,"AT+ENPWRSAVE=0" 'solves slow +PBREADY ?
ClearTOTimer
DO
IF TOFg THEN GOTO GSMFail
A$=GetIO$(GSM,120)
CLog A$,0
LOOP UNTIL A$="+PBREADY"
FlushIO(GSM)
GSMExec "ATE0",2,0,"OK" '(TURN OFF LOCAL ECHO)
FlushIO(GSM)
GSMExec "AT+CPAS",2,0,"+CPAS: 0"
IF TOFg THEN GOTO GSMFail
DO ' forever
'FlushIO(GSM)
'GSMExec "AT+CREG?",2,0,"+CREG: 0,1" '(MODULE IS REGISTERED ON THE NETWORK)
PRINT #GSM,"AT+CREG?"
DO:A$=GetIO$(GSM,2):LOOP WHILE LEN(A$)=0
CLog A$,0
IF TOFg THEN GOTO CREGWait
IF INSTR(A$,"+CREG:") THEN
IF INSTR(A$,"+CREG: 0,1")=0 THEN
GOTO CREGWait
ELSE
CLog "Registered on GSM network",0
GSMf=0
EXIT DO
END IF
END IF
CREGWait:
CLog "Waiting for GSM network registration",0
PAUSE 5000
FlushIO(GSM)
GSMf=1
LOOP
IF GSMf THEN GOTO GSMFail
GSMf=0
GSMExec "AT+ENPWRSAVE=0",2,0,"OK"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+COPS?",2,0,"OK"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+CSQ",2,0,"OK"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+XBANDSEL?",2,0,"OK"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+CCID?",2,0,"OK"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+CSCA?",2,0,"OK"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+CFUN?",2,0,"+CFUN: 1,0"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+CPIN?",2,0,"+CPIN: READY"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+CSMS?",2,0,"OK"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+CMGF=1",2,0,"OK"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+CSCS="+CHR$(34)+"GSM"+CHR$(34),2,0,"OK"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
GSMExec "AT+CMGD=1,1",2,0,"OK"
IF TOFg THEN GOTO GSMFail
FlushIO(GSM)
EXIT SUB
GSMFail:
CLog "... Failed to start in "+STR$(TIMER-Chan)+"mS",0
GSMf=1
END SUB
SUB GSMExec(CM$,T,obf,Resp$)
LOCAL STRING A$
A$=M590Exec$(CM$,T,obf,Resp$):CLog A$,0
END SUB
FUNCTION M590Exec$(Com$,TimeOut,obf,Resp$)
LOCAL STRING A$ LENGTH 1,LN$,LNBuf$
LOCAL INTEGER C,n,z
CLog Com$,obf
z=Split(Resp$,"|")
PRINT #GSM,Com$
StartTOTimer TimeOut
DO
IF TOFg=1 THEN M590Exec$="T/O ["+LNBuf$+"]":EXIT DO
IF LOC(#GSM)<>0 THEN
A$=INPUT$(1,#GSM):C=ASC(A$)
SELECT CASE C
CASE 13
IF LN$<>"" THEN
LNBuf$=LNBuf$+LN$
CLog "["+LNBuf$+"]",0
FOR n=1 TO z
IF LN$=SP$(n) THEN M590Exec$=LN$:EXIT DO
NEXT
IF INSTR(LN$,"ERROR") THEN M590Exec$="ERROR ["+LNBuf$+"]":EXIT DO
LN$="":LNBuf$=""
END IF
CASE 0 TO 31
CASE ELSE
LN$=LN$+A$
END SELECT
END IF
LOOP
ClearTOTimer
END FUNCTION
FUNCTION GSMSend(t$,m$)
LOCAL INTEGER n
LOCAL STRING A$
IF GSMf<>0 THEN GSMSend=10191:EXIT FUNCTION
a$="AT+CMGS="+chr$(34)+t$+CHR$(34)
PRINT#GSM,A$
CLog A$,0
PAUSE 1000
a$=LEFT$(m$,140)
PRINT#GSM,A$+CHR$(26);
CLog a$,0
PAUSE 100
DO
A$=GetIO$(GSM,15)
CLog A$,0
IF INSTR(A$,"+CMGS:") THEN GSMSend=0:EXIT FUNCTION
IF A$="T/O" THEN EXIT DO
LOOP
GSMSend=10156
END FUNCTION
'----------------------------------------------------
SUB CLog(Com$,obf)
SELECT CASE Obf
CASE 0
PRINT DS$();Com$
CASE 1
PRINT DS$();STRING$(20,"#")
CASE ELSE
END SELECT
END SUB
FUNCTION GetIO$(io,TimeOut)
LOCAL STRING a$,b$
LOCAL INTEGER c
StartTOTimer TimeOut
DO
IF TOFg=1 THEN GetIO$="T/O":EXIT DO
IF LOC(#io)<>0 THEN
A$=INPUT$(1,#io):C=ASC(A$)
SELECT CASE C
CASE 13
GetIO$=b$:EXIT DO
CASE 0 TO 31
CASE ELSE
IF LEN(b$)+LEN(a$)<255 THEN b$=b$+a$ ELSE b$=a$
END SELECT
END IF
LOOP
ClearTOTimer
END FUNCTION
SUB FlushIO(stream)
LOCAL STRING A$
DO WHILE LOC(#stream)<>0
PAUSE 50:A$=INPUT$(LOC(#stream),#stream):PAUSE 50
LOOP
END SUB
SUB CoreTMR
PingTMR=PingTMR-1
GSMPollTMR=GSMPollTMR-1
RL1TMR=RL1TMR-1
IF TChr$="*" THEN TChr$=" " ELSE TChr$="*"
BuildLCD
END SUB
SUB StartTOTimer(Timeout)
TOFg=0:SETTICK TimeOut*1000,SetTOFg,2
END SUB
SUB ClearTOTimer
SETTICK 0,0,2:TOFg=0
END SUB
SUB SetTOFg
TOFg=1
END SUB
SUB SetClock
RTC GETTIME
END SUB
SUB BuildLCD
LCDLN1$="L" + STR$(LANf) + "G" + STR$(GSMf) + "S" + STR$(PIN(16)) + "O" + STR$(OBSMSCount,4,0,"0") + "I" + STR$(IBSMSCount,4,0,"0")
LCDLN2$=LEFT$(LCDLN2$,10) + " " + TChr$ + STR$(DistSMSCount,2,0,"0")
'PRINT LCDLN1$:PRINT LCDLN2$:PRINT
END SUB
FUNCTION DS$()
LOCAL a$,b$
DO:a$=date$:b$=time$:LOOP WHILE a$<>date$ OR b$<>time$
DS$=RIGHT$(a$,4)+MID$(a$,3,3)+"-"+LEFT$(a$,2)+" "+b$+" "
END FUNCTION
FUNCTION Replace$(a$,b$,c$)
LOCAL INTEGER z
LOCAL STRING x$,y$
z=1
DO
z=INSTR(z,a$,b$)
IF z=0 THEN EXIT DO
x$=LEFT$(a$,z-1):y$=MID$(a$,z+LEN(b$)):a$=x$+c$+y$:z=LEN(x$)+LEN(c$)
LOOP
Replace$=a$
END FUNCTION
FUNCTION URLDecode$(a$)
LOCAL INTEGER z
LOCAL STRING b$,c$
z=1
DO
z=INSTR(z,a$,"%")
IF z=0 OR z=LEN(a$) THEN EXIT DO
b$=MID$(a$,z,3):c$=CHR$(VAL("&h"+MID$(b$,2))):a$=Replace$(a$,b$,c$)
LOOP
URLDecode$=a$
END FUNCTION
FUNCTION LTrim$(a$)
LOCAL INTEGER m
FOR m=1 TO LEN(a$)
IF not(MID$(a$,m,1)=" " OR MID$(a$,m,1)=CHR$(9)) THEN LTrim$=MID$(a$,m):EXIT FUNCTION
NEXT
LTrim$=""
END FUNCTION
FUNCTION RTrim$(a$)
LOCAL INTEGER n
FOR n=LEN(a$) TO 1 STEP -1
IF not(MID$(a$,n,1)=" " OR MID$(a$,n,1)=CHR$(9)) THEN RTrim$=LEFT$(a$,n):EXIT FUNCTION
NEXT
RTrim$=""
END FUNCTION
FUNCTION Split(a$,b$)
LOCAL INTEGER z,n,m
ON ERROR SKIP
ERASE SP$
z=1:n=0
DO
z=INSTR(z,a$,b$)
IF z=0 THEN
IF n=0 THEN
DIM SP$(1):SP$(1)=a$:Split=1:EXIT FUNCTION
ELSE
EXIT DO
END IF
ELSE
n=n+1:z=z+LEN(b$)
END IF
LOOP
m=n+1:n=1
DIM SP$(m)
DO
z=INSTR(1,a$,b$)
IF z=0 THEN
SP$(m)=a$:EXIT DO
ELSE
SP$(n)=LEFT$(a$,z-1):a$=MID$(a$,z+LEN(b$)):n=n+1
END IF
LOOP
Split=m
END FUNCTION