/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2001-2008, Martin Schoeberl (martin@jopdesign.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * Sms.java */ package sms; import joprt.RtThread; import com.jopdesign.sys.Const; import ejip.CS8900; import ejip.Ejip; import ejip.LinkLayer; import ejip.Net; import util.Dbg; import util.Serial; import util.Timer; /** * Send a SMS via a mobile phone. * * All functions are static and simple to be used with <a href="http://www.jopdesign.com/">Jop</a>.<br> * * All 'strings' (buffer) are int arrays with C-type length (0). * * @author <a href="mailto:martin.schoeberl@chello.at">Martin Schoeberl</a> * @since 07/2002 * @see <a href="http://www.dreamfabric.com/sms/">SMS messages and the PDU format</a> * @see <a href="http://www.fastlogic.co.za/faq59.htm">Hayes AT command parameters * for sending and receiving SMS messages</a> */ public class Sms { static Serial ser; /** maximum length of 7 bit (default) messages */ public static final int SMS_MAX = 160; /** maximum length of a telefon number */ public static final int NR_MAX = 20; /** new message if ready for send */ private static boolean sendIt; /** 'plain' text of SMS to be sent */ static int[] sndTxt; /** length of msg in sndTxt. */ static int sndTxtLen; /** destination number of SMS to be sent */ static int[] sndNr; /** len of destination number */ static int sndNrLen; /** type of destination number */ static int sndNrType; /** * Is the sender free? */ public static boolean isFree() { return !sendIt; } /** * Send a message. * copies data and tries to deliver it. * No error on problems: Unreliable as the SMS service by itself. * End to End check on higher level (ack SMS from human). * * @param txt Text of message. * @param nr Destination telefon number * @param nrType Type of number: 0x91 indicates international format */ public static void send(int[] txt, int[] nr, int nrType) { if (sendIt) return; // just drop it Dbg.wr('\n'); Dbg.wr('s'); int i, j; for (i=0; i<nr.length; ++i) { j = nr[i]; if (j==0) break; Dbg.wr(j); } Dbg.wr(':'); for (i=0; i<txt.length; ++i) { j = txt[i]; if (j==0) break; Dbg.wr(j); } Dbg.wr(':'); Dbg.wr('\n'); sndTxtLen = strcpy(sndTxt, txt); sndNrLen = strcpy(sndNr, nr); sndNrType = nrType; sendIt = true; // 'triggers' send event } /** * Buffer is filled with a new SMS. This flag must be cleared (from the uper level) * after reading the message from the public buffers ({@link #rcvTxt}, {@link #rcvNr} and * {@link #rcvNrType}). */ public static boolean gotSms; /** 'plain' text of received SMS */ public static int[] rcvTxt; /** senders number of received SMS */ public static int[] rcvNr; /** type of senders number */ public static int rcvNrType; /** * Must be called befor any other function or field is accessed. */ public static void init() { sndTxt = new int[SMS_MAX]; sndNr = new int[NR_MAX]; rcvTxt = new int[SMS_MAX]; rcvNr = new int[NR_MAX]; gotSms = false; sendIt = false; strInit(); Receive.init(); Send.init(); timer = Timer.getTimeoutMs(WD_TIME); sec = 0; state = INIT; timEvent = STATE_TIME; } private static final int WD_TIME = 500; // every half second private static int timer; // ms Timer used to set sec private static int tick; // half second tick static int sec; // local clock for other timers (used in Receive) /** * This is the main loop! */ public static void loop() { Receive.loop(); Send.loop(); // // half second timer // alternate between Receive and Sms second loop. // if (Timer.timeout(timer)) { timer = Timer.getTimeoutMs(WD_TIME); ++tick; if ((tick & 1)!=0) { // one half loopSec(); } else { Receive.loopSec(); // and the other } } } /** timer for next Event ... state change or what else */ private static int timEvent; /** do the init sequence some time to be able a cange of mobile phone... */ private static int timInit; private static final int INIT_TIME = 5*60; /** timer to change state or check result */ private static final int STATE_TIME = 10; // private static final int ERROR_TIME = 60; private static final int ERROR_TIME = 10; private static final int PIN_TIME = 60; /** master states */ private static int state; private static final int INIT = 0; private static final int INIT0 = 1; private static final int INIT1 = 2; private static final int INIT2 = 3; private static final int INIT3 = 4; private static final int NO_HANDY = 5; private static final int READY = 6; private static final int SEND_HEAD = 7; private static final int SEND_PDU = 8; /** * This loop is called once every second too handle the state machine. */ private static void loopSec() { Timer.wd(); ++sec; // // time for state change // if (sec-timEvent >= 0) { timEvent = sec + STATE_TIME; // restart timer boolean ok = Receive.okRcvd; Receive.okRcvd = false; if (state==INIT) { Send.send(ath); state = INIT0; } else if (state==INIT0) { if (ok) { Send.send(cpin); // a longer time for the pin timEvent = sec + PIN_TIME; state = INIT1; } else { state = NO_HANDY; timEvent = sec + ERROR_TIME; } } else if (state==INIT1) { if (ok) { Send.send(cmgf); state = INIT2; } else { state = NO_HANDY; timEvent = sec + ERROR_TIME; } } else if (state==INIT2) { state = INIT3; if (ok) { Send.send(csms); state = INIT3; } else { state = NO_HANDY; timEvent = sec + ERROR_TIME; } } else if (state==INIT3) { if (ok) { state = READY; timInit = sec + INIT_TIME; // next new init sequence } else { state = NO_HANDY; timEvent = sec + ERROR_TIME; } } else if (state==NO_HANDY) { state = INIT; // now try again // // now we are in the ready/poll... loop // } else if (state==READY) { doReady(); // // we've sent CMGS, now send PDU and wait for OK // } else if (state==SEND_HEAD) { Send.sendPDU(); state = SEND_PDU; // // PDU is sent, did we get OK? // } else if (state==SEND_PDU) { if (ok) { Sms.sendIt = false; // Sender is free again state = READY; } else { state = INIT; // something wrong, start an init sequence } } else { } } } /** * The READY state in its own funtion. */ private static void doReady() { int i = Receive.delNr; // // delete a msg // if (i!=-1) { Send.send(cmgd, i); Receive.delNr = -1; // // send a message // } else if(sendIt) { i = Send.genPDU(); Send.send(cmgs, i); state = SEND_HEAD; // // restart (INIT) // } else if (sec-timInit >= 0) { // it's time to initialze again :-) state = INIT; // // poll SMS list // } else { Send.send(cmgl); // poll list } } /** * A C like string copy :-) * @return resulting strlen. */ public static int strcpy(int[] d, int[] s) { int i, max; i = d.length; max = s.length; if (i<max) max = i; for (i=0; i<max; ++i) { d[i] = s[i]; if (d[i]==0) break; } if (i==max && i<d.length) d[i] = 0; return i; } private static int[] ath; private static int[] cmgf; private static int[] csms; private static int[] cmgs; private static int[] cmgl; private static int[] cmgd; private static int[] cpin; private static void strInit() { // // some strings // int[] s1 = {'A','T','H','\r'}; ath = s1; int[] s2 = {'A','T','+','C','M','G','F','=','0','\r'}; cmgf = s2; int[] s3 = {'A','T','+','C','S','M','S','=','0','\r'}; csms = s3; int[] s4 = {'A','T','+','C','M','G','S','=',}; cmgs = s4; int[] s5 = {'A','T','+','C','M','G','L','=','4','\r'}; cmgl = s5; int[] s6 = {'A','T','+','C','M','G','D','=',}; cmgd = s6; // int[] s7 = {'A','T','+','C','P','I','N','=','5','6','4','4','\r'}; int[] s7 = {'A','T','+','C','P','I','N','=','9','1','7','4','\r'}; cpin = s7; } static Net net; static LinkLayer ipLink; /** * Test main. */ public static void main(String[] args) { Dbg.init(); // that's the UDP version init(); ser = new Serial(Const.IO_UART1_BASE); new RtThread(1, 10000) { public void run() { for (;;) { waitForNextPeriod(); ser.loop(); } } }; // // start TCP/IP // Ejip ejip = new Ejip(); net = new Net(ejip); // don't use CS8900 when simulating on PC or for BG263 int[] eth = {0x00, 0xe0, 0x98, 0x33, 0xb0, 0xf8}; int ip = Ejip.makeIp(192, 168, 0, 123); ipLink = new CS8900(ejip, eth, ip); // // start device driver threads // new RtThread(5, 10000) { public void run() { for (;;) { waitForNextPeriod(); net.run(); } } }; new RtThread(5, 10000) { public void run() { for (;;) { waitForNextPeriod(); ipLink.run(); } } }; RtThread.startMission(); int i, j; int[] text = {'H','e','l','l','o',' ','f','r','o','m',' ','J','O','P','!'}; int[] nr = {'4','3','6','9','9','1','9','5','2','0','2','2','0'}; int[] gotNr = new int[Sms.NR_MAX]; int gotNrType; int timer = Timer.getTimeoutMs(1000); int sec = 0; boolean doit = true; for (;;) { loop(); if (Timer.timeout(timer)) { timer = Timer.getTimeoutMs(1000); ++sec; } if (state==READY && doit) { Dbg.wr("ready to send"); // 0x91 for intl. numbers (43...) Sms.send(text, nr, 0x91); doit = false; } if (gotSms) { // tim(); Dbg.wr("got SMS:"); for (i=0; i<rcvTxt.length; ++i) { j = rcvTxt[i]; if (j==0) break; Dbg.wr((char) j); } Dbg.lf(); Dbg.wr("from "); for (i=0; i<rcvNr.length; ++i) { j = rcvNr[i]; if (j==0) break; Dbg.wr((char) j); } Dbg.wr(" type: "+Sms.rcvNrType); Dbg.lf(); Sms.strcpy(gotNr, Sms.rcvNr); gotNrType = Sms.rcvNrType; if (Sms.isFree()) { Dbg.wr("send replay"); Dbg.lf(); Sms.send(text, gotNr, gotNrType); } else { Dbg.wr("send buffer full!"); Dbg.lf(); } Sms.gotSms = false; } } } }