USB Host Library for Sprint Dongles
Dependencies: Socket USBHostWANDongleSprint lwip-sys lwip
Dependents: SprintUSBModemWebsocketTest SprintUSBModemHTTPClientTest SprintUSBModemNTPClientTest SprintUSBModemSMSTest ... more
Fork of SprintUSBModem_bleedingedge by
Diff: sms/SMSInterface.cpp
- Revision:
- 6:56000fe39df9
- Parent:
- 4:23100b0757d6
- Child:
- 7:098c2adcc17a
--- a/sms/SMSInterface.cpp Wed Oct 10 08:29:50 2012 +0000 +++ b/sms/SMSInterface.cpp Wed Oct 10 14:44:11 2012 +0000 @@ -17,7 +17,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#define __DEBUG__ 2 +#define __DEBUG__ 0 #ifndef __MODULE__ #define __MODULE__ "SMSInterface.cpp" #endif @@ -32,44 +32,19 @@ SMSInterface::SMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL) { - m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers } int SMSInterface::init() { - m_msgRefListCount = 0; - m_needsUpdate = true; m_state = SMS_IDLE; - DBG("Set format"); - //Set Text mode format - int ret = m_pIf->executeSimple("AT+CMGF=1", NULL, DEFAULT_TIMEOUT); - if(ret != OK) + DBG("Get number of messages in the different inboxes"); + int ret = updateInbox(); + if(ret) { return NET_PROTOCOL; } - - DBG("Setup new messages indication"); - //Setup new messages indication - ret = m_pIf->executeSimple("AT+CNMI=2,1,0,0,0", NULL, DEFAULT_TIMEOUT); - if(ret != OK) - { - return NET_PROTOCOL; - } - - DBG("Try to fetch inbox"); - m_inboxMtx.lock(); - if( m_needsUpdate ) - { - ret = updateInbox(); //Fetch existing messages references - if(ret) - { - m_inboxMtx.unlock(); - return NET_PROTOCOL; - } - } - m_inboxMtx.unlock(); - + DBG("Initialization done"); return OK; } @@ -78,30 +53,63 @@ { if( strlen(number) > 16 ) { - return NET_INVALID; //Number too long to match 3GPP spec + return NET_INVALID; //Number too long } int ret; //Prepare infos m_state = SMS_SEND_CMD_SENT; - m_msg = (char*) message; + + bool intlNumber=(number[0]=='+'); //If the number starts with the + sign, replace it with 011 instead (int'l dialing code in the US) DBG("Send SM"); //Send command - char cmd[32]; - std::sprintf(cmd, "AT+CMGS=\"%s\"", number); + char cmd[32+strlen(message)]; + std::sprintf(cmd, "AT!SSMS=0,%s%s,,\"%s\"",intlNumber?"011":"", intlNumber?(number+1):number, message); //Send with normal priority ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT); - if( (ret != OK) || (m_state != SMS_CMD_PROCESSED) ) + if(ret != OK) { - WARN("ret %d, state %d", ret, m_state); + WARN("ret %d", ret); m_state = SMS_IDLE; return NET_PROTOCOL; } - DBG("SM sent"); - m_state = SMS_IDLE; + DBG("Check status"); + m_txState = SMS_PENDING; + + int tries = 10; + while(tries--) + { + m_state = SMS_GET_TX_STATUS_CMD_SENT; + ret = m_pIf->execute("AT!SSMS?", this, NULL, DEFAULT_TIMEOUT); + if(ret) + { + m_state = SMS_IDLE; + return ret; + } + m_state = SMS_IDLE; + if(m_txState == SMS_PENDING) //Wait more + { + Thread::wait(1000); + continue; + } + else if(m_txState == SMS_FAILED) + { + ERR("The modem could not send the SM"); + return NET_CONN; //Probably a conenction issue, the user can retry + } + else + { + break; + } + } + if(!tries) + { + ERR("The is still trying to send the SM"); + return NET_TIMEOUT; + } return OK; } @@ -116,24 +124,35 @@ int ret; DBG("Get next message"); - m_inboxMtx.lock(); - if(m_msgRefListCount == 0 && m_needsUpdate) + if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0) { DBG("Message list count is 0 and needs updating. Running updateInbox."); ret = updateInbox(); - if (ret) { - m_inboxMtx.unlock(); return ret; } } - if(m_msgRefListCount == 0) + if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0) + { + DBG("Message list count is 0"); + return NET_EMPTY; //No message to read + } + + //Determine which index to use : 3 (read), then 1 (urgent), then 2 (regular) + int index; + if(m_msgInListsCount[2]) { - m_inboxMtx.unlock(); - DBG("Message list count is 0, I think it's empty and returning."); - return NET_EMPTY; //No message to read + index = 3; + } + else if(m_msgInListsCount[0]) + { + index = 1; + } + else //if(m_msgInListsCount[1]) + { + index = 2; } //Prepare infos @@ -141,46 +160,65 @@ m_msisdn = (char*) number; m_msg = (char*) message; m_maxMsgLength = maxLength; + m_headersToRead = 3; + + m_msisdn[0] = '\0'; DBG("Get SMS"); - //List command + //Read command char cmd[32]; - std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]); + std::sprintf(cmd, "AT!GSMS?%d,1", index); //1 is the oldest message ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT); if( ret != OK ) { - WARN("AT+CMGR returned %d", ret); + WARN("AT!GSMS returned %d", ret); m_state = SMS_IDLE; - m_inboxMtx.unlock(); return NET_PROTOCOL; } - - if (m_state != SMS_CMD_PROCESSED) + + //If message is not read, it will be put at the end of the read list + int item; + if( index != 3 ) { - WARN("State variable is not 'SMS_CMD_PROCESSED' - returning 'NET_EMPTY'"); + //Decrement count in relevant list + m_msgInListsCount[index-1]--; + //Increment count in read list + m_msgInListsCount[3-1]++; + item = m_msgInListsCount[3-1]; + //Normally item should be equal to 1 as we'd have read any older messages first + if( item != 1 ) + { + WARN("Still some older messages pending in the read inbox"); + } } - - DBG("Deleting message from index number: %d", m_msgRefList[0] ); - //Delete message from outbox - std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]); + else + { + //The item is still the oldest one + item = 1; + } + + DBG("Deleting message"); + //Delete message from inbox + std::sprintf(cmd, "AT!DSMS=3"/*%d", item*/); //FIXME why doesn't that works when specifying the index?? ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT); if(ret != OK) { ERR("Could not delete message"); } - //Remove message from list - std::memmove(m_msgRefList, m_msgRefList+1, m_msgRefListCount-1); - m_msgRefListCount--; + else + { + //Now we can decrease the number of read messages + m_msgInListsCount[3-1]--; + } if (m_state != SMS_CMD_PROCESSED) { + WARN("Message could not be retrieved properly"); m_state = SMS_IDLE; - m_inboxMtx.unlock(); return NET_EMPTY; } m_state = SMS_IDLE; - m_inboxMtx.unlock(); return OK; } @@ -188,21 +226,13 @@ int SMSInterface::getCount(size_t* pCount) { - int ret; - - m_inboxMtx.lock(); - if( m_needsUpdate ) + int ret = updateInbox(); + if(ret) { - ret = updateInbox(); - if(ret) - { - m_inboxMtx.unlock(); return NET_PROTOCOL; - } } - *pCount = m_msgRefListCount; - m_inboxMtx.unlock(); + *pCount = m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]; //Urgent messages + regular messages + read messages return OK; } @@ -212,18 +242,52 @@ { if(m_state == SMS_SEND_CMD_SENT) { - if( std::sscanf(line, "+CMGS: %*d") == 0 ) + DBG("SMS Send: %s", line); + } + else if(m_state == SMS_GET_TX_STATUS_CMD_SENT) + { + if(!strcmp(line, "sent")) + { + m_txState = SMS_SENT; + m_state = SMS_CMD_PROCESSED; + } + else if(!strcmp(line, "failed")) { - DBG("SM sent"); + m_txState = SMS_FAILED; + m_state = SMS_CMD_PROCESSED; + } + else if(!strcmp(line, "none")) + { + m_txState = SMS_NONE; + m_state = SMS_CMD_PROCESSED; + } + else if(!strcmp(line, "pending")) + { + m_txState = SMS_PENDING; m_state = SMS_CMD_PROCESSED; } } else if(m_state == SMS_GET_CMD_SENT) { DBG("Header: %s", line); - if( std::sscanf(line, "+CMGR: %*[^,],\"%16[^\"]\"", m_msisdn) == 1 ) //Get message ref + + if(m_msisdn[0]=='\0') { - m_state = SMS_GET_HDR_RECEIVED; + sscanf(line, "From: %16s", m_msisdn); + } + + m_headersToRead--; + + if(m_headersToRead==0) //End of headers + { + if(m_msisdn[0]!='\0') //Checks that the incoming number has been retrieved + { + m_state = SMS_GET_HDR_RECEIVED; + } + else + { + m_state = SMS_IDLE; //Error, signal it + } } } else if(m_state == SMS_GET_HDR_RECEIVED) @@ -236,175 +300,48 @@ } else if(m_state == SMS_GET_COUNT_CMD_SENT) { - DBG("Header: %s", line); - int msgRef; - if( std::sscanf(line, "+CMGL: %d,\"REC", &msgRef) == 1 ) //Filter on REC READ and REC UNREAD messages + DBG("Inbox: %s", line); + int index; + size_t count; + if((strlen(line) > 16) && sscanf(line + 16, "{Index = %d}: %d", &index, &count) == 2) { - m_state = SMS_GET_COUNT_HDR_RECEIVED; - //Add message to list - if(m_msgRefListCount < MAX_SM) + if((index > 0) && (index <=4)) { - m_msgRefList[m_msgRefListCount] = msgRef; + m_msgInListsCount[index-1] = count; } - m_msgRefListCount++; //Always count message - DBG("m_msgRefListCount=%d",m_msgRefListCount); + if(index == 4) + { + m_state = SMS_CMD_PROCESSED; + } } } - else if(m_state == SMS_GET_COUNT_HDR_RECEIVED) - { - DBG("Message (debug only): %s", line); //For debug only - m_state = SMS_GET_COUNT_CMD_SENT; - } return OK; } /*virtual*/ int SMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst) { - if(m_state == SMS_SEND_CMD_SENT) - { - char* crPtr = strchr(m_msg, CR); - if(crPtr != NULL) - { - int crPos = crPtr - m_msg; - //Replace m_inputBuf[crPos] with null-terminating char - m_msg[crPos] = '\x0'; + return OK; +} + - //If there is a CR char, split message there - - //Do print the message - int ret = pInst->sendData(m_msg); - if(ret) - { - return ret; - } +int SMSInterface::updateInbox() +{ + //Get number of unread/read messages - char cr[2] = {CR, '\0'}; - ret = pInst->sendData(cr); - if(ret) - { - return ret; - } - - m_msg += crPos; + DBG("Updating inbox"); + m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Reset counts - if(m_msg[0] == LF) - { - m_msg++; //Discard LF char as well - } - - return NET_MOREINFO; - } - else - { - //Do print the message - pInst->sendData(m_msg); - return OK; - } + //Get counts + m_state = SMS_GET_COUNT_CMD_SENT; + int ret = m_pIf->execute("AT!CNTSMS", this, NULL, DEFAULT_TIMEOUT); + if( ret != OK ) + { + WARN("AT!CNTSMS returned %d", ret); + m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Invalidate counts + m_state = SMS_IDLE; + return NET_PROTOCOL; } return OK; } -/*virtual*/ bool SMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled -{ - DBG("AT code is %s", atCode); - if( strcmp("+CMTI", atCode) == 0 ) - { - return true; - } - - DBG("Not handled"); - return false; -} - -/*virtual*/ void SMSInterface::onDispatchStart() -{ - - -} - -/*virtual*/ void SMSInterface::onDispatchStop() -{ - -} - -/*virtual*/ void SMSInterface::onEvent(const char* atCode, const char* evt) -{ - if( strcmp("+CMTI", atCode) != 0 ) - { - return; //Not supported - } - - DBG("Unsollicited result code: %s - %s", atCode, evt); - - //Get index - int msgRef; - if( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 ) - { - DBG("Adding message to list (ref %d)", msgRef); - if(m_inboxMtx.trylock()) - { - //Add message to list - if(m_msgRefListCount < MAX_SM) - { - m_msgRefList[m_msgRefListCount] = msgRef; - } - else - { - m_needsUpdate = true; - } - m_msgRefListCount++; //Always count message - m_inboxMtx.unlock(); - } - else - { - WARN("Could not get lock"); - m_needsUpdate = true; - } - } -} - -int SMSInterface::updateInbox() -{ - //Get memory indexes of unread messages - - DBG("Updating inbox"); - m_msgRefListCount = 0; //Reset list - m_needsUpdate = false; //Assume we won't need update after this routine (can be set to true by an incoming SM event) - - //First list the "REC READ" messages that were not processed in the previous session - m_state = SMS_GET_COUNT_CMD_SENT; - int ret = m_pIf->execute("AT+CMGL=\"REC READ\"", this, NULL, DEFAULT_TIMEOUT); - if( ret != OK ) - { - WARN("AT+CMGL returned %d", ret); - m_state = SMS_IDLE; - m_msgRefListCount = 0; //List could be invalid - m_needsUpdate = true; - return NET_PROTOCOL; - } - - //Now list the "REC UNREAD" messages that were received by the modem since - m_state = SMS_GET_COUNT_CMD_SENT; - ret = m_pIf->execute("AT+CMGL=\"REC UNREAD\"", this, NULL, DEFAULT_TIMEOUT); - if( ret != OK ) - { - WARN("AT+CMGL returned %d", ret); - m_state = SMS_IDLE; - m_msgRefListCount = 0; //List could be invalid - m_needsUpdate = true; - return NET_PROTOCOL; - } - - DBG("%d incoming messages in inbox", m_msgRefListCount); - - if( m_msgRefListCount > MAX_SM ) - { - m_needsUpdate = true; - } - - m_state = SMS_IDLE; - - return OK; -} -