/*
Copyright 2004/2005, Freie Universitaet Berlin. All rights reserved.

These sources were developed at the Freie Universität Berlin, Computer
Systems and Telematics group.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
 
- Neither the name of Freie Universitaet Berlin (FUB) nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

This software is provided by FUB and the contributors on an "as is"
basis, without any representations or warranties of any kind, express
or implied including, but not limited to, representations or
warranties of non-infringement, merchantability or fitness for a
particular purpose. In no event shall FUB or contributors be liable
for any direct, indirect, incidental, special, exemplary, or
consequential damages (including, but not limited to, procurement of
substitute goods or services; loss of use, data, or profits; or
business interruption) however caused and on any theory of liability,
whether in contract, strict liability, or tort (including negligence
or otherwise) arising in any way out of the use of this software, even
if advised of the possibility of such damage.

This implementation was developed by the CST group at the FUB.
Contributors: Marco Hutta

For documentation and questions please use the web site
http://www.scatterweb.net and the mailinglist
scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website).
Berlin, 2004/2005
*/

#include "ScatterWeb.SMS.h"

#define MAX_NUMBER_LENGTH 12

char* numberTo;
UINT8 idle;
UINT8 isNumberSet;

void clean(char *data, int length) {
  int i = 0;
  while(i<length) {
    *(data+i) = 0;
    i++;    
  }
  i = 0;
}

int strlength(char* string) {
   int i = 0;
   for(;*(string+i)!=0;i++);
   return i;
}

char getGSM(char c) {
	switch(c) {
		case '@': 
			return 0x00;
		case '$':
			return 0x02;
		case '\n':
			return 0x0A;
		case '\r':
			return 0x0D;
		case '_':
			return 0x11;
		case ' ':
			return 0x20;
		case '!':
			return 0x21;
		case '"':
			return 0x22;
		case '#':
			return 0x23;
		case '%':
			return 0x25;
		case '&':
			return 0x26;
		case '\'':
			return 0x27;
		case '(':
			return 0x28;
		case ')':
			return 0x29;
		case '*':
			return 0x2A;
		case '+':
			return 0x2B;
		case ',':
			return 0x2C;
		case '-':
			return 0x2D;
		case '.':
			return 0x2E;
		default:
			return c;
	}
	return c;
}

char getChar(char c) {
   	switch(c){
    	case 0x00: 
    		return '0';
    	case 0x01:
    		return '1';
    	case 0x02:
    		return '2';
    	case 0x03:
    		return '3';
    	case 0x04:
    		return '4';
    	case 0x05:
    		return '5';
    	case 0x06:
    		return '6';
    	case 0x07:
    		return '7';
    	case 0x08:
    		return '8';
    	case 0x09:
    		return '9';
    	case 0x0A:
    		return 'A';
    	case 0x0B:
    		return 'B';
    	case 0x0C:
    		return 'C';
    	case 0x0D:
    		return 'D';
    	case 0x0E:
    		return 'E';
    	case 0x0F:
    		return 'F';
    	
    }
    return 0;
}

void send(char* number, char* text) {
  unsigned char msg[320]; // IO 2000-2319
  unsigned char pdutext[161]; // IO 2400-2559
  int i = 0;
  int length= 0;
  int x = 0;
  int count = 0;
  unsigned char temp;
  unsigned char temp2;
  length = strlength(number);
  if(length > MAX_NUMBER_LENGTH) return;
  clean(msg, 320); // IO_erase 2000-2319
  clean(pdutext, 161); // IO_erase 2400-2559
  msg[0] = '0'; // IO_read 2000
  msg[1] = '0'; // IO_read 2001
  msg[2] = '1'; // IO_read 2002
  msg[3] = '1'; // IO_read 2003
  msg[4] = '0'; // IO_read 2004
  msg[5] = '0'; // IO_read 2005
  msg[6] = '0'; // IO_read 2006
  msg[7] = 'B'; // IO_read 2007
  msg[8] = '9'; // IO_read 2008
  msg[9] = '1'; // IO_read 2009
  i = 10;
  for(;x<length/2;x++){
  	msg[i+(2*x)+1] = *(number+(2*x));
  	msg[i+(2*x)] = *(number+(2*x)+1);
  }
  if(length%2 != 0){
  	msg[i+(2*x)+1] = *(number+(2*x));
  	msg[i+(2*x)] = 'F'; 
  	i = i+(2*x)+2;	
  } else {
     i = i+(2*x);	
  }
  x = 0;
  length = strlength(text);
  msg[i] = '0';
  msg[i+1] = '0';
  msg[i+2] = '0';
  msg[i+3] = '0';
  msg[i+4] = 'A';
  msg[i+5] = 'A';
  msg[i+6] = getChar(((((unsigned char)length) & 0xF0)>>4));
  msg[i+7] = getChar((((unsigned char)length) & 0x0F));
  length = strlength(text);
  if(length>160) return;
  for(;x<length;x+=8) {
    if(x+1<=length) {
      temp = getGSM(*(text+x+1)) & 0x01;
      temp <<=7;
      pdutext[x-count] = getGSM(*(text+x)) | temp; 
    }
    if(x+2<=length) {
      temp = getGSM(*(text+x+2)) & 0x03;
      temp <<=6;
      temp2 = getGSM(*(text+x+1));
      temp2 >>=1;
      pdutext[x+1-count] = temp2 | temp;
    }
    if(x+3<=length) {
      temp = getGSM(*(text+x+3)) & 0x07;
      temp <<=5;
      temp2 = getGSM(*(text+x+2));
      temp2 >>=2;
      pdutext[x+2-count] = temp2 | temp; 
    }
    if(x+4<=length) {
      temp = getGSM(*(text+x+4)) & 0x0F;
      temp <<=4;
      temp2 = getGSM(*(text+x+3));
      temp2 >>=3;
      pdutext[x+3-count] = temp2 | temp;
    }
    if(x+5<=length) {
      temp = getGSM(*(text+x+5)) & 0x1F;
      temp <<=3;
      temp2 = getGSM(*(text+x+4));
      temp2 >>=4;
      pdutext[x+4-count] = temp2 | temp; 
    }
    if(x+6<=length) {
      temp = getGSM(*(text+x+6)) & 0x3F;
      temp <<=2;
      temp2 = getGSM(*(text+x+5));
      temp2 >>=5;
      pdutext[x+5-count] = temp2 | temp; 
    }
    if(x+7<=length) {
      temp = getGSM(*(text+x+7)) & 0x7F;
      temp <<=1;
      temp2 = getGSM(*(text+x+6));
      temp2 >>=6;
      pdutext[x+6-count] = temp2 | temp;
    }
    count++;
  }
  x = 0;
  length = strlength(pdutext);
  for(;x<length;x++) {
  	temp = *(pdutext+x);
  	temp = temp & 0xF0;
  	temp >>= 4;
  	msg[i+8+(2*x)] = getChar(temp);
  	temp = *(pdutext+x);
  	temp = temp & 0x0F;
  	msg[i+8+(2*x)+1] = getChar(temp);
  }
  msg[i+8+(2*x)]=0x1A;
  length = (strlength(msg)-3)/2;
  Comm_print("AT+CMGF=0\r\n");
  System_wait(50000);
  Comm_print("AT+CMGS=");
  Comm_print(term_reply, "%i", length);
  Comm_print("\r\n");
  System_wait(20000);
  Comm_print(msg);
  return;
}

bool SMS_send(char* text) {
  if (isNumberSet && idle) {
    send(numberTo, text);
    return True;
  }
  else return False;
}

bool SMS_isConnected() {
  return idle;
}

void SMS_serialHandler(void* line) {
  UINT8* str = (UINT8*) line;
  if (str[0] == 'O' && str[1] == 'K') idle = 1;
}

bool SMS_setNumber(char* number) {
  isNumberSet = True;
  numberTo = number;
  return True;
}

bool SMS_init() {
  idle = 0;
  isNumberSet = False;
  System_registerCallback(C_SERIAL, SMS_serialHandler);         
  Comm_init(BPS_19200);
  Comm_print("AT");
  return True;
}
