1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
rem Email320.bas
rem
rem last revision 2005 May 13
rem

rem send an Email from a Tiger 320 with Ethernet module
rem when capture pin is connected to common;
rem LED6 indicates that a message is being sent

rem the macro makes use of the XPorts modem mode to
rem establish a connection - once established it is plain SMTP
rem
rem see RFC 821 for more details on SMTP
rem
rem XPort modem mode set to 'Without Echo' so we get only SMTP replies
rem
rem the IP and Gateway address of the Tiger have
rem to be setup correctly in the Ethernet module

DIM MSG[] = [ "", \
              "Email rejected", \
              "Email permanently disabled !!!", \
              "Communication timed out", \
              "Done", \
              "      " ] 

// MSG[] index, also used as #msg value
CONST mNONE = 0
CONST mREJECTED = 1
CONST mMAIL_DISABLED = 2
CONST mTIMEOUT = 3
CONST mDONE = 4
CONST mSPACE = 5

// other #msg values
CONST mRESTART = 7
CONST mRESET_MODEM = 8
CONST mDISCONNECT = 9
CONST mCONNECT = 10
CONST mHELO = 11
CONST mFROM = 12
CONST mTO = 13
CONST mDATA = 14
CONST mdFROM = 15        // not mandatory
CONST mdTO = 16          // not mandatory
CONST mdSUBJECT = 17     // not mandatory
CONST mdPRIORITY = 18    // not mandatory
CONST mdLINE1 = 19       // the actual mail body
CONST mEND_MESSAGE = 20

// #state values
CONST sIDLE = 0
CONST sSEND = 1
CONST sWAIT_FOR_REPLY = 2  // wait for SMTP replies
CONST sWAIT = 3            // pauses for modem commands
CONST sERROR = 4
CONST sRESET = 5

// serial setup
CONST SLAVE_MODE = 0000
CONST MASTER_MODE = 0002
MEM &CODE3 = SLAVE_MODE
MEM &STRING_LENGTH = 0         // replies have variable length
MEM &STRING_CHARACTER = CR     // all SMTP replies should end with CR/LF

// don't wait forever for replies
CONST TIMEOUT = 300 // 30.0 secs (only the CONNECT should take that long)

// there has to be a pause >1sec before and after the '+++' for disconnect
CONST MODEM_TIMEOUT = 12

// don't send messages when a permanent messaging failure has occured
BITREG &USER_MEMORY_1 = [ |SEND_MESSAGE ]
MEM &USER_MEMORY_1 = 0x0001  // send messages

// mail priority
CONST PRIORITY_HIGHEST = 1
CONST PRIORITY_HIGH = 2
CONST PRIORITY_NORMAL = 3

////////////////////////////////////////////////////////////////////////////////
CUSTOMER_ID_MACRO:
////////////////////////////////////////////////////////////////////////////////
write "      Email 320      "
END


////////////////////////////////////////////////////////////////////////////////
RESET_MACRO:
////////////////////////////////////////////////////////////////////////////////
#state = sIDLE
#msg = mNONE
#errmsg = mNONE
|message_sent = false
&TIMER1 = 0
&CODE3 = SLAVE_MODE // so we can talk to the meter in ASCII mode
END


////////////////////////////////////////////////////////////////////////////////
MAIN_MACRO:
////////////////////////////////////////////////////////////////////////////////
select #state
case sIDLE:
  |LED6 = off
  // send email when capture pin is connected to common
  if |CAPTURE_PIN = on and |SEND_MESSAGE = true then
    &CODE3 = MASTER_MODE
    // terminate any connections before we start with a new one
    #msg = mRESTART
    #state = sSEND
    |message_sent = false
    &TIMER1 = 0
  endif

case sSEND:
  if &CODE2 >= 0200 then
    // in fast mode we have to wait a little for the print command to finish
    #state = sWAIT
  endif
  |LED6 = on
  &TIMER1 = 0
  print ""        // reset serial buffer

  select #msg

  // modem commands
  case mRESTART:
    // timer is already reset so we just wait before we send '+++'
    #state = sWAIT
  case mRESET_MODEM:
    // wait agagin after the '+++'
    #state = sWAIT
    print "+++"
  case mDISCONNECT:
    // wait again before we start a new connection
    #state = sWAIT
    print "ATH" + CHR(CR) // hang up connection
  case mCONNECT:
    #state = sWAIT_FOR_REPLY
    // dial to IP address and SMTP port
    print "ATDT192.168.10.1/0025" + CHR(CR)

  // SMTP commands
  case mHELO:
    #state = sWAIT_FOR_REPLY
    print "HELO mycompany.com"  // "Hello, I am from <domain>"
  case mFROM:
    #state = sWAIT_FOR_REPLY
    print "MAIL FROM: <[email protected]>"
  case mTO:
    #state = sWAIT_FOR_REPLY
    print "RCPT TO: <[email protected]>"

  // actual email text
  case mDATA:
    print "DATA"
  case mdFROM:
    print "From: [email protected]"
  case mdTO:
    print "To: [email protected]"
  case mdSUBJECT:
    print "Subject: Alarm"
  case mdPRIORITY:
    print "X-Priority: " + PRIORITY_HIGHEST
  case mdLINE1:
    // add an empty line to separate the mail body from the mail header 
    print CHR(CR) + CHR(LF) + "CH1: " + &CH1 + CHR(TAB) + "CH2: " + &CH2
  case mEND_MESSAGE:
    #state = sWAIT_FOR_REPLY
    |message_sent = true
    print "."
  endsel

  // only SMTP commands send CR/LF
  if #msg > mCONNECT then
    print CHR(CR)+CHR(LF)

    if #msg > mTO then
      // keep on sending the email text line by line without WAIT_FOR_REPLY
      #msg = #msg + 1
    endif   
  endif   

case sWAIT_FOR_REPLY:
  if |RECEIVE_READY = true then

    // let's first assume that the reply is OK and we can continue...
    #state = sSEND

    // ...then check for errors

    if #msg = mCONNECT then
      // got service ready reply on connect
      if SERIAL_INPUT = "220" then
        #msg = mHELO
      else // wrong answer
        #state = sERROR
        #errmsg = mREJECTED
      endif

    else
      if &RECEIVE_BUFFER[0] = ASC("4") or SERIAL_INPUT = "552" then
        // couldn't get through or mailbox is full 
        #state = sERROR
        #errmsg = mREJECTED

      elsif &RECEIVE_BUFFER[0] = ASC("5") then
        // permanent failure, see RFC 821 for more details on error codes
        |SEND_MESSAGE = false
        #state = sERROR
        #errmsg = mMAIL_DISABLED

      elsif #msg >= mEND_MESSAGE then
        // terminate current connection
        #msg = mRESTART
      else
        #msg = #msg + 1
      endif
    endif

  elsif &TIMER1 > TIMEOUT then
    // don't wait forever 
    #state = sERROR
    #errmsg = mTIMEOUT
  endif

case sWAIT:
  if #msg >= mDATA and &TIMER1 > 0 then
    // delay new output to avoid aborting old message (only in fast mode)
    #state = sSEND

  elsif &TIMER1 > MODEM_TIMEOUT then
    // wait before and after the '+++' to terminate the connection
    if #msg = mDISCONNECT and |message_sent = true then
      #state = sRESET
    else
      #msg = #msg + 1
      #state = sSEND
    endif
  endif

case sERROR:
  // terminate current connection
  #msg = mRESTART
  #state = sSEND
  |message_sent = true
  write MSG[mSPACE]
  append MSG[#errmsg]
  append MSG[mSPACE]

case sRESET:
  print ""           // reset serial buffer
  &CODE3 = SLAVE_MODE
  #msg = mNONE
  #errmsg = mNONE
  #state = sIDLE
  write MSG[mSPACE]
  append MSG[mDONE]
  append MSG[mSPACE]

endsel

END

Download Email320.bas
(6.7 KB , Aug. 26, 2008)