'********************************************************************
'* SMS Message Relay controller
'* uP:                AT89S2313
'* Language:          BASCOM-AVR 1.11.8.7
'* Originally posted: 2005.Feb.27
'* Last updated:      2007.Nov.19
'* Version:           V1.10
'********************************************************************
$regfile = "2313def.dat"
$crystal = 8000000
$baud = 19200
 
Const Dlcd = 0
 
Dim Rs232_exit As Byte
Dim Read_ok As Bit
Dim Data_ok As Bit
Dim Sync_ok As Bit
Dim Read_num As Byte
 
Dim Read_select As Byte
Dim S2 As String * 40
Dim Gsm_signal As String * 3
 
Dim Time1_count As Byte
Dim Time1_ok As Bit
Dim Ch As Byte
Dim S2addr As Integer
 
Read_noop Alias 0
Read_gsm_sta1 Alias 1
Read_gsm_m1 Alias 2
 
Dim Relay(4) As Byte
Control_char Alias 0
Status_action Alias 1
Single_action Alias 2
Multiple_action Alias 3
Invalid_action Alias 4
On_action Alias 5
Off_action Alias 6
Toggle_action Alias 7
 
#if Dlcd
Declare Sub Lcdlocation(byval Row As Byte , Byval Col As Byte)
#endif
 
Config Portb = Output
 
' Set all Relays OFF
Relay(1) = 2 : Relay(2) = 3 : Relay(3) = 4 : Relay(4) = 7
For Ch = 1 To 4
  Set Portb.relay(ch)
Next Ch
 
#if Dlcd
'Serial connection to LCD is via Port B.6
'LCD runs at 9600 baud
Open "comb.6:9600,8,n,1" For Output As #2
 
'LCD Reset pin is driven from PortB.5
Reset Portb.5                                               'Drive pin low
Waitms 400
Set Portb.5                                                 'Then high
Waitms 400
#endif
 
' Once enabled, the timer counts each clock period (or you can select a
' divided down input clock if you prefer). When the timer overflows (65536
' counts) you get an interrupt. With a 8MHz clock, this doesn't work out to
' anything very useful. At 8MHz, each clock pulse is 125nS and 65536 of them
' is 8.192 milliseconds.
 
' I want a timer that resolves to 1000mS, so the first step is to divide down
' the input clock .  Input clock to divide by 256, so now each clock pulse is
' worth (8.192/256)=32uS.
 
' The trick is to preload the counter with a value that will cause it to count
' for 1000mS. Each time the counter expires, you can force the new number back
' into the timer register. We need 1/.000032 or 31250 counts. However, the
' counter expires at 65536, so the correct number to preload is 65536-31250 or
' 34285 This way, the timer will count up 31250 counts (1 second) and
' expire.
 
Const 1000ms = 34285
Config Timer1 = Timer , Prescale = 256
 
On Timer1 Timer1_int
On Urxc Rec_rs232                                           'define serial receive ISR
 
' Initialize the GSM Modem
Print "AT&FE0V0+CMGF=1;+CNMI=2,1,0,0,0"
 
Time1_count = 0 : Timer1 = 1000ms : Time1_ok = 0
Enable Timer1
Enable Interrupts
 
Start Timer1
 
Do
  If Time1_ok = 1 Then                                      ' Timer fires every 1 sec and wraps at 10sec
      Read_ok = 0 : Read_num = 0 : Data_ok = 0 : Rs232_exit = 0 : Sync_ok = 0
      Stop Timer1
 
      If Time1_count = 5 Then                               ' t+5
            Read_select = Read_gsm_m1
            Print "AT+CMGR=1"                               ' Read Message
            Gosub Rs232_r
            If Data_ok = 1 Then
               Print "AT+CMGD=1"                            ' Delete Message
               #if Dlcd
               Call Lcdlocation(3 , 0)
               Print #2 , "Msg: " ; S2
               #endif
               Gosub Read_message
               Time1_count = Time1_count + 5
            End If
      Elseif Time1_count = 3 Then                           ' t+3
            Read_select = Read_gsm_sta1 : Gsm_signal = ""
            Print "AT+CSQ"                                  ' Signal Quality
            Gosub Rs232_r
            If Read_ok = 0 Then Gsm_signal = "--"           'If Timeout waiting for Response
            #if Dlcd
            Call Lcdlocation(1 , 14)
            Print #2 , "Signal: " ; Gsm_signal ;
            #endif
      End If
 
      Reset Time1_ok
      Start Timer1
   End If
Loop
 
Timer1_int:
   Timer1 = 1000ms
   Set Time1_ok
   Incr Time1_count
   Incr Rs232_exit
   If Time1_count > 9 Then Time1_count = 0                  ' 10 * 1sec = 10sec
   Return
 
Rec_rs232:
   Incr Read_num
      If Read_select = Read_gsm_m1 Then
'+CMGR: "REC READ","+447762722186",,"05/02/26,11:07:47+00" chr(13)chr(10)
'Hello  chr(13)chr(10)
          If Udr = 43 And Sync_ok = 0 Then     '"+"-->43
            Read_num = 1
            Sync_ok = 1
            S2 = ""
          Elseif Sync_ok = 1 Then
             Select Case Read_num
               Case 5:
                  If Udr <> 82 Then Read_ok = 1             '"R"-->82
               Case Else
                  If Data_ok = 1 Then
                     If Udr = 13 Then                       ' Until 1st chr(13)
                        Read_ok = 1
                     Else                                   ' Accumulate data
                        S2 = S2 + Chr(udr)
                     End If
                  End If
                  ' Read to end of first line before we are ready
                  If Udr = 10 Then Data_ok = 1
            End Select
         End If
   ' Signal quality check
      Elseif Read_select = Read_gsm_sta1 Then
'+CSQ: 31,99
         If Udr = 43 Then Read_num = 1
         Select Case Read_num
            Case 4:
               If Udr <> 81 Then Read_ok = 1                '"Q"-->81
            Case 7 To 8:
               '"0..9"-->48..57
               If Udr > 47 And Udr < 58 Then Gsm_signal = Gsm_signal + Chr(udr)
            Case 9:
               Read_ok = 1
         End Select
      End If
 
   Rs232_exit = 0                                           'Reset RS232 timeout
   Return
 
Rs232_r:
   Udr = 0
   Reset Usr.7
   Reset Ucr.7
   Enable Urxc                                              'enable receive isr
   Start Timer1
   Do
     If Rs232_exit > 3 Then Exit Do
   Loop Until Read_ok = 1
   Disable Urxc
   Stop Timer1
   Return
 
 
'Inbound String From The Gsm Modem Will Have The Following Syntax:
' a. R - Single Relay action followed by [SRT]
'      - Set / Reset / Toggle action and a number of the relay [1-4]
'
'        RS2 - Set relay number 2 (ON).
'        RR4 - Reset relay number 4 (OFF)
 
Read_message:
' Use address pointer its more efficent than this--> mid(s2,read_num,1)
   S2addr = Varptr(s2)
   Read_select = Control_char
   For Read_num = 1 To Len(s2)
     Ch = Inp(s2addr)
     Incr S2addr
 
     Select Case Read_select
       Case Control_char:
            Select Case Ch
'                 Case 83 : Read_select = Status_action      '"S"-->83
                 Case 82 : Read_select = Single_action      '"R"-->82
                 Case Else Read_select = Invalid_action
            End Select
       Case Single_action:
         Select Case Ch
            Case 82 : Read_select = Off_action              '"RR"
            Case 83 : Read_select = On_action               '"RS"
            Case Else Read_select = Invalid_action
         End Select
       Case On_action:
         If Ch > 47 And Ch < 53 Then                        ' 1..4
           Ch = Ch - 48
           Reset Portb.relay(ch)
         End If
       Case Off_action:
         If Ch > 47 And Ch < 53 Then                        ' 1..4
           Ch = Ch - 48
           Set Portb.relay(ch)
         End If
     End Select
     Next
   Return
 
#if Dlcd
Sub Lcdlocation(byval Row As Byte , Byval Col As Byte)
  Col = Col + 32
  Row = Row + 32
  Print #2 , "\B" ; Chr(col) ; Chr(row);
End Sub
#endif