/* Samsung-specific functions * Copyright (C) 2004 Claudio Matsuoka * Tested with S300 only! */ #include "../../gsmstate.h" #ifdef GSM_ENABLE_ATGEN #include #include #include #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 */ 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