Vodafone K3770/K3772-Z modems driver & networking library
Dependencies: Socket USBHostWANDongle lwip-sys lwip
Dependents: VodafoneUSBModemHTTPClientTest VodafoneUSBModemNTPClientTest VodafoneUSBModemSMSTest VodafoneUSBModemUSSDTest ... more
Fork of VodafoneUSBModem_bleedingedge by
This is the driver for the Vodafone K3700 & K3772-Z Dongles:
More details and instructions can be found here.
Revision 8:04b6a042595f, committed 2012-06-26
- Comitter:
- donatien
- Date:
- Tue Jun 26 13:44:59 2012 +0000
- Parent:
- 7:2069ba77b6b8
- Child:
- 9:3f077dde13c9
- Child:
- 10:21a6f09d5631
- Commit message:
- Bleeding edge - test with two different interfaces
Changed in this revision
--- a/LwIPNetworking.lib Fri Jun 08 13:30:06 2012 +0000 +++ b/LwIPNetworking.lib Tue Jun 26 13:44:59 2012 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/donatien/code/LwIPNetworking/#567bdc7f0dd8 +http://mbed.org/users/donatien/code/LwIPNetworking/#cf5f669a30bc
--- a/USBHostWANDongleLib.lib Fri Jun 08 13:30:06 2012 +0000 +++ b/USBHostWANDongleLib.lib Tue Jun 26 13:44:59 2012 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/donatien/code/USBHostWANDongleLib/#49df46e3295c +http://mbed.org/users/donatien/code/USBHostWANDongle_bleedingedge/#a8b2d0cd9bbd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VodafoneK3770.cpp Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,474 @@ +/* VodafoneK3770.cpp */ +/* +Copyright (C) 2012 ARM Limited. + +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__ 4 +#ifndef __MODULE__ +#define __MODULE__ "VodafoneK3770.cpp" +#endif + +#include "core/fwk.h" + +#include "VodafoneK3770.h" + +VodafoneK3770::VodafoneK3770() : m_dongle(), +m_atStream(m_dongle.getSerial(1)), m_pppStream(m_dongle.getSerial(0)), m_at(&m_atSream), +m_ppp(&m_pppStream), m_sms(&m_at), m_ussd(&m_at), +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; +}; + +class COPSProcessor : public IATCommandsProcessor +{ +public: + COPSProcessor() : valid(false) + { + network[0] = '\0'; + apn[0] = '\0'; + bearer[0] = '\0'; + } + char* getNetwork() + { + return network; + } + char* getAPN() + { + return apn; + } + char* getBearer() + { + return bearer; + } + bool isValid() + { + return valid; + } +private: + virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) + { + int networkId; + int bearerId; + int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId); + if( s == 2 ) + { + switch(networkId) + { + case 23415: + strcpy(network, "Vodafone UK"); + strcpy(apn, "pp.vodafone.co.uk"); + valid = true; + break; + case 20810: + strcpy(network, "SFR FR"); + strcpy(apn, "websfr"); + valid = true; + break; + default: + break; + } + } + else + { + return OK; + } + switch(bearerId) + { + case 0: strcpy(bearer, "GSM"); break; + case 1: strcpy(bearer, "GSM Compact"); break; + case 2: strcpy(bearer, "UTRAN"); break; + case 3: strcpy(bearer, "GSM w/EGPRS"); break; + case 4: strcpy(bearer, "UTRAN w/HSDPA"); break; + case 5: strcpy(bearer, "UTRAN w/HSUPA"); break; + case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break; + case 7: strcpy(bearer, "E-UTRAN"); break; + + default: + break; + } + return OK; + } + virtual int onNewEntryPrompt(ATCommandsInterface* pInst) + { + return OK; + } + char network[24]; + char bearer[24]; + char apn[24]; + volatile bool valid; +}; + + +int VodafoneK3770::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; + } + + m_smsInit = false; //SMS status reset + m_ussdInit = false; //USSD status reset + + ATCommandsInterface::ATResult result; + +#if 0 + //Get network info & select corresponding APN + COPSProcessor copsProcessor; + DBG("Get network info & select APN from DB"); + ret = m_at.execute("AT+COPS=,2;+COPS?", &copsProcessor, &result); //Configure to get operator's info in numeric code & get operator's id + DBG("Result of command: Err code=%d", ret); + DBG("ATResult: AT return=%d (code %d)", result.result, result.code); + + if(!copsProcessor.isValid()) + { + WARN("Connected to an unknown network, try to connect with default parameters"); + DBG("Connected with %s", copsProcessor.getBearer()); + } + else + { + DBG("Connected to %s with %s", copsProcessor.getNetwork(), copsProcessor.getBearer()); + char cmd[48]; + sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", copsProcessor.getAPN()); + 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", copsProcessor.getAPN()); + } + #else + 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); + } + #endif + + + //Connect + DBG("Connecting"); + ret = m_at.executeSimple("ATDT *99#", &result); + DBG("Result of command: Err code=%d", ret); + DBG("ATResult: AT return=%d (code %d)", result.result, result.code); + m_at.close(); // Closing AT parser + m_atOpen = false; //Will need to be reinitialized afterwards + + DBG("AT Parser closed"); + if( (ret!=NET_MOREINFO) || (result.result != ATCommandsInterface::ATResult::AT_CONNECT)) + { + ERR("Could not connect"); + return ret; //Could not connect + } + DBG("Connecting PPP"); + + ret = m_ppp.connect(); + DBG("Result of connect: Err code=%d", ret); + return ret; +} + + +int VodafoneK3770::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); + + ATCommandsInterface::ATResult result; + DBG("Starting AT thread"); + ret = m_at.open(); + if(ret) + { + return ret; + } + + 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 + + //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; + } + + m_at.close(); // Closing AT parser + DBG("AT Parser closed"); + return OK; +} + +int VodafoneK3770::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 VodafoneK3770::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 VodafoneK3770::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; +} + +int VodafoneK3770::sendUSSD(const char* command, char* result, size_t maxLength) +{ + int ret = init(); + if(ret) + { + return ret; + } + + if(!m_ussdInit) + { + ret = m_ussd.init(); + if(ret) + { + return ret; + } + m_ussdInit = true; + } + + ret = m_ussd.send(command, result, maxLength); + if(ret) + { + return ret; + } + + return OK; +} + +ATCommandsInterface* VodafoneK3770::getATCommandsInterface() +{ + return &m_at; +} + +int VodafoneK3770::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; + } + + DBG("Configuring unsolicited result codes support properly"); + //Configuring port + ret = m_at.executeSimple("AT^CURC=0;^PORTSEL=1", NULL); //Huawei-specific, not 3GPP-compliant + if(ret != OK) + { + return NET_PROTOCOL; + } + + 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/VodafoneK3770.h Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,118 @@ +/* VodafoneK3770.h */ +/* +Copyright (C) 2012 ARM Limited. + +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 VODAFONEK3770_H_ +#define VODAFONEK3770_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" +#include "ussd/USSDInterface.h" + +/** Vodafone K3770 dongle + */ +class VodafoneK3770 +{ +public: + /** Create Vodafone K3770 dongle API instance + + */ + VodafoneK3770(); + + //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); + + /** Send a USSD command & wait for its result + @param command The command to send + @param result Buffer in which to store the result + @param maxLength Maximum result length that can be stored in buffer (including null-terminating character) + @return 0 on success, error code on failure + */ + int sendUSSD(const char* command, char* result, size_t maxLength); + + /** 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; + USSDInterface m_ussd; + + PPPIPInterface m_ppp; + + bool m_dongleConnected; + bool m_ipInit; + bool m_smsInit; + bool m_ussdInit; + bool m_atOpen; +}; + + +#endif /* VODAFONEK3770_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/at/ATCommandsInterface.cpp Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,806 @@ +/* ATCommandsInterface.cpp */ +/* +Copyright (C) 2012 ARM Limited. + +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 Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,146 @@ +/* ATCommandsInterface.h */ +/* +Copyright (C) 2012 ARM Limited. + +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 8 + +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_ */
--- a/contrib/vodafone/if/VodafoneK3770.cpp Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,474 +0,0 @@ -/* VodafoneK3770.cpp */ -/* -Copyright (C) 2012 ARM Limited. - -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__ 4 -#ifndef __MODULE__ -#define __MODULE__ "VodafoneK3770.cpp" -#endif - -#include "core/fwk.h" - -#include "VodafoneK3770.h" - -VodafoneK3770::VodafoneK3770() : m_dongle(), -m_stream(m_dongle), m_at(&m_stream), -m_ppp(&m_stream), m_sms(&m_at), m_ussd(&m_at), -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; -}; - -class COPSProcessor : public IATCommandsProcessor -{ -public: - COPSProcessor() : valid(false) - { - network[0] = '\0'; - apn[0] = '\0'; - bearer[0] = '\0'; - } - char* getNetwork() - { - return network; - } - char* getAPN() - { - return apn; - } - char* getBearer() - { - return bearer; - } - bool isValid() - { - return valid; - } -private: - virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) - { - int networkId; - int bearerId; - int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId); - if( s == 2 ) - { - switch(networkId) - { - case 23415: - strcpy(network, "Vodafone UK"); - strcpy(apn, "pp.vodafone.co.uk"); - valid = true; - break; - case 20810: - strcpy(network, "SFR FR"); - strcpy(apn, "websfr"); - valid = true; - break; - default: - break; - } - } - else - { - return OK; - } - switch(bearerId) - { - case 0: strcpy(bearer, "GSM"); break; - case 1: strcpy(bearer, "GSM Compact"); break; - case 2: strcpy(bearer, "UTRAN"); break; - case 3: strcpy(bearer, "GSM w/EGPRS"); break; - case 4: strcpy(bearer, "UTRAN w/HSDPA"); break; - case 5: strcpy(bearer, "UTRAN w/HSUPA"); break; - case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break; - case 7: strcpy(bearer, "E-UTRAN"); break; - - default: - break; - } - return OK; - } - virtual int onNewEntryPrompt(ATCommandsInterface* pInst) - { - return OK; - } - char network[24]; - char bearer[24]; - char apn[24]; - volatile bool valid; -}; - - -int VodafoneK3770::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; - } - - m_smsInit = false; //SMS status reset - m_ussdInit = false; //USSD status reset - - ATCommandsInterface::ATResult result; - -#if 0 - //Get network info & select corresponding APN - COPSProcessor copsProcessor; - DBG("Get network info & select APN from DB"); - ret = m_at.execute("AT+COPS=,2;+COPS?", &copsProcessor, &result); //Configure to get operator's info in numeric code & get operator's id - DBG("Result of command: Err code=%d", ret); - DBG("ATResult: AT return=%d (code %d)", result.result, result.code); - - if(!copsProcessor.isValid()) - { - WARN("Connected to an unknown network, try to connect with default parameters"); - DBG("Connected with %s", copsProcessor.getBearer()); - } - else - { - DBG("Connected to %s with %s", copsProcessor.getNetwork(), copsProcessor.getBearer()); - char cmd[48]; - sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", copsProcessor.getAPN()); - 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", copsProcessor.getAPN()); - } - #else - 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); - } - #endif - - - //Connect - DBG("Connecting"); - ret = m_at.executeSimple("ATDT *99#", &result); - DBG("Result of command: Err code=%d", ret); - DBG("ATResult: AT return=%d (code %d)", result.result, result.code); - m_at.close(); // Closing AT parser - m_atOpen = false; //Will need to be reinitialized afterwards - - DBG("AT Parser closed"); - if( (ret!=NET_MOREINFO) || (result.result != ATCommandsInterface::ATResult::AT_CONNECT)) - { - ERR("Could not connect"); - return ret; //Could not connect - } - DBG("Connecting PPP"); - - ret = m_ppp.connect(); - DBG("Result of connect: Err code=%d", ret); - return ret; -} - - -int VodafoneK3770::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); - - ATCommandsInterface::ATResult result; - DBG("Starting AT thread"); - ret = m_at.open(); - if(ret) - { - return ret; - } - - 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 - - //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; - } - - m_at.close(); // Closing AT parser - DBG("AT Parser closed"); - return OK; -} - -int VodafoneK3770::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 VodafoneK3770::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 VodafoneK3770::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; -} - -int VodafoneK3770::sendUSSD(const char* command, char* result, size_t maxLength) -{ - int ret = init(); - if(ret) - { - return ret; - } - - if(!m_ussdInit) - { - ret = m_ussd.init(); - if(ret) - { - return ret; - } - m_ussdInit = true; - } - - ret = m_ussd.send(command, result, maxLength); - if(ret) - { - return ret; - } - - return OK; -} - -ATCommandsInterface* VodafoneK3770::getATCommandsInterface() -{ - return &m_at; -} - -int VodafoneK3770::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; - } - - DBG("Configuring unsolicited result codes support properly"); - //Configuring port - ret = m_at.executeSimple("AT^CURC=0;^PORTSEL=1", NULL); //Huawei-specific, not 3GPP-compliant - if(ret != OK) - { - return NET_PROTOCOL; - } - - 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; -} - - -
--- a/contrib/vodafone/if/VodafoneK3770.h Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/* VodafoneK3770.h */ -/* -Copyright (C) 2012 ARM Limited. - -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 VODAFONEK3770_H_ -#define VODAFONEK3770_H_ - -#include "core/fwk.h" - -#include "USB3GModule/WANDongle.h" -#include "drv/at/ATCommandsInterface.h" -#include "drv/serial/usb/USBSerialStream.h" -#include "if/ip/PPPIPInterface.h" -#include "if/sms/SMSInterface.h" -#include "if/ussd/USSDInterface.h" - -/** Vodafone K3770 dongle - */ -class VodafoneK3770 -{ -public: - /** Create Vodafone K3770 dongle API instance - - */ - VodafoneK3770(); - - //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); - - /** Send a USSD command & wait for its result - @param command The command to send - @param result Buffer in which to store the result - @param maxLength Maximum result length that can be stored in buffer (including null-terminating character) - @return 0 on success, error code on failure - */ - int sendUSSD(const char* command, char* result, size_t maxLength); - - /** Get the ATCommandsInterface instance - @return Pointer to the ATCommandsInterface instance - */ - ATCommandsInterface* getATCommandsInterface(); - -protected: - int init(); - -private: - WANDongle m_dongle; - USBSerialStream m_stream; - ATCommandsInterface m_at; - PPPIPInterface m_ppp; - SMSInterface m_sms; - USSDInterface m_ussd; - - bool m_dongleConnected; - bool m_ipInit; - bool m_smsInit; - bool m_ussdInit; - bool m_atOpen; -}; - - -#endif /* VODAFONEK3770_H_ */
--- a/contrib/vodafone/if/vodafone/VodafoneManager.h Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -/* - * VodafoneManager.h - * - * Created on: 16 déc. 2011 - * Author: Donatien - */ - -#ifndef VODAFONEMANAGER_H_ -#define VODAFONEMANAGER_H_ - -#include "core/fwk.h" -#include "if/ussd/USSDInterface.h" - -class VodafoneManager : protected USSDInterface -{ - - -}; - -#endif /* VODAFONEMANAGER_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ip/PPPIPInterface.cpp Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,269 @@ +/* PPPIPInterface.cpp */ +/* +Copyright (C) 2012 ARM Limited. + +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 //Maximum verbosity +#ifndef __MODULE__ +#define __MODULE__ "PPPIPInterface.cpp" +#endif + +#include "core/fwk.h" +#include "rtos.h" + +#include "PPPIPInterface.h" + +extern "C" { +#include "lwip/ip_addr.h" +#include "lwip/inet.h" +#include "netif/ppp/ppp.h" +} + +#if NET_PPP + +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() +{ + DBG("Trying to connect with PPP"); + m_linkStatusSphre.wait(0); + if((m_pppd != -1) && (m_pppErrCode == 0)) //Already connected + { + return NET_INVALID; + } + int 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 + } + 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)); + setConnected(true); + setIPAddress(inet_ntoa(addrs->our_ipaddr)); + break; + case PPPERR_CONNECT: //Connection lost + WARN("Connection lost/terminated"); + setConnected(false); + break; + case PPPERR_AUTHFAIL: //Authentication failed + WARN("Authentication failed"); + setConnected(false); + break; + case PPPERR_PROTOCOL: //Protocol error + WARN("Protocol error"); + setConnected(false); + break; + case PPPERR_USER: + WARN("Disconnected by user"); + setConnected(false); + break; + default: + WARN("Unknown error (%d)", errCode); + 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"); +} + +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ip/PPPIPInterface.h Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,67 @@ +/* PPPIPInterface.h */ +/* +Copyright (C) 2012 ARM Limited. + +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: + 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/lwipopts.h Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,45 @@ +/* lwipopts.h */ +/* + Copyright (C) 2012 ARM Limited. + + 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_H_ +#define LWIPOPTS_H_ + +#include "lwipopts_common.h" //Get common options + +///PPP Options + +#define TCP_SND_BUF (3 * 536) +#define TCP_WND (2 * 536) + +#define LWIP_ARP 0 + +#define PPP_SUPPORT 1 +#define CHAP_SUPPORT 1 +#define PAP_SUPPORT 1 +#define PPP_THREAD_STACKSIZE 4*192 +#define PPP_THREAD_PRIO 0 + +#define MAXNAMELEN 64 /* max length of hostname or name for auth */ +#define MAXSECRETLEN 64 + +#endif /* LWIPOPTS_H_ */ \ No newline at end of file
--- a/main/drv/at/ATCommandsInterface.cpp Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,806 +0,0 @@ -/* ATCommandsInterface.cpp */ -/* -Copyright (C) 2012 ARM Limited. - -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"); - } -} -
--- a/main/drv/at/ATCommandsInterface.h Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,146 +0,0 @@ -/* ATCommandsInterface.h */ -/* -Copyright (C) 2012 ARM Limited. - -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 8 - -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_ */
--- a/main/drv/serial/io/IOSerialStream.cpp Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -/* IOSerialStream.cpp */ -/* -Copyright (C) 2012 ARM Limited. - -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"); - 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"); - 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"); - 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 -}
--- a/main/drv/serial/io/IOSerialStream.h Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* IOSerialStream.h */ -/* -Copyright (C) 2012 ARM Limited. - -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_ */
--- a/main/drv/serial/usb/USBSerialStream.cpp Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,237 +0,0 @@ -/* USBSerialStream.cpp */ -/* -Copyright (C) 2012 ARM Limited. - -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 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 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? - { - 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(!m_inBuf.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 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"); - return ret; - } - int writeLen = MIN( space(), length ); - DBG("Writing %d chars", length); - setupWriteableISR(false); - while(writeLen) - { - m_outBuf.queue(*buf); - buf++; - length--; - writeLen--; - } - setupWriteableISR(true); - } while(length); - //If m_serial tx fifo is empty we need to start the packet write - setupWriteableISR(false); - if( m_outBuf.available() && m_serialTxFifoEmpty ) - { - writeable(); - } - setupWriteableISR(true); - 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? - { - 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 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); - } - static volatile int i=0; - m_serial.writePacket(); //Start packet write - } - m_spaceSphre.release(); //Force exiting the waiting state -}
--- a/main/drv/serial/usb/USBSerialStream.h Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* USBSerialStream.h */ -/* -Copyright (C) 2011 ARM Limited. - -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 255 -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_ */
--- a/main/if/ip/PPPIPInterface.cpp Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,262 +0,0 @@ -/* PPPIPInterface.cpp */ -/* -Copyright (C) 2012 ARM Limited. - -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 //Maximum verbosity -#ifndef __MODULE__ -#define __MODULE__ "PPPIPInterface.cpp" -#endif - -#include "core/fwk.h" -#include "rtos.h" - -#include "PPPIPInterface.h" - -extern "C" { -#include "lwip/ip_addr.h" -#include "lwip/inet.h" -#include "netif/ppp/ppp.h" -} - -#if NET_PPP - -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() -{ - DBG("Trying to connect with PPP"); - m_linkStatusSphre.wait(0); - if((m_pppd != -1) && (m_pppErrCode == 0)) //Already connected - { - return NET_INVALID; - } - int 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 - } - 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)); - break; - case PPPERR_CONNECT: //Connection lost - WARN("Connection lost/terminated"); - break; - case PPPERR_AUTHFAIL: //Authentication failed - WARN("Authentication failed"); - break; - case PPPERR_PROTOCOL: //Protocol error - WARN("Protocol error"); - break; - case PPPERR_USER: - WARN("Disconnected by user"); - break; - default: - WARN("Unknown error (%d)", errCode); - 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"); -} - -} - -#endif -
--- a/main/if/ip/PPPIPInterface.h Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* PPPIPInterface.h */ -/* -Copyright (C) 2012 ARM Limited. - -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(); - - virtual 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: - 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_ */
--- a/main/if/sms/SMSInterface.cpp Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,390 +0,0 @@ -/* SMSInterface.cpp */ -/* -Copyright (C) 2012 ARM Limited. - -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__ 4 -#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; -} - -
--- a/main/if/sms/SMSInterface.h Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* SMSInterface.h */ -/* -Copyright (C) 2012 ARM Limited. - -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 "drv/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_ */
--- a/main/if/ussd/USSDInterface.cpp Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -/* USSDInterface.cpp */ -/* -Copyright (C) 2012 ARM Limited. - -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__ 4 -#ifndef __MODULE__ -#define __MODULE__ "USSDInterface.cpp" -#endif - -#include "core/fwk.h" - -#include "USSDInterface.h" - -#include <cstdio> - -#define DEFAULT_TIMEOUT 10000 -#define USSD_TIMEOUT 15000 - -USSDInterface::USSDInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_responseMtx(), m_responseSphre(1), m_result(NULL), m_maxResultLength(0) -{ - m_responseSphre.wait(0); //Take ownership of the semaphore - m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers -} - -int USSDInterface::init() -{ - DBG("Initialization done"); - return OK; -} - -int USSDInterface::send(const char* command, char* result, size_t maxLength) -{ - if (strlen(command) > 20) //Prevent buffer overflow - { - return NET_TOOSMALL; - } - - m_responseMtx.lock(); - m_result = result; - m_maxResultLength = maxLength; - m_responseMtx.unlock(); - - m_responseSphre.wait(0); //Make sure there is not a pending result that needs to be discarded - - DBG("Send USSD command & register for unsolicited result codes"); - //Send USSD command to the network - char cmd[32]; - std::sprintf(cmd, "AT+CUSD=1,\"%s\"", command); - int ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT); - if( ret != OK ) - { - return NET_PROTOCOL; - } - - //Now wait for response - int res = m_responseSphre.wait(USSD_TIMEOUT); - - //Reset data - m_responseMtx.lock(); - m_result = NULL; - m_maxResultLength = 0; - m_responseMtx.unlock(); - - if(res <= 0) - { - DBG("No result received"); - ret = m_pIf->executeSimple("AT+CUSD=2", NULL, DEFAULT_TIMEOUT); //Cancel command - if( ret != OK ) - { - return NET_PROTOCOL; - } - return NET_TIMEOUT; - } - - DBG("Result received: %s", result); - - return OK; - -} - -/*virtual*/ bool USSDInterface::isATCodeHandled(const char* atCode) //Is this AT code handled -{ - DBG("AT code is %s", atCode); - if( strcmp("+CUSD", atCode) == 0 ) - { - return true; - } - - DBG("Not handled"); - return false; -} - -/*virtual*/ void USSDInterface::onDispatchStart() -{ - - -} - -/*virtual*/ void USSDInterface::onDispatchStop() -{ - -} - -/*virtual*/ void USSDInterface::onEvent(const char* atCode, const char* evt) -{ - if( strcmp("+CUSD", atCode) != 0 ) - { - return; //Not supported - } - - char* pStart = (char*) strchr(evt,'\"'); - if(pStart==NULL) - { - return; //Invalid/incomplete response - } - pStart++; //Point to first char of response - char* pEnd = (char*) strchr(pStart,'\"'); - if(pEnd==NULL) - { - return; //Invalid/incomplete response - } - m_responseMtx.lock(); - if(m_maxResultLength == 0) //No pending command - { - m_responseMtx.unlock(); - return; - } - size_t cpyLen = MIN( pEnd - pStart, m_maxResultLength - 1 ); - memcpy(m_result, pStart, cpyLen); - m_result[cpyLen] = '\0'; - m_responseMtx.unlock(); - m_responseSphre.release(); //Signal user thread that response is ready -}
--- a/main/if/ussd/USSDInterface.h Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* USSDInterface.h */ -/* -Copyright (C) 2012 ARM Limited. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#ifndef USSDINTERFACE_H_ -#define USSDINTERFACE_H_ - -#include "core/fwk.h" - -#include "rtos.h" - -#include "drv/at/ATCommandsInterface.h" - -/** Component to send/receive Unstructured Supplementary Service Data (USSD) - * - */ -class USSDInterface : protected IATEventsHandler -{ -public: - /** Create USSDInterface instance - @param pIf Pointer to the ATCommandsInterface instance to use - */ - USSDInterface(ATCommandsInterface* pIf); - - /** Initialize interface - Configure USSD commands & register for USSD-related unsolicited result codes - */ - int init(); - - /** Send a USSD command & wait for its result - @param command The command to send - @param result Buffer in which to store the result - @param maxLength Maximum result length that can be stored in buffer (including null-terminating character) - @return 0 on success, error code on failure - */ - int send(const char* command, char* result, size_t maxLength); - -protected: - //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); - -private: - ATCommandsInterface* m_pIf; - Mutex m_responseMtx; //To protect concurrent accesses btw the user's thread and the AT thread - Semaphore m_responseSphre; - - //Result - char* m_result; - size_t m_maxResultLength; - -}; - - -#endif /* USSDINTERFACE_H_ */
--- a/main/lwipopts.h Fri Jun 08 13:30:06 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* lwipopts.h */ -/* - Copyright (C) 2012 ARM Limited. - - 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_H_ -#define LWIPOPTS_H_ - -#include "lwipopts_common.h" //Get common options - -///PPP Options - -#define TCP_SND_BUF (3 * 536) -#define TCP_WND (2 * 536) - -#define LWIP_ARP 0 - -#define PPP_SUPPORT 1 -#define CHAP_SUPPORT 1 -#define PAP_SUPPORT 1 -#define PPP_THREAD_STACKSIZE 4*192 -#define PPP_THREAD_PRIO 0 - -#define MAXNAMELEN 64 /* max length of hostname or name for auth */ -#define MAXSECRETLEN 64 - -#endif /* LWIPOPTS_H_ */ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/serial/io/IOSerialStream.cpp Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,257 @@ +/* IOSerialStream.cpp */ +/* +Copyright (C) 2012 ARM Limited. + +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"); + 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"); + 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"); + 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 Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,77 @@ +/* IOSerialStream.h */ +/* +Copyright (C) 2012 ARM Limited. + +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 Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,237 @@ +/* USBSerialStream.cpp */ +/* +Copyright (C) 2012 ARM Limited. + +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 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 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? + { + 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(!m_inBuf.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 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"); + return ret; + } + int writeLen = MIN( space(), length ); + DBG("Writing %d chars", length); + setupWriteableISR(false); + while(writeLen) + { + m_outBuf.queue(*buf); + buf++; + length--; + writeLen--; + } + setupWriteableISR(true); + } while(length); + //If m_serial tx fifo is empty we need to start the packet write + setupWriteableISR(false); + if( m_outBuf.available() && m_serialTxFifoEmpty ) + { + writeable(); + } + setupWriteableISR(true); + 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? + { + 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 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); + } + static volatile int i=0; + m_serial.writePacket(); //Start packet write + } + m_spaceSphre.release(); //Force exiting the waiting state +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/serial/usb/USBSerialStream.h Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,77 @@ +/* USBSerialStream.h */ +/* +Copyright (C) 2011 ARM Limited. + +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 255 +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 Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,390 @@ +/* SMSInterface.cpp */ +/* +Copyright (C) 2012 ARM Limited. + +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__ 4 +#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 Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,105 @@ +/* SMSInterface.h */ +/* +Copyright (C) 2012 ARM Limited. + +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 "drv/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/ussd/USSDInterface.cpp Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,152 @@ +/* USSDInterface.cpp */ +/* +Copyright (C) 2012 ARM Limited. + +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__ 4 +#ifndef __MODULE__ +#define __MODULE__ "USSDInterface.cpp" +#endif + +#include "core/fwk.h" + +#include "USSDInterface.h" + +#include <cstdio> + +#define DEFAULT_TIMEOUT 10000 +#define USSD_TIMEOUT 15000 + +USSDInterface::USSDInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_responseMtx(), m_responseSphre(1), m_result(NULL), m_maxResultLength(0) +{ + m_responseSphre.wait(0); //Take ownership of the semaphore + m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers +} + +int USSDInterface::init() +{ + DBG("Initialization done"); + return OK; +} + +int USSDInterface::send(const char* command, char* result, size_t maxLength) +{ + if (strlen(command) > 20) //Prevent buffer overflow + { + return NET_TOOSMALL; + } + + m_responseMtx.lock(); + m_result = result; + m_maxResultLength = maxLength; + m_responseMtx.unlock(); + + m_responseSphre.wait(0); //Make sure there is not a pending result that needs to be discarded + + DBG("Send USSD command & register for unsolicited result codes"); + //Send USSD command to the network + char cmd[32]; + std::sprintf(cmd, "AT+CUSD=1,\"%s\"", command); + int ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT); + if( ret != OK ) + { + return NET_PROTOCOL; + } + + //Now wait for response + int res = m_responseSphre.wait(USSD_TIMEOUT); + + //Reset data + m_responseMtx.lock(); + m_result = NULL; + m_maxResultLength = 0; + m_responseMtx.unlock(); + + if(res <= 0) + { + DBG("No result received"); + ret = m_pIf->executeSimple("AT+CUSD=2", NULL, DEFAULT_TIMEOUT); //Cancel command + if( ret != OK ) + { + return NET_PROTOCOL; + } + return NET_TIMEOUT; + } + + DBG("Result received: %s", result); + + return OK; + +} + +/*virtual*/ bool USSDInterface::isATCodeHandled(const char* atCode) //Is this AT code handled +{ + DBG("AT code is %s", atCode); + if( strcmp("+CUSD", atCode) == 0 ) + { + return true; + } + + DBG("Not handled"); + return false; +} + +/*virtual*/ void USSDInterface::onDispatchStart() +{ + + +} + +/*virtual*/ void USSDInterface::onDispatchStop() +{ + +} + +/*virtual*/ void USSDInterface::onEvent(const char* atCode, const char* evt) +{ + if( strcmp("+CUSD", atCode) != 0 ) + { + return; //Not supported + } + + char* pStart = (char*) strchr(evt,'\"'); + if(pStart==NULL) + { + return; //Invalid/incomplete response + } + pStart++; //Point to first char of response + char* pEnd = (char*) strchr(pStart,'\"'); + if(pEnd==NULL) + { + return; //Invalid/incomplete response + } + m_responseMtx.lock(); + if(m_maxResultLength == 0) //No pending command + { + m_responseMtx.unlock(); + return; + } + size_t cpyLen = MIN( pEnd - pStart, m_maxResultLength - 1 ); + memcpy(m_result, pStart, cpyLen); + m_result[cpyLen] = '\0'; + m_responseMtx.unlock(); + m_responseSphre.release(); //Signal user thread that response is ready +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ussd/USSDInterface.h Tue Jun 26 13:44:59 2012 +0000 @@ -0,0 +1,76 @@ +/* USSDInterface.h */ +/* +Copyright (C) 2012 ARM Limited. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef USSDINTERFACE_H_ +#define USSDINTERFACE_H_ + +#include "core/fwk.h" + +#include "rtos.h" + +#include "drv/at/ATCommandsInterface.h" + +/** Component to send/receive Unstructured Supplementary Service Data (USSD) + * + */ +class USSDInterface : protected IATEventsHandler +{ +public: + /** Create USSDInterface instance + @param pIf Pointer to the ATCommandsInterface instance to use + */ + USSDInterface(ATCommandsInterface* pIf); + + /** Initialize interface + Configure USSD commands & register for USSD-related unsolicited result codes + */ + int init(); + + /** Send a USSD command & wait for its result + @param command The command to send + @param result Buffer in which to store the result + @param maxLength Maximum result length that can be stored in buffer (including null-terminating character) + @return 0 on success, error code on failure + */ + int send(const char* command, char* result, size_t maxLength); + +protected: + //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); + +private: + ATCommandsInterface* m_pIf; + Mutex m_responseMtx; //To protect concurrent accesses btw the user's thread and the AT thread + Semaphore m_responseSphre; + + //Result + char* m_result; + size_t m_maxResultLength; + +}; + + +#endif /* USSDINTERFACE_H_ */