-rw-r--r-- | gammu/emb/common/phone/at/atgen.c | 295 | ||||
-rw-r--r-- | gammu/emb/common/phone/at/atgen.h | 8 | ||||
-rw-r--r-- | gammu/emb/common/phone/at/samsung.c | 447 | ||||
-rw-r--r-- | gammu/emb/common/phone/at/samsung.h | 16 | ||||
-rw-r--r-- | gammu/emb/common/phone/at/siemens.c | 74 | ||||
-rw-r--r-- | gammu/emb/common/phone/at/sonyeric.c | 141 |
6 files changed, 874 insertions, 107 deletions
diff --git a/gammu/emb/common/phone/at/atgen.c b/gammu/emb/common/phone/at/atgen.c index 1834f15..ba23eb2 100644 --- a/gammu/emb/common/phone/at/atgen.c +++ b/gammu/emb/common/phone/at/atgen.c @@ -1,93 +1,73 @@ /* (c) 2002-2004 by Marcin Wiacek and Michal Cihar */ #include "../../gsmstate.h" #ifdef GSM_ENABLE_ATGEN #include <string.h> #include <time.h> #include <ctype.h> #include "../../gsmcomon.h" #include "../../misc/coding/coding.h" #include "../../service/sms/gsmsms.h" #include "../pfunc.h" + #include "atgen.h" +#include "samsung.h" +#include "siemens.h" +#include "sonyeric.h" + #ifdef GSM_ENABLE_ALCATEL -extern GSM_Error ALCATEL_ProtocolVersionReply (GSM_Protocol_Message msg, GSM_StateMachine *s); +GSM_Error ALCATEL_ProtocolVersionReply (GSM_Protocol_Message, GSM_StateMachine *); #endif -extern GSM_Error ATGEN_CMS35ReplyGetBitmap (GSM_Protocol_Message msg, GSM_StateMachine *s); -extern GSM_Error ATGEN_CMS35ReplySetBitmap (GSM_Protocol_Message msg, GSM_StateMachine *s); -extern GSM_Error ATGEN_CMS35ReplyGetRingtone (GSM_Protocol_Message msg, GSM_StateMachine *s); -extern GSM_Error ATGEN_CMS35ReplySetRingtone (GSM_Protocol_Message msg, GSM_StateMachine *s); -extern GSM_Error ATGEN_CMS35ReplyGetNextCal (GSM_Protocol_Message msg, GSM_StateMachine *s); -extern GSM_Error ATGEN_CMS35ReplySetCalendar (GSM_Protocol_Message msg, GSM_StateMachine *s); -extern GSM_Error ATGEN_CMS35ReplyDeleteCalendar (GSM_Protocol_Message msg, GSM_StateMachine *s); -extern GSM_Error ATGEN_SL45ReplyGetMemory (GSM_Protocol_Message msg, GSM_StateMachine *s); - -extern GSM_Error ATGEN_GetRingtone (GSM_StateMachine *s, GSM_Ringtone *Ringtone, bool PhoneRingtone); -extern GSM_Error ATGEN_SetRingtone (GSM_StateMachine *s, GSM_Ringtone *Ringtone, int *maxlength); -extern GSM_Error ATGEN_GetBitmap (GSM_StateMachine *s, GSM_Bitmap *Bitmap); -extern GSM_Error ATGEN_SetBitmap (GSM_StateMachine *s, GSM_Bitmap *Bitmap); -extern GSM_Error SIEMENS_GetNextCalendar (GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start); -extern GSM_Error SIEMENS_AddCalendarNote (GSM_StateMachine *s, GSM_CalendarEntry *Note); -extern GSM_Error SIEMENS_DelCalendarNote (GSM_StateMachine *s, GSM_CalendarEntry *Note); - -extern GSM_Error SONYERIC_GetNextCalendar (GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start); -extern GSM_Error SONYERIC_GetNextToDo (GSM_StateMachine *s, GSM_ToDoEntry *ToDo, bool start); -extern GSM_Error SONYERIC_GetToDoStatus (GSM_StateMachine *s, GSM_ToDoStatus *status); -extern GSM_Error SONYERIC_AddCalendarNote (GSM_StateMachine *s, GSM_CalendarEntry *Note); -extern GSM_Error SONYERIC_AddToDo (GSM_StateMachine *s, GSM_ToDoEntry *ToDo); -extern GSM_Error SONYERIC_DeleteAllToDo (GSM_StateMachine *s); -extern GSM_Error SONYERIC_DelCalendarNote (GSM_StateMachine *s, GSM_CalendarEntry *Note); -extern GSM_Error SONYERIC_GetCalendarStatus (GSM_StateMachine *s, GSM_CalendarStatus *Status); typedef struct { int Number; char Text[60]; } ATErrorCode; static ATErrorCode CMSErrorCodes[] = { /* * Error codes not specified here were either undefined or reserved in my * copy of specifications, if you have newer one, please fill in the gaps. */ /* 0...127 from GSM 04.11 Annex E-2 */ {1, "Unassigned (unallocated) number"}, {8, "Operator determined barring"}, {10, "Call barred"}, {21, "Short message transfer rejected"}, {27, "Destination out of service"}, {28, "Unidentified subscriber"}, {29, "Facility rejected"}, {30, "Unknown subscriber"}, {38, "Network out of order"}, {41, "Temporary failure"}, {42, "Congestion"}, {47, "Resources unavailable, unspecified"}, {50, "Requested facility not subscribed"}, {69, "Requested facility not implemented"}, {81, "Invalid short message transfer reference value"}, {95, "Invalid message, unspecified"}, {96, "Invalid mandatory information"}, {97, "Message type non-existent or not implemented"}, {98, "Message not compatible with short message protocol state"}, {99, "Information element non-existent or not implemented"}, {111, "Protocol error, unspecified"}, {127, "Interworking, unspecified"}, /* 128...255 from GSM 03.40 subclause 9.2.3.22 */ {0x80, "Telematic interworking not supported"}, {0x81, "Short message Type 0 not supported"}, {0x82, "Cannot replace short message"}, {0x8F, "Unspecified TP-PID error"}, {0x90, "Data coding scheme (alphabet) not supported"}, {0x91, "Message class not supported"}, {0x9F, "Unspecified TP-DCS error"}, {0xA0, "Command cannot be actioned"}, {0xA1, "Command unsupported"}, {0xAF, "Unspecified TP-Command error"}, {0xB0, "TPDU not supported"}, {0xC0, "SC busy"}, {0xC1, "No SC subscription"}, @@ -130,402 +110,467 @@ static ATErrorCode CMSErrorCodes[] = { /* > 512 are manufacturer specific according to GSM 07.05 subclause 3.2.5 */ {-1, ""} }; static ATErrorCode CMEErrorCodes[] = { /* CME Error codes from GSM 07.07 section 9.2 */ {0, "phone failure"}, {1, "no connection to phone"}, {2, "phone-adaptor link reserved"}, {3, "operation not allowed"}, {4, "operation not supported"}, {5, "PH-SIM PIN required"}, {10, "SIM not inserted"}, {11, "SIM PIN required"}, {12, "SIM PUK required"}, {13, "SIM failure"}, {14, "SIM busy"}, {15, "SIM wrong"}, {16, "incorrect password"}, {17, "SIM PIN2 required"}, {18, "SIM PUK2 required"}, {20, "memory full"}, {21, "invalid index"}, {22, "not found"}, {23, "memory failure"}, {24, "text string too long"}, {25, "invalid characters in text string"}, {26, "dial string too long"}, {27, "invalid characters in dial string"}, {30, "no network service"}, {31, "network timeout"}, {100, "unknown"}, }; GSM_Error ATGEN_HandleCMEError(GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; if (Priv->ErrorCode == 0) { smprintf(s, "CME Error occured, but it's type not detected\n"); } else if (Priv->ErrorText == NULL) { smprintf(s, "CME Error %i, no description available\n", Priv->ErrorCode); } else { smprintf(s, "CME Error %i: \"%s\"\n", Priv->ErrorCode, Priv->ErrorText); } /* For error codes descriptions see table a bit above */ switch (Priv->ErrorCode) { + case -1: + return ERR_EMPTY; case 3: return ERR_PERMISSION; case 4: return ERR_NOTSUPPORTED; case 5: case 11: case 12: case 16: case 17: case 18: return ERR_SECURITYERROR; case 20: return ERR_FULL; case 21: return ERR_INVALIDLOCATION; case 22: return ERR_EMPTY; case 23: return ERR_MEMORY; case 24: case 25: case 26: case 27: return ERR_INVALIDDATA; default: return ERR_UNKNOWN; } } GSM_Error ATGEN_HandleCMSError(GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; if (Priv->ErrorCode == 0) { smprintf(s, "CMS Error occured, but it's type not detected\n"); } else if (Priv->ErrorText == NULL) { smprintf(s, "CMS Error %i, no description available\n", Priv->ErrorCode); } else { smprintf(s, "CMS Error %i: \"%s\"\n", Priv->ErrorCode, Priv->ErrorText); } /* For error codes descriptions see table a bit above */ switch (Priv->ErrorCode) { case 304: return ERR_NOTSUPPORTED; case 305: return ERR_BUG; case 311: case 312: case 316: case 317: case 318: return ERR_SECURITYERROR; case 322: return ERR_FULL; case 321: return ERR_INVALIDLOCATION; default: return ERR_UNKNOWN; } } /* FIXME: Function doesn't respect quoting of parameters and thus +FOO: * "ab","cd,ef" will consider as three arguments: "ab" >> "cd >> ef" */ int ATGEN_ExtractOneParameter(unsigned char *input, unsigned char *output) { int position=0; while (*input!=',' && *input!=0x0d && *input!=0x00) { *output=*input; input ++; output ++; position++; } *output=0; position++; return position; } void ATGEN_DecodeDateTime(GSM_DateTime *dt, unsigned char *input) { - dt->Year=2000+(*input-'0')*10; input++; + /* Samsung phones report year as %d instead of %02d */ + if (input[2] == '/') { + dt->Year=(*input-'0')*10; + input++; + } else { + dt->Year=0; + } + dt->Year=dt->Year+(*input-'0'); input++; + dt->Year+=2000; input++; dt->Month=(*input-'0')*10; input++; dt->Month=dt->Month+(*input-'0'); input++; input++; dt->Day=(*input-'0')*10; input++; dt->Day=dt->Day+(*input-'0'); input++; input++; dt->Hour=(*input-'0')*10; input++; dt->Hour=dt->Hour+(*input-'0'); input++; input++; dt->Minute=(*input-'0')*10; input++; dt->Minute=dt->Minute+(*input-'0');input++; input++; dt->Second=(*input-'0')*10; input++; dt->Second=dt->Second+(*input-'0');input++; if (input!=NULL) { input++; dt->Timezone=(*input-'0')*10; input++; dt->Timezone=dt->Timezone+(*input-'0');input++; input=input-2; if (*input=='-') dt->Timezone=-dt->Timezone; } } GSM_Error ATGEN_DispatchMessage(GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_Protocol_Message *msg = s->Phone.Data.RequestMsg; int i = 0, j, k; char *err, *line; ATErrorCode *ErrorCodes = NULL; SplitLines(msg->Buffer, msg->Length, &Priv->Lines, "\x0D\x0A", 2, true); /* Find number of lines */ while (Priv->Lines.numbers[i*2+1] != 0) { /* FIXME: handle special chars correctly */ smprintf(s, "%i \"%s\"\n",i+1,GetLineString(msg->Buffer,Priv->Lines,i+1)); i++; } Priv->ReplyState = AT_Reply_Unknown; Priv->ErrorText = NULL; Priv->ErrorCode = 0; line = GetLineString(msg->Buffer,Priv->Lines,i); if (!strcmp(line,"OK")) Priv->ReplyState = AT_Reply_OK; if (!strcmp(line,"> ")) Priv->ReplyState = AT_Reply_SMSEdit; if (!strcmp(line,"CONNECT")) Priv->ReplyState = AT_Reply_Connect; if (!strcmp(line,"ERROR" )) Priv->ReplyState = AT_Reply_Error; if (!strncmp(line,"+CME ERROR:",11)) { Priv->ReplyState = AT_Reply_CMEError; ErrorCodes = CMEErrorCodes; } if (!strncmp(line,"+CMS ERROR:",11)) { Priv->ReplyState = AT_Reply_CMSError; ErrorCodes = CMSErrorCodes; } + + /* FIXME: Samsung phones can answer +CME ERROR:-1 meaning empty location */ + if (Priv->ReplyState == AT_Reply_CMEError && Priv->Manufacturer == AT_Samsung) { + err = line + 11; + Priv->ErrorCode = atoi(err); + + if (Priv->ErrorCode == -1) { + Priv->ErrorText = "[Samsung] Empty location"; + return GSM_DispatchMessage(s); + } + } + if (Priv->ReplyState == AT_Reply_CMEError || Priv->ReplyState == AT_Reply_CMSError) { j = 0; /* One char behind +CM[SE] ERROR */ err = line + 12; while (err[j] && !isalnum(err[j])) j++; if (isdigit(err[j])) { Priv->ErrorCode = atoi(&(err[j])); k = 0; while (ErrorCodes[k].Number != -1) { if (ErrorCodes[k].Number == Priv->ErrorCode) { Priv->ErrorText = (char *)&(ErrorCodes[k].Text); break; } k++; } } else if (isalpha(err[j])) { k = 0; while (ErrorCodes[k].Number != -1) { if (!strncmp(err + j, ErrorCodes[k].Text, strlen(ErrorCodes[k].Text))) { Priv->ErrorCode = ErrorCodes[k].Number; Priv->ErrorText = (char *)&(ErrorCodes[k].Text); break; } k++; } } } return GSM_DispatchMessage(s); } GSM_Error ATGEN_GenericReply(GSM_Protocol_Message msg, GSM_StateMachine *s) { switch (s->Phone.Data.Priv.ATGEN.ReplyState) { case AT_Reply_OK: case AT_Reply_Connect: return ERR_NONE; case AT_Reply_Error: return ERR_UNKNOWN; case AT_Reply_CMSError: return ATGEN_HandleCMSError(s); case AT_Reply_CMEError: return ATGEN_HandleCMEError(s); default: break; } return ERR_UNKNOWNRESPONSE; } +GSM_Error ATGEN_ReplyGetUSSD(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + unsigned char buffer[2000],buffer2[4000]; + int i = 10; + + /* Ugly hack */ + while (msg.Buffer[i]!=13) i++; + i = i - 6; + memcpy(buffer,msg.Buffer+10,i-11); + buffer[i-11] = 0x00; + + smprintf(s, "USSD reply: \"%s\"\n",buffer); + + if (s->Phone.Data.EnableIncomingUSSD && s->User.IncomingUSSD!=NULL) { + EncodeUnicode(buffer2,buffer,strlen(buffer)); + s->User.IncomingUSSD(s->CurrentConfig->Device, buffer2); + } + + return ERR_NONE; +} + +GSM_Error ATGEN_SetIncomingUSSD(GSM_StateMachine *s, bool enable) +{ + GSM_Error error; + + if (enable) { + smprintf(s, "Enabling incoming USSD\n"); + error=GSM_WaitFor (s, "AT+CUSD=1\r", 10, 0x00, 3, ID_SetUSSD); + } else { + smprintf(s, "Disabling incoming USSD\n"); + error=GSM_WaitFor (s, "AT+CUSD=0\r", 10, 0x00, 3, ID_SetUSSD); + } + if (error==ERR_NONE) s->Phone.Data.EnableIncomingUSSD = enable; + return error; +} + GSM_Error ATGEN_ReplyGetModel(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_Phone_Data *Data = &s->Phone.Data; if (s->Phone.Data.Priv.ATGEN.ReplyState != AT_Reply_OK) return ERR_NOTSUPPORTED; if (strlen(GetLineString(msg.Buffer, Priv->Lines, 2)) <= MAX_MODEL_LENGTH) { CopyLineString(Data->Model, msg.Buffer, Priv->Lines, 2); /* Sometimes phone adds this before manufacturer (Sagem) */ if (strncmp("+CGMM: ", Data->Model, 7) == 0) { memmove(Data->Model, Data->Model + 7, strlen(Data->Model + 7) + 1); } Data->ModelInfo = GetModelData(NULL,Data->Model,NULL); if (Data->ModelInfo->number[0] == 0) Data->ModelInfo = GetModelData(NULL,NULL,Data->Model); if (Data->ModelInfo->number[0] == 0) Data->ModelInfo = GetModelData(Data->Model,NULL,NULL); if (Data->ModelInfo->number[0] != 0) strcpy(Data->Model,Data->ModelInfo->number); if (strstr(msg.Buffer,"Nokia")) Priv->Manufacturer = AT_Nokia; else if (strstr(msg.Buffer,"M20")) Priv->Manufacturer = AT_Siemens; else if (strstr(msg.Buffer,"MC35")) Priv->Manufacturer = AT_Siemens; + else if (strstr(msg.Buffer,"TC35")) Priv->Manufacturer = AT_Siemens; else if (strstr(msg.Buffer, "iPAQ")) Priv->Manufacturer = AT_HP; if (strstr(msg.Buffer,"M20")) strcpy(Data->Model,"M20"); else if (strstr(msg.Buffer,"MC35")) strcpy(Data->Model,"MC35"); + else if (strstr(msg.Buffer,"TC35")) strcpy(Data->Model,"TC35"); else if (strstr(msg.Buffer, "iPAQ")) strcpy(Data->Model,"iPAQ"); } else { smprintf(s, "WARNING: Model name too long, increase MAX_MODEL_LENGTH to at least %zd\n", strlen(GetLineString(msg.Buffer, Priv->Lines, 2))); } return ERR_NONE; } GSM_Error ATGEN_GetModel(GSM_StateMachine *s) { GSM_Error error; if (s->Phone.Data.Model[0] != 0) return ERR_NONE; smprintf(s, "Getting model\n"); error=GSM_WaitFor (s, "AT+CGMM\r", 8, 0x00, 3, ID_GetModel); if (error==ERR_NONE) { if (s->di.dl==DL_TEXT || s->di.dl==DL_TEXTALL || s->di.dl==DL_TEXTDATE || s->di.dl==DL_TEXTALLDATE) { smprintf(s, "[Connected model - \"%s\"]\n",s->Phone.Data.Model); } } return error; } GSM_Error ATGEN_ReplyGetManufacturer(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; switch (Priv->ReplyState) { case AT_Reply_OK: smprintf(s, "Manufacturer info received\n"); Priv->Manufacturer = AT_Unknown; if (strlen(GetLineString(msg.Buffer, Priv->Lines, 2)) <= MAX_MANUFACTURER_LENGTH) { CopyLineString(s->Phone.Data.Manufacturer, msg.Buffer, Priv->Lines, 2); } else { smprintf(s, "WARNING: Manufacturer name too long, increase MAX_MANUFACTURER_LENGTH to at least %zd\n", strlen(GetLineString(msg.Buffer, Priv->Lines, 2))); s->Phone.Data.Manufacturer[0] = 0; } /* Sometimes phone adds this before manufacturer (Sagem) */ if (strncmp("+CGMI: ", s->Phone.Data.Manufacturer, 7) == 0) { memmove(s->Phone.Data.Manufacturer, s->Phone.Data.Manufacturer + 7, strlen(s->Phone.Data.Manufacturer + 7) + 1); } if (strstr(msg.Buffer,"Falcom")) { smprintf(s, "Falcom\n"); strcpy(s->Phone.Data.Manufacturer,"Falcom"); Priv->Manufacturer = AT_Falcom; if (strstr(msg.Buffer,"A2D")) { strcpy(s->Phone.Data.Model,"A2D"); s->Phone.Data.ModelInfo = GetModelData(NULL,s->Phone.Data.Model,NULL); smprintf(s, "Model A2D\n"); } } if (strstr(msg.Buffer,"Nokia")) { smprintf(s, "Nokia\n"); strcpy(s->Phone.Data.Manufacturer,"Nokia"); Priv->Manufacturer = AT_Nokia; } if (strstr(msg.Buffer,"SIEMENS")) { smprintf(s, "Siemens\n"); strcpy(s->Phone.Data.Manufacturer,"Siemens"); Priv->Manufacturer = AT_Siemens; } if (strstr(msg.Buffer,"ERICSSON")) { smprintf(s, "Ericsson\n"); strcpy(s->Phone.Data.Manufacturer,"Ericsson"); Priv->Manufacturer = AT_Ericsson; } if (strstr(msg.Buffer,"iPAQ")) { smprintf(s, "iPAQ\n"); strcpy(s->Phone.Data.Manufacturer,"HP"); Priv->Manufacturer = AT_HP; } if (strstr(msg.Buffer,"ALCATEL")) { smprintf(s, "Alcatel\n"); strcpy(s->Phone.Data.Manufacturer,"Alcatel"); Priv->Manufacturer = AT_Alcatel; } if (strstr(msg.Buffer,"SAGEM")) { smprintf(s, "Sagem\n"); strcpy(s->Phone.Data.Manufacturer,"Sagem"); Priv->Manufacturer = AT_Sagem; } + if (strstr(msg.Buffer,"Samsung")) { + smprintf(s, "Samsung\n"); + strcpy(s->Phone.Data.Manufacturer,"Samsung"); + Priv->Manufacturer = AT_Samsung; + } return ERR_NONE; case AT_Reply_CMSError: return ATGEN_HandleCMSError(s); default: break; } return ERR_UNKNOWNRESPONSE; } GSM_Error ATGEN_GetManufacturer(GSM_StateMachine *s) { if (s->Phone.Data.Manufacturer[0] != 0) return ERR_NONE; return GSM_WaitFor (s, "AT+CGMI\r", 8, 0x00, 4, ID_GetManufacturer); } GSM_Error ATGEN_ReplyGetFirmwareCGMR(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; unsigned int i = 0; strcpy(s->Phone.Data.Version,"unknown"); s->Phone.Data.VerNum = 0; if (Priv->ReplyState == AT_Reply_OK) { CopyLineString(s->Phone.Data.Version, msg.Buffer, Priv->Lines, 2); /* Sometimes phone adds this before manufacturer (Sagem) */ if (strncmp("+CGMR: ", s->Phone.Data.Version, 7) == 0) { memmove(s->Phone.Data.Version, s->Phone.Data.Version + 7, strlen(s->Phone.Data.Version + 7) + 1); } } if (Priv->Manufacturer == AT_Ericsson) { while (1) { if (s->Phone.Data.Version[i] == 0x20) { s->Phone.Data.Version[i] = 0x00; break; } if (i == strlen(s->Phone.Data.Version)) break; i++; } } smprintf(s, "Received firmware version: \"%s\"\n",s->Phone.Data.Version); GSM_CreateFirmwareNumber(s); return ERR_NONE; } GSM_Error ATGEN_ReplyGetFirmwareATI(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; @@ -629,106 +674,116 @@ GSM_Error ATGEN_Initialise(GSM_StateMachine *s) if (error != ERR_NONE) return error; smprintf(s, "Enabling CME errors\n"); /* Try numeric errors */ if (GSM_WaitFor (s, "AT+CMEE=1\r", 10, 0x00, 3, ID_EnableErrorInfo) != ERR_NONE) { /* Try textual errors */ if (GSM_WaitFor (s, "AT+CMEE=2\r", 10, 0x00, 3, ID_EnableErrorInfo) != ERR_NONE) { smprintf(s, "CME errors could not be enabled, some error types won't be detected.\n"); } } error = ATGEN_GetModel(s); if (error != ERR_NONE) return error; if (!IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SLOWWRITE)) { s->Protocol.Data.AT.FastWrite = true; } return error; } GSM_Error ATGEN_SetSMSC(GSM_StateMachine *s, GSM_SMSC *smsc) { unsigned char req[50]; if (smsc->Location!=1) return ERR_NOTSUPPORTED; sprintf(req, "AT+CSCA=\"%s\"\r",DecodeUnicodeString(smsc->Number)); smprintf(s, "Setting SMSC\n"); return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_SetSMSC); } GSM_Error ATGEN_ReplyGetSMSMemories(GSM_Protocol_Message msg, GSM_StateMachine *s) { switch (s->Phone.Data.Priv.ATGEN.ReplyState) { case AT_Reply_OK: /* Reply here is: * (memories for reading)[, (memories for writing)[, (memories for storing received messages)]] * each memory is in quotes, * Example: ("SM"), ("SM"), ("SM") * * We need to get from this supported memories. For this case * we assume, that just appearence of memory makes it * available for everything. Then we need to find out whether * phone supports writing to memory. This is done by searching * for "), (", which will appear between lists. */ - s->Phone.Data.Priv.ATGEN.CanSaveSMS = (strstr(msg.Buffer, "), (") != NULL); + s->Phone.Data.Priv.ATGEN.CanSaveSMS = false; + if (strstr(msg.Buffer, "), (") != NULL || strstr(msg.Buffer, "),(") != NULL) { + s->Phone.Data.Priv.ATGEN.CanSaveSMS = true; + } + if (strstr(msg.Buffer, "\"SM\"") != NULL) s->Phone.Data.Priv.ATGEN.SIMSMSMemory = AT_AVAILABLE; else s->Phone.Data.Priv.ATGEN.SIMSMSMemory = AT_NOTAVAILABLE; + if (strstr(msg.Buffer, "\"ME\"") != NULL) s->Phone.Data.Priv.ATGEN.PhoneSMSMemory = AT_AVAILABLE; else s->Phone.Data.Priv.ATGEN.PhoneSMSMemory = AT_NOTAVAILABLE; - smprintf(s, "Available SMS memories received, ME = %d, SM = %d\n", s->Phone.Data.Priv.ATGEN.PhoneSMSMemory, s->Phone.Data.Priv.ATGEN.SIMSMSMemory); + + smprintf(s, "Available SMS memories received, ME = %d, SM = %d, cansavesms =", s->Phone.Data.Priv.ATGEN.PhoneSMSMemory, s->Phone.Data.Priv.ATGEN.SIMSMSMemory); + if (s->Phone.Data.Priv.ATGEN.CanSaveSMS) smprintf(s, "true"); + smprintf(s, "\n"); return ERR_NONE; case AT_Reply_Error: case AT_Reply_CMSError: return ATGEN_HandleCMSError(s); + case AT_Reply_CMEError: + return ATGEN_HandleCMEError(s); default: return ERR_UNKNOWNRESPONSE; } } GSM_Error ATGEN_GetSMSMemories(GSM_StateMachine *s) { smprintf(s, "Getting available SMS memories\n"); return GSM_WaitFor (s, "AT+CPMS=?\r", 10, 0x00, 4, ID_GetSMSMemories); } GSM_Error ATGEN_SetSMSMemory(GSM_StateMachine *s, bool SIM) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; char req[] = "AT+CPMS=\"XX\",\"XX\"\r"; int reqlen = 18; GSM_Error error; if ((SIM && Priv->SIMSMSMemory == 0) || (!SIM && Priv->PhoneSMSMemory == 0)) { /* We silently ignore error here, because when this fails, we can try to setmemory anyway */ ATGEN_GetSMSMemories(s); } /* If phone can not save SMS, don't try to set memory for saving */ if (!Priv->CanSaveSMS) { req[12] = '\r'; reqlen = 13; } if (SIM) { if (Priv->SMSMemory == MEM_SM) return ERR_NONE; if (Priv->SIMSMSMemory == AT_NOTAVAILABLE) return ERR_NOTSUPPORTED; req[9] = 'S'; req[10] = 'M'; req[14] = 'S'; req[15] = 'M'; smprintf(s, "Setting SMS memory type to SM\n"); error=GSM_WaitFor (s, req, reqlen, 0x00, 3, ID_SetMemoryType); if (Priv->SIMSMSMemory == 0 && error == ERR_NONE) { Priv->SIMSMSMemory = AT_AVAILABLE; } if (error == ERR_NOTSUPPORTED) { smprintf(s, "Can't access SIM card?\n"); return ERR_SECURITYERROR; } if (error != ERR_NONE) return error; Priv->SMSMemory = MEM_SM; } else { @@ -813,188 +868,189 @@ GSM_Error ATGEN_GetSMSLocation(GSM_StateMachine *s, GSM_SMSMessage *sms, unsigne } smprintf(s, "SMS folder %i & location %i -> ATGEN folder %i & location %i\n", sms->Folder,sms->Location,*folderid,*location); if (Priv->SIMSMSMemory == AT_AVAILABLE && *folderid == 1) { return ATGEN_SetSMSMemory(s, true); } else { return ATGEN_SetSMSMemory(s, false); } } void ATGEN_SetSMSLocation(GSM_StateMachine *s, GSM_SMSMessage *sms, unsigned char folderid, int location) { sms->Folder = 0; sms->Location = (folderid - 1) * PHONE_MAXSMSINFOLDER + location; smprintf(s, "ATGEN folder %i & location %i -> SMS folder %i & location %i\n", folderid,location,sms->Folder,sms->Location); } GSM_Error ATGEN_ReplyGetSMSMessage(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_SMSMessage *sms = &s->Phone.Data.GetSMSMessage->SMS[0]; int current = 0, current2, i; unsigned char buffer[300],smsframe[800]; unsigned char firstbyte, TPDCS, TPUDL, TPStatus; GSM_Error error; switch (Priv->ReplyState) { case AT_Reply_OK: if (Priv->Lines.numbers[4] == 0x00) return ERR_EMPTY; s->Phone.Data.GetSMSMessage->Number = 1; s->Phone.Data.GetSMSMessage->SMS[0].Name[0] = 0; s->Phone.Data.GetSMSMessage->SMS[0].Name[1] = 0; switch (Priv->SMSMode) { case SMS_AT_PDU: CopyLineString(buffer, msg.Buffer, Priv->Lines, 2); switch (buffer[7]) { case '0': sms->State = SMS_UnRead; break; case '1': sms->State = SMS_Read; break; case '2': sms->State = SMS_UnSent; break; default : sms->State = SMS_Sent; break;//case '3' } DecodeHexBin (buffer, GetLineString(msg.Buffer,Priv->Lines,3), strlen(GetLineString(msg.Buffer,Priv->Lines,3))); /* Siemens MC35 (only ?) */ if (strstr(msg.Buffer,"+CMGR: 0,,0")!=NULL) return ERR_EMPTY; /* Siemens M20 */ if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_M20SMS)) { - if (buffer[1]!=NUMBER_UNKNOWN && buffer[1]!=NUMBER_INTERNATIONAL && - buffer[1]!=NUMBER_ALPHANUMERIC) { + /* we check for the most often visible */ + if (buffer[1]!=NUMBER_UNKNOWN_NUMBERING_PLAN_ISDN && buffer[1]!=NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN && + buffer[1]!=NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN) { /* Seems to be Delivery Report */ smprintf(s, "SMS type - status report (M20 style)\n"); sms->PDU = SMS_Status_Report; sms->Folder = 1; /*INBOX SIM*/ sms->InboxFolder = true; smsframe[12]=buffer[current++]; smsframe[PHONE_SMSStatusReport.TPMR]=buffer[current++]; current2=((buffer[current])+1)/2+1; for(i=0;i<current2+1;i++) smsframe[PHONE_SMSStatusReport.Number+i]=buffer[current++]; for(i=0;i<7;i++) smsframe[PHONE_SMSStatusReport.DateTime+i]=buffer[current++]; smsframe[0] = 0; for(i=0;i<7;i++) smsframe[PHONE_SMSStatusReport.SMSCTime+i]=buffer[current++]; smsframe[PHONE_SMSStatusReport.TPStatus]=buffer[current]; GSM_DecodeSMSFrame(sms,smsframe,PHONE_SMSStatusReport); return ERR_NONE; } } /* We use locations from SMS layouts like in ../phone2.c(h) */ for(i=0;i<buffer[0]+1;i++) smsframe[i]=buffer[current++]; smsframe[12]=buffer[current++]; /* See GSM 03.40 section 9.2.3.1 */ switch (smsframe[12] & 0x03) { case 0x00: smprintf(s, "SMS type - deliver\n"); sms->PDU = SMS_Deliver; if (Priv->SMSMemory == MEM_SM) { sms->Folder = 1; /*INBOX SIM*/ } else { sms->Folder = 3; /*INBOX ME*/ } sms->InboxFolder = true; current2=((buffer[current])+1)/2+1; if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_M20SMS)) { - if (buffer[current+1]==NUMBER_ALPHANUMERIC) { + if (buffer[current+1]==NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN) { smprintf(s, "Trying to read alphanumeric number\n"); for(i=0;i<4;i++) smsframe[PHONE_SMSDeliver.Number+i]=buffer[current++]; current+=6; for(i=0;i<current2-3;i++) smsframe[PHONE_SMSDeliver.Number+i+4]=buffer[current++]; } else { for(i=0;i<current2+1;i++) smsframe[PHONE_SMSDeliver.Number+i]=buffer[current++]; } } else { for(i=0;i<current2+1;i++) smsframe[PHONE_SMSDeliver.Number+i]=buffer[current++]; } smsframe[PHONE_SMSDeliver.TPPID] = buffer[current++]; smsframe[PHONE_SMSDeliver.TPDCS] = buffer[current++]; for(i=0;i<7;i++) smsframe[PHONE_SMSDeliver.DateTime+i]=buffer[current++]; smsframe[PHONE_SMSDeliver.TPUDL] = buffer[current++]; for(i=0;i<smsframe[PHONE_SMSDeliver.TPUDL];i++) smsframe[i+PHONE_SMSDeliver.Text]=buffer[current++]; GSM_DecodeSMSFrame(sms,smsframe,PHONE_SMSDeliver); return ERR_NONE; case 0x01: smprintf(s, "SMS type - submit\n"); sms->PDU = SMS_Submit; if (Priv->SMSMemory == MEM_SM) { sms->Folder = 2; /*OUTBOX SIM*/ smprintf(s, "Outbox SIM\n"); } else { sms->Folder = 4; /*OUTBOX ME*/ } sms->InboxFolder = false; smsframe[PHONE_SMSSubmit.TPMR] = buffer[current++]; current2=((buffer[current])+1)/2+1; if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_M20SMS)) { - if (buffer[current+1]==NUMBER_ALPHANUMERIC) { + if (buffer[current+1]==NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN) { smprintf(s, "Trying to read alphanumeric number\n"); for(i=0;i<4;i++) smsframe[PHONE_SMSSubmit.Number+i]=buffer[current++]; current+=6; for(i=0;i<current2-3;i++) smsframe[PHONE_SMSSubmit.Number+i+4]=buffer[current++]; } else { for(i=0;i<current2+1;i++) smsframe[PHONE_SMSSubmit.Number+i]=buffer[current++]; } } else { for(i=0;i<current2+1;i++) smsframe[PHONE_SMSSubmit.Number+i]=buffer[current++]; } smsframe[PHONE_SMSSubmit.TPPID] = buffer[current++]; smsframe[PHONE_SMSSubmit.TPDCS] = buffer[current++]; /* See GSM 03.40 9.2.3.3 - TPVP can not exist in frame */ if ((smsframe[12] & 0x18)!=0) current++; //TPVP is ignored now smsframe[PHONE_SMSSubmit.TPUDL] = buffer[current++]; for(i=0;i<smsframe[PHONE_SMSSubmit.TPUDL];i++) smsframe[i+PHONE_SMSSubmit.Text]=buffer[current++]; GSM_DecodeSMSFrame(sms,smsframe,PHONE_SMSSubmit); return ERR_NONE; case 0x02: smprintf(s, "SMS type - status report\n"); sms->PDU = SMS_Status_Report; sms->Folder = 1; /*INBOX SIM*/ sms->InboxFolder = true; - smprintf(s, "TPMR is %02x\n",buffer[current]); + smprintf(s, "TPMR is %d\n",buffer[current]); smsframe[PHONE_SMSStatusReport.TPMR] = buffer[current++]; current2=((buffer[current])+1)/2+1; for(i=0;i<current2+1;i++) smsframe[PHONE_SMSStatusReport.Number+i]=buffer[current++]; for(i=0;i<7;i++) smsframe[PHONE_SMSStatusReport.DateTime+i]=buffer[current++]; for(i=0;i<7;i++) smsframe[PHONE_SMSStatusReport.SMSCTime+i]=buffer[current++]; smsframe[PHONE_SMSStatusReport.TPStatus]=buffer[current]; GSM_DecodeSMSFrame(sms,smsframe,PHONE_SMSStatusReport); return ERR_NONE; } break; case SMS_AT_TXT: current = 0; while (msg.Buffer[current]!='"') current++; current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer); if (!strcmp(buffer,"\"0\"") || !strcmp(buffer,"\"REC UNREAD\"")) { smprintf(s, "SMS type - deliver\n"); sms->State = SMS_UnRead; sms->PDU = SMS_Deliver; if (Priv->SMSMemory == MEM_SM) { sms->Folder = 1; /*INBOX SIM*/ } else { sms->Folder = 3; /*INBOX ME*/ } sms->InboxFolder = true; } else if (!strcmp(buffer,"\"1\"") || !strcmp(buffer,"\"REC READ\"")) { smprintf(s, "SMS type - deliver\n"); sms->State = SMS_Read; sms->PDU = SMS_Deliver; if (Priv->SMSMemory == MEM_SM) { sms->Folder = 1; /*INBOX SIM*/ } else { sms->Folder = 3; /*INBOX ME*/ } sms->InboxFolder = true; } else if (!strcmp(buffer,"\"2\"") || !strcmp(buffer,"\"STO UNSENT\"")) { smprintf(s, "SMS type - submit\n"); sms->State = SMS_UnSent; sms->PDU = SMS_Submit; if (Priv->SMSMemory == MEM_SM) { sms->Folder = 2; /*OUTBOX SIM*/ } else { sms->Folder = 4; /*OUTBOX ME*/ } sms->InboxFolder = false; } else if (!strcmp(buffer,"\"3\"") || !strcmp(buffer,"\"STO SENT\"")) { smprintf(s, "SMS type - submit\n"); sms->State = SMS_Sent; sms->PDU = SMS_Submit; @@ -1595,107 +1651,107 @@ GSM_Error ATGEN_AddSMS(GSM_StateMachine *s, GSM_SMSMessage *sms) } } s->Protocol.Data.AT.EditMode = true; Replies = s->ReplyNum; s->ReplyNum = 1; smprintf(s,"Waiting for modem prompt\n"); error=GSM_WaitFor (s, buffer, strlen(buffer), 0x00, 3, ID_SaveSMSMessage); s->ReplyNum = Replies; if (error == ERR_NONE) { Phone->DispatchError = ERR_TIMEOUT; Phone->RequestID = ID_SaveSMSMessage; smprintf(s, "Saving SMS\n"); error = s->Protocol.Functions->WriteMessage(s, hexreq, current2, 0x00); if (error!=ERR_NONE) return error; my_sleep(500); /* CTRL+Z ends entering */ error = s->Protocol.Functions->WriteMessage(s, "\x1A", 1, 0x00); if (error!=ERR_NONE) return error; error = GSM_WaitForOnce(s, NULL, 0x00, 0x00, 4); if (error != ERR_TIMEOUT) return error; } else { smprintf(s, "Escaping SMS mode\n"); error2 = s->Protocol.Functions->WriteMessage(s, "\x1B\r", 2, 0x00); if (error2 != ERR_NONE) return error2; return error; } } return Phone->DispatchError; } GSM_Error ATGEN_ReplySendSMS(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; char *start; if (s->Protocol.Data.AT.EditMode) { if (s->Phone.Data.Priv.ATGEN.ReplyState != AT_Reply_SMSEdit) { return ERR_UNKNOWN; } s->Protocol.Data.AT.EditMode = false; return ERR_NONE; } switch (Priv->ReplyState) { case AT_Reply_OK: smprintf(s, "SMS sent OK\n"); if (s->User.SendSMSStatus!=NULL) { - start = strstr(msg.Buffer, "+CMGW: "); + start = strstr(msg.Buffer, "+CMGS: "); if (start != NULL) { s->User.SendSMSStatus(s->CurrentConfig->Device,0,atoi(start+7)); } else { - s->User.SendSMSStatus(s->CurrentConfig->Device,0,0); + s->User.SendSMSStatus(s->CurrentConfig->Device,0,-1); } } return ERR_NONE; case AT_Reply_CMSError: smprintf(s, "Error %i\n",Priv->ErrorCode); - if (s->User.SendSMSStatus!=NULL) s->User.SendSMSStatus(s->CurrentConfig->Device,Priv->ErrorCode,0); + if (s->User.SendSMSStatus!=NULL) s->User.SendSMSStatus(s->CurrentConfig->Device,Priv->ErrorCode,-1); return ATGEN_HandleCMSError(s); case AT_Reply_Error: return ERR_UNKNOWN; default: return ERR_UNKNOWNRESPONSE; } } GSM_Error ATGEN_SendSMS(GSM_StateMachine *s, GSM_SMSMessage *sms) { GSM_Error error,error2; int current, current2, Replies; unsigned char buffer[1000], hexreq[1000]; GSM_Phone_Data *Phone = &s->Phone.Data; if (sms->PDU == SMS_Deliver) sms->PDU = SMS_Submit; error = ATGEN_MakeSMSFrame(s, sms, hexreq, ¤t, ¤t2); if (error != ERR_NONE) return error; switch (Phone->Priv.ATGEN.SMSMode) { case SMS_AT_PDU: sprintf(buffer, "AT+CMGS=%i\r",current); break; case SMS_AT_TXT: sprintf(buffer, "AT+CMGS=\"%s\"\r",DecodeUnicodeString(sms->Number)); } s->Protocol.Data.AT.EditMode = true; Replies = s->ReplyNum; s->ReplyNum = 1; smprintf(s,"Waiting for modem prompt\n"); error=GSM_WaitFor (s, buffer, strlen(buffer), 0x00, 3, ID_IncomingFrame); s->ReplyNum = Replies; if (error == ERR_NONE) { smprintf(s, "Sending SMS\n"); error = s->Protocol.Functions->WriteMessage(s, hexreq, current2, 0x00); if (error!=ERR_NONE) return error; my_sleep(500); /* CTRL+Z ends entering */ error=s->Protocol.Functions->WriteMessage(s, "\x1A", 1, 0x00); my_sleep(100); return error; } else { smprintf(s, "Escaping SMS mode\n"); error2=s->Protocol.Functions->WriteMessage(s, "\x1B\r", 2, 0x00); if (error2 != ERR_NONE) return error2; } @@ -1742,96 +1798,109 @@ GSM_Error ATGEN_ReplyGetDateTime_Alarm(GSM_Protocol_Message msg, GSM_StateMachin if (Data->RequestID == ID_GetDateTime) { ATGEN_DecodeDateTime(Data->DateTime, msg.Buffer+current); } else { ATGEN_DecodeDateTime(&(Data->Alarm->DateTime), msg.Buffer+current); } return ERR_NONE; } case AT_Reply_Error: return ERR_NOTSUPPORTED; case AT_Reply_CMSError: return ATGEN_HandleCMSError(s); default: break; } return ERR_UNKNOWNRESPONSE; } GSM_Error ATGEN_GetDateTime(GSM_StateMachine *s, GSM_DateTime *date_time) { s->Phone.Data.DateTime=date_time; smprintf(s, "Getting date & time\n"); return GSM_WaitFor (s, "AT+CCLK?\r", 9, 0x00, 4, ID_GetDateTime); } GSM_Error ATGEN_SetDateTime(GSM_StateMachine *s, GSM_DateTime *date_time) { char req[128]; sprintf(req, "AT+CCLK=\"%02i/%02i/%02i,%02i:%02i:%02i+00\"\r", date_time->Year-2000,date_time->Month,date_time->Day, date_time->Hour,date_time->Minute,date_time->Second); smprintf(s, "Setting date & time\n"); return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_SetDateTime); } GSM_Error ATGEN_GetAlarm(GSM_StateMachine *s, GSM_Alarm *alarm) { if (alarm->Location != 1) return ERR_NOTSUPPORTED; alarm->Repeating = true; alarm->Text[0] = 0; alarm->Text[1] = 0; s->Phone.Data.Alarm = alarm; smprintf(s, "Getting alarm\n"); return GSM_WaitFor (s, "AT+CALA?\r", 9, 0x00, 4, ID_GetAlarm); } +/* R320 only takes HH:MM. Do other phones understand full date? */ +GSM_Error ATGEN_SetAlarm(GSM_StateMachine *s, GSM_Alarm *alarm) +{ + char req[20]; + + if (alarm->Location != 1) return ERR_INVALIDLOCATION; + + sprintf(req, "AT+CALA=\"%02i:%02i\"\r",alarm->DateTime.Hour,alarm->DateTime.Minute); + + smprintf(s, "Setting Alarm\n"); + return GSM_WaitFor (s, req, strlen(req), 0x00, 3, ID_SetAlarm); +} + GSM_Error ATGEN_ReplyGetSMSC(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_SMSC *SMSC = s->Phone.Data.SMSC; int current; int len; unsigned char buffer[100]; switch (s->Phone.Data.Priv.ATGEN.ReplyState) { case AT_Reply_OK: smprintf(s, "SMSC info received\n"); current = 0; while (msg.Buffer[current]!='"') current++; /* SMSC number */ /* FIXME: support for all formats */ current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer); /* * Some phones return this as unicode encoded when they are * switched to UCS2 mode, so we try to solve this correctly. */ len = strlen(buffer + 1) - 1; buffer[len + 1] = 0; if ((len > 20) && (len % 4 == 0) && (strchr(buffer + 1, '+') == NULL)) { /* This is probably unicode encoded number */ DecodeHexUnicode(SMSC->Number,buffer + 1,len); } else { EncodeUnicode(SMSC->Number,buffer + 1,len); } smprintf(s, "Number: \"%s\"\n",DecodeUnicodeString(SMSC->Number)); /* Format of SMSC number */ current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer); smprintf(s, "Format %s\n",buffer); /* International number */ if (!strcmp(buffer,"145")) { sprintf(buffer+1,"%s",DecodeUnicodeString(SMSC->Number)); if (strlen(buffer+1)!=0 && buffer[1] != '+') { /* Sony Ericsson issue */ /* International number is without + */ buffer[0] = '+'; EncodeUnicode(SMSC->Number,buffer,strlen(buffer)); } } SMSC->Format = SMS_FORMAT_Text; SMSC->Validity.Format = SMS_Validity_RelativeFormat; SMSC->Validity.Relative = SMS_VALID_Max_Time; @@ -2157,162 +2226,170 @@ GSM_Error ATGEN_ReplyGetCPBRMemoryStatus(GSM_Protocol_Message msg, GSM_StateMach { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_MemoryStatus *MemoryStatus = s->Phone.Data.MemoryStatus; int line=0; char *str; int cur; switch (Priv->ReplyState) { case AT_Reply_OK: smprintf(s, "Memory entries received\n"); /* Walk through lines with +CPBR: */ while (Priv->Lines.numbers[line*2+1]!=0) { str = GetLineString(msg.Buffer,Priv->Lines,line+1); if (strncmp(str, "+CPBR: ", 7) == 0) { MemoryStatus->MemoryUsed++; if (sscanf(str, "+CPBR: %d,", &cur) == 1) { cur -= Priv->FirstMemoryEntry - 1; if (cur == Priv->NextMemoryEntry || Priv->NextMemoryEntry == 0) Priv->NextMemoryEntry = cur + 1; } } line++; } return ERR_NONE; case AT_Reply_Error: return ERR_UNKNOWN; case AT_Reply_CMSError: return ATGEN_HandleCMSError(s); default: return ERR_UNKNOWNRESPONSE; } } GSM_Error ATGEN_GetMemoryInfo(GSM_StateMachine *s, GSM_MemoryStatus *Status, GSM_AT_NeededMemoryInfo NeededInfo) { GSM_Error error; char req[20]; int start; int end; GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; smprintf(s, "Getting memory information\n"); Priv->MemorySize = 0; Priv->TextLength = 0; Priv->NumberLength = 0; error = GSM_WaitFor (s, "AT+CPBR=?\r", 10, 0x00, 4, ID_GetMemoryStatus); + if (Priv->Manufacturer == AT_Samsung) + error = GSM_WaitFor (s, "", 0, 0x00, 4, ID_GetMemoryStatus); if (error != ERR_NONE) return error; if (NeededInfo == AT_Total || NeededInfo == AT_Sizes || NeededInfo == AT_First) return ERR_NONE; smprintf(s, "Getting memory status by reading values\n"); s->Phone.Data.MemoryStatus = Status; Status->MemoryUsed = 0; Status->MemoryFree = 0; start = Priv->FirstMemoryEntry; Priv->NextMemoryEntry = 0; while (1) { end = start + 20; if (end > Priv->MemorySize) end = Priv->MemorySize; sprintf(req, "AT+CPBR=%i,%i\r", start, end); error = GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetMemoryStatus); if (error != ERR_NONE) return error; if (NeededInfo == AT_NextEmpty && Priv->NextMemoryEntry != 0 && Priv->NextMemoryEntry != end + 1) return ERR_NONE; if (end == Priv->MemorySize) { Status->MemoryFree = Priv->MemorySize - Status->MemoryUsed; return ERR_NONE; } start = end + 1; } } GSM_Error ATGEN_GetMemoryStatus(GSM_StateMachine *s, GSM_MemoryStatus *Status) { GSM_Error error; error = ATGEN_SetPBKMemory(s, Status->MemoryType); if (error != ERR_NONE) return error; s->Phone.Data.MemoryStatus=Status; /* in some phones doesn't work or doesn't return memory status inside */ /* Some workaround for buggy mobile, that hangs after "AT+CPBS?" for other * memory than SM. */ if (!IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_BROKENCPBS) || (Status->MemoryType == MEM_SM)) { smprintf(s, "Getting memory status\n"); error=GSM_WaitFor (s, "AT+CPBS?\r", 9, 0x00, 4, ID_GetMemoryStatus); if (error == ERR_NONE) return ERR_NONE; } return ATGEN_GetMemoryInfo(s, Status, AT_Status); } GSM_Error ATGEN_SetPBKCharset(GSM_StateMachine *s, bool PreferUnicode) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_Error error; /* Have we already selected something? */ if (Priv->PBKCharset!=0) { /* If we want unicode charset and we have it already or setting of it * failed, we have nothing to do. */ if (PreferUnicode && (Priv->PBKCharset==AT_PBK_UCS2 || Priv->UCS2CharsetFailed)) return ERR_NONE; /* If we don't need unicode charset and we have some (or have unicode * charset when other failed), we have nothing to do. */ if (!PreferUnicode && (Priv->PBKCharset!=AT_PBK_UCS2 || Priv->NonUCS2CharsetFailed)) return ERR_NONE; } error=ATGEN_GetManufacturer(s); if (error != ERR_NONE) return error; + /* Samsung (and Sagem?) phones use only PCCP437? */ + if (Priv->Manufacturer == AT_Samsung) { + Priv->PBKCharset = AT_PBK_PCCP437; + return ERR_NONE; + } + if (PreferUnicode && !Priv->UCS2CharsetFailed) { smprintf(s, "Setting charset to UCS2\n"); error=GSM_WaitFor (s, "AT+CSCS=\"UCS2\"\r", 15, 0x00, 3, ID_SetMemoryCharset); if (error == ERR_NONE) { Priv->PBKCharset = AT_PBK_UCS2; return ERR_NONE; } else { Priv->UCS2CharsetFailed = true; } } smprintf(s, "Setting charset to HEX\n"); error=GSM_WaitFor (s, "AT+CSCS=\"HEX\"\r", 14, 0x00, 3, ID_SetMemoryCharset); /* Falcom replies OK for HEX mode and send everything * in normal format */ if (error == ERR_NONE && Priv->Manufacturer != AT_Falcom) { Priv->PBKCharset = AT_PBK_HEX; return ERR_NONE; } smprintf(s, "Setting charset to GSM\n"); error=GSM_WaitFor (s, "AT+CSCS=\"GSM\"\r", 14, 0x00, 3, ID_SetMemoryCharset); if (error == ERR_NONE) { Priv->PBKCharset = AT_PBK_GSM; return ERR_NONE; } if (!Priv->UCS2CharsetFailed) { Priv->NonUCS2CharsetFailed = true; smprintf(s, "Setting charset to UCS2\n"); error=GSM_WaitFor (s, "AT+CSCS=\"UCS2\"\r", 15, 0x00, 3, ID_SetMemoryCharset); if (error == ERR_NONE) { Priv->PBKCharset = AT_PBK_UCS2; return ERR_NONE; } else { Priv->UCS2CharsetFailed = true; } } return error; } GSM_Error ATGEN_ReplyGetMemory(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_MemoryEntry *Memory = s->Phone.Data.Memory; char *pos; unsigned char buffer[500],buffer2[500]; @@ -2340,97 +2417,127 @@ GSM_Error ATGEN_ReplyGetMemory(GSM_Protocol_Message msg, GSM_StateMachine *s) Memory->EntriesNum++; Memory->Entries[0].EntryType = PBK_Number_General; Memory->Entries[0].VoiceTag = 0; Memory->Entries[0].SMSList[0] = 0; len = strlen(buffer + 1) - 1; if (Priv->PBKCharset == AT_PBK_HEX && (len > 10) && (len % 2 == 0) && (strchr(buffer + 1, '+') == NULL)) { /* This is probably hex encoded number */ DecodeHexBin(buffer2, buffer+1, len); DecodeDefault(Memory->Entries[0].Text ,buffer2, strlen(buffer2), false, NULL); } else if (Priv->PBKCharset == AT_PBK_UCS2 && (len > 20) && (len % 4 == 0) && (strchr(buffer + 1, '+') == NULL)) { /* This is probably unicode encoded number */ DecodeHexUnicode(Memory->Entries[0].Text, buffer + 1,len); } else { EncodeUnicode(Memory->Entries[0].Text, buffer + 1, len); } /* Number format */ pos += ATGEN_ExtractOneParameter(pos, buffer); smprintf(s, "Number format: %s\n",buffer); /* International number */ if (!strcmp(buffer,"145")) { sprintf(buffer+1,"%s",DecodeUnicodeString(Memory->Entries[0].Text)); if (strlen(buffer+1)!=0 && buffer[1] != '+') { /* Sony Ericsson issue */ /* International number is without + */ buffer[0] = '+'; EncodeUnicode(Memory->Entries[0].Text,buffer,strlen(buffer)); } } /* Name */ pos += ATGEN_ExtractOneParameter(pos, buffer); smprintf(s, "Name text: %s\n",buffer); Memory->EntriesNum++; Memory->Entries[1].EntryType=PBK_Text_Name; switch (Priv->PBKCharset) { case AT_PBK_HEX: DecodeHexBin(buffer2,buffer+1,strlen(buffer)-2); DecodeDefault(Memory->Entries[1].Text,buffer2,strlen(buffer2),false,NULL); break; case AT_PBK_GSM: DecodeDefault(Memory->Entries[1].Text,buffer+1,strlen(buffer)-2,false,NULL); break; case AT_PBK_UCS2: DecodeHexUnicode(Memory->Entries[1].Text,buffer+1,strlen(buffer+1) - 1); break; + case AT_PBK_PCCP437: + /* FIXME: correctly decode PCCP437 */ + DecodeDefault(Memory->Entries[1].Text,buffer+1,strlen(buffer)-2,false,NULL); + break; + } + + /* Samsung number type */ + if (Priv->Manufacturer == AT_Samsung) { + int type; + + pos += ATGEN_ExtractOneParameter(pos, buffer); + smprintf(s, "Number type: %s\n",buffer); + type = strtoul(buffer, NULL, 0); + switch (type) { + case 0: + Memory->Entries[0].EntryType = PBK_Number_Mobile; + break; + case 1: + Memory->Entries[0].EntryType = PBK_Number_Work; + break; + case 2: + Memory->Entries[0].EntryType = PBK_Number_Home; + break; + case 3: + Memory->Entries[0].EntryType = PBK_Text_Email; + break; + default: + Memory->Entries[0].EntryType = PBK_Number_General; + } } + return ERR_NONE; case AT_Reply_CMEError: return ATGEN_HandleCMEError(s); case AT_Reply_Error: smprintf(s, "Error - too high location ?\n"); return ERR_INVALIDLOCATION; case AT_Reply_CMSError: return ATGEN_HandleCMSError(s); default: break; } return ERR_UNKNOWNRESPONSE; } GSM_Error ATGEN_PrivGetMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry, int endlocation) { GSM_Error error; unsigned char req[20]; GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; if (entry->Location==0x00) return ERR_INVALIDLOCATION; if (entry->MemoryType == MEM_ME) { if (Priv->PBKSBNR == 0) { sprintf(req, "AT^SBNR=?\r"); smprintf(s, "Checking availablity of SBNR\n"); error=GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetMemory); switch (error) { case ERR_NONE: Priv->PBKSBNR = AT_SBNR_AVAILABLE; break; case ERR_UNKNOWN: case ERR_NOTSUPPORTED: Priv->PBKSBNR = AT_SBNR_NOTAVAILABLE; break; default: return error; } } if (Priv->PBKSBNR == AT_SBNR_AVAILABLE) { sprintf(req, "AT^SBNR=vcf,%i\r",entry->Location-1); s->Phone.Data.Memory=entry; smprintf(s, "Getting phonebook entry\n"); return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetMemory); } } error=ATGEN_GetManufacturer(s); @@ -2517,96 +2624,98 @@ GSM_Error ATGEN_DeleteAllMemory(GSM_StateMachine *s, GSM_MemoryType type) error = GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_SetMemory); if (error != ERR_NONE) return error; } return ERR_NONE; } GSM_Error ATGEN_ReplyDialVoice(GSM_Protocol_Message msg, GSM_StateMachine *s) { switch (s->Phone.Data.Priv.ATGEN.ReplyState) { case AT_Reply_OK: smprintf(s, "Dial voice OK\n"); return ERR_NONE; case AT_Reply_Error: smprintf(s, "Dial voice error\n"); return ERR_UNKNOWN; case AT_Reply_CMSError: return ATGEN_HandleCMSError(s); default: break; } return ERR_UNKNOWNRESPONSE; } GSM_Error ATGEN_DialVoice(GSM_StateMachine *s, char *number, GSM_CallShowNumber ShowNumber) { char req[39] = "ATDT"; if (ShowNumber != GSM_CALL_DefaultNumberPresence) return ERR_NOTSUPPORTED; if (strlen(number) > 32) return (ERR_UNKNOWN); strcat(req, number); strcat(req, ";\r"); smprintf(s, "Making voice call\n"); return GSM_WaitFor (s, req, 4+2+strlen(number), 0x00, 5, ID_DialVoice); } GSM_Error ATGEN_ReplyEnterSecurityCode(GSM_Protocol_Message msg, GSM_StateMachine *s) { switch (s->Phone.Data.Priv.ATGEN.ReplyState) { case AT_Reply_OK: smprintf(s, "Security code was OK\n"); return ERR_NONE; case AT_Reply_Error: smprintf(s, "Incorrect security code\n"); return ERR_SECURITYERROR; case AT_Reply_CMSError: return ATGEN_HandleCMSError(s); + case AT_Reply_CMEError: + return ATGEN_HandleCMEError(s); default: break; } return ERR_UNKNOWNRESPONSE; } GSM_Error ATGEN_EnterSecurityCode(GSM_StateMachine *s, GSM_SecurityCode Code) { unsigned char req[50]; switch (Code.Type) { case SEC_Pin : sprintf(req, "AT+CPIN=\"%s\"\r" , Code.Code); break; case SEC_Pin2 : if (s->Phone.Data.Priv.ATGEN.Manufacturer == AT_Siemens) { sprintf(req, "AT+CPIN2=\"%s\"\r", Code.Code); } else { sprintf(req, "AT+CPIN=\"%s\"\r" , Code.Code); } break; default : return ERR_NOTIMPLEMENTED; } smprintf(s, "Entering security code\n"); return GSM_WaitFor (s, req, strlen(req), 0x00, 6, ID_EnterSecurityCode); } GSM_Error ATGEN_ReplyGetSecurityStatus(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_SecurityCodeType *Status = s->Phone.Data.SecurityStatus; smprintf(s, "Security status received - "); if (strstr(msg.Buffer,"READY")) { *Status = SEC_None; smprintf(s, "nothing to enter\n"); return ERR_NONE; } if (strstr(msg.Buffer,"PH_SIM PIN")) { smprintf(s, "no SIM inside or other error\n"); return ERR_UNKNOWN; } if (strstr(msg.Buffer,"SIM PIN2")) { *Status = SEC_Pin2; smprintf(s, "waiting for PIN2\n"); return ERR_NONE; } if (strstr(msg.Buffer,"SIM PUK2")) { @@ -2879,96 +2988,102 @@ GSM_Error ATGEN_PrivSetMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry) if (entry->Location == 0) return ERR_INVALIDLOCATION; error = ATGEN_SetPBKMemory(s, entry->MemoryType); if (error != ERR_NONE) return error; GSM_PhonebookFindDefaultNameNumberGroup(entry, &Name, &Number, &Group); name[0] = 0; if (Name != -1) { len = UnicodeLength(entry->Entries[Name].Text); /* Compare if we would loose some information when not using * unicode */ EncodeDefault(name, entry->Entries[Name].Text, &len, true, NULL); DecodeDefault(uname, name, len, true, NULL); if (!mywstrncmp(uname, entry->Entries[Name].Text, len)) { /* Get maximal text length */ if (Priv->TextLength == 0) { ATGEN_GetMemoryInfo(s, NULL, AT_Sizes); } /* I char stored in GSM alphabet takes 7 bits, one * unicode 16, if storing in unicode would truncate * text, do not use it, otherwise we will use it */ if ((Priv->TextLength != 0) && ((Priv->TextLength * 7 / 16) <= len)) { PreferUnicode = false; } else { PreferUnicode = true; } } error = ATGEN_SetPBKCharset(s, PreferUnicode); if (error != ERR_NONE) return error; switch (Priv->PBKCharset) { case AT_PBK_HEX: EncodeHexBin(name, DecodeUnicodeString(entry->Entries[Name].Text), UnicodeLength(entry->Entries[Name].Text)); len = strlen(name); break; case AT_PBK_GSM: smprintf(s, "str: %s\n", DecodeUnicodeString(entry->Entries[Name].Text)); len = UnicodeLength(entry->Entries[Name].Text); EncodeDefault(name, entry->Entries[Name].Text, &len, true, NULL); break; case AT_PBK_UCS2: EncodeHexUnicode(name, entry->Entries[Name].Text, UnicodeLength(entry->Entries[Name].Text)); len = strlen(name); break; + case AT_PBK_PCCP437: + /* FIXME: correctly decode PCCP437 */ + smprintf(s, "str: %s\n", DecodeUnicodeString(entry->Entries[Name].Text)); + len = UnicodeLength(entry->Entries[Name].Text); + EncodeDefault(name, entry->Entries[Name].Text, &len, true, NULL); + break; } } else { smprintf(s, "WARNING: No usable name found!\n"); len = 0; } if (Number != -1) { GSM_PackSemiOctetNumber(entry->Entries[Number].Text, number, false); NumberType = number[0]; sprintf(number,"%s",DecodeUnicodeString(entry->Entries[Number].Text)); } else { smprintf(s, "WARNING: No usable number found!\n"); number[0] = 0; } if (Priv->FirstMemoryEntry == 0) { error = ATGEN_GetMemoryInfo(s, NULL, AT_First); if (error != ERR_NONE) return error; } /* We can't use here: * sprintf(req, "AT+CPBW=%d, \"%s\", %i, \"%s\"\r", * entry->Location, number, NumberType, name); * because name can contain 0 when using GSM alphabet. */ sprintf(req, "AT+CPBW=%d, \"%s\", %i, \"", entry->Location + Priv->FirstMemoryEntry - 1, number, NumberType); reqlen = strlen(req); if (reqlen + len > REQUEST_SIZE - 2) { smprintf(s, "WARNING: Text truncated to fit in buffer!\n"); len = REQUEST_SIZE - 2 - reqlen; } memcpy(req + reqlen, name, len); reqlen += len; memcpy(req + reqlen, "\"\r", 2); reqlen += 2; smprintf(s, "Writing phonebook entry\n"); return GSM_WaitFor (s, req, reqlen, 0x00, 4, ID_SetMemory); #undef REQUEST_SIZE } GSM_Error ATGEN_SetMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry) { if (entry->Location == 0) return ERR_INVALIDLOCATION; return ATGEN_PrivSetMemory(s, entry); } GSM_Error ATGEN_AddMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry) @@ -3207,463 +3322,541 @@ GSM_Error ATGEN_GetSignalQuality(GSM_StateMachine *s, GSM_SignalQuality *sig) return GSM_WaitFor (s, "AT+CSQ\r", 7, 0x00, 4, ID_GetSignalQuality); } /* When use AT+CPIN?, A2D returns it without OK and because of it Gammu parses answer without it. MC35 and other return OK after answer for AT+CPIN?. Here we handle it. Any better idea ? */ GSM_Error ATGEN_ReplyOK(GSM_Protocol_Message msg, GSM_StateMachine *s) { return ERR_NONE; } static GSM_Error ATGEN_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; if (Priv->Manufacturer==AT_Siemens ) return SIEMENS_GetNextCalendar(s,Note,start); if (Priv->Manufacturer==AT_Ericsson) return SONYERIC_GetNextCalendar(s,Note,start); return ERR_NOTSUPPORTED; } GSM_Error ATGEN_Terminate(GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; free(Priv->file.Buffer); return ERR_NONE; } GSM_Error ATGEN_AddCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; if (Priv->Manufacturer==AT_Siemens) return SIEMENS_AddCalendarNote(s, Note); if (Priv->Manufacturer==AT_Ericsson) return SONYERIC_AddCalendarNote(s, Note); return ERR_NOTSUPPORTED; } GSM_Error ATGEN_DelCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; if (Priv->Manufacturer==AT_Siemens) return SIEMENS_DelCalendarNote(s, Note); if (Priv->Manufacturer==AT_Ericsson) return SONYERIC_DelCalendarNote(s, Note); return ERR_NOTSUPPORTED; } + +GSM_Error ATGEN_GetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap) +{ + GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; + + if (Priv->Manufacturer==AT_Siemens) return SIEMENS_GetBitmap(s, Bitmap); + if (Priv->Manufacturer==AT_Samsung) return SAMSUNG_GetBitmap(s, Bitmap); + return ERR_NOTSUPPORTED; +} + +GSM_Error ATGEN_SetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap) +{ + GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; + + if (Priv->Manufacturer==AT_Siemens) return SIEMENS_SetBitmap(s, Bitmap); + if (Priv->Manufacturer==AT_Samsung) return SAMSUNG_SetBitmap(s, Bitmap); + return ERR_NOTSUPPORTED; +} + +GSM_Error ATGEN_GetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, bool PhoneRingtone) +{ + GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; + + if (Priv->Manufacturer==AT_Siemens) return SIEMENS_GetRingtone(s, Ringtone, PhoneRingtone); + if (Priv->Manufacturer==AT_Samsung) return SAMSUNG_GetRingtone(s, Ringtone, PhoneRingtone); + return ERR_NOTSUPPORTED; +} + +GSM_Error ATGEN_SetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, int *maxlength) +{ + GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; + + if (Priv->Manufacturer==AT_Siemens) return SIEMENS_SetRingtone(s, Ringtone, maxlength); + if (Priv->Manufacturer==AT_Samsung) return SAMSUNG_SetRingtone(s, Ringtone, maxlength); + return ERR_NOTSUPPORTED; +} + GSM_Error ATGEN_PressKey(GSM_StateMachine *s, GSM_KeyCode Key, bool Press) { GSM_Error error; unsigned char Frame[] = "AT+CKPD=\"?\"\r"; if (Press) { switch (Key) { case GSM_KEY_1 : Frame[9] = '1'; break; case GSM_KEY_2 : Frame[9] = '2'; break; case GSM_KEY_3 : Frame[9] = '3'; break; case GSM_KEY_4 : Frame[9] = '4'; break; case GSM_KEY_5 : Frame[9] = '5'; break; case GSM_KEY_6 : Frame[9] = '6'; break; case GSM_KEY_7 : Frame[9] = '7'; break; case GSM_KEY_8 : Frame[9] = '8'; break; case GSM_KEY_9 : Frame[9] = '9'; break; case GSM_KEY_0 : Frame[9] = '0'; break; case GSM_KEY_HASH : Frame[9] = '#'; break; case GSM_KEY_ASTERISK : Frame[9] = '*'; break; case GSM_KEY_POWER : return ERR_NOTSUPPORTED; case GSM_KEY_GREEN : Frame[9] = 'S'; break; case GSM_KEY_RED : Frame[9] = 'E'; break; case GSM_KEY_INCREASEVOLUME : Frame[9] = 'U'; break; case GSM_KEY_DECREASEVOLUME : Frame[9] = 'D'; break; case GSM_KEY_UP : Frame[9] = '^'; break; case GSM_KEY_DOWN : Frame[9] = 'V'; break; case GSM_KEY_MENU : Frame[9] = 'F'; break; case GSM_KEY_NAMES : Frame[9] = 'C'; break; default : return ERR_NOTSUPPORTED; } smprintf(s, "Pressing key\n"); error = GSM_WaitFor (s, Frame, 12, 0x00, 4, ID_PressKey); if (error != ERR_NONE) return error; /* Strange. My T310 needs it */ return GSM_WaitFor (s, "ATE1\r", 5, 0x00, 4, ID_EnableEcho); } else { return ERR_NONE; } } #ifdef GSM_ENABLE_CELLBROADCAST GSM_Error ATGEN_ReplyIncomingCB(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_CBMessage CB; int i,j; char Buffer[300],Buffer2[300]; smprintf(s, "CB received\n"); return ERR_NONE; DecodeHexBin (Buffer,msg.Buffer+6,msg.Length-6); DumpMessage(stdout, di.dl ,Buffer,msg.Length-6); CB.Channel = Buffer[4]; for (j=0;j<msg.Length;j++) { smprintf(s, "j=%i\n",j); i=GSM_UnpackEightBitsToSeven(0, msg.Buffer[6], msg.Buffer[6], msg.Buffer+j, Buffer2); // i = msg.Buffer[6] - 1; // while (i!=0) { // if (Buffer[i] == 13) i = i - 1; else break; // } DecodeDefault(CB.Text, Buffer2, msg.Buffer[6], false, NULL); smprintf(s, "Channel %i, text \"%s\"\n",CB.Channel,DecodeUnicodeString(CB.Text)); } if (s->Phone.Data.EnableIncomingCB && s->User.IncomingCB!=NULL) { s->User.IncomingCB(s->CurrentConfig->Device,CB); } return ERR_NONE; } #endif GSM_Error ATGEN_SetIncomingCB(GSM_StateMachine *s, bool enable) { #ifdef GSM_ENABLE_CELLBROADCAST if (s->Phone.Data.EnableIncomingCB!=enable) { s->Phone.Data.EnableIncomingCB = enable; if (enable) { smprintf(s, "Enabling incoming CB\n"); return GSM_WaitFor(s, "AT+CNMI=3,,2\r", 13, 0x00, 4, ID_SetIncomingCB); } else { smprintf(s, "Disabling incoming CB\n"); return GSM_WaitFor(s, "AT+CNMI=3,,0\r", 13, 0x00, 4, ID_SetIncomingCB); } } return ERR_NONE; #else return ERR_SOURCENOTAVAILABLE; #endif } +GSM_Error ATGEN_SetFastSMSSending(GSM_StateMachine *s, bool enable) +{ + if (enable) { + smprintf(s, "Enabling fast SMS sending\n"); + return GSM_WaitFor(s, "AT+CMMS=2\r", 10, 0x00, 4, ID_SetFastSMSSending); + } else { + smprintf(s, "Disabling fast SMS sending\n"); + return GSM_WaitFor(s, "AT+CMMS=0\r", 10, 0x00, 4, ID_SetFastSMSSending); + } +} + GSM_Error ATGEN_IncomingSMSInfo(GSM_Protocol_Message msg, GSM_StateMachine *s) { smprintf(s, "Incoming SMS\n"); return ERR_NONE; } GSM_Error ATGEN_IncomingSMSDeliver(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_Phone_Data *Data = &s->Phone.Data; GSM_SMSMessage sms; int current = 0, current2, i=0; unsigned char buffer[300],smsframe[800]; smprintf(s, "Incoming SMS received (Deliver)\n"); if (Data->EnableIncomingSMS && s->User.IncomingSMS!=NULL) { sms.State = SMS_UnRead; sms.InboxFolder = true; sms.PDU = SMS_Deliver; /* T310 with larger SMS goes crazy and mix this incoming * frame with normal answers. PDU is always last frame * We find its' number and parse it */ while (Data->Priv.ATGEN.Lines.numbers[i*2+1] != 0) { /* FIXME: handle special chars correctly */ i++; } DecodeHexBin (buffer, GetLineString(msg.Buffer,Data->Priv.ATGEN.Lines,i), strlen(GetLineString(msg.Buffer,Data->Priv.ATGEN.Lines,i))); /* We use locations from SMS layouts like in ../phone2.c(h) */ for(i=0;i<buffer[0]+1;i++) smsframe[i]=buffer[current++]; smsframe[12]=buffer[current++]; current2=((buffer[current])+1)/2+1; for(i=0;i<current2+1;i++) smsframe[PHONE_SMSDeliver.Number+i]=buffer[current++]; smsframe[PHONE_SMSDeliver.TPPID] = buffer[current++]; smsframe[PHONE_SMSDeliver.TPDCS] = buffer[current++]; for(i=0;i<7;i++) smsframe[PHONE_SMSDeliver.DateTime+i]=buffer[current++]; smsframe[PHONE_SMSDeliver.TPUDL] = buffer[current++]; for(i=0;i<smsframe[PHONE_SMSDeliver.TPUDL];i++) smsframe[i+PHONE_SMSDeliver.Text]=buffer[current++]; GSM_DecodeSMSFrame(&sms,smsframe,PHONE_SMSDeliver); s->User.IncomingSMS(s->CurrentConfig->Device,sms); } return ERR_NONE; } /* I don't have phone able to do it and can't fill it */ GSM_Error ATGEN_IncomingSMSReport(GSM_Protocol_Message msg, GSM_StateMachine *s) { smprintf(s, "Incoming SMS received (Report)\n"); return ERR_NONE; } GSM_Error ATGEN_SetIncomingSMS(GSM_StateMachine *s, bool enable) { /* Nokia returns OK, but doesn't return anything */ if (s->Phone.Data.Priv.ATGEN.Manufacturer == AT_Nokia) return ERR_NOTSUPPORTED; if (s->Phone.Data.EnableIncomingSMS!=enable) { s->Phone.Data.EnableIncomingSMS = enable; if (enable) { smprintf(s, "Enabling incoming SMS\n"); /* Delivery reports */ GSM_WaitFor(s, "AT+CNMI=3,,,1\r", 14, 0x00, 4, ID_SetIncomingSMS); /* SMS deliver */ return GSM_WaitFor(s, "AT+CNMI=3,3\r", 12, 0x00, 4, ID_SetIncomingSMS); } else { smprintf(s, "Disabling incoming SMS\n"); return GSM_WaitFor(s, "AT+CNMI=3,0\r", 12, 0x00, 4, ID_SetIncomingSMS); } } return ERR_NONE; } +GSM_Error ATGEN_GetLocale(GSM_StateMachine *s, GSM_Locale *locale) +{ + if (s->Phone.Data.Priv.ATGEN.Manufacturer==AT_Ericsson) return ERICSSON_GetLocale(s,locale); + return ERR_NOTSUPPORTED; +} + +GSM_Error ATGEN_SetLocale(GSM_StateMachine *s, GSM_Locale *locale) +{ + if (s->Phone.Data.Priv.ATGEN.Manufacturer==AT_Ericsson) return ERICSSON_SetLocale(s,locale); + return ERR_NOTSUPPORTED; +} + GSM_Reply_Function ATGENReplyFunctions[] = { {ATGEN_GenericReply, "AT\r" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_GenericReply, "ATE1" ,0x00,0x00,ID_EnableEcho }, {ATGEN_GenericReply, "AT+CMEE=" ,0x00,0x00,ID_EnableErrorInfo }, {ATGEN_GenericReply, "AT+CKPD=" ,0x00,0x00,ID_PressKey }, {ATGEN_ReplyGetSIMIMSI, "AT+CIMI" ,0x00,0x00,ID_GetSIMIMSI }, {ATGEN_GenericReply, "AT*EOBEX" ,0x00,0x00,ID_SetOBEX }, +{ERICSSON_ReplyGetDateLocale, "*ESDF:" ,0x00,0x00,ID_GetLocale }, +{ERICSSON_ReplyGetTimeLocale, "*ESTF:" ,0x00,0x00,ID_GetLocale }, +{ATGEN_GenericReply, "AT*ESDF=" ,0x00,0x00,ID_SetLocale }, +{ATGEN_GenericReply, "AT*ESTF=" ,0x00,0x00,ID_SetLocale }, + #ifdef GSM_ENABLE_CELLBROADCAST {ATGEN_ReplyIncomingCB, "+CBM:" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_GenericReply, "AT+CNMI" ,0x00,0x00,ID_SetIncomingCB }, #endif {ATGEN_IncomingBattery, "_OBS:" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_ReplyGetBatteryCharge, "AT+CBC" ,0x00,0x00,ID_GetBatteryCharge }, {ATGEN_ReplyGetModel, "AT+CGMM" ,0x00,0x00,ID_GetModel }, {ATGEN_ReplyGetManufacturer, "AT+CGMI" ,0x00,0x00,ID_GetManufacturer }, {ATGEN_ReplyGetFirmwareCGMR, "AT+CGMR" ,0x00,0x00,ID_GetFirmware }, {ATGEN_ReplyGetFirmwareATI, "ATI" ,0x00,0x00,ID_GetFirmware }, {ATGEN_ReplyGetIMEI, "AT+CGSN" ,0x00,0x00,ID_GetIMEI }, {ATGEN_ReplySendSMS, "AT+CMGS" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_ReplySendSMS, "AT+CMSS" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_GenericReply, "AT+CNMI" ,0x00,0x00,ID_SetIncomingSMS }, {ATGEN_GenericReply, "AT+CMGF" ,0x00,0x00,ID_GetSMSMode }, {ATGEN_GenericReply, "AT+CSDH" ,0x00,0x00,ID_GetSMSMode }, {ATGEN_ReplyGetSMSMessage, "AT+CMGR" ,0x00,0x00,ID_GetSMSMessage }, {ATGEN_GenericReply, "AT+CPMS" ,0x00,0x00,ID_SetMemoryType }, {ATGEN_ReplyGetSMSStatus, "AT+CPMS" ,0x00,0x00,ID_GetSMSStatus }, {ATGEN_ReplyGetSMSMemories, "AT+CPMS=?" ,0x00,0x00,ID_GetSMSMemories }, {ATGEN_ReplyAddSMSMessage, "AT+CMGW" ,0x00,0x00,ID_SaveSMSMessage }, {ATGEN_GenericReply, "AT+CSMP" ,0x00,0x00,ID_SetSMSParameters }, {ATGEN_GenericReply, "AT+CSCA" ,0x00,0x00,ID_SetSMSC }, {ATGEN_ReplyGetSMSC, "AT+CSCA?" ,0x00,0x00,ID_GetSMSC }, {ATGEN_ReplyDeleteSMSMessage, "AT+CMGD" ,0x00,0x00,ID_DeleteSMSMessage }, {ATGEN_GenericReply, "ATE1" ,0x00,0x00,ID_SetSMSParameters }, {ATGEN_GenericReply, "\x1b\x0D" ,0x00,0x00,ID_SetSMSParameters }, +{ATGEN_GenericReply, "AT+CMMS" ,0x00,0x00,ID_SetFastSMSSending }, {ATGEN_IncomingSMSInfo, "+CMTI:" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_IncomingSMSDeliver, "+CMT:" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_IncomingSMSReport, "+CDS:" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_IncomingSMSCInfo, "^SCN:" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_ReplyGetDateTime_Alarm, "AT+CCLK?" ,0x00,0x00,ID_GetDateTime }, {ATGEN_GenericReply, "AT+CCLK=" ,0x00,0x00,ID_SetDateTime }, +{ATGEN_GenericReply, "AT+CALA=" ,0x00,0x00,ID_SetAlarm }, {ATGEN_ReplyGetDateTime_Alarm, "AT+CALA?" ,0x00,0x00,ID_GetAlarm }, {ATGEN_ReplyGetNetworkLAC_CID, "AT+CREG?" ,0x00,0x00,ID_GetNetworkInfo }, {ATGEN_GenericReply, "AT+CREG=2" ,0x00,0x00,ID_GetNetworkInfo }, {ATGEN_GenericReply, "AT+COPS=" ,0x00,0x00,ID_GetNetworkInfo }, {ATGEN_GenericReply, "AT+COPS=" ,0x00,0x00,ID_SetAutoNetworkLogin}, {ATGEN_ReplyGetNetworkCode, "AT+COPS" ,0x00,0x00,ID_GetNetworkInfo }, {ATGEN_ReplyGetSignalQuality, "AT+CSQ" ,0x00,0x00,ID_GetSignalQuality }, {ATGEN_IncomingNetworkLevel, "_OSIGQ:" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_IncomingGPRS, "+CGREG:" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_ReplyGetNetworkLAC_CID, "+CREG:" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_ReplyGetPBKMemories, "AT+CPBS=?" ,0x00,0x00,ID_SetMemoryType }, {ATGEN_GenericReply, "AT+CPBS=" ,0x00,0x00,ID_SetMemoryType }, {ATGEN_ReplyGetCPBSMemoryStatus,"AT+CPBS?" ,0x00,0x00,ID_GetMemoryStatus }, +// /* Samsung phones reply +CPBR: after OK --claudio*/ {ATGEN_ReplyGetCPBRMemoryInfo, "AT+CPBR=?" ,0x00,0x00,ID_GetMemoryStatus }, +{ATGEN_ReplyGetCPBRMemoryInfo, "+CPBR:" ,0x00,0x00,ID_GetMemoryStatus }, {ATGEN_ReplyGetCPBRMemoryStatus,"AT+CPBR=" ,0x00,0x00,ID_GetMemoryStatus }, {ATGEN_GenericReply, "AT+CSCS=" ,0x00,0x00,ID_SetMemoryCharset }, {ATGEN_ReplyGetMemory, "AT+CPBR=" ,0x00,0x00,ID_GetMemory }, {ATGEN_GenericReply, "AT^SBNR=?" ,0x00,0x00,ID_GetMemory }, -{ATGEN_SL45ReplyGetMemory, "AT^SBNR" ,0x00,0x00,ID_GetMemory }, +{SIEMENS_ReplyGetMemory, "AT^SBNR" ,0x00,0x00,ID_GetMemory }, {ATGEN_ReplySetMemory, "AT+CPBW" ,0x00,0x00,ID_SetMemory }, -{ATGEN_CMS35ReplyGetBitmap, "AT^SBNR=\"bmp\"" ,0x00,0x00,ID_GetBitmap }, -{ATGEN_CMS35ReplySetBitmap, "AT^SBNW=\"bmp\"" ,0x00,0x00,ID_SetBitmap }, +{SIEMENS_ReplyGetBitmap, "AT^SBNR=\"bmp\"" ,0x00,0x00,ID_GetBitmap }, +{SIEMENS_ReplySetBitmap, "AT^SBNW=\"bmp\"" ,0x00,0x00,ID_SetBitmap }, -{ATGEN_CMS35ReplyGetRingtone, "AT^SBNR=\"mid\"" ,0x00,0x00,ID_GetRingtone }, -{ATGEN_CMS35ReplySetRingtone, "AT^SBNW=\"mid\"" ,0x00,0x00,ID_SetRingtone }, +{SIEMENS_ReplyGetRingtone, "AT^SBNR=\"mid\"" ,0x00,0x00,ID_GetRingtone }, +{SIEMENS_ReplySetRingtone, "AT^SBNW=\"mid\"" ,0x00,0x00,ID_SetRingtone }, -{ATGEN_CMS35ReplyGetNextCal, "AT^SBNR=\"vcs\"" ,0x00,0x00,ID_GetCalendarNote }, -{ATGEN_CMS35ReplySetCalendar, "AT^SBNW=\"vcs\"" ,0x00,0x00,ID_SetCalendarNote }, -{ATGEN_CMS35ReplyDeleteCalendar,"AT^SBNW=\"vcs\"" ,0x00,0x00,ID_DeleteCalendarNote }, +{SIEMENS_ReplyGetNextCalendar, "AT^SBNR=\"vcs\"" ,0x00,0x00,ID_GetCalendarNote }, +{SIEMENS_ReplyAddCalendarNote, "AT^SBNW=\"vcs\"" ,0x00,0x00,ID_SetCalendarNote }, +{SIEMENS_ReplyDelCalendarNote, "AT^SBNW=\"vcs\"" ,0x00,0x00,ID_DeleteCalendarNote }, {ATGEN_ReplyEnterSecurityCode, "AT+CPIN=" ,0x00,0x00,ID_EnterSecurityCode }, {ATGEN_ReplyEnterSecurityCode, "AT+CPIN2=" ,0x00,0x00,ID_EnterSecurityCode }, {ATGEN_ReplyGetSecurityStatus, "AT+CPIN?" ,0x00,0x00,ID_GetSecurityStatus }, {ATGEN_ReplyOK, "OK" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_GenericReply, "AT+VTS" ,0x00,0x00,ID_SendDTMF }, {ATGEN_ReplyCancelCall, "AT+CHUP" ,0x00,0x00,ID_CancelCall }, {ATGEN_ReplyDialVoice, "ATDT" ,0x00,0x00,ID_DialVoice }, {ATGEN_ReplyCancelCall, "ATH" ,0x00,0x00,ID_CancelCall }, +{ATGEN_GenericReply, "AT+CUSD" ,0x00,0x00,ID_SetUSSD }, +{ATGEN_ReplyGetUSSD, "+CUSD" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_GenericReply, "AT+CLIP=1" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_ReplyIncomingCallInfo, "+CLIP" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_ReplyIncomingCallInfo, "+COLP" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_ReplyIncomingCallInfo, "RING" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_ReplyIncomingCallInfo, "NO CARRIER" ,0x00,0x00,ID_IncomingFrame }, {ATGEN_ReplyReset, "AT^SRESET" ,0x00,0x00,ID_Reset }, {ATGEN_ReplyReset, "AT+CFUN=1,1" ,0x00,0x00,ID_Reset }, {ATGEN_ReplyResetPhoneSettings, "AT&F" ,0x00,0x00,ID_ResetPhoneSettings }, +{SAMSUNG_ReplyGetBitmap, "AT+IMGR=" ,0x00,0x00,ID_GetBitmap }, +{SAMSUNG_ReplySetBitmap, "SDNDCRC =" ,0x00,0x00,ID_SetBitmap }, + +{SAMSUNG_ReplyGetRingtone, "AT+MELR=" ,0x00,0x00,ID_GetRingtone }, +{SAMSUNG_ReplySetRingtone, "SDNDCRC =" ,0x00,0x00,ID_SetRingtone }, + #ifdef GSM_ENABLE_ALCATEL /* Why do I give Alcatel specific things here? It's simple, Alcatel needs * some AT commands to start it's binary mode, so this needs to be in AT * related stuff. * * XXX: AT+IFC could later move outside this ifdef, because it is not Alcatel * specific and it's part of ETSI specifications */ {ATGEN_GenericReply, "AT+IFC" ,0x00,0x00,ID_SetFlowControl }, {ALCATEL_ProtocolVersionReply, "AT+CPROT=?" ,0x00,0x00,ID_AlcatelProtocol }, {ATGEN_GenericReply, "AT+CPROT" ,0x00,0x00,ID_AlcatelConnect }, #endif {NULL, "\x00" ,0x00,0x00,ID_None } }; GSM_Phone_Functions ATGENPhone = { - "A2D|iPAQ|at|M20|S25|MC35|C35i|5110|5130|5190|5210|6110|6130|6150|6190|6210|6250|6310|6310i|6510|7110|8210|8250|8290|8310|8390|8850|8855|8890|8910|9110|9210", + "A2D|iPAQ|at|M20|S25|MC35|TC35|C35i|S300|5110|5130|5190|5210|6110|6130|6150|6190|6210|6250|6310|6310i|6510|7110|8210|8250|8290|8310|8390|8850|8855|8890|8910|9110|9210", ATGENReplyFunctions, ATGEN_Initialise, ATGEN_Terminate, ATGEN_DispatchMessage, NOTSUPPORTED, /* ShowStartInfo */ ATGEN_GetManufacturer, ATGEN_GetModel, ATGEN_GetFirmware, ATGEN_GetIMEI, NOTSUPPORTED, /* GetOriginalIMEI */ NOTSUPPORTED, /* GetManufactureMonth */ NOTSUPPORTED, /* GetProductCode */ NOTSUPPORTED, /* GetHardware */ NOTSUPPORTED, /* GetPPM */ ATGEN_GetSIMIMSI, ATGEN_GetDateTime, ATGEN_SetDateTime, ATGEN_GetAlarm, - NOTIMPLEMENTED, /* SetAlarm */ - NOTSUPPORTED, /* GetLocale */ - NOTSUPPORTED, /* SetLocale */ + ATGEN_SetAlarm, + ATGEN_GetLocale, + ATGEN_SetLocale, ATGEN_PressKey, ATGEN_Reset, ATGEN_ResetPhoneSettings, ATGEN_EnterSecurityCode, ATGEN_GetSecurityStatus, ATGEN_GetDisplayStatus, ATGEN_SetAutoNetworkLogin, ATGEN_GetBatteryCharge, ATGEN_GetSignalQuality, ATGEN_GetNetworkInfo, NOTSUPPORTED, /* GetCategory */ NOTSUPPORTED, /* AddCategory */ NOTSUPPORTED, /* GetCategoryStatus */ ATGEN_GetMemoryStatus, ATGEN_GetMemory, ATGEN_GetNextMemory, ATGEN_SetMemory, ATGEN_AddMemory, ATGEN_DeleteMemory, ATGEN_DeleteAllMemory, NOTSUPPORTED, /* GetSpeedDial */ NOTSUPPORTED, /* SetSpeedDial */ ATGEN_GetSMSC, ATGEN_SetSMSC, ATGEN_GetSMSStatus, ATGEN_GetSMS, ATGEN_GetNextSMS, NOTSUPPORTED, /* SetSMS */ ATGEN_AddSMS, ATGEN_DeleteSMS, ATGEN_SendSMS, ATGEN_SendSavedSMS, + ATGEN_SetFastSMSSending, ATGEN_SetIncomingSMS, ATGEN_SetIncomingCB, ATGEN_GetSMSFolders, NOTSUPPORTED, /* AddSMSFolder */ NOTSUPPORTED, /* DeleteSMSFolder */ ATGEN_DialVoice, ATGEN_AnswerCall, ATGEN_CancelCall, NOTSUPPORTED, /* HoldCall */ NOTSUPPORTED, /* UnholdCall */ NOTSUPPORTED, /* ConferenceCall */ NOTSUPPORTED, /* SplitCall */ NOTSUPPORTED, /* TransferCall */ NOTSUPPORTED, /* SwitchCall */ NOTSUPPORTED, /* GetCallDivert */ NOTSUPPORTED, /* SetCallDivert */ NOTSUPPORTED, /* CancelAllDiverts */ NONEFUNCTION, /* SetIncomingCall */ - NOTSUPPORTED, /* SetIncomingUSSD */ + ATGEN_SetIncomingUSSD, ATGEN_SendDTMF, ATGEN_GetRingtone, ATGEN_SetRingtone, NOTSUPPORTED, /* GetRingtonesInfo */ NOTSUPPORTED, /* DeleteUserRingtones */ NOTSUPPORTED, /* PlayTone */ NOTSUPPORTED, /* GetWAPBookmark */ NOTSUPPORTED, /* SetWAPBookmark */ NOTSUPPORTED, /* DeleteWAPBookmark */ NOTSUPPORTED, /* GetWAPSettings */ NOTSUPPORTED, /* SetWAPSettings */ NOTSUPPORTED, /* GetMMSSettings */ NOTSUPPORTED, /* SetMMSSettings */ NOTSUPPORTED, /* GetSyncMLSettings */ NOTSUPPORTED, /* SetSyncMLSettings */ NOTSUPPORTED, /* GetChatSettings */ NOTSUPPORTED, /* SetChatSettings */ ATGEN_GetBitmap, /* GetBitmap */ ATGEN_SetBitmap, /* SetBitmap */ SONYERIC_GetToDoStatus, NOTSUPPORTED, /* GetToDo */ SONYERIC_GetNextToDo, NOTSUPPORTED, /* SetToDo */ SONYERIC_AddToDo, NOTSUPPORTED, /* DeleteToDo */ SONYERIC_DeleteAllToDo, SONYERIC_GetCalendarStatus, NOTIMPLEMENTED, /* GetCalendar */ ATGEN_GetNextCalendar, NOTIMPLEMENTED, /* SetCalendar */ ATGEN_AddCalendarNote, ATGEN_DelCalendarNote, NOTIMPLEMENTED, /* DeleteAllCalendar */ NOTSUPPORTED, /* GetCalendarSettings */ NOTSUPPORTED, /* SetCalendarSettings */ - NOTSUPPORTED, /* GetNote */ + NOTSUPPORTED, /* GetNextNote */ NOTSUPPORTED, /* GetProfile */ NOTSUPPORTED, /* SetProfile */ NOTSUPPORTED, /* GetFMStation */ NOTSUPPORTED, /* SetFMStation */ NOTSUPPORTED, /* ClearFMStations */ NOTSUPPORTED, /* GetNextFileFolder */ NOTSUPPORTED, /* GetFilePart */ NOTSUPPORTED, /* AddFile */ NOTSUPPORTED, /* GetFileSystemStatus */ NOTSUPPORTED, /* DeleteFile */ NOTSUPPORTED, /* AddFolder */ NOTSUPPORTED, /* GetGPRSAccessPoint */ NOTSUPPORTED /* SetGPRSAccessPoint */ }; #endif /* How should editor hadle tabs in this file? Add editor commands here. * vim: noexpandtab sw=8 ts=8 sts=8: */ diff --git a/gammu/emb/common/phone/at/atgen.h b/gammu/emb/common/phone/at/atgen.h index 0e08ee4..bb5c559 100644 --- a/gammu/emb/common/phone/at/atgen.h +++ b/gammu/emb/common/phone/at/atgen.h @@ -1,110 +1,116 @@ /* (c) 2002-2004 by Marcin Wiacek and Michal Cihar */ #ifndef atgen_h #define atgen_h #include "../../gsmcomon.h" #include "../../gsmstate.h" #include "../../service/sms/gsmsms.h" #ifndef GSM_USED_AT # define GSM_USED_AT #endif #ifndef GSM_USED_BLUEAT # define GSM_USED_BLUEAT #endif #ifndef GSM_USED_IRDAAT # define GSM_USED_IRDAAT #endif #define MAX_VCALENDAR_LOCATION 50 typedef enum { SMS_AT_PDU = 1, SMS_AT_TXT } GSM_AT_SMS_Modes; typedef enum { AT_Reply_OK = 1, AT_Reply_Connect, AT_Reply_Error, AT_Reply_Unknown, AT_Reply_CMSError, AT_Reply_CMEError, AT_Reply_SMSEdit } GSM_AT_Reply_State; typedef enum { AT_Nokia = 1, AT_Alcatel, AT_Siemens, AT_HP, AT_Falcom, AT_Ericsson, AT_Sagem, + AT_Samsung, AT_Unknown } GSM_AT_Manufacturer; typedef enum { AT_PBK_HEX = 1, AT_PBK_GSM, - AT_PBK_UCS2 + AT_PBK_UCS2, + AT_PBK_PCCP437 } GSM_AT_PBK_Charset; typedef enum { AT_AVAILABLE = 1, AT_NOTAVAILABLE } GSM_AT_SMSMemory; typedef enum { AT_SBNR_AVAILABLE = 1, AT_SBNR_NOTAVAILABLE } GSM_AT_SBNR; typedef enum { AT_Status, AT_NextEmpty, AT_Total, AT_First, AT_Sizes } GSM_AT_NeededMemoryInfo; #define AT_PBK_MAX_MEMORIES 200 typedef struct { GSM_AT_Manufacturer Manufacturer; /* Who is manufacturer */ GSM_Lines Lines; /* Allow to simply get each line in response */ GSM_AT_Reply_State ReplyState; /* What response type - error, OK, etc. */ int ErrorCode; /* Error codes from responses */ char *ErrorText; /* Error description */ GSM_MemoryType PBKMemory; /* Last read PBK memory */ char PBKMemories[AT_PBK_MAX_MEMORIES + 1]; /* Supported by phone PBK memories */ int NextMemoryEntry; /* Next empty memory entry */ int FirstMemoryEntry; /* First memory entry to be read */ GSM_AT_PBK_Charset PBKCharset; /* Last read PBK charset */ bool UCS2CharsetFailed; /* Whether setting of UCS2 charset has already failed */ bool NonUCS2CharsetFailed; /* Whether setting of non-UCS2 charset has already failed */ GSM_AT_SBNR PBKSBNR; int NumberLength; int TextLength; int MemorySize; GSM_SMSMemoryStatus LastSMSStatus; int LastSMSRead; int FirstCalendarPos; bool CanSaveSMS; GSM_AT_SMSMemory PhoneSMSMemory; /* Is phone SMS memory available ? */ GSM_AT_SMSMemory SIMSMSMemory; /* Is SIM SMS memory available ? */ GSM_MemoryType SMSMemory; /* Last read SMS memory */ GSM_AT_SMS_Modes SMSMode; /* PDU or TEXT mode for SMS ? */ bool OBEX; GSM_File file; } GSM_Phone_ATGENData; +GSM_Error ATGEN_HandleCMSError (GSM_StateMachine *); +GSM_Error ATGEN_HandleCMEError (GSM_StateMachine *); +GSM_Error ATGEN_DispatchMessage (GSM_StateMachine *); + #endif /* How should editor hadle tabs in this file? Add editor commands here. * vim: noexpandtab sw=8 ts=8 sts=8: */ diff --git a/gammu/emb/common/phone/at/samsung.c b/gammu/emb/common/phone/at/samsung.c new file mode 100644 index 0000000..55a42e5 --- a/dev/null +++ b/gammu/emb/common/phone/at/samsung.c @@ -0,0 +1,447 @@ +/* Samsung-specific functions + * Copyright (C) 2004 Claudio Matsuoka <cmatsuoka@gmail.com> + * Tested with S300 only! + */ + +#include "../../gsmstate.h" + +#ifdef GSM_ENABLE_ATGEN + +#include <string.h> +#include <time.h> +#include <ctype.h> + +#include "../../misc/coding/coding.h" +#include "../../gsmcomon.h" +#include "../../service/sms/gsmsms.h" +#include "../pfunc.h" + +#include "atgen.h" +#include "samsung.h" + +/* Binary frame size */ +#define BLKSZ 1024 + +struct ModelRes { + char *model; + int width; + int height; +}; + +static struct ModelRes modres[] = { + { "S100", 128, 128 }, + { "S200", 128, 113 }, + { "S300", 128, 97 }, + { "S500", 128, 128 }, + { "T100", 128, 128 }, + { "E700", 128, 128 }, + { NULL, 0, 0 } +}; + +/* + * CRC functions from the Granch SBNI12 Linux driver by + * Denis I. Timofeev <timofeev@granch.ru> + */ +static unsigned int crc32tab[] = { + 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, + 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, + 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, + 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, + 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, + 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, + 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, + 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, + 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, + 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, + 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, + 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, + 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, + 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, + 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, + 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, + 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, + 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, + 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, + 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, + 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, + 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, + 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, + 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, + 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, + 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, + 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, + 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, + 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, + 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, + 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, + 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, + 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, + 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, + 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, + 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, + 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, + 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, + 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, + 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, + 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, + 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, + 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, + 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, + 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, + 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, + 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, + 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, + 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, + 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, + 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, + 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, + 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, + 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, + 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, + 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, + 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, + 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, + 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, + 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, + 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, + 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, + 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, + 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 +}; + +static unsigned int GetCRC(char *data, int size) +{ + unsigned int crc = 0; + + while (size--) + crc = crc32tab[(crc ^ *data++) & 0xff] ^ ((crc >> 8) & 0x00FFFFFF); + + return crc; +} + +/* + * Frame transfer + */ + +static GSM_Error WaitFor(GSM_StateMachine *s, char *t, int ttl) +{ + char readbuf[100]; + int n; + unsigned int sec; + GSM_DateTime Date; + + GSM_GetCurrentDateTime (&Date); + sec = Date.Second; + + n = s->Device.Functions->ReadDevice(s, readbuf, 80); + readbuf[n] = 0; + while (strstr(readbuf, t) == NULL && (sec + ttl) >= Date.Second) { + my_sleep(5000); + n = s->Device.Functions->ReadDevice(s, readbuf, 80); + readbuf[n] = 0; + GSM_GetCurrentDateTime (&Date); + } + + return (sec + ttl) >= Date.Second ? ERR_NONE : ERR_TIMEOUT; +} + +static GSM_Error SetSamsungFrame(GSM_StateMachine *s, unsigned char *buff, int size, GSM_Phone_RequestID id) +{ + GSM_Phone_Data *Phone = &s->Phone.Data; + GSM_Error error; + int i, count; + + count = size / BLKSZ; + + for (i = 0; i < count; i++) { + error = WaitFor(s, ">", 4); + if (error!=ERR_NONE) return error; + + error = s->Protocol.Functions->WriteMessage(s, + buff + i * BLKSZ, BLKSZ, 0x00); + if (error!=ERR_NONE) return error; + } + + error = WaitFor(s, ">", 4); + if (error!=ERR_NONE) return error; + error = s->Protocol.Functions->WriteMessage(s, + buff + i * BLKSZ, size%BLKSZ, 0x00); + if (error!=ERR_NONE) return error; + + error = GSM_WaitFor(s, "", 0, 0x00, 4, id); + if (error!=ERR_NONE) return error; + + return Phone->DispatchError; +} + +/* Answer format for binary data transfer + * + * SDNDCRC = 0xa : RECEIVECRC = 0xcbf53a1c : BINSIZE = 5 + * CRCERR + */ +static GSM_Error ReplySetSamsungFrame(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + unsigned long txcrc, rxcrc; + int binsize; + char *pos; + + /* Parse SDNDCRC */ + pos = strchr(msg.Buffer, '='); + if (!pos) return ERR_UNKNOWN; + pos++; + txcrc = strtoul(pos, NULL, 0); + smprintf(s, "Sent CRC : 0x%lx\n", txcrc); + + /* Parse RECEIVECRC */ + pos = strchr(pos, '='); + if (!pos) return ERR_UNKNOWN; + pos++; + rxcrc = strtoul(pos, NULL, 0); + smprintf(s, "Reveived CRC : 0x%lx\n", rxcrc); + + /* Parse BINSIZE */ + pos = strchr(pos, '='); + if (!pos) return ERR_UNKNOWN; + pos++; + binsize = strtoul(pos, NULL, 0); + smprintf(s, "Binary size : %d\n", binsize); + + return txcrc == rxcrc ? ERR_NONE : ERR_WRONGCRC; +} + +/* + * Bitmaps + */ + +GSM_Error SAMSUNG_ReplyGetBitmap(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; + unsigned char buffer[32]; + char *pos; + int location, count; + + switch (Priv->ReplyState) { + case AT_Reply_OK: + smprintf(s, "Bitmap info received\n"); + /* Parse +IMGR:location,name,0,0,0,0 */ + + /* Parse location */ + pos = strchr(msg.Buffer, ':'); + if (!pos) return ERR_UNKNOWN; + pos++; + location = atoi(pos); + smprintf(s, "Location : %d\n", location); + + /* Parse name */ + pos = strchr(pos, '"'); + if (!pos) return ERR_UNKNOWN; + pos++; + for (count = 0; count < 31; count++) { + if (pos[count] == '"') + break; + buffer[count] = pos[count]; + } + buffer[count] = 0; + smprintf(s, "Name : %s\n", buffer); + s->Phone.Data.Bitmap->Name = malloc((strlen(buffer) + 1) * 2); + if (s->Phone.Data.Bitmap->Name == NULL) + return ERR_MOREMEMORY; + EncodeUnicode(s->Phone.Data.Bitmap->Name, buffer, strlen(buffer)); + + s->Phone.Data.Bitmap->Location = location; + + return ERR_NONE; + case AT_Reply_Error: + return ERR_UNKNOWN; + case AT_Reply_CMSError: + return ATGEN_HandleCMSError(s); + case AT_Reply_CMEError: + return ATGEN_HandleCMEError(s); + default: + return ERR_UNKNOWNRESPONSE; + } +} + +GSM_Error SAMSUNG_ReplySetBitmap(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + smprintf(s, "Bitmap sent\n"); + return ReplySetSamsungFrame(msg, s); +} + +GSM_Error SAMSUNG_GetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap) +{ + unsigned char req[100]; + + s->Phone.Data.Bitmap=Bitmap; + smprintf(s, "Getting bitmap\n"); + sprintf(req, "AT+IMGR=%d\r", Bitmap->Location-1); + return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetBitmap); +} + +GSM_Error SAMSUNG_SetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap) +{ + unsigned char req[100]; + unsigned long crc; + GSM_Error error; + char name[50], *dot, *model; + GSM_Phone_Data *Data = &s->Phone.Data; + int i; + + s->Phone.Data.Bitmap = Bitmap; + smprintf(s, "Setting bitmap\n"); + + if (Bitmap->Type != GSM_PictureBinary) { + smprintf(s, "Invalid picture type\n"); + return ERR_INVALIDDATA; + } + + if (Bitmap->BinaryPic.Type != PICTURE_GIF) { + smprintf(s, "Invalid binary picture type\n"); + return ERR_INVALIDDATA; + } + + /* Check if picture size matches phone model */ + model = GetModelData(NULL,Data->Model,NULL)->model; + smprintf(s, "Checking picture size for %s\n", model); + for (i = 0; modres[i].model; i++) { + if (!strcmp(model, modres[i].model)) { + if (Bitmap->BitmapWidth != modres[i].width || + Bitmap->BitmapHeight != modres[i].height) { + smprintf(s, "Model %s must use %d x %d picture size\n", + modres[i].model, modres[i].width, + modres[i].height); + return ERR_INVALIDDATA; + } + break; + } + } + if (modres[i].model == NULL) { + smprintf(s, "Model \"%s\" is not supported.\n", Data->Model); + return ERR_NOTSUPPORTED; + } + + crc = GetCRC(Bitmap->BinaryPic.Buffer, Bitmap->BinaryPic.Length); + + /* Remove extension from file name */ + strncpy(name, DecodeUnicodeString(Bitmap->Name), 50); + if ((dot = strrchr(name, '.')) != NULL) + *dot = 0; + + sprintf(req, "AT+IMGW=0,\"%s\",2,0,0,0,0,100,%d,%u\r", name, + Bitmap->BinaryPic.Length, (unsigned int)crc); + + error = s->Protocol.Functions->WriteMessage(s, req, strlen(req), 0x00); + if (error!=ERR_NONE) return error; + + return SetSamsungFrame(s, Bitmap->BinaryPic.Buffer, + Bitmap->BinaryPic.Length, ID_SetBitmap); +} + +/* + * Ringtones + */ + +GSM_Error SAMSUNG_ReplyGetRingtone(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; + unsigned char buffer[32]; + char *pos; + int location, length, count; + + switch (Priv->ReplyState) { + case AT_Reply_OK: + smprintf(s, "Ringtone info received\n"); + /* Parse +MELR:location,name,size */ + + /* Parse location */ + pos = strchr(msg.Buffer, ':'); + if (!pos) return ERR_UNKNOWN; + pos++; + location = atoi(pos); + smprintf(s, "Location : %d\n", location); + + /* Parse name */ + pos = strchr(pos, '"'); + if (!pos) return ERR_UNKNOWN; + pos++; + /* Ringtone.Name size is 20 chars */ + for (count = 0; count < 19; count++) { + if (pos[count] == '"') + break; + buffer[count] = pos[count]; + } + buffer[count] = 0; + smprintf(s, "Name : %s\n", buffer); + EncodeUnicode(s->Phone.Data.Ringtone->Name,buffer,strlen(buffer)); + + /* Parse ringtone length */ + pos = strchr(pos, ','); + if (!pos) return ERR_UNKNOWN; + pos++; + length = atoi(pos); + smprintf(s, "Length : %d\n", length); + + /* S300 ringtones are always MMF */ + s->Phone.Data.Ringtone->Format = RING_MMF; + s->Phone.Data.Ringtone->Location = location; + s->Phone.Data.Ringtone->BinaryTone.Length = length; + + return ERR_NONE; + case AT_Reply_Error: + return ERR_UNKNOWN; + case AT_Reply_CMSError: + return ATGEN_HandleCMSError(s); + case AT_Reply_CMEError: + return ATGEN_HandleCMEError(s); + default: + return ERR_UNKNOWNRESPONSE; + } +} + +GSM_Error SAMSUNG_GetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, bool PhoneRingtone) +{ + unsigned char req[100]; + + s->Phone.Data.Ringtone = Ringtone; + smprintf(s, "Getting ringtone\n"); + sprintf(req, "AT+MELR=%d\r", Ringtone->Location-1); + return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetRingtone); +} + +GSM_Error SAMSUNG_ReplySetRingtone(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + smprintf(s, "Ringtone sent\n"); + return ReplySetSamsungFrame(msg, s); +} + +GSM_Error SAMSUNG_SetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, int *maxlength) +{ + unsigned char req[100]; + unsigned long crc; + GSM_Error error; + char name[50], *dot; + + s->Phone.Data.Ringtone = Ringtone; + smprintf(s, "Setting ringtone\n"); + + if (Ringtone->Format != RING_MMF) { + smprintf(s, "Not MMF ringtone\n"); + return ERR_INVALIDDATA; + } + + /* Remove extension from file name */ + strncpy(name, DecodeUnicodeString(Ringtone->Name), 50); + if ((dot = strrchr(name, '.')) != NULL) *dot = 0; + + crc = GetCRC(Ringtone->BinaryTone.Buffer, Ringtone->BinaryTone.Length); + sprintf(req, "AT+MELW=0,\"%s\",4,%d,%u\r", name, + Ringtone->BinaryTone.Length, (unsigned int)crc); + + error = s->Protocol.Functions->WriteMessage(s, req, strlen(req), 0x00); + if (error!=ERR_NONE) return error; + + return SetSamsungFrame(s, Ringtone->BinaryTone.Buffer, + Ringtone->BinaryTone.Length, ID_SetRingtone); +} + +#endif diff --git a/gammu/emb/common/phone/at/samsung.h b/gammu/emb/common/phone/at/samsung.h new file mode 100644 index 0000000..3b2947c --- a/dev/null +++ b/gammu/emb/common/phone/at/samsung.h @@ -0,0 +1,16 @@ +#ifndef samsung_h +#define samsung_h + +#include "../../gsmstate.h" + +GSM_Error SAMSUNG_ReplyGetRingtone (GSM_Protocol_Message, GSM_StateMachine *); +GSM_Error SAMSUNG_ReplySetRingtone (GSM_Protocol_Message, GSM_StateMachine *); +GSM_Error SAMSUNG_ReplyGetBitmap (GSM_Protocol_Message, GSM_StateMachine *); +GSM_Error SAMSUNG_ReplySetBitmap (GSM_Protocol_Message, GSM_StateMachine *); +GSM_Error SAMSUNG_GetRingtone (GSM_StateMachine *, GSM_Ringtone *, bool); +GSM_Error SAMSUNG_SetRingtone (GSM_StateMachine *, GSM_Ringtone *, int *); +GSM_Error SAMSUNG_GetBitmap (GSM_StateMachine *, GSM_Bitmap *); +GSM_Error SAMSUNG_SetBitmap (GSM_StateMachine *, GSM_Bitmap *); +GSM_Error SAMSUNG_GetCallLogs (GSM_StateMachine *, GSM_MemoryEntry *, int); + +#endif diff --git a/gammu/emb/common/phone/at/siemens.c b/gammu/emb/common/phone/at/siemens.c index ab7dd2c..7f66cf8 100644 --- a/gammu/emb/common/phone/at/siemens.c +++ b/gammu/emb/common/phone/at/siemens.c @@ -1,320 +1,316 @@ /* (c) 2002-2003 by Walek */ #include "../../gsmstate.h" #ifdef GSM_ENABLE_ATGEN #include <string.h> #include <time.h> #include <ctype.h> #include "../../misc/coding/coding.h" #include "../../gsmcomon.h" #include "../../service/sms/gsmsms.h" #include "../pfunc.h" -extern GSM_Error ATGEN_HandleCMSError(GSM_StateMachine *s); +#include "atgen.h" +#include "siemens.h" -GSM_Error ATGEN_CMS35ReplySetFunction (GSM_Protocol_Message msg, GSM_StateMachine *s,char *function) -{ - if (s->Protocol.Data.AT.EditMode) { - s->Protocol.Data.AT.EditMode = false; - return ERR_NONE; - } - dbgprintf ("Written %s",function); - if (s->Phone.Data.Priv.ATGEN.ReplyState == AT_Reply_OK){ - dbgprintf (" - OK\n"); - return ERR_NONE; - } else { - dbgprintf (" - error\n"); - return ERR_UNKNOWN; - } -} -GSM_Error GetSiemensFrame(GSM_Protocol_Message msg, GSM_StateMachine *s, char *templ, +static GSM_Error GetSiemensFrame(GSM_Protocol_Message msg, GSM_StateMachine *s, char *templ, unsigned char *buffer, int *len) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; int i=2, pos=0, length=0; unsigned char buf[512]; if (strstr(GetLineString(msg.Buffer,Priv->Lines,2),"OK")) return ERR_EMPTY; if (!strstr(GetLineString(msg.Buffer,Priv->Lines,2),templ)) return ERR_UNKNOWN; while (1) { if (Priv->Lines.numbers[i*2+1]==0) break; if ((!strstr(GetLineString(msg.Buffer,Priv->Lines,i+1),templ)) && (strstr(GetLineString(msg.Buffer,Priv->Lines,i),templ))){ length = strlen(GetLineString(msg.Buffer,Priv->Lines,i+1)); DecodeHexBin(buf, GetLineString(msg.Buffer,Priv->Lines,i+1),length); length = length/2; memcpy (buffer+pos,buf,length); pos+=length; } i++; } *len = pos; return ERR_NONE; } -GSM_Error SetSiemensFrame (GSM_StateMachine *s, unsigned char *buff, char *templ, +static GSM_Error SetSiemensFrame (GSM_StateMachine *s, unsigned char *buff, char *templ, int Location, GSM_Phone_RequestID RequestID, int len) { GSM_Phone_Data *Phone = &s->Phone.Data; GSM_Error error; unsigned char req[20],req1[512],hexreq[2096]; int MaxFrame,CurrentFrame,size,sz,pos=0; EncodeHexBin(hexreq,buff,len); size = len * 2; MaxFrame = size / 352; if (size % 352) MaxFrame++; for (CurrentFrame=0;CurrentFrame<MaxFrame;CurrentFrame++) { pos=CurrentFrame*352; if (pos+352 < size) sz = 352; else sz = size - pos; sprintf(req, "AT^SBNW=\"%s\",%i,%i,%i\r",templ,Location,CurrentFrame+1,MaxFrame); s->Protocol.Data.AT.EditMode = true; error = GSM_WaitFor (s, req, strlen(req), 0x00, 3, RequestID); s->Phone.Data.DispatchError=ERR_TIMEOUT; s->Phone.Data.RequestID=RequestID; if (error!=ERR_NONE) return error; memcpy (req1,hexreq+pos,sz); error = s->Protocol.Functions->WriteMessage(s, req1, sz, 0x00); if (error!=ERR_NONE) return error; error = s->Protocol.Functions->WriteMessage(s,"\x1A", 1, 0x00); if (error!=ERR_NONE) return error; error = GSM_WaitForOnce(s, NULL, 0x00, 0x00, 4); if (error == ERR_TIMEOUT) return error; } return Phone->DispatchError; } -GSM_Error ATGEN_CMS35ReplyGetBitmap(GSM_Protocol_Message msg, GSM_StateMachine *s) +GSM_Error SIEMENS_ReplyGetBitmap(GSM_Protocol_Message msg, GSM_StateMachine *s) { unsigned char buffer[4096]; int length; GSM_Error error; error = GetSiemensFrame(msg,s,"bmp",buffer,&length); if (error!=ERR_NONE) return error; dbgprintf ("Operator logo received lenght=%i\n",length); error = BMP2Bitmap (buffer,NULL,s->Phone.Data.Bitmap); if (error==ERR_NONE) return error; else return ERR_UNKNOWN; } -GSM_Error ATGEN_CMS35ReplySetBitmap(GSM_Protocol_Message msg, GSM_StateMachine *s) +GSM_Error SIEMENS_ReplySetFunction (GSM_Protocol_Message msg, GSM_StateMachine *s,char *function) { - return ATGEN_CMS35ReplySetFunction (msg, s, "Operator Logo");
+ if (s->Protocol.Data.AT.EditMode) { + s->Protocol.Data.AT.EditMode = false; + return ERR_NONE; + } + dbgprintf ("Written %s",function); + if (s->Phone.Data.Priv.ATGEN.ReplyState == AT_Reply_OK){ + dbgprintf (" - OK\n"); + return ERR_NONE; + } else { + dbgprintf (" - error\n"); + return ERR_UNKNOWN; + } } -GSM_Error ATGEN_GetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap) +GSM_Error SIEMENS_ReplySetBitmap(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + return SIEMENS_ReplySetFunction (msg, s, "Operator Logo");
+} + +GSM_Error SIEMENS_GetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap) { unsigned char req[32]; - if (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED; if (Bitmap->Type!=GSM_OperatorLogo) return ERR_NOTSUPPORTED; if (Bitmap->Location-1 < 0) Bitmap->Location++; s->Phone.Data.Bitmap=Bitmap; sprintf(req, "AT^SBNR=\"bmp\",%i\r", Bitmap->Location-1); smprintf(s, "Getting Bitmap\n"); return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetBitmap); } -GSM_Error ATGEN_SetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap) +GSM_Error SIEMENS_SetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap) { unsigned char buffer[4096]; int length; GSM_Error error; - if (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED; if (Bitmap->Type!=GSM_OperatorLogo) return ERR_NOTSUPPORTED; error = Bitmap2BMP (buffer,NULL,Bitmap); if (error!=ERR_NONE) return error; length = 0x100 * buffer[3] + buffer[2]; buffer[58]=0xff; buffer[59]=0xff; buffer[60]=0xff; if (Bitmap->Location-1 < 0) Bitmap->Location++; s->Phone.Data.Bitmap=Bitmap; return SetSiemensFrame(s, buffer,"bmp",Bitmap->Location-1, ID_SetBitmap,length); } -GSM_Error ATGEN_CMS35ReplyGetRingtone(GSM_Protocol_Message msg, GSM_StateMachine *s) +GSM_Error SIEMENS_ReplyGetRingtone(GSM_Protocol_Message msg, GSM_StateMachine *s) { unsigned char buffer[32]; int length; GSM_Error error; error = GetSiemensFrame(msg,s,"mid",s->Phone.Data.Ringtone->NokiaBinary.Frame,&length); if (error!=ERR_NONE) return error; dbgprintf ("Midi ringtone received\n"); s->Phone.Data.Ringtone->Format = RING_MIDI; s->Phone.Data.Ringtone->NokiaBinary.Length = length; sprintf(buffer,"Individual"); EncodeUnicode (s->Phone.Data.Ringtone->Name,buffer,strlen(buffer)); return ERR_NONE; } -GSM_Error ATGEN_GetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, bool PhoneRingtone) +GSM_Error SIEMENS_GetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, bool PhoneRingtone) { unsigned char req[32]; - if (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED; - s->Phone.Data.Ringtone=Ringtone; sprintf(req, "AT^SBNR=\"mid\",%i\r", Ringtone->Location-1); smprintf(s, "Getting RingTone\n"); return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetRingtone); } -GSM_Error ATGEN_CMS35ReplySetRingtone(GSM_Protocol_Message msg, GSM_StateMachine *s) +GSM_Error SIEMENS_ReplySetRingtone(GSM_Protocol_Message msg, GSM_StateMachine *s) { - return ATGEN_CMS35ReplySetFunction (msg, s, "Ringtone"); + return SIEMENS_ReplySetFunction (msg, s, "Ringtone"); } -GSM_Error ATGEN_SetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, int *maxlength) +GSM_Error SIEMENS_SetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, int *maxlength) { GSM_Phone_Data *Phone = &s->Phone.Data; - if (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED; - if (Ringtone->Location==255) Ringtone->Location=1; if (Ringtone->Location-1 > 1) return ERR_INVALIDLOCATION; s->Phone.Data.Ringtone = Ringtone; Phone->Ringtone = Ringtone; return SetSiemensFrame(s, Ringtone->NokiaBinary.Frame,"mid",Ringtone->Location-1, ID_SetRingtone,Ringtone->NokiaBinary.Length); } -GSM_Error ATGEN_CMS35ReplyGetNextCal(GSM_Protocol_Message msg, GSM_StateMachine *s) +GSM_Error SIEMENS_ReplyGetNextCalendar(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_Phone_Data *Data = &s->Phone.Data; GSM_CalendarEntry *Calendar = Data->Cal; GSM_ToDoEntry ToDo; GSM_Error error; unsigned char buffer[354]; int len, pos=0; if (Data->Priv.ATGEN.ReplyState != AT_Reply_OK) return ERR_UNKNOWN; error = GetSiemensFrame(msg,s,"vcs",buffer,&len); if (error!=ERR_NONE) return error; error=GSM_DecodeVCALENDAR_VTODO(buffer,&pos,Calendar,&ToDo,Siemens_VCalendar,0); return error; } GSM_Error SIEMENS_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_Error error; unsigned char req[32]; int Location; if (Priv->Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED; if (start) Note->Location=Priv->FirstCalendarPos; s->Phone.Data.Cal = Note; Note->EntriesNum = 0; smprintf(s, "Getting VCALENDAR\n"); Location = Note->Location; while (1){ Location++; sprintf(req, "AT^SBNR=\"vcs\",%i\r",Location); error = GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetCalendarNote); if ((error!=ERR_NONE) && (error!=ERR_EMPTY)) return ERR_INVALIDLOCATION; Note->Location = Location; Priv->FirstCalendarPos = Location; if (Location > MAX_VCALENDAR_LOCATION) return ERR_EMPTY; if (error==ERR_NONE) return error; } return error; } -GSM_Error ATGEN_CMS35ReplySetCalendar(GSM_Protocol_Message msg, GSM_StateMachine *s) +GSM_Error SIEMENS_ReplyAddCalendarNote(GSM_Protocol_Message msg, GSM_StateMachine *s) { - return ATGEN_CMS35ReplySetFunction (msg, s, "Calendar Note"); + return SIEMENS_ReplySetFunction (msg, s, "Calendar Note"); } -GSM_Error ATGEN_CMS35ReplyDeleteCalendar(GSM_Protocol_Message msg, GSM_StateMachine *s) +GSM_Error SIEMENS_ReplyDelCalendarNote(GSM_Protocol_Message msg, GSM_StateMachine *s) { GSM_Phone_Data *Data = &s->Phone.Data; if (Data->Cal->Location > MAX_VCALENDAR_LOCATION) return ERR_UNKNOWN; if (Data->Priv.ATGEN.ReplyState== AT_Reply_OK) { smprintf(s, "Calendar note deleted\n"); return ERR_NONE; } else { smprintf(s, "Can't delete calendar note\n"); return ERR_UNKNOWN; } } GSM_Error SIEMENS_DelCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note) { unsigned char req[32]; if (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED; s->Phone.Data.Cal = Note; sprintf(req, "AT^SBNW=\"vcs\",%i,0\r",Note->Location); smprintf(s, "Deleting calendar note\n"); return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_DeleteCalendarNote); } GSM_Error SIEMENS_AddCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_Error error; unsigned char req[500]; int size=0; if (Priv->Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED; // if (Note->Location==0x00) return ERR_INVALIDLOCATION; s->Phone.Data.Cal = Note; error=GSM_EncodeVCALENDAR(req,&size,Note,true,Siemens_VCalendar); return SetSiemensFrame (s,req,"vcs",Note->Location,ID_SetCalendarNote,size); } /* (c) by Timo Teras */ -GSM_Error ATGEN_SL45ReplyGetMemory(GSM_Protocol_Message msg, GSM_StateMachine *s) +GSM_Error SIEMENS_ReplyGetMemory(GSM_Protocol_Message msg, GSM_StateMachine *s) { #ifndef ENABLE_LGPL GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_MemoryEntry *Memory = s->Phone.Data.Memory; unsigned char buffer[500],buffer2[500]; switch (Priv->ReplyState) { case AT_Reply_OK: smprintf(s, "Phonebook entry received\n"); CopyLineString(buffer, msg.Buffer, Priv->Lines, 3); DecodeHexBin(buffer2,buffer,strlen(buffer)); Memory->EntriesNum = 0; DecodeVCARD21Text(buffer2, Memory); if (Memory->EntriesNum == 0) return ERR_EMPTY; return ERR_NONE; case AT_Reply_Error: smprintf(s, "Error - too high location ?\n"); return ERR_INVALIDLOCATION; case AT_Reply_CMSError: return ATGEN_HandleCMSError(s); default: break; } return ERR_UNKNOWNRESPONSE; #else return ERR_NOTIMPLEMENTED; #endif } #endif /* How should editor hadle tabs in this file? Add editor commands here. * vim: noexpandtab sw=8 ts=8 sts=8: */ diff --git a/gammu/emb/common/phone/at/sonyeric.c b/gammu/emb/common/phone/at/sonyeric.c index 4b2670a..8eeb39b 100644 --- a/gammu/emb/common/phone/at/sonyeric.c +++ b/gammu/emb/common/phone/at/sonyeric.c @@ -1,72 +1,70 @@ /* (c) 2003 by Marcin Wiacek */ #include "../../gsmstate.h" #ifdef GSM_ENABLE_ATGEN #include <string.h> #include <time.h> #include <ctype.h> #include "../../gsmcomon.h" #include "../../misc/coding/coding.h" -extern GSM_Reply_Function ATGENReplyFunctions[]; -extern GSM_Error ATGEN_DispatchMessage (GSM_StateMachine *s); +#include "atgen.h" +#include "sonyeric.h" #ifdef GSM_ENABLE_OBEXGEN -extern GSM_Reply_Function OBEXGENReplyFunctions[]; -extern GSM_Error OBEXGEN_GetFilePart (GSM_StateMachine *s, GSM_File *File); -extern GSM_Error OBEXGEN_AddFilePart (GSM_StateMachine *s, GSM_File *File, int *Pos); -extern GSM_Error OBEXGEN_Disconnect (GSM_StateMachine *s); +#include "../obex/obexgen.h" -#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX) +extern GSM_Reply_Function OBEXGENReplyFunctions[]; +extern GSM_Reply_Function ATGENReplyFunctions[]; static GSM_Error SONYERIC_SetOBEXMode(GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_Error error; if (Priv->OBEX) return ERR_NONE; dbgprintf ("Changing to OBEX\n"); error=GSM_WaitFor (s, "AT*EOBEX\r", 9, 0x00, 4, ID_SetOBEX); if (error != ERR_NONE) return error; error = s->Protocol.Functions->Terminate(s); if (error != ERR_NONE) return error; s->Protocol.Functions = &OBEXProtocol; error = s->Protocol.Functions->Initialise(s); if (error != ERR_NONE) { s->Protocol.Functions = &ATProtocol; return error; } strcpy(s->CurrentConfig->Model,"seobex"); s->Phone.Data.Priv.OBEXGEN.Service = 0; s->Phone.Functions->DispatchMessage = GSM_DispatchMessage; s->Phone.Functions->ReplyFunctions = OBEXGENReplyFunctions; Priv->OBEX = true; return ERR_NONE; } static GSM_Error SONYERIC_SetATMode(GSM_StateMachine *s) { GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; GSM_Error error; if (!Priv->OBEX) return ERR_NONE; dbgprintf ("Changing to AT\n"); error = OBEXGEN_Disconnect(s); if (error != ERR_NONE) return error; error = s->Protocol.Functions->Terminate(s); if (error != ERR_NONE) return error; s->Protocol.Functions = &ATProtocol; error = s->Protocol.Functions->Initialise(s); if (error != ERR_NONE) { @@ -81,331 +79,442 @@ static GSM_Error SONYERIC_SetATMode(GSM_StateMachine *s) } static GSM_Error SONYERIC_GetFile(GSM_StateMachine *s, GSM_File *File, unsigned char *FileName) { GSM_Error error; strcpy(File->ID_FullName,FileName); File->Used = 0; if (File->Buffer != NULL) free(File->Buffer); File->Buffer = NULL; error = SONYERIC_SetOBEXMode(s); if (error != ERR_NONE) return error; error = ERR_NONE; while (error == ERR_NONE) error = OBEXGEN_GetFilePart(s,File); if (error != ERR_EMPTY) return error; return SONYERIC_SetATMode(s); } static GSM_Error SONYERIC_SetFile(GSM_StateMachine *s, unsigned char *FileName, unsigned char *Buffer, int Length) { GSM_Error error; GSM_File File; int Pos = 0; error = SONYERIC_SetOBEXMode(s); if (error != ERR_NONE) return error; strcpy(File.ID_FullName,FileName); EncodeUnicode(File.Name,FileName,strlen(FileName)); File.Used = Length; File.Buffer = malloc(Length); memcpy(File.Buffer,Buffer,Length); error = ERR_NONE; while (error == ERR_NONE) error = OBEXGEN_AddFilePart(s,&File,&Pos); free(File.Buffer); if (error != ERR_EMPTY) return error; return SONYERIC_SetATMode(s); } #endif GSM_Error SONYERIC_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start) { -#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX) +#ifdef GSM_ENABLE_OBEXGEN GSM_Error error; GSM_ToDoEntry ToDo; int Pos, num, Loc; GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; if (start) { error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs"); if (error != ERR_NONE) return error; Note->Location = 1; } else { Note->Location++; } smprintf(s, "Getting calendar note %i\n",Note->Location); Loc = Note->Location; Pos = 0; num = 0; while (1) { error = GSM_DecodeVCALENDAR_VTODO(Priv->file.Buffer, &Pos, Note, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo); if (error == ERR_EMPTY) break; if (error != ERR_NONE) return error; if (Note->EntriesNum != 0) { num++; if (num == Loc) return ERR_NONE; } } return ERR_EMPTY; #else return ERR_SOURCENOTAVAILABLE; #endif } GSM_Error SONYERIC_GetNextToDo(GSM_StateMachine *s, GSM_ToDoEntry *ToDo, bool start) { -#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX) +#ifdef GSM_ENABLE_OBEXGEN GSM_Error error; GSM_CalendarEntry Calendar; int Pos, num, Loc; GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; if (Priv->Manufacturer!=AT_Ericsson) return ERR_NOTSUPPORTED; if (start) { error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs"); if (error != ERR_NONE) return error; ToDo->Location = 1; } else { ToDo->Location++; } smprintf(s,"Getting ToDo %i\n",ToDo->Location); Loc = ToDo->Location; Pos = 0; num = 0; while (1) { error = GSM_DecodeVCALENDAR_VTODO(Priv->file.Buffer, &Pos, &Calendar, ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo); if (error == ERR_EMPTY) break; if (error != ERR_NONE) return error; if (ToDo->EntriesNum != 0) { num++; if (num == Loc) return ERR_NONE; } } return ERR_EMPTY; #else return ERR_SOURCENOTAVAILABLE; #endif } GSM_Error SONYERIC_GetToDoStatus(GSM_StateMachine *s, GSM_ToDoStatus *status) { -#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX) +#ifdef GSM_ENABLE_OBEXGEN GSM_Error error; GSM_ToDoEntry ToDo; GSM_CalendarEntry Calendar; int Pos; GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; if (Priv->Manufacturer!=AT_Ericsson) return ERR_NOTSUPPORTED; smprintf(s,"Getting ToDo status\n"); error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs"); if (error != ERR_NONE) return error; status->Used = 0; Pos = 0; while (1) { error = GSM_DecodeVCALENDAR_VTODO(Priv->file.Buffer, &Pos, &Calendar, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo); if (error == ERR_EMPTY) break; if (error != ERR_NONE) return error; if (ToDo.EntriesNum != 0) status->Used++; } return ERR_NONE; #else return ERR_SOURCENOTAVAILABLE; #endif } GSM_Error SONYERIC_AddCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note) { -#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX) +#ifdef GSM_ENABLE_OBEXGEN unsigned char req[5000]; int size=0; smprintf(s,"Adding calendar note\n"); GSM_EncodeVCALENDAR(req,&size,Note,true,SonyEricsson_VCalendar); return SONYERIC_SetFile(s, "telecom/cal/luid/.vcs", req, size); #else return ERR_SOURCENOTAVAILABLE; #endif } GSM_Error SONYERIC_AddToDo(GSM_StateMachine *s, GSM_ToDoEntry *ToDo) { -#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX) +#ifdef GSM_ENABLE_OBEXGEN GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; unsigned char req[5000]; int size=0; if (Priv->Manufacturer!=AT_Ericsson) return ERR_NOTSUPPORTED; smprintf(s,"Adding ToDo\n"); GSM_EncodeVTODO(req,&size,ToDo,true,SonyEricsson_VToDo); return SONYERIC_SetFile(s, "telecom/cal/luid/.vcs", req, size); #else return ERR_SOURCENOTAVAILABLE; #endif } GSM_Error SONYERIC_DeleteAllToDo(GSM_StateMachine *s) { -#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX) +#ifdef GSM_ENABLE_OBEXGEN GSM_Error error; int Pos,Level = 0,Used; unsigned char *Buf; GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; unsigned char Line[2000]; if (Priv->Manufacturer!=AT_Ericsson) return ERR_NOTSUPPORTED; smprintf(s,"Deleting all ToDo\n"); error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs"); if (error != ERR_NONE) return error; Pos = 0; Buf = NULL; Used = 0; while (1) { MyGetLine(Priv->file.Buffer, &Pos, Line, Priv->file.Used); if (strlen(Line) == 0) break; dbgprintf("Line is %s,%i,%i\n",Line,Priv->file.Used,Pos); switch (Level) { case 0: if (strstr(Line,"BEGIN:VTODO")) { Level = 2; break; } Buf=(unsigned char *)realloc(Buf,Used+strlen(Line)+3); strcpy(Buf+Used,Line); Used=Used+strlen(Line)+3; Buf[Used-3] = 13; Buf[Used-2] = 10; Buf[Used-1] = 0x00; break; case 2: /* ToDo note */ if (strstr(Line,"END:VTODO")) { Level = 0; } break; } } error = SONYERIC_SetFile(s, "telecom/cal.vcs", Buf, Used); // if (Buf != NULL) free(Buf); return error; #else return ERR_SOURCENOTAVAILABLE; #endif } GSM_Error SONYERIC_DelCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note) { -#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX) +#ifdef GSM_ENABLE_OBEXGEN GSM_Error error; int Pos,Level = 0,Loc=0,Used; GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; unsigned char Line[2000]; unsigned char *Buf; smprintf(s, "Deleting calendar note %i\n",Note->Location); error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs"); if (error != ERR_NONE) return error; Pos = 0; Buf = NULL; Used = 0; while (1) { MyGetLine(Priv->file.Buffer, &Pos, Line, Priv->file.Used); if (strlen(Line) == 0) break; dbgprintf("Line is %s,%i,%i\n",Line,Priv->file.Used,Pos); switch (Level) { case 0: if (strstr(Line,"BEGIN:VEVENT")) { Loc++; if (Loc == Note->Location) { Level = 1; break; } } Buf=(unsigned char *)realloc(Buf,Used+strlen(Line)+3); strcpy(Buf+Used,Line); Used=Used+strlen(Line)+3; Buf[Used-3] = 13; Buf[Used-2] = 10; Buf[Used-1] = 0x00; break; case 1: /* Calendar note */ if (strstr(Line,"END:VEVENT")) { Level = 0; } break; } } DumpMessage(s->di.df, s->di.dl, Buf, Used); error = SONYERIC_SetFile(s, "telecom/cal.vcs", Buf, Used); if (Buf != NULL) free(Buf); return error; #else return ERR_SOURCENOTAVAILABLE; #endif } GSM_Error SONYERIC_GetCalendarStatus(GSM_StateMachine *s, GSM_CalendarStatus *Status) { -#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX) +#ifdef GSM_ENABLE_OBEXGEN GSM_Error error; GSM_ToDoEntry ToDo; GSM_CalendarEntry Calendar; int Pos; GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN; if (Priv->Manufacturer!=AT_Ericsson) return ERR_NOTSUPPORTED; smprintf(s, "Getting calendar status\n"); error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs"); if (error != ERR_NONE) return error; Status->Used = 0; Pos = 0; while (1) { error = GSM_DecodeVCALENDAR_VTODO(Priv->file.Buffer, &Pos, &Calendar, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo); if (error == ERR_EMPTY) break; if (error != ERR_NONE) return error; if (Calendar.EntriesNum != 0) Status->Used++; } return ERR_NONE; #else return ERR_SOURCENOTAVAILABLE; #endif } -#endif +GSM_Error ERICSSON_ReplyGetDateLocale(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ /* Author: Peter Ondraska, based on code by Marcin Wiacek and Michal Cihar + License: Whatever the current maintainer of gammulib chooses, as long as there + is an easy way to obtain the source under GPL, otherwise the author's parts + of this function are GPL 2.0. + */ + GSM_Locale *locale = s->Phone.Data.Locale; + char format; + + switch (s->Phone.Data.Priv.ATGEN.ReplyState) { + case AT_Reply_OK: + smprintf(s, "Date settings received\n"); + format=atoi(msg.Buffer); + switch (format) { + case 0: locale->DateFormat = GSM_Date_OFF; + locale->DateSeparator = 0; + break; + case 1: locale->DateFormat = GSM_Date_DDMMMYY; + locale->DateSeparator = '-'; + break; + case 2: locale->DateFormat = GSM_Date_DDMMYY; + locale->DateSeparator = '-'; + break; + case 3: locale->DateFormat = GSM_Date_MMDDYY; + locale->DateSeparator = '/'; + break; + case 4: locale->DateFormat = GSM_Date_DDMMYY; + locale->DateSeparator = '/'; + break; + case 5: locale->DateFormat = GSM_Date_DDMMYY; + locale->DateSeparator = '.'; + break; + case 6: locale->DateFormat = GSM_Date_YYMMDD; + locale->DateSeparator = 0; + break; + case 7: locale->DateFormat = GSM_Date_YYMMDD; + locale->DateSeparator = '-'; + break; + default:return ERR_UNKNOWNRESPONSE; + } + default: + return ERR_NOTSUPPORTED; + } +} + +GSM_Error ERICSSON_ReplyGetTimeLocale(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ /* Author: Peter Ondraska + License: Whatever the current maintainer of gammulib chooses, as long as there + is an easy way to obtain the source under GPL, otherwise the author's parts + of this function are GPL 2.0. + */ + char format; + + switch (s->Phone.Data.Priv.ATGEN.ReplyState) { + case AT_Reply_OK: + smprintf(s, "Time settings received\n"); + format=atoi(msg.Buffer); + switch (format) { + case 1: + case 2: s->Phone.Data.Locale->AMPMTime=(format==2); + return ERR_NONE; + default:return ERR_UNKNOWNRESPONSE; + } + default: return ERR_NOTSUPPORTED; + } +} + +GSM_Error ERICSSON_GetLocale(GSM_StateMachine *s, GSM_Locale *locale) +{ + GSM_Error error; + + s->Phone.Data.Locale = locale; + + smprintf(s, "Getting date format\n"); + error=GSM_WaitFor (s, "AT+ESDF?\r", 9, 0x00, 3, ID_GetLocale); + if (error!=ERR_NONE) return error; + + smprintf(s, "Getting time format\n"); + return GSM_WaitFor (s, "AT+ESTF?\r", 9, 0x00, 3, ID_GetLocale); +} + + +GSM_Error ERICSSON_SetLocale(GSM_StateMachine *s, GSM_Locale *locale) +{ /* Author: Peter Ondraska + License: Whatever the current maintainer of gammulib chooses, as long as there + is an easy way to obtain the source under GPL, otherwise the author's parts + of this function are GPL 2.0. + */ + /* this is not yet supported by gammu.c */ + int format=0; + char req[12]; + + if (locale->DateFormat==GSM_Date_OFF) { format=0; } else + if ((locale->DateFormat==GSM_Date_DDMMMYY)&&(locale->DateSeparator=='-')) { format=1; } else + if ((locale->DateFormat==GSM_Date_DDMMYY)&&(locale->DateSeparator=='-')) { format=2; } else + if ((locale->DateFormat==GSM_Date_MMDDYY)&&(locale->DateSeparator=='/')) { format=3; } else + if ((locale->DateFormat==GSM_Date_DDMMYY)&&(locale->DateSeparator=='/')) { format=4; } else + if ((locale->DateFormat==GSM_Date_DDMMYY)&&(locale->DateSeparator=='.')) { format=5; } else + if ((locale->DateFormat==GSM_Date_YYMMDD)&&(locale->DateSeparator==0)) { format=6; } else + if ((locale->DateFormat==GSM_Date_YYMMDD)&&(locale->DateSeparator=='-')) { format=7; } + else { return ERR_NOTSUPPORTED; } /* ERR_WRONGINPUT */ + + sprintf(req,"AT+ESDF=%i\r",format); + smprintf(s, "Setting date format\n"); + return GSM_WaitFor (s, req, strlen(req), 0x00, 3, ID_SetLocale); + + if (locale->AMPMTime) { format=2; } else { format=1; } + sprintf(req,"AT+ESTF=%i\r",format); + smprintf(s, "Setting time format\n"); + return GSM_WaitFor (s, req, strlen(req), 0x00, 3, ID_SetLocale); +} + #endif /* How should editor hadle tabs in this file? Add editor commands here. * vim: noexpandtab sw=8 ts=8 sts=8: */ |