gnokii-users
[Top][All Lists]
Advanced

[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;
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]