FreeCalypso > hg > fc-magnetite
view src/aci2/aci/conc_sms.c @ 349:09b12bd1b0f2
charging control AT command: make it AT@CHG instead of AT@CHARGE
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 16 Dec 2017 06:05:53 +0000 |
parents | 93999a60b835 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : $Workfile:: | Modul : CONC_SMS +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : SMS Concatenation Handler +----------------------------------------------------------------------------- */ #ifndef CONC_SMS_C #define CONC_SMS_C #endif /*==== INCLUDES ===================================================*/ #include "aci_all.h" #include "aci_cmh.h" #include "ati_cmd.h" #include "aci_cmd.h" #include "aci_fd.h" #include "aci_mem.h" #include "psa.h" #include "psa_sms.h" #include "cmh.h" #include "cmh_sms.h" #include "psa_cc.h" #include "typedefs.h" #include "aci_lst.h" #include "conc_sms.h" #ifdef _CONC_TESTING_ #include "aci_io.h" #include "aci_mfw.h" #endif /*==== VARIABLES ==================================================*/ GLOBAL T_SM_ASSEMBLY assembly_list[MAX_BUF_ELEMS]; GLOBAL T_SEG_BUF segBuf_list [MAX_BUF_ELEMS]; GLOBAL T_CONC_BUF concBuf_list [MAX_CONC_BUF_ELEMS]; LOCAL USHORT RefNum_Del = 0xFF; LOCAL BOOL dFLAG = FALSE; LOCAL CHAR Addres[MAX_SMS_ADDR_DIG]; /*==== FUNCTIONS ==================================================*/ LOCAL void concSMS_printConcatList (); LOCAL USHORT concSMS_findMaxRefNum(void); // Marcus: Issue 872: 03/10/2002 /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_findSeqNumSB | +--------------------------------------------------------------------+ PURPOSE : find 'seq_num' in segment buffer */ LOCAL BOOL concSMS_findSeqNumSB ( UBYTE critrerium, void *elem ) { T_SEG_BUF_ELEM *compared = (T_SEG_BUF_ELEM *)elem; if ( compared->seq_num == critrerium ) return TRUE; else return FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_findSeqNumElemCB | +--------------------------------------------------------------------+ PURPOSE : find 'seq_num' in concatenation buffer */ LOCAL BOOL concSMS_findSeqNumElemCB ( UBYTE critrerium, void *elem ) { T_CONC_BUF_ELEM *compared = (T_CONC_BUF_ELEM *)elem; if ( compared->seq_num == critrerium ) return TRUE; else return FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_findRecNumElemCB | +--------------------------------------------------------------------+ PURPOSE : find 'rec_num' in concatenation buffer */ LOCAL BOOL concSMS_findRecNumElemCB ( UBYTE critrerium, void *elem ) { T_CONC_BUF_ELEM *compared = (T_CONC_BUF_ELEM *)elem; if ( compared->rec_num == critrerium ) return TRUE; else return FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_getAsBuffer | +--------------------------------------------------------------------+ PURPOSE : This functions searchs the assembly buffer for ref_num and address. */ LOCAL T_SM_ASSEMBLY* concSMS_getAsBuffer( USHORT ref_num, CHAR *address ) { UBYTE i; TRACE_FUNCTION ("concSMS_getAsBuffer()"); /* search for the element */ for (i=0; i<MAX_BUF_ELEMS; i++) { if ( (assembly_list[i].ref_num EQ ref_num) AND (assembly_list[i].in_use) ) { if ((address NEQ NULL) /* AND (address[0] NEQ '\0') */) { if (!strcmp(assembly_list[i].address, address)) { return &assembly_list[i]; } } else { return &assembly_list[i]; } } } return NULL; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_addToAsBuffer | +--------------------------------------------------------------------+ PURPOSE : This function adds data to the assembly buffer. It returns NULL if buffer is full. */ LOCAL T_SM_ASSEMBLY* concSMS_addToAsBuffer ( USHORT ref_num, CHAR *address, UBYTE max_num, T_SM_DATA_EXT *data ) { UBYTE i; T_SM_ASSEMBLY *assembly_elem = NULL; TRACE_FUNCTION ("concSMS_addToAsBuffer()"); /* search for the element */ assembly_elem = concSMS_getAsBuffer( ref_num, address ); #ifdef _CONC_TESTING_ TRACE_EVENT_P1("addToAsBuffer:[0].in_use: %d", assembly_list[0].in_use); TRACE_EVENT_P1("addToAsBuffer:[1].in_use: %d", assembly_list[1].in_use); #endif /* element not found */ if (assembly_elem EQ NULL) { /* search for an unused list entry */ for (i=0; i<MAX_BUF_ELEMS; i++) { if (assembly_list[i].in_use EQ FALSE) { assembly_elem = &assembly_list[i]; break; } } /* buffer is full */ if (assembly_elem EQ NULL) return NULL; /* create new assembly buffer for this ref_num*/ assembly_elem->in_use = TRUE; assembly_elem->ref_num = ref_num; if ( (address NEQ NULL) AND (address[0] NEQ '\0') ) strcpy(assembly_elem->address, address); else assembly_elem->address[0] = '\0'; assembly_elem->next_exp_num = 1; assembly_elem->segs_left = max_num; assembly_elem->seg_count = 0; } /* if (assembly_elem EQ NULL) */ if (assembly_elem->seg_count EQ 0) { /* alloc memory for data to assemble */ UBYTE segs; segs = MINIMUM(assembly_elem->segs_left, CONC_MAX_SEGS); ACI_MALLOC(assembly_elem->data.data, (USHORT)(MAX_SM_LEN*segs)); assembly_elem->segs_left -= segs; assembly_elem->data.len = 0; } memcpy(assembly_elem->data.data+assembly_elem->data.len, data->data, data->len); assembly_elem->data.len += data->len; assembly_elem->data.data[assembly_elem->data.len] = '\0'; assembly_elem->next_exp_num++; assembly_elem->seg_count++; #ifdef _CONC_TESTING_ if (assembly_elem->data.len < TTRACE_LEN) { TRACE_EVENT_P1("addToAsBuffer:data.data: %s", assembly_elem->data.data); } TRACE_EVENT_P1("addToAsBuffer:data.len: %d", assembly_elem->data.len); TRACE_EVENT_P1("addToAsBuffer:next_exp_num: %d", assembly_elem->next_exp_num); TRACE_EVENT_P1("addToAsBuffer:seg_count: %d", assembly_elem->seg_count); #endif return assembly_elem; } /* +---------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_removeFromAsBuffer | +---------------------------------------------------------------------+ PURPOSE : This functions gets data from the assembly buffer and sets it to 'unused'. The assembly is completed. */ LOCAL UBYTE concSMS_removeFromAsBuffer(T_SM_DATA_EXT *data_conc, USHORT ref_num, CHAR *address) { T_SM_ASSEMBLY *assembly_buf; TRACE_FUNCTION ("concSMS_removeFromAsBuffer()"); /* search for the element */ assembly_buf = concSMS_getAsBuffer( ref_num, address ); if (assembly_buf EQ NULL) return FALSE; assembly_buf->in_use = FALSE; data_conc->data = assembly_buf->data.data; data_conc->len = assembly_buf->data.len; return TRUE; } /* +---------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_getFromAsBuffer | +---------------------------------------------------------------------+ PURPOSE : This functions gets data from the assembly buffer and resets the seg_count. The assembly buffer is still in use and the assembly is not completed. */ LOCAL UBYTE concSMS_getFromAsBuffer(T_SM_DATA_EXT *data_conc, USHORT ref_num, CHAR *address) { T_SM_ASSEMBLY *assembly_buf; TRACE_FUNCTION ("concSMS_getFromAsBuffer()"); /* search for the element */ assembly_buf = concSMS_getAsBuffer( ref_num, address ); /* assemlby buffer not found */ if (assembly_buf EQ NULL) return FALSE; assembly_buf->seg_count = 0; data_conc->data = assembly_buf->data.data; data_conc->len = assembly_buf->data.len; return TRUE; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_getSegBuffer | +--------------------------------------------------------------------+ PURPOSE : This functions searchs the segment buffer for ref_num and address. */ LOCAL T_SEG_BUF* concSMS_getSegBuffer( USHORT ref_num, CHAR *address ) { UBYTE i; TRACE_FUNCTION ("concSMS_getSegBuffer()"); /* search for the element */ for (i=0; i<MAX_BUF_ELEMS; i++) { if ((segBuf_list[i].ref_num EQ ref_num) AND (segBuf_list[i].in_use)) { if ((address NEQ NULL) /* AND (address[0] NEQ '\0') */) { if (!strcmp(segBuf_list[i].address, address)) return &segBuf_list[i]; } else { return &segBuf_list[i]; } } } return NULL; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_addToSegBuffer | +--------------------------------------------------------------------+ PURPOSE : This functions adds one segment to the buffer and returns FALSE if no segment buffer is available or the current seg buffer is full. */ LOCAL UBYTE concSMS_addToSegBuffer ( USHORT ref_num, CHAR *address, UBYTE seq_num, UBYTE rec_num, T_ACI_SMS_STAT status, T_SM_DATA_EXT *data ) { T_SEG_BUF *segBuf = NULL; T_SEG_BUF_ELEM *segBufElem; USHORT count; UBYTE i; TRACE_FUNCTION ("concSMS_addToSegBuffer()"); /* search for the segment buffer */ segBuf = concSMS_getSegBuffer( ref_num, address ); /* element not found */ if (segBuf EQ NULL) { /* search for an unused list entry */ for (i=0; i<MAX_BUF_ELEMS; i++) { if (segBuf_list[i].in_use EQ FALSE) { segBuf = &segBuf_list[i]; break; } } /* no segment buffer available */ if ( segBuf EQ NULL) return FALSE; /* initialise new buffer */ segBuf->in_use = TRUE; segBuf->ref_num = ref_num; if ( (address) AND (address[0] NEQ '\0') ) strcpy(segBuf->address, address); else segBuf->address[0] = '\0'; segBuf->list = new_list(); } count = get_list_count(segBuf->list); if ( count >= CONC_MAX_SEGS ) { /* clean segment buffer before it overflows */ while (1) { segBufElem = remove_first_element(segBuf->list); if (segBufElem EQ NULL) break; ACI_MFREE(segBufElem->data.data); ACI_MFREE(segBufElem); } segBuf->in_use = FALSE; return FALSE; } /* create new segment buffer element */ ACI_MALLOC(segBufElem, sizeof(T_SEG_BUF_ELEM)); memset(segBufElem, 0, sizeof(T_SEG_BUF_ELEM)); /* fill new buffer element */ segBufElem->seq_num = seq_num; segBufElem->rec_num = rec_num; segBufElem->status = status; /* alloc memory and copy user data to segment buffer */ ACI_MALLOC(segBufElem->data.data, data->len); segBufElem->data.len = data->len; memcpy(segBufElem->data.data, data->data, data->len); /* insert element (segment) into the segment buffer */ insert_list(segBuf->list, segBufElem); return TRUE; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_removeFromSegBuffer| +--------------------------------------------------------------------+ PURPOSE : This function finds and removes the segment with 'seq_num' from the segment buffer. */ LOCAL T_SEG_BUF_ELEM* concSMS_removeFromSegBuffer ( USHORT ref_num, CHAR* address, UBYTE seq_num ) { T_SEG_BUF *segBuf = NULL; T_SEG_BUF_ELEM *segBufElem; USHORT count; TRACE_FUNCTION ("concSMS_removeFromSegBuffer()"); /* search for the segment buffer */ segBuf = concSMS_getSegBuffer( ref_num, address ); /* segment buffer not found */ if (segBuf EQ NULL) return NULL; segBufElem = remove_element(segBuf->list, seq_num, concSMS_findSeqNumSB); if (segBufElem EQ NULL) { return NULL; /* didn't find the segment buffer element for this seq_num */ } count = get_list_count(segBuf->list); if (count EQ 0) { ACI_MFREE (segBuf->list); segBuf->list = NULL; segBuf->in_use = FALSE; } return segBufElem; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_getConcBuffer | +--------------------------------------------------------------------+ PURPOSE : This functions searchs the concatenations buffer for ref_num and address. */ LOCAL T_CONC_BUF* concSMS_getConcBuffer( USHORT ref_num, CHAR *address ) { UBYTE i; TRACE_FUNCTION ("concSMS_getConcBuffer()"); /* search for the element */ for (i=0; i<MAX_CONC_BUF_ELEMS; i++) { if ((concBuf_list[i].ref_num EQ ref_num) AND (concBuf_list[i].in_use)) { if ((address NEQ NULL) /* AND (address[0] NEQ '\0') */) { if (!strcmp(concBuf_list[i].address, address)) { return &concBuf_list[i]; } } else { return &concBuf_list[i]; } } } return NULL; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_addToConcatList | +--------------------------------------------------------------------+ PURPOSE : */ LOCAL BOOL concSMS_addToConcatList ( USHORT ref_num, CHAR *address, UBYTE max_num, UBYTE seq_num, UBYTE rec_num, T_ACI_SMS_STAT status ) { T_CONC_BUF *concBuf; T_CONC_BUF_ELEM *concBufElem; UBYTE i; TRACE_FUNCTION ("concSMS_addToConcatList()"); /* search for concatenation buffer */ concBuf = concSMS_getConcBuffer( ref_num, address ); /* element not found */ if (concBuf EQ NULL) { /* search for an unused list entry */ for (i=0; i<MAX_CONC_BUF_ELEMS; i++) { if (concBuf_list[i].in_use EQ FALSE) { concBuf = &concBuf_list[i]; break; } } /* buffer is full */ if ( concBuf EQ NULL) return FALSE; concBuf->in_use = TRUE; concBuf->ref_num = ref_num; if ( (address) AND (address[0] NEQ '\0') ) strcpy(concBuf->address, address); else concBuf->address[0] = '\0'; concBuf->max_num = max_num; concBuf->list = new_list(); } /* don't add elements with same seq_num to the Concatenation Buffer */ concBufElem = find_element(concBuf->list,seq_num,concSMS_findSeqNumElemCB); if (concBufElem) return FALSE; /* create new conc. buffer element */ ACI_MALLOC(concBufElem, sizeof(T_CONC_BUF_ELEM)); concBufElem->seq_num = seq_num; concBufElem->rec_num = rec_num; concBufElem->status = status; /* insert element into the conc. buffer */ insert_list(concBuf->list, concBufElem); concSMS_printConcatList(); return TRUE; } /* +---------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_removeFromConcatList| +---------------------------------------------------------------------+ PURPOSE : This function removes and FREES the memory for the element. */ LOCAL T_ACI_LIST *concSMS_removeFromConcatList ( USHORT ref_num, CHAR *address, UBYTE rec_num ) { T_CONC_BUF *concBuf = NULL; T_CONC_BUF_ELEM *concBufElem; USHORT count; TRACE_FUNCTION ("concSMS_removeFromConcatList()"); /* search for concatenation buffer */ concBuf = concSMS_getConcBuffer( ref_num, address ); /* concatenation buffer not found */ if (concBuf EQ NULL) { TRACE_EVENT_P1("conc_buf NULL: rec: %d", rec_num); return NULL; } concBufElem = remove_element(concBuf->list, rec_num, concSMS_findRecNumElemCB); if (concBufElem EQ NULL) { TRACE_EVENT_P1("concBufElem NULL: rec: %d", rec_num); return NULL; } /* free memory for this element */ ACI_MFREE(concBufElem); count = get_list_count(concBuf->list); if (count EQ 0) { ACI_MFREE (concBuf->list); concBuf->list = NULL; concBuf->in_use = FALSE; return NULL; } return concBuf->list; } /* +---------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_sortConcatList | +---------------------------------------------------------------------+ PURPOSE : This function sorts the concat. buffer acc. to its seq_num. */ LOCAL void concSMS_sortConcatList ( USHORT ref_num, CHAR *address ) { T_CONC_BUF *concBuf = NULL; T_CONC_BUF_ELEM *concBufElem; UBYTE seq_num; UBYTE rec_num = 0; T_ACI_LIST *oldlist, *newlist, *current; USHORT count; TRACE_FUNCTION ("concSMS_sortConcatList()"); /* search for concatenation buffer */ concBuf = concSMS_getConcBuffer( ref_num, address ); /* concatenation buffer not found */ if (concBuf EQ NULL) return; newlist = new_list(); oldlist = concBuf->list; count = get_list_count(oldlist); while (count) { seq_num = 255; current = oldlist; while (current) { concBufElem = (T_CONC_BUF_ELEM*)current->msg; if ( concBufElem->seq_num < seq_num ) { seq_num = concBufElem->seq_num; rec_num = concBufElem->rec_num; } current = current->next; } concBufElem = remove_element(oldlist, rec_num, concSMS_findRecNumElemCB); insert_list(newlist, concBufElem); count = get_list_count(oldlist); } if (concBuf->list) { ACI_MFREE (concBuf->list); concBuf->list = NULL; } concBuf->list = newlist; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_split | +--------------------------------------------------------------------+ PURPOSE : return TRUE if splitting was done, otherwise FALSE */ LOCAL UBYTE concSMS_split ( T_ACI_SM_DATA* tar_data, T_SM_DATA_EXT* src_data, UBYTE alphabet, T_EXT_CMS_CMD_ID id) { static UBYTE sref_num = 0; /* Temp variable for the value returned by concSMS_findMaxRefNum() */ UBYTE t_num = 0; TRACE_FUNCTION ("concSMS_split ()"); if (alphabet EQ 0x00) { /* 7-bit data coding scheme */ if (src_data->len <= concShrdPrm.l_uncomp7bit_data) { tar_data->len = (UBYTE)src_data->len; memcpy ( tar_data->data, src_data->data, tar_data->len ); return FALSE; } else { tar_data->len = concShrdPrm.l_uncomp7bit_data_conc; concShrdPrm.max_sms_len = concShrdPrm.l_uncomp7bit_data_conc; } } else { /* 8-bit data coding scheme */ if (src_data->len <= concShrdPrm.l_uncomp8bit_data) { tar_data->len = (UBYTE)src_data->len; memcpy ( tar_data->data, src_data->data, tar_data->len ); return FALSE; } else { tar_data->len = concShrdPrm.l_uncomp8bit_data_conc; concShrdPrm.max_sms_len = concShrdPrm.l_uncomp8bit_data_conc; } } /* copy first segment to 'tar_data' */ memcpy ( tar_data->data, src_data->data, tar_data->len ); concShrdPrm.udh.ref_num = (UBYTE)concSMS_findMaxRefNum(); /* Marcus: Issue 872: 03/10/2002 */ t_num = concShrdPrm.udh.ref_num++; concShrdPrm.udh.max_num = (src_data->len+(concShrdPrm.max_sms_len-1)) / concShrdPrm.max_sms_len; concShrdPrm.udh.seq_num = 1; if (id EQ CMGS_CONC) { /* sref_num assigned the value depending on the value returned by concSMS_findMaxRefNum() and the value already stored in the sref_num so that for every sent conc SMS reference number value will be different */ sref_num=((sref_num+1 > t_num)? (sref_num) : t_num)+1; concShrdPrm.udh.ref_num = sref_num; concShrdPrm.specPrm.concCMGS.data.len = src_data->len; concShrdPrm.specPrm.concCMGS.data.data = src_data->data; concShrdPrm.specPrm.concCMGS.offset = tar_data->len; return TRUE; } if (id EQ CMGW_CONC) { concShrdPrm.specPrm.concCMGW.data.len = src_data->len; concShrdPrm.specPrm.concCMGW.data.data = src_data->data; concShrdPrm.specPrm.concCMGW.offset = tar_data->len; return TRUE; } return FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_fillUDH | +--------------------------------------------------------------------+ PURPOSE : */ LOCAL void concSMS_fillUDH ( T_ACI_UDH_DATA* udh, UBYTE ref_num, UBYTE max_num, UBYTE seq_num ) { /* fill user data header structure for 8-bit ref number */ udh->len = 0x05; /* Information Element Identifier */ udh->data[0] = SMS_IEI_CONC_8BIT; /* Information Element Identifier Length */ udh->data[1] = 0x03; /* Information Element Data */ udh->data[2] = (UBYTE)(ref_num & 0x00FF); /* since we use only 8-Bit ref number */ udh->data[3] = max_num; udh->data[4] = seq_num; } /********************** Init Functions *********************************/ /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_retrieveConcBuf | +--------------------------------------------------------------------+ PURPOSE : This function searches for the concatenation buffer which has 'index' in its first element. Returns 'CONC_ERROR' if index is not the first element or list is incomplete. */ LOCAL T_CONC_INIT_RETURN concSMS_retrieveConcBuf ( T_CONC_BUF **concBuf, UBYTE index ) { UBYTE i; T_CONC_BUF_ELEM *concBufElem; USHORT count; TRACE_FUNCTION ("concSMS_retrieveConcBuf ()"); *concBuf = NULL; for (i=0; i<MAX_CONC_BUF_ELEMS; i++) { concSMS_printConcatList(); /* find conc. buffer element for this rec number */ concBufElem = find_element(concBuf_list[i].list, index, concSMS_findRecNumElemCB); /* element found */ if (concBufElem NEQ NULL) { break; } } if (concBufElem EQ NULL) { /* no concatenation handler needed */ return CONC_NOT_NEEDED; } *concBuf = &concBuf_list[i]; count = get_list_count((*concBuf)->list); /* check if rec number is the first segment (with seq_num == 1) */ if ( ( concBufElem->seq_num EQ 1 ) AND ( smsShrdPrm.status EQ CMGD_DEL_INDEX ) ) { *concBuf = &concBuf_list[i]; count = get_list_count((*concBuf)->list); /* check if concat. list is complete */ if (count EQ (*concBuf)->max_num) { return CONC_NEEDED; } } else if( smsShrdPrm.status > CMGD_DEL_INDEX ) { /* The below check needs to be changed for deleting all the concatmessages in case of DELET FLAG > 0. */ *concBuf = &concBuf_list[i]; count = get_list_count((*concBuf)->list); return CONC_NEEDED; } /* rec number is not the first element in conc. buffer * allow reading of incomplete segments and tread them like "normal" SMS */ return CONC_NOT_NEEDED; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_initSendFromMem | +--------------------------------------------------------------------+ PURPOSE : This function initialises shared parameter for CMSS. */ GLOBAL T_CONC_INIT_RETURN concSMS_initSendFromMem ( T_ACI_CMD_SRC srcId, UBYTE *index, CHAR *da, T_ACI_TOA *toda ) { T_CONC_BUF *concBuf = NULL; T_CONC_BUF_ELEM* elem = NULL; T_CONC_INIT_RETURN ret = CONC_ERROR; T_CONC_CMSS *prm = &concShrdPrm.specPrm.concCMSS; TRACE_FUNCTION ("concSMS_initSendFromMem ()"); ret = concSMS_retrieveConcBuf ( &concBuf, *index ); if (ret EQ CONC_ERROR) { /* Error: segment is not the first segment of the SM */ return CONC_ERROR; } if (ret EQ CONC_NOT_NEEDED) { /* no conatenation handler needed */ return CONC_NOT_NEEDED; } concShrdPrm.sentSegs = 0; concShrdPrm.srcId = srcId; if (da) { memcpy(prm->da, da, strlen(da)); prm->da[strlen(da)] = '\0'; prm->p_da = prm->da; } else { prm->p_da = NULL; } if (toda) { memcpy(&prm->toda, toda, sizeof(T_ACI_TOA)); prm->p_toda = &prm->toda; } else { prm->p_toda = NULL; } /* save the first concatenated buffer element */ prm->currConcBufListElem = concBuf->list; prm->skipStoSent = TRUE; /* skip segments with status SMS_STAT_StoSent */ while (prm->currConcBufListElem) { elem = (T_CONC_BUF_ELEM*)prm->currConcBufListElem->msg; if (elem->status EQ SMS_STAT_StoSent) { prm->currConcBufListElem = prm->currConcBufListElem->next; } else { break; } } /* * All elements were set to SMS_STAT_StoSent. Assume that this message was * sent completly and should be sent for the second time. */ if (prm->currConcBufListElem EQ NULL) { prm->skipStoSent = FALSE; /* save the first concatenated buffer element */ prm->currConcBufListElem = concBuf->list; elem = (T_CONC_BUF_ELEM*)prm->currConcBufListElem->msg; } *index = elem ? elem->rec_num : NULL; if (elem NEQ NULL) { elem->status = SMS_STAT_StoSent; } return CONC_NEEDED; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_initReadFromMem | +--------------------------------------------------------------------+ PURPOSE : This function initialises shared parameter for CMGR. */ GLOBAL T_CONC_INIT_RETURN concSMS_initReadFromMem ( T_ACI_CMD_SRC srcId, UBYTE index, T_ACI_SMS_READ rdMode ) { T_CONC_BUF *concBuf; T_CONC_INIT_RETURN ret; TRACE_FUNCTION ("concSMS_initReadFromMem ()"); ret = concSMS_retrieveConcBuf ( &concBuf, index ); if (ret EQ CONC_ERROR) { /* Error: segment is not the first segment of the SM */ return CONC_ERROR; } if (ret EQ CONC_NOT_NEEDED) { /* no conatenation handler needed */ return CONC_NOT_NEEDED; } concShrdPrm.srcId = srcId; concShrdPrm.specPrm.concCMGR.rdMode = rdMode; /* save the second concatenated buffer element */ concShrdPrm.specPrm.concCMGR.currConcBufListElem = concBuf->list->next; return CONC_NEEDED; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_initDeleteFromMem | +--------------------------------------------------------------------+ PURPOSE : This function initialises shared parameter for CMGD. */ GLOBAL T_CONC_INIT_RETURN concSMS_initDeleteFromMem ( T_ACI_CMD_SRC srcId, UBYTE index ) { T_CONC_BUF *concBuf; T_CONC_INIT_RETURN ret; TRACE_FUNCTION ("concSMS_initDeleteFromMem ()"); ret = concSMS_retrieveConcBuf ( &concBuf, index ); if (ret EQ CONC_ERROR) { /* Error: segment is not the first segment of the SM */ return CONC_ERROR; } if (ret EQ CONC_NOT_NEEDED) { if (concBuf NEQ NULL) { RefNum_Del = concBuf->ref_num; } /*else if (*/ else if (dFLAG EQ TRUE) { TRACE_EVENT("BUFFER FULL"); } else { RefNum_Del = 0xFF; } /* no conatenation handler needed */ return CONC_NOT_NEEDED; } /* save the concatenation list */ concShrdPrm.specPrm.concCMGD.currConcBufListElem = concBuf->list; concShrdPrm.specPrm.concCMGD.ref_num = concBuf->ref_num; concShrdPrm.specPrm.concCMGD.address = concBuf->address; concShrdPrm.srcId = srcId; concShrdPrm.specPrm.concCMGD.error_count = 0; return CONC_NEEDED; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_initSend | +--------------------------------------------------------------------+ PURPOSE : This function initialises shared parameter for CMGS. */ GLOBAL T_CONC_INIT_RETURN concSMS_initSend ( T_ACI_SM_DATA* tar_data, T_ACI_UDH_DATA* udh, T_ACI_CMD_SRC srcId, CHAR* da, T_ACI_TOA* toda, T_SM_DATA_EXT* src_data, CHAR* sca, T_ACI_TOA* tosca, SHORT isReply, UBYTE alphabet ) { UBYTE ret; T_CONC_CMGS *prm = &concShrdPrm.specPrm.concCMGS; TRACE_FUNCTION ("concSMS_initSend ()"); ret = concSMS_split ( tar_data, src_data, alphabet, CMGS_CONC ); if ( ret EQ FALSE ) return CONC_NOT_NEEDED; concShrdPrm.srcId = srcId; if (da) { memcpy(prm->da, da, strlen(da)); prm->da[strlen(da)] = '\0'; prm->p_da = prm->da; } else { prm->p_da = NULL; } if (toda) { memcpy(&prm->toda, toda, sizeof(T_ACI_TOA)); prm->p_toda = &prm->toda; } else { prm->p_toda = NULL; } prm->data.len = src_data->len; prm->data.data = src_data->data; if (sca) { memcpy(prm->sca, sca, strlen(sca)); prm->sca[strlen(sca)] = '\0'; prm->p_sca = prm->sca; } else { prm->p_sca = NULL; } if (tosca) { memcpy(&prm->tosca, tosca, sizeof(T_ACI_TOA)); prm->p_tosca = &prm->tosca; } else { prm->p_tosca = NULL; } prm->isReply = isReply; prm->sent_bytes = 0; concShrdPrm.sentSegs = 0; /* fill user data header structure */ concSMS_fillUDH ( udh, concShrdPrm.udh.ref_num, concShrdPrm.udh.max_num, concShrdPrm.udh.seq_num ); return CONC_NEEDED; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_initStoreInMem | +--------------------------------------------------------------------+ PURPOSE : This function initialises shared parameter for CMGW. */ GLOBAL T_CONC_INIT_RETURN concSMS_initStoreInMem ( T_ACI_SM_DATA* tar_data, T_ACI_UDH_DATA* udh, T_ACI_CMD_SRC srcId, SHORT index, CHAR* address, T_ACI_TOA* toa, T_ACI_SMS_STAT stat, UBYTE msg_ref, T_SM_DATA_EXT* src_data, CHAR* sca, T_ACI_TOA* tosca, SHORT isReply, UBYTE alphabet ) { T_CONC_INIT_RETURN ret; T_CONC_CMGW *prm = &concShrdPrm.specPrm.concCMGW; TRACE_FUNCTION ("concSMS_initStoreInMem ()"); ret = concSMS_split ( tar_data, src_data, alphabet, CMGW_CONC ); if ( ret EQ FALSE ) { return CONC_NOT_NEEDED; } concShrdPrm.srcId = srcId; if (address) { memcpy(prm->da, address, strlen(address)); prm->da[strlen(address)] = '\0'; prm->p_da = prm->da; } else { prm->p_da = NULL; } if (toa) { memcpy(&prm->toda, toa, sizeof(T_ACI_TOA)); prm->p_toda = &prm->toda; } else { prm->p_toda = NULL; } if ( stat NEQ SMS_STAT_NotPresent) { prm->stat = stat; } else { prm->stat = SMS_STAT_StoUnsent; } prm->msg_ref = msg_ref; prm->data.len = src_data->len; prm->data.data = src_data->data; if (sca) { memcpy(prm->sca, sca, strlen(sca)); prm->sca[strlen(sca)] = '\0'; prm->p_sca = prm->sca; } else { prm->p_sca = NULL; } if (tosca) { memcpy(&prm->tosca, tosca, sizeof(T_ACI_TOA)); prm->p_tosca = &prm->tosca; } else { prm->p_tosca = NULL; } prm->isReply = isReply; /* fill user data header structure */ concSMS_fillUDH ( udh, concShrdPrm.udh.ref_num, concShrdPrm.udh.max_num, concShrdPrm.udh.seq_num ); return CONC_NEEDED; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_initCommand | +--------------------------------------------------------------------+ PURPOSE : This function initialises shared parameter for CMGC. */ GLOBAL T_CONC_INIT_RETURN concSMS_initCommand ( T_ACI_CMD_SRC srcId, SHORT fo, SHORT ct, SHORT pid, SHORT mn, CHAR* da, T_ACI_TOA* toda, T_ACI_CMD_DATA* data ) { T_CONC_CMGC *prm = &concShrdPrm.specPrm.concCMGC; TRACE_FUNCTION ("concSMS_initCommand ()"); if ( ct NEQ COMMAND_TYPE_DELETE) return CONC_NOT_NEEDED; if ((mn < concShrdPrm.first_mr) OR (mn > concShrdPrm.first_mr + concShrdPrm.sentSegs-1)) return CONC_NOT_NEEDED; if ( mn NEQ concShrdPrm.first_mr) { /* Error: segment is not the first segment of the SM */ return CONC_ERROR; } else { concShrdPrm.srcId = srcId; prm->command_count = 0; prm->fo = (UBYTE)fo; prm->ct = (UBYTE)ct; prm->pid = (UBYTE)pid; if (da) { memcpy(prm->da, da, strlen(da)); prm->da[strlen(da)] = '\0'; prm->p_da = prm->da; } else { prm->p_da = NULL; } if (toda) { memcpy(&prm->toda, toda, sizeof(T_ACI_TOA)); prm->p_toda = &prm->toda; } else { prm->p_toda = NULL; } ACI_MALLOC(prm->data.data, MAX_SM_CMD_LEN); memcpy ( prm->data.data, data->data, data->len ); prm->data.len = data->len; } return CONC_NEEDED; } /********************** RAT Callback Fucntions ****************************/ GLOBAL void rConcSMS_PlusCMSS (UBYTE mr, UBYTE numSeg) { UBYTE index; T_CONC_BUF_ELEM* elem; T_CONC_CMSS *prm = &concShrdPrm.specPrm.concCMSS; TRACE_FUNCTION ("rConcSMS_PlusCMSS()"); /* save the first message reference */ if (concShrdPrm.sentSegs EQ 0) { concShrdPrm.first_mr = mr; } /* increment number of successfully sent elements */ concShrdPrm.sentSegs++; /* get next concat. list element */ prm->currConcBufListElem = prm->currConcBufListElem->next; if (prm->skipStoSent) { /* skip segments with status SMS_STAT_StoSent */ while (prm->currConcBufListElem) { elem = (T_CONC_BUF_ELEM*)prm->currConcBufListElem->msg; if (elem->status EQ SMS_STAT_StoSent) { prm->currConcBufListElem = prm->currConcBufListElem->next; } else { break; } } /* while */ } if (prm->currConcBufListElem NEQ NULL) { elem = (T_CONC_BUF_ELEM*)prm->currConcBufListElem->msg; index = elem->rec_num; sAT_PlusCMSS_Gl(concShrdPrm.srcId, index, prm->p_da, prm->p_toda, rConcSMS_PlusCMSS, rConcSMS_PlusCMS_CMSS); elem->status = SMS_STAT_StoSent; } else /* if (concShrdPrm.currConcBufListElem NEQ NULL) */ { #ifdef _CONC_TESTING_ char *sa; ACI_MALLOC(sa,KEY + BYTE_LTH); sprintf(sa,"+CMSS: %d,%d",concShrdPrm.first_mr, concShrdPrm.sentSegs); io_sendMessage(concShrdPrm.srcId, sa, ATI_NORMAL_OUTPUT); ACI_MFREE(sa); #endif rAT_PlusCMSS(concShrdPrm.first_mr, (UBYTE)(concShrdPrm.sentSegs)); R_AT ( RAT_OK, concShrdPrm.srcId ) ( AT_CMD_CMSS ); UNSET_CONC; } } GLOBAL void rConcSMS_PlusCMGS (UBYTE mr, UBYTE numSeg) { T_ACI_SM_DATA data; T_ACI_UDH_DATA udh; USHORT len_left; T_CONC_CMGS *prm = &concShrdPrm.specPrm.concCMGS; TRACE_FUNCTION ("rConcSMS_PlusCMGS()"); /* save the first message reference */ if (concShrdPrm.udh.seq_num EQ 1) { concShrdPrm.first_mr = mr; } /* increment number of successfully sent elements */ len_left = prm->data.len - prm->offset; concShrdPrm.sentSegs++; if (len_left NEQ 0) { prm->sent_bytes += concShrdPrm.max_sms_len; if ( len_left > concShrdPrm.max_sms_len ) { data.len = concShrdPrm.max_sms_len; } else { data.len = (UBYTE)len_left; } memcpy (data.data, prm->data.data+prm->offset, data.len); prm->offset += data.len; concShrdPrm.udh.seq_num++; /* fill user data header structure */ concSMS_fillUDH ( &udh, concShrdPrm.udh.ref_num, concShrdPrm.udh.max_num, concShrdPrm.udh.seq_num ); sAT_PlusCMGS_Gl(concShrdPrm.srcId, prm->p_da, prm->p_toda, &data, &udh, prm->p_sca, prm->p_tosca, prm->isReply, rConcSMS_PlusCMGS, rConcSMS_PlusCMS_CMGS); } else { #ifdef _CONC_TESTING_ char *sa; ACI_MALLOC(sa,KEY + BYTE_LTH); sprintf(sa,"+CMGS: %d,%d",concShrdPrm.first_mr, concShrdPrm.udh.seq_num); io_sendMessage(concShrdPrm.srcId, sa, ATI_NORMAL_OUTPUT); ACI_MFREE(sa); ACI_MFREE(prm->data.data); #endif rAT_PlusCMGS (concShrdPrm.first_mr, (UBYTE)(concShrdPrm.udh.seq_num)); R_AT ( RAT_OK, concShrdPrm.srcId ) ( AT_CMD_CMGS ); UNSET_CONC; } } GLOBAL void rConcSMS_PlusCMGR ( T_ACI_CMGL_SM* sm, T_ACI_CMGR_CBM* cbm ) { T_CONC_CMGR *prm = &concShrdPrm.specPrm.concCMGR; TRACE_FUNCTION ("rConcSMS_PlusCMGR ()"); if (prm->currConcBufListElem NEQ NULL) { T_CONC_BUF_ELEM *elem; elem = (T_CONC_BUF_ELEM *)prm->currConcBufListElem->msg; sAT_PlusCMGR_Gl(concShrdPrm.srcId, elem->rec_num, concShrdPrm.specPrm.concCMGR.rdMode, rConcSMS_PlusCMGR); prm->currConcBufListElem = prm->currConcBufListElem->next; #ifdef _CONC_TESTING_ rAT_PlusCMGR_Ext (sm, cbm); #else rAT_PlusCMGR (sm, cbm); #endif } else /* if (concShrdPrm.currConcBufListElem NEQ NULL) */ { #ifdef _CONC_TESTING_ rAT_PlusCMGR_Ext (sm, cbm); #else rAT_PlusCMGR (sm, cbm); #endif R_AT ( RAT_OK, concShrdPrm.srcId ) ( AT_CMD_CMGR ); UNSET_CONC; } } GLOBAL void rConcSMS_PercentCMGMDU (void) { T_CONC_CMGR *prm = &concShrdPrm.specPrm.concCMGR; TRACE_FUNCTION ("rConcSMS_PercentCMGMDU ()"); if (prm->currConcBufListElem NEQ NULL) { T_CONC_BUF_ELEM *elem; elem = (T_CONC_BUF_ELEM *)prm->currConcBufListElem->msg; sAT_PercentCMGMDU_Gl(concShrdPrm.srcId, elem->rec_num, rConcSMS_PercentCMGMDU); prm->currConcBufListElem = prm->currConcBufListElem->next; } else /* if (concShrdPrm.currConcBufListElem NEQ NULL) */ { if( concShrdPrm.srcId NEQ CMD_SRC_LCL ) R_AT ( RAT_OK, concShrdPrm.srcId ) ( AT_CMD_P_CMGMDU ); UNSET_CONC; } } GLOBAL void rConcSMS_PlusCMGW ( UBYTE index, UBYTE numSeg ) { T_ACI_SM_DATA data; T_ACI_UDH_DATA udh; USHORT len_left; T_CONC_CMGW *prm = &concShrdPrm.specPrm.concCMGW; static UBYTE first_rec; TRACE_FUNCTION ("rConcSMS_PlusCMGW ()"); /* save the first index */ if (concShrdPrm.udh.seq_num EQ 1) { first_rec = index; } concSMS_addToConcatList((USHORT)concShrdPrm.udh.ref_num, NULL, concShrdPrm.udh.max_num, concShrdPrm.udh.seq_num, index, prm->stat); concSMS_printConcatList(); len_left = prm->data.len - prm->offset; if (len_left NEQ 0) { prm->sent_bytes += concShrdPrm.max_sms_len; if ( len_left > concShrdPrm.max_sms_len ) { data.len = concShrdPrm.max_sms_len; } else { data.len = (UBYTE)len_left; } memcpy (data.data, prm->data.data+prm->offset, data.len); prm->offset += data.len; concShrdPrm.udh.seq_num++; /* fill user data header structure */ concSMS_fillUDH ( &udh, concShrdPrm.udh.ref_num, concShrdPrm.udh.max_num, concShrdPrm.udh.seq_num ); sAT_PlusCMGW_Gl(concShrdPrm.srcId, CMGW_IDX_FREE_ENTRY, prm->p_da, prm->p_toda, prm->stat, prm->msg_ref, &data, &udh, prm->p_sca, prm->p_tosca, prm->isReply, rConcSMS_PlusCMGW, rConcSMS_PlusCMS_CMGW); } else { #ifdef _CONC_TESTING_ char *sa; ACI_MALLOC(sa,KEY + BYTE_LTH); sprintf(sa,"+CMGW: %d,%d",first_rec, concShrdPrm.udh.seq_num); io_sendMessage(concShrdPrm.srcId, sa, ATI_NORMAL_OUTPUT); ACI_MFREE(sa); #endif rAT_PlusCMGW (first_rec, concShrdPrm.udh.seq_num); R_AT ( RAT_OK, concShrdPrm.srcId ) ( AT_CMD_CMGW ); UNSET_CONC; } } GLOBAL void rConcSMS_PlusCMGD ( ) { T_CONC_CMGD *prm = &concShrdPrm.specPrm.concCMGD; T_CONC_BUF_ELEM *elem; T_ACI_LIST *conc_list; TRACE_FUNCTION ("rConcSMS_PlusCMGD ()"); elem = (T_CONC_BUF_ELEM *)prm->currConcBufListElem->msg; /* remove the old element from concatenation list and free its memory */ conc_list = concSMS_removeFromConcatList(prm->ref_num, prm->address, elem->rec_num); concSMS_printConcatList(); if (conc_list NEQ NULL) { TRACE_EVENT("conc_list not null"); elem = (T_CONC_BUF_ELEM *)conc_list->msg; /* save the concatenation list */ prm->currConcBufListElem= conc_list; sAT_PlusCMGD_Gl(concShrdPrm.srcId, elem->rec_num, smsShrdPrm.status, rConcSMS_PlusCMGD, rConcSMS_PlusCMS_CMGD); } else /* if (concShrdPrm.currConcBufListElem NEQ NULL) */ { if (concShrdPrm.full.Conc_Full EQ TRUE) { concSMS_AddtoconcBuff(); concShrdPrm.full.Conc_Full = FALSE; } TRACE_EVENT("RAT_OK in rConcSMS_PlusCMGD"); R_AT ( RAT_OK, concShrdPrm.srcId ) ( AT_CMD_CMGD ); UNSET_CONC; } } GLOBAL void rConcSMS_PlusCMGC ( UBYTE mr ) { UBYTE mn; T_CONC_CMGC *prm = &concShrdPrm.specPrm.concCMGC; TRACE_FUNCTION ("rConcSMS_PlusCMGC ()"); /* save the first message reference */ if (concShrdPrm.udh.seq_num EQ 1) { concShrdPrm.first_mr = mr; } prm->command_count++; if (prm->command_count < concShrdPrm.sentSegs) { mn = concShrdPrm.first_mr + prm->command_count; sAT_PlusCMGC_Gl(concShrdPrm.srcId, prm->fo, prm->ct, prm->pid, mn, prm->p_da, prm->p_toda, (T_ACI_CMD_DATA*)&prm->data, rConcSMS_PlusCMGC); } else { #ifdef _CONC_TESTING_ char *sa; ACI_MALLOC(sa,KEY + BYTE_LTH); sprintf(sa,"+CMGC: %d",concShrdPrm.first_mr /*, prm->command_count*/); io_sendMessage(concShrdPrm.srcId, sa, ATI_NORMAL_OUTPUT); ACI_MFREE(sa); #endif ACI_MFREE( prm->data.data ); rAT_PlusCMGC (concShrdPrm.first_mr/*, prm->command_count*/); R_AT ( RAT_OK, concShrdPrm.srcId ) ( AT_CMD_CMGC ); UNSET_CONC; } } GLOBAL void rConcSMS_PlusCMS_CMSS (T_ACI_AT_CMD cmdId, T_ACI_CMS_ERR err, T_EXT_CMS_ERROR *ce) { T_EXT_CMS_ERROR conc_error; #ifdef _CONC_TESTING_ char *sa; #endif TRACE_FUNCTION ("rConcSMS_PlusCMS_CMSS ()"); conc_error.id = CMSS_CONC; conc_error.specErr.errConcCMSS.segs = concShrdPrm.udh.max_num - concShrdPrm.sentSegs; #ifdef _CONC_TESTING_ ACI_MALLOC(sa,KEY + BYTE_LTH); sprintf(sa,"+CMS ERROR: %d,%d",err, conc_error.specErr.errConcCMSS.segs); io_sendMessage(concShrdPrm.srcId, sa, ATI_NORMAL_OUTPUT); ACI_MFREE(sa); rCI_PlusCMS ( cmdId, err, NULL ); #endif rAT_PlusCMS (cmdId, err, &conc_error); UNSET_CONC; } GLOBAL void rConcSMS_PlusCMS_CMGS (T_ACI_AT_CMD cmdId, T_ACI_CMS_ERR err, T_EXT_CMS_ERROR *ce) { T_EXT_CMS_ERROR conc_error; #ifdef _CONC_TESTING_ char *sa; #endif TRACE_FUNCTION ("rConcSMS_PlusCMS_CMGS ()"); conc_error.id = CMGS_CONC; conc_error.specErr.errConcCMGS.sent_chars = concShrdPrm.specPrm.concCMGS.sent_bytes; conc_error.specErr.errConcCMGS.ref_num = concShrdPrm.udh.ref_num; conc_error.specErr.errConcCMGS.next_seg = concShrdPrm.udh.seq_num; conc_error.specErr.errConcCMGS.max_num = concShrdPrm.udh.max_num; #ifdef _CONC_TESTING_ ACI_MALLOC(sa,KEY + BYTE_LTH); sprintf(sa,"+CMS ERROR: %d,%d,%d,%d,%d",err, conc_error.specErr.errConcCMGS.sent_chars, conc_error.specErr.errConcCMGS.ref_num, conc_error.specErr.errConcCMGS.next_seg, conc_error.specErr.errConcCMGS.max_num); io_sendMessage(concShrdPrm.srcId, sa, ATI_NORMAL_OUTPUT); ACI_MFREE(sa); rCI_PlusCMS ( cmdId, err, NULL ); #endif rAT_PlusCMS (cmdId, err, &conc_error); UNSET_CONC; } GLOBAL void rConcSMS_PlusCMS_CMGW (T_ACI_AT_CMD cmdId, T_ACI_CMS_ERR err, T_EXT_CMS_ERROR *ce) { T_EXT_CMS_ERROR conc_error; #ifdef _CONC_TESTING_ char *sa; #endif TRACE_FUNCTION ("rConcSMS_PlusCMS_CMGW ()"); conc_error.id = CMGW_CONC; conc_error.specErr.errConcCMGW.sent_chars = concShrdPrm.specPrm.concCMGW.sent_bytes; conc_error.specErr.errConcCMGW.ref_num = concShrdPrm.udh.ref_num; conc_error.specErr.errConcCMGW.next_seg = concShrdPrm.udh.seq_num; conc_error.specErr.errConcCMGW.max_num = concShrdPrm.udh.max_num; #ifdef _CONC_TESTING_ ACI_MALLOC(sa,KEY + BYTE_LTH); sprintf(sa,"+CMS ERROR: %d,%d,%d,%d,%d",err, conc_error.specErr.errConcCMGW.sent_chars, conc_error.specErr.errConcCMGW.ref_num, conc_error.specErr.errConcCMGW.next_seg, conc_error.specErr.errConcCMGW.max_num); io_sendMessage(concShrdPrm.srcId, sa, ATI_NORMAL_OUTPUT); ACI_MFREE(sa); rCI_PlusCMS ( cmdId, err, NULL ); #endif rAT_PlusCMS (cmdId, err, &conc_error); UNSET_CONC; } GLOBAL void rConcSMS_PlusCMS_CMGD (T_ACI_AT_CMD cmdId, T_ACI_CMS_ERR err, T_EXT_CMS_ERROR *ce) { T_CONC_CMGD *prm = &concShrdPrm.specPrm.concCMGD; T_CONC_BUF_ELEM *elem; T_EXT_CMS_ERROR conc_error; TRACE_FUNCTION ("rConcSMS_PlusCMS_CMGD ()"); conc_error.id = EMPTY; prm->error_count++; if (prm->error_count EQ concShrdPrm.udh.max_num) { #ifdef _CONC_TESTING_ char *sa; ACI_MALLOC(sa,KEY + BYTE_LTH); sprintf(sa,"+CMS ERROR: %d",err); io_sendMessage(concShrdPrm.srcId, sa, ATI_NORMAL_OUTPUT); ACI_MFREE(sa); rCI_PlusCMS ( cmdId, err, NULL ); #endif elem = (T_CONC_BUF_ELEM *)prm->currConcBufListElem->msg; /* remove the old element from concatenation list and free its memory */ concSMS_removeFromConcatList(prm->ref_num, prm->address, elem->rec_num); concSMS_printConcatList(); rAT_PlusCMS ( cmdId, err, &conc_error); UNSET_CONC; } else { /* continue with the next segment */ rConcSMS_PlusCMGD(); } } /*************** Functions which must be called by MFW ***************/ /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : SMS_getSMSType | +--------------------------------------------------------------------+ PURPOSE : This function must be called by the MFW to detect the SMS type from the information element identifier. */ GLOBAL T_SMS_TYPE SMS_getSMSType( T_ACI_UDH_DATA* udh ) { TRACE_FUNCTION ("SMS_getSMSType()"); if (udh->len EQ 0) return NORMAL; if (udh->data[0] EQ SMS_IEI_CONC_8BIT) return CONCATE; if (udh->data[0] EQ SMS_IEI_CONC_16BIT) return CONCATE; return UNKNOWN; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_GetFirstIndex | +--------------------------------------------------------------------+ PURPOSE : This function provides MFW with the first index of a given concatenated SMS (identified by its message reference). returns first index: (0 means no message found...) */ #define FIRST_SEQ_NUM (1) GLOBAL UBYTE concSMS_GetFirstIndex ( USHORT msg_ref, char *address ) { T_CONC_BUF *concBuf; T_CONC_BUF_ELEM *concBufElem; TRACE_FUNCTION ("concSMS_GetFirstIndex()"); /* search for concatenation buffer */ concBuf = concSMS_getConcBuffer( msg_ref, address ); if( concBuf EQ NULL ) { TRACE_EVENT_P1("ERROR: unknown msg_ref: 0x%04x", msg_ref); return( 0 ); } /* search for the first sequence */ concBufElem = find_element(concBuf->list, FIRST_SEQ_NUM, concSMS_findSeqNumElemCB); if( concBufElem EQ NULL ) { TRACE_EVENT("ERROR: first sequence not found"); return( 0 ); } TRACE_EVENT_P1("first rec_num: %d", concBufElem->rec_num); /* return index of first segment */ return(concBufElem->rec_num); } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_GetMsgRef | +--------------------------------------------------------------------+ PURPOSE : This function provides MFW with the message reference of a given concatenated SMS (decoded from the header). returns msg ref. */ GLOBAL USHORT concSMS_GetMsgRef ( T_ACI_CMGL_SM *sm ) { USHORT ref_num; TRACE_FUNCTION ("concSMS_GetMsgRef()"); if( sm EQ NULL ) { TRACE_ERROR("sm is NULL"); return 0; } /* 8-bit reference number */ if (sm->udh.data[0] EQ SMS_IEI_CONC_8BIT) { ref_num = sm->udh.data[2]; } /* 16-bit reference number */ else if (sm->udh.data[0] EQ SMS_IEI_CONC_16BIT) { /* MSB */ ref_num = (sm->udh.data[2] & 0x00FF) << 8u; /* 23.040 9.1.2.1 */ /* LSB */ ref_num |= sm->udh.data[3]; } else { TRACE_ERROR("sm->udh.data unknown"); return 0; } TRACE_EVENT_P1("ref_num: 0x%04x", ref_num); return(ref_num); } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_Collect | +--------------------------------------------------------------------+ PURPOSE : This function must be called by the MFW. The function reassembles the received SM segments. Set 'isStored' to: TRUE, if rAT_PlusCMTI() was called FALSE, if rAT_PlusCMT() was called FALSE, if rAT_PlusCMGR() was called */ GLOBAL T_CONC_ASSEMBLY_RETURN concSMS_Collect ( T_SM_DATA_EXT *data_conc, T_ACI_CMGL_SM *sm, UBYTE isStored ) { USHORT ref_num = 0; UBYTE max_num = 0; UBYTE seq_num = 0; UBYTE rec_num; T_SM_ASSEMBLY *assembly_elem; T_SEG_BUF_ELEM *segBufElem; T_SM_DATA_EXT data; T_ACI_SMS_STAT status; UBYTE next_exp_num; UBYTE ret; static UBYTE i = 0; CHAR *address; TRACE_FUNCTION ("concSMS_Collect()"); /* initialize data_conc->len */ data_conc->len = 0; /* ACI-SPR-16372 */ /* extract parameters from user data header */ /* 8-bit reference number */ if (sm->udh.data[0] EQ SMS_IEI_CONC_8BIT) { ref_num = sm->udh.data[2]; max_num = sm->udh.data[3]; seq_num = sm->udh.data[4]; } /* 16-bit reference number */ else if (sm->udh.data[0] EQ SMS_IEI_CONC_16BIT) { /* MSB */ ref_num = (sm->udh.data[2] & 0x00FF) << 8u; /* 23.040 9.1.2.1 */ /* LSB */ ref_num += sm->udh.data[3]; max_num = sm->udh.data[4]; seq_num = sm->udh.data[5]; } rec_num = sm->msg_ref; status = sm->stat; address = sm->adress; data.data = sm->data.data; data.len = sm->data.len; TRACE_EVENT_P1("rec_num:%d", rec_num); TRACE_EVENT_P1("concSMS_GetFirstIndex():%d", concSMS_GetFirstIndex (ref_num, sm->adress)); TRACE_EVENT_P1("ref_num:0x%04x", ref_num); TRACE_EVENT_P1("concSMS_GetMsgRef():0x%04x", concSMS_GetMsgRef ( sm )); TRACE_EVENT_P1("max_num:%d", max_num); TRACE_EVENT_P1("seq_num:%d", seq_num); /* try to get an existing assembly buffer */ assembly_elem = concSMS_getAsBuffer(ref_num, address); /* if no assembly buffer found, then assume that is a new conc. SM */ if (assembly_elem EQ NULL) { next_exp_num = 1; } else { next_exp_num = assembly_elem->next_exp_num; } /* the received seq_num is not valid */ if ( (seq_num EQ 0) OR (seq_num > max_num) OR (seq_num < next_exp_num) ) { return CONC_ERR_UNKN; } /* * If CMTI, then add every received segment to concatenation buffer. * The segments in the concatenation buffer were also stored in non-volatile * memory. */ if (isStored) { ret = concSMS_addToConcatList(ref_num, address, max_num, seq_num, rec_num, status); if (ret EQ FALSE) { dFLAG = TRUE; RefNum_Del = ref_num; concShrdPrm.full.Conc_Full = TRUE; concShrdPrm.full.RefNum = ref_num; memcpy(Addres,address,sizeof(Addres)); concShrdPrm.full.MaxNum = max_num; concShrdPrm.full.SeqNum[i] = seq_num; concShrdPrm.full.RecNum[i] = rec_num; i++; concShrdPrm.full.Numsegs = i; /* error: concatenation buffer full */ return CONC_ERR_BUF_FULL; } } i = 0; if ( seq_num > next_exp_num ) { /* * the received segment is not in sequence * -> add it to the segment buffer */ ret = concSMS_addToSegBuffer(ref_num, address, seq_num, rec_num, status, &data); if (ret EQ FALSE) { /* error: segment buffer full */ return CONC_ERR_BUF_FULL; } return CONC_CONTINUED; } else { /* * the received segment is in sequence */ while (1) { /* add segment to assembly buffer */ assembly_elem = concSMS_addToAsBuffer (ref_num, address, max_num, &data); /* free data memory only for data from segment buffer */ if (data.data NEQ sm->data.data) { ACI_MFREE (data.data); } /* error: no assembly buffer available */ if (assembly_elem EQ NULL) { return CONC_ERR_BUF_FULL; } /* maximum reached in assembly buffer , assembly is NOT completed */ if (assembly_elem->seg_count EQ CONC_MAX_SEGS) { concSMS_getFromAsBuffer(data_conc, ref_num, address); concSMS_sortConcatList(ref_num, address); return CONC_COMPLETED; } /* assembly of concatenated SM is completed */ if (assembly_elem->next_exp_num EQ max_num+1) { concSMS_removeFromAsBuffer(data_conc, ref_num, address); concSMS_sortConcatList(ref_num, address); return CONC_COMPLETED; } /* search and remove the next segment from segment buffer */ segBufElem = concSMS_removeFromSegBuffer(ref_num, address, assembly_elem->next_exp_num); if ( segBufElem EQ NULL ) { /* no segment found */ return CONC_CONTINUED; } /* for adding to concatenation list */ rec_num = segBufElem->rec_num; status = segBufElem->status; /* for adding to assembly buffer */ data.data = segBufElem->data.data; data.len = segBufElem->data.len; ACI_MFREE(segBufElem); } /* while */ } /* if ( seq_num EQ next_exp_num ) */ } GLOBAL void concSMS_Init() { concShrdPrm.isConcatenated = FALSE; memset (&concShrdPrm, 0, sizeof(T_CONC_SHRD_PRM) ); memset (&assembly_list, 0, sizeof(T_SM_ASSEMBLY)*MAX_BUF_ELEMS); memset (&segBuf_list, 0, sizeof(T_SEG_BUF) *MAX_BUF_ELEMS); memset (&concBuf_list, 0, sizeof(T_CONC_BUF) *MAX_CONC_BUF_ELEMS); concShrdPrm.l_uncomp8bit_data = L_UNCOMP_8BIT_DATA; concShrdPrm.l_uncomp7bit_data = L_UNCOMP_7BIT_DATA; concShrdPrm.l_uncomp8bit_data_conc = L_UNCOMP_8BIT_DATA_CONC; concShrdPrm.l_uncomp7bit_data_conc = L_UNCOMP_7BIT_DATA_CONC; #ifdef _CONC_TESTING_ #ifndef _SIMULATION_ concSMS_InitForTesting(); #endif #endif } /* only for test purposes */ GLOBAL void concSMS_InitForTesting() { concShrdPrm.concTesting = TRUE; concShrdPrm.l_uncomp8bit_data = L_UNCOMP_8BIT_DATA_TST; concShrdPrm.l_uncomp7bit_data = L_UNCOMP_7BIT_DATA_TST; concShrdPrm.l_uncomp8bit_data_conc = L_UNCOMP_8BIT_DATA_CONC_TST; concShrdPrm.l_uncomp7bit_data_conc = L_UNCOMP_7BIT_DATA_CONC_TST; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : CONC_SMS | | STATE : code ROUTINE : concSMS_delAllIncompleteMsg| +--------------------------------------------------------------------+ PURPOSE : This function must be called by the MFW to clean all segment buffers, assembly buffers and remove all incompleted SM from concat. buffer and non-volatile memory. */ GLOBAL void concSMS_delAllIncompleteMsg( ) { T_SEG_BUF *segBuf = NULL; T_SEG_BUF_ELEM *segBufElem; T_CONC_BUF *concBuf = NULL; T_CONC_BUF_ELEM *concBufElem; T_SM_ASSEMBLY *assembly_elem; USHORT count; UBYTE i; TRACE_FUNCTION ("concSMS_delAllIncompleteMsg()"); concShrdPrm.srcId = CMD_SRC_LCL; for (i=0; i<MAX_BUF_ELEMS; i++) { /* delete assembly buffer */ if (assembly_list[i].in_use) { assembly_elem = &assembly_list[i]; assembly_elem->in_use = FALSE; ACI_MFREE(assembly_elem->data.data); } /* delete segment buffer */ if (segBuf_list[i].in_use) { segBuf = &segBuf_list[i]; /* remove element from segment buffer */ segBufElem = remove_first_element(segBuf->list); if (segBufElem NEQ NULL) { /* free memory */ ACI_MFREE(segBufElem->data.data); ACI_MFREE(segBufElem); } else { segBuf->in_use = FALSE; } } } /* for */ for (i=0; i<MAX_CONC_BUF_ELEMS; i++) { /* find concat. buffer in use */ if (concBuf_list[i].in_use) { /* get number of segments in this concat. buffer */ count = get_list_count(concBuf_list[i].list); /* conc buffer is incomplete */ if (count < concBuf_list[i].max_num) { if (count EQ 0) { /* last element of one conc buffer was deleted */ concBuf_list[i].in_use = FALSE; R_AT ( RAT_OK, concShrdPrm.srcId ) ( AT_CMD_CMGC ); continue; } concBuf = &concBuf_list[i]; break; } } } if (concBuf) { /* remove element from concat. buffer */ concBufElem = remove_first_element(concBuf->list); if (concBufElem) { /* delete segment from non-volatile memory */ sAT_PlusCMGD_Gl(concShrdPrm.srcId, concBufElem->rec_num, smsShrdPrm.status, concSMS_delAllIncompleteMsg, rConcSMS_PlusCMS_CMGD); /* free memory */ ACI_MFREE(concBufElem); } } } /************** Help Functions ******************************/ /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CONC_SMS | | ROUTINE : concSMS_printConcatList | +-------------------------------------------------------------------+ PURPOSE : */ LOCAL void concSMS_printConcatList () { T_ACI_LIST *current; UBYTE i; T_CONC_BUF *concBuf; T_CONC_BUF_ELEM *elem; TRACE_EVENT("Concatenation List:"); for (i=0; i<MAX_CONC_BUF_ELEMS; i++) { if (concBuf_list[i].in_use EQ TRUE) { concBuf = &concBuf_list[i]; TRACE_EVENT_P2(" ref_num: 0x%04x , max_num: %u", concBuf->ref_num, concBuf->max_num); current = concBuf->list; while (current) { elem = (T_CONC_BUF_ELEM*) current->msg; TRACE_EVENT_P3(" seq_num: %d , rec_num: %d , status: %d", elem->seq_num, elem->rec_num, elem->status); current = current->next; } } } } /* Marcus: Issue 872: 03/10/2002 +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CONC_SMS | | ROUTINE : concSMS_findMaxRefNum | +-------------------------------------------------------------------+ PURPOSE : Find the highest value of concBuf_list[i].ref_num */ LOCAL USHORT concSMS_findMaxRefNum(void) { UBYTE i; USHORT ref_num = 0; TRACE_FUNCTION("concSMS_findMaxRefNum()"); for (i=0; i<MAX_CONC_BUF_ELEMS; i++) { if (concBuf_list[i].in_use EQ TRUE) { if ((concBuf_list[i].ref_num & 0x00ff)> ref_num) /* since we use only 8-Bit ref_num */ ref_num = concBuf_list[i].ref_num & 0x00ff; } } return ref_num; } GLOBAL void concSMS_clearIncompleteMsg() { T_SEG_BUF *segBuf = NULL; T_SEG_BUF_ELEM *segBufElem; T_SM_ASSEMBLY *assembly_elem; T_CONC_BUF *concBuf = NULL; T_CONC_BUF_ELEM *concBufElem; UBYTE i; TRACE_FUNCTION ("concSMS_clearIncompleteMsg()"); if (RefNum_Del EQ concShrdPrm.full.RefNum) { concShrdPrm.full.Conc_Full = FALSE; concShrdPrm.full.RefNum = 0xFF; } for (i=0; i<MAX_BUF_ELEMS; i++) { /* delete assembly buffer */ if (assembly_list[i].in_use AND assembly_list[i].ref_num EQ RefNum_Del) { assembly_elem = &assembly_list[i]; assembly_elem->in_use = FALSE; ACI_MFREE(assembly_elem->data.data); break; } /* delete segment buffer */ if (segBuf_list[i].in_use AND segBuf_list[i].ref_num EQ RefNum_Del) { segBuf = &segBuf_list[i]; /*remove element from segment buffer */ segBufElem = remove_first_element(segBuf->list); if (segBufElem NEQ NULL) { segBuf->in_use = FALSE; /* free memory */ ACI_MFREE(segBufElem->data.data); ACI_MFREE(segBufElem); } else { segBuf->in_use = FALSE; } break; } } for (i=0; i<MAX_CONC_BUF_ELEMS; i++) { /* find concat. buffer in use */ if (concBuf_list[i].in_use AND concBuf_list[i].ref_num EQ RefNum_Del) { concBuf_list[i].in_use = FALSE; concBuf = &concBuf_list[i]; break; } } if (concBuf) { /* remove element from concat. buffer */ concBufElem = remove_first_element(concBuf->list); if (concBufElem) { /* free memory */ ACI_MFREE(concBufElem); } } } GLOBAL void concSMS_AddtoconcBuff(void) { UBYTE i; TRACE_FUNCTION("concSMS_AddtoconcBuff()"); for (i=0;i<concShrdPrm.full.Numsegs;i++) { concSMS_addToConcatList(concShrdPrm.full.RefNum,Addres, concShrdPrm.full.MaxNum,concShrdPrm.full.SeqNum[i], concShrdPrm.full.RecNum[i],1); } } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CONC_SMS | | ROUTINE : concSMS_DeleteConcList | +-------------------------------------------------------------------+ PURPOSE : This function is used to delete the concatinated SMS, when the CMGD command contails the delete flag greater than ZERO. */ GLOBAL void concSMS_DeleteConcList ( ) { T_CONC_CMGD *prm = &concShrdPrm.specPrm.concCMGD; T_CONC_BUF_ELEM *elem; T_ACI_LIST *conc_list; TRACE_FUNCTION ("concSMS_DeleteConcList()"); elem = (T_CONC_BUF_ELEM *)prm->currConcBufListElem->msg; /* remove the old element from concatenation list and free its memory */ conc_list = concSMS_removeFromConcatList(prm->ref_num, prm->address, elem->rec_num); concSMS_printConcatList(); if (conc_list NEQ NULL) { TRACE_EVENT("conc_list not null"); elem = (T_CONC_BUF_ELEM *)conc_list->msg; /* save the concatenation list */ prm->currConcBufListElem= conc_list; } else /* if (concShrdPrm.currConcBufListElem NEQ NULL) */ { TRACE_EVENT("Concat List is NULL : concSMS_DeleteConcList"); UNSET_CONC; } } GLOBAL void rConcSMS_PercentCMGR ( T_ACI_CMGL_SM* sm, T_ACI_CMGR_CBM* cbm ) { T_CONC_CMGR *prm = &concShrdPrm.specPrm.concCMGR; TRACE_FUNCTION ("rConcSMS_PercentCMGR ()"); if (prm->currConcBufListElem NEQ NULL) { T_CONC_BUF_ELEM *elem; elem = (T_CONC_BUF_ELEM *)prm->currConcBufListElem->msg; sAT_PercentCMGR_Gl(concShrdPrm.srcId, elem->rec_num, concShrdPrm.specPrm.concCMGR.rdMode, rConcSMS_PercentCMGR); prm->currConcBufListElem = prm->currConcBufListElem->next; #ifdef _CONC_TESTING_ rAT_PercentCMGR_Ext (sm, cbm); #else rAT_PercentCMGR (sm, cbm); #endif } else /* if (concShrdPrm.currConcBufListElem NEQ NULL) */ { #ifdef _CONC_TESTING_ rAT_PercentCMGR_Ext (sm, cbm); #else rAT_PercentCMGR (sm, cbm); #endif R_AT ( RAT_OK, concShrdPrm.srcId ) ( AT_CMD_P_CMGR ); UNSET_CONC; } }