[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: how to send extra commands
From: |
W. de Hoog |
Subject: |
Re: how to send extra commands |
Date: |
Sun, 22 Feb 2009 13:50:39 +0100 |
User-agent: |
Mozilla-Thunderbird 2.0.0.19 (X11/20090103) |
Hi,
This morning I noticed I have been working with an older version (0.6.26
debian source package). The atsam.c from cvs is almost empty!
Before I make an even bigger fool of myself I hope you can comment on my
current version.
I can now read, delete and probably write (not tested a lot) phone book
entries on my samsung sgh-m150.
To save the index I need for modifying entries I abuse the
additional_names field which is not supported on my phone.
--
Willem-Jan de Hoog
? sam-m150.diff
Index: common/phones/atsam.c
===================================================================
RCS file: /sources/gnokii/gnokii/common/phones/atsam.c,v
retrieving revision 1.6
diff -u -r1.6 atsam.c
--- common/phones/atsam.c 4 Sep 2008 20:04:53 -0000 1.6
+++ common/phones/atsam.c 22 Feb 2009 12:48:37 -0000
@@ -45,18 +45,430 @@
#include "phones/atsam.h"
#include "links/atbus.h"
+enum SAMSUNG_MODELS {
+ SAM_SGH_M150,
+ SAM_GENERIC
+};
+
+static enum SAMSUNG_MODELS samsungModel = SAM_GENERIC;
+static int maxPhonebook = 0;
+static int phonebookRequestIndex = 0;
+
+static char *sam_skip_entry(char *buffer) {
+ char *pos, *endpos;
+
+ if (!buffer)
+ return NULL;
+
+ if (!(pos = strstr(buffer, ",\"")))
+ return NULL;
+ pos += 2;
+
+ if (!(endpos = strstr(pos, "\",")))
+ return NULL;
+ *endpos = 0;
+
+ return endpos + 1;
+}
+
+// maybe if extpb_scan_entry becomes non static it can be adapted and used
+static char *sam_scan_entry(at_driver_instance *drvinst, char *buffer,
gn_phonebook_entry *entry, gn_phonebook_entry_type type,
gn_phonebook_number_type number_type, int ext_str)
+{
+ char *pos, *endpos;
+ size_t len;
+ int ix;
+ if (!buffer)
+ return NULL;
+
+ if (!(pos = strstr(buffer, ",\"")))
+ return NULL;
+ pos += 2;
+
+ if (ext_str==1) {
+ if (!(endpos = strchr(pos, ',')))
+ return NULL;
+ *endpos = 0;
+ len = atoi(pos);
+ pos = endpos + 1;
+ endpos = pos + len;
+ *endpos = 0;
+ } else {
+ if (!(endpos = strstr(pos, "\",")))
+ return NULL;
+ *endpos = 0;
+ len = strlen(pos);
+ }
+
+ if (len > 0) {
+ ix = entry->subentries_count++;
+ entry->subentries[ix].entry_type = type;
+ entry->subentries[ix].number_type = number_type;
+ if(ext_str == 2) // remove STX and ETX chars
+ at_decode(drvinst->charset, entry->subentries[ix].data.number, pos+1,
len-2);
+ else
+ at_decode(drvinst->charset, entry->subentries[ix].data.number, pos, len);
+ if (entry->number[0] == 0 && type == GN_PHONEBOOK_ENTRY_Number)
+ snprintf(entry->number, sizeof(entry->number), "%s",
entry->subentries[ix].data.number);
+ }
+
+ return endpos + 1;
+}
+
+// when extpb_find_subentry becomes non static we can use that one
+static char *sam_find_subentry(gn_phonebook_entry *entry,
gn_phonebook_entry_type type)
+{
+ int i;
+ for (i = 0; i < entry->subentries_count; ++i)
+ if (entry->subentries[i].entry_type == type)
+ return entry->subentries[i].data.number;
+ return NULL;
+}
+
+// when extpb_find_number_subentry becomes non static we can use that one
+static char *sam_find_number_subentry(gn_phonebook_entry *entry,
gn_phonebook_number_type type)
+{
+ int i;
+ for (i = 0; i < entry->subentries_count; ++i)
+ if (entry->subentries[i].entry_type ==
GN_PHONEBOOK_ENTRY_Number && entry->subentries[i].number_type == type)
+ return entry->subentries[i].data.number;
+ return NULL;
+}
+
static gn_error Unsupported(gn_data *data, struct gn_statemachine *state)
{
return GN_ERR_NOTSUPPORTED;
}
+static gn_error ReplyReadPhonebook(int messagetype, unsigned char *buffer, int
length, gn_data *data, struct gn_statemachine *state)
+{
+ at_driver_instance *drvinst = AT_DRVINST(state);
+ at_line_buffer buf;
+ char *pos, *first_name, *last_name, *tmp;
+ gn_error error;
+ size_t len = 0;
+
+ if ((error = at_error_get(buffer, state)) != GN_ERR_NONE) {
+ if(error == GN_ERR_INVALIDLOCATION && phonebookRequestIndex <=
maxPhonebook) {
+ // SGH-M150 responds with invalid location even for empty slots
+ return GN_ERR_EMPTYLOCATION;
+ }
+ return (error == GN_ERR_UNKNOWN) ? GN_ERR_INVALIDLOCATION :
error;
+ }
+
+ buf.line1 = buffer + 1;
+ buf.length = length;
+ splitlines(&buf);
+
+ if (strncmp(buf.line1, "AT+CPBR=", 8))
+ return GN_ERR_UNKNOWN;
+
+ if (!strncmp(buf.line2, "OK", 2)) {
+ /* Empty phonebook location found */
+ if (data->phonebook_entry) {
+ data->phonebook_entry->number[0] = 0;
+ data->phonebook_entry->name[0] = 0;
+ data->phonebook_entry->caller_group =
GN_PHONEBOOK_GROUP_None;
+ data->phonebook_entry->subentries_count = 0;
+ data->phonebook_entry->empty = true;
+ }
+ return GN_ERR_NONE;
+ }
+
+ if (strncmp(buf.line2, "+CPBR: ", 7))
+ return GN_ERR_UNKNOWN;
+
+ if (data->phonebook_entry) {
+ gn_phonebook_entry *entry = data->phonebook_entry;
+ data->phonebook_entry->number[0] = 0;
+ data->phonebook_entry->name[0] = 0;
+ entry->caller_group = GN_PHONEBOOK_GROUP_None;
+ entry->subentries_count = 0;
+ entry->empty = false;
+ pos = buf.line2;
+ int deleteLocation = entry->location;
+
+ /* store sub entries */
+ sscanf(pos, "+CPBR: %d,", &deleteLocation);
+ pos = sam_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Number,
GN_PHONEBOOK_NUMBER_Mobile, 0);
+ pos = sam_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_LastName,
GN_PHONEBOOK_NUMBER_None, 2);
+ pos = sam_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_FirstName,
GN_PHONEBOOK_NUMBER_None, 2);
+ pos = sam_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Number,
GN_PHONEBOOK_NUMBER_Home, 0);
+ pos = sam_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Number,
GN_PHONEBOOK_NUMBER_Work, 0);
+ pos = sam_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Number,
GN_PHONEBOOK_NUMBER_Fax, 0);
+ pos = sam_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Number,
GN_PHONEBOOK_NUMBER_Common, 0);
+ pos = sam_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Email,
GN_PHONEBOOK_NUMBER_None, 0);
+ pos = sam_skip_entry(pos);
+ pos = sam_scan_entry(drvinst, pos, entry, GN_PHONEBOOK_ENTRY_Note,
GN_PHONEBOOK_NUMBER_None, 2);
+ // 0
+ // 65535
+ // 2 sound?
+ // 255
+ // 47 group? (family etc)
+ // ""
+ // "<picture>"
+
+ first_name = sam_find_subentry(entry, GN_PHONEBOOK_ENTRY_Email);
+ /* compile a name out of first name + last name */
+ first_name = sam_find_subentry(entry,
GN_PHONEBOOK_ENTRY_FirstName);
+ last_name = sam_find_subentry(entry,
GN_PHONEBOOK_ENTRY_LastName);
+ if(first_name || last_name) {
+ if (first_name)
+ len += strlen(first_name);
+ if (last_name)
+ len += strlen(last_name);
+ if (!(tmp = (char *)malloc(len + 2))) /* +2 for \0 and
space */
+ return GN_ERR_INTERNALERROR;
+ tmp[0] = 0;
+ if (first_name) {
+ if (strlen(first_name) + strlen(entry->name) +
1 > sizeof(entry->name))
+ return GN_ERR_FAILED;
+ strncat(entry->name, first_name,
strlen(first_name));
+ if (last_name)
+ strncat(entry->name, " ", strlen(" "));
+ }
+ if (strlen(last_name) + strlen(entry->name) + 1 >
sizeof(entry->name))
+ return GN_ERR_FAILED;
+ if (last_name)
+ strncat(entry->name, last_name, strlen
(last_name));
+ free(tmp);
+
+ // add to person as well to produce useful vcard
+ if(first_name) {
+ entry->person.has_person = 1;
+ strncpy(entry->person.given_name, first_name, strlen(first_name));
+ }
+ if(last_name) {
+ entry->person.has_person = 1;
+ strncpy(entry->person.family_name, last_name, strlen(last_name));
+ }
+ // HACK: put the edit index in the additional_names
+ if(deleteLocation != entry->location)
+ entry->person.has_person = 1;
+ sprintf(entry->person.additional_names, "%d", deleteLocation);
+ }
+ }
+ return GN_ERR_NONE;
+}
+
+static gn_error FetchInfo(gn_data *data, struct gn_statemachine *state) {
+ char req[32];
+
+ snprintf(req, sizeof(req), "AT+INFO\r");
+ if (sm_message_send(strlen(req), GN_OP_AT_Info, req, state))
+ return GN_ERR_NOTREADY;
+ return sm_block_no_retry(GN_OP_AT_Info, data, state);
+}
+
+static gn_error ReplyFetchInfo(int messagetype, unsigned char *buffer, int
length, gn_data *data, struct gn_statemachine *state) {
+ // for now we ignore the response
+ return GN_ERR_NONE;
+}
+
+static gn_error AT_ReadPhonebook(gn_data *data, struct gn_statemachine *state)
{
+ at_driver_instance *drvinst = AT_DRVINST(state);
+ char req[32];
+ gn_error ret;
+
+ ret = state->driver.functions(GN_OP_AT_SetCharset, data, state);
+ if (ret)
+ return ret;
+
+ ret = at_memory_type_set(data->phonebook_entry->memory_type, state);
+ if (ret)
+ return ret;
+
+ ret = state->driver.functions(GN_OP_AT_Info, data, state);
+ if (ret)
+ return ret;
+
+ phonebookRequestIndex =
data->phonebook_entry->location+drvinst->memoryoffset;
+ snprintf(req, sizeof(req), "AT+CPBR=%d\r", phonebookRequestIndex);
+
+ if (sm_message_send(strlen(req), GN_OP_ReadPhonebook, req, state))
+ return GN_ERR_NOTREADY;
+ return sm_block_no_retry(GN_OP_ReadPhonebook, data, state);
+}
+
+static gn_error AT_DeletePhonebook(gn_data *data, struct gn_statemachine
*state)
+{
+ at_driver_instance *drvinst = AT_DRVINST(state);
+ int len;
+ char req[64];
+ gn_error ret;
+
+ if (!data->phonebook_entry)
+ return GN_ERR_INTERNALERROR;
+
+ ret = at_memory_type_set(data->phonebook_entry->memory_type, state);
+ if (ret)
+ return ret;
+
+ ret = state->driver.functions(GN_OP_AT_Info, data, state);
+ if (ret)
+ return ret;
+
+ len = snprintf(req, sizeof(req), "AT+CPBW=%d\r",
data->phonebook_entry->location+drvinst->memoryoffset);
+
+ if (sm_message_send(len, GN_OP_DeletePhonebook, req, state))
+ return GN_ERR_NOTREADY;
+ return sm_block_no_retry(GN_OP_DeletePhonebook, data, state);
+}
+
+#define MAX_REQ 2048
+static gn_error AT_WritePhonebook(gn_data *data, struct gn_statemachine *state)
+{
+ at_driver_instance *drvinst = AT_DRVINST(state);
+ int len, ofs;
+ char req[MAX_REQ + 1], tmp[MAX_REQ + 1];
+ char *mobile, *home, *work, *fax, *general, *email, *first_name,
*last_name, *note;
+ gn_phonebook_entry *entry = data->phonebook_entry;
+ gn_data data2;
+ gn_memory_status memstat;
+ gn_error ret;
+ int ix;
+ int i;
+
+ if (entry->empty)
+ return AT_DeletePhonebook(data, state);
+
+ ret = at_memory_type_set(entry->memory_type, state);
+ if (ret)
+ return ret;
+
+ ret = state->driver.functions(GN_OP_AT_SetCharset, data, state);
+ if (ret)
+ return ret;
+
+ gn_data_clear(&data2);
+ data2.memory_status = &memstat;
+ data2.memory_status->memory_type = entry->memory_type;
+ ret = state->driver.functions(GN_OP_GetMemoryStatus, &data2, state);
+ if (ret)
+ return ret;
+
+ ret = state->driver.functions(GN_OP_AT_Info, data, state);
+ if (ret)
+ return ret;
+
+ // for (i = 0; i < entry->subentries_count; ++i)
+ // printf("%d=%s (%d)\n", i, entry->subentries[i].data.number,
entry->subentries[i].entry_type);
+ // printf("name=%s\n", entry->name);
+ // if(entry->person.has_person) {
+ // printf("family_name=%s\n", entry->person.family_name);
+ // printf("given_name=%s\n", entry->person.given_name);
+ // printf("additional_names=%s\n", entry->person.additional_names);
+ // printf("honorific_prefixes=%s\n", entry->person.honorific_prefixes);
+ // printf("honorific_suffixes=%s\n", entry->person.honorific_suffixes);
+ // }
+
+ if(entry->person.has_person && strlen(entry->person.additional_names)>0)
+ sscanf(entry->person.additional_names,"%d", &ix);
+ else
+ ix = entry->location;
+ mobile = sam_find_number_subentry(entry, GN_PHONEBOOK_NUMBER_Mobile);
+ if(entry->person.has_person && strlen(entry->person.given_name)>0)
+ first_name = entry->person.given_name;
+ else
+ first_name = sam_find_subentry(entry, GN_PHONEBOOK_ENTRY_FirstName);
+ if(entry->person.has_person && strlen(entry->person.family_name)>0)
+ last_name = entry->person.family_name;
+ else
+ last_name = sam_find_subentry(entry, GN_PHONEBOOK_ENTRY_LastName);
+ home = sam_find_number_subentry(entry, GN_PHONEBOOK_NUMBER_Home);
+ work = sam_find_number_subentry(entry, GN_PHONEBOOK_NUMBER_Work);
+ fax = sam_find_number_subentry(entry, GN_PHONEBOOK_NUMBER_Fax);
+ general = sam_find_number_subentry(entry, GN_PHONEBOOK_NUMBER_Common);
+ email = sam_find_subentry(entry, GN_PHONEBOOK_ENTRY_Email);
+ note = sam_find_subentry(entry, GN_PHONEBOOK_ENTRY_Note);
+ if (!(mobile || home || work || fax || general) && entry->number[0] != 0)
+ mobile = entry->number;
+ if (!(first_name || last_name) && entry->name[0] != 0)
+ first_name = entry->name;
+
+ ofs = snprintf(req, MAX_REQ, "AT+CPBW=%d", ix);
+ // ix,"<mobile>",4,"^B<last name>^C","^B<first
name>^C","<home>",6,"<work>",7,"<fax>",2,"<general>",
+ // 5,"<email>","","^B<note>^C",0,65535,2,255,47,"","<picture>"
+
+ ofs += snprintf(req+ofs, MAX_REQ, ",\"");
+ if (mobile)
+ ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, mobile,
strlen(mobile)) - 1;
+ req[ofs++] = '"';
+
+ ofs += snprintf(req+ofs, MAX_REQ, ",4,\"");
+ req[ofs++] = 0x02;
+ if (last_name)
+ ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, last_name,
strlen(last_name)) - 1;
+ req[ofs++] = 0x03;
+ req[ofs++] = '"';
+
+ ofs += snprintf(req+ofs, MAX_REQ, ",\"");
+ req[ofs++] = 0x02;
+ if (first_name)
+ ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, first_name,
strlen(first_name)) - 1;
+ req[ofs++] = 0x03;
+ req[ofs++] = '"';
+
+ ofs += snprintf(req+ofs, MAX_REQ, ",\"");
+ if (home)
+ ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, home,
strlen(home)) - 1;
+ req[ofs++] = '"';
+
+ ofs += snprintf(req+ofs, MAX_REQ, ",6,\"");
+ if (work)
+ ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, work,
strlen(work)) - 1;
+ req[ofs++] = '"';
+
+ ofs += snprintf(req+ofs, MAX_REQ, ",7,\"");
+ if (fax)
+ ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, fax,
strlen(fax)) - 1;
+ req[ofs++] = '"';
+
+ ofs += snprintf(req+ofs, MAX_REQ, ",2,\"");
+ if (general)
+ ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, general,
strlen(general)) - 1;
+ req[ofs++] = '"';
+
+ ofs += snprintf(req+ofs, MAX_REQ, ",5,\"");
+ if (email)
+ ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, email,
strlen(email)) - 1;
+ req[ofs++] = '"';
+
+ ofs += snprintf(req+ofs, MAX_REQ, ",\"");
+ req[ofs++] = 0x02;
+ if (note)
+ ofs += at_encode(drvinst->charset, req + ofs, MAX_REQ - ofs, note,
strlen(note)) - 1;
+ req[ofs++] = 0x03;
+ ofs += snprintf(req+ofs, MAX_REQ, "\",,,,,,,\"\",\"\"\r");
+
+ // printf("%s\n", req);
+ if (sm_message_send(ofs, GN_OP_WritePhonebook, req, state))
+ return GN_ERR_NOTREADY;
+ return sm_block_no_retry(GN_OP_WritePhonebook, data, state);
+}
+#undef MAX_REQ
+
void at_samsung_init(char* foundmodel, char* setupmodel, struct
gn_statemachine *state) {
- /* FIXME: some Samsung phones should have:
- AT_DRVINST(state)->extended_phonebook = 1;
- */
-
- /* phone lacks many usefull commands :( */
- at_insert_send_function(GN_OP_GetBatteryLevel, Unsupported, state);
- at_insert_send_function(GN_OP_GetPowersource, Unsupported, state);
- at_insert_send_function(GN_OP_GetRFLevel, Unsupported, state);
+ if(!strncasecmp(foundmodel, "samsung sgh-m150", 16))
+ samsungModel = SAM_SGH_M150;
+
+ switch(samsungModel) {
+ case SAM_SGH_M150:
+ maxPhonebook = 500;
+ at_insert_send_function(GN_OP_ReadPhonebook, AT_ReadPhonebook, state);
+ at_insert_recv_function(GN_OP_ReadPhonebook, ReplyReadPhonebook, state);
+ at_insert_send_function(GN_OP_WritePhonebook, AT_WritePhonebook, state);
+ at_insert_send_function(GN_OP_DeletePhonebook, AT_DeletePhonebook,
state);
+ at_insert_send_function(GN_OP_AT_Info, FetchInfo, state);
+ at_insert_recv_function(GN_OP_AT_Info, ReplyFetchInfo, state);
+ break;
+ default:
+ /* FIXME: some Samsung phones should have:
+ AT_DRVINST(state)->extended_phonebook = 1;
+ */
+ /* phone lacks many usefull commands :( */
+ at_insert_send_function(GN_OP_GetBatteryLevel, Unsupported, state);
+ at_insert_send_function(GN_OP_GetPowersource, Unsupported, state);
+ at_insert_send_function(GN_OP_GetRFLevel, Unsupported, state);
+ break;
+ }
}
Index: include/phones/atgen.h
===================================================================
RCS file: /sources/gnokii/gnokii/include/phones/atgen.h,v
retrieving revision 1.36
diff -u -r1.36 atgen.h
--- include/phones/atgen.h 4 Sep 2008 20:04:53 -0000 1.36
+++ include/phones/atgen.h 22 Feb 2009 12:48:37 -0000
@@ -49,6 +49,7 @@
GN_OP_AT_IncomingSMS,
GN_OP_AT_GetSMSMemorySize,
GN_OP_AT_PrepareDateTime,
+ GN_OP_AT_Info,
GN_OP_AT_Max /* don't append anything after this entry */
} at_operation;