Rif: RE: [RFC] feature freeze?!

<[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <20020321103746.QED1149.fep31-svc.tin.it@[127.0.0.1]>
Well, didn't try this patch, but with the last one
applied  successfully (apart the 1 dlr row) on the latest snapshot and works
fine with wavecom.
So, thanks Oded, looking forward to see it applied to cvs.
Andrea

> Da: "Oded Arbel" <[email protected]>
> Data: 21/03/2002 11:07
> A: "Stipe Tolj" <[email protected]>,
>    "Andreas Fink (E-mail)" <[email protected]>
> cc: <[email protected]>
> Oggetto: RE: [RFC] feature freeze?!
> 
> Attached latest revision of "SIM buffering" patch.
> ChangeLog : 
> - no default for message-storage : will not send +CPMS= if not set.
> should make some people feel more comfortable.
> - added documentation modems.conf 
> - added documentation for configuration options in userguide
> 
> --
> Oded Arbel
> m-Wise Inc.
> [email protected]
> 
> Rick:	"How can you close me up?  On what grounds?"
> Renault: "I'm shocked!  Shocked!  To find that gambling is going on
> here."
> Croupier (handing money to Renault): "Your winnings, sir."
> Renault:"Oh.  Thank you very much."
> 		-- Casablanca
> 
> 
> > -----Original Message-----
> > From: Stipe Tolj [mailto:[email protected]]
> > Sent: Thursday, March 21, 2002 11:50 AM
> > Cc: Oded Arbel; [email protected]
> > Subject: Re: [RFC] feature freeze?!
> > 
> > 
> > Andreas Fink wrote:
> > > 
> > > >I think the DLR and time stamp patches I submitted should 
> > go in before
> > > >feature freeze and definetly before release (mainly as 
> > these are not new
> > > >features, but bug fixes).
> > > 
> > > its bugs, not features. so they go in before the release.
> > > 
> > > >I would also like to see the "SIM buffering" patch in 
> > before feature
> > > >freeze (this is definetly a new feature).
> > > 
> > > Even I don't like using SIM buffering, I think its a niche "backup"
> > > plan for some applications or for buggy devices. I would say this
> > > should be part of the release. Oded if you send me a proper patch (I
> > > now have a gazillion versions of yours), I'll test it out with a few
> > > devices I have (Nokia 7110, 6210, 6310, 6250, Wavecom, Siemens TC35,
> > > Ericsson T68m, 520m and maybe even a Xircom which is not supported
> > > yet). Be aware that I'm pretty busy now being in Brasil at a
> > > strategic wireless conference (see www.enterprisela.com) and it will
> > > take me a while until I can do anything about it.
> > > 
> > > Any other features which are a must for the release? I dont see any.
> > 
> > please re-submit the patch in a clean form to the list, so anyone of
> > us developers can grap it to review. I'm definitly focusing to get
> > current cvs tree into freeze mode, so I'll try to review as much as
> > possible.
> > 
> > Stipe
> > 
> > [email protected]
> > -------------------------------------------------------------------
> > Wapme Systems AG
> > 
> > Münsterstr. 248
> > 40470 Düsseldorf
> > 
> > Tel: +49-211-74845-0
> > Fax: +49-211-74845-299
> > 
> > E-Mail: [email protected]
> > Internet: http://www.wapme-systems.de
> > -------------------------------------------------------------------
> > wapme.net - wherever you are
> > 
> > 
> 
>
smsc_at2.sim.patch (application/octet-stream, 16.9 KB)
Index: gw/smsc_at2.c
===================================================================
RCS file: /home/cvs/gateway/gw/smsc_at2.c,v
retrieving revision 1.37
diff -u -r1.37 smsc_at2.c
--- gw/smsc_at2.c	20 Mar 2002 16:06:49 -0000	1.37
+++ gw/smsc_at2.c	21 Mar 2002 09:51:52 -0000
@@ -47,6 +47,7 @@
     long	sendline_sleep;
     Octstr	*keepalive_cmd;
     int		broken;
+    Octstr	*message_storage;
 } ModemDef;
  
 /* maximum data to attempt to read in one go */
@@ -70,6 +71,10 @@
 /* The number of times to attempt to send a message should sending fail */
 #define RETRY_SEND 3
  
+/* defines for use with the so-called "SIM buffering techinique" :*/
+/* once in how many seconds to poll the memory locations, if keepalive is _not_ set (will use keepalive time if set) */
+#define AT2_DEFAULT_SMS_POLL_INTERVAL	60	
+
 typedef struct PrivAT2data
 {
     List	*outgoing_queue;
@@ -93,6 +98,9 @@
     Octstr	*sms_center;
     Octstr	*name;
     Octstr	*configfile;
+    int		sms_memory_poll_interval;
+    int		sms_memory_capacity;
+    int		sms_memory_usage;
 } PrivAT2data;
 
 
@@ -107,7 +115,7 @@
 void	at2_flush_buffer(PrivAT2data *privdata);
 int	at2_init_device(PrivAT2data *privdata);
 int	at2_send_modem_command(PrivAT2data *privdata,char *cmd, time_t timeout, int greaterflag);
-int	at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int greaterflag);
+int	at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int greaterflag, int* messages_collected);
 void	at2_set_speed(PrivAT2data *privdata, int bps);
 void	at2_device_thread(void *arg);
 int	at2_shutdown_cb(SMSCConn *conn, int finish_sending);
@@ -131,6 +139,8 @@
 int	at2_detect_modem_type(PrivAT2data *privdata);
 ModemDef *at2_read_modems(PrivAT2data *privdata, Octstr *file, Octstr *id, int idnumber);
 void	at2_destroy_modem(ModemDef *modem);
+void at2_read_sms_memory(PrivAT2data *privdata);
+int at2_check_sms_memory(PrivAT2data* privdata);
 
 /******************************************************************************
 ** For debugging purposes octstr_destroy might be a macro,
@@ -538,7 +548,7 @@
     	the next command. 10 sec should be suficient */
     	if(!privdata->pin_ready)
     	{
-   	   at2_wait_modem_command(privdata,10, 0);
+   	   at2_wait_modem_command(privdata,10, 0, NULL);
     	   if(!privdata->pin_ready) {
 	       at2_send_modem_command(privdata, "AT+CPIN?", 10, 0);
 	       if(!privdata->pin_ready) {
@@ -614,6 +624,20 @@
      ret = at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->init_string), 0, 0);
     	if(ret != 0)
     	    return -1;
+		
+    if (privdata->sms_memory_poll_interval && privdata->modem->message_storage) {
+    /* set message storage location for "SIM buffering" using the CPMS command */
+	Octstr *temp;
+	temp = octstr_create("AT+CPMS=");
+	octstr_append_char(temp, 34); // "
+	octstr_append(temp, privdata->modem->message_storage);
+	octstr_append_char(temp, 34); // "
+	ret = at2_send_modem_command(privdata, octstr_get_cstr(temp),0, 0);
+	octstr_destroy(temp);
+	if (ret != 0)
+	    return -1;
+    }
+    
     info(0, "AT2[%s]: AT SMSC successfully opened.", octstr_get_cstr(privdata->name));
     return 0;
 }
@@ -635,7 +659,7 @@
 int at2_send_modem_command(PrivAT2data *privdata,char *cmd, time_t timeout, int gt_flag)
 {
     at2_write_line(privdata,cmd);
-    return at2_wait_modem_command(privdata, timeout, gt_flag);
+    return at2_wait_modem_command(privdata, timeout, gt_flag, NULL);
 }
 
 
@@ -644,7 +668,7 @@
 ** waits for the modem to send us something
 */
 
-int at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int gt_flag)
+int at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int gt_flag, int* messages_collected)
 {
     Octstr *line = NULL;
     Octstr *line2 = NULL;
@@ -654,6 +678,7 @@
     time_t cur_time;
     Msg	*msg;
     int len;
+    int cmgr_flag = 0;
  
     time(&end_time);
     if(timeout == 0)
@@ -709,7 +734,8 @@
 	   	ret = 1;
 	   	goto end;
 	   }
-           if (-1 != octstr_search(line, octstr_imm("+CMT:"), 0))
+           if (-1 != octstr_search(line, octstr_imm("+CMT:"), 0) 
+			   || ((-1 != octstr_search(line, octstr_imm("+CMGR:"), 0)) && (cmgr_flag = 1)) )
            {
            	line2 = at2_wait_line(privdata,1,0);
  
@@ -730,14 +756,21 @@
 		    }
 		    else
 		    {
+		    	// count message even if I can't decode it
+			if (messages_collected)
+				++(*messages_collected);
 			msg = at2_pdu_decode(pdu, privdata);
                     	if(msg != NULL)
                     	{
 			    msg->sms.smsc_id = octstr_duplicate(privdata->conn->id);
                     	    bb_smscconn_receive(privdata->conn, msg);
                     	}
-                    	if(privdata->phase2plus)
-		    	    at2_write_line(privdata,"AT+CNMA");
+			
+			if (!cmgr_flag) {
+	                    	if(privdata->phase2plus)
+			    	    at2_write_line(privdata,"AT+CNMA");
+			}
+			
 			O_DESTROY(pdu);
 		    }
                 }
@@ -772,6 +805,136 @@
     return ret;
 }
 
+/*
+ * at2_read_sms_memory
+ * checks whether any messages are buffered in message storage and extract them.
+ */
+void at2_read_sms_memory(PrivAT2data* privdata)
+{
+	char cmd[20];
+
+	// get memory status
+	if (at2_check_sms_memory(privdata) == -1) 
+	{
+		debug("bb.smsc.at2",0,"AT2[%s]: memory check error",octstr_get_cstr(privdata->device));
+		return;
+	}
+
+	if (privdata->sms_memory_usage)
+	{ // that is - greater then 0, meaning there are some messages to fetch
+		// now - I used to just loop over the first input_mem_sms_used locations, but it doesn't
+		// hold, since under load, messages may be received while we're in the loop, and get stored
+		// in locations towards the end of the list, thus creating 'holes' in the memory.
+		// there are two ways we can fix this : (a) just read the last message location, delete it and return.
+		// it's not a complete solution since holes can still be created if messages are recieved between the
+		// memory check and the delete command, and anyway - it will slow us down and won't hold well under pressure
+		// (b) just scan the entire memory each call, bottom to top. this will be slow too, but it'll be reliable. 
+		//
+		// we can massivly improve performance by stopping after input_mem_sms_used messages have been read,
+		// but send_modem_command returns 0 for no message as well as for a message read, and the only other
+		// way to implement it is by doing memory_check after each read and stoping when input_mem_sms_used
+		// get to 0. this is slow (modem commands take time) so we improve speed only if there are less then
+		// 10 messages in memory.
+		// 
+		// I implemented the alternative - changed at2_wait_modem_command to return the number of messages it 
+		// collected
+		int i;
+		int message_count = 0; // cound number of messages collected
+
+		debug("bb.smsc.at2",0,"AT2[%s]: %d messages waiting in memory",octstr_get_cstr(privdata->device),privdata->sms_memory_usage);
+		
+		for (i = 1; i <= privdata->sms_memory_capacity && 
+			message_count < privdata->sms_memory_usage; ++i) 
+		{ // loop till end of memory or collected enouch messages
+			int old_message_count = message_count;
+			sprintf(cmd,"AT+CMGR=%d",i);
+			/* read one message from memory */
+			at2_write_line(privdata,cmd);
+			if (at2_wait_modem_command(privdata,0,0,&message_count) != 0)
+			{
+			   	debug("bb.smsc.at2",0,"AT2[%s]: failed to get message %d.",octstr_get_cstr(privdata->device),i);
+				continue; /* failed to read the message - skip to next message */
+			}
+
+			if (old_message_count == message_count) { /* no need to delete if no message collected */
+				debug("bb.smsc.at2",0,"AT2[%s]: not deleted.",octstr_get_cstr(privdata->device));
+				continue;
+			}
+			
+			sprintf(cmd,"AT+CMGD=%d",i); /* delete the message we just read */
+			if (at2_send_modem_command(privdata,cmd,7,0) != 0)
+			{  /* 3 seconds is not enough with some modems if the message is large - so we'll give it 7 seconds */
+			   	debug("bb.smsc.at2",0,"AT2[%s]: failed to delete message %d.",octstr_get_cstr(privdata->device),i);
+				continue; /* failed to delete the message, we'll just ignore it for now - this is bad, since
+							if the message really didn't get deleted - we'll see it next time around. */
+			}
+		}
+	}
+	//at2_send_modem_command(privdata, ModemTypes[privdata->modemid].init1, 0, 0);
+}
+
+/*
+ * at_check_sms_memory()
+ * Memory capacity and usage check
+ */
+int at2_check_sms_memory(PrivAT2data *privdata) 
+{
+	long values[4]; // array to put response data in
+	int pos; // position of parser in data stream
+	int ret; // return code
+	Octstr* search_cpms = NULL;
+
+	if ((ret = at2_send_modem_command(privdata, "AT+CPMS?",0,0)) != 0) //MEM_SELECT_COMMAND
+	{ // select memory type and get report
+		debug("bb.smsc.at2.memory_check",0,"failed to send mem select command to modem %d",ret);
+		return -1;
+	}
+
+	search_cpms = octstr_create("+CPMS:");
+
+	if ((pos = octstr_search(privdata->lines,search_cpms,0)) != -1)
+	{ // got back a +CPMS response
+		int index = 0; // index in values array
+		pos += 6; // position of parser in the stream - start after header
+		
+		pos = octstr_search(privdata->lines,octstr_imm(","),pos) +1 ; // skip memory indication
+		while (index < 4 && 
+			pos < octstr_len(privdata->lines) && 
+			(pos = octstr_parse_long(&values[index],privdata->lines,pos,10)) != -1)
+		{ // find all the values
+			++pos; // skip number seperator;
+			++index; // increment array index
+			if (index == 2)
+				pos = octstr_search(privdata->lines,octstr_imm(","),pos)+1; // skip second memory indication
+		}
+		
+		if (index < 4)
+		{ // didn't get all memory data - I don't why, so I'll bail
+		   	debug("bb.smsc.at2",0,"AT2[%s]: couldn't parse all memory locations : %d:'%s'.",
+				octstr_get_cstr(privdata->device), index,&(octstr_get_cstr(privdata->lines)[pos]));
+			O_DESTROY(search_cpms);
+			return -1;
+		}
+
+		privdata->sms_memory_usage = values[0];
+		privdata->sms_memory_capacity = values[1];
+		/*
+		privdata->output_mem_sms_used = values[2];
+		privdata->output_mem_sms_capacity = values[3];
+		*/
+		
+		ret = 0; // everything's cool
+		
+		//  clear the buffer
+		O_DESTROY(privdata->lines);
+	} else {
+	   	debug("bb.smsc.at2",0,"AT2[%s]: no correct header for CPMS response.",octstr_get_cstr(privdata->device));
+		ret = -1; // didn't get a +CPMS response - this is clearly an error
+	}
+
+	O_DESTROY(search_cpms);
+	return ret; 
+}
 
 /******************************************************************************
 ** at2_set_speed
@@ -844,7 +1007,7 @@
     PrivAT2data	*privdata = conn->data;
 
     int l, wait=0;
-    long idle_timeout;
+    long idle_timeout, memory_poll_timeout = 0;
    
     conn->status = SMSCCONN_CONNECTING;
     
@@ -918,7 +1081,7 @@
 	    at2_send_messages(privdata);
 	    idle_timeout = time(NULL);
 	} else
-	    at2_wait_modem_command(privdata,1,0);
+	    at2_wait_modem_command(privdata,1,0,NULL);
 
 	if(privdata->keepalive && 
 	   idle_timeout + privdata->keepalive < time(NULL)) {
@@ -930,6 +1093,12 @@
 	    }
 	    idle_timeout = time(NULL);
 	}
+		 
+	if (privdata->sms_memory_poll_interval &&
+	    memory_poll_timeout + privdata->sms_memory_poll_interval < time(NULL)) {
+	    at2_read_sms_memory(privdata);
+	    memory_poll_timeout = time(NULL);
+	}
    }
     at2_close_device(privdata);
     conn->status = SMSCCONN_DISCONNECTED;
@@ -1034,6 +1203,14 @@
 
     privdata->keepalive = 0;
     cfg_get_integer(&privdata->keepalive, cfg, octstr_imm("keepalive"));
+	
+    cfg_get_bool(&privdata->sms_memory_poll_interval, cfg, octstr_imm("sim-buffering"));
+    if (privdata->sms_memory_poll_interval) {
+    	if (privdata->keepalive)
+    		privdata->sms_memory_poll_interval = privdata->keepalive;
+    	else
+    		privdata->sms_memory_poll_interval = AT2_DEFAULT_SMS_POLL_INTERVAL;
+    }
 
     cfg_get_bool(&privdata->retry, cfg, octstr_imm("retry"));
     privdata->my_number = cfg_get(cfg, octstr_imm("my-number"));
@@ -1134,10 +1311,17 @@
 
     buffer = octstr_duplicate(line);
     /* find the beginning of a message from the modem*/ 
-    pos = octstr_search(buffer, octstr_imm("+CMT:"), 0);
-    if(pos == -1) 
+    if ( -1 != (pos = octstr_search(buffer, octstr_imm("+CMT:"), 0)) )
+    	pos +=5;
+    else if ( -1 != (pos = octstr_search(buffer, octstr_imm("+CMGR:"), 0)) ) {
+	pos += 6;
+	if ( -1 != (pos = octstr_search(buffer,octstr_imm(","),pos)) ) // skip status field in +CMGR response
+	    pos++;
+	else
+	    goto nomsg;
+    }
+    else
 	goto nomsg;
-    pos += 5;
 
     tmp = octstr_search(buffer, octstr_imm(","), pos);
     if(! privdata->modem->broken && tmp == -1)
@@ -1480,7 +1664,7 @@
 	    at2_write(privdata,command);
 	    at2_write_ctrlz(privdata);
         /* wait 20 secs for modem command */
-	    ret = at2_wait_modem_command(privdata, 20, 0);
+	    ret = at2_wait_modem_command(privdata, 20, 0, NULL);
 	    debug("bb.at", 0, "AT2[%s]: send command status: %d", 
 		  octstr_get_cstr(privdata->name), ret);
 	    if(ret != 0) /* OK only */
@@ -2030,6 +2214,10 @@
 	if(modem->keepalive_cmd == NULL)
 	    modem->keepalive_cmd = octstr_create("AT");
 
+        modem->message_storage = cfg_get(grp,octstr_imm("message-storage"));
+/*	if (modem->message_storage == NULL)
+	    modem->message_storage = octstr_create("SM");*/
+				    
 	cfg_get_bool(&modem->broken, grp, octstr_imm("broken"));
 
 	cfg_destroy(cfg);
@@ -2050,6 +2238,7 @@
 	O_DESTROY(modem->init_string);
 	O_DESTROY(modem->enable_hwhs);
 	O_DESTROY(modem->keepalive_cmd);
+	O_DESTROY(modem->message_storage);
 	gw_free(modem);
     }
 }
Index: gwlib/cfg.def
===================================================================
RCS file: /home/cvs/gateway/gwlib/cfg.def,v
retrieving revision 1.46
diff -u -r1.46 cfg.def
--- gwlib/cfg.def	21 Mar 2002 03:54:32 -0000	1.46
+++ gwlib/cfg.def	21 Mar 2002 09:51:52 -0000
@@ -161,6 +161,7 @@
     OCTSTR(smsc-username)
     OCTSTR(smsc-password)
     OCTSTR(keepalive)
+    OCTSTR(sim-buffering)
     OCTSTR(modemtype)
     OCTSTR(device)
     OCTSTR(speed)
@@ -312,6 +313,7 @@
     OCTSTR(sendline-sleep)
     OCTSTR(keepalive-cmd)
     OCTSTR(broken)
+    OCTSTR(message-storage)
 )
 
 #undef OCTSTR
Index: doc/modems.conf
===================================================================
RCS file: /home/cvs/gateway/doc/modems.conf,v
retrieving revision 1.2
diff -u -r1.2 modems.conf
--- doc/modems.conf	17 Mar 2002 16:03:37 -0000	1.2
+++ doc/modems.conf	21 Mar 2002 09:51:52 -0000
@@ -16,6 +16,7 @@
 # sendline-sleep = 100 [Default, miliseconds]
 # keepalive-cmd = "AT" [Default]
 # broken = false [Default]
+# message-storage = "SM"
 
 
 # If modemtype=auto, try everyone and defaults to this one
Index: doc/userguide/userguide.xml
===================================================================
RCS file: /home/cvs/gateway/doc/userguide/userguide.xml,v
retrieving revision 1.150
diff -u -r1.150 userguide.xml
--- doc/userguide/userguide.xml	21 Mar 2002 03:54:32 -0000	1.150
+++ doc/userguide/userguide.xml	21 Mar 2002 09:51:56 -0000
@@ -2592,6 +2592,22 @@
       	SMS Center to send messages.
      </entry></row>
 
+    <row><entry><literal>sim-buffering</literal></entry>
+      <entry><literal>boolean</literal></entry>
+      <entry valign=bottom>
+        Whether to enable the so-called "SIM buffering behaviour" of the GSM module.
+                if assigned a true value, the module will query the message storage memory
+                of the modem and will process and delete any messages found there. this does
+                not alter normal behaviour, but only add the capability of reading messages that
+                were stored in the memory for some reason. The type of memory to use can be
+                selected using the 'message-storage' parameter of the modem configuration.
+                Polling the memory is done at the same interval as keepalive (if set) or 60 seconds
+                (if not set).
+                NOTE: This behaviour is known to cause minor or major hicups for a few buggy modems.
+                A modem known not to like this setting is Siemens M20.
+                A modem known to work with this setting is Wavecom.
+     </entry></row>
+
    </tbody></tgroup></informaltable>
 
    <para>Modem definitions are now multiple groups present in kannel.conf,
@@ -2705,6 +2721,18 @@
 	see in logs the reply "+CBC: 0,64" (0=On batery, 64% 
 	full) and "+CSQ: 14,99" (0-31, 0-7: signal strenght and
 	channel bit error rate; 99 for unknown). See 3GPP 27007.
+     </entry></row>
+
+   <row><entry><literal>message-storage</literal></entry>
+     <entry><literal>string</literal></entry>
+     <entry valign=bottom>
+        Message storage memory type to enable for "SIM buffering".
+                Possible values are: "SM" - SIM card memory or "ME" -
+                Mobile equipment memory (may not be suppoerted by your
+                modem). check your modem's manual for more types.
+                By default, if the option is not set, no message storage command
+                will be sent to the modem and the modem's default message
+                storage will be used (usually "SM").
      </entry></row>
 
    </tbody></tgroup></informaltable>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.