Files
qmk-keychron-q3-colemak-dh/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.cpp
Jun Wako 1fe4406f37 Squashed 'tmk_core/' changes from 7967731..b9e0ea0
b9e0ea0 Merge commit '7fa9d8bdea3773d1195b04d98fcf27cf48ddd81d' as 'tool/mbed/mbed-sdk'
7fa9d8b Squashed 'tool/mbed/mbed-sdk/' content from commit 7c21ce5

git-subtree-dir: tmk_core
git-subtree-split: b9e0ea08cb940de20b3610ecdda18e9d8cd7c552
2015-04-24 16:26:14 +09:00

424 lines
10 KiB
C++

/* GSMSMSInterface.cpp */
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define __DEBUG__ 2
#ifndef __MODULE__
#define __MODULE__ "GSMSMSInterface.cpp"
#endif
#include "core/fwk.h"
#include "GSMSMSInterface.h"
#include <cstdio>
#include <cstring>
#define DEFAULT_TIMEOUT 10000
GSMSMSInterface::GSMSMSInterface(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 GSMSMSInterface::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)
{
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;
}
int GSMSMSInterface::send(const char* number, const char* message)
{
if( strlen(number) > 16 )
{
return NET_INVALID; //Number too long to match 3GPP spec
}
int ret;
//Prepare infos
m_state = SMS_SEND_CMD_SENT;
m_msg = (char*) message;
DBG("Send SM");
//Send command
char cmd[32];
std::sprintf(cmd, "AT+CMGS=\"%s\"", number);
ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
if( (ret != OK) || (m_state != SMS_CMD_PROCESSED) )
{
WARN("ret %d, state %d", ret, m_state);
m_state = SMS_IDLE;
return NET_PROTOCOL;
}
DBG("SM sent");
m_state = SMS_IDLE;
return OK;
}
int GSMSMSInterface::get(char* number, char* message, size_t maxLength)
{
if( maxLength < 1 )
{
return NET_INVALID; //Buffer too short
}
int ret;
DBG("Get next message");
m_inboxMtx.lock();
if( ((m_msgRefListCount == 0) && m_needsUpdate) || ((m_msgRefListCount > 0) && (m_msgRefList[0] == -1)) )
{
DBG("Message list count is 0 and needs updating or next index is unknown, calling updateInbox()");
ret = updateInbox();
if (ret)
{
m_inboxMtx.unlock();
return ret;
}
}
DBG("%d messages to read", m_msgRefListCount);
if(m_msgRefListCount == 0)
{
m_inboxMtx.unlock();
DBG("Message list count is 0, I think it's empty and returning.");
return NET_EMPTY; //No message to read
}
//Prepare infos
m_state = SMS_GET_CMD_SENT;
m_msisdn = (char*) number;
m_msg = (char*) message;
m_maxMsgLength = maxLength;
DBG("Get SMS");
//List command
char cmd[32];
std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]);
ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
if( ret != OK )
{
WARN("AT+CMGR returned %d", ret);
m_state = SMS_IDLE;
m_inboxMtx.unlock();
return NET_PROTOCOL;
}
if (m_state != SMS_CMD_PROCESSED)
{
WARN("State variable is not 'SMS_CMD_PROCESSED' - returning 'NET_EMPTY'");
}
DBG("Deleting message from index number: %d", m_msgRefList[0] );
//Delete message from outbox
std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]);
ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
if(ret != OK)
{
ERR("Could not delete message");
}
//Remove message from list
std::memmove(&m_msgRefList[0], &m_msgRefList[1], MIN(m_msgRefListCount-1,MAX_SM-1)*sizeof(m_msgRefList[0]));
m_msgRefListCount--;
if(m_msgRefListCount > MAX_SM - 1) //Last message index is unknown, so put -1 to tell the lib to fetch it when needed
{
DBG("Last message index is unknown, will need to be updated");
m_msgRefList[MAX_SM - 1] = -1;
}
DBG("%d messages to read", m_msgRefListCount);
if (m_state != SMS_CMD_PROCESSED)
{
m_state = SMS_IDLE;
m_inboxMtx.unlock();
return NET_EMPTY;
}
m_state = SMS_IDLE;
m_inboxMtx.unlock();
return OK;
}
int GSMSMSInterface::getCount(size_t* pCount)
{
int ret;
m_inboxMtx.lock();
if( m_needsUpdate )
{
ret = updateInbox();
if(ret)
{
m_inboxMtx.unlock();
return NET_PROTOCOL;
}
}
*pCount = m_msgRefListCount;
m_inboxMtx.unlock();
return OK;
}
/*virtual*/ int GSMSMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
{
if(m_state == SMS_SEND_CMD_SENT)
{
if( std::sscanf(line, "+CMGS: %*d") == 0 )
{
DBG("SM sent");
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
{
m_state = SMS_GET_HDR_RECEIVED;
}
}
else if(m_state == SMS_GET_HDR_RECEIVED)
{
DBG("Message: %s", line);
size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
std::memcpy( m_msg, line, cpyLen );
m_msg[cpyLen] = '\0';
m_state = SMS_CMD_PROCESSED;
}
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
{
m_state = SMS_GET_COUNT_HDR_RECEIVED;
//Add message to list
if(m_msgRefListCount < MAX_SM)
{
m_msgRefList[m_msgRefListCount] = msgRef;
}
m_msgRefListCount++; //Always count message
DBG("m_msgRefListCount=%d",m_msgRefListCount);
}
}
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 GSMSMSInterface::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';
//If there is a CR char, split message there
//Do print the message
int ret = pInst->sendData(m_msg);
if(ret)
{
return ret;
}
char cr[2] = {CR, '\0'};
ret = pInst->sendData(cr);
if(ret)
{
return ret;
}
m_msg += crPos;
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;
}
}
return OK;
}
/*virtual*/ bool GSMSMSInterface::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 GSMSMSInterface::onDispatchStart()
{
}
/*virtual*/ void GSMSMSInterface::onDispatchStop()
{
}
/*virtual*/ char* GSMSMSInterface::getEventsEnableCommand()
{
return "AT+CNMI=2,1,0,0,0";
}
/*virtual*/ char* GSMSMSInterface::getEventsDisableCommand()
{
return "AT+CNMI=0,0,0,0,0"; //Indications will be buffered within the modem and flushed back when the former command is executed
}
/*virtual*/ void GSMSMSInterface::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 ) ||
( std::sscanf(evt, "\"ME\",%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;
}
m_msgRefListCount++; //Always count message
m_inboxMtx.unlock();
}
else
{
WARN("Could not get lock");
m_needsUpdate = true;
}
}
}
int GSMSMSInterface::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);
m_state = SMS_IDLE;
return OK;
}