rem Email380.bas rem rem last revision 2005 May 13 rem rem send an Email from a Tiger 380 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 REG &ERR_MSG = &TEXT_VARIABLE8 REG &SPACES = &TEXT_VARIABLE7 REG &ERR_REJECTED = &USER_TEXT1 REG &ERR_DISABLED = &USER_TEXT2 REG &ERR_TIMEOUT = &USER_TEXT3 REG &MSG_DONE = &USER_TEXT4 REG &SERVER = &USER_TEXT5 REG &FROM = &USER_TEXT6 REG &TO = &USER_TEXT7 REG &DOMAIN = &USER_TEXT8 REG &SUBJECT = &USER_TEXT9 // #msg values CONST mNONE = 0 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 // initialize text registers MEM &ERR_REJECTED = "Email rejected" MEM &ERR_DISABLED = "Email permanently disabled !!!" MEM &ERR_TIMEOUT = "Communication timed out" MEM &MSG_DONE = "Done" MEM &SERVER = "192.168.10.1/0025" MEM &FROM = "tiger380" MEM &TO = "technician" MEM &DOMAIN = "mycompany.com" MEM &SUBJECT = "Alarm" // #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 &SERIAL_MODE1 = 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 &SPACES append "Email 380" append &SPACES END //////////////////////////////////////////////////////////////////////////////// RESET_MACRO: //////////////////////////////////////////////////////////////////////////////// #state = sIDLE #msg = mNONE |message_sent = false &TIMER1 = 0 &SERIAL_MODE1 = SLAVE_MODE // so we can talk to the meter in ASCII mode &SPACES = " " // spaces for scrolling text messages 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 &SERIAL_MODE1 = 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 "ATDT" + &SERVER + CHR(CR) // SMTP commands case mHELO: #state = sWAIT_FOR_REPLY print "HELO " + &DOMAIN // "Hello, I am from " case mFROM: #state = sWAIT_FOR_REPLY print "MAIL FROM: <" + &FROM + "@" + &DOMAIN + ">" case mTO: #state = sWAIT_FOR_REPLY print "RCPT TO: <" + &TO + "@" + &DOMAIN + ">" // actual email text case mDATA: print "DATA" case mdFROM: print "From: " + &FROM + "@" + &DOMAIN case mdTO: print "To: " + &TO + "@" + &DOMAIN case mdSUBJECT: print "Subject: " + &SUBJECT 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) // current data cannot be stored in a fixed string (e.g. "CH1: ~9" would be // replaced with the actual value at download time) but has to be // assembled to print at runtime print &HOURS_MINUTES + CHR(TAB) + "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 &ERR_MSG = &ERR_REJECTED endif else if &RECEIVE_BUFFER[0] = ASC("4") or SERIAL_INPUT = "552" then // couldn't get through or mailbox is full #state = sERROR &ERR_MSG = &ERR_REJECTED elsif &RECEIVE_BUFFER[0] = ASC("5") then // permanent failure, see RFC 821 for more details on error codes |SEND_MESSAGE = false #state = sERROR &ERR_MSG = &ERR_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 &ERR_MSG = &ERR_TIMEOUT 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 &SPACES append &ERR_MSG append &SPACES case sRESET: print "" // reset serial buffer &SERIAL_MODE1 = SLAVE_MODE #msg = mNONE #state = sIDLE write &SPACES append &MSG_DONE append &SPACES endsel END