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 0:3b2f052c333b, committed 2012-05-24
- Comitter:
- donatien
- Date:
- Thu May 24 16:40:40 2012 +0000
- Child:
- 1:e20fc9aeb62e
- Commit message:
- Initial Commit
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostWANDongleLib.lib Thu May 24 16:40:40 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/donatien/code/USBHostWANDongleLib/#ae46a0638b2c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/vodafone/if/VodafoneK3770.cpp Thu May 24 16:40:40 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_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;
+}
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/vodafone/if/VodafoneK3770.h Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,113 @@
+/* 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/vodafone/if/vodafone/VodafoneManager.h Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,20 @@
+/*
+ * 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/main/drv/at/ATCommandsInterface.cpp Thu May 24 16:40:40 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/main/drv/at/ATCommandsInterface.h Thu May 24 16:40:40 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main/drv/serial/io/IOSerialStream.cpp Thu May 24 16:40:40 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/main/drv/serial/io/IOSerialStream.h Thu May 24 16:40:40 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/main/drv/serial/usb/USBSerialStream.cpp Thu May 24 16:40:40 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/main/drv/serial/usb/USBSerialStream.h Thu May 24 16:40:40 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/main/if/info/DongleDeviceInfo.h Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,19 @@
+/*
+ * DongleDeviceInfo.h
+ *
+ * Created on: 16 déc. 2011
+ * Author: Donatien
+ */
+
+#ifndef DONGLEDEVICEINFO_H_
+#define DONGLEDEVICEINFO_H_
+
+#include "core/fwk.h"
+#include "drv/modemtransport/ModemTransport.h"
+
+class DongleDeviceInfo : protected ModemTransportUser
+{
+
+};
+
+#endif /* DONGLEDEVICEINFO_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main/if/ip/PPPIPInterface.cpp Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,262 @@
+/* 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
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main/if/ip/PPPIPInterface.h Thu May 24 16:40:40 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();
+
+ 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main/if/sms/SMSInterface.cpp Thu May 24 16:40:40 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/main/if/sms/SMSInterface.h Thu May 24 16:40:40 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/main/if/ussd/USSDInterface.cpp Thu May 24 16:40:40 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/main/if/ussd/USSDInterface.h Thu May 24 16:40:40 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_ */
