/*
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/>.
*/
/**
* Receive.java
*/
package sms;
/**
* Receive functions for SMS.
* @author <a href="mailto:martin.schoeberl@chello.at">Martin Schoeberl</a>
* @since 07/2002
*/
// class Receive {
public class Receive {
/** PDU message in 'hex' int's. */
static int[] hexBuf;
/** response or msg in 'plain' ascii. */
static int[] buf;
/** Pointer in receiver buffer */
private static int rcvd;
/** signal 'OK' received to Sms. */
static boolean okRcvd;
/** signal a message to be deleted to Sms. */
static int delNr;
private static final int BUF_MAX = 1000;
/** Receive timeout in seconds. */
private static final int RCV_TIMEOUT = 2;
/** Timer for receiver */
private static int timer;
/** State of receiver */
private static int state;
private static final int IDLE = 0;
private static final int READ = 1;
private static final int INTER = 2;
/** "+CMGL" */
private static int[] cmgl;
private static int[] ok;
/**
* Must be called befor any other function or field is accessed.
*/
static void init() {
hexBuf = new int[Sms.SMS_MAX+Sms.NR_MAX+20];
buf = new int[BUF_MAX+10]; // can be long!!!
rcvd = 0;
for (int i=0; i<BUF_MAX; ++i) buf[i] = ' '; // for easier scan ?
okRcvd = false;
delNr = -1;
timer = 0; // some value
state = IDLE;
int[] s1 = {'+','C','M','G','L',':',' '};
cmgl = s1;
int[] s2 = {'O','K'};
ok = s2;
}
/**
* This is the main loop!
* Fast loop to read Serial buffer.
*/
static void loop() {
while (Sms.ser.rxCnt()>0 && rcvd<BUF_MAX) {
buf[rcvd] = Sms.ser.rd();
timer = Sms.sec + RCV_TIMEOUT; // restart Timer
if (rcvd==0) util.Dbg.wr('r');
if (buf[rcvd]=='\r') util.Dbg.wr('c');
else util.Dbg.wr(buf[rcvd]);
/*
if (rcvd==0) System.out.print("receive:");
System.out.print((char) buf[rcvd]);
if (buf[rcvd]=='\r') System.out.println();
*/
rcvd++;
}
}
/**
* This loop is called once every second too handle receive state machine.
*/
static void loopSec() {
if (state == IDLE) {
if (rcvd != 0) state = READ;
} else if (state == READ) {
if (Sms.sec-timer >= 0) {
state = INTER;
}
} else if (state == INTER) {
interpret();
state = IDLE;
}
}
private static boolean strncmp(int[] s1, int[] s2, int pos, int len) {
int i;
for (i=0; i<s1.length && i+pos<len; ++i) {
if (s2[pos+i] != s1[i]) break;
}
return (i==s1.length);
}
private static int nextLine(int[] s, int pos, int len) {
for (; pos<len; ++pos) {
if (s[pos]=='\r') break;
if (s[pos]=='\n') break;
}
++pos;
if (pos>=len) return -1;
if (s[pos]=='\n') ++pos;
if (pos>=len) return -1;
return pos;
}
private static int readInt(int[] s, int pos) {
int val;
boolean found = false;
for (val=0; s[pos]>='0' && s[pos]<='9'; ++pos) {
found = true;
val *= 10;
val += s[pos]-'0';
}
if (!found) return -1;
return val;
}
private static int overInt(int[] s, int pos) {
for (; s[pos]>='0' && s[pos]<='9'; ++pos) {
;
}
return pos;
}
private static int readHex(int[] s, int pos) {
int i, j;
i = s[pos];
if (i>='0' && i<='9') { i -= '0'; }
else if (i>='A' && i<='F') { i = i-'A'+10; }
else return -1;
j = i*16;
i = s[pos+1];
if (i>='0' && i<='9') { i -= '0'; }
else if (i>='A' && i<='F') { i = i-'A'+10; }
else return -1;
return j+i;
}
/*
+CMGL: 3,2,,12
07913496090091991100038121F30000A902CB30
+CMGL: 1,1,,67
07913496090091990407A1286697F900002070927183410839E8329BFD4697D9EC37880745BFE9EF39FA4D9F835AA0245A5E0631D365313BED3ECFC56936B92C0785EB66D0B4397505A93E
OK
0: received unread
1: received read;
2: stored unsent;
3: stored sent;
4: all;
*/
/**
* Convert number to plain ascii.
* @return number type.
*/
private static int getNumber(int[] s, int pos, int len, int[] d) {
int i, j, k;
int ret = s[pos];
++pos;
k = 0;
for (i=0; i<len; ++i) {
j = s[pos];
d[k++] = (j & 0x0f) + '0';
j >>>= 4;
if (j!=0x0f) {
d[k++] = j + '0';
}
++pos;
}
d[k] = 0; // EOS
return ret;
}
/**
* Convert strange coding to ascii.
*/
private static void getText(int[] s, int pos, int len, int[] d) {
int j, k;
int cnt = 0;
for (j=0; j<len; ++j) {
k = s[pos]<<cnt;
k |= s[pos-1]>>(8-cnt);
d[j] = k & 0x7f;
++cnt;
if (cnt==8) {
cnt = 0;
} else {
++pos;
}
}
d[j] = 0; // EOS
}
/**
* Read a PDU message from receive buffer and fill buffers in Sms.
* Should be called only when Sms.gotSms is false;
*/
private static void getMsg(int type, int[] s, int len) {
if (type==2 || type==3) { // only rcvd msg are interesting
return;
}
int i;
int pos = 0;
i = s[pos]; ++pos; // SMSC len
if (i>Sms.NR_MAX) return;
pos += i;
++pos; // some type
i = s[pos]; ++pos;
//
// TODO store senders Number (and nr type) for replay
// now len is in nibbles and without type field!!!
//
if (i>Sms.NR_MAX) return;
Sms.rcvNrType = getNumber(s, pos, (i+1)>>1, Sms.rcvNr);
pos += 1+((i+1)>>1);
pos += 9; // rcv msg.
// TODO: read TP-DCS to see if 7, 8 or 16 bit data!
i = s[pos]; ++pos; // msg len in 'character' !!!
if (i>Sms.SMS_MAX) return;
getText(s, pos, i, Sms.rcvTxt);
Sms.gotSms = true; // Now message is ready for upper level application.
}
/**
* Interprete received data. This function is called when the receive buffer
* contains data but no more data arrived one the serial line for more than
* RCV_TIMEOUT seconds.
* <p>interpret() has three functions:<br>
* Empty buffer for unused echo...<br>
* Signal 'OK' to Sms for modem handling.<br>
* Read received SMS and mark them for delete.<br>
*
*/
private static void interpret() {
int i, j;
int pos = 0;
int msgNr, msgTyp;
while (pos!=-1 && pos<BUF_MAX) {
//
// handle CMGL messages:
// only first msg will be copied to Sms.rcvTxt (in getMsg) and deleted.
//
if (strncmp(cmgl, buf, pos, rcvd)) {
pos += cmgl.length;
msgNr = readInt(buf, pos); pos = overInt(buf, pos)+1;
msgTyp = readInt(buf, pos);
pos = nextLine(buf, pos, rcvd);
if (pos==-1) break;
for (i=0; buf[pos]!='\r' && buf[pos]!='\n' && pos<rcvd-1; ++i) {
j = readHex(buf, pos);
if (j<0) break; // somthing really wrong!
hexBuf[i] = j;
pos += 2;
}
if (Sms.gotSms) {
break; // buffer in Sms is not free -> forget it!
}
getMsg(msgTyp, hexBuf, i);
delNr = msgNr;
break; // only one msg per call
}
if (strncmp(ok, buf, pos, rcvd)) {
okRcvd = true;
break; // forget the rest on 'OK'
}
pos = nextLine(buf, pos, rcvd);
}
//
// clear rcv buffer
//
for (i=0; i<BUF_MAX; ++i) buf[i] = ' ';
rcvd = 0; // empty buffer
}
/*
private static void printMsg(int type, int[] s, int len) {
int i, j, k;
int pos = 0;
i = s[pos]; ++pos;
if (i>0) { // len in octets
System.out.print("SMSC=");
// printNumber(s, pos, i-1);
System.out.println();
pos += i;
}
++pos; // some type
if (type==2 || type==3) { // send msg.
++pos;
}
i = s[pos]; ++pos;
if (type==2 || type==3) {
System.out.print("Destination Number=");
} else {
System.out.print("Sender Number=");
}
// printNumber(s, pos, (i+1)/2); // now len is in nibbles and without type field!!!
System.out.println();
pos += 1+(i+1)/2;
if (type==2 || type==3) {
pos += 3; // send msg.
} else {
pos += 9; // rcv msg.
}
// TODO: read TP-DCS to see if 7, 8 or 16 bit data!
i = s[pos]; ++pos; // msg len in 'character' !!!
System.out.println("msg len="+i);
getText(s, pos, i, Sms.rcvTxt);
System.out.print("msg='");
for (j=0; j<i; ++j) {
System.out.print((char) Sms.rcvTxt[j]);
}
Sms.rcvTxt[j] = 0;
System.out.println("'");
System.out.println();
}
*/
}