Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: Socket USBHostWANDongle lwip-sys lwip
Fork of VodafoneUSBModem by
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_ */
