USB Host Library for Sprint Dongles
Dependencies: Socket USBHostWANDongleSprint lwip-sys lwip
Dependents: SprintUSBModemWebsocketTest SprintUSBModemHTTPClientTest SprintUSBModemNTPClientTest SprintUSBModemSMSTest ... more
Fork of SprintUSBModem_bleedingedge by
Revision 0:8f57713b2147, committed 2012-09-12
- Comitter:
- donatien
- Date:
- Wed Sep 12 09:34:21 2012 +0000
- Child:
- 1:1e847d871409
- Commit message:
- Initial Commit
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Socket.lib Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/Socket/#41e3af01f58e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SprintUSBModem.cpp Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,340 @@ +/* SprintUSBModem.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__ 3 +#ifndef __MODULE__ +#define __MODULE__ "SprintUSBModem.cpp" +#endif + +#include "core/fwk.h" + +#include "SprintUSBModem.h" + +SprintUSBModem::SprintUSBModem() : m_dongle(), +m_atStream(m_dongle.getSerial(1)), m_pppStream(m_dongle.getSerial(0)), m_at(&m_atStream), +m_sms(&m_at), m_ppp(&m_pppStream), +m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false) +{ + +} + +class CREGProcessor : public IATCommandsProcessor +{ +public: + CREGProcessor() : status(STATUS_REGISTERING) + { + + } + enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED }; + REGISTERING_STATUS getStatus() + { + return status; + } +private: + virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) + { + int r; + if( sscanf(line, "+CREG: %*d,%d", &r) == 1 ) + { + switch(r) + { + case 1: + case 5: + status = STATUS_OK; + break; + case 0: + case 2: + status = STATUS_REGISTERING; + break; + case 3: + default: + status = STATUS_FAILED; + break; + } + } + return OK; + } + virtual int onNewEntryPrompt(ATCommandsInterface* pInst) + { + return OK; + } + volatile REGISTERING_STATUS status; +}; + +int SprintUSBModem::connect(const char* apn, const char* user, const char* password) +{ + if( !m_ipInit ) + { + m_ipInit = true; + m_ppp.init(); + } + m_ppp.setup(user, password); + + int ret = init(); + if(ret) + { + return ret; + } + + #if USE_ONE_PORT + m_smsInit = false; //SMS status reset + m_ussdInit = false; //USSD status reset + m_linkMonitorInit = false; //Link monitor status reset + #endif + + ATCommandsInterface::ATResult result; + + if(apn != NULL) + { + char cmd[48]; + sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn); + ret = m_at.executeSimple(cmd, &result); + DBG("Result of command: Err code=%d", ret); + DBG("ATResult: AT return=%d (code %d)", result.result, result.code); + DBG("APN set to %s", apn); + } + + + //Connect + DBG("Connecting"); + #if USE_ONE_PORT + m_at.close(); // Closing AT parser + m_atOpen = false; //Will need to be reinitialized afterwards + #endif + + DBG("Connecting PPP"); + + ret = m_ppp.connect(); + DBG("Result of connect: Err code=%d", ret); + return ret; +} + + +int SprintUSBModem::disconnect() +{ + DBG("Disconnecting from PPP"); + int ret = m_ppp.disconnect(); + if(ret) + { + ERR("Disconnect returned %d, still trying to disconnect", ret); + } + + //Ugly but leave dongle time to recover + Thread::wait(500); + + #if USE_ONE_PORT + ATCommandsInterface::ATResult result; + DBG("Starting AT thread"); + ret = m_at.open(); + if(ret) + { + return ret; + } + #endif + + DBG("Trying to hangup"); + + #if 0 //Does not appear to work + int tries = 10; + do + { + ret = m_at.executeSimple("+++", &result, 1000); + DBG("Result of command: Err code=%d\n", ret); + DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code); + } while(tries-- && ret); + if(!ret) + { + ret = m_at.executeSimple("ATH", &result); + DBG("Result of command: Err code=%d\n", ret); + DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code); + } + #endif + + #if USE_ONE_PORT + //Reinit AT parser + ret = m_at.init(); + DBG("Result of command: Err code=%d\n", ret); + if(ret) + { + m_at.close(); // Closing AT parser + DBG("AT Parser closed, could not complete disconnection"); + return NET_TIMEOUT; + } + + #if 0 + m_at.close(); // Closing AT parser + DBG("AT Parser closed"); + #endif + #endif + return OK; +} + +int SprintUSBModem::sendSM(const char* number, const char* message) +{ + int ret = init(); + if(ret) + { + return ret; + } + + if(!m_smsInit) + { + ret = m_sms.init(); + if(ret) + { + return ret; + } + m_smsInit = true; + } + + ret = m_sms.send(number, message); + if(ret) + { + return ret; + } + + return OK; +} + +int SprintUSBModem::getSM(char* number, char* message, size_t maxLength) +{ + int ret = init(); + if(ret) + { + return ret; + } + + if(!m_smsInit) + { + ret = m_sms.init(); + if(ret) + { + return ret; + } + m_smsInit = true; + } + + ret = m_sms.get(number, message, maxLength); + if(ret) + { + return ret; + } + + return OK; +} + +int SprintUSBModem::getSMCount(size_t* pCount) +{ + int ret = init(); + if(ret) + { + return ret; + } + + if(!m_smsInit) + { + ret = m_sms.init(); + if(ret) + { + return ret; + } + m_smsInit = true; + } + + ret = m_sms.getCount(pCount); + if(ret) + { + return ret; + } + + return OK; +} + +ATCommandsInterface* SprintUSBModem::getATCommandsInterface() +{ + return &m_at; +} + +int SprintUSBModem::init() +{ + if( !m_dongleConnected ) + { + m_dongleConnected = true; + while( !m_dongle.connected() ) + { + m_dongle.tryConnect(); + Thread::wait(10); + } + } + + if(m_atOpen) + { + return OK; + } + + DBG("Starting AT thread if needed"); + int ret = m_at.open(); + if(ret) + { + return ret; + } + + DBG("Sending initialisation commands"); + ret = m_at.init(); + if(ret) + { + return ret; + } + + if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_SPRINT598U) + { + INFO("Using a Sprint 598U Dongle"); + } + else + { + WARN("Using an Unknown Dongle"); + } + + ATCommandsInterface::ATResult result; + + //Wait for network registration + CREGProcessor cregProcessor; + do + { + DBG("Waiting for network registration"); + ret = m_at.execute("AT+CREG?", &cregProcessor, &result); + DBG("Result of command: Err code=%d\n", ret); + DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code); + if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING) + { + Thread::wait(3000); + } + } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING); + if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED) + { + ERR("Registration denied"); + return NET_AUTH; + } + + m_atOpen = true; + + return OK; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SprintUSBModem.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,103 @@ +/* SprintUSBModem.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 SPRINTUSBMODEM_H_ +#define SPRINTUSBMODEM_H_ + +#include "core/fwk.h" + +#include "WANDongle.h" +#include "at/ATCommandsInterface.h" +#include "serial/usb/USBSerialStream.h" +#include "ip/PPPIPInterface.h" +#include "sms/SMSInterface.h" + +/** Sprint USB Modem (Sierra Wireless 598U) + */ +class SprintUSBModem +{ +public: + /** Create Sprint USB Modem (Sierra Wireless 598U) API instance + + */ + SprintUSBModem(); + + //Internet-related functions + + /** Open a 3G internet connection + @return 0 on success, error code on failure + */ + int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL); + + /** Close the internet connection + @return 0 on success, error code on failure + */ + int disconnect(); + + + /** Send a SM + @param number The receiver's phone number + @param message The message to send + @return 0 on success, error code on failure + */ + int sendSM(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 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 + */ + int getSM(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 + */ + int getSMCount(size_t* pCount); + + /** Get the ATCommandsInterface instance + @return Pointer to the ATCommandsInterface instance + */ + ATCommandsInterface* getATCommandsInterface(); + +protected: + int init(); + +private: + WANDongle m_dongle; + + USBSerialStream m_atStream; + USBSerialStream m_pppStream; + + ATCommandsInterface m_at; + + SMSInterface m_sms; + + PPPIPInterface m_ppp; + + bool m_dongleConnected; + bool m_ipInit; + bool m_smsInit; + bool m_atOpen; +}; + + +#endif /* SPRINTUSBMODEM_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostWANDongleSprint_bleedingedge.lib Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/donatien/code/USBHostWANDongleSprint_bleedingedge/#bfed5767d0a5
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/at/ATCommandsInterface.cpp Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,802 @@ +/* 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_env2AT(), m_AT2Env(), m_processingMtx(), + m_processingThread(&ATCommandsInterface::staticCallback, this, (osPriority)AT_THREAD_PRIORITY, 4*192), + m_eventsMtx() +{ + 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; + + //Advertize this to events handlers + m_eventsMtx.lock(); + for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot + { + if( m_eventsHandlers[i] != NULL ) + { + m_eventsHandlers[i]->onDispatchStart(); + } + } + m_eventsMtx.unlock(); + + DBG("AT interface opened"); + + return OK; +} + +//Initialize AT link +int ATCommandsInterface::init() +{ + DBG("Sending ATZ E1 V1"); + //Should we flush m_pStream at this point ??? + int err; + int tries = 5; + do + { + err = executeSimple("ATZ E1 V1", 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); + return err; + } + + DBG("AT interface initialized"); + + return OK; +} + +//Close connection +int ATCommandsInterface::close() +{ + if( !m_open ) + { + WARN("AT interface is already closed"); + return OK; + } + + DBG("Closing AT interface"); + + //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; + + //Advertize this to events handlers + m_eventsMtx.lock(); + for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot + { + if( m_eventsHandlers[i] != NULL ) + { + m_eventsHandlers[i]->onDispatchStop(); + } + } + m_eventsMtx.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*/) +{ + DBG("Executing command %s", command); + if(!m_open) + { + WARN("Interface is not open!"); + return NET_INVALID; + } + + //Lock transaction mutex + m_transactionMtx.lock(); + + //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 + } + + Thread::wait(100); //FIXME find stg else + + 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 + + WARN("Command returned no message"); + m_transactionMtx.unlock(); + 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); + } + + DBG("Command returned successfully"); + + //Unlock transaction mutex + m_transactionMtx.unlock(); + + return ret; +} + +int ATCommandsInterface::registerEventsHandler(IATEventsHandler* pHdlr) +{ + m_eventsMtx.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_eventsMtx.unlock(); + return OK; + } + } + m_eventsMtx.unlock(); + return NET_OOM; //No room left +} + +int ATCommandsInterface::deregisterEventsHandler(IATEventsHandler* pHdlr) +{ + m_eventsMtx.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_eventsMtx.unlock(); + return OK; + } + } + m_eventsMtx.unlock(); + return NET_NOTFOUND; //Not found +} + + +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 + processReadLine(); + //Shift remaining data to beginning of buffer + 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; + 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; + 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; + 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 + { + 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_eventsMtx.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_eventsMtx.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; +} + +//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); + return ret; + }; + + if( memcmp(m_inputBuf, data + dataPos, readLen) != 0 ) + { + //Echo does not match output + WARN("Echo does not match output"); + 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 + + 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 read a new line"); + tryReadLine(); + DBG("Trying to send a pending command"); + trySendCommand(); + } 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"); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/at/ATCommandsInterface.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,142 @@ +/* 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 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 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(); + + //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 tryReadLine(); + int trySendCommand(); + int processReadLine(); + int processEntryPrompt(); + + 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; + + 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]; + int m_inputPos; + + Mutex m_transactionMtx; + + Mail<int,1> m_env2AT; + Mail<int,1> m_AT2Env; + + IATEventsHandler* m_eventsHandlers[MAX_AT_EVENTS_HANDLERS]; + + Mutex m_processingMtx; + Thread m_processingThread; + + Mutex m_eventsMtx; +}; + +#endif /* ATCOMMANDSINTERFACE_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/IOStream.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,61 @@ +/* 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 "fwk.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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/MtxCircBuffer.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,103 @@ +/* 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 "fwk.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(); + while (((write + 1) % size) == read) //if (isFull()) + { + /*while((((write + 1) % size) == read)) + {*/ + mtx.unlock(); + Thread::wait(10); + mtx.lock(); + /*}*/ + //read++; + //read %= size; + } + buf[write++] = k; + write %= 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 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/config.h Wed Sep 12 09:34:21 2012 +0000 @@ -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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/dbg.cpp Wed Sep 12 09:34:21 2012 +0000 @@ -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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/dbg.h Wed Sep 12 09:34:21 2012 +0000 @@ -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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/errors.h Wed Sep 12 09:34:21 2012 +0000 @@ -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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/fwk.h Wed Sep 12 09:34:21 2012 +0000 @@ -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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ip/IPInterface.cpp Wed Sep 12 09:34:21 2012 +0000 @@ -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() +{ + +} + +/*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; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ip/IPInterface.h Wed Sep 12 09:34:21 2012 +0000 @@ -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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ip/LwIPInterface.cpp Wed Sep 12 09:34:21 2012 +0000 @@ -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(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ip/LwIPInterface.h Wed Sep 12 09:34:21 2012 +0000 @@ -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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ip/PPPIPInterface.cpp Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,442 @@ +/* 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 //Maximum verbosity +#ifndef __MODULE__ +#define __MODULE__ "PPPIPInterface.cpp" +#endif + +#include "core/fwk.h" +#include "rtos.h" + +#include "PPPIPInterface.h" + +#define MSISDN "#777" +//TODO Pass this as parameter (*99# is used by GSM systems, #777 by CDMA systems--well at least Sprint!) + +#define CONNECT_CMD "ATD " MSISDN "\x0D" +#define EXPECTED_RESP CONNECT_CMD "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A" +#define EXPECTED_RESP_DATARATE CONNECT_CMD "\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 "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) +{ + DBG("Configuring PPP authentication method"); + pppSetAuth(PPPAUTHTYPE_ANY, user, pw); + DBG("Done"); + return OK; +} + +/*virtual*/ int PPPIPInterface::connect() +{ + int ret; + char buf[32]; + size_t len; + DBG("Trying to connect with PPP"); + + cleanupLink(); + + DBG("Sending %s", CONNECT_CMD); + + ret = m_pStream->write((uint8_t*)CONNECT_CMD, strlen(CONNECT_CMD), osWaitForever); + if( ret != OK ) + { + return NET_UNKNOWN; + } + + DBG("Expect %s", EXPECTED_RESP); + + 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; + if( (sscanf( buf, EXPECTED_RESP_DATARATE, &datarate ) != 1) && (strcmp(EXPECTED_RESP, 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)); + 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"); +} + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ip/PPPIPInterface.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,65 @@ +/* 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; + +/** 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); //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; + + 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwip-sys.lib Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/lwip-sys/#b409691fb352
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwip.lib Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/lwip/#00bf89892c76
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwipopts_conf.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,25 @@ +/* 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_ */ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/serial/io/IOSerialStream.cpp Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,253 @@ +/* IOSerialStream.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 //Maximum verbosity +#ifndef __MODULE__ +#define __MODULE__ "IOSerialStream.cpp" +#endif + +#include "core/fwk.h" + +#include <stdio.h> + +#include "IOSerialStream.h" + +IOSerialStream::IOSerialStream(mbed::Serial& serial) : m_serial(serial), m_serialTxFifoEmpty(true), +m_availableSphre(1), m_spaceSphre(1), m_inBuf(), m_outBuf() +{ + m_availableSphre.wait(); + m_spaceSphre.wait(); + //Attach interrupts + m_serial.attach(this, &IOSerialStream::readable, mbed::Serial::RxIrq); + m_serial.attach(this, &IOSerialStream::writeable, mbed::Serial::TxIrq); +} + +/*virtual*/ IOSerialStream::~IOSerialStream() +{ + m_serial.attach(NULL, mbed::Serial::RxIrq); + m_serial.attach(NULL, mbed::Serial::TxIrq); +} + +//0 for non-blocking (returns immediately), osWaitForever for infinite blocking +/*virtual*/ int IOSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/) +{ + DBG("Trying to read at most %d chars", maxLength); + int ret = waitAvailable(timeout); + if(ret) + { + WARN("Error %d while waiting for incoming data", ret); + return ret; + } + int readLen = MIN( available(), maxLength ); + *pLength = readLen; + setupReadableISR(false); + while(readLen--) + { + m_inBuf.dequeue(buf); + buf++; + } + setupReadableISR(true); + DBG("Read %d chars successfully", *pLength); + return OK; +} + +/*virtual*/ size_t IOSerialStream::available() +{ + setupReadableISR(false); //m_inBuf.available() is not reentrant + size_t len = m_inBuf.available(); + setupReadableISR(true); + return len; +} + +/*virtual*/ int IOSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available +{ + int ret; + if(available()) //Is data already available? + { + m_availableSphre.wait(0); //Clear the queue as data is available + return OK; + } + + DBG("Waiting for data availability %d ms (-1 is infinite)", timeout); + ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort + if(ret <= 0) + { + DBG("Timeout"); + return NET_TIMEOUT; + } + if(!available()) //Even if abort has been called, return that data is available + { + DBG("Aborted"); + return NET_INTERRUPTED; + } + DBG("Finished waiting"); + m_availableSphre.wait(0); //Clear the queue as data is available + return OK; +} + +/*virtual*/ int IOSerialStream::abortRead() //Abort current reading (or waiting) operation +{ + if( !available() ) //If there is data pending, no need to abort + { + m_availableSphre.release(); //Force exiting the waiting state; kludge to pass a RC directly + } + else + { + DBG("Serial is readable"); ; + } + return OK; +} + +void IOSerialStream::setupReadableISR(bool en) +{ + if(en) + { + ((LPC_UART_TypeDef *)(UART_3))->IER |= 1 << 0; + } + else + { + ((LPC_UART_TypeDef *)(UART_3))->IER &= ~(1 << 0); + } +} + +void IOSerialStream::readable() //Callback from m_serial when new data is available +{ + do + { + m_inBuf.queue(((LPC_UART_TypeDef *)UART_3)->RBR); //FIXME mbed libraries this is an awful kludge + } while(m_serial.readable()); + m_availableSphre.release(); //Force exiting the waiting state +} + +//0 for non-blocking (returns immediately), osWaitForever for infinite blocking +/*virtual*/ int IOSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=osWaitForever*/) +{ + DBG("Trying to write %d chars", length); + int ret = waitSpace(timeout); + if(ret) + { + WARN("Error %d while waiting for space", ret); + return ret; + } + DBG("Writing %d chars", length); + setupWriteableISR(false); + while(length) + { + m_outBuf.queue(*buf); + buf++; + length--; + if(length && !space()) + { + DBG("Waiting to write remaining %d chars", length); + setupWriteableISR(true); + ret = waitSpace(timeout); + if(ret) + { + WARN("Error %d while waiting for space", ret); + return ret; + } + setupWriteableISR(false); + } + } + //If m_serial tx fifo is empty we need to manually tx a byte in order to trigger the interrupt + if( m_outBuf.available() && m_serialTxFifoEmpty ) + { + m_serialTxFifoEmpty = false; + uint8_t c; + m_outBuf.dequeue(&c); + //m_serial.putc((char)c); + ((LPC_UART_TypeDef *)UART_3)->THR = c; //FIXME awful kludge + } + setupWriteableISR(true); + DBG("Write successful"); + return OK; +} + +/*virtual*/ size_t IOSerialStream::space() +{ + setupWriteableISR(false); //m_outBuf.available() is not reentrant + size_t len = CIRCBUF_SIZE - m_outBuf.available(); + setupWriteableISR(true); + return len; +} + +/*virtual*/ int IOSerialStream::waitSpace(uint32_t timeout/*=osWaitForever*/) //Wait for space to be available +{ + int ret; + if(space()) //Is still space already left? + { + m_spaceSphre.wait(0); //Clear the queue as space is available + return OK; + } + + DBG("Waiting for data space %d ms (-1 is infinite)", timeout); + ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort + if(ret <= 0) + { + DBG("Timeout"); + return NET_TIMEOUT; + } + if(!space()) //Even if abort has been called, return that space is available + { + DBG("Aborted"); + return NET_INTERRUPTED; + } + m_spaceSphre.wait(0); //Clear the queue as space is available + return OK; +} + +/*virtual*/ int IOSerialStream::abortWrite() //Abort current writing (or waiting) operation +{ + if( !space() ) //If there is space left, no need to abort + { + m_spaceSphre.release(); //Force exiting the waiting state + } + return OK; +} + +void IOSerialStream::setupWriteableISR(bool en) +{ + if(en) + { + ((LPC_UART_TypeDef *)(UART_3))->IER |= 1 << 1; + } + else + { + ((LPC_UART_TypeDef *)(UART_3))->IER &= ~(1 << 1); + } +} + +void IOSerialStream::writeable() //Callback from m_serial when new space is available +{ + if(m_outBuf.isEmpty()) + { + m_serialTxFifoEmpty = true; + } + else + { + while(m_serial.writeable() && !m_outBuf.isEmpty()) + { + uint8_t c; + m_outBuf.dequeue(&c); + //m_serial.putc((char)c); + ((LPC_UART_TypeDef *)UART_3)->THR = c; //FIXME awful kludge + } + } + m_spaceSphre.release(); //Force exiting the waiting state +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/serial/io/IOSerialStream.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,72 @@ +/* IOSerialStream.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 IOSERIALSTREAM_H_ +#define IOSERIALSTREAM_H_ + +#include "core/fwk.h" + +#include "Serial.h" + +#include "rtos.h" +#include "core/MtxCircBuffer.h" + +/** Input Serial Stream for physical serial interfaces (UART...) +This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR +*/ +#define CIRCBUF_SIZE 255 +class IOSerialStream : public IOStream +{ +public: + IOSerialStream(mbed::Serial& serial); + /*virtual*/ ~IOSerialStream(); + + //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); + virtual size_t available(); + virtual int waitAvailable(uint32_t timeout=osWaitForever); //Wait for data to be available + virtual int abortRead(); //Abort current reading (or waiting) operation + + + //0 for non-blocking (returns immediately), osWaitForever for infinite blocking + virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever); + virtual size_t space(); + virtual int waitSpace(uint32_t timeout=osWaitForever); //Wait for space to be available + virtual int abortWrite(); //Abort current writing (or waiting) operation + +private: + + mbed::Serial& m_serial; + volatile bool m_serialTxFifoEmpty; + + void setupReadableISR(bool en); + void readable(); //Callback from m_serial when new data is available + + Semaphore m_availableSphre; //Used for signalling + + void setupWriteableISR(bool en); + void writeable(); //Callback from m_serial when new space is available + + Semaphore m_spaceSphre; //Used for signalling + + MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_inBuf; + MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_outBuf; + +}; + +#endif /* IOSERIALSTREAM_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/serial/usb/USBSerialStream.cpp Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,236 @@ +/* USBSerialStream.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 //Maximum verbosity +#ifndef __MODULE__ +#define __MODULE__ "USBSerialStream.cpp" +#endif + +#include "core/fwk.h" + +#include <stdio.h> + +#include "USBSerialStream.h" + + +USBSerialStream::USBSerialStream(IUSBHostSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true), +m_availableSphre(1), m_spaceSphre(1), m_inBuf() +{ + m_availableSphre.wait(); + m_spaceSphre.wait(); + //Attach interrupts + m_serial.attach(this); +} + +/*virtual*/ USBSerialStream::~USBSerialStream() +{ + m_serial.attach(NULL); +} + +//0 for non-blocking (returns immediately), -1 for infinite blocking +/*virtual*/ int USBSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/) +{ + DBG("Trying to read at most %d chars", maxLength); + int ret = waitAvailable(timeout); + if(ret) + { + WARN("Error %d while waiting for incoming data", ret); + return ret; + } + int a = available(); //Prevent macro issues + int readLen = MIN( a, maxLength ); + *pLength = readLen; + + setupReadableISR(false); + while(readLen--) + { + m_inBuf.dequeue(buf); + buf++; + } + setupReadableISR(true); + DBG("Read %d chars successfully", *pLength); + return OK; +} + +/*virtual*/ size_t USBSerialStream::available() +{ + setupReadableISR(false); //m_inBuf.available() is not reentrant + size_t len = m_inBuf.available(); + setupReadableISR(true); + return len; +} + +/*virtual*/ int USBSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available +{ + int ret; + if(available()) //Is data already available? + { + while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available + return OK; + } + + DBG("Waiting for data availability %d ms (-1 is infinite)", timeout); + ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort + if(ret <= 0) + { + DBG("Timeout"); + return NET_TIMEOUT; + } + if(!m_inBuf.available()) //Even if abort has been called, return that data is available + { + DBG("Aborted"); + return NET_INTERRUPTED; + } + DBG("Finished waiting"); + while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available + return OK; +} + +/*virtual*/ int USBSerialStream::abortRead() //Abort current reading (or waiting) operation +{ + if( /*!available()*/true ) //If there is data pending, no need to abort + { + m_availableSphre.release(); //Force exiting the waiting state + } + else + { + DBG("Serial is readable"); ; + } + return OK; +} + +void USBSerialStream::setupReadableISR(bool en) +{ + m_serial.setupIrq(en, IUSBHostSerial::RxIrq); +} + +void USBSerialStream::readable() //Callback from m_serial when new data is available +{ + while(m_serial.readable()) + { + m_inBuf.queue(m_serial.getc()); + } + m_serial.readPacket(); //Start read of next packet + m_availableSphre.release(); //Force exiting the waiting state +} + +//0 for non-blocking (returns immediately), -1 for infinite blocking +/*virtual*/ int USBSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=-1*/) +{ + DBG("Trying to write %d chars", length); + do + { + int ret = waitSpace(timeout); + if(ret) + { + WARN("Error %d while waiting for space", ret); + return ret; + } + int s = space(); //Prevent macro issues + int writeLen = MIN( s, length ); + DBG("Writing %d chars", writeLen); + setupWriteableISR(false); + while(writeLen) + { + m_outBuf.queue(*buf); + buf++; + length--; + writeLen--; + } + //If m_serial tx fifo is empty we need to start the packet write + if( m_outBuf.available() && m_serialTxFifoEmpty ) + { + writeable(); + } + setupWriteableISR(true); + } while(length); + + DBG("Write successful"); + return OK; +} + +/*virtual*/ size_t USBSerialStream::space() +{ + setupWriteableISR(false); //m_outBuf.available() is not reentrant + size_t len = CIRCBUF_SIZE - m_outBuf.available(); + setupWriteableISR(true); + return len; +} + +/*virtual*/ int USBSerialStream::waitSpace(uint32_t timeout/*=-1*/) //Wait for space to be available +{ + int ret; + if(space()) //Is still space already left? + { + while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available + return OK; + } + + DBG("Waiting for data space %d ms (-1 is infinite)", timeout); + ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort + if(ret <= 0) + { + DBG("Timeout"); + return NET_TIMEOUT; + } + if(!space()) //Even if abort has been called, return that space is available + { + DBG("Aborted"); + return NET_INTERRUPTED; + } + while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available + return OK; +} + +/*virtual*/ int USBSerialStream::abortWrite() //Abort current writing (or waiting) operation +{ + if( !space() ) //If there is space left, no need to abort + { + m_spaceSphre.release(); //Force exiting the waiting state + } + return OK; +} + +void USBSerialStream::setupWriteableISR(bool en) +{ + m_serial.setupIrq(en, IUSBHostSerial::TxIrq); +} + +void USBSerialStream::writeable() //Callback from m_serial when new space is available +{ + if(m_outBuf.isEmpty()) + { + m_serialTxFifoEmpty = true; + } + else + { + m_serialTxFifoEmpty = false; + while(m_serial.writeable() && !m_outBuf.isEmpty()) + { + uint8_t c; + m_outBuf.dequeue(&c); + m_serial.putc((char)c); + } + m_serial.writePacket(); //Start packet write + } + if(!m_outBuf.isFull()) + { + m_spaceSphre.release(); //Force exiting the waiting state + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/serial/usb/USBSerialStream.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,73 @@ +/* USBSerialStream.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 USBSERIALSTREAM_H_ +#define USBSERIALSTREAM_H_ + + +#include "core/fwk.h" + +#include "USB3GModule/IUSBHostSerial.h" +#include "USB3GModule/IUSBHostSerialListener.h" + +#include "rtos.h" +#include "core/MtxCircBuffer.h" + +/* Input Serial Stream for USB virtual serial ports interfaces +This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR +*/ +#define CIRCBUF_SIZE 127 +class USBSerialStream : public IOStream, IUSBHostSerialListener +{ +public: + USBSerialStream(IUSBHostSerial& serial); + /*virtual*/ ~USBSerialStream(); + + //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); + virtual size_t available(); + virtual int waitAvailable(uint32_t timeout=osWaitForever); //Wait for data to be available + virtual int abortRead(); //Abort current reading (or waiting) operation + + + //0 for non-blocking (returns immediately), osWaitForever for infinite blocking + virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever); + virtual size_t space(); + virtual int waitSpace(uint32_t timeout=osWaitForever); //Wait for space to be available + virtual int abortWrite(); //Abort current writing (or waiting) operation + +private: + IUSBHostSerial& m_serial; + volatile bool m_serialTxFifoEmpty; + + void setupReadableISR(bool en); + virtual void readable(); //Callback from m_serial when new data is available + + Semaphore m_availableSphre; //Used for signalling + + void setupWriteableISR(bool en); + virtual void writeable(); //Callback from m_serial when new space is available + + Semaphore m_spaceSphre; //Used for signalling + + MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_inBuf; + MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_outBuf; +}; + +#endif /* USBSERIALSTREAM_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sms/SMSInterface.cpp Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,386 @@ +/* SMSInterface.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__ "SMSInterface.cpp" +#endif + +#include "core/fwk.h" + +#include "SMSInterface.h" + +#include <cstdio> + +#define DEFAULT_TIMEOUT 10000 + +SMSInterface::SMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL), /*m_msgCount(0),*/ +m_msgRefListCount(0), m_needsUpdate(true), m_state(SMS_IDLE) +{ + m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers +} + +int SMSInterface::init() +{ + 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 SMSInterface::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 SMSInterface::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) + { + ret = updateInbox(); + if (ret) + { + m_inboxMtx.unlock(); + return ret; + } + } + + if(m_msgRefListCount == 0) + { + m_inboxMtx.unlock(); + 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) + { + m_state = SMS_IDLE; + m_inboxMtx.unlock(); + return NET_EMPTY; + } + + m_state = SMS_IDLE; + + DBG("Deleting message"); + //Delete message from outbox + std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]); + ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT); + if(ret != OK) + { + m_inboxMtx.unlock(); + WARN("Could not delete message"); + } + + //Remove message from list + std::memmove(m_msgRefList, m_msgRefList+1, m_msgRefListCount-1); + m_msgRefListCount--; + + m_inboxMtx.unlock(); + + return OK; +} + + +int SMSInterface::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 SMSInterface::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", &msgRef) == 1 ) + { + 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 SMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst) +{ + if(m_state == SMS_SEND_CMD_SENT) + { + char* crPtr = strchr(m_msg, CR); + if(crPtr != NULL) + { + int crPos = crPtr - m_msg; + //Replace m_inputBuf[crPos] with null-terminating char + m_msg[crPos] = '\x0'; + + //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 SMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled +{ + DBG("AT code is %s", atCode); + if( strcmp("+CMTI", atCode) == 0 ) + { + return true; + } + + DBG("Not handled"); + return false; +} + +/*virtual*/ void SMSInterface::onDispatchStart() +{ + + +} + +/*virtual*/ void SMSInterface::onDispatchStop() +{ + +} + +/*virtual*/ void SMSInterface::onEvent(const char* atCode, const char* evt) +{ + if( strcmp("+CMTI", atCode) != 0 ) + { + return; //Not supported + } + + DBG("Unsollicited result code: %s - %s", atCode, evt); + + //Get index + int msgRef; + if( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 ) + { + DBG("Adding message to list (ref %d)", msgRef); + m_inboxMtx.lock(); + //Add message to list + if(m_msgRefListCount < MAX_SM) + { + m_msgRefList[m_msgRefListCount] = msgRef; + } + else + { + m_needsUpdate = true; + } + m_msgRefListCount++; //Always count message + m_inboxMtx.unlock(); + } +} + +int SMSInterface::updateInbox() +{ + //Get memory indexes of unread messages + m_state = SMS_GET_COUNT_CMD_SENT; + + DBG("Updating inbox"); + m_msgRefListCount = 0; //Reset list + + int ret = m_pIf->execute("AT+CMGL=\"REC UNREAD\"", this, NULL, DEFAULT_TIMEOUT); + if( ret != OK ) + { + WARN("AT+CMGL returned %d", ret); + m_state = SMS_IDLE; + m_msgRefListCount = 0; //List could be invalid + m_needsUpdate = true; + return NET_PROTOCOL; + } + + DBG("%d incoming messages in inbox", m_msgRefListCount); + + if( m_msgRefListCount > MAX_SM ) + { + m_needsUpdate = true; + } + else + { + m_needsUpdate = false; + } + + m_state = SMS_IDLE; + + return OK; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sms/SMSInterface.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,101 @@ +/* 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 SMSINTERFACE_H_ +#define SMSINTERFACE_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 SMSInterface : protected IATCommandsProcessor, IATEventsHandler +{ +public: + /** Create SMSInterface instance + @param pIf Pointer to the ATCommandsInterface instance to use + */ + SMSInterface(ATCommandsInterface* pIf); + + /** Initialize interface + Configure SMS commands & register for SMS-related unsolicited result codes + */ + 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 + */ + 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 + */ + 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 + */ + 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 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 /* SMSINTERFACE_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/socket/bsd_socket.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,34 @@ +/* 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 BSD_SOCKET_H_ +#define BSD_SOCKET_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "socket/sys/socket.h" //Must conform to <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html> +#include "socket/netinet/in.h" //Must conform to <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html> +#include "socket/netdb.h" //Must conform to <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netdb.h.html> + +#ifdef __cplusplus +} +#endif + +#endif /* BSD_SOCKET_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/socket/netdb.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,47 @@ +/* netdb.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 NETDB_H_ +#define NETDB_H_ + +#include "lwip/netdb.h" + +//DNS + +inline struct hostent *gethostbyname(const char *name) +{ + return lwip_gethostbyname(name); +} + +inline int gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop) +{ + return lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop); +} + +inline void freeaddrinfo(struct addrinfo *ai) +{ + return lwip_freeaddrinfo(ai); +} + +inline int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) +{ + return lwip_getaddrinfo(nodename, servname, hints, res); +} + +#endif /* NETDB_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/socket/netinet/in.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,25 @@ +/* in.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 IN_H_ +#define IN_H_ + +#include "lwip/inet.h" + +#endif /* IN_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/socket/sys/socket.h Wed Sep 12 09:34:21 2012 +0000 @@ -0,0 +1,126 @@ +/* socket.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 SOCKET_H_ +#define SOCKET_H_ + +#include "lwip/sockets.h" + +//Sockets + +inline int accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + return lwip_accept(s, addr, addrlen); +} + +inline int bind(int s, const struct sockaddr *name, socklen_t namelen) +{ + return lwip_bind(s, name, namelen); +} + +inline int shutdown(int s, int how) +{ + return lwip_shutdown(s, how); +} + +inline int getsockname (int s, struct sockaddr *name, socklen_t *namelen) +{ + return lwip_getsockname(s, name, namelen); +} + +inline int getpeername (int s, struct sockaddr *name, socklen_t *namelen) +{ + return lwip_getpeername(s, name, namelen); +} + +inline int getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen) +{ + return lwip_getsockopt(s, level, optname, optval, optlen); +} + +inline int setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen) +{ + return lwip_setsockopt(s, level, optname, optval, optlen); +} + +inline int connect(int s, const struct sockaddr *name, socklen_t namelen) +{ + return lwip_connect(s, name, namelen); +} + +inline int listen(int s, int backlog) +{ + return lwip_listen(s, backlog); +} + +inline int recv(int s, void *mem, size_t len, int flags) +{ + return lwip_recv(s, mem, len, flags); +} + +inline int recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + return lwip_recvfrom(s, mem, len, flags, from, fromlen); +} + +inline int send(int s, const void *dataptr, size_t size, int flags) +{ + return lwip_send(s, dataptr, size, flags); +} + +inline int sendto(int s, const void *dataptr, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + return lwip_sendto(s, dataptr, size, flags, to, tolen); +} + +inline int socket(int domain, int type, int protocol) +{ + return lwip_socket(domain, type, protocol); +} + +inline int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout) +{ + return lwip_select(maxfdp1, readset, writeset, exceptset, timeout); +} + +inline int ioctlsocket(int s, long cmd, void *argp) +{ + return lwip_ioctl(s, cmd, argp); +} + +inline int read(int s, void *mem, size_t len) +{ + return lwip_read(s, mem, len); +} + +inline int write(int s, const void *dataptr, size_t size) +{ + return lwip_write(s, dataptr, size); +} + +inline int close(int s) +{ + return lwip_close(s); +} + +#endif /* SOCKET_H_ */