Suggest a feature
×

Welcome to TagMyCode

Please login or create account to add a snippet.
0
0
 
0
Language: C
Posted by: Diep Doan
Added: Jan 10, 2019 7:42 PM
Views: 11
Tags: no tags
  1. /*
  2.  * Copyright (C) 2018
  3.  */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <math.h>
  8. #include "app_defs.h"
  9. #include "boot.h"
  10. #include "common.h"
  11. #include "le910.h"
  12. #include "modem_iface.h"
  13. #include "modem_iface.h"
  14. #include "app_defs.h"
  15. #include "at_cmd.h"
  16. #include "settings.h"
  17. #include "utils.h"
  18. #include "talisker.h"
  19. #include "cellLogicTal.h"
  20. #include "dei_net.h"
  21. #include "mdm_bridge.h"
  22. #include "cell.h"
  23. #include "cellLogic.h"
  24.  
  25. // Externs
  26. extern UART_HandleTypeDef huart2;
  27. extern UINT8 main_state;
  28. extern char cellLogic_version[];
  29. extern char cellLogic_iccid[];
  30. extern FLOAT cellLogic_lastATRcvd;
  31. extern FLOAT cellLogic_commChangeAge;
  32. extern UINT32 cellLogic_localAreaCode;
  33. extern bool cellLogic_isCommAvailable;
  34. extern UINT32 cellLogic_mccmnc;
  35. extern long long cellLogic_msisdn;
  36. extern long long cellLogic_imei;
  37. extern long long cellLogic_imsi;
  38.  
  39. extern void handleCharForCell();
  40. extern void myHandleCharForCell(const char *whence);
  41. extern void main_setState (UINT8 newState);
  42.  
  43. #define        IMEI_HEX_LEN   16
  44. #define        SMS_NUMBER_LEN 16
  45. #define        DEFAULT_SEGMENT_LENGTH 512
  46. #define        REQUEST_SEGMENT_LENGTH 1024
  47. #define        NETWORK_TYPE_POLL 10  // Number of time intervals between network type req
  48.  
  49. //--------------------------------------------------------------------------------
  50. //   Globals
  51. //--------------------------------------------------------------------------------
  52.  
  53. QUEUE          cell_atBuffer;
  54. UINT8          imeiBuffer[8]    = {0, };
  55. cmdDataType    dataPool[MAX_NUM_AT_CMD];    // to do - meant for long udp msg move to internal flash
  56. atCmdType      atCmdPool[MAX_NUM_AT_CMD];   // to do - move to internal flash
  57. cellOpState    cellState = CELL_WAIT_INIT | CELL_WAIT_SETUP; // initial AT cmds and socket cmd not done
  58. xferState      sendState = XFER_NONE;
  59. bool           udpMsgSocketOpen = false;
  60. bool           udpDmanSocketOpen = false;
  61. bool           udpTalSocketOpen = false;
  62. UINT32         segmentLength = DEFAULT_SEGMENT_LENGTH;
  63. INT8           networkType = -1;
  64. INT32          netTypePollCount = 0;
  65. char           *networkTypeStr[] = {"GPRS", "EGPRS", "WCDMA", "HSDPA", "LTE", "Unknown or unregistered"};
  66. char           operatorName[32] = {0, };
  67. char           cell_dmanServer[DMAN_REPORT_SERVER_SIZE] = {0, };
  68.  
  69. /**
  70.  * Hex representation of imei
  71.  * @public {string}
  72.  */
  73. char cell_imeiHex[IMEI_HEX_LEN * 2]= {0, };
  74. char cell_imeiPrint[17]= {0, };  // for print since long long printf doesn't work
  75. char cell_imsiPrint[16]= {0, };  // for print since long long printf doesn't work
  76. char cell_msidnPrint[16]= {0, }; // for print since long long printf doesn't work
  77.  
  78. /**
  79.  * Store last response for parsing purposes
  80.  * @private {string}
  81.  */
  82. char cell_lastResponse[MAX_RESP_LEN] = {0, };
  83.  
  84. /*
  85.  *
  86.  * @public {boolean}
  87.  */
  88. bool cell_isRoaming = false;
  89.  
  90. /**
  91.  *
  92.  * @private {string}
  93.  */
  94. char cell_smsFrom[SMS_NUMBER_LEN] = {0, };
  95.  
  96. /**
  97.  *
  98.  * @public {boolean}
  99.  */
  100. bool cell_simStoreReady = false;
  101.  
  102.  
  103. /**
  104.  * Is SIP registered yet
  105.  * @public {boolean}
  106.  */
  107. bool cell_netRegistered = false;
  108.  
  109.  
  110. /**
  111.  * Count of consecutive retry failures
  112.  * @public {uint8_t}
  113.  */
  114. UINT8 retryFaultCount = 0;
  115.  
  116.  
  117. /**
  118.  * Store date last AT command sent
  119.  * @private {number}
  120.  */
  121. FLOAT cell_lastAtSendDate = 0;
  122. FLOAT cell_lastAtRecDate = 0;
  123.  
  124.  
  125. bool hasSmsSrc = false;
  126. char tmpStr[MAX_TMP_STR_LEN] = {0, };
  127.  
  128. //--------------------------------------------------------------------------------
  129. //   Local globals
  130. //--------------------------------------------------------------------------------
  131.  
  132. // Set true when an AT command is issued to the modem
  133. static bool atCmdInProgress = false;
  134.  
  135.  
  136. //--------------------------------------------------------------------------------
  137. //   Begin functions
  138. //--------------------------------------------------------------------------------
  139.  
  140. xferState getSendState(void)
  141. {
  142.     return sendState;
  143. }
  144.  
  145. /**
  146.  * @public
  147.  * @param {string} cmdString
  148.  */
  149. void cellWrite(UINT8 *str, UINT16 len) {
  150.     UINT16 ii;
  151.  
  152.     for (ii = 0; ii < len; ii++) {
  153.         Mdm_Put_Char(str[ii]);
  154.     }
  155. }
  156.  
  157. void cellSetOpState(cellOpState newOpState) {
  158.   //DBG(D_CELL,"curCellState=0x%02x newOpState=0x%02x\n", cellState, newOpState);
  159.   cellState = newOpState;
  160. }
  161.  
  162. cellOpState cellCheckOpState() {
  163.   UINT8 initDoneFlags = CELL_GOOD_CEREG | CELL_GOOD_CGSN | CELL_GOOD_CIMI | CELL_GOOD_CCID;
  164.   if ((cellState & initDoneFlags) == initDoneFlags) {
  165.      cellState &= ~CELL_INIT_IN_PROG;
  166.      cellState |= CELL_INIT_DONE;
  167.      //DBG(D_CELL,"%s: cell init done!\n");
  168.   } else {
  169.      cellState |= CELL_INIT_IN_PROG;
  170.   }
  171.   return cellState;
  172. }
  173.  
  174. bool cellControl(UINT8 flags) {
  175.   bool pwrStateGood = false;
  176.   if (flags & CELL_CTRL_ON) {
  177.     //
  178.     // See pinTable for all the pins the Cell use), to turn on comm module:
  179.     // 1- De-assert ID_COM_HW_SHUTDOWN
  180.     // 2- Assert ID_COM_POWER
  181.     // 3- Assert,wait and then de-assert ID_COM_POWER_KEY
  182.     //    (optional: Check comm module power By reading ID_COM_POWER_MON)
  183.     //
  184.     DBG(D_CELL,"Cell control: Turn on cell at %.3f\n", utilsAge());
  185.     Mdm_Hw_Shdn_Inactive();
  186.     Mdm_Pwr_Enable();
  187.     HAL_Delay(1000);
  188.     Mdm_On_Off_Active();
  189.     HAL_Delay(5500);
  190.     App_WDog_Refresh();
  191.     HAL_Delay(5000);
  192.     Mdm_On_Off_Inactive();
  193.     cellReadyHandler();
  194.  
  195.   } else if (flags & CELL_CTRL_OFF) { // Disable - Turn off cell power
  196.     DBG(D_CELL,"Cell control: Turn off cell at %.3f\n", utilsAge());
  197.     printf("Toggling modem ON/OFF...\n");
  198.     Mdm_On_Off_Active();
  199.     HAL_Delay(3500);
  200.     Mdm_On_Off_Inactive();
  201.     printf("Toggling modem ON/OFF done\n");
  202.     Refresh_IWDog();
  203.     printf("5000 ms delay...\n");
  204.     HAL_Delay(5000);
  205.     printf("Removing power...\n");
  206.     Mdm_Pwr_Disable();
  207.     printf("10000 ms delay...\n");
  208.     Refresh_IWDog();
  209.     {
  210.       int i=10;
  211.       while (i--) {
  212.         printf("Modem power down %d...\n", i);
  213.         printf("HW_SH 1\n");
  214.         Mdm_Hw_Shdn_Active();
  215.         HAL_Delay(250);
  216.         Mdm_Hw_Shdn_Inactive();
  217.         printf("HW_SH 0\n");
  218.         HAL_Delay(750);
  219.         Refresh_IWDog();
  220.       }
  221.     }
  222.     printf("Modem off done\n");
  223.   } else if (flags & CELL_CTRL_CHK_PWR) { // Check cell power
  224.     if (Mdm_Pwr_Mon() == 0) {
  225.       pwrStateGood = true;
  226.     }
  227.     DBG(D_CELL,"Cell control: pwrStateGood = %d\n", pwrStateGood);
  228.     return pwrStateGood;
  229.  
  230.   } else if (flags & CELL_CTRL_RESET) { // inband cmd reset cell
  231.     char tmp[12];
  232.     sprintf((char*)tmp, "%s%s", AT_RESET, RETURN);
  233.     DBG(D_CELL,"Cell control: Reset cell (%s)\n", (char*)tmp);
  234.     cellWrite((UINT8*)tmp, strlen((char*)tmp));
  235.   }
  236.   return false;
  237. }
  238.  
  239.  
  240. /**
  241.  * Convenience method for finding str2 in str1
  242.  * @private
  243.  * @param {Uint8Array} data
  244.  * @param {number} dataStart
  245.  * @param {number} dataLength
  246.  * @param {string} str
  247.  * @returns {boolean}
  248.  */
  249. bool cell_match(UINT8 *data, UINT8 startIdx, UINT32 len, char *s) {
  250.   UINT32 i, here= startIdx, n = strlen(s);
  251.  
  252.   if (len < startIdx + n) {
  253.     return false;
  254.   }
  255.   // compare to the integer value of a single character at position i in the String
  256.   for (i = 0; i < n; i++) {
  257.     if (data[i + here] != (UINT8)s[i]) {
  258.       //printf("BAD Compare %s: i=%d 1st=%d 2nd[0]=%d\n", s, i, data[i + startIdx]);
  259.       return false;
  260.     }
  261.   }
  262.   return true;
  263. }
  264.  
  265. /**
  266.  * Configure UDP messaging port.
  267.  * @private
  268.  * @param {number} connId
  269.  * @param {string} serverIp
  270.  * @param {number} port
  271.  */
  272. void cell_configUdp(UINT8 connId, char *serverIp, UINT32 port) {
  273.   cell_openSocket(connId, serverIp, port);
  274. }
  275.  
  276.  
  277. // Handle all AT cmd response WITHOUT +<cmd> prefix
  278. void cell_processGoodCmdResp(char *lastCmd, UINT8 *lastResp) {
  279.    //DBG(D_CELL, "%s: lastCmd=%s lastResp=%s\n", __FUNCTION__, (char*)lastCmd, (char*)lastResp);
  280.    if (strncmp(lastCmd, AT_SMS, 7) == 0) {
  281.      UINT8 i;
  282.      DBG(D_CELL, "%s: lastCmd=%s lastResp=%s\n", __FUNCTION__, (char*)lastCmd, (char*)lastResp);
  283.      for (i = 0; i < strlen(lastResp); i++) {
  284.        DBG(D_CELL, "%02d ", (UINT8)lastResp[i]);
  285.      }
  286.  
  287.    } else if (strcmp(lastCmd, CGSN) == 0) {
  288.      // Product Serial Number
  289. #if defined(PLATFORM_TALISKER_PRO) || defined(PLATFORM_TALISKER_OBD)
  290.      Mdm_Bridge_Set_IMEI(lastResp);
  291. #endif
  292.      cellLogic_imei = parseInt(lastResp, 10);
  293.      strcpy((char*)cell_imeiPrint, (char*)lastResp);
  294.      utils_put8BE((UINT8*)imeiBuffer, 0, cellLogic_imei);
  295.      utoh((UINT8*)imeiBuffer, 0, IMEI_HEX_LEN-1, (char*)cell_imeiHex);
  296.      cellState |= CELL_GOOD_CGSN;
  297.  
  298.      DBG(D_CELL, "cell_imeiHex:\n");
  299.      Dump_Hex_Data(cell_imeiHex, IMEI_HEX_LEN);
  300.  
  301.    } else if (strcmp(lastCmd, CIMI) == 0) {
  302.      // Message Receiving Behavior - Get IMSI
  303.      cellState |= CELL_GOOD_CIMI;
  304.      strcpy((char*)cell_imsiPrint,(char*)lastResp);
  305.      cellLogic_imsi = parseInt((char*)lastResp, 10);
  306.      //DBG(D_CELL, "cell imsi=%lld\n", cellLogic_imsi);
  307.  
  308.    } else if (strcmp(lastCmd, CGMR) == 0) {
  309.      // Get Device Software Rev, remove \r\n in resp
  310.      strcpy((char*)cellLogic_version, (char*)lastResp);
  311.      remChar((char*)cellLogic_version, (char)13);
  312.      DBG(D_CELL, "cell sw ver = %s\n", (char*)cellLogic_version);
  313.      //Dump_Hex_Data((UINT8*)cellLogic_version, 16);
  314.  
  315.    } else if (strncmp(lastCmd, AT_SOC_CFGEXT, 10) == 0) { // last setup cmd done, clear wait state
  316.      if (cellCheckOpState() & CELL_WAIT_SETUP) {
  317.        cellOpState s = cellCheckOpState();
  318.        s &= ~(CELL_WAIT_SETUP);
  319.        cellSetOpState(s);
  320.        DBG(D_CELL, "Cleared WAIT_SETUP state=0x%02x --> handleComm\n", s);
  321.        cellLogic_handleComm();
  322.  
  323. #if defined(PLATFORM_TALISKER_PRO) || defined(PLATFORM_TALISKER_SPORT)  || defined(PLATFORM_TALISKER_OBD)
  324.        // request time from Tal server
  325.        if (!testPuiLoc) {  // only request time if using back-end Tal server
  326.          cell_configUdp(UDP_TALISKER_SOC, settings[MESSAGES_REPORT_SERVER].u.ptr,
  327.                       settings[MESSAGES_REPORT_PORT].u.v.iVal);
  328.          HAL_Delay(100);
  329.          cellLogicSendTalTimeReq();
  330.        }
  331. #endif
  332.      }
  333.    } else if (strncmp(lastResp, AT_MTUSIZE, 11) == 0) {
  334.      segmentLength = (UINT32)strtol((char*)&lastResp[11], NULL, 10);
  335.      if (segmentLength > MAX_SEGMENT_LENGTH) {
  336.        segmentLength = MAX_SEGMENT_LENGTH;
  337.      }
  338.      DBG(D_CELL, "MTUSIZE Response received: %lu\n", segmentLength);
  339.    }
  340. }
  341.  
  342. #define MAX_C_SNAC_RETRIES    0   // do not do retries here!
  343.  
  344. /**
  345.  * Check AT Command queue for unsent messages and send them.
  346.  * Also print out last command with status.
  347.  * @privatcountste
  348.  * @param {string=} handleReceive ("OK", "ERROR", or NULL)
  349.  */
  350. bool cell_sendNextAtCommand (char* handleReceive)
  351. {
  352.     static int retry_count = 0;
  353.     bool rtn = false;
  354.  
  355.     bool  sendFirst = false;
  356.     bool  hasSent   = false;
  357.     INT8 idx        = 0;
  358.  
  359.     // Is there anything in the "cell_atBuffer" queue
  360.     if (cell_atBuffer.count > 0) {
  361.         idx = cell_atBuffer.front;
  362.         hasSent = cell_atBuffer.s.arr[idx].sent;
  363.         if (!hasSent) {
  364.           sendState = 0;  // should keep -- safety knows no season!
  365.           retry_count = 0;
  366.         }
  367.     }
  368.  
  369.     // If already sent p1, send p2 right away since p2 only depends on ">" from the cell
  370.     // For all other cases (new cmd) allow 3 seconds for response, resend if no resp
  371.     sendFirst = ((utilsAge() - cell_lastAtSendDate) > 3);    // seconds
  372.  
  373.     if (sendState & XFER_SENT_P1) {
  374.         if (sendFirst)   // didn't get resp, already sent p1, clear the flag to retry p1
  375.         {
  376.             sendState &= ~XFER_SENT_P1;
  377.         }
  378.         else     // already sent p1, just wait for prompt ">" to send p2, send it now
  379.         {
  380.             sendFirst = true;
  381.         }
  382.     }
  383.     else if (sendState & XFER_SENT_P2) {
  384.         if (sendFirst)   // didn't get resp, already sent p2, clear flag retry sending p1
  385.         {
  386.             sendState &= ~XFER_SENT_P2;
  387.             retry_count++;
  388.             printf("%s, retry %d\n", __func__, retry_count);  //debug
  389.             DBG(D_CELL, "%s, retry %d\n", __func__, retry_count);
  390.  
  391. #define DO_NOt_USE_INFINITE_RETRIES
  392. #ifdef DO_NOt_USE_INFINITE_RETRIES
  393.             if(retry_count > MAX_C_SNAC_RETRIES)
  394.             {
  395.                 idx = deQ(&cell_atBuffer); // Upper levels must retry
  396.                 if(idx >= 0) {
  397.                     atCmdType *lastCmd = &cell_atBuffer.s.arr[idx];
  398.                     lastCmd->type = 0;
  399.                     lastCmd->sent = 0;
  400.                     printf("%s, retry count %d exceeded!\n", __func__, retry_count);
  401.                     retry_count = 0;
  402.                 } else {
  403.                     printf("%s, AT queue unexpectedly empty! (1)\n",__func__);
  404.                 }
  405.             }
  406. #endif // DO_NOt_USE_INFINITE_RETRIES
  407.  
  408.         }
  409.     }
  410.     //DBG(D_CELL, "%s: lastReceived=%f\n", __FUNCTION__, cell_lastAtRecDate);
  411.     //if (handleReceive)
  412.     //  DBG(D_CELL, "%s: Received=%s\n", __FUNCTION__, handleReceive);
  413.     //DBG(D_CELL, "hasSent=%d sendFirst=%d utilsAge=%f lastSentDate=%f\n",
  414.     //   (INT32)hasSent, sendFirst, utilsAge(), cell_lastAtSendDate);
  415.  
  416.  
  417.  
  418.  
  419.     if (hasSent)
  420.     {
  421.         // check if anything received
  422.         //   NULL --> nothing received, if
  423.         //   OK -->
  424.         //   ERROR -->
  425.         if (handleReceive != NULL)
  426.         {
  427.             // NOT NULL so handleReceive is expected to be: OK or ERROR
  428.             idx = deQ(&cell_atBuffer); // Only take out of the Q when get response
  429.  
  430.             atCmdInProgress = false;
  431.  
  432.             if(idx < 0) {
  433.                 printf("%s, AT queue unexpectedly empty! (2)\n",__func__);
  434.                 return;
  435.             }
  436.             atCmdType *lastCmd = &cell_atBuffer.s.arr[idx];
  437.             memset((char*)tmpStr, 0, sizeof(tmpStr));
  438.             if ((lastCmd->type == AT_CMD_UDP_MESSAGE) || (lastCmd->type == AT_CMD_UDP_DMAN))
  439.             {
  440.                 sprintf(tmpStr, "%s -> UDP\n", handleReceive);
  441.                 printf("%s", tmpStr);
  442.             }
  443.             else if (lastCmd->type == AT_CMD_SMS)
  444.             {
  445.                 sprintf(tmpStr, "%s -> SMS=%s, %s\n", handleReceive, (char*)lastCmd->cmd, (char*)lastCmd->extra);
  446.                 printf("%s", tmpStr);
  447.                 sendState &= ~XFER_SENT_P2; // Got resp, clear p2 flag
  448.             }
  449.             else
  450.             {
  451.                 if (strstr(lastCmd->cmd, CSQ) != NULL && strstr(lastCmd->cmd, CCLK) != NULL)
  452.                 {
  453.                     DBG(D_CELL, "%s -> %s%s\n", handleReceive,
  454.                            (((strstr((char*)lastCmd->cmd, "AT")) == 0) ? "AT+" : ""),
  455.                            (char*)lastCmd->cmd);
  456.                 }
  457.                 if (strcmp(handleReceive, "OK") == 0)
  458.                 {
  459.                     cell_processGoodCmdResp((char*)lastCmd->cmd, (char*)cell_lastResponse);
  460.                 }
  461.             }
  462.             // Zero out the cmd struct that was done
  463.             //DBG(D_CELL, "Done - zero-out last cmd\n");
  464.             lastCmd->type = 0;
  465.             lastCmd->sent = 0;
  466.             memset(lastCmd->cmd, 0, sizeof(cmdDataType));
  467.             sendFirst = true;
  468.         }
  469.         else
  470.         {
  471.             //   NULL --> nothing received
  472.             // Has sent the cmd but no resp back and the time allowed
  473.             // to get resp hasn't expired. So, not sending anything
  474.             if(sendState & XFER_SENT_P1)
  475.             {
  476.                 sendFirst = true;
  477.             }
  478.         }
  479.     }
  480.     else
  481.     {
  482.         // cmd has not been sent
  483.         sendFirst = true;
  484.     }
  485.  
  486.     if (sendFirst && cell_atBuffer.count > 0)
  487.     {
  488.         idx                  = cell_atBuffer.front;
  489.         atCmdType *atCommand = &cell_atBuffer.s.arr[idx];
  490.         atCommand->sent      = true;
  491.         cell_lastAtSendDate  = utilsAge();
  492.         if ((atCommand->type == AT_CMD_UDP_MESSAGE) || (atCommand->type == AT_CMD_UDP_DMAN))
  493.         {
  494.             char   msg[6];
  495.             UINT16 cmdLen = atCommand->cmdLen; // already include 2-byte Fletcherchksum + 8-byte IMEI
  496.             UINT8  connId = UDP_MSG_SOC;       // default to pui msg server
  497.  
  498.             if (atCommand->type == AT_CMD_UDP_DMAN)
  499.             {
  500.                 strcpy((char*)msg,"DMAN=");
  501.                 connId = UDP_DMAN_SOC;
  502.             }
  503.             else
  504.             {
  505.                 strcpy((char*)msg,"UDP=");
  506. #if defined(PLATFORM_TALISKER_PRO) || defined(PLATFORM_TALISKER_SPORT)  || defined(PLATFORM_TALISKER_OBD)
  507.               if (!testPuiLoc) {
  508.                 connId = UDP_TALISKER_SOC;
  509.               }
  510. #endif
  511.             }
  512.             // Send data in command mode (see chip's AT command spec for details)
  513.             // at#ssendext=<connId>,<num bytes>,<carrage return>
  514.             // TO DO: make this part cell-chip-specific
  515.  
  516.             if (!(sendState & XFER_SENT_P1))
  517.             {
  518.                 char sendStr[32];
  519.                 // Tell the cell how many bytes to send (cmdLen + 2byte checksum + 16byte imei)
  520.                 memset((char*)sendStr, 0, 32);
  521.                 sprintf((char*)sendStr, "%s%d,%d%s", AT_SEND, connId, cmdLen, RETURN);
  522.                 //printf("Sendp1: %s\n", (char*)sendStr);
  523.                 cellWrite((UINT8*)sendStr, strlen((char*)sendStr));
  524.                 sendState |= XFER_SENT_P1;
  525.                 waitCount(1);        // gives it 10ms to respond
  526.  
  527.                 rtn = true;
  528.             }
  529.             else
  530.             {
  531.                 if (sendState & XFER_SENT_P1)
  532.                 {
  533.                     cellWrite((UINT8*)atCommand->cmd, cmdLen);
  534.                     sendState &= ~XFER_SENT_P1;
  535.                     sendState |= XFER_SENT_P2;
  536.                     //DBG(D_CELL, "Sendp2: cmdLen=%d time=%.3f\n", cmdLen, utilsAge());
  537.                     printf("%s\n", msg);
  538.                     Dump_Hex_Data((UINT8*)atCommand->cmd, cmdLen);
  539.                 }
  540.             }
  541.         }
  542.         else if (atCommand->type == AT_CMD_SMS)
  543.         {
  544.             // Send SMS messages (see cell AT command spec for details)
  545.             // TO DO: make this part cell-chip-specific
  546.             memset((char*)tmpStr, 0, sizeof(tmpStr));
  547.             if (strlen(atCommand->extra) != 0)
  548.             {
  549.                 if (!(sendState & XFER_SENT_P1))
  550.                 {
  551.                     // ATcmd + destAddr + Carriage Return
  552.                     sprintf((char*)tmpStr, "%s%s%s", AT_SMS, (char*)atCommand->cmd, RETURN);
  553.                     //DBG(D_CELL, "SMSp1: len=%d\n", strlen(tmpStr));
  554.                     //Dump_Hex_Data((UINT8*)tmpStr,strlen(tmpStr));
  555.                     cellWrite((UINT8*)tmpStr, strlen((char*)tmpStr));
  556.                     sendState |= XFER_SENT_P1;
  557.                     waitCount(1);        // gives it 10ms to respond
  558.  
  559.                     rtn = true;
  560.                 }
  561.                 else     // must get it by now, more check?
  562.                 {
  563.                     if (sendState & XFER_SENT_P1)
  564.                     {
  565.                         memset((char*)tmpStr, 0, MAX_TMP_STR_LEN);
  566.                         sprintf((char*)tmpStr, "%s%s", (char*)atCommand->extra, CTRL_Z);
  567.                         cellWrite((UINT8*)tmpStr, strlen((char*)tmpStr));
  568.                         //DBG(D_CELL, "SMSp2: len=%d\n", strlen((char*)atCommand->extra));
  569.                         //Dump_Hex_Data((UINT8*)tmpStr,strlen((char*)atCommand->extra));
  570.                         sendState &= ~XFER_SENT_P1;
  571.                         sendState |= XFER_SENT_P2;
  572.                     }
  573.                 }
  574.             } else {
  575.                 // So, if the atCommand->type is AT_CMD_SMS    BUT
  576.                 //     there is nothing in the extra string
  577.                 // WE DO NOTHING????
  578.                 // Just leave the command at the front of the queue FOREVER?
  579.                 //
  580.                 // NO!!! log an error and dump the command!!!!
  581.                 int idx = deQ(&cell_atBuffer); // Upper levels must retry
  582.  
  583.                 atCmdInProgress = false;
  584.  
  585.                 if(idx < 0) {
  586.                     printf("%s, AT queue unexpectedly empty! (3)\n",__func__);
  587.                     return;
  588.                 }
  589.                 atCmdType *lastCmd = &cell_atBuffer.s.arr[idx];
  590.                 lastCmd->type = 0;
  591.                 lastCmd->sent = 0;
  592.                 printf("%s, ERROR -- SMS extra is empty -- cmd ignored!\n",__func__);
  593.             }
  594.         }
  595.         else
  596.         {
  597.             // To support "sendat" with AT# command, use "sendat,AT#<cmdname>"
  598.             memset((char*)tmpStr, 0, sizeof(tmpStr));
  599.             if (((strstr((char*)atCommand->cmd, "AT") == NULL) &&
  600.                     (strstr((char*)atCommand->cmd, "at") == NULL)) ||
  601.                     (strstr((char*)atCommand->cmd, "CGDCONT") != NULL))   // pdpcontext cmd from settings
  602.             {
  603.                 sprintf((char*)tmpStr, "AT+%s%s", (char*)atCommand->cmd, RETURN);
  604.             }
  605.             else
  606.             {
  607.                 sprintf((char*)tmpStr, "%s%s", (char*)atCommand->cmd, RETURN);
  608.             }
  609.             cellWrite((UINT8*)tmpStr, strlen((char*)tmpStr));
  610.         }
  611.     }
  612.     return rtn;
  613. }
  614.  
  615.  
  616. static UINT8 atFaultCount = 0;                  // count of consecutive failed at commands
  617. static UINT8 mdmCycleCount = 0;                 // count of consecutive modem cycles
  618. static UINT8 mdmShdnCount = 0;                  // count of consecutive shutdown cycles
  619. static UINT8 mdmPwrCount = 0;                   // count of consecutive power cycles
  620.  
  621. static UINT8 sktFaultCount = 0;                 // count of consecutive socket faults
  622. static UINT8 sktCycleCount = 0;                 // count of consecutive modem cycles
  623. static UINT8 sktShdnCount = 0;                  // count of consecutive shutdown cycles
  624. static UINT8 sktPwrCount = 0;                   // count of consecutive power cycles
  625.  
  626. /**
  627.  * Clear ALL of the AT command fault counters.
  628.  */
  629. void clrMdmFaults(void) {
  630.   atFaultCount = 0;
  631.   mdmCycleCount = 0;
  632.   mdmShdnCount = 0;
  633.   mdmPwrCount = 0;
  634. }
  635.  
  636.  
  637. /**
  638.  * Pulse the modem cycle pin with the specified pulse width
  639.  */
  640. static void mdmCyclePulse(UINT32 duration)
  641. {
  642.   Mdm_On_Off_Active();
  643.   HAL_Delay(duration);
  644.   Mdm_On_Off_Inactive();
  645.   HAL_Delay(1000);
  646. }
  647.  
  648.  
  649. /**
  650.  * Check for modem faults -- take various modem recovery actions:
  651.  * restarting (cycling), resetting, pulsing power, and
  652.  * ultimately resetting the system.
  653.  */
  654. void monitorModemFaults(void)
  655. {
  656.   if(atFaultCount >= MAX_AT_FAULTS) {
  657.     mdmCycleCount++;
  658.     atFaultCount = 0;
  659.     if(mdmCycleCount < MAX_MODEM_CYCLES) {
  660.       printf("MODEM AT cmd fault count reached maximum!\n");
  661.       mdmCyclePulse(3000);
  662.       mdmCyclePulse(5000);
  663.     } else {
  664.       mdmShdnCount++;
  665.       mdmCycleCount = 0;
  666.       if(mdmShdnCount < MAX_MODEM_SHDNS) {
  667.         printf("MODEM cycle count reached maximum!\n");
  668.         Mdm_Hw_Shdn_Active();
  669.         HAL_Delay(1000);
  670.         Mdm_Hw_Shdn_Inactive();
  671.       } else {
  672.         mdmPwrCount++;
  673.         mdmShdnCount = 0;
  674.         if(mdmPwrCount < MAX_MODEM_PWRS) {
  675.           printf("MODEM shutdown cycle count reached maximum!\n");
  676.           Mdm_Pwr_Disable();
  677.           HAL_Delay(1000);
  678.           Mdm_Pwr_Enable();
  679.         } else {
  680.           printf("MODEM power cycle count reached maximum\n");
  681.           printf("RESET THE SYSTEM -- need to add code here!\n");
  682.           cellControl(CELL_CTRL_OFF);
  683.           HAL_NVIC_SystemReset();
  684.         }
  685.       }
  686.     }
  687.   }
  688. }
  689.  
  690.  
  691. /**
  692.  * Increment the socket fault counter
  693.  * This counter is used by: monitorSocketFaults() to take
  694.  * various recovery actions.
  695.  */
  696. void incSocketFault(void)
  697. {
  698.     sktFaultCount++;
  699. }
  700.  
  701.  
  702. /**
  703.  * Clear ALL of the socket fault counters.
  704.  */
  705. void clrSocketFaults(void)
  706. {
  707.   sktFaultCount = 0;
  708.   sktCycleCount = 0;
  709.   sktShdnCount = 0;
  710.   sktPwrCount = 0;
  711. }
  712.  
  713.  
  714. /**
  715.  * Monitor socket faults -- take various modem recovery actions:
  716.  * restarting (cycling), resetting, pulsing power, and
  717.  * ultimately resetting the system.
  718.  */
  719. void monitorSocketFaults(void)
  720. {
  721.   if(sktFaultCount >= MAX_SOCKET_FAULTS) {
  722.     sktCycleCount++;
  723.     sktFaultCount = 0;
  724.     if(sktCycleCount < MAX_MODEM_CYCLES) {
  725.       printf("SOCKET fault count reached maximum!\n");
  726.       mdmCyclePulse(3000);
  727.       mdmCyclePulse(5000);
  728.     } else {
  729.       sktShdnCount++;
  730.       sktCycleCount = 0;
  731.       if(sktShdnCount < MAX_MODEM_SHDNS) {
  732.         printf("SOCKET cycle count reached maximum!\n");
  733.         Mdm_Hw_Shdn_Active();
  734.         HAL_Delay(1000);
  735.         Mdm_Hw_Shdn_Inactive();
  736.       } else {
  737.         sktPwrCount++;
  738.         sktShdnCount = 0;
  739.         if(sktPwrCount < MAX_MODEM_PWRS) {
  740.           printf("SOCKET shutdown cycle count reached maximum!\n");
  741.           Mdm_Pwr_Disable();
  742.           HAL_Delay(1000);
  743.           Mdm_Pwr_Enable();
  744.         } else {
  745.           printf("SOCKET power cycle count reached maximum\n");
  746.           printf("RESET THE SYSTEM -- need to add code here!\n");
  747.           cellControl(CELL_CTRL_OFF);
  748.           HAL_NVIC_SystemReset();
  749.         }
  750.       }
  751.     }
  752.   }
  753. }
  754.  
  755.  
  756. /**
  757.  * Send AT command to module and add to trace.
  758.  */
  759. void cell_sendAtCmd(char *cmd, UINT8 type, UINT16 len, char *extra, char *whence)
  760. {
  761. #define SHOW_AT_CMDS
  762. #ifdef SHOW_AT_CMDS
  763.   {
  764.     static UINT8 firstTime= 1;
  765.     if(firstTime) {
  766.       UINT32 nowms = (UINT32)getSystemTime();
  767.       int ii;
  768.       printf("%s(%d.%03d)[%s], %d: ", __func__, nowms / 1000,
  769.              nowms % 1000, whence, type);
  770.       //printf("%s(%d)[%s], %d: ", __func__, nowms, whence, type);
  771.       for(ii=0;ii<len;ii++) {
  772.         UINT8 chr = cmd[ii];
  773.         if((chr < 0x20) || (chr > 0x7F)) printf("\\%02X",chr);
  774.         else printf("%c",(char)chr);
  775.       }
  776.       printf("\n");
  777.       if(extra != NULL) printf("extra: %s\n",extra);
  778.     }
  779.   }
  780. #endif // SHOW_AT_CMDS
  781.  
  782.   //DBG(D_CELL, "%s type %d len=%d\n", __FUNCTION__, type, len);
  783.   if (cmd) {
  784.     // force comm wakeup to send at message
  785.     if (main_state == STATE_SLEEPING) {
  786.       main_setState(STATE_STOPPED);
  787.     }
  788.  
  789.         // check cellState before turning it on since no flow control CTS/RTS
  790.         //cellControl(CELL_CTRL_ON);
  791.  
  792.         // Get end slot of the cmd queue
  793.         INT8 rear = enQ(&cell_atBuffer);
  794.  
  795.     if (rear >= 0) {
  796.       atCmdType *atCmd = (atCmdType*)&cell_atBuffer.s.arr[rear];
  797.  
  798.       // Fill out ATcmd struct
  799.       if (atCmd) {
  800.         atCmd->sent = false;
  801.         memcpy((char*)atCmd->cmd, cmd, len);
  802.         atCmd->cmdLen = len;
  803.         if (type)
  804.           atCmd->type = type;
  805.         else
  806.           atCmd->type = AT_CMD_CUSTOM;
  807.         if (extra) {
  808.           memset(atCmd->extra, 0, sizeof(atCmd->extra));
  809.           memcpy((char*)atCmd->extra, extra, strlen(extra));
  810.         }
  811.       } else {
  812.         DBG(D_CELL, "No resource for AT cmd (%s)\n", cmd);
  813.         printf("No resource for AT cmd (%s)\n", cmd);
  814.         return;
  815.       }
  816.       //DBG(D_CELL, "NewCmd: addr=0x%x Qrear=%d Qfront=%d Qcount=%d cmdType=%d len=%d extra=%s\n\n",
  817.       //   (UINT32)atCmd, cell_atBuffer.rear, cell_atBuffer.front, cell_atBuffer.count,
  818.       //   atCmd->type, atCmd->cmdLen, atCmd->extra);
  819.       //Dump_Hex_Data((UINT8*)atCmd->cmd, atCmd->cmdLen);
  820.     }
  821.  
  822.     atCmdInProgress = true;
  823.     if(cell_sendNextAtCommand(NULL)) myHandleCharForCell(__func__);
  824.  
  825. //#define NO_csNAC_RETRY  // csNAC: cell_sendNextAtCommand
  826. #ifdef NO_csNAC_RETRY
  827.     while(atCmdInProgress) handleCharForCell();
  828. #else // NO_csNAC_RETRY
  829.     {
  830.       UINT32 startTime = HAL_GetTick();
  831.       int atRetryCount = AT_MAX_RETRIES;
  832.       while(atCmdInProgress) {
  833.         if((HAL_GetTick() - startTime) > AT_MAX_TIME) {
  834.           if(--atRetryCount > 0) {
  835.             startTime = HAL_GetTick();
  836.             cell_sendNextAtCommand(NULL);  // re-issue the AT command
  837.           } else {
  838.             int items= howQ(&cell_atBuffer);
  839.             printf("\n\nAT cmd: %s(%s)  FAILED!\n\n",whence,cmd);
  840.             if(atFaultCount < MAX_AT_FAULTS) atFaultCount++;
  841.             if(items != 1) {
  842.               printf("UNEXPECTED queue'd 'AT' cmds! (%d > 1)\n",items);
  843.             }
  844.             deQ(&cell_atBuffer);
  845.             break;
  846.           }
  847.         }
  848.         handleCharForCell();
  849.       }
  850.     }
  851.     if(!atCmdInProgress) clrMdmFaults();
  852.     atCmdInProgress = false;
  853. #endif // NO_csNAC_RETRY
  854.  
  855.   }
  856. }
  857.  
  858.  
  859. /**
  860.  * @public
  861.  * @param {string} cmdString (multiple AT cmd separated by ;)
  862.  * NOTE: string may not exceed 256 bytes.
  863.  */
  864. void cell_sendCmds(char *cmdString) {
  865.   int ii;
  866.   int start = 0;
  867.   int len = 0;
  868.  
  869.   printf("%s, cmdString: %s\n",__func__,cmdString); //debug
  870.   for(ii=0;ii<256;ii++) {
  871.     char chr= cmdString[ii];
  872.  
  873.     if((chr == 0) || (chr == ';')) {
  874.       if(len > 0) {
  875.         cell_sendAtCmd(&cmdString[start], 0, len, 0, __func__);
  876.       }
  877.       if(chr == 0) break;
  878.       len = 0;
  879.       start = ii + 1;
  880.     } else {
  881.       len++;
  882.     }
  883.   }
  884. }
  885.  
  886.  
  887. /**
  888.  * Send an SMS.
  889.  *
  890.  * @param {string} to
  891.  * @param {string} txt
  892.  */
  893. void cell_sendSms(char *to, char *txt) {
  894.   char   *ptr  = txt;
  895.   UINT16 index = 0, txtLen = strlen(txt);
  896.   DBG(D_CELL, "%s: tLen=%d TO=%s TEXT=%s\n", __FUNCTION__, txtLen, to, txt);
  897.   do {
  898.     ptr += index;
  899.     cell_sendAtCmd(to, AT_CMD_SMS, (strlen(to) + strlen((char*)AT_SMS)), ptr, __func__);
  900.     index += MAX_SMS_LEN;
  901.   } while (index < txtLen);
  902. }
  903.  
  904.  
  905. /**
  906.  * Called to get new RSSI and Clock data from Comm Module.
  907.  */
  908. void cell_updateInfo(void) {
  909.   if (cell_simStoreReady) {
  910.     cell_sendAtCmd(CSQ, 0, 3, NULL, __func__);
  911.     cell_sendAtCmd(CCLK_QUERRY, 0, 5, NULL, __func__);
  912.     cell_sendAtCmd("COPS?", 0, 5, NULL, __func__);
  913.     if (cellLogic_msisdn == 0) {
  914.       cell_sendAtCmd(CNUM, 0, 4, NULL, __func__);
  915.     }
  916.     cell_sendAtCmd("CREG?", 0, 5, NULL, __func__);
  917.     if (networkType == -1 || cellLogic_mccmnc == 0 || netTypePollCount-- <= 0) {
  918.       netTypePollCount = NETWORK_TYPE_POLL;
  919.       cell_sendAtCmd(AT_RFSTS, 0, 8, NULL, __func__);
  920.       cell_sendAtCmd(AT_PSNT, 0, 8, NULL, __func__);
  921.     }
  922.   }
  923. }
  924.  
  925.  
  926. // Init the pre-allocated pool of AT cmd
  927. // Allow Max 32 outstanding cmds
  928. void initAtCmdPool(void) {
  929.   UINT8 i;
  930.  
  931.   memset((char*)&atCmdPool[0],0, sizeof(atCmdPool));
  932.   memset((char*)&dataPool[0],0, sizeof(dataPool));
  933.   DBG(D_CELL, "Init atCmdPool at 0x%x dataPool at 0x%x\n",
  934.                (UINT32)&atCmdPool[0], (UINT32)&dataPool[0]);
  935.   for (i = 0; i < MAX_NUM_AT_CMD; i++) {
  936.     atCmdPool[i].cmdLen       = 0;
  937.     atCmdPool[i].inUse        = false;
  938.     atCmdPool[i].cmd          = (cmdDataType*)&dataPool[i];
  939.   }
  940. }
  941.  
  942. void cell_enableNetworkRegReport(void) {
  943.   // Check SIM type and issue CREG or CEREG accordingly
  944.   // NOTE: AT+CEREG AT command returns the EPS registration status.
  945.   // For now, check board and infer SIM type
  946.   // TODO: find out how to differentiate SIM type on the same board
  947.   //
  948. #if defined(PLATFORM_TALISKER_PRO) || defined(PLATFORM_TALISKER_SPORT)  || defined(PLATFORM_TALISKER_OBD)
  949.     //////////////////////////// Required to detect Network Detach
  950.     cell_sendCmds("CEREG=2");
  951.     cell_sendCmds("CGREG=2");
  952.     cell_sendCmds("CREG=2");
  953.     ////////////////////////////////////////////////////////////////
  954. #else
  955.     cell_sendCmds("CEREG=2");      // FJ2000 uses AT&T/Verizon SIM which supports CEREG
  956. #endif
  957.   HAL_Delay(100);
  958.   cell_sendCmds("AT#MTUSIZE=1024"); // Possible values of MTU size, only if cell fw >= 20.00.524
  959.                                     // 0 = Default MTU size used by network operator
  960. }
  961.  
  962.  
  963. void cellReadyHandler(void) {
  964.   //DBG(D_CELL, "%s\n", __FUNCTION__);
  965.   if (cell_simStoreReady) {
  966.     DBG(D_CELL, "Send cmds in Q\n");
  967.     if(cell_sendNextAtCommand(NULL)) myHandleCharForCell(__func__);
  968.   } else {
  969.     cell_simStoreReady = true;
  970.     DBG(D_CELL, "Set cell_simStoreReady, send initial ATcmds at %.3f\n", utilsAge());
  971.     cell_enableNetworkRegReport();
  972.     HAL_Delay(100);
  973.     cell_sendCmds("CGSN;CGMR;CNUM;CIMI;CMGF=1;CCID;CSQ");
  974.     HAL_Delay(100);
  975.     cell_sendCmds("CGEREP=2");
  976.   }
  977. }
  978.  
  979.  
  980. void initCell(void) {
  981.   // Create queue for AT cmd
  982.   initAtCmdPool();
  983.   initCellLogic();
  984.   initQ(QTYPE_AT, &cell_atBuffer, MAX_NUM_AT_CMD, (void*)&atCmdPool[0]);
  985.   cell_setDmanServer(settings[DMAN_REPORT_SERVER].u.ptr);
  986. }
  987.  
  988.  
  989. /**
  990.  * Cause Comm Module to wake.
  991.  */
  992. void cell_wake(void) {
  993.   if (settings[POWER_SAVINGS_MODE].u.v.iVal & PWR_MODE_COMM_TURN_OFF) {
  994.     bool pwrStateGood = false;
  995.     cellLogic_commChangeAge = utilsAge();
  996.     cellControl(CELL_CTRL_ON); // no sleep/reset, just power on/off - turn on 5ms from now?
  997.     pwrStateGood = cellControl(CELL_CTRL_CHK_PWR); // no sleep/reset, just power on/off - turn on 5ms from now?
  998.     DBG(D_CELL, "%s pwrStateGood = %d\n", __FUNCTION__, pwrStateGood);
  999.   }
  1000. }
  1001.  
  1002.  
  1003. /**
  1004.  * Comm module to sleep if appropriate
  1005.  */
  1006. void cell_sleep(void) {
  1007.   if (settings[POWER_SAVINGS_MODE].u.v.iVal & PWR_MODE_COMM_LOW) {
  1008.     // comm sleep RXM
  1009.     if (utilsAge() - cellLogic_lastATRcvd > 3) {
  1010.       //DBG(D_CELL, "Sleep: Turn cell low at %.3f\n", utilsAge());
  1011.       //cellControl(CELL_CTRL_OFF); //no sleep/reset, just off?
  1012.     }
  1013.   }
  1014.   if (settings[POWER_SAVINGS_MODE].u.v.iVal & PWR_MODE_COMM_TURN_OFF) {
  1015.     // comm sleep OFF
  1016.     DBG(D_CELL, "Sleep: Turn cell off at %.3f\n", utilsAge());
  1017.     cellControl(CELL_CTRL_OFF);
  1018.     cell_setIsRegistered(false);
  1019.     cell_simStoreReady = false;
  1020.   }
  1021. }
  1022.  
  1023.  
  1024. /**
  1025.  * Power off/on the Comm Module.
  1026.  */
  1027. void cell_reset(void) {
  1028.   DBG(D_CELL, "%s at %.3f\n", __FUNCTION__, utilsAge());
  1029.   cell_setIsRegistered(false);
  1030.   cell_simStoreReady = false;
  1031.   cellLogic_commChangeAge = utilsAge();
  1032.   cellControl(CELL_CTRL_OFF);
  1033.   cellControl(CELL_CTRL_ON);
  1034. }
  1035.  
  1036.  
  1037. /**
  1038.  * Get the length of a DMAN update segment
  1039.  */
  1040. UINT32 cell_segmentLength(void) {
  1041.   //DBG(D_CELL, "%s at %.3f\n", __FUNCTION__, utilsAge());
  1042.   return segmentLength;
  1043. }
  1044.  
  1045. /**
  1046.  * Properly initialize modem based upon carrier
  1047.  *
  1048.  * @param {boolean} force
  1049.  */
  1050. void cell_handleDataSetup (bool force) {
  1051.   char tmp[64];
  1052.  
  1053.   //DBG(D_CELL, "%s\n", __FUNCTION__);
  1054.   // Wait for cell/gps good
  1055.   if (!(cellCheckOpState() & CELL_INIT_DONE)) {
  1056.     DBG(D_CELL, "Cell Init not done, defer dataSetup cellState=0x%x\n",
  1057.                  cellCheckOpState());
  1058.     return; // Wait state is cleared when the ATcmd to setup returns
  1059.   }
  1060.  
  1061.   if (strlen((char*)cellLogic_iccid) != 0) {
  1062.     if (force || (!cellLogic_isCommAvailable && cell_getIsRegistered() && cell_simStoreReady)) {
  1063.  
  1064.       cell_sendCmds(settings[CUSTOM_INIT_AT_CMDS].u.ptr); // define PDP context
  1065.  
  1066.       UINT8 activePDP = 1; // default - check SIM mfg for PDPcontext: Verizon = 3, others = 1
  1067.       char  *strPtr   = NULL;
  1068.       if (strncmp((char*)&cellLogic_iccid[2], "148", 3) == NULL) {
  1069.         activePDP = 3;
  1070.         cell_sendAtCmd("CNMI=3,2,0,0", 0, 12, NULL, __func__); // buffer unsolicited result code
  1071.         printf("Init VZW\n");
  1072.       } else {
  1073.         cell_sendAtCmd("CNMI=2,2,0,0", 0, 12, NULL, __func__); // hw ring line 1s when sms is received
  1074.         printf("Init non-VZW\n");
  1075.       }
  1076.       UINT8 socketToMsgServer = UDP_MSG_SOC;  // default to pui msg server
  1077. #if defined(PLATFORM_TALISKER_PRO) || defined(PLATFORM_TALISKER_SPORT)  || defined(PLATFORM_TALISKER_OBD)
  1078.       if (!testPuiLoc) {
  1079.         socketToMsgServer = UDP_TALISKER_SOC;
  1080.       }
  1081. #endif
  1082.       cell_closeSocket(UDP_DMAN_SOC);
  1083.       cell_closeSocket(socketToMsgServer);
  1084.       cellLogic_handleCommChange(true);
  1085.  
  1086.       // <PDPcontext>,1 (means activate)
  1087.       memset((char*)tmp, 0, sizeof(tmp));
  1088.       sprintf((char*)tmp, "%s%d,1", AT_PDPACT, activePDP);
  1089.       cell_sendAtCmd((char*)tmp, 0, strlen((char*)tmp), NULL, __func__);
  1090.  
  1091.       // socket 1,<PDPcontext>, packetSize 1500
  1092.       memset((char*)tmp, 0, sizeof(tmp));
  1093.       sprintf((char*)tmp, "%s%d,%d,1500,0,600,50", AT_SOC_CFG, socketToMsgServer, activePDP);
  1094.       cell_sendAtCmd((char*)tmp, 0, strlen((char*)tmp), NULL, __func__);
  1095.       // socket 2,<PDPcontext>, packetSize 1500
  1096.       memset((char*)tmp, 0, sizeof(tmp));
  1097.       sprintf((char*)tmp, "%s%d,%d,1500,0,600,50", AT_SOC_CFG, UDP_DMAN_SOC, activePDP);
  1098.       cell_sendAtCmd((char*)tmp, 0, strlen((char*)tmp), NULL, __func__);
  1099.  
  1100.       // socket 1,
  1101.       // 2=Data view: SRING: <connId>,<receivedDataLen>,<data>
  1102.       // 1= Receive data in hex mode (0= Receive data in text mode - normal mode)
  1103.       // 0, 0 = no keep alive, no listen auto-resp
  1104.       // 1= Send data with #SSEND in hex mode
  1105.       memset((char*)tmp, 0, sizeof(tmp));
  1106.       sprintf((char*)tmp, "%s%d,2,0,0,0,1", AT_SOC_CFGEXT, socketToMsgServer);
  1107.       cell_sendAtCmd((char*)tmp, 0, strlen((char*)tmp), NULL, __func__);
  1108.       memset((char*)tmp, 0, sizeof(tmp));
  1109.       sprintf((char*)tmp, "%s%d,2,0,0,0,1", AT_SOC_CFGEXT, UDP_DMAN_SOC);
  1110.       cell_sendAtCmd((char*)tmp, 0, strlen((char*)tmp), NULL, __func__);
  1111.     }
  1112.   } else {
  1113.     DBG(D_CELL, "%s do nothing cell iccid=%s\n", __FUNCTION__, cellLogic_iccid);
  1114.   }
  1115. }
  1116.  
  1117. void cell_closeSocket(UINT8 connId) {
  1118.   char tmp[40];
  1119.   DBG(D_CELL, "%s: %d\n", __FUNCTION__, connId);
  1120.  
  1121.   sprintf((char*)tmp, "%s%d", AT_SOC_SH, connId);
  1122.   cell_sendAtCmd((char*)tmp, 0, strlen((char*)tmp),  NULL, __func__);
  1123.   if (connId == UDP_DMAN_SOC)
  1124.     udpDmanSocketOpen = false;
  1125.   else if (connId == UDP_MSG_SOC)
  1126.     udpMsgSocketOpen = false;
  1127.   else
  1128.     udpTalSocketOpen = false;
  1129. }
  1130.  
  1131. void cell_openSocket(UINT8 connId, char *serverIp, UINT32 port) {
  1132.   char  tmp[40];
  1133.   UINT8 localPort;
  1134.  
  1135.   // If already opened, return
  1136.   if (((connId == UDP_DMAN_SOC) && udpDmanSocketOpen) ||
  1137.       ((connId == UDP_MSG_SOC) && udpMsgSocketOpen) ||
  1138.       ((connId == UDP_TALISKER_SOC) && udpTalSocketOpen))
  1139.     return;
  1140.  
  1141.   if (connId == UDP_MSG_SOC)
  1142.     localPort = 198; // arbitrary
  1143.   else if (connId == UDP_DMAN_SOC)
  1144.     localPort = 199; // arbitrary
  1145.   else
  1146.     localPort = 200; // arbitrary for connection to Talisker server
  1147.  
  1148.   DBG(D_CELL, "%s: %d port %d\n", __FUNCTION__, connId, port);
  1149.   memset((char*)tmp, 0, sizeof(tmp));
  1150.   sprintf((char*)tmp, "%s%d,1,%d,%s,0,%d,1", AT_SOC_OPEN, connId, port, serverIp, localPort);
  1151.   DBG(D_CELL, "%s\n",tmp);
  1152.  
  1153.   cell_sendAtCmd(tmp, 0, strlen((char*)tmp), NULL, __func__);
  1154.   if (connId == UDP_DMAN_SOC)
  1155.     udpDmanSocketOpen = true;
  1156.   else if (connId == UDP_MSG_SOC)
  1157.     udpMsgSocketOpen = true;
  1158.   else
  1159.     udpTalSocketOpen = true;
  1160. }
  1161.  
  1162.  
  1163. /**
  1164.  * Send a UDP packet.  Where type = UDP Server, either Location or PASS
  1165.  *
  1166.  * @param {Uint8Array} data
  1167.  * @param {number} type
  1168.  */
  1169. void cell_sendUdp(UINT8 *data, UINT8 type, UINT32 len) {
  1170.  
  1171.   UINT8 socketToMsgServer = UDP_MSG_SOC;  // default to pui msg server
  1172. #if defined(PLATFORM_TALISKER_PRO) || defined(PLATFORM_TALISKER_SPORT)  || defined(PLATFORM_TALISKER_OBD)
  1173.   if (!testPuiLoc) {
  1174.     socketToMsgServer = UDP_TALISKER_SOC;
  1175.   }
  1176. #endif
  1177.  
  1178.   if (type == AT_CMD_UDP_DMAN) {
  1179.     if (!udpDmanSocketOpen)
  1180.       cell_configUdp(UDP_DMAN_SOC, settings[DMAN_REPORT_SERVER].u.ptr,
  1181.                      settings[DMAN_REPORT_PORT].u.v.iVal);
  1182.   }
  1183.   else if (type == AT_CMD_UDP_MESSAGE) {
  1184.     if (!udpMsgSocketOpen)
  1185.       cell_configUdp(socketToMsgServer, settings[MESSAGES_REPORT_SERVER].u.ptr,
  1186.                      settings[MESSAGES_REPORT_PORT].u.v.iVal);
  1187.   }
  1188.   HAL_Delay(100);
  1189.  
  1190.   // Append the payload to Fletcher+IMEI here to support legacy pui msg with Talisker
  1191.   char   calc[2]  = {0, 0};
  1192.   memset((char*)tmpStr, 0, MAX_TMP_STR_LEN);
  1193.   memcpy((char*)tmpStr+2, (char*)imeiBuffer, 8); // imeiHex string
  1194.   memcpy((char*)(tmpStr+2+8), (char*)data, len); // udp data
  1195.   calcFletcher((char*)(tmpStr+2), len+8, (char*)calc);
  1196.   memcpy((char*)tmpStr, (char*)calc, 2);         // insert Fletcher checksum
  1197.  
  1198.   // Now if it is loc msg, and it is Talisker, wrap the Talisker header/CRC
  1199.   UINT16 totalLen = len + 2 + 8; // 2-byte Fletcherchksum + 8-byte IMEI
  1200. #if defined(PLATFORM_TALISKER_PRO) || defined(PLATFORM_TALISKER_SPORT)  || defined(PLATFORM_TALISKER_OBD)
  1201.   if (type == AT_CMD_UDP_MESSAGE) {
  1202.     cell_sendAtCmd((char*)data, type, len, NULL, __func__);
  1203.   } else {
  1204.     cell_sendAtCmd((char*)tmpStr, type, totalLen, NULL, __func__);
  1205.   }
  1206. #else
  1207.   cell_sendAtCmd((char*)tmpStr, type, totalLen, NULL, __func__);
  1208. #endif
  1209. }
  1210.  
  1211.  
  1212.  
  1213. //
  1214. // Looking for all SRING and process the data associated with them
  1215. //
  1216. void cellParseData(UINT8 *data, UINT16 length) {
  1217.   char *ptr      = NULL;
  1218.   UINT16 dataLen = length;
  1219.  
  1220.   printf("debug Parse, len=%d:\n", length);
  1221.   Dump_Hex_Data((UINT8*)data, 20);
  1222.  
  1223.   ptr = data;
  1224.   while (ptr) {
  1225.     UINT16  readLen = 0;
  1226.     UINT8   socketId;
  1227.     char    *dataPtr, *tok1, *tok2;
  1228.     findToken(1, ptr+7, dataLen, &tok1, ',');
  1229.     findToken(2, ptr+7, dataLen, &tok2, ',');
  1230.     socketId = *tok1 - 0x30;
  1231.     readLen  = (UINT16)strtol(tok2, NULL, 10);
  1232.     DBG(D_CELL, "SRING dataLen=%d socket=%d readLen=%d\n", dataLen, socketId, readLen);
  1233.     //Dump_Hex_Data((UINT8*)data, 256);
  1234.     if (readLen > 0) {
  1235.       //
  1236.       // Get the 3rd token which is data bcause we set srMode=2 in SCFGEXT
  1237.       // which present the data as SRING: <socketId>,<readLen>,<data>
  1238.       //
  1239.       if (findToken(3, ptr, dataLen, &dataPtr, ',')) {
  1240.         if (socketId == UDP_MSG_SOC) {
  1241. #if defined(PLATFORM_TALISKER_PRO) || defined(PLATFORM_TALISKER_OBD)
  1242.            if (Send_Msg(Get_Dei_Net_Q(), dataPtr, readLen) < 0) {
  1243.             printf("%s() Send_Msg() %d bytes failed\n", __func__, readLen);
  1244.           }
  1245. #endif
  1246.         } else {
  1247.           if ((socketId == UDP_DMAN_SOC) && (readLen >= MAX_SEGMENT_LENGTH)) {
  1248.             cellLogic_handleData((UINT8*)dataPtr, readLen);
  1249.             return; // can't have more data
  1250.           } else
  1251.             cellLogic_handleData((UINT8*)dataPtr, readLen);
  1252.         }
  1253.       } else {
  1254.         printf("Parse error, can't find data in SRING\n");
  1255.         break;
  1256.       }
  1257.     } else {
  1258.       printf("Error: dataLen= 0 for SRING\n");
  1259.       break;
  1260.     }
  1261.     ptr = strstr((char*)dataPtr+readLen, "SRING"); // find next SRING
  1262.     dataLen = length - (14 + readLen); // SRING: x,yyyy,<readLen>
  1263.   } // while
  1264. }
  1265.  
  1266. // Data comes from USARTx (hw platform dependent)
  1267. void cellHandler(UINT8 *data, UINT16 length) {
  1268.  
  1269.   data[length] = 0;
  1270.  
  1271.   // Check data comming in from serial port
  1272.   static char cmd[256] = {0, };
  1273.   FLOAT lastDate           = 0;
  1274.   FLOAT cell_lastAtRecDate = 0;
  1275.  
  1276.   if (utilsAge() == lastDate) {
  1277.     DBG(D_CELL, "Set system clock - NO OP\n");
  1278.     // M=16, N=336, P=4, Q=7, latency=2, clkDiv1=2, clkDiv2=4
  1279.     // See "Supported STM32F401xx devices" in targetlibs/stm32f4/lib/system_stm32f4xx.c
  1280.     //sysClockType c = {16, 336, 4, 7, 2, 2, 4};
  1281.     //setSystemClock(&c);
  1282.   }
  1283.   lastDate = utilsAge();
  1284.   cellLogic_lastATRcvd = utilsAge();
  1285.  
  1286.   // Prompt
  1287.   if (length == 2) {
  1288.     //printf("0x%x i0x%x\n", data[0], data[1]);
  1289.  
  1290.     //if(cell_sendNextAtCommand(NULL)) myHandleCharForCell(__func__);  // this is recursive!
  1291.     cell_sendNextAtCommand(NULL);  // this is not recursive!
  1292.  
  1293.   } else if (length > 2) { // ignore lines with just \r\n
  1294.     char   values[4*MAX_TOKEN_SIZE] = {0,}; // 16-byte each val, allow 4 tokens
  1295.     char   *sringPtr;
  1296.  
  1297.     // UDP data from cell
  1298.     if ((sringPtr = strstr((char*)data, "SRING")) != NULL) {
  1299.  
  1300. #ifdef REMOVE_REDUNDANT_OK_ERROR_CHECK
  1301.       // If there's ok or error mixed in process them first
  1302.  
  1303.       char *str= strstr((char*)data, "OK");
  1304.       if (str != NULL) {
  1305.  
  1306.         printf("<< OK found with SRING >>\n"); //debug
  1307.  
  1308.         if(str < sringPtr) {
  1309.           if(cell_sendNextAtCommand("OK")) myHandleCharForCell(__func__);
  1310.           // AND sellParseData() will need to process
  1311.           // any chars after the SRING block (if any)
  1312.         }
  1313.       } else {
  1314.         char *str= strstr((char*)data, "ERROR");
  1315.         if (str != NULL) {
  1316.  
  1317.           printf("<< ERROR found with SRING >>\n"); //debug
  1318.  
  1319.           if(str < sringPtr) {
  1320.             if(cell_sendNextAtCommand("ERROR")) myHandleCharForCell(__func__);
  1321.           }
  1322.         }
  1323.       }
  1324. #endif
  1325.       cellParseData(sringPtr, length);
  1326.       /*
  1327.       NOW, IF cellParseData() IS MODIFIED TO RETURN A POINTER TO
  1328.       THE REMAINDER OF data (IF ANY) THEN THE FOLLOWING  } else {
  1329.       CAN BE USED TO PROCESS IT.  (NOTE -- THIS  IGNORES  THE
  1330.       POSSIBILITY OF 2 OR MORE SRINGS IN THE BUFFER!!!  -- there
  1331.       should be only one unless the first SRING is damaged.)
  1332.       */
  1333.  
  1334.     } else { // command response
  1335.       if (cell_match(data, 0, length, "OK")) {
  1336.  
  1337. //#define ENABLE_RECURSION
  1338. #ifdef ENABLE_RECURSION
  1339.         if(cell_sendNextAtCommand("OK")) myHandleCharForCell(__func__);  // this is recursive!
  1340. #else
  1341.         (void)cell_sendNextAtCommand("OK");  // this is not recursive!
  1342. #endif // ENABLE_RECURSION
  1343.  
  1344.       } else if (cell_match(data, 0, length, "ERROR") || cell_match(data, 5, length, "ERROR")) {
  1345.  
  1346. #ifdef ENABLE_RECURSION
  1347.         if(cell_sendNextAtCommand("ERROR")) myHandleCharForCell(__func__);  // this is recursive!
  1348. #else
  1349.         (void)cell_sendNextAtCommand("ERROR");  // this is not recursive!
  1350. #endif // ENABLE_RECURSION
  1351.  
  1352.       } else {
  1353.         char *dummy = NULL;
  1354.         // strip off 2 CR and 1 LF
  1355.         memset((char*)&cmd[0], 0, sizeof(cmd));
  1356.         arrToStr(data, 0, (UINT8)(length - 3), &cmd[0]);
  1357.         if (!cell_match(data, 1, length, CCLK) && !cell_match(data, 1, length, CSQ) &&
  1358.             !cell_match(data, 3, length, CCLK) && !cell_match(data, 3, length, CSQ)) {
  1359.           strncpy(&cell_lastResponse[0], &cmd[0], MAX_RESP_LEN);
  1360.           //printf("-> %s\n", (char*)&cmd[0]);
  1361.           printf("Modem cmd:\n");
  1362.           Dump_Hex_Data(data, length);
  1363.           //printf("cellHandler debug:\n");
  1364.           //Dump_Hex_Data((UINT8*)&cmd[0], length);
  1365.         }
  1366.         if (cell_match(data, 1, length, CMT)) {
  1367.           char smsFromTemp[SMS_NUMBER_LEN+1]; // extra char for the "+"
  1368.           // LE910:  +CMT: "xxx","","18/03/08,16:45:08-32" - xxx is the src phone#
  1369.           getStrTokens(&cmd[6], (char*)&values[0], ",");
  1370.           if (getSubStrInQuote((char*)smsFromTemp, (char*)&values[0])) {
  1371.             strncpy((char*)cell_smsFrom, (char*)(smsFromTemp+1), sizeof(cell_smsFrom)-1);
  1372.             if (strlen((char*)cell_smsFrom) > 0) {
  1373.                 hasSmsSrc = true;
  1374.             }
  1375.             DBG(D_CELL, "Got CMT/SMS from %s\n", (char*)cell_smsFrom);
  1376.           }
  1377.  
  1378.          } else if (hasSmsSrc && !(sendState & XFER_SENT_P2)) {
  1379.            DBG(D_CELL, "SMS text:\n");
  1380.            hasSmsSrc = false;
  1381.            Dump_Hex_Data((UINT8*)cmd, strlen((char*)cmd));
  1382.            cellLogic_handleSMS((char*)cmd, (char*)cell_smsFrom);
  1383.            memset((char*)cell_smsFrom, 0, sizeof(cell_smsFrom));
  1384.  
  1385.          } else if (cell_match(data, 1, length, CCID)) {
  1386.            cellState |= CELL_GOOD_CCID;
  1387.            getSubStr(cellLogic_iccid, (char*)cmd, 7, length); // check
  1388.            DBG(D_CELL, " cellLogic_ccid=%s\n", (char*)cellLogic_iccid);
  1389.            cell_handleDataSetup(false);
  1390.  
  1391.          // Sometimes data from cell is mangled, prefixed by some other cmd resp
  1392.          // so, can't count from a fixed beginging, just look for the string
  1393.          } else if (((dummy = strstr((char*)data, "+CREG")) != NULL)) {
  1394.             UINT8 state, cnt;
  1395.             UINT8 baseIdx;
  1396.             // cell returns <mode>,<stat>[,<Lac>,<Ci>[,<Act>]] split into multiple arrays
  1397.             cnt = getStrTokens(dummy+7, (char*)&values[0], ",");
  1398.             if (!(cnt == 1 && strlen(&values[0]) == 2 && values[0] == 0x0d && values[1] == 0x0a)) {
  1399.               if (cnt == 1 || (cnt > 1 && values[1*MAX_TOKEN_SIZE] == '"')) {
  1400.                 // CREG requested with AT+CREG?
  1401.                 baseIdx = 0;
  1402.               } else {
  1403.                 // CREG async report from AT+CREG=2
  1404.                 baseIdx = 1;
  1405.               }
  1406.               state = (UINT32)strtol(&values[baseIdx*MAX_TOKEN_SIZE], NULL, 10);
  1407.               DBG(D_CELL, "Got CREG state=%d cnt=%d base=%d\n", state, cnt, baseIdx);
  1408.               bool prevRegState = cell_getIsRegistered();
  1409.               if (state == 5) { // 5 = registered, roaming
  1410.                 cell_isRoaming = true;
  1411.               } else {
  1412.                 cell_isRoaming = false;
  1413.               }
  1414.                 if((state == 1) || cell_isRoaming) {  // 1= registerd home network
  1415.                 cell_setIsRegistered(true);
  1416.               } else {
  1417.                 cell_setIsRegistered(false);
  1418.               }
  1419.              
  1420.               if (cnt > (baseIdx+3)) {
  1421.                 char str[16];
  1422.                 if (getSubStrInQuote((char*)str, (char*)&values[(baseIdx+1)*MAX_TOKEN_SIZE])) {
  1423.                   cellLogic_localAreaCode = (UINT32)strtol((char*)str, NULL, 16);
  1424.                 }
  1425.                 if (getSubStrInQuote((char*)str, (char*)&values[(baseIdx+2)*MAX_TOKEN_SIZE])) {
  1426.                   cellLogic_setCellId((UINT32)strtol((char*)str, NULL, 16));
  1427.                 }
  1428.                 DBG(D_CELL, "cellId=%lx AreadCode=%lx\n", cellLogic_getCellId(), cellLogic_localAreaCode);
  1429.               }              
  1430.  
  1431.               if (cell_getIsRegistered() != prevRegState) {
  1432.                 // A change in the registration state
  1433.                 if (cell_getIsRegistered() && cell_getIsRegistered() != prevRegState) { // registered or roaming
  1434.                   cellState |= CELL_GOOD_CEREG;
  1435.                   cell_handleDataSetup(false);
  1436.                 } else {
  1437.                   cellLogic_handleCommChange(false);
  1438.                 }
  1439.               }
  1440.             }
  1441.  
  1442.          } else if (cell_match(data, 1, length, CSQ)) {
  1443.             INT8 value;
  1444.             UINT8 tmp[4];
  1445.             getSubStr((char*)tmp, (char*)cmd, 6, 7); // +CSQ: 28,4  (which is rssi,ber)
  1446.             value = (INT8)strtol((char*)tmp, NULL, 10);
  1447.             if (value < 32) {
  1448.               value = -113 + value * 2;
  1449.             } else {
  1450.               value = -115;
  1451.             }
  1452.             if (cellLogic_isCommAvailable) {
  1453.               cellLogic_setRssi(value);
  1454.             } else {
  1455.               cellLogic_setRssi(-115);
  1456.             }
  1457.             //DBG(D_CELL, " got CSQ - cell value=%d rssi=%d isCommAVail=%d\n",
  1458.             //             value, cellLogic_rssi, cellLogic_isCommAvailable);
  1459.            // the last init cmd, if setup was defered, go it now
  1460.            if (cellCheckOpState() & CELL_WAIT_SETUP)
  1461.               cell_handleDataSetup(false);
  1462.  
  1463.          } else if (cell_match(data, 1, length, "CNUM")) { // +CNUM: "","12345678..",123
  1464.             char cnum[MAX_TOKEN_SIZE];
  1465.             INT16 idx = 0;
  1466.             getStrTokens((char*)cmd, (char*)values, ",");
  1467.             memset(cnum, 0, MAX_TOKEN_SIZE);
  1468.             if (getSubStrInQuote(cnum, (char*)&values[1*MAX_TOKEN_SIZE])) {
  1469.               if ((idx = getCharIdx(cnum, '+')) != -1) {
  1470.                  cellLogic_msisdn = parseInt(cnum+idx+1, 10);
  1471.               } else {
  1472.                  cellLogic_msisdn = parseInt(cnum, 10);
  1473.               }
  1474.               strcpy((char*)cell_msidnPrint, cnum);
  1475.               DBG(D_CELL, "Got CNUM msisdn=%s\n", cell_msidnPrint);
  1476.             }
  1477.  
  1478.          } else if (cell_match(data, 1, length, "RFSTS")) { // #RFSTS: "310 410",...
  1479.             // RFSTS (Read current network status) provides MCC, MNC and Network Name
  1480.             char mccmnc[MAX_TOKEN_SIZE];
  1481.             if (getSubStrInQuote(mccmnc, cmd)) {
  1482.               remChar(mccmnc, ' ');
  1483.               cellLogic_mccmnc = parseInt(mccmnc, 10);
  1484.               DBG(D_CELL, "Got mccmnc=%lu\n", cellLogic_mccmnc);
  1485.             }
  1486. #if 0
  1487.             // Get the operator name (string)
  1488.             char *tok1, *tok2;
  1489.             if (findToken(17, (char *)(data+7), length, &tok1, ',')
  1490.                 && findToken(18, (char *)(data+7), length, &tok2, ',')) {
  1491.               tok2--; // before the delimeter
  1492.               if (*tok1 == '"') {
  1493.                 tok1++; // remove leading quote
  1494.                 tok2--; // remove trailing quote
  1495.               }
  1496.               INT16 size = (tok2 - tok1);
  1497.               if (size > 32) {
  1498.                 size = 32;  // limit operator name length
  1499.               }
  1500.               strncpy(operatorName, tok1,  size);
  1501.               operatorName[size] = 0;
  1502.               DBG(D_CELL, "Got operator=%s\n", operatorName);
  1503.             } else {
  1504.               DBG(D_CELL, "No operator name\n");
  1505.             }
  1506. #endif
  1507.          } else if (cell_match(data, 1, length, "PSNT")) {
  1508.             // PSTN (Read packet service network type)
  1509.             getStrTokens((char*)cmd, (char*)values, ",");
  1510.             networkType = parseInt(&values[1*MAX_TOKEN_SIZE], 10);
  1511.             DBG(D_CELL, "Got network type=%d\n", networkType);
  1512.  
  1513.          } else if (cell_match(data, 1, length, "CGEV")) {
  1514.             getStrTokens((char*)cmd, (char*)values, ",");
  1515.             DBG(D_CELL, "Got CGEV\n");
  1516.             cellLogic_setCgEvent(&values[0]);
  1517.  
  1518.          } else if (cell_match(data, 1, length, "COPS")) {
  1519.             memset(operatorName, 0, MAX_TOKEN_SIZE);
  1520.             getStrTokens((char*)cmd, (char*)values, ",");
  1521.             if (getSubStrInQuote(operatorName, (char*)&values[2*MAX_TOKEN_SIZE])) {
  1522.  
  1523.               DBG(D_CELL, "COPS: Operator=%s\n", operatorName);
  1524.             } else {
  1525.               DBG(D_CELL, "COPS: No operator name\n");
  1526.             }
  1527.  
  1528.          } else if (cell_match(data, 1, length, CCLK)) {
  1529.  
  1530.            //printf("app/cell.c::%s, have time: %s\n",__func__,cmd); //debug
  1531.  
  1532.            // For Talisker, sync time with Tal server, not using cell time
  1533.            // String. Format is "yy/MM/dd,hh:mm:ss-zz",
  1534.            // where characters indicate year (two last digits),
  1535.            // month, day, hour, minutes, seconds and time zone
  1536.            // (indicates the difference, expressed in quarters
  1537.            // of an hour, between the local time and GMT;
  1538.            // range -96...+96). E.g. 6th of May 1994, 22:10:00
  1539.            // GMT+2 hours equals to "94/05/06,22:10:00+08"
  1540.            char tmp[24];
  1541.            char *cclk = (char*)tmp;
  1542.            char c[3];
  1543.            INT32 year;
  1544.            strcpy((char*)cclk, &cmd[8]);
  1545.            c[0] = cclk[0]; c[1] = cclk[1]; c[2] = '\0';
  1546.            year = (INT32)strtol((char*)c, NULL, 10);
  1547.            year += 2000;
  1548.            //DBG(D_CELL, "clockstr=%s year=%d\n", (char*)tmp, year);
  1549.            if (year > 2016 && year < 2030) {
  1550.              INT32     zoneOffset = 0;
  1551.              structDate d;
  1552.              zoneOffset = (INT32)strtol((char*)&cclk[17], NULL, 10) * 15 * 60;
  1553.              d.year  = year;
  1554.              c[0] = cclk[3]; c[1] = cclk[4];
  1555.              d.month = (UINT8)strtol((char*)c, NULL, 10);
  1556.              c[0] = cclk[6]; c[1] = cclk[7];
  1557.              d.day   = (UINT8)strtol((char*)c, NULL, 10);
  1558.              c[0] = cclk[9]; c[1] = cclk[10];
  1559.              d.hour  = (UINT8)strtol((char*)c, NULL, 10);
  1560.               c[0] = cclk[12]; c[1] = cclk[13];
  1561.              d.min   = (UINT8)strtol((char*)c, NULL, 10);
  1562.              c[0] = cclk[15]; c[1] = cclk[16];
  1563.              d.sec   = (UINT8)strtol((char*)c, NULL, 10);
  1564.               d.ms    = 0;
  1565.              UINT32 nowInSec = utilsGetSecFromDate(&d);
  1566.              //DBG(D_CELL, "clockstr=%s yr=%d mo=%d day=%d hr=%d min=%d sec=%d zone=%ld nowInSec=%u\n",
  1567.                  //cclk, d.year, d.month, d.day, d.hour, d.min, d.sec, zoneOffset, nowInSec);
  1568.              cellLogic_handleClock(nowInSec - zoneOffset);
  1569.            }
  1570.          }
  1571.          if (!(cellState & CELL_INIT_DONE))
  1572.            cellCheckOpState();
  1573.        }
  1574.      }
  1575.    }
  1576. }
  1577.  
  1578. void cell_setIsRegistered(bool isRegistered) {
  1579.   cell_netRegistered = isRegistered;
  1580. }
  1581.  
  1582. bool cell_getIsRegistered() {
  1583.   return cell_netRegistered;
  1584. }
  1585.  
  1586. void cell_setIsSimStoreReady(bool isReady) {
  1587.   cell_simStoreReady = isReady;
  1588. }
  1589.  
  1590. /*
  1591.  * Get the network status. These are the status values:
  1592.  *  -1 have not read status from modem yet
  1593.  *   0 GPRS network
  1594.  *   1 EGPRS network
  1595.  *   2 WCDMA network
  1596.  *   3 HSDPA network
  1597.  *   4 LTE network
  1598.  *   5 unknown or not registered (reported by modem)
  1599.  */
  1600. INT8 cell_networkType() {
  1601.   return networkType;
  1602. }
  1603.  
  1604. char *cell_networkTypeStr() {
  1605.   if (networkType == -1) {
  1606.     return "Unknown";
  1607.   }
  1608.   return networkTypeStr[networkType];
  1609. }
  1610.  
  1611. char *cell_operatorName() {
  1612.   return operatorName;
  1613. }
  1614.  
  1615. #ifdef ENABLE_OPEN_CLOSE_RD_WR_PARADIGM
  1616.  
  1617.  
  1618. NOTE:  UNDER CONSTRUCTION
  1619.  
  1620.  
  1621. /*
  1622. >>Packet Data Protocol (PDP; e.g., IP, X.25, FrameRelay) context
  1623. >>AT+CGDCONT AT commands sets the PDP context parameters such as PDP type
  1624.   (IP, IPV6, PPP, X.25 etc), APN, data compression, header compression etc.
  1625. at+cgdcont=1,"IP","a1.korem2m.com","",0,0      ------> Set APN for context 1
  1626.  
  1627. >>AT#SCFG AT command is used to configure the socket.
  1628. >>AT#SCFG=<connId>,<cid>,<pktSz>,<maxTo>,<connTo>,<txTo>
  1629. at#scfg=X,1,1500,0,600,50                      ------> X is 1 or 2 (Check what format Diep implemented)
  1630. >>At#SCFEXT is used to configure extended parameters of the socket.
  1631. >>AT#SCFGEXT=<conned>,<srMode>,<recvDataMode>,<keepalive>,[,<ListenAutoRsp>[,<sendDataMode>]]
  1632. at#scfgext=X,2,0,0                             ------> X is socket 1 or 2 (Check what format Diep implemented)
  1633.  
  1634. >>AT#SGACT command is used to activate (stat= 1) or deactivate (stat= 0) specific PDP context.
  1635. >>AT#SGACT=<cid>,<stat>[,<userId>,<pwd>]
  1636. at#sgact=1,1                                   ------> Open data session for context 1
  1637.  
  1638. >>AT#SD AT command opens remote connection via socket.
  1639. >>AT#SD=<connId>,<txProt>,<rPort>,<IPaddr>[,<closureType>[,<lPort>[,<connMode>]]]
  1640. at#sd=X,1,<remote port>,"<remote ip>",0,1234,1 ------> X is socket 1 or 2
  1641.  
  1642. >>This command is used to close a socket. {This command is used to close a socket: 1..6}
  1643. >>Note: socket cannot be closed in states “resolving DNS” and “connecting” (see AT#SS command)
  1644. at#sh=X                                        ------> Close socket X
  1645.  
  1646. >>AT#SGACT command is used to activate (stat= 1) or deactivate (stat= 0) specific PDP context.
  1647. >>AT#SGACT=<cid>,<stat>[,<userId>,<pwd>]
  1648. at#sgact=1,0                                   ------> Close data session (see this is the same number as in APN 1)
  1649.  
  1650. >>AT#SHDN AT command causes the device to detach from the netwrok and shutdown.
  1651. at#shdn                                        ------> Turn off modem
  1652.                                                ------> Remove power from modem
  1653.                                                ------> Wait 15 secs
  1654.                                                ------> Enable modem power
  1655.                                                ------> Reinit
  1656. */
  1657.  
  1658. #define CTX_OK                    0
  1659. #define CTX_NOT_OPEN             -1
  1660. #define CTX_ALREADY_OPEN         -2
  1661. #define CTX_NO_REG               -3
  1662. #define CTX_BAD_CID              -4
  1663. #define CTX_ACTIVATION_FAILED    -5
  1664. #define CTX_BAD_HANDLE           -6
  1665.  
  1666. #define MAX_MDM_CONTEXTS         1
  1667.  
  1668. typedef struct {
  1669.   INT8 handle;
  1670.   UINT8 cid;
  1671. } mdmContext_t;
  1672.  
  1673. static mdmContext_t mdmh[MAX_MDM_CONTEXTS];
  1674.  
  1675. // Opens a context using the specified apn # (cid: context id )
  1676. // i.e. obtains an ip address used to communicate with other internet sites
  1677. // Returns:
  1678. //   >= 0 -- context handle (there is only 1 for now and it is always 0)
  1679. //    < 0 -- error code
  1680. //
  1681. int openContext(int cid)
  1682. {
  1683.   if (mdmh[0].handle >= 0)
  1684.     return CTX_ALREADY_OPEN; // already open
  1685.   }
  1686.   if (!cell_getIsRegistered()) {
  1687.     return CTX_NO_REG;   // NOT registered (out of coverage?)
  1688.   }
  1689.   if ((cid != 1) && (cid != 3)) {
  1690.     return CTX_BAD_CID; // invalid context id specified
  1691.   }
  1692.   // >>AT#SGACT command is used to activate (stat= 1) or deactivate (stat= 0) specific PDP context.
  1693.   // >>AT#SGACT=<cid>,<stat>[,<userId>,<pwd>]
  1694.   // at#sgact=1,1                                   ------> Open data session for context 1
  1695.   // cell_sendAtCmd(tmp, 0, strlen((char*)tmp), NULL);
  1696.   //cell_sendAtCmd(tmp, 0, strlen((char*)tmp), NULL, __func__); //debug
  1697.   return CTX_ACTIVATION_FAILED;                    // context activation failed
  1698. }
  1699.  
  1700. // Closes the specified context
  1701. //
  1702. int closeContext(int handle)
  1703. {
  1704.   if (handle != 0) {
  1705.     return CTX_BAD_HANDLE;           // invalid handle
  1706.   }
  1707.   if (mdmh[handle].handle < 0) {
  1708.     return CTX_NOT_OPEN; // not open
  1709.   }
  1710.  
  1711.   // >>AT#SGACT command is used to activate (stat= 1) or deactivate (stat= 0) specific PDP context.
  1712.   // >>AT#SGACT=<cid>,<stat>[,<userId>,<pwd>]
  1713.   // at#sgact=1,0                                   ------> Close data session (see this is the same number as in APN 1)
  1714.   mdmh[handle].handle = -1;
  1715.   return CTX_OK;
  1716. }
  1717.  
  1718. //void cell_closeSocket(UINT8 connId) {
  1719. //void cell_openSocket(UINT8 connId, char *serverIp, UINT32 port) {
  1720.  
  1721. // Opens a socket using the specified ip and port
  1722. // (What apnNum is this associated with?????)
  1723. // Returns:
  1724. int openSocket(UINT32 ip,UINT16 port)
  1725. {
  1726.   return -1;
  1727. }
  1728.  
  1729. // Closes the specified socket
  1730. //
  1731. void closeSocket(int handle)
  1732. {
  1733.  
  1734. }
  1735.  
  1736.  
  1737. // Do we want to allow timeouts to be specified for readSocket() and writeSocket()???????????????
  1738.  
  1739. // Writes a UDP packet to the specified socket
  1740. // Returns:
  1741. //   < 0 -- error
  1742. //   = 0 -- ERROR, this should NEVER happen!
  1743. //   > 0 -- # of bytes written
  1744. int writeSocket(int handle,UINT8 *udp,int len)
  1745. {
  1746.   return -1;
  1747. }
  1748.  
  1749. // Reads a UDP packet from the specified socket
  1750. // Returns:
  1751. //   < 0 -- error
  1752. //   = 0 -- no data available
  1753. //   > 0 -- # of bytes in the UDP packet
  1754. //
  1755. int readSocket(int handle,UINT8 *udp,int maxLen)
  1756. {
  1757.   // How do we initiate a UDP read from the back end?????????????????????????
  1758.   return 0;   // nothing available
  1759. }
  1760. #endif // ENABLE_OPEN_CLOSE_RD_WR_PARADIGM
  1761.  
  1762. /*
  1763.  * Set the DMAN server.
  1764.  */
  1765. void cell_setDmanServer(char *server) {
  1766.   strcpy(cell_dmanServer, server);
  1767. }
  1768.  
  1769.