Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**************************************************************************
- Nokia 61xx SMS send/receive functions
- Version 1.0
- Justin Karneges
- June 2000
- Thanks goes to the gnokii team for figuring out the frame format, among
- many other things! These guys did all the hard work. Although this file
- was written from scratch, it was heavily based on their research.
- http://www.gnokii.org/
- Overview:
- This file contains a set of functions for sending and receiving SMS
- (short message service) text messages across a GSM network with a
- Nokia 61xx series phone. I've only tested it with my phone (a 6190),
- however it should work fine with any GSM phone in the series. It
- should also work with the 59xx series phones.
- These functions were meant to be as portable as possible (they contain
- no serial communications code), and to perform two simple things: send
- and receive SMS. That's all. If you want a full program to control
- all the aspects of the Nokia 61xx, then I suggest checking out gnokii.
- This code was meant to be small, so that it could be used in small
- devices/applications.
- To use:
- Setup the serial port and call n61_init(). Then use n61_smssend() and
- n61_smsrecv() to send/recv SMS messages. Call n61_update() as often
- as possible (possibly by having a timer ISR call it) so that the driver
- stays in sync with the phone. All incoming SMS messages are deleted
- from the phone's inbox (you want this).
- ------------------------------------------------------------------------
- Functions:
- +---------------------------------------------------------+
- | void n61_init(int (*func)(int cmd, unsigned char c)); |
- +---------------------------------------------------------+
- Before calling this function, do everything necessary to have the
- serial port ready. The port MUST be set as follows:
- Baud rate: 115200
- Parity: None
- Bits: 8
- Stop bits: 1
- DTR: set
- RTS: cleared
- Since this driver does not contain any serial communications
- functionality, you must supply it. An interrupt driven / threaded
- serial interface MUST be used. This driver does not poll the port,
- and so it is completely dependant on a background serial driver
- keeping a queue of all incoming data (so that no data is lost).
- To give the serial functionality to this nokia driver, write a simple
- function to perform the four types of requests that this driver will
- need handled. Pass this function as the argument to init:
- n61_init(myhandler);
- The myhandler() function should look like this:
- int myhandler(int cmd, unsigned char c)
- {
- if(cmd == 0) {
- serial_send(c); // send c out the port
- return;
- }
- else if(cmd == 1)
- return serial_recv(); // return the next byte in queue
- else if(cmd == 2)
- return serial_isdata(); // return zero if queue is empty
- else if(cmd == 3)
- msleep(1); // delay for 1 millisecond
- }
- 0 means send "c" out the serial port. 1 means return a byte from the
- serial port. 2 means return true/false if there is data waiting.
- Simple enough!
- This driver also requires a millisecond resolution timer, which is
- what the last request is for. Most platforms include some sort of
- millisecond (or less) delay function. For MSVC++ there is Sleep(),
- Unix has usleep() and DOS has delay(). If you're not using such a
- platform, then you'll have to time it yourself. The driver doesn't
- specify how many milliseconds to wait, your function should wait
- just one millisecond. So just do Sleep(1), usleep(1000), delay(1),
- or whatever your homebrew method is. Easy!
- Lastly, n61_init() also queries the phone for the SMSC number to be
- used when sending SMS.
- Whew! If you got past n61_init(), then the rest is easy as cake.
- +--------------------------------------------+
- | int n61_smssend(char *dest, char *msg); |
- +--------------------------------------------+
- Sends "msg" to "dest". Returns 1 if sent, 0 if not.
- +---------------------------------------------+
- | int n61_smsrecv(char *source, char *msg); |
- +---------------------------------------------+
- Copies a received message into "msg", stores the source phone number
- in "source" and returns 1. Returns 0 if no messages are in the queue.
- "msg" will not be larger than 161 bytes (including null byte).
- "source" will not be larger than 17 bytes (including null byte).
- +-----------------------+
- | int n61_smsqueue(); |
- +-----------------------+
- Returns the number of messages in the incoming queue.
- +---------------------+
- | int n61_update(); |
- +---------------------+
- This must be called as often as possible. If it's not called, then
- you won't be able to receive messages. This might be something good
- to put in a timer interrupt if possible (yes, it's safe).
- That's all you need to know!
- ------------------------------------------------------------------------
- Nokia 6190 message format:
- 1 byte = start byte (0x1e)
- 1 byte = message destination
- 1 byte = message source
- 1 byte = message type
- 1 byte = ???
- 1 byte = message size
- X bytes = message data (X = message size)
- 1 byte = filler byte (exists only if needed to make message size even)
- 2 byte = result of all 16bit words XOR'ed together
- **************************************************************************/
- //#include <string.h>
- #define N61MODE_SYNC 0
- #define N61MODE_DEST 1
- #define N61MODE_SOURCE 2
- #define N61MODE_TYPE 3
- #define N61MODE_UNKNOWN 4
- #define N61MODE_SIZE 5
- #define N61MODE_DATA 6
- #define N61STATE_WAIT 0
- #define N61STATE_PROC 1
- #define N61STATE_GOOD 2
- #define N61STATE_BAD 3
- #define N61MAXSIZE 120
- #define N61VALID_1H 0x0b
- #define N61VALID_6H 0x47
- #define N61VALID_24H 0xa7
- #define N61VALID_72H 0xa9
- #define N61VALID_1W 0xad
- #define N61VALID_MAX 0xff
- struct MESSAGE
- {
- int dest;
- int source;
- int type;
- int unknown;
- int size;
- unsigned char dat[256];
- int cs[2];
- };
- struct MESSAGE tmp, buf;
- int seqnum = 0;
- int prevseq = 0;
- int (*serial)(int cmd, unsigned char c);
- int mode = 0;
- int atbyte = 0;
- int datp = 0;
- int readsize = 0;
- int readbase = 0;
- int state;
- int multiple;
- char smsc[32];
- int msgqueuesize;
- char msgqueue[4][161];
- char msgqueue2[4][17];
- int ack, gotmsg, waittype;
- int blocked;
- // ** translate table taken directly from gnokii **
- unsigned char transtable[] = {
- /* ETSI GSM 03.38, version 6.0.1, section 6.2.1; Default alphabet */
- /* Characters in hex position 10, [12 to 1a] and 24 are not present on
- latin1 charset, so we cannot reproduce on the screen, however they are
- greek symbol not present even on my Nokia */
- '@', 0xa3, '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec,
- 0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5,
- '?', '_', '?', '?', '?', '?', '?', '?',
- '?', '?', '?', '?', 0xc6, 0xe6, 0xdf, 0xc9,
- ' ', '!', '"', '#', 0xa4, '%', '&', '\'',
- '(', ')', '*', '+', ',', '-', '.', '/',
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', ':', ';', '<', '=', '>', '?',
- 0xa1, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
- 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
- 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
- 'X', 'Y', 'Z', 0xc4, 0xd6, 0xd1, 0xdc, 0xa7,
- 0xbf, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
- 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
- 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
- 'x', 'y', 'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0
- };
- // **** Functions ****
- void init(int (*func)(int cmd, unsigned char c)); // initialize the driver
- int smssend(char *dest, char *msg); // send SMS
- int smsrecv(char *dest, char *msg); // recv SMS
- int smsqueue(); // check the recv queue
- void update(); // keep the driver in sync
- // **** Functions - internal ****
- void block(); // protect during update
- void unblock(); // unprotect
- void update_main(); // main update
- void update_internal(); // internal version of
- // update()
- void serial_send(unsigned char c); // send byte
- unsigned char serial_recv(); // recv byte
- unsigned char serial_isdata(); // check for serial data
- void serial_delay(); // wait 1 millisecond
- int nextseq(); // get next sequence number
- int sendframe(int type, int size, unsigned char *data); // send frame
- int sendmsg(int type, int size, char *data); // send message
- void sendack(int type, int seqnum); // send acknowledgement
- void ackwait(int x); // wait for ack
- void wait(int x); // wait for a message
- void addchar(char *str, char c); // strcat() but for chars
- void bcd(char *dest, char *s); // encode SMSC number
- void bcd2(char *dest, char *s); // encode phone number
- char *unbcd(unsigned char *dat); // decode SMSC number
- char *unbcd2(unsigned char *dat); // decode phone number
- void pack7(char *dest, char *s); // pack when sending
- char *unpack7(unsigned char *dat, int len); // unpack when received
- unsigned char gettrans(unsigned char c); // translate char
- void addmsg(char *dest, char *msg); // add a received SMS
- // to the queue
- void procmsg(struct MESSAGE *msg); // process incoming message
- void getstatus(); // request phone status
- void getsmsc(); // request SMSC
- void delsms(int x); // delete SMS message
- int smssendfull(char *smsc, char *dest, char *msg); // send SMS via SMSC
- // ** Code **
- int myhandler(int cmd, unsigned char c)
- {
- if(cmd == 0) {
- serial_send(c); // send c out the port
- return 0;
- }
- else if(cmd == 1)
- return serial_recv(); // return the next byte in queue
- else if(cmd == 2)
- return serial_isdata(); // return zero if queue is empty
- else if(cmd == 3)
- delay(1); // delay for 1 millisecond
- }
- unsigned char gettrans(unsigned char c)
- {
- unsigned char n;
- if(c == '?')
- return 0x3f;
- for(n = 0; n < 128; ++n) {
- if(transtable[n] == c)
- return n;
- }
- return 0x3f;
- }
- void block()
- {
- blocked = 1;
- }
- void unblock()
- {
- blocked = 0;
- }
- void update()
- {
- if(!blocked) {
- block();
- update_main();
- unblock();
- }
- }
- void update_internal()
- {
- update_main();
- }
- void serial_send(unsigned char c)
- {
- //serial(0, c);
- Serial.print(c);
- }
- unsigned char serial_recv()
- {
- return Serial.read();
- //return serial(1, 0);
- }
- unsigned char serial_isdata()
- {
- return Serial.available();
- //return serial(2, 0);
- }
- void serial_delay()
- {
- delay(1);
- //serial(3, 0);
- }
- void ackwait(int x)
- {
- int n;
- for(n = 0; n < x; ++n) {
- update_internal();
- serial_delay();
- if(ack)
- return;
- }
- }
- void wait(int x)
- {
- int n;
- for(n = 0; n < x; ++n) {
- update_internal();
- serial_delay();
- if(gotmsg)
- return;
- }
- }
- void addmsg(char *dest, char *msg)
- {
- int n;
- // clip args for safety. in theory not necessary
- msg[160] = 0;
- dest[16] = 0;
- // add the message
- n = msgqueuesize;
- strcpy(msgqueue[n], msg);
- strcpy(msgqueue2[n], dest);
- ++msgqueuesize;
- }
- int smsrecv(char *dest, char *msg)
- {
- int n;
- block();
- n = msgqueuesize;
- if(n <= 0) {
- unblock();
- return 0;
- }
- strcpy(msg, msgqueue[0]);
- strcpy(dest, msgqueue2[0]);
- --msgqueuesize;
- for(n = 0; n < msgqueuesize; ++n) {
- strcpy(msgqueue[n], msgqueue[n+1]);
- strcpy(msgqueue2[n], msgqueue2[n+1]);
- }
- unblock();
- return 1;
- }
- int smsqueue()
- {
- return msgqueuesize;
- }
- int sendframe(int type, int size, unsigned char *data)
- {
- unsigned char buf[256];
- int at, n, check, len;
- unsigned short *p;
- at = 0;
- // build header
- buf[at++] = 0x1e; // message startbyte
- buf[at++] = 0x00; // dest: phone
- buf[at++] = 0x0c; // source: PC
- buf[at++] = type;
- buf[at++] = 0x00;
- buf[at++] = size;
- // add data
- for(n = 0; n < size; ++n)
- buf[at++] = data[n];
- // if odd numbered, add filler byte
- if(size % 2) {
- buf[at++] = 0x00;
- }
- // calculate checksums
- check = 0;
- p = (unsigned short *)buf;
- len = at / 2;
- for(n = 0; n < len; ++n)
- check ^= p[n];
- p[n] = check;
- at += 2;
- // send the message!
- for(n = 0; n < at; ++n) {
- serial_send(buf[n]);
- }
- }
- int nextseq()
- {
- int n;
- n = seqnum;
- prevseq = n;
- ++seqnum;
- seqnum &= 7;
- return (n + 0x40);
- }
- int sendmsg(int type, int size, char *data)
- {
- unsigned char buf[N61MAXSIZE + 2];
- unsigned char num, lastsize;
- int n;
- int len;
- num = (size + N61MAXSIZE - 1) / N61MAXSIZE;
- lastsize = size % N61MAXSIZE;
- for(n = 0; n < num;) {
- if(n + 1 == num)
- len = lastsize;
- else
- len = N61MAXSIZE;
- // get current chunk
- memcpy(buf, data + (n * N61MAXSIZE), len);
- buf[len] = num - n;
- buf[len+1] = nextseq();
- if(n)
- buf[len+1] &= 7;
- ack = 0;
- sendframe(type, len + 2, buf);
- ackwait(1000);
- if(ack)
- ++n;
- }
- }
- void sendack(int type, int seqnum)
- {
- unsigned char buf[2];
- buf[0] = type;
- buf[1] = seqnum;
- sendframe(0x7f, 2, buf);
- }
- void update_main()
- {
- int n;
- unsigned char c;
- while(serial_isdata()) {
- c = serial_recv();
- // calculate the checksums
- tmp.cs[atbyte & 1] ^= c;
- // act on the byte
- switch(mode) {
- case N61MODE_SYNC:
- if(c == 0x1e) {
- if(!multiple) {
- memset(tmp.dat, 0, 256);
- atbyte = 0;
- }
- tmp.cs[0] = 0x1e;
- tmp.cs[1] = 0;
- mode = N61MODE_DEST;
- }
- break;
- case N61MODE_DEST:
- tmp.dest = c;
- mode = N61MODE_SOURCE;
- break;
- case N61MODE_SOURCE:
- tmp.source = c;
- mode = N61MODE_TYPE;
- break;
- case N61MODE_TYPE:
- tmp.type = c;
- mode = N61MODE_UNKNOWN;
- break;
- case N61MODE_UNKNOWN:
- tmp.unknown = c;
- mode = N61MODE_SIZE;
- break;
- case N61MODE_SIZE:
- if(multiple)
- tmp.size += c - 2;
- else {
- tmp.size = c;
- datp = 0;
- }
- mode = N61MODE_DATA;
- // calculate the number of bytes to read
- n = tmp.size % 2;
- // message size + filler + checksums
- readsize = tmp.size + n + 2;
- break;
- case N61MODE_DATA:
- n = datp++;
- if(n > 255) {
- multiple = 0;
- mode = N61MODE_SYNC;
- break;
- }
- tmp.dat[n] = c; // get the byte
- // are we done yet?
- if(n >= readsize - 1) {
- // checksums ok?
- if(tmp.cs[0] == tmp.cs[1] && tmp.cs[0] == 0) {
- // don't want to ACK on an ACK
- if(tmp.type != 0x7f) {
- sendack(tmp.type, tmp.dat[tmp.size-1] & 0x0f);
- if(tmp.size > 1 && tmp.dat[tmp.size-2] != 0x01) {
- datp -= 4; // back up past checksums and seqinfo
- ++multiple;
- }
- else
- multiple = 0;
- }
- if(!multiple || tmp.type == 0x7f) {
- multiple = 0;
- memcpy(&buf, &tmp, sizeof(struct MESSAGE));
- procmsg(&buf);
- }
- }
- else {
- // bad!
- multiple = 0;
- }
- mode = N61MODE_SYNC;
- }
- default:
- break;
- }
- ++atbyte;
- }
- }
- void getstatus()
- {
- char buf[32];
- buf[0] = 0x00;
- buf[1] = 0x01;
- buf[2] = 0x00;
- buf[3] = 0x6d;
- sendmsg(0x11, 4, buf);
- }
- void getsmsc()
- {
- char buf[32];
- int x, n;
- buf[0] = 0x00;
- buf[1] = 0x01;
- buf[2] = 0x00;
- buf[3] = 0x33;
- buf[4] = 0x64;
- buf[5] = 0x01;
- // "do" or "try", there is no "do not"
- while(1) {
- // send off the request
- state = N61STATE_PROC;
- gotmsg = 0;
- waittype = 2;
- sendmsg(0x02, 6, buf);
- wait(1000);
- if(state == N61STATE_GOOD)
- break;
- }
- }
- void delsms(int x)
- {
- char buf[32];
- buf[0] = 0x00;
- buf[1] = 0x01;
- buf[2] = 0x00;
- buf[3] = 0x0a;
- buf[4] = 0x02;
- buf[5] = x;
- sendmsg(0x14, 6, buf);
- }
- void bcd(char *dest, char *s)
- {
- int size, x, y, n, hi, lo;
- if(s[0] == '+') {
- dest[1] = 0x91;
- ++s;
- }
- else
- dest[1] = 0x81;
- x = 0;
- y = 2;
- while(s[x]) {
- lo = s[x++] - '0';
- if(s[x])
- hi = s[x++] - '0';
- else
- hi = 0x0f;
- n = (hi << 4) + lo;
- dest[y++] = n;
- }
- dest[0] = y - 1;
- }
- void bcd2(char *dest, char *s)
- {
- int size, x, y, n, hi, lo;
- if(s[0] == '+') {
- dest[1] = 0x91;
- ++s;
- }
- else
- dest[1] = 0x81;
- x = 0;
- y = 2;
- while(s[x]) {
- lo = s[x++] - '0';
- if(s[x])
- hi = s[x++] - '0';
- else
- hi = 0x0f;
- n = (hi << 4) + lo;
- dest[y++] = n;
- }
- dest[0] = strlen(s);
- }
- void pack7(char *dest, char *s)
- {
- int len;
- unsigned char c;
- unsigned short *p, w;
- int at;
- int shift;
- int n, x;
- len = strlen(s);
- x = (len * 8) / 7;
- for(n = 0; n < x; ++n)
- dest[n] = 0;
- shift = 0;
- at = 0;
- w = 0;
- for(n = 0; n < len; ++n) {
- p = (unsigned short *)(dest + at);
- w = gettrans(s[n]) & 0x7f;
- w <<= shift;
- *p |= w;
- shift += 7;
- if(shift >= 8) {
- shift &= 7;
- ++at;
- }
- }
- }
- int smssendfull(char *smsc, char *dest, char *msg)
- {
- char buf[256];
- int n;
- // standard frame data header
- buf[0] = 0x00;
- buf[1] = 0x01;
- buf[2] = 0x00;
- // send sms ?
- buf[3] = 0x01;
- buf[4] = 0x02;
- buf[5] = 0x00;
- // smsc
- memset(buf + 6, 0, 12);
- bcd(buf + 6, smsc);
- // TPDU ?
- buf[18] = 0x11;
- // misc
- buf[19] = 0x00; // message ref
- buf[20] = 0x00; // protocol ID
- buf[21] = 0xf1; // data coding scheme (non-flash)
- // message size
- buf[22] = strlen(msg);
- // destination
- memset(buf + 23, 0, 12);
- bcd2(buf + 23, dest);
- // validity period
- buf[35] = N61VALID_24H;
- // filler
- buf[36] = 0;
- buf[37] = 0;
- buf[38] = 0;
- buf[39] = 0;
- buf[40] = 0;
- buf[41] = 0;
- // the string
- pack7(buf + 42, msg);
- // try till we get some response
- while(1) {
- state = N61STATE_PROC;
- gotmsg = 0;
- waittype = 1;
- sendmsg(0x02, 42 + strlen(msg), buf);
- wait(5000);
- if(state != N61STATE_PROC)
- break;
- }
- if(state == N61STATE_GOOD)
- return 1;
- return 0;
- }
- int smssend(char *dest, char *msg)
- {
- int n;
- block();
- n = smssendfull(smsc, dest, msg);
- unblock();
- return n;
- }
- void addchar(char *str, char c)
- {
- int n;
- n = strlen(str);
- str[n] = c;
- str[n+1] = 0;
- }
- char *unbcd(unsigned char *dat)
- {
- static char buf[32];
- int len;
- int n, x;
- buf[0] = 0;
- len = dat[0];
- if(dat[1] == 0x91) {
- addchar(buf, '+');
- }
- for(n = 0; n < len-1; ++n) {
- x = dat[n+2] & 0x0f;
- if(x < 10)
- addchar(buf, '0' + x);
- x = (dat[n+2] >> 4) & 0x0f;
- if(x < 10)
- addchar(buf, '0' + x);
- }
- return buf;
- }
- char *unbcd2(unsigned char *dat)
- {
- static char buf[32];
- int len;
- int n, x;
- int at;
- buf[0] = 0;
- len = dat[0];
- if(dat[1] == 0x6f || dat[1] == 0x91) {
- addchar(buf, '+');
- }
- at = 2;
- for(n = 0; n < len; ++n) {
- x = dat[at] & 0x0f;
- if(x < 10)
- addchar(buf, '0' + x);
- ++n;
- if(!(n < len))
- break;
- x = (dat[at] >> 4) & 0x0f;
- if(x < 10)
- addchar(buf, '0' + x);
- ++at;
- }
- return buf;
- }
- char *unpack7(unsigned char *dat, int len)
- {
- static char buf[256];
- unsigned short *p, w;
- unsigned char c;
- int n;
- int shift;
- int at;
- shift = 0;
- at = 0;
- buf[0] = 0;
- for(n = 0; n < len; ++n) {
- p = (unsigned short *)(dat + at);
- w = *p;
- w >>= shift;
- c = w & 0x7f;
- shift += 7;
- if(shift & 8) {
- shift &= 0x07;
- ++at;
- }
- addchar(buf, transtable[c]);
- }
- return buf;
- }
- void procmsg(struct MESSAGE *msg)
- {
- int n, subtype;
- // check if this is a msg of interest
- subtype = 0;
- if(msg->type != 0x7f) {
- if(msg->type == 0x02) {
- if(msg->dat[3] == 0x02 || msg->dat[3] == 0x03)
- subtype = 1;
- if(msg->dat[3] == 0x10)
- subtype = 2;
- if(msg->dat[3] == 0x34)
- subtype = 3;
- }
- if(subtype == waittype)
- gotmsg = 1;
- }
- // act on it
- switch(msg->type) {
- // SMS
- case 0x02:
- if(msg->dat[3] == 0x02) {
- state = N61STATE_GOOD;
- }
- if(msg->dat[3] == 0x03) {
- state = N61STATE_BAD;
- }
- if(msg->dat[3] == 0x10) {
- addmsg(unbcd2(msg->dat + 23), unpack7(msg->dat + 42, msg->dat[22]));
- // now delete the msg
- if(msg->dat[5])
- delsms(msg->dat[5]);
- }
- // SMSC
- if(msg->dat[3] == 0x34) {
- state = N61STATE_GOOD;
- strcpy(smsc, unbcd(msg->dat+21));
- }
- break;
- case 0x7f:
- if((msg->dat[1] & 7) == prevseq)
- ack = 1;
- break;
- default:
- break;
- }
- }
- void init(int (*func)(int cmd, unsigned char c))
- {
- int n;
- seqnum = 0;
- serial = func;
- blocked = 0;
- msgqueuesize = 0;
- multiple = 0;
- readbase = 0;
- // getsmsc
- getsmsc();
- }
- void setup() {
- char * destinatario = "+3900000000";
- char * messaggio = "Incredible, it works!";
- Serial.begin(115200);
- init(myhandler);
- smssend(destinatario,messaggio);
- }
- void loop() {
- }
Advertisement
Add Comment
Please, Sign In to add comment