diff options
Diffstat (limited to 'tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem')
26 files changed, 4000 insertions, 0 deletions
diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/CellularModem.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/CellularModem.h new file mode 100644 index 0000000000..fd47622c86 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/CellularModem.h @@ -0,0 +1,78 @@ +/* CellularModem.h */ +/* Copyright (C) 2013 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. + */ + +#ifndef CELLULARMODEM_H_ +#define CELLULARMODEM_H_ + +#include "core/fwk.h" +#include "at/ATCommandsInterface.h" + +class CellularModem +{ +public: + //Internet-related functions + + /** Open a 3G internet connection + @return 0 on success, error code on failure + */ + virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL) = 0; + + /** Close the internet connection + @return 0 on success, error code on failure + */ + virtual int disconnect() = 0; + + + /** Send a SM + @param number The receiver's phone number + @param message The message to send + @return 0 on success, error code on failure + */ + virtual int sendSM(const char* number, const char* message) = 0; + + + /** Receive a SM + @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char) + @param message Pointer to a buffer to store the the incoming message + @param maxLength Maximum message length that can be stored in buffer (including null-terminating character) + @return 0 on success, error code on failure + */ + virtual int getSM(char* number, char* message, size_t maxLength) = 0; + + /** Get the number of SMs in the incoming box + @param pCount pointer to store the number of unprocessed SMs on + @return 0 on success, error code on failure + */ + virtual int getSMCount(size_t* pCount) = 0; + + /** Get the ATCommandsInterface instance + @return Pointer to the ATCommandsInterface instance + */ + virtual ATCommandsInterface* getATCommandsInterface() = 0; + + /** Switch power on or off + In order to use this function, a pin name must have been entered in the constructor + @param enable true to switch the dongle on, false to switch it off + @return 0 on success, error code on failure + */ + virtual int power(bool enable) = 0; +}; + + +#endif /* CELLULARMODEM_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.cpp new file mode 100644 index 0000000000..9f711630ce --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.cpp @@ -0,0 +1,902 @@ +/* ATCommandsInterface.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 //ERR+WARN +#ifndef __MODULE__ +#define __MODULE__ "ATCommandsInterface.cpp" +#endif + +#include "core/fwk.h" + +#include <cstdio> +#include <cstring> //For memset, strstr... + +using std::memmove; + +#include "ATCommandsInterface.h" + +ATCommandsInterface::ATCommandsInterface(IOStream* pStream) : + m_pStream(pStream), m_open(false), m_transactionState(IDLE), m_env2AT(), m_AT2Env(), m_processingMtx(), + m_processingThread(&ATCommandsInterface::staticCallback, this, (osPriority)AT_THREAD_PRIORITY, 4*192), + m_eventsMgmtMtx(), m_eventsProcessingMtx() +{ + memset(m_eventsHandlers, 0, MAX_AT_EVENTS_HANDLERS * sizeof(IATEventsHandler*)); + + m_processingMtx.lock(); +} + +//Open connection to AT Interface in order to execute command & register/unregister events +int ATCommandsInterface::open() +{ + if( m_open ) + { + WARN("AT interface is already open"); + return OK; + } + DBG("Opening AT interface"); + //Start processing + m_processingThread.signal_set(AT_SIG_PROCESSING_START); + + m_processingMtx.unlock(); + + m_open = true; + + DBG("AT interface opened"); + + return OK; +} + +//Initialize AT link & start events processing +int ATCommandsInterface::init(bool reset /* = true*/) +{ + + //Lock transaction mutex + m_transactionMtx.lock(); + + if (reset) + { + DBG("Sending ATZ E1 V1"); + //Should we flush m_pStream at this point ??? + int err; + int tries = 5; + do + { + err = executeInternal("ATZ E1 V1", this, NULL, 3000); //Enable echo and verbosity + if(err && tries) + { + WARN("No response, trying again"); + Thread::wait(1000); //Give dongle time to recover + } + } while(err && tries--); + if( err ) + { + ERR("Sending ATZ E1 V1 returned with err code %d", err); + m_transactionMtx.unlock(); + return err; + } + } + + //Enable events handling and execute events enabling commands + enableEvents(); + + DBG("AT interface initialized"); + + //Unlock transaction mutex + m_transactionMtx.unlock(); + + return OK; +} + +//Close connection +int ATCommandsInterface::close() +{ + if( !m_open ) + { + WARN("AT interface is already closed"); + return OK; + } + + DBG("Closing AT interface"); + + //Lock transaction mutex + m_transactionMtx.lock(); + + //Disable events handling and advertize this to the events handlers + disableEvents(); + + //Stop processing + m_processingThread.signal_set(AT_SIG_PROCESSING_STOP); + //m_stopSphre.release(); + + int* msg = m_env2AT.alloc(osWaitForever); + *msg = AT_STOP; + m_env2AT.put(msg); //Used to unstall the process if needed + + //Unlock process routine (abort read) + m_pStream->abortRead(); //This is thread-safe + m_processingMtx.lock(); + m_open = false; + + //Unlock transaction mutex + m_transactionMtx.unlock(); + + DBG("AT interface closed"); + return OK; +} + +bool ATCommandsInterface::isOpen() +{ + return m_open; +} + +int ATCommandsInterface::executeSimple(const char* command, ATResult* pResult, uint32_t timeout/*=1000*/) +{ + return execute(command, this, pResult, timeout); +} + +int ATCommandsInterface::execute(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/) +{ + if(!m_open) + { + WARN("Interface is not open!"); + return NET_INVALID; + } + + //Lock transaction mutex + m_transactionMtx.lock(); + + disableEvents(); //Disable unsollicited result codes + int ret = executeInternal(command, pProcessor, pResult, timeout); + enableEvents(); //Re-enable unsollicited result codes whatever the result of the command is + + //Unlock transaction mutex + m_transactionMtx.unlock(); + + return ret; +} + +int ATCommandsInterface::registerEventsHandler(IATEventsHandler* pHdlr) +{ + m_eventsMgmtMtx.lock(); + m_eventsProcessingMtx.lock(); + for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot + { + if( m_eventsHandlers[i] == NULL ) + { + m_eventsHandlers[i] = pHdlr; + m_eventsProcessingMtx.unlock(); + m_eventsMgmtMtx.unlock(); + return OK; + } + } + m_eventsProcessingMtx.unlock(); + m_eventsMgmtMtx.unlock(); + return NET_OOM; //No room left +} + +int ATCommandsInterface::deregisterEventsHandler(IATEventsHandler* pHdlr) +{ + m_eventsMgmtMtx.lock(); + m_eventsProcessingMtx.lock(); + for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find handler in list + { + if( m_eventsHandlers[i] == pHdlr ) + { + m_eventsHandlers[i] = NULL; + m_eventsProcessingMtx.unlock(); + m_eventsMgmtMtx.unlock(); + return OK; + } + } + m_eventsProcessingMtx.unlock(); + m_eventsMgmtMtx.unlock(); + return NET_NOTFOUND; //Not found +} + +//Private methods + +int ATCommandsInterface::executeInternal(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/) +{ + DBG("Executing command %s", command); + + //Discard previous result if it arrived too late + osEvent evt = m_AT2Env.get(0); + + if(evt.status == osEventMail) + { + m_AT2Env.free((int*)evt.value.p); + WARN("Previous result discarded"); + } + + //Send params to the process routine + m_transactionCommand = command; + if(pProcessor != NULL) + { + m_pTransactionProcessor = pProcessor; + } + else + { + m_pTransactionProcessor = this; //Use default behaviour + } + + DBG("Sending command ready signal to AT thread & aborting current blocking read operation"); + + //Produce command ready signal + int* msg = m_env2AT.alloc(osWaitForever); + *msg = AT_CMD_READY; + m_env2AT.put(msg); + + DBG("Trying to enter abortRead()"); + //Unlock process routine (abort read) + m_pStream->abortRead(); //This is thread-safe + + //Wait for a result (get result message) + evt = m_AT2Env.get(timeout); + + if(evt.status != osEventMail) + { + //Cancel request + msg = m_env2AT.alloc(osWaitForever); + *msg = AT_TIMEOUT; + m_env2AT.put(msg); + + DBG("Trying to enter abortRead()"); + //Unlock process routine (abort read) + m_pStream->abortRead(); //This is thread-safe + + //Wait for acknowledge + int msgResult; + do + { + evt = m_AT2Env.get(osWaitForever); + msgResult = *((int*) evt.value.p); + m_AT2Env.free((int*)evt.value.p); + } while(msgResult != AT_TIMEOUT); + + WARN("Command returned no message"); + WARN("Command \"%s\" returned no message", command); + return NET_TIMEOUT; + } + DBG("Command returned with message %d", *msg); + + m_AT2Env.free((int*)evt.value.p); + + if(pResult != NULL) + { + *pResult = m_transactionResult; + } + + int ret = ATResultToReturnCode(m_transactionResult); + if(ret != OK) + { + WARN("Command returned AT result %d with code %d", m_transactionResult.result, m_transactionResult.code); + WARN("Command \"%s\" returned AT result %d with code %d", command, m_transactionResult.result, m_transactionResult.code); + } + + DBG("Command returned successfully"); + + return ret; +} + +int ATCommandsInterface::tryReadLine() +{ + static bool lineDetected = false; + + //Block on serial read or incoming command + DBG("Trying to read a new line from stream"); + int ret = m_pStream->waitAvailable(); //This can be aborted + size_t readLen = 0; + if(ret == OK) + { + ret = m_pStream->read((uint8_t*)m_inputBuf + m_inputPos, &readLen, AT_INPUT_BUF_SIZE - 1 - m_inputPos, 0); //Do NOT wait at this point + } + if(ret == OK) + { + m_inputPos+=readLen; + m_inputBuf[m_inputPos] = '\0'; //Add null terminating character to ease the use of str* functions + DBG("In buffer: [%s]", m_inputBuf); + } + + if( ret == NET_INTERRUPTED ) //It is worth checking readLen as data might have been read even though the read was interrupted + { + DBG("Read was interrupted"); + return NET_INTERRUPTED; //0 chars were read + } + else if(readLen == 0) + { + DBG("Nothing read"); + return OK; //0 chars were read + } + + DBG("Trying to process incoming line"); + bool lineProcessed = false; + + do + { + lineProcessed = false; //Reset flag + + DBG("New iteration"); + + //Look for a new line + if(!lineDetected) + { + DBG("No line detected yet"); + //Try to look for a starting CRLF + char* crPtr = strchr(m_inputBuf, CR); + /* + Different cases at this point: + - CRLF%c sequence: this is the start of a line + - CRLFCR(LF) sequence: this is the end of a line (followed by the beginning of the next one) + - LF: this is the trailing LF char of the previous line, discard + - CR / CRLF incomplete sequence: more data is needed to determine which action to take + - %c ... CR sequence: this should be the echo of the previous sequence + - %c sequence: This might be the echo of the previous command; more data is needed to determine which action to take + + In every case, move mem at the beginning + */ + if(crPtr != NULL) + { + DBG("CR char found"); + +#if 0 + //Discard all preceding characters (can do nothing if m_inputBuf == crPtr) + memmove(m_inputBuf, crPtr, (m_inputPos + 1) - (crPtr-m_inputBuf)); //Move null-terminating char as well + m_inputPos = m_inputPos - (crPtr-m_inputBuf); //Adjust m_inputPos +#endif + + //If the line starts with CR, this should be a result code + if( crPtr == m_inputBuf ) + { + //To determine the sequence we need at least 3 chars + if(m_inputPos >= 3) + { + //Look for a LF char next to the CR char + if(m_inputBuf[1] == LF) + { + //At this point we can check whether this is the end of a preceding line or the beginning of a new one + if(m_inputBuf[2] != CR) + { + DBG("Beginning of new line found"); + //Beginning of a line + lineDetected = true; //Move to next state-machine step + } + else + { + //End of an unprocessed line + WARN("End of unprocessed line"); + } + //In both cases discard CRLF + DBG("Discarding CRLF"); + memmove(m_inputBuf, m_inputBuf + 2, (m_inputPos + 1) - 2); //Move null-terminating char as well + m_inputPos = m_inputPos - 2; //Adjust m_inputPos + } + else + { + //This is completely unexpected, discard the CR char to try to recover good state + WARN("Unexpected %c char (%02d code) found after CR char", m_inputBuf[1]); + memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well + m_inputPos = m_inputPos - 1; //Adjust m_inputPos + } + } + } + //if the line does NOT begin with CR, this can be an echo of the previous command, process it + else + { + int crPos = crPtr - m_inputBuf; + int lfOff = 0; //Offset for LF if present + DBG("New line found (possible echo of command)"); + //This is the end of line + //Replace m_inputBuf[crPos] with null-terminating char + m_inputBuf[crPos] = '\0'; + //Check if there is a LF char afterwards + if(m_inputPos - crPos >= 1) + { + if(m_inputBuf[crPos+1] == LF) + { + lfOff++; //We will discard LF char as well + } + } + //Process line + int ret = processReadLine(); + if(ret) + { + m_inputPos = 0; + m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer + lineDetected = false; + return ret; + } + + //If sendData has been called, all incoming data has been discarded + if(m_inputPos > 0) + { + memmove(m_inputBuf, m_inputBuf + crPos + lfOff + 1, (m_inputPos + 1) - (crPos + lfOff + 1)); //Move null-terminating char as well + m_inputPos = m_inputPos - (crPos + lfOff + 1); //Adjust m_inputPos + } + DBG("One line was successfully processed"); + lineProcessed = true; //Line was processed with success + lineDetected = false; //Search now for a new line + } + } + else if(m_inputBuf[0] == LF) //If there is a remaining LF char from the previous line, discard it + { + DBG("Discarding single LF char"); + memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well + m_inputPos = m_inputPos - 1; //Adjust m_inputPos + } + } + + //Look for the end of line + if(lineDetected) + { + DBG("Looking for end of line"); + //Try to look for a terminating CRLF + char* crPtr = strchr(m_inputBuf, CR); + /* + Different cases at this point: + - CRLF sequence: this is the end of the line + - CR%c sequence : unexpected + - CR incomplete sequence: more data is needed to determine which action to take + */ + + //Try to look for a '>' (greater than character) that marks an entry prompt + char* greaterThanPtr = strchr(m_inputBuf, GD); + /* + This character must be detected as there is no CRLF sequence at the end of an entry prompt + */ + + if(crPtr != NULL) + { + DBG("CR char found"); + int crPos = crPtr - m_inputBuf; + //To determine the sequence we need at least 2 chars + if(m_inputPos - crPos >= 2) + { + //Look for a LF char next to the CR char + if(m_inputBuf[crPos + 1] == LF) + { + DBG("End of new line found"); + //This is the end of line + //Replace m_inputBuf[crPos] with null-terminating char + m_inputBuf[crPos] = '\0'; + //Process line + int ret = processReadLine(); + if(ret) + { + m_inputPos = 0; + m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer + lineDetected = false; + return ret; + } + + //If sendData has been called, all incoming data has been discarded + if(m_inputPos > 0) + { + //Shift remaining data to beginning of buffer + memmove(m_inputBuf, m_inputBuf + crPos + 2, (m_inputPos + 1) - (crPos + 2)); //Move null-terminating char as well + m_inputPos = m_inputPos - (crPos + 2); //Adjust m_inputPos + } + + DBG("One line was successfully processed"); + lineProcessed = true; //Line was processed with success + } + else + { + //This is completely unexpected, discard all chars till the CR char to try to recover good state + WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[crPos + 1]); + memmove(m_inputBuf, m_inputBuf + crPos + 1, (m_inputPos + 1) - (crPos + 1)); //Move null-terminating char as well + m_inputPos = m_inputPos - (crPos + 1); //Adjust m_inputPos + } + lineDetected = false; //In both case search now for a new line + } + } + else if(greaterThanPtr != NULL) + { + DBG("> char found"); + int gdPos = greaterThanPtr - m_inputBuf; + //To determine the sequence we need at least 2 chars + if(m_inputPos - gdPos >= 2) + { + //Look for a space char next to the GD char + if(m_inputBuf[gdPos + 1] == ' ') + { + //This is an entry prompt + //Replace m_inputBuf[gdPos] with null-terminating char + m_inputBuf[gdPos] = '\0'; + + //Shift remaining data to beginning of buffer + memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well + m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos + + //Process prompt + ret = processEntryPrompt(); + if(ret) + { + m_inputPos = 0; + m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer + lineDetected = false; + return ret; + } + + DBG("One line was successfully processed"); + lineProcessed = true; //Line was processed with success + } + else + { + //This is completely unexpected, discard all chars till the GD char to try to recover good state + WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[gdPos + 1]); + memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well + m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos + } + lineDetected = false; //In both case search now for a new line + } + } + } + } while(lineProcessed); //If one complete line was processed there might be other incoming lines that can also be processed without reading the buffer again + + //If the line could not be processed AND buffer is full, it means that we won't ever be able to process it (buffer too short) + if(m_inputPos == AT_INPUT_BUF_SIZE - 1) + { + //Discard everything + m_inputPos = 0; + m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer + WARN("Incoming buffer is too short to process incoming line"); + //Look for a new line + lineDetected = false; + } + + DBG("Processed every full incoming lines"); + + return OK; +} + +int ATCommandsInterface::trySendCommand() +{ + osEvent evt = m_env2AT.get(0); + DBG("status = %d, msg = %d", evt.status, evt.value.p); + if(evt.status == osEventMail) + { + int* msg = (int*) evt.value.p; + if( *msg == AT_CMD_READY ) //Command pending + { + if(m_transactionState != IDLE) + { + WARN("Previous command not processed!"); + } + DBG("Sending pending command"); + m_pStream->write((uint8_t*)m_transactionCommand, strlen(m_transactionCommand), osWaitForever); + char cr = CR; + m_pStream->write((uint8_t*)&cr, 1, osWaitForever); //Carriage return line terminator + m_transactionState = COMMAND_SENT; + } + else //Timeout + { + //Acknowledge + int* msg = m_AT2Env.alloc(osWaitForever); + *msg = AT_TIMEOUT; + m_AT2Env.put(msg); //Command has timed out + m_transactionState = IDLE; //State-machine reset + } + m_env2AT.free(msg); + } + return OK; +} + +int ATCommandsInterface::processReadLine() +{ + DBG("Processing read line [%s]", m_inputBuf); + //The line is stored in m_inputBuf + if(m_transactionState == COMMAND_SENT) + { + //If the command has been sent, checks echo to see if it has been received properly + if( strcmp(m_transactionCommand, m_inputBuf) == 0 ) + { + DBG("Command echo received"); + //If so, it means that the following lines will only be solicited results + m_transactionState = READING_RESULT; + return OK; + } + } + if(m_transactionState == IDLE || m_transactionState == COMMAND_SENT) + { + bool found = false; + char* pSemicol = strchr(m_inputBuf, ':'); + char* pData = NULL; + if( pSemicol != NULL ) //Split the identifier & the result code (if it exists) + { + *pSemicol = '\0'; + pData = pSemicol + 1; + if(pData[0]==' ') + { + pData++; //Suppress whitespace + } + } + //Looks for a unsolicited result code; we can have m_transactionState == COMMAND_SENT as the code may have arrived just before we sent the command + m_eventsProcessingMtx.lock(); + //Go through the list + for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot + { + if( m_eventsHandlers[i] != NULL ) + { + if( m_eventsHandlers[i]->isATCodeHandled(m_inputBuf) ) + { + m_eventsHandlers[i]->onEvent(m_inputBuf, pData); + found = true; //Do not break here as there might be multiple handlers for one event type + } + } + } + m_eventsProcessingMtx.unlock(); + if(found) + { + return OK; + } + } + if(m_transactionState == READING_RESULT) + { + //The following lines can either be a command response or a result code (OK / ERROR / CONNECT / +CME ERROR: %s / +CMS ERROR: %s) + if(strcmp("OK", m_inputBuf) == 0) + { + DBG("OK result received"); + m_transactionResult.code = 0; + m_transactionResult.result = ATResult::AT_OK; + m_transactionState = IDLE; + int* msg = m_AT2Env.alloc(osWaitForever); + *msg = AT_RESULT_READY; + m_AT2Env.put(msg); //Command has been processed + return OK; + } + else if(strcmp("ERROR", m_inputBuf) == 0) + { + DBG("ERROR result received"); + m_transactionResult.code = 0; + m_transactionResult.result = ATResult::AT_ERROR; + m_transactionState = IDLE; + int* msg = m_AT2Env.alloc(osWaitForever); + *msg = AT_RESULT_READY; + m_AT2Env.put(msg); //Command has been processed + return OK; + } + else if(strncmp("CONNECT", m_inputBuf, 7 /*=strlen("CONNECT")*/) == 0) //Result can be "CONNECT" or "CONNECT %d", indicating baudrate + { + DBG("CONNECT result received"); + m_transactionResult.code = 0; + m_transactionResult.result = ATResult::AT_CONNECT; + m_transactionState = IDLE; + int* msg = m_AT2Env.alloc(osWaitForever); + *msg = AT_RESULT_READY; + m_AT2Env.put(msg); //Command has been processed + return OK; + } + else if(strcmp("COMMAND NOT SUPPORT", m_inputBuf) == 0) //Huawei-specific, not normalized + { + DBG("COMMAND NOT SUPPORT result received"); + m_transactionResult.code = 0; + m_transactionResult.result = ATResult::AT_ERROR; + m_transactionState = IDLE; + int* msg = m_AT2Env.alloc(osWaitForever); + *msg = AT_RESULT_READY; + m_AT2Env.put(msg); //Command has been processed + return OK; + } + else if(strstr(m_inputBuf, "+CME ERROR:") == m_inputBuf) //Mobile Equipment Error + { + std::sscanf(m_inputBuf + 12 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code); + DBG("+CME ERROR: %d result received", m_transactionResult.code); + m_transactionResult.result = ATResult::AT_CME_ERROR; + m_transactionState = IDLE; + int* msg = m_AT2Env.alloc(osWaitForever); + *msg = AT_RESULT_READY; + m_AT2Env.put(msg); //Command has been processed + return OK; + } + else if(strstr(m_inputBuf, "+CMS ERROR:") == m_inputBuf) //SIM Error + { + std::sscanf(m_inputBuf + 13 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code); + DBG("+CMS ERROR: %d result received", m_transactionResult.code); + m_transactionResult.result = ATResult::AT_CMS_ERROR; + m_transactionState = IDLE; + int* msg = m_AT2Env.alloc(osWaitForever); + *msg = AT_RESULT_READY; + m_AT2Env.put(msg); //Command has been processed + return OK; + } + else + { + DBG("Unprocessed result received: '%s'", m_inputBuf); + //Must call transaction processor to complete line processing + int ret = m_pTransactionProcessor->onNewATResponseLine(this, m_inputBuf); //Here sendData can be called + return ret; + } + } + + return OK; +} + +int ATCommandsInterface::processEntryPrompt() +{ + DBG("Calling prompt handler"); + int ret = m_pTransactionProcessor->onNewEntryPrompt(this); //Here sendData can be called + + if( ret != NET_MOREINFO ) //A new prompt is expected + { + DBG("Sending break character"); + //Send CTRL+Z (break sequence) to exit prompt + char seq[2] = {BRK, 0x00}; + sendData(seq); + } + return OK; +} + +//This will be called on initialization & after the execution of a command +void ATCommandsInterface::enableEvents() +{ + //Advertize this to events handlers + m_eventsMgmtMtx.lock(); + for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot + { + if( m_eventsHandlers[i] != NULL ) + { + m_eventsHandlers[i]->onDispatchStart(); + //Enable this kind of events + const char* cmd = m_eventsHandlers[i]->getEventsEnableCommand(); + if(cmd != NULL) + { + int ret = executeInternal(cmd, this, NULL); //Execute enable command + if(ret) + { + WARN("Events enabling command \"%s\" failed", cmd); + } + } + } + } + m_eventsMgmtMtx.unlock(); +} + +//This will be called on de-initialization & before the execution of a command to prevent unsollicited result codes from polluting the results +void ATCommandsInterface::disableEvents() +{ + //Advertize this to events handlers + m_eventsMgmtMtx.lock(); + for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot + { + if( m_eventsHandlers[i] != NULL ) + { + m_eventsHandlers[i]->onDispatchStart(); + //Disable this kind of events + const char* cmd = m_eventsHandlers[i]->getEventsDisableCommand(); + if(cmd != NULL) + { + int ret = executeInternal(cmd, this, NULL); //Execute disable command + if(ret) + { + WARN("Events disabling command \"%s\" failed", cmd); + } + } + } + } + m_eventsMgmtMtx.unlock(); +} + +//Commands that can be called during onNewATResponseLine callback, additionally to close() +//Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution) +int ATCommandsInterface::sendData(const char* data) +{ + //m_inputBuf is cleared at this point (and MUST therefore be empty) + int dataLen = strlen(data); + DBG("Sending raw string of length %d", dataLen); + int ret = m_pStream->write((uint8_t*)data, dataLen, osWaitForever); + if(ret) + { + WARN("Could not write to stream (returned %d)", ret); + return ret; + } + + int dataPos = 0; + do + { + //Read echo + size_t readLen; + int ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, MIN(dataLen - dataPos, AT_INPUT_BUF_SIZE - 1), osWaitForever); //Make sure we do not read more than needed otherwise it could break the parser + if(ret) + { + WARN("Could not read from stream (returned %d)", ret); + m_inputPos = 0; //Reset input buffer state + m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer + return ret; + } + + if( memcmp(m_inputBuf, data + dataPos, readLen) != 0 ) + { + //Echo does not match output + m_inputBuf[readLen] = '\0'; + WARN("Echo does not match output, got '%s' instead", m_inputBuf); + m_inputPos = 0; //Reset input buffer state + m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer + return NET_DIFF; + } + + dataPos += readLen; + //If all characters have not been read yet + + } while(dataPos < dataLen); + + DBG("String sent successfully"); + + m_inputPos = 0; //Reset input buffer state + m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer + + return OK; +} + +/*static*/ void ATCommandsInterface::staticCallback(void const* p) +{ + ((ATCommandsInterface*)p)->process(); +} + +int ATCommandsInterface::ATResultToReturnCode(ATResult result) //Helper +{ + if(result.result == ATResult::AT_OK) + { + return OK; + } + else + { + return NET_MOREINFO; + } +} + +/*virtual*/ int ATCommandsInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) //Default implementation for simple commands handling +{ + return OK; +} + +/*virtual*/ int ATCommandsInterface::onNewEntryPrompt(ATCommandsInterface* pInst) //Default implementation (just sends Ctrl+Z to exit the prompt by returning OK right-away) +{ + return OK; +} + +void ATCommandsInterface::process() //Processing thread +{ + DBG("AT Thread started"); + while(true) + { + DBG("AT Processing on hold"); + m_processingThread.signal_wait(AT_SIG_PROCESSING_START); //Block until the process is started + + m_processingMtx.lock(); + DBG("AT Processing started"); + //First of all discard buffer + int ret; + size_t readLen; + do //Drop everything + { + ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, AT_INPUT_BUF_SIZE - 1, 0); //Do NOT wait at this point + } while(ret == OK); + m_inputPos = 0; //Clear input buffer + do + { + DBG("Trying to send a pending command"); + trySendCommand(); //This must be tried first as we discarded the buffer before and therefore would be blocking though there is a pending command + DBG("Trying to read a new line"); + tryReadLine(); + } while( m_processingThread.signal_wait(AT_SIG_PROCESSING_STOP, 0).status != osEventSignal ); //Loop until the process is interrupted + m_processingMtx.unlock(); + DBG("AT Processing stopped"); + } +} + diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.h new file mode 100644 index 0000000000..8334df8957 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.h @@ -0,0 +1,153 @@ +/* ATCommandsInterface.h */ +/* 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. + */ + +#ifndef ATCOMMANDSINTERFACE_H_ +#define ATCOMMANDSINTERFACE_H_ + +#include "core/fwk.h" +#include "rtos.h" + +#define MAX_AT_EVENTS_HANDLERS 4 + +class ATCommandsInterface; + +/** Interface implemented by components handling AT events + * + */ +class IATEventsHandler +{ +protected: + virtual bool isATCodeHandled(const char* atCode) = 0; //Is this AT code handled + virtual void onDispatchStart() = 0; + virtual void onDispatchStop() = 0; + virtual char* getEventsEnableCommand() = 0; + virtual char* getEventsDisableCommand() = 0; + virtual void onEvent(const char* atCode, const char* evt) = 0; + friend class ATCommandsInterface; +}; + +/** Interface implemented by components executing complex AT commands + * + */ +class IATCommandsProcessor +{ +protected: + virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) = 0; + virtual int onNewEntryPrompt(ATCommandsInterface* pInst) = 0; + friend class ATCommandsInterface; +}; + +#define AT_INPUT_BUF_SIZE 192//64 + +//Signals to be sent to the processing thread +#define AT_SIG_PROCESSING_START 1 +#define AT_SIG_PROCESSING_STOP 2 +//Messages to be sent to the processing thread +#define AT_CMD_READY 1 +#define AT_TIMEOUT 2 +#define AT_STOP 3 +//Messages to be sent from the processing thread +#define AT_RESULT_READY 1 + +/** AT Commands interface class + * + */ +class ATCommandsInterface : protected IATCommandsProcessor +{ +public: + ATCommandsInterface(IOStream* pStream); + + //Open connection to AT Interface in order to execute command & register/unregister events + int open(); + + //Initialize AT link + int init(bool reset = true); + + //Close connection + int close(); + + bool isOpen(); + + class ATResult + { + public: + enum { AT_OK, AT_ERROR, AT_CONNECT, AT_CMS_ERROR, AT_CME_ERROR } result; + int code; + }; + + int executeSimple(const char* command, ATResult* pResult, uint32_t timeout=1000); + int execute(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout=1000); + + int registerEventsHandler(IATEventsHandler* pHdlr); + int deregisterEventsHandler(IATEventsHandler* pHdlr); + + //Commands that can be called during onNewATResponseLine callback, additionally to close() + //Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution) + int sendData(const char* data); + + static void staticCallback(void const* p); +private: + int executeInternal(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout=1000); + + int tryReadLine(); + int trySendCommand(); + int processReadLine(); + int processEntryPrompt(); + + void enableEvents(); + void disableEvents(); + + int ATResultToReturnCode(ATResult result); //Helper + + virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line); //Default implementation for simple commands handling + virtual int onNewEntryPrompt(ATCommandsInterface* pInst); //Default implementation (just sends Ctrl+Z to exit the prompt) + + void process(); //Processing thread + + IOStream* m_pStream; + + bool m_open; //< TRUE when the AT interface is open, and FALSE when it is not. + + const char* m_transactionCommand; + const char* m_transactionData; + + IATCommandsProcessor* m_pTransactionProcessor; + ATResult m_transactionResult; + + enum { IDLE, COMMAND_SENT, READING_RESULT, ABORTED } m_transactionState; + + char m_inputBuf[AT_INPUT_BUF_SIZE]; // Stores characters received from the modem. + int m_inputPos; // Current position of fill pointer in the input buffer. + + Mutex m_transactionMtx; + + // These are RTOS queues, concurrent access protected. In this case both only contain an integer. + Mail<int,1> m_env2AT; // used by calling function to inform processing thread of events + Mail<int,1> m_AT2Env; // used by processing thread to inform calling function of events + + IATEventsHandler* m_eventsHandlers[MAX_AT_EVENTS_HANDLERS]; // all registered events handlers + + Mutex m_processingMtx; + Thread m_processingThread; + + Mutex m_eventsMgmtMtx; //Lock events use within the calling thread + Mutex m_eventsProcessingMtx; //Lock events use within the processing thread +}; + +#endif /* ATCOMMANDSINTERFACE_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/IOStream.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/IOStream.h new file mode 100644 index 0000000000..6d411b8e4b --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/IOStream.h @@ -0,0 +1,59 @@ +/* IOStream.h */ +/* 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. + */ + +#ifndef IOSTREAM_H_ +#define IOSTREAM_H_ + +#include "rtos.h" + +class IStream +{ +public: + //IStream(); + //virtual ~IStream(); + + //0 for non-blocking (returns immediately), osWaitForever for infinite blocking + virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever) = 0; + virtual size_t available() = 0; + virtual int waitAvailable(uint32_t timeout=osWaitForever) = 0; //Wait for data to be available + virtual int abortRead() = 0; //Abort current reading (or waiting) operation +}; + +class OStream +{ +public: + //OStream(); + //virtual ~OStream(); + + //0 for non-blocking (returns immediately), osWaitForever for infinite blocking + virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever) = 0; + virtual size_t space() = 0; + virtual int waitSpace(uint32_t timeout=osWaitForever) = 0; //Wait for space to be available + virtual int abortWrite() = 0; //Abort current writing (or waiting) operation +}; + +class IOStream : public IStream, public OStream +{ +public: + //IOStream(); + //virtual ~IOStream(); +}; + + +#endif /* IOSTREAM_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/MtxCircBuffer.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/MtxCircBuffer.h new file mode 100644 index 0000000000..b011693eb4 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/MtxCircBuffer.h @@ -0,0 +1,95 @@ +/* MtxCircBuf.h */ +/* 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. + */ + +#ifndef MTXCIRCBUFFER_H +#define MTXCIRCBUFFER_H + +#include "rtos.h" + +//Mutex protected circualr buffer +template<typename T, int size> +class MtxCircBuffer +{ +public: + MtxCircBuffer() //: + //mtx() + { + write = 0; + read = 0; + } + + bool isFull() + { + mtx.lock(); + bool r = (((write + 1) % size) == read); + mtx.unlock(); + return r; + } + + bool isEmpty() + { + mtx.lock(); + bool r = (read == write); + mtx.unlock(); + return r; + } + + void queue(T k) + { + mtx.lock(); + buf[write++] = k; + write %= size; + if (isFull()) + { + read++; + read %= size; + } + mtx.unlock(); + } + + uint16_t available() + { + mtx.lock(); + uint16_t a = (write >= read) ? (write - read) : (size - read + write); + mtx.unlock(); + return a; + } + + bool dequeue(T * c) + { + mtx.lock(); + bool empty = (read == write); + if (!empty) + { + *c = buf[read++]; + read %= size; + } + mtx.unlock(); + return (!empty); + } + +private: + volatile uint16_t write; + volatile uint16_t read; + volatile T buf[size]; + Mutex mtx; +}; + +#endif + diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/config.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/config.h new file mode 100644 index 0000000000..508424dc66 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/config.h @@ -0,0 +1,27 @@ +/* config.h */ +/* 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. + */ +#ifndef CONFIG_H_ +#define CONFIG_H_ + + +//Configuration +#define AT_THREAD_PRIORITY 0 + + +#endif /* CONFIG_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.cpp new file mode 100644 index 0000000000..4314e2342f --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.cpp @@ -0,0 +1,127 @@ +/* dbg.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. + */ + +#include "dbg.h" + +#include "mbed.h" +#include "rtos.h" + +#include <cstdio> +#include <cstdarg> + +using namespace std; + +static Serial debug_pc(USBTX, USBRX); + +static char debug_newline[3]; + +static void debug_lock(bool set) +{ + static Mutex* mtx = new Mutex(); //Singleton runtime initialisation to avoid static initialisation chaos problems + static bool init = false; + if(set) + { + mtx->lock(); + if(!init) + { + strncpy( debug_newline, "\n", 2 ); + printf("[START]\n"); + fflush(stdout); + init = true; + } + } + else + { + mtx->unlock(); + } +} + +void debug_init() +{ + debug_lock(true); //Force init + debug_lock(false); +} + +void debug_set_newline(const char* newline) +{ + debug_lock(true); + strncpy( debug_newline, newline, 2 ); + debug_newline[2] = '\0'; + debug_lock(false); +} + +void debug_set_speed(int speed) +{ + debug_pc.baud(speed); +} + +void debug(int level, const char* module, int line, const char* fmt, ...) +{ + debug_lock(true); + switch(level) + { + default: + case 1: + printf("[ERROR]"); + break; + case 2: + printf("[WARN]"); + break; + case 3: + printf("[INFO]"); + break; + case 4: + printf("[DBG]"); + break; + } + + printf(" Module %s - Line %d: ", module, line); + + va_list argp; + + va_start(argp, fmt); + vprintf(fmt, argp); + va_end(argp); + + printf(debug_newline); + + fflush(stdout); + + debug_lock(false); + +} + +void debug_error(const char* module, int line, int ret) +{ + debug_lock(true); + printf("[RC] Module %s - Line %d : Error %d\n", module, line, ret); + fflush(stdout); + debug_lock(false); +} + +void debug_exact(const char* fmt, ...) +{ + debug_lock(true); + va_list argp; + + va_start(argp, fmt); + vprintf(fmt, argp); + va_end(argp); + debug_lock(false); +} diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.h new file mode 100644 index 0000000000..2ff24e1b31 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/dbg.h @@ -0,0 +1,79 @@ +/* dbg.h */ +/* 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. + */ + +#ifndef DBG_H_ +#define DBG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +void debug_init(void); +void debug(int level, const char* module, int line, const char* fmt, ...); +void debug_set_newline(const char* newline); +void debug_set_speed(int speed); +void debug_error(const char* module, int line, int ret); +void debug_exact(const char* fmt, ...); + +#define DBG_INIT() do{ debug_init(); }while(0) + +#define DBG_SET_NEWLINE( x ) do{ debug_set_newline(x); }while(0) + +#define DBG_SET_SPEED( x ) do{ debug_set_speed(x); }while(0) + +#if __DEBUG__ > 0 +#ifndef __MODULE__ +#error "__MODULE__ must be defined" +#endif +#endif + +#if __DEBUG__ >= 1 +#define ERR(...) do{ debug(1, __MODULE__, __LINE__, __VA_ARGS__); }while(0) +#else +#define ERR(...) do{ }while(0) +#endif + +#if __DEBUG__ >= 2 +#define WARN(...) do{ debug(2, __MODULE__, __LINE__, __VA_ARGS__); }while(0) +#else +#define WARN(...) do{ }while(0) +#endif + +#if __DEBUG__ >= 3 +#define INFO(...) do{ debug(3, __MODULE__, __LINE__, __VA_ARGS__); }while(0) +#define CHECK(ret) do{ if(ret){ debug_error(__MODULE__, __LINE__, ret); } }while(0) +#else +#define INFO(...) do{ }while(0) +#define CHECK(ret) do{ }while(0) +#endif + +#if __DEBUG__ >= 4 +#define DBG(...) do{ debug(4, __MODULE__, __LINE__, __VA_ARGS__); }while(0) +#define DBGX(...) do{ debug_exact(__VA_ARGS__); }while(0) +#else +#define DBG(...) do{ }while(0) +#define DBGX(...) do{ }while(0) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* DBG_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/errors.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/errors.h new file mode 100644 index 0000000000..73ca00c1c4 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/errors.h @@ -0,0 +1,47 @@ +/* errors.h */ +/* 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. + */ + +#ifndef ERRORS_H_ +#define ERRORS_H_ + +/** \page Network-related errors */ + +#define OK 0 //No error + +#define NET_FULL 1 //>All available resources are already used +#define NET_EMPTY 2 //>No resource +#define NET_NOTFOUND 3 //>Element cannot be found +#define NET_INVALID 4 //>Invalid +#define NET_CONTEXT 5 //>Called in a wrong context (eg during an interrupt) +#define NET_TIMEOUT 6 //>Timeout +#define NET_UNKNOWN 7 //>Unknown error +#define NET_OVERFLOW 8 //>Overflow +#define NET_PROCESSING 9 //>Command is processing +#define NET_INTERRUPTED 10 //>Current operation has been interrupted +#define NET_MOREINFO 11 //>More info on this error can be retrieved elsewhere (eg in a parameter passed as ptr) +#define NET_ABORT 12 //>Current operation must be aborted +#define NET_DIFF 13 //>Items that should match are different +#define NET_AUTH 14 //>Authentication failed +#define NET_PROTOCOL 15 //>Protocol error +#define NET_OOM 16 //>Out of memory +#define NET_CONN 17 //>Connection error +#define NET_CLOSED 18 //>Connection was closed by remote end +#define NET_TOOSMALL 19 //>Buffer is too small + +#endif /* ERRORS_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/fwk.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/fwk.h new file mode 100644 index 0000000000..4efc281c0e --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/core/fwk.h @@ -0,0 +1,61 @@ +/* fwk.h */ +/* 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. + */ + +#ifndef FWK_H_ +#define FWK_H_ + +#include "config.h" + +#include "string.h" +//using namespace std; + +#include "stdint.h" +typedef unsigned int size_t; + +#ifndef __cplusplus +//boolean type compatibility +typedef byte bool; +#define true 1 +#define false 0 +#endif + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#define CR '\x0D' +#define LF '\x0A' +#define GD '\x3E' +#define BRK '\x1A' + +//Custom utility classes +#include "IOStream.h" +//#include "String.h" + +//Error codes +#include "errors.h" + +//Debug +#include "dbg.h" + +//Utility macros +#define MIN(x,y) (((x)<(y))?(x):(y)) +#define MAX(x,y) (((x)>(y))?(x):(y)) + +#endif /* FWK_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.cpp new file mode 100644 index 0000000000..3732303e24 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.cpp @@ -0,0 +1,81 @@ +/* IPInterface.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. + */ + +#include "core/fwk.h" + +#include "IPInterface.h" + +#include <cstring> //For strcpy + + +IPInterface::IPInterface() : m_connected(false) +{ + +} + +/*virtual*/ IPInterface::~IPInterface() +{ + +} + +void IPInterface::registerAsDefaultInterface() //First come, first served +{ + s_pDefaultInterface = this; +} + +void IPInterface::unregisterAsDefaultInterface() //Must be called before inst is destroyed to avoid invalid ptr fault +{ + s_pDefaultInterface = NULL; +} + +/*static*/ IPInterface* IPInterface::getDefaultInterface() //For use by TCP, UDP sockets library +{ + return s_pDefaultInterface; +} + +/*static*/ IPInterface* IPInterface::s_pDefaultInterface = NULL; + + +char* IPInterface::getIPAddress() //Get IP Address as a string ('a.b.c.d') +{ + if(isConnected()) + { + return m_ipAddr; + } + else + { + return NULL; + } +} + +bool IPInterface::isConnected() //Is the interface connected? +{ + return m_connected; +} + +void IPInterface::setIPAddress(char* ipAddr) +{ + std::strcpy(m_ipAddr, ipAddr); //Let's trust the derived class not to buffer overflow us +} + +void IPInterface::setConnected(bool connected) +{ + m_connected = connected; +} + diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.h new file mode 100644 index 0000000000..6655aec9ca --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/IPInterface.h @@ -0,0 +1,60 @@ +/* IPInterface.h */ +/* 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. + */ + +#ifndef IPINTERFACE_H_ +#define IPINTERFACE_H_ + +#include "core/fwk.h" + +/** Generic IP-based network interface + * + */ +class IPInterface +{ +public: + IPInterface(); + virtual ~IPInterface(); + + //int init(); //Initialize interface; no connection should be performed at this stage + virtual int connect() = 0; //Do connect the interface + virtual int disconnect() = 0; + //It is encouraged that the derived class implement a "setup(...)" function to configure the interface before the connection + + char* getIPAddress(); //Get IP Address as a string ('a.b.c.d') + bool isConnected(); //Is the interface connected? + + static IPInterface* getDefaultInterface(); //For use by TCP, UDP sockets library + + //WARN: Implementation will have to be more careful in case of multiple interfaces (or implement a routing protocol based on local IP addresses differentiation) + void registerAsDefaultInterface(); //First come, first served + void unregisterAsDefaultInterface(); //Must be called before inst is destroyed to avoid invalid ptr fault + +protected: + //Must be called by subclasses + void setIPAddress(char* ipAddr); + void setConnected(bool connected); + +private: + char m_ipAddr[16]; + bool m_connected; + + static IPInterface* s_pDefaultInterface; +}; + +#endif /* IPINTERFACE_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.cpp new file mode 100644 index 0000000000..b20f2a6617 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.cpp @@ -0,0 +1,52 @@ +/* LwIPInterface.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. + */ + + +#include "core/fwk.h" + +#include "LwIPInterface.h" + +extern "C" { +#include "lwip/init.h" +#include "lwip/tcpip.h" +} + +LwIPInterface::LwIPInterface() : IPInterface(), m_rdySphre(1) +{ + m_rdySphre.wait(); +} + +LwIPInterface::~LwIPInterface() +{ + +} + +int LwIPInterface::init() //Init LwIP-specific stuff, create the right bindings, etc +{ + //lwip_init(); //All LwIP initialisation functions called on a per-module basis (according to lwipopts.h) + tcpip_init(LwIPInterface::tcpipRdyCb, this); //Start TCP/IP processing thread + m_rdySphre.wait(); //Wait for callback to produce resource + return OK; +} + +/*static*/ void LwIPInterface::tcpipRdyCb(void* ctx) //Result of TCP/IP thread launch +{ + LwIPInterface* pIf = (LwIPInterface*) ctx; + pIf->m_rdySphre.release(); +} diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.h new file mode 100644 index 0000000000..7e5471e204 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/LwIPInterface.h @@ -0,0 +1,44 @@ +/* LwIPInterface.h */ +/* 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. + */ + +#ifndef LWIPINTERFACE_H_ +#define LWIPINTERFACE_H_ + +#include "core/fwk.h" +#include "IPInterface.h" + +#include "rtos.h" + +/** LwIP-based network interface + * + */ +class LwIPInterface : public IPInterface +{ +public: + LwIPInterface(); + virtual ~LwIPInterface(); + + int init(); //Init LwIP-specific stuff, create the right bindings, etc + +private: + static void tcpipRdyCb(void* ctx); //Result of TCP/IP thread launch + Semaphore m_rdySphre; +}; + +#endif /* LWIPINTERFACE_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.cpp new file mode 100644 index 0000000000..98614050ef --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.cpp @@ -0,0 +1,466 @@ +/* PPPIPInterface.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__ 0 +#ifndef __MODULE__ +#define __MODULE__ "PPPIPInterface.cpp" +#endif + +#include "core/fwk.h" +#include "rtos.h" + +#include <cstdio> +using std::sscanf; +using std::sprintf; + +#include "PPPIPInterface.h" + +#define MSISDN "*99#" + +#define CONNECT_CMD_PREFIX "ATD " +#define CONNECT_CMD_SUFFIX "\x0D" +#define EXPECTED_RESP_SUFFIX "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A" +#define EXPECTED_RESP_DATARATE_SUFFIX "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A" +#define EXPECTED_RESP_MIN_LEN 20 +#define OK_RESP "\x0D" "\x0A" "OK" "\x0D" "\x0A" +#define ESCAPE_SEQ "+++" +#define HANGUP_CMD "ATH" "\x0D" +#define NO_CARRIER_RESP "\x0D" "\x0A" "NO CARRIER" "\x0D" "\x0A" +extern "C" { +#include "lwip/ip_addr.h" +#include "lwip/inet.h" +#include "lwip/err.h" +#include "lwip/dns.h" + +#include "netif/ppp/ppp.h" +} + +PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1) +{ + m_linkStatusSphre.wait(); +} + + + +/*virtual*/ PPPIPInterface::~PPPIPInterface() +{ +} + +/*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc +{ + DBG("Initializing LwIP"); + LwIPInterface::init(); //Init LwIP, NOT including PPP + DBG("Initializing PPP"); + pppInit(); + DBG("Done"); + return OK; +} + +int PPPIPInterface::setup(const char* user, const char* pw, const char* msisdn) +{ + DBG("Configuring PPP authentication method"); + pppSetAuth(PPPAUTHTYPE_ANY, user, pw); + m_msisdn = msisdn; + DBG("Done"); + return OK; +} + +/*virtual*/ int PPPIPInterface::connect() +{ + int ret; + char cmd[32]; + int cmdLen; + char buf[32]; + size_t len; + DBG("Trying to connect with PPP"); + + cleanupLink(); + + cmdLen = sprintf(cmd, "%s%s%s", CONNECT_CMD_PREFIX, m_msisdn, CONNECT_CMD_SUFFIX); + DBG("Sending %s", cmd); + ret = m_pStream->write((uint8_t*)cmd, cmdLen, osWaitForever); + if( ret != OK ) + { + return NET_UNKNOWN; + } + + len = 0; + size_t readLen; + ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000); + if( ret != OK ) + { + return NET_UNKNOWN; + } + len += readLen; + while( (len < EXPECTED_RESP_MIN_LEN) || (buf[len-1] != LF) ) + { + ret = m_pStream->read((uint8_t*)buf + len, &readLen, 1, 10000); + if( ret != OK ) + { + return NET_UNKNOWN; + } + len += readLen; + } + + buf[len]=0; + + DBG("Got %s[len %d]", buf, len); + + int datarate = 0; + strcpy(&cmd[cmdLen], EXPECTED_RESP_DATARATE_SUFFIX); + if( (sscanf(buf, cmd, &datarate ) != 1)) + { + strcpy(&cmd[cmdLen], EXPECTED_RESP_SUFFIX); + if (strcmp(cmd, buf) != 0) + { + //Discard buffer + do //Clear buf + { + ret = m_pStream->read((uint8_t*)buf, &len, 32, 0); + } while( (ret == OK) && (len > 0) ); + return NET_CONN; + } + } + + DBG("Transport link open"); + if(datarate != 0) + { + DBG("Datarate: %d bps", datarate); + } + m_linkStatusSphre.wait(0); + if((m_pppd != -1) && (m_pppErrCode == 0)) //Already connected + { + return NET_INVALID; + } + + ret = pppOverSerialOpen(this, PPPIPInterface::linkStatusCb, this); + if(ret < 0) + { + switch(ret) + { + case PPPERR_OPEN: + default: + return NET_FULL; //All available resources are already used + } + } + m_pppd = ret; //PPP descriptor + m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there + if(m_pppErrCode != PPPERR_NONE) + { + m_pppd = -1; + } + switch(m_pppErrCode) + { + case PPPERR_NONE: //Connected OK + return OK; + case PPPERR_CONNECT: //Connection lost + return NET_INTERRUPTED; + case PPPERR_AUTHFAIL: //Authentication failed + return NET_AUTH; + case PPPERR_PROTOCOL: //Protocol error + return NET_PROTOCOL; + default: + return NET_UNKNOWN; + } +} + +/*virtual*/ int PPPIPInterface::disconnect() +{ + int ret = m_linkStatusSphre.wait(0); + if(ret > 0) //Already disconnected? + { + m_pppd = -1; //Discard PPP descriptor + switch(m_pppErrCode) + { + case PPPERR_CONNECT: //Connection terminated + case PPPERR_AUTHFAIL: //Authentication failed + case PPPERR_PROTOCOL: //Protocol error + case PPPERR_USER: + return OK; + default: + return NET_UNKNOWN; + } + } + else + { + if(m_pppd == -1) + { + return NET_INVALID; + } + pppClose(m_pppd); + do + { + m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there + DBG("Received PPP err code %d", m_pppErrCode); + } while(m_pppErrCode != PPPERR_USER); + m_pppd = -1; //Discard PPP descriptor + } + + DBG("Sending %s", ESCAPE_SEQ); + + ret = m_pStream->write((uint8_t*)ESCAPE_SEQ, strlen(ESCAPE_SEQ), osWaitForever); + if( ret != OK ) + { + return NET_UNKNOWN; + } + + cleanupLink(); + + return OK; +} + + +int PPPIPInterface::cleanupLink() +{ + int ret; + char buf[32]; + size_t len; + + do //Clear buf + { + ret = m_pStream->read((uint8_t*)buf, &len, 32, 100); + if(ret == OK) + { + buf[len] = '\0'; + DBG("Got %s", buf); + } + } while( (ret == OK) && (len > 0) ); + + DBG("Sending %s", HANGUP_CMD); + + ret = m_pStream->write((uint8_t*)HANGUP_CMD, strlen(HANGUP_CMD), osWaitForever); + if( ret != OK ) + { + return NET_UNKNOWN; + } + + size_t readLen; + + //Hangup + DBG("Expect %s", HANGUP_CMD); + + len = 0; + while( len < strlen(HANGUP_CMD) ) + { + ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(HANGUP_CMD) - len, 100); + if( ret != OK ) + { + break; + } + len += readLen; + ///// + buf[len]=0; + DBG("Got %s", buf); + } + + buf[len]=0; + + DBG("Got %s[len %d]", buf, len); + + //OK response + DBG("Expect %s", OK_RESP); + + len = 0; + while( len < strlen(OK_RESP) ) + { + ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(OK_RESP) - len, 100); + if( ret != OK ) + { + break; + } + len += readLen; + ///// + buf[len]=0; + DBG("Got %s", buf); + } + + buf[len]=0; + + DBG("Got %s[len %d]", buf, len); + + //NO CARRIER event + DBG("Expect %s", NO_CARRIER_RESP); + + len = 0; + while( len < strlen(NO_CARRIER_RESP) ) + { + ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(NO_CARRIER_RESP) - len, 100); + if( ret != OK ) + { + break; + } + len += readLen; + ///// + buf[len]=0; + DBG("Got %s", buf); + } + + buf[len]=0; + + DBG("Got %s[len %d]", buf, len); + + do //Clear buf + { + ret = m_pStream->read((uint8_t*)buf, &len, 32, 100); + if(ret == OK) + { + buf[len] = '\0'; + DBG("Got %s", buf); + } + } while( (ret == OK) && (len > 0) ); + + + return OK; +} + +/*static*/ void PPPIPInterface::linkStatusCb(void *ctx, int errCode, void *arg) //PPP link status +{ + PPPIPInterface* pIf = (PPPIPInterface*)ctx; + struct ppp_addrs* addrs = (struct ppp_addrs*) arg; + + switch(errCode) + { + case PPPERR_NONE: + WARN("Connected via PPP."); + DBG("Local IP address: %s", inet_ntoa(addrs->our_ipaddr)); + DBG("Netmask: %s", inet_ntoa(addrs->netmask)); + DBG("Remote IP address: %s", inet_ntoa(addrs->his_ipaddr)); + DBG("Primary DNS: %s", inet_ntoa(addrs->dns1)); + DBG("Secondary DNS: %s", inet_ntoa(addrs->dns2)); + //Setup DNS + if (addrs->dns1.addr != 0) + { + dns_setserver(0, (struct ip_addr*)&(addrs->dns1)); + } + if (addrs->dns2.addr != 0) + { + dns_setserver(1, (struct ip_addr*)&(addrs->dns1)); + } + + pIf->setConnected(true); + pIf->setIPAddress(inet_ntoa(addrs->our_ipaddr)); + break; + case PPPERR_CONNECT: //Connection lost + WARN("Connection lost/terminated"); + pIf->setConnected(false); + break; + case PPPERR_AUTHFAIL: //Authentication failed + WARN("Authentication failed"); + pIf->setConnected(false); + break; + case PPPERR_PROTOCOL: //Protocol error + WARN("Protocol error"); + pIf->setConnected(false); + break; + case PPPERR_USER: + WARN("Disconnected by user"); + pIf->setConnected(false); + break; + default: + WARN("Unknown error (%d)", errCode); + pIf->setConnected(false); + break; + } + + pIf->m_linkStatusSphre.wait(0); //If previous event has not been handled, "delete" it now + pIf->m_pppErrCode = errCode; + pIf->m_linkStatusSphre.release(); +} + +//LwIP PPP implementation +extern "C" +{ + +/** + * Writes to the serial device. + * + * @param fd serial device handle + * @param data pointer to data to send + * @param len length (in bytes) of data to send + * @return number of bytes actually sent + * + * @note This function will block until all data can be sent. + */ +u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len) +{ + DBG("sio_write"); + PPPIPInterface* pIf = (PPPIPInterface*)fd; + int ret; + if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further + { + return 0; + } + ret = pIf->m_pStream->write(data, len, osWaitForever); //Blocks until all data is sent or an error happens + if(ret != OK) + { + return 0; + } + return len; +} + +/** + * Reads from the serial device. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received - may be 0 if aborted by sio_read_abort + * + * @note This function will block until data can be received. The blocking + * can be cancelled by calling sio_read_abort(). + */ +u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len) +{ + DBG("sio_read"); + PPPIPInterface* pIf = (PPPIPInterface*)fd; + int ret; + size_t readLen; + if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further + { + WARN("EXIT NOT AVAIL"); + return 0; + } + ret = pIf->m_pStream->read(data, &readLen, len, osWaitForever); //Blocks until some data is received or an error happens + if(ret != OK) + { + return 0; + } + DBG("ret"); + return readLen; +} + +/** + * Aborts a blocking sio_read() call. + * + * @param fd serial device handle + */ +void sio_read_abort(sio_fd_t fd) +{ + DBG("sio_read_abort"); + PPPIPInterface* pIf = (PPPIPInterface*)fd; + if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further + { + return; + } + pIf->m_pStream->abortRead(); + DBG("ret"); +} + +} + diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.h new file mode 100644 index 0000000000..2d24009dcd --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.h @@ -0,0 +1,69 @@ +/* PPPIPInterface.h */ +/* 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. + */ + +#ifndef PPPIPINTERFACE_H_ +#define PPPIPINTERFACE_H_ + +#include "core/fwk.h" + +#include "LwIPInterface.h" + +#include "lwip/sio.h" + +namespace rtos { +class Semaphore; +} +using namespace rtos; + +#define DEFAULT_MSISDN_GSM "*99#" +#define DEFAULT_MSISDN_CDMA "#777" + +/** Interface using PPP to connect to an IP-based network + * + */ +class PPPIPInterface : public LwIPInterface +{ +public: + PPPIPInterface(IOStream* pStream); + virtual ~PPPIPInterface(); + + int init(); //Init PPP-specific stuff, create the right bindings, etc + int setup(const char* user, const char* pw, const char* msisdn); //Setup authentication + virtual int connect(); + virtual int disconnect(); + +private: + int cleanupLink(); + + static void linkStatusCb(void *ctx, int errCode, void *arg); //PPP link status + Semaphore m_linkStatusSphre; + int m_pppErrCode; + + IOStream* m_pStream; //Serial stream + bool m_streamAvail; + const char* m_msisdn; + + int m_pppd; + + friend u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len); + friend u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len); + friend void sio_read_abort(sio_fd_t fd); +}; + +#endif /* PPPIPINTERFACE_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.cpp new file mode 100644 index 0000000000..612b376921 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.cpp @@ -0,0 +1,175 @@ +/* LinkMonitor.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__ 0 +#ifndef __MODULE__ +#define __MODULE__ "LinkMonitor.cpp" +#endif + +#include "core/fwk.h" + +#include "LinkMonitor.h" + +#include <cstdio> +using std::sscanf; + +#define DEFAULT_TIMEOUT 10000 + +LinkMonitor::LinkMonitor(ATCommandsInterface* pIf) : m_pIf(pIf), m_rssi(0), m_registrationState(REGISTRATION_STATE_UNKNOWN), m_bearer(BEARER_UNKNOWN) +{ + m_gsm = true; +} + +int LinkMonitor::init(bool gsm) +{ + m_gsm = gsm; + if (m_gsm) + { + // we need to make sure that we setup the operator selection to be in 'numeric' format. + // i.e. it is made up of a network and country code when returned by the modem e.g. Operator = 23415. This allows easy logic parsing for + // setting up other network parameters in future. + DBG("LinkMonitor::init() being called. This should only happen once: executinging AT+COPS=0,2"); + int ret = m_pIf->executeSimple("AT+COPS=0,2", NULL, DEFAULT_TIMEOUT); //Configure to set the operator string to Country Code and mobile network code + if(ret != OK) + { + WARN(" NET_PROTOCOL error from sending the AT+COPS command to the modem. "); + return NET_PROTOCOL; + } + } + return OK; +} + +/*virtual*/ int LinkMonitor::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) +{ + DBG("Line is %s", line); + char n[32] = ""; + char s[32] = ""; + int v; + if( sscanf(line, "+CREG: %*d,%d", &v) >= 1 ) //Reg state is valid + { + DBG("+CREG %d", v); + switch( v ) + { + case 0: + m_registrationState = REGISTRATION_STATE_UNKNOWN; + break; + case 1: + m_registrationState = REGISTRATION_STATE_HOME_NETWORK; + break; + case 2: + m_registrationState = REGISTRATION_STATE_REGISTERING; + break; + case 3: + m_registrationState = REGISTRATION_STATE_DENIED; + break; + case 4: + m_registrationState = REGISTRATION_STATE_NO_SIGNAL; + break; + case 5: + m_registrationState = REGISTRATION_STATE_ROAMING; + break; + default: + m_registrationState = REGISTRATION_STATE_UNKNOWN; + break; + } + } + else if( sscanf(line, "+COPS: %*d,%*d,\"%*[^\"]\",%d", &v) >= 1 ) + { + DBG("+COPS %d", v); + switch( v ) + { + case 0: + m_bearer = BEARER_GSM; + break; + case 2: + m_bearer = BEARER_UMTS; + break; + case 3: + m_bearer = BEARER_EDGE; + break; + case 4: //HSDPA + case 5: //HSUPA + case 6: //HSDPA + HSUPA + m_bearer = BEARER_HSPA; + break; + case 7: + m_bearer = BEARER_LTE; + break; + case 1: //GSM Compact + default: + m_bearer = BEARER_UNKNOWN; + break; + } + } + else if( sscanf(line, "+CSQ: %d,%*d", &v) >= 1 ) + { + DBG("+CSQ %d", v); + if(v == 99) //Unknown + { + m_rssi = 0; //Unknown + } + else + { + m_rssi = -113 + 2*v; + } + } + else if ( (sscanf(line, "+CNUM: \"%[^\"]\",\"%[^\"]\",%d", n, s, &v) == 3) || + (sscanf(line, "+CNUM: \"\",\"%[^\"]\",%d", s, &v) == 2) ) + { + if (*s && ((v == 145/*number includes + */) || (v == 129/*otherwise*/))) { + strcpy(m_phoneNumber, s); + } + } + return OK; +} + +/*virtual*/ int LinkMonitor::onNewEntryPrompt(ATCommandsInterface* pInst) +{ + return OK; +} + +int LinkMonitor::getState(int* pRssi, REGISTRATION_STATE* pRegistrationState, BEARER* pBearer) +{ + m_rssi = 0; + m_registrationState = REGISTRATION_STATE_UNKNOWN; + m_bearer = BEARER_UNKNOWN; + int ret = m_pIf->execute(m_gsm ? "AT+CREG?;+COPS?;+CSQ" : "AT+CREG?;+CSQ", this, NULL, DEFAULT_TIMEOUT); //Configure to get registration info & get it; get signal quality + if(ret != OK) + { + return NET_PROTOCOL; + } + *pRssi = m_rssi; + *pRegistrationState = m_registrationState; + *pBearer = m_bearer; + return OK; +} + +int LinkMonitor::getPhoneNumber(char* phoneNumber) +{ + *m_phoneNumber = '\0'; + if (m_gsm) { + int ret = m_pIf->execute("AT+CNUM", this, NULL, DEFAULT_TIMEOUT); + if(ret != OK) + { + return NET_PROTOCOL; + } + } + strcpy(phoneNumber, m_phoneNumber); + return OK; +}
\ No newline at end of file diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.h new file mode 100644 index 0000000000..864909d6c5 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/link/LinkMonitor.h @@ -0,0 +1,96 @@ +/* LinkMonitor.h */ +/* 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. + */ + +#ifndef LINKMONITOR_H_ +#define LINKMONITOR_H_ + +#include "core/fwk.h" + +#include "rtos.h" + +#include "at/ATCommandsInterface.h" + +/** Component to monitor link quality + * + */ +class LinkMonitor : protected IATCommandsProcessor +{ +public: + /** Create LinkMonitor instance + @param pIf Pointer to the ATCommandsInterface instance to use + */ + LinkMonitor(ATCommandsInterface* pIf); + + /** Initialize monitor + */ + int init(bool gsm = true); + + /** Registration State + */ + enum REGISTRATION_STATE + { + REGISTRATION_STATE_UNKNOWN, //!< Unknown + REGISTRATION_STATE_REGISTERING, //!< Registering + REGISTRATION_STATE_DENIED, //!< Denied + REGISTRATION_STATE_NO_SIGNAL, //!< No Signal + REGISTRATION_STATE_HOME_NETWORK, //!< Registered on home network + REGISTRATION_STATE_ROAMING //!< Registered on roaming network + }; + + /** Bearer type + */ + enum BEARER + { + BEARER_UNKNOWN, //!< Unknown + BEARER_GSM, //!< GSM (2G) + BEARER_EDGE, //!< EDGE (2.5G) + BEARER_UMTS, //!< UMTS (3G) + BEARER_HSPA, //!< HSPA (3G+) + BEARER_LTE //!< LTE (4G) + }; + + /** Get link state + @param pRssi pointer to store the current RSSI in dBm, between -51 dBm and -113 dBm if known; -51 dBm means -51 dBm or more; -113 dBm means -113 dBm or less; 0 if unknown + @param pRegistrationState pointer to store the current registration state + @param pBearer pointer to store the current bearer + @return 0 on success, error code on failure + */ + int getState(int* pRssi, REGISTRATION_STATE* pRegistrationState, BEARER* pBearer); + + /** Get my phone number + @param phoneNumber pointer to store the current phoneNumber + @return 0 on success, error code on failure + */ + int getPhoneNumber(char* phoneNumber); +protected: + //IATCommandsProcessor + virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line); + virtual int onNewEntryPrompt(ATCommandsInterface* pInst); + +private: + ATCommandsInterface* m_pIf; + + int m_rssi; + bool m_gsm; + REGISTRATION_STATE m_registrationState; + BEARER m_bearer; + char m_phoneNumber[16]; +}; + +#endif /* LINKMONITOR_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/lwipopts_conf.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/lwipopts_conf.h new file mode 100644 index 0000000000..5cd84be875 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/lwipopts_conf.h @@ -0,0 +1,26 @@ +/* lwipopts.h */ +/* 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. + */ + +#ifndef LWIPOPTS_CONF_H_ +#define LWIPOPTS_CONF_H_ + +#define LWIP_TRANSPORT_PPP 1 + +#endif /* LWIPOPTS_CONF_H_ */ + diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.cpp new file mode 100644 index 0000000000..978b3e1e8b --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.cpp @@ -0,0 +1,350 @@ +/* CDMASMSInterface.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__ 0 +#ifndef __MODULE__ +#define __MODULE__ "CDMASMSInterface.cpp" +#endif + +#include "core/fwk.h" + +#include "CDMASMSInterface.h" + +#include <cstdio> +#include <cstring> + +using std::sscanf; + +#define DEFAULT_TIMEOUT 10000 + +CDMASMSInterface::CDMASMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL) +{ +} + +int CDMASMSInterface::init() +{ + m_state = SMS_IDLE; + + DBG("Get number of messages in the different inboxes"); + int ret = updateInbox(); + if(ret) + { + return NET_PROTOCOL; + } + + DBG("Initialization done"); + return OK; +} + +int CDMASMSInterface::send(const char* number, const char* message) +{ + if( strlen(number) > 16 ) + { + return NET_INVALID; //Number too long + } + + int ret; + + //Prepare infos + m_state = SMS_SEND_CMD_SENT; + + 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+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) + { + WARN("ret %d", ret); + m_state = SMS_IDLE; + return NET_PROTOCOL; + } + + 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; +} + + +int CDMASMSInterface::get(char* number, char* message, size_t maxLength) +{ + if( maxLength < 1 ) + { + return NET_INVALID; //Buffer too short + } + + int ret; + + DBG("Get next message"); + 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) + { + return ret; + } + } + + 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]) + { + index = 3; + } + else if(m_msgInListsCount[0]) + { + index = 1; + } + else //if(m_msgInListsCount[1]) + { + index = 2; + } + + //Prepare infos + m_state = SMS_GET_CMD_SENT; + m_msisdn = (char*) number; + m_msg = (char*) message; + m_maxMsgLength = maxLength; + m_headersToRead = 3; + + m_msisdn[0] = '\0'; + + DBG("Get SMS"); + //Read command + char cmd[32]; + 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!GSMS returned %d", ret); + m_state = SMS_IDLE; + return NET_PROTOCOL; + } + + //If message is not read, it will be put at the end of the read list + int item; + if( index != 3 ) + { + //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"); + } + } + 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 work when specifying the index?? + ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT); + if(ret != OK) + { + ERR("Could not delete message"); + } + 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; + return NET_EMPTY; + } + + m_state = SMS_IDLE; + + return OK; +} + + +int CDMASMSInterface::getCount(size_t* pCount) +{ + int ret = updateInbox(); + if(ret) + { + return NET_PROTOCOL; + } + + *pCount = m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]; //Urgent messages + regular messages + read messages + + return OK; +} + + +/*virtual*/ int CDMASMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) +{ + if(m_state == SMS_SEND_CMD_SENT) + { + 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")) + { + 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(m_msisdn[0]=='\0') + { + 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) + { + 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("Inbox: %s", line); + int index; + size_t count; + if((strlen(line) > 16) && sscanf(line + 16, "{Index = %d}: %d", &index, &count) == 2) + { + if((index > 0) && (index <=4)) + { + m_msgInListsCount[index-1] = count; + } + if(index == 4) + { + m_state = SMS_CMD_PROCESSED; + } + } + } + return OK; +} + +/*virtual*/ int CDMASMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst) +{ + return OK; +} + + +int CDMASMSInterface::updateInbox() +{ + //Get number of unread/read messages + + DBG("Updating inbox"); + m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Reset counts + + //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; +} + diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.h new file mode 100644 index 0000000000..6aa4557c36 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/CDMASMSInterface.h @@ -0,0 +1,90 @@ +/* SMSInterface.h */ +/* 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. + */ + +#ifndef CDMASMSINTERFACE_H_ +#define CDMASMSINTERFACE_H_ + +#include "SMSInterface.h" + +#define MAX_SM 8 + +/** Component to use the Short Messages Service (SMS) + * + */ +class CDMASMSInterface : public ISMSInterface, protected IATCommandsProcessor +{ +public: + /** Create SMSInterface instance + @param pIf Pointer to the ATCommandsInterface instance to use + */ + CDMASMSInterface(ATCommandsInterface* pIf); + + /** Initialize interface + Configure SMS commands & register for SMS-related unsolicited result codes + */ + virtual int init(); + + /** Send a SM + @param number The receiver's phone number + @param message The message to send + @return 0 on success, error code on failure + */ + virtual int send(const char* number, const char* message); + + + /** Receive a SM + @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the space for the null-terminating char) + @param message Pointer to a buffer to store the the incoming message + @param maxLength Maximum message length that can be stored in buffer (including null-terminating character) + @return 0 on success, error code on failure + */ + virtual int get(char* number, char* message, size_t maxLength); + + + /** Get the number of SMs in the incoming box + @param pCount pointer to store the number of unprocessed SMs on + @return 0 on success, error code on failure + */ + virtual int getCount(size_t* pCount); + +protected: + //IATCommandsProcessor + virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line); + virtual int onNewEntryPrompt(ATCommandsInterface* pInst); + + int updateInbox(); //Update messages count in the different inboxes + +private: + ATCommandsInterface* m_pIf; + + //Current message + char* m_msg; + size_t m_maxMsgLength; + char* m_msisdn; + + //Messages list + size_t m_msgInListsCount[4]; //4 lists + + size_t m_headersToRead; + + enum { SMS_NONE, SMS_SENT, SMS_PENDING, SMS_FAILED } m_txState; + enum { SMS_IDLE, SMS_SEND_CMD_SENT, SMS_GET_TX_STATUS_CMD_SENT, SMS_GET_CMD_SENT, SMS_GET_HDR_RECEIVED, SMS_GET_COUNT_CMD_SENT, SMS_CMD_PROCESSED } m_state; +}; + +#endif /* CDMASMSINTERFACE_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.cpp new file mode 100644 index 0000000000..2ed50ad126 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.cpp @@ -0,0 +1,423 @@ +/* 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; +} + + diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.h new file mode 100644 index 0000000000..446a73e518 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.h @@ -0,0 +1,97 @@ +/* SMSInterface.h */ +/* 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. + */ + +#ifndef GSMSMSINTERFACE_H_ +#define GSMSMSINTERFACE_H_ + +#include "SMSInterface.h" + +/** Component to use the Short Messages Service (SMS) + * + */ +class GSMSMSInterface : public ISMSInterface, protected IATCommandsProcessor, IATEventsHandler +{ +public: + /** Create SMSInterface instance + @param pIf Pointer to the ATCommandsInterface instance to use + */ + GSMSMSInterface(ATCommandsInterface* pIf); + + /** Initialize interface + Configure SMS commands & register for SMS-related unsolicited result codes + */ + virtual int init(); + + /** Send a SM + @param number The receiver's phone number + @param message The message to send + @return 0 on success, error code on failure + */ + virtual int send(const char* number, const char* message); + + + /** Receive a SM + @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the space for the null-terminating char) + @param message Pointer to a buffer to store the the incoming message + @param maxLength Maximum message length that can be stored in buffer (including null-terminating character) + @return 0 on success, error code on failure + */ + virtual int get(char* number, char* message, size_t maxLength); + + + /** Get the number of SMs in the incoming box + @param pCount pointer to store the number of unprocessed SMs on + @return 0 on success, error code on failure + */ + virtual int getCount(size_t* pCount); + +protected: + //IATCommandsProcessor + virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line); + virtual int onNewEntryPrompt(ATCommandsInterface* pInst); + + //IATEventsHandler + virtual bool isATCodeHandled(const char* atCode); //Is this AT code handled + virtual void onDispatchStart(); + virtual void onDispatchStop(); + virtual char* getEventsEnableCommand(); + virtual char* getEventsDisableCommand(); + virtual void onEvent(const char* atCode, const char* evt); + + //Updates messages count/references + int updateInbox(); + +private: + ATCommandsInterface* m_pIf; + + //Current message + char* m_msg; + size_t m_maxMsgLength; + char* m_msisdn; + + //Messages list + int m_msgRefList[MAX_SM]; + size_t m_msgRefListCount; + bool m_needsUpdate; + Mutex m_inboxMtx; //To protect concurrent accesses btw the user's thread and the AT thread + + enum { SMS_IDLE, SMS_SEND_CMD_SENT, SMS_GET_CMD_SENT, SMS_GET_HDR_RECEIVED, SMS_GET_COUNT_CMD_SENT, SMS_GET_COUNT_HDR_RECEIVED, SMS_CMD_PROCESSED } m_state; +}; + +#endif /* GSMSMSINTERFACE_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/SMSInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/SMSInterface.h new file mode 100644 index 0000000000..df226709d1 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/SMSInterface.h @@ -0,0 +1,67 @@ +/* SMSInterface.h */ +/* 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. + */ + +#ifndef ISMSINTERFACE_H_ +#define ISMSINTERFACE_H_ + +#include "core/fwk.h" + +#include "rtos.h" + +#include "at/ATCommandsInterface.h" + +#define MAX_SM 8 + +/** Component to use the Short Messages Service (SMS) + * + */ +class ISMSInterface +{ +public: + /** Initialize interface + Configure SMS commands & register for SMS-related unsolicited result codes + */ + virtual int init() = 0; + + + /** Send a SM + @param number The receiver's phone number + @param message The message to send + @return 0 on success, error code on failure + */ + virtual int send(const char* number, const char* message) = 0; + + + /** Receive a SM + @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the space for the null-terminating char) + @param message Pointer to a buffer to store the the incoming message + @param maxLength Maximum message length that can be stored in buffer (including null-terminating character) + @return 0 on success, error code on failure + */ + virtual int get(char* number, char* message, size_t maxLength) = 0; + + + /** Get the number of SMs in the incoming box + @param pCount pointer to store the number of unprocessed SMs on + @return 0 on success, error code on failure + */ + virtual int getCount(size_t* pCount) = 0; +}; + +#endif /* ISMSINTERFACE_H_ */ diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.cpp b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.cpp new file mode 100644 index 0000000000..4815babd6a --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.cpp @@ -0,0 +1,196 @@ +/* USSDInterface.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__ 0 +#ifndef __MODULE__ +#define __MODULE__ "USSDInterface.cpp" +#endif + +#include "core/fwk.h" + +#include "USSDInterface.h" + +#include <cstdio> + +#define DEFAULT_TIMEOUT 10000 +#define USSD_TIMEOUT 15000 + +USSDInterface::USSDInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_responseMtx(), m_responseSphre(1), m_result(NULL), m_maxResultLength(0) +{ + m_responseSphre.wait(0); //Take ownership of the semaphore + m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers +} + +int USSDInterface::init() +{ + DBG("Initialization done"); + return OK; +} + +int USSDInterface::send(const char* command, char* result, size_t maxLength) +{ + if (strlen(command) > 20) //Prevent buffer overflow + { + return NET_TOOSMALL; + } + + m_responseMtx.lock(); + m_result = result; + m_maxResultLength = maxLength; + m_responseMtx.unlock(); + + m_responseSphre.wait(0); //Make sure there is not a pending result that needs to be discarded + + DBG("Send USSD command & register for unsolicited result codes"); + //Send USSD command to the network + char cmd[32]; + std::sprintf(cmd, "AT+CUSD=1,\"%s\"", command); + int ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT); + if( ret != OK ) + { + return NET_PROTOCOL; + } + + //Did we already get a response (3GPP rev < 6) ? + + //Now wait for response + int res = m_responseSphre.wait(USSD_TIMEOUT); + + //Reset data + m_responseMtx.lock(); + m_result = NULL; + m_maxResultLength = 0; + m_responseMtx.unlock(); + + if(res <= 0) + { + DBG("No result received"); + ret = m_pIf->executeSimple("AT+CUSD=2", NULL, DEFAULT_TIMEOUT); //Cancel command + if( ret != OK ) + { + return NET_PROTOCOL; + } + return NET_TIMEOUT; + } + + DBG("Result received: %s", result); + + return OK; +} + +/*virtual*/ int USSDInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) +{ + const char* pSemicol = strchr(line, ':'); + if( ( (pSemicol - line) != strlen("+CUSD") ) || ( memcmp(line, "+CUSD", strlen("+CUSD")) != 0) ) + { + WARN("Unknown code"); + return OK; + } + + const char* pData = NULL; + if( pSemicol != NULL ) //Split the identifier & the result code (if it exists) + { + pData = pSemicol + 1; + if(pData[0]==' ') + { + pData++; //Suppress whitespace + } + processResult(pData); + } + return OK; +} + +/*virtual*/ int USSDInterface::onNewEntryPrompt(ATCommandsInterface* pInst) +{ + return OK; +} + +/*virtual*/ bool USSDInterface::isATCodeHandled(const char* atCode) //Is this AT code handled +{ + DBG("AT code is %s", atCode); + if( strcmp("+CUSD", atCode) == 0 ) + { + return true; + } + + DBG("Not handled"); + return false; +} + +/*virtual*/ void USSDInterface::onDispatchStart() +{ + + +} + +/*virtual*/ void USSDInterface::onDispatchStop() +{ + +} + +/*virtual*/ char* USSDInterface::getEventsEnableCommand() +{ + return NULL; //No need to disable events here +} + +/*virtual*/ char* USSDInterface::getEventsDisableCommand() +{ + return NULL; //No need to re-enable events here +} + +/*virtual*/ void USSDInterface::onEvent(const char* atCode, const char* evt) +{ + if( strcmp("+CUSD", atCode) != 0 ) + { + WARN("Wrong AT Code"); + return; //Not supported + } + + processResult(evt); +} + +void USSDInterface::processResult(const char* data) +{ + char* pStart = (char*) strchr(data,'\"'); + if(pStart==NULL) + { + WARN("Could not find opening quote"); + return; //Invalid/incomplete response + } + pStart++; //Point to first char of response + char* pEnd = (char*) strchr(pStart,'\"'); + if(pEnd==NULL) + { + WARN("Could not find closing quote"); + return; //Invalid/incomplete response + } + m_responseMtx.lock(); + if(m_maxResultLength == 0) //No pending command + { + WARN("No pending command"); + m_responseMtx.unlock(); + return; + } + size_t cpyLen = MIN( pEnd - pStart, m_maxResultLength - 1 ); + memcpy((void*)m_result, pStart, cpyLen); + m_result[cpyLen] = '\0'; + DBG("Got USSD response: %s", m_result); + m_responseMtx.unlock(); + m_responseSphre.release(); //Signal user thread that response is ready +} diff --git a/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.h b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.h new file mode 100644 index 0000000000..47984d1d91 --- /dev/null +++ b/tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ussd/USSDInterface.h @@ -0,0 +1,80 @@ +/* USSDInterface.h */ +/* 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. + */ + +#ifndef USSDINTERFACE_H_ +#define USSDINTERFACE_H_ + +#include "core/fwk.h" + +#include "rtos.h" + +#include "at/ATCommandsInterface.h" + +/** Component to send/receive Unstructured Supplementary Service Data (USSD) + * + */ +class USSDInterface : protected IATCommandsProcessor, IATEventsHandler +{ +public: + /** Create USSDInterface instance + @param pIf Pointer to the ATCommandsInterface instance to use + */ + USSDInterface(ATCommandsInterface* pIf); + + /** Initialize interface + Configure USSD commands & register for USSD-related unsolicited result codes + */ + int init(); + + /** Send a USSD command & wait for its result + @param command The command to send + @param result Buffer in which to store the result + @param maxLength Maximum result length that can be stored in buffer (including null-terminating character) + @return 0 on success, error code on failure + */ + int send(const char* command, char* result, size_t maxLength); + +protected: + //IATCommandsProcessor, needed for implementations of 3GGP standard < r06 + virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line); + virtual int onNewEntryPrompt(ATCommandsInterface* pInst); + + //IATEventsHandler, needed for implementations of 3GGP standard >= r06 + virtual bool isATCodeHandled(const char* atCode); //Is this AT code handled + virtual void onDispatchStart(); + virtual void onDispatchStop(); + virtual char* getEventsEnableCommand(); + virtual char* getEventsDisableCommand(); + virtual void onEvent(const char* atCode, const char* evt); + +private: + void processResult(const char* data); + + ATCommandsInterface* m_pIf; + Mutex m_responseMtx; //To protect concurrent accesses btw the user's thread and the AT thread + Semaphore m_responseSphre; + + //Result + volatile char* m_result; + volatile size_t m_maxResultLength; + +}; + + +#endif /* USSDINTERFACE_H_ */ |