Example of AWS IoT connection and Web Dashboard thru STM32 Nucleo evaluation board and mbed OS.
Dependencies: X_NUCLEO_IKS01A1 mbed FP MQTTPacket DnsQuery ATParser
Introduction
The demo is aimed to STM32 Nucleo board with WiFi and sensors expansions. The board is a "thing" for the AWS IoT service. It updates IoT service shadow with sensors data every second and checks subscription messages.
Hardware Configuration
- NUCLEO-F401RE - Nucleo Development Board
- X-NUCLEO-IDW01M1 - Wi-Fi expansion board for STM32 Nucleo
- X-NUCLEO-IKS01A1 - Motion MEMS and environmental sensor expansion board for STM32 Nucleo
Software Configuration
- Import this Project to mbed online compiler
- Find the next part of code in main.cpp file ...
WiFi network credential
#include "mbed.h" // WiFi network credential #define SSID "" // Network must be visible otherwise it can't connect #define PASSW "" #error "Wifi SSID & password empty"
- ... And set it to your Network Name and Password. Do not forget to remove "#error" pragma line.
Information
Nucleo WiFi module is not the same as your smartphone or laptope - it is based on demo board. To avoid connection problems:
- Place Nucleo as close to WiFi hot spot as possible. Or...
- Turn on mobile hot spot in your laptop as close to the device as possible.
- Make sure that hot spot permits 2.4 GHz band communications
- Setup BackEnd and store certificates using this backend setup instruction
- Find AWS_IOT_MQTT_HOST define and change it to HTTPS point mentioned in your AWS IoT thing properties named "interact"
#define AWS_IOT_MQTT_HOST "xxxxxxxxxx.iot.us-east-1.amazonaws.com" //Use your own host.
- Find the certificate defines clientCRT and clientKey in main.cpp file and change it to ones provided by Amazon.
/********************************************************************************************** *********************************************************************************************** Device Identity Certificates: Modify for your AWS IoT Thing *********************************************************************************************** ***********************************************************************************************/ /**************************************** (somecode)-certificate.pem.crt - Amazon signed PEM sertificate. *****************************************/ //This Client cert is example. Use own instead. const uint8_t clientCRT[] = "\ -----BEGIN CERTIFICATE-----\n\ MIIDBjCCAe6gAwIBAgIUVph856omeIxW3UPioq+UrX1DbwowDQYJKoZIhvcNAQEL\ BQAwTTFLMEkGA1UECwxCQW1hem9uIFdlYiBTZXJ2aWNlcyBPPUFtYXpvbi5jb20g\ SW5jLiBMPVNlYXR0bGUgU1Q9V2FzaGluZ3RvbiBDPVVTMB4XDTE3MDUyNTExNTEy\ OVoXDTQ5MTIzMTIzNTk1OVowgZUxCzAJBgNVBAYTAkJZMQ4wDAYDVQQIDAVNaW5z\ azEOMAwGA1UEBwwFTWluc2sxFzAVBgNVBAoMDktsaWthLVRlY2ggTExDMRcwFQYD\ VQQLDA5LbGlrYS1UZWNoIExMQzEMMAoGA1UEAwwDUm5EMSYwJAYJKoZIhvcNAQkB\ FhdtdmF0YWxldUBrbGlrYS10ZWNoLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH\ A0IABCJgOQJmoTBJVPfli9Hm/JVixaxkY5rtlgrYO3hSl633A2hg0P/ue0wXDbF3\ aQ0X57IRFE4k4FEbr3UXjT/IczKjYDBeMB8GA1UdIwQYMBaAFK3YzTUPlYB2Li75\ i/z8rEogr1d6MB0GA1UdDgQWBBT18HXBaXFJuAR/0SwegnxJ+pyJ6TAMBgNVHRMB\ Af8EAjAAMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAb0Ux1aH5\ RLxjrfGqXN6rPVqh8QQRS+AyBfzmaQN8HaPZMkX5WxXLvcn0A3uWlwQxPPkcZ4zf\ 51GHtFFQWB4YZ8dx8mUQ0v/j7onHjCJgZ8iDgwOyKMGtnsDZWCakQw+a6cj+NrMZ\ tzhjwCzEEP6ePcbXwErI5OOzLuWns2L/JEr2wWNkokgRuS8ewr/SQ9OLWIWa2rFM\ ahPNTb3y/qBeWdjeJmhI+TOxdqIpsF8roWP25zwo/zkzCHCjXFBrL+0CA4MpxIl9\ x02i7aAhlJ6ys80lDxdeWeeQJXRKkGknP8mcmKn3iEqqJ5s1dQePj2b5d3ldatya\ wsxQBqqZXzIWEw==\ \n\ -----END CERTIFICATE-----\n"; /********************************************************************************************** *********************************************************************************************** Private Key: Modify for your AWS IoT Thing *********************************************************************************************** ***********************************************************************************************/ /********************************************************************8**************************************** nucleo.key.pem - client key generated according to readme. **************************************************************************************************************/ //This Client Key is example. Use own instead. const uint8_t clientKey[] ="\ -----BEGIN EC PARAMETERS-----\n\ BggqhkjOPQMBBw==\ -----END EC PARAMETERS-----\n\ -----BEGIN EC PRIVATE KEY-----\n\ MHcCAQEEIHPRfWSC8/k/BsqDWKuP15dXsI9fGwpkTIsLZe6mIrAAoAoGCCqGSM49\ AwEHoUQDQgAEImA5AmahMElU9+WL0eb8lWLFrGRjmu2WCtg7eFKXrfcDaGDQ/+57\ TBcNsXdpDRfnshEUTiTgURuvdReNP8hzMg==\ -----END EC PRIVATE KEY-----\n";
Build and Check
- Plugin your board to USB of your PC. USB Disk Drive and USB COM Port should appear in your system.
- Open any Serial Console, connect it to your USB Serial Port and setup speed equal to 115200.
- Compile this Project and save .bin file to USB Disk Drive
- After board reset you should see next log in serial console:
X-NUCLEO-IDW01M1 mbed Application
connecting to AP
LOG: int main() L#361 Connected to WiFI.
LOG: int connect(MQTT::Client<MQTTWiFi, Countdown, 350, 5> *, MQTTWiFi *) L#186 =====================================
LOG: int connect(MQTT::Client<MQTTWiFi, Countdown, 350, 5> *, MQTTWiFi *) L#187 Connecting WiFi.
LOG: int connect(MQTT::Client<MQTTWiFi, Countdown, 350, 5> *, MQTTWiFi *) L#188 Nucleo IP ADDRESS: X.X.X.X
LOG: int connect(MQTT::Client<MQTTWiFi, Countdown, 350, 5> *, MQTTWiFi *) L#189 Nucleo MAC ADDRESS: 00:11:22:33:44:55
LOG: int connect(MQTT::Client<MQTTWiFi, Countdown, 350, 5> *, MQTTWiFi *) L#190 Server Hostname: xxxxxxxx.iot.us-east-1.amazonaws.com port: 8883
LOG: int connect(MQTT::Client<MQTTWiFi, Countdown, 350, 5> *, MQTTWiFi *) L#191 Client ID: Nucleo
LOG: int connect(MQTT::Client<MQTTWiFi, Countdown, 350, 5> *, MQTTWiFi *) L#194 =====================================
LOG: int MQTTSocket::getNTPtime(int) L#58 Success receiving time from ntp server. Tick from 1 Jan 1970 is equal to 1505399292.
--->TCP Connected
--->MQTT Connected
--->>>MQTT subscribed to: Nucleo/test
Length - 245, Publishing {"state": {"reported": {"temperature": 23.690001, "humidity": 98.190002, "pressure": 982.869141, "accelerometer": [-0.009000, 0.030000, 0.971000], "gyroscope": [0.420000, -2.660000, 1.750000], "magnetometer": [-3.600000, -7.100000, 53.300000]}}}
Length - 245, Publishing {"state": {"reported": {"temperature": 23.660000, "humidity": 98.010002, "pressure": 982.770264, "accelerometer": [-0.009000, 0.030000, 0.971000], "gyroscope": [0.770000, -2.310000, 1.470000], "magnetometer": [-3.100000, -8.300000, 54.200000]}}}
Length - 245, Publishing {"state": {"reported": {"temperature": 23.670000, "humidity": 98.129997, "pressure": 982.724121, "accelerometer": [-0.008000, 0.029000, 0.971000], "gyroscope": [0.630000, -2.380000, 1.400000], "magnetometer": [-3.100000, -7.900000, 53.400000]}}}
Length - 245, Publishing {"state": {"reported": {"temperature": 23.690001, "humidity": 98.019997, "pressure": 982.840088, "accelerometer": [-0.009000, 0.030000, 0.972000], "gyroscope": [0.700000, -2.450000, 1.540000], "magnetometer": [-3.700000, -7.900000, 53.400000]}}}
Length - 245, Publishing {"state": {"reported": {"temperature": 23.709999, "humidity": 98.040001, "pressure": 982.828613, "accelerometer": [-0.009000, 0.030000, 0.971000], "gyroscope": [0.630000, -2.520000, 1.470000], "magnetometer": [-2.900000, -7.400000, 52.400000]}}}
Length - 245, Publishing {"state": {"reported": {"temperature": 23.719999, "humidity": 97.860001, "pressure": 982.917236, "accelerometer": [-0.026000, 0.103000, 0.891000], "gyroscope": [1.050000, -2.310000, 1.260000], "magnetometer": [-3.300000, -7.100000, 53.500000]}}}
Information
Device connection state might be checked by Green Led on the board. Green light means that device is connected and transferring data to cloud.
- Configure and start your dashboard using instruction and corresponding sources from github
- Use Blue button to set up markers to charts.
- Use AWS IoT console MQTT Client to test device subscription to "Nucleo/test". Just publish any message to this topic and serial port output.
- PROFIT!
Revision 0:4cdaf9b1e7d0, committed 2017-09-27
- Comitter:
- PavelSavyhin
- Date:
- Wed Sep 27 14:40:52 2017 +0300
- Child:
- 1:042ca9148926
- Commit message:
- Initial commit
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/FP.lib Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,1 @@ +http://mbed.org/users/sam_grove/code/FP/#3c62ba1807ac
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTT/MQTTAsync.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,607 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTTASYNC_H)
+#define MQTTASYNC_H
+
+#include "FP.h"
+#include "MQTTPacket.h"
+#include "stdio.h"
+
+namespace MQTT
+{
+
+
+enum QoS { QOS0, QOS1, QOS2 };
+
+
+struct Message
+{
+ enum QoS qos;
+ bool retained;
+ bool dup;
+ unsigned short id;
+ void *payload;
+ size_t payloadlen;
+};
+
+
+class PacketId
+{
+public:
+ PacketId();
+
+ int getNext();
+
+private:
+ static const int MAX_PACKET_ID = 65535;
+ int next;
+};
+
+typedef void (*messageHandler)(Message*);
+
+typedef struct limits
+{
+ int MAX_MQTT_PACKET_SIZE; //
+ int MAX_MESSAGE_HANDLERS; // each subscription requires a message handler
+ int MAX_CONCURRENT_OPERATIONS; // each command which runs concurrently can have a result handler, when we are in multi-threaded mode
+ int command_timeout_ms;
+
+ limits()
+ {
+ MAX_MQTT_PACKET_SIZE = 100;
+ MAX_MESSAGE_HANDLERS = 5;
+ MAX_CONCURRENT_OPERATIONS = 1; // 1 indicates single-threaded mode - set to >1 for multithreaded mode
+ command_timeout_ms = 30000;
+ }
+} Limits;
+
+
+/**
+ * @class Async
+ * @brief non-blocking, threaded MQTT client API
+ * @param Network a network class which supports send, receive
+ * @param Timer a timer class with the methods:
+ */
+template<class Network, class Timer, class Thread, class Mutex> class Async
+{
+
+public:
+
+ struct Result
+ {
+ /* success or failure result data */
+ Async<Network, Timer, Thread, Mutex>* client;
+ int rc;
+ };
+
+ typedef void (*resultHandler)(Result*);
+
+ Async(Network* network, const Limits limits = Limits());
+
+ typedef struct
+ {
+ Async* client;
+ Network* network;
+ } connectionLostInfo;
+
+ typedef int (*connectionLostHandlers)(connectionLostInfo*);
+
+ /** Set the connection lost callback - called whenever the connection is lost and we should be connected
+ * @param clh - pointer to the callback function
+ */
+ void setConnectionLostHandler(connectionLostHandlers clh)
+ {
+ connectionLostHandler.attach(clh);
+ }
+
+ /** Set the default message handling callback - used for any message which does not match a subscription message handler
+ * @param mh - pointer to the callback function
+ */
+ void setDefaultMessageHandler(messageHandler mh)
+ {
+ defaultMessageHandler.attach(mh);
+ }
+
+ int connect(resultHandler fn, MQTTPacket_connectData* options = 0);
+
+ template<class T>
+ int connect(void(T::*method)(Result *), MQTTPacket_connectData* options = 0, T *item = 0); // alternative to pass in pointer to member function
+
+ int publish(resultHandler rh, const char* topic, Message* message);
+
+ int subscribe(resultHandler rh, const char* topicFilter, enum QoS qos, messageHandler mh);
+
+ int unsubscribe(resultHandler rh, const char* topicFilter);
+
+ int disconnect(resultHandler rh);
+
+private:
+
+ void run(void const *argument);
+ int cycle(int timeout);
+ int waitfor(int packet_type, Timer& atimer);
+ int keepalive();
+ int findFreeOperation();
+
+ int decodePacket(int* value, int timeout);
+ int readPacket(int timeout);
+ int sendPacket(int length, int timeout);
+ int deliverMessage(MQTTString* topic, Message* message);
+
+ Thread* thread;
+ Network* ipstack;
+
+ Limits limits;
+
+ char* buf;
+ char* readbuf;
+
+ Timer ping_timer, connect_timer;
+ unsigned int keepAliveInterval;
+ bool ping_outstanding;
+
+ PacketId packetid;
+
+ typedef FP<void, Result*> resultHandlerFP;
+ resultHandlerFP connectHandler;
+
+ typedef FP<void, Message*> messageHandlerFP;
+ struct MessageHandlers
+ {
+ const char* topic;
+ messageHandlerFP fp;
+ } *messageHandlers; // Message handlers are indexed by subscription topic
+
+ // how many concurrent operations should we allow? Each one will require a function pointer
+ struct Operations
+ {
+ unsigned short id;
+ resultHandlerFP fp;
+ const char* topic; // if this is a publish, store topic name in case republishing is required
+ Message* message; // for publish,
+ Timer timer; // to check if the command has timed out
+ } *operations; // result handlers are indexed by packet ids
+
+ static void threadfn(void* arg);
+
+ messageHandlerFP defaultMessageHandler;
+
+ typedef FP<int, connectionLostInfo*> connectionLostFP;
+
+ connectionLostFP connectionLostHandler;
+
+};
+
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> void MQTT::Async<Network, Timer, Thread, Mutex>::threadfn(void* arg)
+{
+ ((Async<Network, Timer, Thread, Mutex>*) arg)->run(NULL);
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> MQTT::Async<Network, Timer, Thread, Mutex>::Async(Network* network, Limits limits) : limits(limits), packetid()
+{
+ this->thread = 0;
+ this->ipstack = network;
+ this->ping_timer = Timer();
+ this->ping_outstanding = 0;
+
+ // How to make these memory allocations portable? I was hoping to avoid the heap
+ buf = new char[limits.MAX_MQTT_PACKET_SIZE];
+ readbuf = new char[limits.MAX_MQTT_PACKET_SIZE];
+ this->operations = new struct Operations[limits.MAX_CONCURRENT_OPERATIONS];
+ for (int i = 0; i < limits.MAX_CONCURRENT_OPERATIONS; ++i)
+ operations[i].id = 0;
+ this->messageHandlers = new struct MessageHandlers[limits.MAX_MESSAGE_HANDLERS];
+ for (int i = 0; i < limits.MAX_MESSAGE_HANDLERS; ++i)
+ messageHandlers[i].topic = 0;
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::sendPacket(int length, int timeout)
+{
+ int sent = 0;
+
+ while (sent < length)
+ sent += ipstack->write(&buf[sent], length, timeout);
+ if (sent == length)
+ ping_timer.countdown(this->keepAliveInterval); // record the fact that we have successfully sent the packet
+ return sent;
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::decodePacket(int* value, int timeout)
+{
+ char c;
+ int multiplier = 1;
+ int len = 0;
+ const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
+
+ *value = 0;
+ do
+ {
+ int rc = MQTTPACKET_READ_ERROR;
+
+ if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+ {
+ rc = MQTTPACKET_READ_ERROR; /* bad data */
+ goto exit;
+ }
+ rc = ipstack->read(&c, 1, timeout);
+ if (rc != 1)
+ goto exit;
+ *value += (c & 127) * multiplier;
+ multiplier *= 128;
+ } while ((c & 128) != 0);
+exit:
+ return len;
+}
+
+
+/**
+ * If any read fails in this method, then we should disconnect from the network, as on reconnect
+ * the packets can be retried.
+ * @param timeout the max time to wait for the packet read to complete, in milliseconds
+ * @return the MQTT packet type, or -1 if none
+ */
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::readPacket(int timeout)
+{
+ int rc = -1;
+ MQTTHeader header = {0};
+ int len = 0;
+ int rem_len = 0;
+
+ /* 1. read the header byte. This has the packet type in it */
+ if (ipstack->read(readbuf, 1, timeout) != 1)
+ goto exit;
+
+ len = 1;
+ /* 2. read the remaining length. This is variable in itself */
+ decodePacket(&rem_len, timeout);
+ len += MQTTPacket_encode(readbuf + 1, rem_len); /* put the original remaining length back into the buffer */
+
+ /* 3. read the rest of the buffer using a callback to supply the rest of the data */
+ if (ipstack->read(readbuf + len, rem_len, timeout) != rem_len)
+ goto exit;
+
+ header.byte = readbuf[0];
+ rc = header.bits.type;
+exit:
+ return rc;
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::deliverMessage(MQTTString* topic, Message* message)
+{
+ int rc = -1;
+
+ // we have to find the right message handler - indexed by topic
+ for (int i = 0; i < limits.MAX_MESSAGE_HANDLERS; ++i)
+ {
+ if (messageHandlers[i].topic != 0 && MQTTPacket_equals(topic, (char*)messageHandlers[i].topic))
+ {
+ messageHandlers[i].fp(message);
+ rc = 0;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::cycle(int timeout)
+{
+ /* get one piece of work off the wire and one pass through */
+
+ // read the socket, see what work is due
+ int packet_type = readPacket(timeout);
+
+ int len, rc;
+ switch (packet_type)
+ {
+ case CONNACK:
+ if (this->thread)
+ {
+ Result res = {this, 0};
+ if (MQTTDeserialize_connack(&res.rc, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1)
+ ;
+ connectHandler(&res);
+ connectHandler.detach(); // only invoke the callback once
+ }
+ break;
+ case PUBACK:
+ if (this->thread)
+ ; //call resultHandler
+ case SUBACK:
+ break;
+ case PUBLISH:
+ MQTTString topicName;
+ Message msg;
+ rc = MQTTDeserialize_publish((int*)&msg.dup, (int*)&msg.qos, (int*)&msg.retained, (int*)&msg.id, &topicName,
+ (char**)&msg.payload, (int*)&msg.payloadlen, readbuf, limits.MAX_MQTT_PACKET_SIZE);;
+ if (msg.qos == QOS0)
+ deliverMessage(&topicName, &msg);
+ break;
+ case PUBREC:
+ int type, dup, mypacketid;
+ if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1)
+ ;
+ // must lock this access against the application thread, if we are multi-threaded
+ len = MQTTSerialize_ack(buf, limits.MAX_MQTT_PACKET_SIZE, PUBREL, 0, mypacketid);
+ rc = sendPacket(len, timeout); // send the PUBREL packet
+ if (rc != len)
+ goto exit; // there was a problem
+
+ break;
+ case PUBCOMP:
+ break;
+ case PINGRESP:
+ ping_outstanding = false;
+ break;
+ }
+ keepalive();
+exit:
+ return packet_type;
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::keepalive()
+{
+ int rc = 0;
+
+ if (keepAliveInterval == 0)
+ goto exit;
+
+ if (ping_timer.expired())
+ {
+ if (ping_outstanding)
+ rc = -1;
+ else
+ {
+ int len = MQTTSerialize_pingreq(buf, limits.MAX_MQTT_PACKET_SIZE);
+ rc = sendPacket(len, 1000); // send the ping packet
+ if (rc != len)
+ rc = -1; // indicate there's a problem
+ else
+ ping_outstanding = true;
+ }
+ }
+
+exit:
+ return rc;
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> void MQTT::Async<Network, Timer, Thread, Mutex>::run(void const *argument)
+{
+ while (true)
+ cycle(ping_timer.left_ms());
+}
+
+
+// only used in single-threaded mode where one command at a time is in process
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::waitfor(int packet_type, Timer& atimer)
+{
+ int rc = -1;
+
+ do
+ {
+ if (atimer.expired())
+ break; // we timed out
+ }
+ while ((rc = cycle(atimer.left_ms())) != packet_type);
+
+ return rc;
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::connect(resultHandler resultHandler, MQTTPacket_connectData* options)
+{
+ connect_timer.countdown(limits.command_timeout_ms);
+
+ MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
+ if (options == 0)
+ options = &default_options; // set default options if none were supplied
+
+ this->keepAliveInterval = options->keepAliveInterval;
+ ping_timer.countdown(this->keepAliveInterval);
+ int len = MQTTSerialize_connect(buf, limits.MAX_MQTT_PACKET_SIZE, options);
+ int rc = sendPacket(len, connect_timer.left_ms()); // send the connect packet
+ if (rc != len)
+ goto exit; // there was a problem
+
+ if (resultHandler == 0) // wait until the connack is received
+ {
+ // this will be a blocking call, wait for the connack
+ if (waitfor(CONNACK, connect_timer) == CONNACK)
+ {
+ int connack_rc = -1;
+ if (MQTTDeserialize_connack(&connack_rc, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1)
+ rc = connack_rc;
+ }
+ }
+ else
+ {
+ // set connect response callback function
+ connectHandler.attach(resultHandler);
+
+ // start background thread
+ this->thread = new Thread((void (*)(void const *argument))&MQTT::Async<Network, Timer, Thread, Mutex>::threadfn, (void*)this);
+ }
+
+exit:
+ return rc;
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::findFreeOperation()
+{
+ int found = -1;
+ for (int i = 0; i < limits.MAX_CONCURRENT_OPERATIONS; ++i)
+ {
+ if (operations[i].id == 0)
+ {
+ found = i;
+ break;
+ }
+ }
+ return found;
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::subscribe(resultHandler resultHandler, const char* topicFilter, enum QoS qos, messageHandler messageHandler)
+{
+ int index = 0;
+ if (this->thread)
+ index = findFreeOperation();
+ Timer& atimer = operations[index].timer;
+
+ atimer.countdown(limits.command_timeout_ms);
+ MQTTString topic = {(char*)topicFilter, 0, 0};
+
+ int len = MQTTSerialize_subscribe(buf, limits.MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic, (int*)&qos);
+ int rc = sendPacket(len, atimer.left_ms()); // send the subscribe packet
+ if (rc != len)
+ goto exit; // there was a problem
+
+ /* wait for suback */
+ if (resultHandler == 0)
+ {
+ // this will block
+ if (waitfor(SUBACK, atimer) == SUBACK)
+ {
+ int count = 0, grantedQoS = -1, mypacketid;
+ if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1)
+ rc = grantedQoS; // 0, 1, 2 or 0x80
+ if (rc != 0x80)
+ {
+ for (int i = 0; i < limits.MAX_MESSAGE_HANDLERS; ++i)
+ {
+ if (messageHandlers[i].topic == 0)
+ {
+ messageHandlers[i].topic = topicFilter;
+ messageHandlers[i].fp.attach(messageHandler);
+ rc = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // set subscribe response callback function
+
+ }
+
+exit:
+ return rc;
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::unsubscribe(resultHandler resultHandler, const char* topicFilter)
+{
+ int index = 0;
+ if (this->thread)
+ index = findFreeOperation();
+ Timer& atimer = operations[index].timer;
+
+ atimer.countdown(limits.command_timeout_ms);
+ MQTTString topic = {(char*)topicFilter, 0, 0};
+
+ int len = MQTTSerialize_unsubscribe(buf, limits.MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic);
+ int rc = sendPacket(len, atimer.left_ms()); // send the subscribe packet
+ if (rc != len)
+ goto exit; // there was a problem
+
+ // set unsubscribe response callback function
+
+
+exit:
+ return rc;
+}
+
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::publish(resultHandler resultHandler, const char* topicName, Message* message)
+{
+ int index = 0;
+ if (this->thread)
+ index = findFreeOperation();
+ Timer& atimer = operations[index].timer;
+
+ atimer.countdown(limits.command_timeout_ms);
+ MQTTString topic = {(char*)topicName, 0, 0};
+
+ if (message->qos == QOS1 || message->qos == QOS2)
+ message->id = packetid.getNext();
+
+ int len = MQTTSerialize_publish(buf, limits.MAX_MQTT_PACKET_SIZE, 0, message->qos, message->retained, message->id, topic, (char*)message->payload, message->payloadlen);
+ int rc = sendPacket(len, atimer.left_ms()); // send the subscribe packet
+ if (rc != len)
+ goto exit; // there was a problem
+
+ /* wait for acks */
+ if (resultHandler == 0)
+ {
+ if (message->qos == QOS1)
+ {
+ if (waitfor(PUBACK, atimer) == PUBACK)
+ {
+ int type, dup, mypacketid;
+ if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1)
+ rc = 0;
+ }
+ }
+ else if (message->qos == QOS2)
+ {
+ if (waitfor(PUBCOMP, atimer) == PUBCOMP)
+ {
+ int type, dup, mypacketid;
+ if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, limits.MAX_MQTT_PACKET_SIZE) == 1)
+ rc = 0;
+ }
+
+ }
+ }
+ else
+ {
+ // set publish response callback function
+
+ }
+
+exit:
+ return rc;
+}
+
+
+template<class Network, class Timer, class Thread, class Mutex> int MQTT::Async<Network, Timer, Thread, Mutex>::disconnect(resultHandler resultHandler)
+{
+ Timer timer = Timer(limits.command_timeout_ms); // we might wait for incomplete incoming publishes to complete
+ int len = MQTTSerialize_disconnect(buf, limits.MAX_MQTT_PACKET_SIZE);
+ int rc = sendPacket(len, timer.left_ms()); // send the disconnect packet
+
+ return (rc == len) ? 0 : -1;
+}
+
+
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTT/MQTTClient.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,939 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2015 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors: *
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ * Ian Craggs - fix for bug 458512 - QoS 2 messages
+ * Ian Craggs - fix for bug 460389 - send loop uses wrong length
+ * Ian Craggs - fix for bug 464169 - clearing subscriptions
+ * Ian Craggs - fix for bug 464551 - enums and ints can be different size
+ *******************************************************************************/
+
+#if !defined(MQTTCLIENT_H)
+#define MQTTCLIENT_H
+
+#include "FP.h"
+#include "MQTTPacket.h"
+#include "stdio.h"
+#include "MQTTLogging.h"
+
+#if !defined(MQTTCLIENT_QOS1)
+ #define MQTTCLIENT_QOS1 1
+#endif
+#if !defined(MQTTCLIENT_QOS2)
+ #define MQTTCLIENT_QOS2 0
+#endif
+
+namespace MQTT
+{
+
+
+enum QoS { QOS0, QOS1, QOS2 };
+
+// all failure return codes must be negative
+enum returnCode { BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };
+
+
+struct Message
+{
+ enum QoS qos;
+ bool retained;
+ bool dup;
+ unsigned short id;
+ void *payload;
+ size_t payloadlen;
+};
+
+
+struct MessageData
+{
+ MessageData(MQTTString &aTopicName, struct Message &aMessage) : message(aMessage), topicName(aTopicName)
+ { }
+
+ struct Message &message;
+ MQTTString &topicName;
+};
+
+
+class PacketId
+{
+public:
+ PacketId()
+ {
+ next = 0;
+ }
+
+ int getNext()
+ {
+ return next = (next == MAX_PACKET_ID) ? 1 : ++next;
+ }
+
+private:
+ static const int MAX_PACKET_ID = 65535;
+ int next;
+};
+
+
+/**
+ * @class Client
+ * @brief blocking, non-threaded MQTT client API
+ *
+ * This version of the API blocks on all method calls, until they are complete. This means that only one
+ * MQTT request can be in process at any one time.
+ * @param Network a network class which supports send, receive
+ * @param Timer a timer class with the methods:
+ */
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE = 100, int MAX_MESSAGE_HANDLERS = 5>
+class Client
+{
+
+public:
+
+ typedef void (*messageHandler)(MessageData&);
+
+ /** Construct the client
+ * @param network - pointer to an instance of the Network class - must be connected to the endpoint
+ * before calling MQTT connect
+ * @param limits an instance of the Limit class - to alter limits as required
+ */
+ Client(Network& network, unsigned int command_timeout_ms = 30000);
+
+ /** Set the default message handling callback - used for any message which does not match a subscription message handler
+ * @param mh - pointer to the callback function
+ */
+ void setDefaultMessageHandler(messageHandler mh)
+ {
+ defaultMessageHandler.attach(mh);
+ }
+
+ /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
+ * The nework object must be connected to the network endpoint before calling this
+ * Default connect options are used
+ * @return success code -
+ */
+ int connect();
+
+ /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
+ * The nework object must be connected to the network endpoint before calling this
+ * @param options - connect options
+ * @return success code -
+ */
+ int connect(MQTTPacket_connectData& options);
+
+ /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
+ * @param topic - the topic to publish to
+ * @param message - the message to send
+ * @return success code -
+ */
+ int publish(const char* topicName, Message& message);
+
+ /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
+ * @param topic - the topic to publish to
+ * @param payload - the data to send
+ * @param payloadlen - the length of the data
+ * @param qos - the QoS to send the publish at
+ * @param retained - whether the message should be retained
+ * @return success code -
+ */
+ int publish(const char* topicName, void* payload, size_t payloadlen, enum QoS qos = QOS0, bool retained = false);
+
+ /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
+ * @param topic - the topic to publish to
+ * @param payload - the data to send
+ * @param payloadlen - the length of the data
+ * @param id - the packet id used - returned
+ * @param qos - the QoS to send the publish at
+ * @param retained - whether the message should be retained
+ * @return success code -
+ */
+ int publish(const char* topicName, void* payload, size_t payloadlen, unsigned short& id, enum QoS qos = QOS1, bool retained = false);
+
+ /** MQTT Subscribe - send an MQTT subscribe packet and wait for the suback
+ * @param topicFilter - a topic pattern which can include wildcards
+ * @param qos - the MQTT QoS to subscribe at
+ * @param mh - the callback function to be invoked when a message is received for this subscription
+ * @return success code -
+ */
+ int subscribe(const char* topicFilter, enum QoS qos, messageHandler mh);
+
+ /** MQTT Unsubscribe - send an MQTT unsubscribe packet and wait for the unsuback
+ * @param topicFilter - a topic pattern which can include wildcards
+ * @return success code -
+ */
+ int unsubscribe(const char* topicFilter);
+
+ /** MQTT Disconnect - send an MQTT disconnect packet, and clean up any state
+ * @return success code -
+ */
+ int disconnect();
+
+ /** A call to this API must be made within the keepAlive interval to keep the MQTT connection alive
+ * yield can be called if no other MQTT operation is needed. This will also allow messages to be
+ * received.
+ * @param timeout_ms the time to wait, in milliseconds
+ * @return success code - on failure, this means the client has disconnected
+ */
+ int yield(unsigned long timeout_ms = 1000L);
+
+ /** Is the client connected?
+ * @return flag - is the client connected or not?
+ */
+ bool isConnected()
+ {
+ return isconnected;
+ }
+
+private:
+
+ void cleanSession();
+ int cycle(Timer& timer);
+ int waitfor(int packet_type, Timer& timer);
+ int keepalive();
+ int publish(int len, Timer& timer, enum QoS qos);
+
+ int decodePacket(int* value, int timeout);
+ int readPacket(Timer& timer);
+ int sendPacket(int length, Timer& timer);
+ int deliverMessage(MQTTString& topicName, Message& message);
+ bool isTopicMatched(char* topicFilter, MQTTString& topicName);
+
+ Network& ipstack;
+ unsigned long command_timeout_ms;
+
+ unsigned char sendbuf[MAX_MQTT_PACKET_SIZE];
+ unsigned char readbuf[MAX_MQTT_PACKET_SIZE];
+
+ Timer last_sent, last_received;
+ unsigned int keepAliveInterval;
+ bool ping_outstanding;
+ bool cleansession;
+
+ PacketId packetid;
+
+ struct MessageHandlers
+ {
+ const char* topicFilter;
+ FP<void, MessageData&> fp;
+ } messageHandlers[MAX_MESSAGE_HANDLERS]; // Message handlers are indexed by subscription topic
+
+ FP<void, MessageData&> defaultMessageHandler;
+
+ bool isconnected;
+
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+ unsigned char pubbuf[MAX_MQTT_PACKET_SIZE]; // store the last publish for sending on reconnect
+ int inflightLen;
+ unsigned short inflightMsgid;
+ enum QoS inflightQoS;
+#endif
+
+#if MQTTCLIENT_QOS2
+ bool pubrel;
+ #if !defined(MAX_INCOMING_QOS2_MESSAGES)
+ #define MAX_INCOMING_QOS2_MESSAGES 10
+ #endif
+ unsigned short incomingQoS2messages[MAX_INCOMING_QOS2_MESSAGES];
+ bool isQoS2msgidFree(unsigned short id);
+ bool useQoS2msgid(unsigned short id);
+ void freeQoS2msgid(unsigned short id);
+#endif
+
+};
+
+}
+
+
+template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
+void MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::cleanSession()
+{
+ ping_outstanding = false;
+ for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+ messageHandlers[i].topicFilter = 0;
+ isconnected = false;
+
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+ inflightMsgid = 0;
+ inflightQoS = QOS0;
+#endif
+
+#if MQTTCLIENT_QOS2
+ pubrel = false;
+ for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+ incomingQoS2messages[i] = 0;
+#endif
+}
+
+
+template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
+MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::Client(Network& network, unsigned int command_timeout_ms) : ipstack(network), packetid()
+{
+ last_sent = Timer();
+ last_received = Timer();
+ this->command_timeout_ms = command_timeout_ms;
+ cleanSession();
+}
+
+
+#if MQTTCLIENT_QOS2
+template<class Network, class Timer, int a, int b>
+bool MQTT::Client<Network, Timer, a, b>::isQoS2msgidFree(unsigned short id)
+{
+ for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+ {
+ if (incomingQoS2messages[i] == id)
+ return false;
+ }
+ return true;
+}
+
+
+template<class Network, class Timer, int a, int b>
+bool MQTT::Client<Network, Timer, a, b>::useQoS2msgid(unsigned short id)
+{
+ for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+ {
+ if (incomingQoS2messages[i] == 0)
+ {
+ incomingQoS2messages[i] = id;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+template<class Network, class Timer, int a, int b>
+void MQTT::Client<Network, Timer, a, b>::freeQoS2msgid(unsigned short id)
+{
+ for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+ {
+ if (incomingQoS2messages[i] == id)
+ {
+ incomingQoS2messages[i] = 0;
+ return;
+ }
+ }
+}
+#endif
+
+
+template<class Network, class Timer, int a, int b>
+int MQTT::Client<Network, Timer, a, b>::sendPacket(int length, Timer& timer)
+{
+ int rc = FAILURE,
+ sent = 0;
+
+ while (sent < length && !timer.expired())
+ {
+ rc = ipstack.write(&sendbuf[sent], length - sent, timer.left_ms());
+ if (rc < 0) // there was an error writing the data
+ break;
+ sent += rc;
+ }
+ if (sent == length)
+ {
+ if (this->keepAliveInterval > 0)
+ last_sent.countdown(this->keepAliveInterval); // record the fact that we have successfully sent the packet
+ rc = SUCCESS;
+ }
+ else
+ rc = FAILURE;
+
+#if defined(MQTT_DEBUG)
+ char printbuf[150];
+ DEBUG("Rc %d from sending packet %s\n", rc, MQTTFormat_toServerString(printbuf, sizeof(printbuf), sendbuf, length));
+#endif
+ return rc;
+}
+
+
+template<class Network, class Timer, int a, int b>
+int MQTT::Client<Network, Timer, a, b>::decodePacket(int* value, int timeout)
+{
+ unsigned char c;
+ int multiplier = 1;
+ int len = 0;
+ const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
+
+ *value = 0;
+ do
+ {
+ int rc = MQTTPACKET_READ_ERROR;
+
+ if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+ {
+ rc = MQTTPACKET_READ_ERROR; /* bad data */
+ goto exit;
+ }
+ rc = ipstack.read(&c, 1, timeout);
+ if (rc != 1)
+ goto exit;
+ *value += (c & 127) * multiplier;
+ multiplier *= 128;
+ } while ((c & 128) != 0);
+exit:
+ return len;
+}
+
+
+/**
+ * If any read fails in this method, then we should disconnect from the network, as on reconnect
+ * the packets can be retried.
+ * @param timeout the max time to wait for the packet read to complete, in milliseconds
+ * @return the MQTT packet type, or -1 if none
+ */
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::readPacket(Timer& timer)
+{
+ int rc = FAILURE;
+ MQTTHeader header = {0};
+ int len = 0;
+ int rem_len = 0;
+
+ /* 1. read the header byte. This has the packet type in it */
+ if (ipstack.read(readbuf, 1, timer.left_ms()) != 1)
+ goto exit;
+
+ len = 1;
+ /* 2. read the remaining length. This is variable in itself */
+ decodePacket(&rem_len, timer.left_ms());
+ len += MQTTPacket_encode(readbuf + 1, rem_len); /* put the original remaining length into the buffer */
+
+ if (rem_len > (MAX_MQTT_PACKET_SIZE - len))
+ {
+ rc = BUFFER_OVERFLOW;
+ goto exit;
+ }
+
+ /* 3. read the rest of the buffer using a callback to supply the rest of the data */
+ if (rem_len > 0 && (ipstack.read(readbuf + len, rem_len, timer.left_ms()) != rem_len))
+ goto exit;
+
+ header.byte = readbuf[0];
+ rc = header.bits.type;
+ if (this->keepAliveInterval > 0)
+ last_received.countdown(this->keepAliveInterval); // record the fact that we have successfully received a packet
+exit:
+
+#if defined(MQTT_DEBUG)
+ if (rc >= 0)
+ {
+ char printbuf[50];
+ DEBUG("Rc %d from receiving packet %s\n", rc, MQTTFormat_toClientString(printbuf, sizeof(printbuf), readbuf, len));
+ }
+#endif
+ return rc;
+}
+
+
+// assume topic filter and name is in correct format
+// # can only be at end
+// + and # can only be next to separator
+template<class Network, class Timer, int a, int b>
+bool MQTT::Client<Network, Timer, a, b>::isTopicMatched(char* topicFilter, MQTTString& topicName)
+{
+ char* curf = topicFilter;
+ char* curn = topicName.lenstring.data;
+ char* curn_end = curn + topicName.lenstring.len;
+
+ while (*curf && curn < curn_end)
+ {
+ if (*curn == '/' && *curf != '/')
+ break;
+ if (*curf != '+' && *curf != '#' && *curf != *curn)
+ break;
+ if (*curf == '+')
+ { // skip until we meet the next separator, or end of string
+ char* nextpos = curn + 1;
+ while (nextpos < curn_end && *nextpos != '/')
+ nextpos = ++curn + 1;
+ }
+ else if (*curf == '#')
+ curn = curn_end - 1; // skip until end of string
+ curf++;
+ curn++;
+ };
+
+ return (curn == curn_end) && (*curf == '\0');
+}
+
+
+
+template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
+int MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::deliverMessage(MQTTString& topicName, Message& message)
+{
+ int rc = FAILURE;
+
+ // we have to find the right message handler - indexed by topic
+ for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+ {
+ if (messageHandlers[i].topicFilter != 0 && (MQTTPacket_equals(&topicName, (char*)messageHandlers[i].topicFilter) ||
+ isTopicMatched((char*)messageHandlers[i].topicFilter, topicName)))
+ {
+ if (messageHandlers[i].fp.attached())
+ {
+ MessageData md(topicName, message);
+ messageHandlers[i].fp(md);
+ rc = SUCCESS;
+ }
+ }
+ }
+
+ if (rc == FAILURE && defaultMessageHandler.attached())
+ {
+ MessageData md(topicName, message);
+ defaultMessageHandler(md);
+ rc = SUCCESS;
+ }
+
+ return rc;
+}
+
+
+
+template<class Network, class Timer, int a, int b>
+int MQTT::Client<Network, Timer, a, b>::yield(unsigned long timeout_ms)
+{
+ int rc = SUCCESS;
+ Timer timer = Timer();
+
+ timer.countdown_ms(timeout_ms);
+ while (!timer.expired())
+ {
+ if (cycle(timer) < 0)
+ {
+ rc = FAILURE;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::cycle(Timer& timer)
+{
+ /* get one piece of work off the wire and one pass through */
+
+ // read the socket, see what work is due
+ int packet_type = readPacket(timer);
+
+ int len = 0,
+ rc = SUCCESS;
+
+ switch (packet_type)
+ {
+ case FAILURE:
+ case BUFFER_OVERFLOW:
+ rc = packet_type;
+ break;
+ case CONNACK:
+ case PUBACK:
+ case SUBACK:
+ break;
+ case PUBLISH:
+ {
+ MQTTString topicName = MQTTString_initializer;
+ Message msg;
+ int intQoS;
+ if (MQTTDeserialize_publish((unsigned char*)&msg.dup, &intQoS, (unsigned char*)&msg.retained, (unsigned short*)&msg.id, &topicName,
+ (unsigned char**)&msg.payload, (int*)&msg.payloadlen, readbuf, MAX_MQTT_PACKET_SIZE) != 1)
+ goto exit;
+ msg.qos = (enum QoS)intQoS;
+#if MQTTCLIENT_QOS2
+ if (msg.qos != QOS2)
+#endif
+ deliverMessage(topicName, msg);
+#if MQTTCLIENT_QOS2
+ else if (isQoS2msgidFree(msg.id))
+ {
+ if (useQoS2msgid(msg.id))
+ deliverMessage(topicName, msg);
+ else
+ WARN("Maximum number of incoming QoS2 messages exceeded");
+ }
+#endif
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+ if (msg.qos != QOS0)
+ {
+ if (msg.qos == QOS1)
+ len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBACK, 0, msg.id);
+ else if (msg.qos == QOS2)
+ len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBREC, 0, msg.id);
+ if (len <= 0)
+ rc = FAILURE;
+ else
+ rc = sendPacket(len, timer);
+ if (rc == FAILURE)
+ goto exit; // there was a problem
+ }
+ break;
+#endif
+ }
+#if MQTTCLIENT_QOS2
+ case PUBREC:
+ case PUBREL:
+ unsigned short mypacketid;
+ unsigned char dup, type;
+ if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) != 1)
+ rc = FAILURE;
+ else if ((len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE,
+ (packet_type == PUBREC) ? PUBREL : PUBCOMP, 0, mypacketid)) <= 0)
+ rc = FAILURE;
+ else if ((rc = sendPacket(len, timer)) != SUCCESS) // send the PUBREL packet
+ rc = FAILURE; // there was a problem
+ if (rc == FAILURE)
+ goto exit; // there was a problem
+ if (packet_type == PUBREL)
+ freeQoS2msgid(mypacketid);
+ break;
+
+ case PUBCOMP:
+ break;
+#endif
+ case PINGRESP:
+ ping_outstanding = false;
+ break;
+ }
+ keepalive();
+exit:
+ if (rc == SUCCESS)
+ rc = packet_type;
+ return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::keepalive()
+{
+ int rc = FAILURE;
+
+ if (keepAliveInterval == 0)
+ {
+ rc = SUCCESS;
+ goto exit;
+ }
+
+ if (last_sent.expired() || last_received.expired())
+ {
+ if (!ping_outstanding)
+ {
+ Timer timer(1000);
+ int len = MQTTSerialize_pingreq(sendbuf, MAX_MQTT_PACKET_SIZE);
+ if (len > 0 && (rc = sendPacket(len, timer)) == SUCCESS) // send the ping packet
+ ping_outstanding = true;
+ }
+ }
+
+exit:
+ return rc;
+}
+
+
+// only used in single-threaded mode where one command at a time is in process
+template<class Network, class Timer, int a, int b>
+int MQTT::Client<Network, Timer, a, b>::waitfor(int packet_type, Timer& timer)
+{
+ int rc = FAILURE;
+
+ do
+ {
+ if (timer.expired())
+ break; // we timed out
+ }
+ while ((rc = cycle(timer)) != packet_type);
+
+ return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::connect(MQTTPacket_connectData& options)
+{
+ Timer connect_timer(command_timeout_ms);
+ int rc = FAILURE;
+ int len = 0;
+
+ if (isconnected) // don't send connect packet again if we are already connected
+ goto exit;
+
+ this->keepAliveInterval = options.keepAliveInterval;
+ this->cleansession = options.cleansession;
+ if ((len = MQTTSerialize_connect(sendbuf, MAX_MQTT_PACKET_SIZE, &options)) <= 0)
+ goto exit;
+ if ((rc = sendPacket(len, connect_timer)) != SUCCESS) // send the connect packet
+ goto exit; // there was a problem
+
+ if (this->keepAliveInterval > 0)
+ last_received.countdown(this->keepAliveInterval);
+ // this will be a blocking call, wait for the connack
+ if (waitfor(CONNACK, connect_timer) == CONNACK)
+ {
+ unsigned char connack_rc = 255;
+ bool sessionPresent = false;
+ if (MQTTDeserialize_connack((unsigned char*)&sessionPresent, &connack_rc, readbuf, MAX_MQTT_PACKET_SIZE) == 1)
+ rc = connack_rc;
+ else
+ rc = FAILURE;
+ }
+ else
+ rc = FAILURE;
+
+#if MQTTCLIENT_QOS2
+ // resend any inflight publish
+ if (inflightMsgid > 0 && inflightQoS == QOS2 && pubrel)
+ {
+ if ((len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBREL, 0, inflightMsgid)) <= 0)
+ rc = FAILURE;
+ else
+ rc = publish(len, connect_timer, inflightQoS);
+ }
+ else
+#endif
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+ if (inflightMsgid > 0)
+ {
+ memcpy(sendbuf, pubbuf, MAX_MQTT_PACKET_SIZE);
+ rc = publish(inflightLen, connect_timer, inflightQoS);
+ }
+#endif
+
+exit:
+ if (rc == SUCCESS)
+ isconnected = true;
+ return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::connect()
+{
+ MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
+ return connect(default_options);
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int MAX_MESSAGE_HANDLERS>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::subscribe(const char* topicFilter, enum QoS qos, messageHandler messageHandler)
+{
+ int rc = FAILURE;
+ Timer timer(command_timeout_ms);
+ int len = 0;
+ MQTTString topic = {(char*)topicFilter, {0, 0}};
+
+ if (!isconnected)
+ goto exit;
+
+ len = MQTTSerialize_subscribe(sendbuf, MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic, (int*)&qos);
+ if (len <= 0)
+ goto exit;
+ if ((rc = sendPacket(len, timer)) != SUCCESS) // send the subscribe packet
+ goto exit; // there was a problem
+
+ if (waitfor(SUBACK, timer) == SUBACK) // wait for suback
+ {
+ int count = 0, grantedQoS = -1;
+ unsigned short mypacketid;
+ if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, readbuf, MAX_MQTT_PACKET_SIZE) == 1)
+ rc = grantedQoS; // 0, 1, 2 or 0x80
+ if (rc != 0x80)
+ {
+ for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+ {
+ if (messageHandlers[i].topicFilter == 0)
+ {
+ messageHandlers[i].topicFilter = topicFilter;
+ messageHandlers[i].fp.attach(messageHandler);
+ rc = 0;
+ break;
+ }
+ }
+ }
+ }
+ else
+ rc = FAILURE;
+
+exit:
+ if (rc != SUCCESS)
+ cleanSession();
+ return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int MAX_MESSAGE_HANDLERS>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::unsubscribe(const char* topicFilter)
+{
+ int rc = FAILURE;
+ Timer timer(command_timeout_ms);
+ MQTTString topic = {(char*)topicFilter, {0, 0}};
+ int len = 0;
+
+ if (!isconnected)
+ goto exit;
+
+ if ((len = MQTTSerialize_unsubscribe(sendbuf, MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic)) <= 0)
+ goto exit;
+ if ((rc = sendPacket(len, timer)) != SUCCESS) // send the unsubscribe packet
+ goto exit; // there was a problem
+
+ if (waitfor(UNSUBACK, timer) == UNSUBACK)
+ {
+ unsigned short mypacketid; // should be the same as the packetid above
+ if (MQTTDeserialize_unsuback(&mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) == 1)
+ {
+ rc = 0;
+
+ // remove the subscription message handler associated with this topic, if there is one
+ for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+ {
+ if (messageHandlers[i].topicFilter && strcmp(messageHandlers[i].topicFilter, topicFilter) == 0)
+ {
+ messageHandlers[i].topicFilter = 0;
+ break;
+ }
+ }
+ }
+ }
+ else
+ rc = FAILURE;
+
+exit:
+ if (rc != SUCCESS)
+ cleanSession();
+ return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(int len, Timer& timer, enum QoS qos)
+{
+ int rc;
+
+ if ((rc = sendPacket(len, timer)) != SUCCESS) // send the publish packet
+ goto exit; // there was a problem
+
+#if MQTTCLIENT_QOS1
+ if (qos == QOS1)
+ {
+ if (waitfor(PUBACK, timer) == PUBACK)
+ {
+ unsigned short mypacketid;
+ unsigned char dup, type;
+ if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) != 1)
+ rc = FAILURE;
+ else if (inflightMsgid == mypacketid)
+ inflightMsgid = 0;
+ }
+ else
+ rc = FAILURE;
+ }
+#elif MQTTCLIENT_QOS2
+ else if (qos == QOS2)
+ {
+ if (waitfor(PUBCOMP, timer) == PUBCOMP)
+ {
+ unsigned short mypacketid;
+ unsigned char dup, type;
+ if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) != 1)
+ rc = FAILURE;
+ else if (inflightMsgid == mypacketid)
+ inflightMsgid = 0;
+ }
+ else
+ rc = FAILURE;
+ }
+#endif
+
+exit:
+ if (rc != SUCCESS)
+ cleanSession();
+ return rc;
+}
+
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(const char* topicName, void* payload, size_t payloadlen, unsigned short& id, enum QoS qos, bool retained)
+{
+ int rc = FAILURE;
+ Timer timer(command_timeout_ms);
+ MQTTString topicString = MQTTString_initializer;
+ int len = 0;
+
+ if (!isconnected)
+ goto exit;
+
+ topicString.cstring = (char*)topicName;
+
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+ if (qos == QOS1 || qos == QOS2)
+ id = packetid.getNext();
+#endif
+
+ len = MQTTSerialize_publish(sendbuf, MAX_MQTT_PACKET_SIZE, 0, qos, retained, id,
+ topicString, (unsigned char*)payload, payloadlen);
+ if (len <= 0)
+ goto exit;
+
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+ if (!cleansession)
+ {
+ memcpy(pubbuf, sendbuf, len);
+ inflightMsgid = id;
+ inflightLen = len;
+ inflightQoS = qos;
+#if MQTTCLIENT_QOS2
+ pubrel = false;
+#endif
+ }
+#endif
+
+ rc = publish(len, timer, qos);
+exit:
+ return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(const char* topicName, void* payload, size_t payloadlen, enum QoS qos, bool retained)
+{
+ unsigned short id = 0; // dummy - not used for anything
+ return publish(topicName, payload, payloadlen, id, qos, retained);
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(const char* topicName, Message& message)
+{
+ return publish(topicName, message.payload, message.payloadlen, message.qos, message.retained);
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::disconnect()
+{
+ int rc = FAILURE;
+ Timer timer(command_timeout_ms); // we might wait for incomplete incoming publishes to complete
+ int len = MQTTSerialize_disconnect(sendbuf, MAX_MQTT_PACKET_SIZE);
+ if (len > 0)
+ rc = sendPacket(len, timer); // send the disconnect packet
+
+ if (cleansession)
+ cleanSession();
+ else
+ isconnected = false;
+ return rc;
+}
+
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTT/MQTTEthernet.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,35 @@
+
+#if !defined(MQTTETHERNET_H)
+#define MQTTETHERNET_H
+
+#include "MQTTmbed.h"
+#include "EthernetInterface.h"
+#include "MQTTSocket.h"
+
+class MQTTEthernet : public MQTTSocket
+{
+public:
+ MQTTEthernet()
+ {
+ eth.init(); // Use DHCP
+ eth.connect();
+ }
+
+ EthernetInterface& getEth()
+ {
+ return eth;
+ }
+
+ void reconnect()
+ {
+ eth.connect(); // nothing I've tried actually works to reconnect
+ }
+
+private:
+
+ EthernetInterface eth;
+
+};
+
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTT/MQTTLogging.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,39 @@
+#if !defined(MQTT_LOGGING_H)
+#define MQTT_LOGGING_H
+
+#define STREAM stdout
+#if !defined(DEBUG)
+#define DEBUG(...) \
+ {\
+ fprintf(STREAM, "DEBUG: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \
+ fprintf(STREAM, ##__VA_ARGS__); \
+ fflush(STREAM); \
+ }
+#endif
+#if !defined(LOG)
+#define LOG(...) \
+ {\
+ fprintf(STREAM, "LOG: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \
+ fprintf(STREAM, ##__VA_ARGS__); \
+ fflush(STREAM); \
+ }
+#endif
+#if !defined(WARN)
+#define WARN(...) \
+ { \
+ fprintf(STREAM, "WARN: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \
+ fprintf(STREAM, ##__VA_ARGS__); \
+ fflush(STREAM); \
+ }
+#endif
+#if !defined(ERROR)
+#define ERROR(...) \
+ { \
+ fprintf(STREAM, "ERROR: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \
+ fprintf(STREAM, ##__VA_ARGS__); \
+ fflush(STREAM); \
+ exit(1); \
+ }
+#endif
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/MQTTPacket.lib Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,1 @@ +http://mbed.org/teams/mqtt/code/MQTTPacket/#62396c1620b6
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTT/MQTTSocket.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,118 @@
+#if !defined(MQTTSOCKET_H)
+#define MQTTSOCKET_H
+
+#include "MQTTmbed.h"
+#include "TCPSocket.h"
+
+class MQTTSocket
+{
+public:
+
+ MQTTSocket(): mysock(true)
+ {
+
+ }
+
+ int open(NetworkStack *ipstack)
+ {
+ _time_last_ticks = 0;
+ timesock.open(ipstack);
+ return mysock.open(ipstack);
+ }
+
+ int getNTPtime(int timeout=1000)
+ {
+ int err;
+
+ uint8_t timedata[4];
+
+ timesock.set_timeout(timeout*3);
+ do
+ {
+ err= timesock.connect("time-d.nist.gov", 37);
+
+ if (err != 0)
+ {
+ LOG("ERROR resolving ntp server IP and connecting to it! \r\n");
+ }
+ } while (err != 0);
+
+ while (err != 4)
+ {
+ err = timesock.recv((char*)timedata, 4);
+
+ if (err != 4)
+ {
+ LOG("ERROR receiving time from ntp server! \r\n");
+ //return -1;
+ }
+ else
+ {
+ ///
+ /// Time Protocol provides the time as a binary number of seconds since 1900,
+ ///
+ /// 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT from 12:00:01 am on 1 January 1900 GMT
+ ///
+ _time_last_ticks = ((timedata[0]<<24 )|(timedata[1]<<16)|(timedata[2]<<8)| timedata[3]) - 2208988800ul;
+
+ LOG("Success receiving time from ntp server. Tick from 1 Jan 1970 is equal to %d. \r\n", _time_last_ticks);
+
+ }
+ }
+
+ err = timesock.close();
+
+ return err;
+ }
+
+ int connect(char* hostname, int port, int timeout=1000)
+ {
+ int err;
+
+ mysock.set_timeout(timeout);
+ err = mysock.connect(hostname, port);
+// t.start();
+ return err;
+ }
+
+ int read(unsigned char* buffer, int len, int timeout)
+ {
+ mysock.set_timeout(timeout);
+//t.reset();
+// int start = t.read_ms();
+ int rc = mysock.recv((char*)buffer, len);
+// int stop = t.read_ms();
+// if (rc>0) printf ("recv File: %s, Line: %d Read nB: %d rc: %d timeout: %d elaps: %d\n\r",__FILE__,__LINE__, len, rc, timeout, stop-start);
+ return rc;
+ }
+
+ int write(unsigned char* buffer, int len, int timeout)
+ {
+ mysock.set_timeout(timeout);
+// mysock.set_blocking(false, timeout);
+// mysock.set_blocking(false);
+ int rc = mysock.send((char*)buffer, len);
+// printf ("send File: %s, Line: %d Write nB: %d rc: %d\n\r",__FILE__,__LINE__, len, rc);
+ return rc;
+ }
+
+ int disconnect()
+ {
+// t.stop();
+ return mysock.close();
+ }
+
+ inline int getTime()
+ {
+ return _time_last_ticks;
+ }
+
+private:
+ TCPSocket mysock;
+ TCPSocket timesock;
+
+ uint32_t _time_last_ticks;
+ // Timer t;
+
+};
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTT/MQTTWiFi.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,30 @@
+
+#if !defined(MQTTWIFI_H)
+#define MQTTWIFI_H
+
+#include "MQTTmbed.h"
+#include "WiFiInterface.h"
+#include "MQTTSocket.h"
+
+class MQTTWiFi : public MQTTSocket
+{
+public:
+ MQTTWiFi(SpwfSAInterface &WiFiIntf, const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE) : WiFi(WiFiIntf)
+ {
+ WiFi.reset_chip();
+ WiFi.connect(ssid, pass, security);
+ }
+
+ SpwfSAInterface& getWiFi()
+ {
+ return WiFi;
+ }
+
+private:
+
+ SpwfSAInterface& WiFi;
+
+};
+
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTT/MQTTmbed.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,49 @@
+#if !defined(MQTT_MBED_H)
+#define MQTT_MBED_H
+
+#include "mbed.h"
+
+class Countdown
+{
+public:
+ Countdown()
+ {
+ t = Timer();
+ }
+
+ Countdown(int ms)
+ {
+ t = Timer();
+ countdown_ms(ms);
+ }
+
+
+ bool expired()
+ {
+ return t.read_ms() >= interval_end_ms;
+ }
+
+ void countdown_ms(unsigned long ms)
+ {
+ t.stop();
+ interval_end_ms = ms;
+ t.reset();
+ t.start();
+ }
+
+ void countdown(int seconds)
+ {
+ countdown_ms((unsigned long)seconds * 1000L);
+ }
+
+ int left_ms()
+ {
+ return interval_end_ms - t.read_ms();
+ }
+
+private:
+ Timer t;
+ unsigned long interval_end_ms;
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTT/NOTICE.TXT Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,4 @@ + +This library is originated from https://developer.mbed.org/teams/ST/code/MQTT/#66826ea709ea +MQTTWiFi class was modified to support hardware wifi reset. +MQTTSocket class was modified to support NTP server time request.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NOTICE.txt Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,2 @@ +This project is originally got from https://developer.mbed.org/teams/ST/code/IDW01M1_Cloud_IBM/ +It was completely adopted to Amazon AWS services. IBM IoT service connection is not supported. \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/CellularInterface.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,51 @@
+/* CellularInterface
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CELLULAR_INTERFACE_H
+#define CELLULAR_INTERFACE_H
+
+#include "NetworkStack.h"
+
+/** CellularInterface class
+ *
+ * Common interface that is shared between ethernet hardware
+ */
+class CellularInterface
+{
+public:
+ /** Start the interface
+ *
+ * @param apn Optional name of the network to connect to
+ * @param username Optional username for your APN
+ * @param password Optional password for your APN
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int connect(const char *apn = 0, const char *username = 0, const char *password = 0) = 0;
+
+ /** Stop the interface
+ *
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int disconnect() = 0;
+
+ /** Get the local MAC address
+ *
+ * @return Null-terminated representation of the local MAC address
+ */
+ virtual const char *get_mac_address() = 0;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetworkSocketAPI/DnsQuery.lib Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,1 @@ +https://developer.mbed.org/teams/NetworkSocketAPI/code/DnsQuery/#2cb1fffed50c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/EthernetInterface.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,48 @@
+/* EthernetInterface
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ETHERNET_INTERFACE_H
+#define ETHERNET_INTERFACE_H
+
+#include "NetworkStack.h"
+
+/** EthernetInterface class
+ *
+ * Common interface that is shared between ethernet hardware.
+ */
+class EthernetInterface
+{
+public:
+ /** Start the interface
+ *
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int connect() = 0;
+
+ /** Stop the interface
+ *
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int disconnect() = 0;
+
+ /** Get the local MAC address
+ *
+ * @return Null-terminated representation of the local MAC address
+ */
+ virtual const char *get_mac_address() = 0;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/MeshInterface.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,48 @@
+/* MeshInterface
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MESH_INTERFACE_H
+#define MESH_INTERFACE_H
+
+#include "NetworkStack.h"
+
+/** MeshInterface class
+ *
+ * Common interface that is shared between mesh hardware
+ */
+class MeshInterface
+{
+public:
+ /** Start the interface
+ *
+ * @return 0 on success, negative on failure
+ */
+ virtual int connect() = 0;
+
+ /** Stop the interface
+ *
+ * @return 0 on success, negative on failure
+ */
+ virtual int disconnect() = 0;
+
+ /** Get the local MAC address
+ *
+ * @return Null-terminated representation of the local MAC address
+ */
+ virtual const char *get_mac_address() = 0;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NetworkSocketAPI/NOTICE.txt Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,3 @@ +This library is origionated from http://mbed.org/teams/NetworkSocketAPI/code/NetworkSocketAPI/#ea3a618e0818 +"enum nsapi_protocol_t" is extended with security socket +"class TCPSocket" is extended with security socket support
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/NetworkStack.cpp Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,50 @@
+/* Socket
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DnsQuery.h"
+#include "mbed.h"
+
+int NetworkStack::gethostbyname(SocketAddress *address, const char *name)
+{
+ char buffer[NSAPI_IP_SIZE];
+ int err = dnsQuery(this, name, buffer);
+ if (err) {
+ return err;
+ }
+
+ address->set_ip_address(buffer);
+ return 0;
+}
+
+int NetworkStack::setstackopt(int level, int optname, const void *optval, unsigned optlen)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int NetworkStack::getstackopt(int level, int optname, void *optval, unsigned *optlen)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int NetworkStack::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int NetworkStack::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/NetworkStack.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,339 @@
+/* NetworkStack
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NETWORK_INTERFACE_H
+#define NETWORK_INTERFACE_H
+
+#include "mbed.h"
+#include "SocketAddress.h"
+
+
+/** Enum of standardized error codes
+ *
+ * Valid error codes have negative values and may
+ * be returned by any network operation.
+ *
+ * @enum nsapi_error_t
+ */
+enum nsapi_error_t {
+ NSAPI_ERROR_WOULD_BLOCK = -3001, /*!< no data is not available but call is non-blocking */
+ NSAPI_ERROR_UNSUPPORTED = -3002, /*!< unsupported functionality */
+ NSAPI_ERROR_PARAMETER = -3003, /*!< invalid configuration */
+ NSAPI_ERROR_NO_CONNECTION = -3004, /*!< not connected to a network */
+ NSAPI_ERROR_NO_SOCKET = -3005, /*!< socket not available for use */
+ NSAPI_ERROR_NO_ADDRESS = -3006, /*!< IP address is not known */
+ NSAPI_ERROR_NO_MEMORY = -3007, /*!< memory resource not available */
+ NSAPI_ERROR_DNS_FAILURE = -3008, /*!< DNS failed to complete successfully */
+ NSAPI_ERROR_DHCP_FAILURE = -3009, /*!< DHCP failed to complete successfully */
+ NSAPI_ERROR_AUTH_FAILURE = -3010, /*!< connection to access point faield */
+ NSAPI_ERROR_DEVICE_ERROR = -3011, /*!< failure interfacing with the network procesor */
+};
+
+/** Enum of socket protocols
+ *
+ * The socket protocol specifies a particular protocol to
+ * be used with a newly created socket.
+ *
+ * @enum nsapi_protocol_t
+ */
+enum nsapi_protocol_t {
+ NSAPI_TCP, /*!< Socket is of TCP type */
+ NSAPI_UDP, /*!< Socket is of UDP type */
+ NSAPI_TLS /*!< Socket is of TCP Secure type */
+};
+
+/* Enum of standardized stack option levels
+ *
+ * @enum nsapi_level_t
+ */
+enum nsapi_level_t {
+ NSAPI_STACK, /*!< Stack option level */
+ NSAPI_SOCKET, /*!< Socket option level */
+};
+
+/* Enum of standardized stack options
+ *
+ * These options may not be supported on all stacks, in which
+ * case NSAPI_ERROR_UNSUPPORTED may be returned from setsockopt.
+ *
+ * @enum nsapi_option_t
+ */
+enum nsapi_option_t {
+ NSAPI_REUSEADDR, /*!< Allow bind to reuse local addresses */
+ NSAPI_KEEPALIVE, /*!< Enables sending of keepalive messages */
+ NSAPI_LINGER, /*!< Keeps close from returning until queues empty */
+ NSAPI_SNDBUF, /*!< Sets send buffer size */
+ NSAPI_RCVBUF, /*!< Sets recv buffer size */
+};
+
+
+/** NetworkStack class
+ *
+ * Common interface that is shared between hardware that
+ * can connect to a network over IP. By implementing the
+ * NetworkStack, a network stack can be used as a target
+ * for instantiating network sockets.
+ */
+class NetworkStack
+{
+public:
+ virtual ~NetworkStack() {};
+
+ /** Get the local IP address
+ *
+ * @return Null-terminated representation of the local IP address
+ * or null if not yet connected
+ */
+ virtual const char *get_ip_address() = 0;
+
+ /** Translates a hostname to an IP address
+ *
+ * The hostname may be either a domain name or an IP address. If the
+ * hostname is an IP address, no network transactions will be performed.
+ *
+ * If no stack-specific DNS resolution is provided, the hostname
+ * will be resolve using a UDP socket on the stack.
+ *
+ * @param address Destination for the host SocketAddress
+ * @param host Hostname to resolve
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int gethostbyname(SocketAddress *address, const char *host);
+
+ /* Set stack-specific stack options
+ *
+ * The setstackopt allow an application to pass stack-specific hints
+ * to the underlying stack. For unsupported options,
+ * NSAPI_ERROR_UNSUPPORTED is returned and the stack is unmodified.
+ *
+ * @param level Stack-specific protocol level
+ * @param optname Stack-specific option identifier
+ * @param optval Option value
+ * @param optlen Length of the option value
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen);
+
+ /* Get stack-specific stack options
+ *
+ * The getstackopt allow an application to retrieve stack-specific hints
+ * from the underlying stack. For unsupported options,
+ * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
+ *
+ * @param level Stack-specific protocol level
+ * @param optname Stack-specific option identifier
+ * @param optval Destination for option value
+ * @param optlen Length of the option value
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int getstackopt(int level, int optname, void *optval, unsigned *optlen);
+
+protected:
+ friend class Socket;
+ friend class UDPSocket;
+ friend class TCPSocket;
+ friend class TCPServer;
+
+ /** Opens a socket
+ *
+ * Creates a network socket and stores it in the specified handle.
+ * The handle must be passed to following calls on the socket.
+ *
+ * A stack may have a finite number of sockets, in this case
+ * NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
+ *
+ * @param handle Destination for the handle to a newly created socket
+ * @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int socket_open(void **handle, nsapi_protocol_t proto) = 0;
+
+ /** Close the socket
+ *
+ * Closes any open connection and deallocates any memory associated
+ * with the socket.
+ *
+ * @param handle Socket handle
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int socket_close(void *handle) = 0;
+
+ /** Bind a specific address to a socket
+ *
+ * Binding a socket specifies the address and port on which to recieve
+ * data. If the IP address is zeroed, only the port is bound.
+ *
+ * @param handle Socket handle
+ * @param address Local address to bind
+ * @return 0 on success, negative error code on failure.
+ */
+ virtual int socket_bind(void *handle, const SocketAddress &address) = 0;
+
+ /** Listen for connections on a TCP socket
+ *
+ * Marks the socket as a passive socket that can be used to accept
+ * incoming connections.
+ *
+ * @param handle Socket handle
+ * @param backlog Number of pending connections that can be queued
+ * simultaneously
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int socket_listen(void *handle, int backlog) = 0;
+
+ /** Connects TCP socket to a remote host
+ *
+ * Initiates a connection to a remote server specified by the
+ * indicated address.
+ *
+ * @param handle Socket handle
+ * @param address The SocketAddress of the remote host
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int socket_connect(void *handle, const SocketAddress &address) = 0;
+
+ /** Accepts a connection on a TCP socket
+ *
+ * The server socket must be bound and set to listen for connections.
+ * On a new connection, creates a network socket and stores it in the
+ * specified handle. The handle must be passed to following calls on
+ * the socket.
+ *
+ * A stack may have a finite number of sockets, in this case
+ * NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
+ *
+ * This call is non-blocking. If accept would block,
+ * NSAPI_ERROR_WOULD_BLOCK is returned immediately.
+ *
+ * @param handle Destination for a handle to the newly created sockey
+ * @param server Socket handle to server to accept from
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int socket_accept(void **handle, void *server) = 0;
+
+ /** Send data over a TCP socket
+ *
+ * The socket must be connected to a remote host. Returns the number of
+ * bytes sent from the buffer.
+ *
+ * This call is non-blocking. If send would block,
+ * NSAPI_ERROR_WOULD_BLOCK is returned immediately.
+ *
+ * @param handle Socket handle
+ * @param data Buffer of data to send to the host
+ * @param size Size of the buffer in bytes
+ * @return Number of sent bytes on success, negative error
+ * code on failure
+ */
+ virtual int socket_send(void *handle, const void *data, unsigned size) = 0;
+
+ /** Receive data over a TCP socket
+ *
+ * The socket must be connected to a remote host. Returns the number of
+ * bytes received into the buffer.
+ *
+ * This call is non-blocking. If recv would block,
+ * NSAPI_ERROR_WOULD_BLOCK is returned immediately.
+ *
+ * @param handle Socket handle
+ * @param data Destination buffer for data received from the host
+ * @param size Size of the buffer in bytes
+ * @return Number of received bytes on success, negative error
+ * code on failure
+ */
+ virtual int socket_recv(void *handle, void *data, unsigned size) = 0;
+
+ /** Send a packet over a UDP socket
+ *
+ * Sends data to the specified address. Returns the number of bytes
+ * sent from the buffer.
+ *
+ * This call is non-blocking. If sendto would block,
+ * NSAPI_ERROR_WOULD_BLOCK is returned immediately.
+ *
+ * @param handle Socket handle
+ * @param address The SocketAddress of the remote host
+ * @param data Buffer of data to send to the host
+ * @param size Size of the buffer in bytes
+ * @return Number of sent bytes on success, negative error
+ * code on failure
+ */
+ virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size) = 0;
+
+ /** Receive a packet over a UDP socket
+ *
+ * Receives data and stores the source address in address if address
+ * is not NULL. Returns the number of bytes received into the buffer.
+ *
+ * This call is non-blocking. If recvfrom would block,
+ * NSAPI_ERROR_WOULD_BLOCK is returned immediately.
+ *
+ * @param handle Socket handle
+ * @param address Destination for the source address or NULL
+ * @param data Destination buffer for data received from the host
+ * @param size Size of the buffer in bytes
+ * @return Number of received bytes on success, negative error
+ * code on failure
+ */
+ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size) = 0;
+
+ /** Register a callback on state change of the socket
+ *
+ * The specified callback will be called on state changes such as when
+ * the socket can recv/send/accept successfully and on when an error
+ * occurs. The callback may also be called spuriously without reason.
+ *
+ * The callback may be called in an interrupt context and should not
+ * perform expensive operations such as recv/send calls.
+ *
+ * @param handle Socket handle
+ * @param callback Function to call on state change
+ * @param data Argument to pass to callback
+ */
+ virtual void socket_attach(void *handle, void (*callback)(void *), void *data) = 0;
+
+ /* Set stack-specific socket options
+ *
+ * The setsockopt allow an application to pass stack-specific hints
+ * to the underlying stack. For unsupported options,
+ * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
+ *
+ * @param handle Socket handle
+ * @param level Stack-specific protocol level
+ * @param optname Stack-specific option identifier
+ * @param optval Option value
+ * @param optlen Length of the option value
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen);
+
+ /* Get stack-specific socket options
+ *
+ * The getstackopt allow an application to retrieve stack-specific hints
+ * from the underlying stack. For unsupported options,
+ * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
+ *
+ * @param handle Socket handle
+ * @param level Stack-specific protocol level
+ * @param optname Stack-specific option identifier
+ * @param optval Destination for option value
+ * @param optlen Length of the option value
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen);
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/Socket.cpp Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,127 @@
+/* Socket
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Socket.h"
+
+Socket::Socket()
+ : _iface(0)
+ , _socket(0)
+ , _timeout(-1)
+{
+}
+
+Socket::~Socket()
+{
+ if (_socket) {
+ close();
+ }
+}
+
+int Socket::open(NetworkStack *iface, nsapi_protocol_t proto)
+{
+ _iface = iface;
+
+ void *socket;
+ int err = _iface->socket_open(&socket, proto);
+ if (err) {
+ return err;
+ }
+
+ _socket = socket;
+ _iface->socket_attach(_socket, &Socket::thunk, this);
+
+ return 0;
+}
+
+int Socket::close()
+{
+ if (!_socket) {
+ return 0;
+ }
+
+ _iface->socket_attach(_socket, 0, 0);
+
+ void *volatile socket = _socket;
+ _socket = 0;
+ return _iface->socket_close(socket);
+}
+
+int Socket::bind(uint16_t port)
+{
+ SocketAddress addr(0, port);
+ return bind(addr);
+}
+
+int Socket::bind(const char *address, uint16_t port)
+{
+ SocketAddress addr(address, port);
+ return bind(addr);
+}
+
+int Socket::bind(const SocketAddress &address)
+{
+ if (!_socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ return _iface->socket_bind(_socket, address);
+}
+
+void Socket::set_blocking(bool blocking)
+{
+ set_timeout(blocking ? -1 : 0);
+}
+
+void Socket::set_timeout(int timeout)
+{
+ _timeout = timeout;
+}
+
+int Socket::setsockopt(int level, int optname, const void *optval, unsigned optlen)
+{
+ if (!_socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ return _iface->setsockopt(_socket, level, optname, optval, optlen);
+}
+
+int Socket::getsockopt(int level, int optname, void *optval, unsigned *optlen)
+{
+ if (!_socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ return _iface->getsockopt(_socket, level, optname, optval, optlen);
+
+}
+
+void Socket::wakeup()
+{
+}
+
+void Socket::thunk(void *data)
+{
+ Socket *self = (Socket *)data;
+ if (self->_callback) {
+ self->_callback();
+ }
+}
+
+void Socket::attach(FunctionPointer callback)
+{
+ _callback = callback;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/Socket.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,180 @@
+/* Socket
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOCKET_H
+#define SOCKET_H
+
+#include "SocketAddress.h"
+#include "NetworkStack.h"
+
+/** Abstract socket class
+ */
+class Socket {
+public:
+ /** Destroy a socket
+ *
+ * Closes socket if the socket is still open
+ */
+ virtual ~Socket();
+
+ /** Opens a socket
+ *
+ * Creates a network socket on the specified network stack.
+ * Not needed if stack is passed to the socket's constructor.
+ *
+ * @param iface Network stack as target for socket
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int open(NetworkStack *iface) = 0;
+
+ /** Close the socket
+ *
+ * Closes any open connection and deallocates any memory associated
+ * with the socket. Called from destructor if socket is not closed.
+ *
+ * @return 0 on success, negative error code on failure
+ */
+ int close();
+
+ /** Bind a specific address to a socket
+ *
+ * Binding a socket specifies the address and port on which to recieve
+ * data.
+ *
+ * @param port Local port to bind
+ * @return 0 on success, negative error code on failure.
+ */
+ int bind(uint16_t port);
+
+ /** Bind a specific address to a socket
+ *
+ * Binding a socket specifies the address and port on which to recieve
+ * data. If the IP address is zeroed, only the port is bound.
+ *
+ * @param address Null-terminated local address to bind
+ * @param port Local port to bind
+ * @return 0 on success, negative error code on failure.
+ */
+ int bind(const char *address, uint16_t port);
+
+ /** Bind a specific address to a socket
+ *
+ * Binding a socket specifies the address and port on which to recieve
+ * data. If the IP address is zeroed, only the port is bound.
+ *
+ * @param address Local address to bind
+ * @return 0 on success, negative error code on failure.
+ */
+ int bind(const SocketAddress &address);
+
+ /** Set blocking or non-blocking mode of the socket
+ *
+ * Initially all sockets are in blocking mode. In non-blocking mode
+ * blocking operations such as send/recv/accept return
+ * NSAPI_ERROR_WOULD_BLOCK if they can not continue.
+ *
+ * set_blocking(false) is equivalent to set_timeout(-1)
+ * set_blocking(true) is equivalent to set_timeout(0)
+ *
+ * @param blocking true for blocking mode, false for non-blocking mode.
+ */
+ void set_blocking(bool blocking);
+
+ /** Set timeout on blocking socket operations
+ *
+ * Initially all sockets have unbounded timeouts. NSAPI_ERROR_WOULD_BLOCK
+ * is returned if a blocking operation takes longer than the specified
+ * timeout. A timeout of -1 removes the timeout from the socket.
+ *
+ * set_timeout(-1) is equivalent to set_blocking(false)
+ * set_timeout(0) is equivalent to set_blocking(true)
+ *
+ * @param timeout Timeout in milliseconds
+ */
+ void set_timeout(int timeout);
+
+ /* Set stack-specific socket options
+ *
+ * The setsockopt allow an application to pass stack-specific hints
+ * to the underlying stack. For unsupported options,
+ * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
+ *
+ * @param level Stack-specific protocol level
+ * @param optname Stack-specific option identifier
+ * @param optval Option value
+ * @param optlen Length of the option value
+ * @return 0 on success, negative error code on failure
+ */
+ int setsockopt(int level, int optname, const void *optval, unsigned optlen);
+
+ /* Get stack-specific socket options
+ *
+ * The getstackopt allow an application to retrieve stack-specific hints
+ * from the underlying stack. For unsupported options,
+ * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
+ *
+ * @param level Stack-specific protocol level
+ * @param optname Stack-specific option identifier
+ * @param optval Destination for option value
+ * @param optlen Length of the option value
+ * @return 0 on success, negative error code on failure
+ */
+ int getsockopt(int level, int optname, void *optval, unsigned *optlen);
+
+ /** Register a callback on state change of the socket
+ *
+ * The specified callback will be called on state changes such as when
+ * the socket can recv/send/accept successfully and on when an error
+ * occurs. The callback may also be called spuriously without reason.
+ *
+ * The callback may be called in an interrupt context and should not
+ * perform expensive operations such as recv/send calls.
+ *
+ * @param callback Function to call on state change
+ */
+ void attach(FunctionPointer callback);
+
+ /** Register a callback on state change of the socket
+ *
+ * The specified callback will be called on state changes such as when
+ * the socket can recv/send/accept successfully and on when an error
+ * occurs. The callback may also be called spuriously without reason.
+ *
+ * The callback may be called in an interrupt context and should not
+ * perform expensive operations such as recv/send calls.
+ *
+ * @param tptr Pointer to object to call method on
+ * @param mptr Method to call on state change
+ */
+ template <typename T, typename M>
+ void attach(T *tptr, M mptr) {
+ attach(FunctionPointer(tptr, mptr));
+ }
+
+protected:
+ Socket();
+ int open(NetworkStack *iface, nsapi_protocol_t proto);
+
+ static void thunk(void *);
+ static void wakeup();
+
+ NetworkStack *_iface;
+ void *_socket;
+ int _timeout;
+ FunctionPointer _callback;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/SocketAddress.cpp Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,275 @@
+/* Socket
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SocketAddress.h"
+#include "NetworkStack.h"
+#include <string.h>
+#include "mbed.h"
+
+
+static bool ipv4_is_valid(const char *addr)
+{
+ int i = 0;
+
+ // Check each digit for [0-9.]
+ for (; addr[i]; i++) {
+ if (!(addr[i] >= '0' && addr[i] <= '9') && addr[i] != '.') {
+ return false;
+ }
+ }
+
+ // Ending with '.' garuntees host
+ if (i > 0 && addr[i-1] == '.') {
+ return false;
+ }
+
+ return true;
+}
+
+static bool ipv6_is_valid(const char *addr)
+{
+ // Check each digit for [0-9a-fA-F:]
+ for (int i = 0; addr[i]; i++) {
+ if (!(addr[i] >= '0' && addr[i] <= '9') &&
+ !(addr[i] >= 'a' && addr[i] <= 'f') &&
+ !(addr[i] >= 'A' && addr[i] <= 'F') &&
+ addr[i] != ':') {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void ipv4_from_address(uint8_t *bytes, const char *addr)
+{
+ int count = 0;
+ int i = 0;
+
+ for (; count < NSAPI_IPv4_BYTES; count++) {
+ int scanned = sscanf(&addr[i], "%hhu", &bytes[count]);
+ if (scanned < 1) {
+ return;
+ }
+
+ for (; addr[i] != '.'; i++) {
+ if (!addr[i]) {
+ return;
+ }
+ }
+
+ i++;
+ }
+}
+
+static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) {
+ int count = 0;
+ int i = 0;
+
+ for (; count < NSAPI_IPv6_BYTES/2; count++) {
+ int scanned = sscanf(&chunk[i], "%hx", &shorts[count]);
+ if (scanned < 1) {
+ return count;
+ }
+
+ for (; chunk[i] != ':'; i++) {
+ if (!chunk[i]) {
+ return count+1;
+ }
+ }
+
+ i++;
+ }
+
+ return count;
+}
+
+static void ipv6_from_address(uint8_t *bytes, const char *addr)
+{
+ // Start with zeroed address
+ uint16_t shorts[NSAPI_IPv6_BYTES/2];
+ memset(shorts, 0, sizeof shorts);
+
+ int suffix = 0;
+
+ // Find double colons and scan suffix
+ for (int i = 0; addr[i]; i++) {
+ if (addr[i] == ':' && addr[i+1] == ':') {
+ suffix = ipv6_scan_chunk(shorts, &addr[i+2]);
+ break;
+ }
+ }
+
+ // Move suffix to end
+ memmove(&shorts[NSAPI_IPv6_BYTES/2-suffix], &shorts[0],
+ suffix*sizeof(uint16_t));
+
+ // Scan prefix
+ ipv6_scan_chunk(shorts, &addr[0]);
+
+ // Flip bytes
+ for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
+ bytes[2*i+0] = (uint8_t)(shorts[i] >> 8);
+ bytes[2*i+1] = (uint8_t)(shorts[i] >> 0);
+ }
+}
+
+static void ipv4_to_address(char *addr, const uint8_t *bytes)
+{
+ sprintf(addr, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
+}
+
+static void ipv6_to_address(char *addr, const uint8_t *bytes)
+{
+ for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
+ sprintf(&addr[5*i], "%02x%02x", bytes[2*i], bytes[2*i+1]);
+ addr[5*i+4] = ':';
+ }
+ addr[NSAPI_IPv6_SIZE-1] = '\0';
+}
+
+
+SocketAddress::SocketAddress(NetworkStack *iface, const char *host, uint16_t port)
+{
+ memset(&_ip_address, 0, sizeof _ip_address);
+
+ // Check for valid IP addresses
+ if (host && ipv4_is_valid(host)) {
+ _ip_version = NSAPI_IPv4;
+ ipv4_from_address(_ip_bytes, host);
+ set_port(port);
+ } else if (host && ipv6_is_valid(host)) {
+ _ip_version = NSAPI_IPv6;
+ ipv6_from_address(_ip_bytes, host);
+ set_port(port);
+ } else {
+ // DNS lookup
+ int err = iface->gethostbyname(this, host);
+ if (!err) {
+ set_port(port);
+ } else {
+ _ip_version = NSAPI_IPv4;
+ memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
+ set_port(0);
+ }
+ }
+}
+
+SocketAddress::SocketAddress(const char *addr, uint16_t port)
+{
+ memset(&_ip_address, 0, sizeof _ip_address);
+ set_ip_address(addr);
+ set_port(port);
+}
+
+SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port)
+{
+ memset(&_ip_address, 0, sizeof _ip_address);
+ set_ip_bytes(bytes, version);
+ set_port(port);
+}
+
+SocketAddress::SocketAddress(const SocketAddress &addr)
+{
+ memset(&_ip_address, 0, sizeof _ip_address);
+ set_ip_bytes(addr.get_ip_bytes(), addr.get_ip_version());
+ set_port(addr.get_port());
+}
+
+void SocketAddress::set_ip_address(const char *addr)
+{
+ _ip_address[0] = '\0';
+
+ if (addr && ipv4_is_valid(addr)) {
+ _ip_version = NSAPI_IPv4;
+ ipv4_from_address(_ip_bytes, addr);
+ } else if (addr && ipv6_is_valid(addr)) {
+ _ip_version = NSAPI_IPv6;
+ ipv6_from_address(_ip_bytes, addr);
+ } else {
+ _ip_version = NSAPI_IPv4;
+ memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
+ }
+}
+
+void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version)
+{
+ _ip_address[0] = '\0';
+
+ if (version == NSAPI_IPv4) {
+ _ip_version = NSAPI_IPv4;
+ memcpy(_ip_bytes, bytes, NSAPI_IPv4_BYTES);
+ } else if (version == NSAPI_IPv6) {
+ _ip_version = NSAPI_IPv6;
+ memcpy(_ip_bytes, bytes, NSAPI_IPv6_BYTES);
+ } else {
+ _ip_version = NSAPI_IPv4;
+ memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
+ }
+}
+
+void SocketAddress::set_port(uint16_t port)
+{
+ _port = port;
+}
+
+const char *SocketAddress::get_ip_address() const
+{
+ char *ip_address = (char *)_ip_address;
+
+ if (!ip_address[0]) {
+ if (_ip_version == NSAPI_IPv4) {
+ ipv4_to_address(ip_address, _ip_bytes);
+ } else if (_ip_version == NSAPI_IPv6) {
+ ipv6_to_address(ip_address, _ip_bytes);
+ }
+ }
+
+ return ip_address;
+}
+
+const void *SocketAddress::get_ip_bytes() const
+{
+ return _ip_bytes;
+}
+
+nsapi_version_t SocketAddress::get_ip_version() const
+{
+ return _ip_version;
+}
+
+uint16_t SocketAddress::get_port() const
+{
+ return _port;
+}
+
+SocketAddress::operator bool() const
+{
+ int count = 0;
+ if (_ip_version == NSAPI_IPv4) {
+ count = NSAPI_IPv4_BYTES;
+ } else if (_ip_version == NSAPI_IPv6) {
+ count = NSAPI_IPv6_BYTES;
+ }
+
+ for (int i = 0; i < count; i++) {
+ if (_ip_bytes[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/SocketAddress.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,166 @@
+/* SocketAddress
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOCKET_ADDRESS_H
+#define SOCKET_ADDRESS_H
+
+#include <stdint.h>
+
+
+/** Maximum size of IP address representation
+ */
+#define NSAPI_IP_SIZE NSAPI_IPv6_SIZE
+
+/** Maximum number of bytes for IP address
+ */
+#define NSAPI_IP_BYTES NSAPI_IPv6_BYTES
+
+/** Maximum size of MAC address representation
+ */
+#define NSAPI_MAC_SIZE 18
+
+/** Maximum number of bytes for MAC address
+ */
+#define NSAPI_MAC_BYTES 6
+
+/** Enum of IP address versions
+ *
+ * The IP version specifies the type of an IP address.
+ *
+ * @enum nsapi_version_t
+ */
+enum nsapi_version_t {
+ NSAPI_IPv4, /*!< Address is IPv4 */
+ NSAPI_IPv6, /*!< Address is IPv6 */
+};
+
+/** Size of IPv4 representation
+ */
+#define NSAPI_IPv4_SIZE 16
+
+/** Number of bytes in IPv4 address
+ */
+#define NSAPI_IPv4_BYTES 4
+
+/** Size of IPv6 representation
+ */
+#define NSAPI_IPv6_SIZE 40
+
+/** Number of bytes in IPv6 address
+ */
+#define NSAPI_IPv6_BYTES 16
+
+// Predeclared classes
+class NetworkStack;
+
+
+/** SocketAddress class
+ *
+ * Representation of an IP address and port pair.
+ */
+class SocketAddress {
+public:
+ /** Create a SocketAddress from a hostname and port
+ *
+ * The hostname may be either a domain name or an IP address. If the
+ * hostname is an IP address, no network transactions will be performed.
+ *
+ * On failure, the IP address and port will be set to zero
+ *
+ * @param iface Network stack to use for DNS resolution
+ * @param host Hostname to resolve
+ * @param port Optional 16-bit port
+ */
+ SocketAddress(NetworkStack *iface, const char *host, uint16_t port = 0);
+
+ /** Create a SocketAddress from an IP address and port
+ *
+ * @param host Null-terminated representation of the IP address
+ * @param port Optional 16-bit port
+ */
+ SocketAddress(const char *addr = 0, uint16_t port = 0);
+
+ /** Create a SocketAddress from a raw IP address and port
+ *
+ * @param bytes Raw IP address in big-endian order
+ * @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6
+ * @param port Optional 16-bit port
+ */
+ SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port = 0);
+
+ /** Create a SocketAddress from another SocketAddress
+ *
+ * @param address SocketAddress to copy
+ */
+ SocketAddress(const SocketAddress &addr);
+
+ /** Set the IP address
+ *
+ * @param addr Null-terminated represention of the IP address
+ */
+ void set_ip_address(const char *addr);
+
+ /** Set the raw IP address
+ *
+ * @param bytes Raw IP address in big-endian order
+ * @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6
+ */
+ void set_ip_bytes(const void *bytes, nsapi_version_t version);
+
+ /** Set the port
+ *
+ * @param port 16-bit port
+ */
+ void set_port(uint16_t port);
+
+ /** Get the IP address
+ *
+ * @return Null-terminated representation of the IP Address
+ */
+ const char *get_ip_address() const;
+
+ /** Get the raw IP address
+ *
+ * @return Raw IP address in big-endian order
+ */
+ const void *get_ip_bytes() const;
+
+ /** Get the IP address version
+ *
+ * @return IP address version, NSAPI_IPv4 or NSAPI_IPv6
+ */
+ nsapi_version_t get_ip_version() const;
+
+ /** Get the port
+ *
+ * @return The 16-bit port
+ */
+ uint16_t get_port() const;
+
+ /** Test if address is zero
+ *
+ * @return True if address is not zero
+ */
+ operator bool() const;
+
+private:
+ char _ip_address[NSAPI_IP_SIZE];
+ uint8_t _ip_bytes[NSAPI_IP_BYTES];
+ nsapi_version_t _ip_version;
+ uint16_t _port;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/TCPServer.cpp Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,75 @@
+/* Socket
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TCPServer.h"
+#include "Timer.h"
+
+TCPServer::TCPServer()
+{
+}
+
+TCPServer::TCPServer(NetworkStack *iface)
+{
+ open(iface);
+}
+
+int TCPServer::open(NetworkStack *iface)
+{
+ return Socket::open(iface, NSAPI_TCP);
+}
+
+int TCPServer::listen(int backlog)
+{
+ if (!_socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ return _iface->socket_listen(_socket, backlog);
+}
+
+int TCPServer::accept(TCPSocket *connection)
+{
+ mbed::Timer timer;
+ timer.start();
+ mbed::Timeout timeout;
+ if (_timeout >= 0) {
+ timeout.attach_us(&Socket::wakeup, _timeout * 1000);
+ }
+
+ if (connection->_socket) {
+ connection->close();
+ }
+
+ while (true) {
+ if (!_socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ void *socket;
+ int err = _iface->socket_accept(&socket, _socket);
+ if (!err) {
+ connection->_iface = _iface;
+ connection->_socket = socket;
+ }
+
+ if (err != NSAPI_ERROR_WOULD_BLOCK
+ || (_timeout >= 0 && timer.read_ms() >= _timeout)) {
+ return err;
+ }
+
+ __WFI();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/TCPServer.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,79 @@
+/* TCPServer
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TCPSERVER_H
+#define TCPSERVER_H
+
+#include "Socket.h"
+#include "TCPSocket.h"
+#include "NetworkStack.h"
+
+/** TCP socket server
+ */
+class TCPServer : public Socket {
+public:
+ /** Create an uninitialized socket
+ *
+ * Must call open to initialize the socket on a network stack.
+ */
+ TCPServer();
+
+ /** Create a socket on a network stack
+ *
+ * Creates and opens a socket on the specified network stack.
+ *
+ * @param iface Network stack as target for socket
+ */
+ TCPServer(NetworkStack *iface);
+
+ /** Opens a socket
+ *
+ * Creates a network socket on the specified network stack.
+ * Not needed if stack is passed to the socket's constructor.
+ *
+ * @param iface Network stack as target for socket
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int open(NetworkStack *iface);
+
+ /** Listen for connections on a TCP socket
+ *
+ * Marks the socket as a passive socket that can be used to accept
+ * incoming connections.
+ *
+ * @param backlog Number of pending connections that can be queued
+ * simultaneously, defaults to 1
+ * @return 0 on success, negative error code on failure
+ */
+ int listen(int backlog = 1);
+
+ /** Accepts a connection on a TCP socket
+ *
+ * The server socket must be bound and set to listen for connections.
+ * On a new connection, creates a network socket using the specified
+ * socket instance.
+ *
+ * By default, accept blocks until data is sent. If socket is set to
+ * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
+ * immediately.
+ *
+ * @param socket TCPSocket instance that will handle the incoming connection.
+ * @return 0 on success, negative error code on failure
+ */
+ int accept(TCPSocket *connection);
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/TCPSocket.cpp Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,100 @@
+/* Socket
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TCPSocket.h"
+#include "Timer.h"
+
+TCPSocket::TCPSocket(bool isTLS) : _isTLS(isTLS)
+{
+}
+
+TCPSocket::TCPSocket(NetworkStack *iface)
+{
+ open(iface);
+}
+
+int TCPSocket::open(NetworkStack *iface)
+{
+ return Socket::open(iface, _isTLS ? NSAPI_TLS : NSAPI_TCP);
+}
+
+int TCPSocket::connect(const SocketAddress &addr)
+{
+ if (!_socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ return _iface->socket_connect(_socket, addr);
+}
+
+
+int TCPSocket::connect(const char *host, uint16_t port)
+{
+ SocketAddress addr(_iface, host, port);
+ if (!addr) {
+ return NSAPI_ERROR_DNS_FAILURE;
+ }
+
+ return connect(addr);
+}
+
+int TCPSocket::send(const void *data, unsigned size)
+{
+ mbed::Timer timer;
+ timer.start();
+ mbed::Timeout timeout;
+ if (_timeout >= 0) {
+ timeout.attach_us(&Socket::wakeup, _timeout * 1000);
+ }
+
+ while (true) {
+ if (!_socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ int sent = _iface->socket_send(_socket, data, size);
+ if (sent != NSAPI_ERROR_WOULD_BLOCK
+ || (_timeout >= 0 && timer.read_ms() >= _timeout)) {
+ return sent;
+ }
+
+ __WFI();
+ }
+}
+
+int TCPSocket::recv(void *data, unsigned size)
+{
+ mbed::Timer timer;
+ timer.start();
+ mbed::Timeout timeout;
+ if (_timeout >= 0) {
+ timeout.attach_us(&Socket::wakeup, _timeout * 1000);
+ }
+
+ while (true) {
+ if (!_socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ int recv = _iface->socket_recv(_socket, data, size);
+ if (recv != NSAPI_ERROR_WOULD_BLOCK
+ || (_timeout >= 0 && timer.read_ms() >= _timeout)) {
+ return recv;
+ }
+
+ __WFI();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/TCPSocket.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,110 @@
+/* TCPSocket
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TCPSOCKET_H
+#define TCPSOCKET_H
+
+#include "Socket.h"
+#include "NetworkStack.h"
+
+/** TCP socket connection
+ */
+class TCPSocket : public Socket {
+public:
+ /** Create an uninitialized socket
+ *
+ * Must call open to initialize the socket on a network stack.
+ */
+ TCPSocket(bool isTLS = false);
+
+ /** Create a socket on a network stack
+ *
+ * Creates and opens a socket on the specified network stack.
+ *
+ * @param iface Network stack as target for socket
+ */
+ TCPSocket(NetworkStack *iface);
+
+ /** Opens a socket
+ *
+ * Creates a network socket on the specified network stack.
+ * Not needed if stack is passed to the socket's constructor.
+ *
+ * @param iface Network stack as target for socket
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int open(NetworkStack *iface);
+
+ /** Connects TCP socket to a remote host
+ *
+ * Initiates a connection to a remote server specified by either
+ * a domain name or an IP address and a port.
+ *
+ * @param host Hostname of the remote host
+ * @param port Port of the remote host
+ * @return 0 on success, negative error code on failure
+ */
+ int connect(const char *host, uint16_t port);
+
+ /** Connects TCP socket to a remote host
+ *
+ * Initiates a connection to a remote server specified by the
+ * indicated address.
+ *
+ * @param address The SocketAddress of the remote host
+ * @return 0 on success, negative error code on failure
+ */
+ int connect(const SocketAddress &address);
+
+ /** Send data over a TCP socket
+ *
+ * The socket must be connected to a remote host. Returns the number of
+ * bytes sent from the buffer.
+ *
+ * By default, send blocks until data is sent. If socket is set to
+ * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
+ * immediately.
+ *
+ * @param data Buffer of data to send to the host
+ * @param size Size of the buffer in bytes
+ * @return Number of sent bytes on success, negative error
+ * code on failure
+ */
+ int send(const void *data, unsigned size);
+
+ /** Receive data over a TCP socket
+ *
+ * The socket must be connected to a remote host. Returns the number of
+ * bytes received into the buffer.
+ *
+ * By default, recv blocks until data is sent. If socket is set to
+ * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
+ * immediately.
+ *
+ * @param data Destination buffer for data received from the host
+ * @param size Size of the buffer in bytes
+ * @return Number of received bytes on success, negative error
+ * code on failure
+ */
+ int recv(void *data, unsigned size);
+
+private:
+ friend class TCPServer;
+
+ bool _isTLS;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/UDPSocket.cpp Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,90 @@
+/* Socket
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "UDPSocket.h"
+#include "Timer.h"
+
+UDPSocket::UDPSocket()
+{
+}
+
+UDPSocket::UDPSocket(NetworkStack *iface)
+{
+ open(iface);
+}
+
+int UDPSocket::open(NetworkStack *iface)
+{
+ return Socket::open(iface, NSAPI_UDP);
+}
+
+int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigned size)
+{
+ SocketAddress addr(_iface, host, port);
+ if (!addr) {
+ return NSAPI_ERROR_DNS_FAILURE;
+ }
+
+ return sendto(addr, data, size);
+}
+
+int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned size)
+{
+ mbed::Timer timer;
+ timer.start();
+ mbed::Timeout timeout;
+ if (_timeout >= 0) {
+ timeout.attach_us(&Socket::wakeup, _timeout * 1000);
+ }
+
+ while (true) {
+ if (!_socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ int sent = _iface->socket_sendto(_socket, address, data, size);
+ if (sent != NSAPI_ERROR_WOULD_BLOCK
+ || (_timeout >= 0 && timer.read_ms() >= _timeout)) {
+ return sent;
+ }
+
+ __WFI();
+ }
+}
+
+int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size)
+{
+ mbed::Timer timer;
+ timer.start();
+ mbed::Timeout timeout;
+ if (_timeout >= 0) {
+ timeout.attach_us(&Socket::wakeup, _timeout * 1000);
+ }
+
+ while (true) {
+ if (!_socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ int recv = _iface->socket_recvfrom(_socket, address, buffer, size);
+ if (recv != NSAPI_ERROR_WOULD_BLOCK
+ || (_timeout >= 0 && timer.read_ms() >= _timeout)) {
+ return recv;
+ }
+
+ __WFI();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/UDPSocket.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,105 @@
+/* UDPSocket
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UDPSOCKET_H
+#define UDPSOCKET_H
+
+#include "Socket.h"
+#include "NetworkStack.h"
+
+/** UDP socket
+ */
+class UDPSocket : public Socket {
+public:
+ /** Create an uninitialized socket
+ *
+ * Must call open to initialize the socket on a network stack.
+ */
+ UDPSocket();
+
+ /** Create a socket on a network stack
+ *
+ * Creates and opens a socket on the specified network stack.
+ *
+ * @param iface Network stack as target for socket
+ */
+ UDPSocket(NetworkStack *iface);
+
+ /** Opens a socket
+ *
+ * Creates a network socket on the specified network stack.
+ * Not needed if stack is passed to the socket's constructor.
+ *
+ * @param iface Network stack as target for socket
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int open(NetworkStack *iface);
+
+ /** Send a packet over a UDP socket
+ *
+ * Sends data to the specified address specified by either a domain name
+ * or an IP address and port. Returns the number of bytes sent from the
+ * buffer.
+ *
+ * By default, sendto blocks until data is sent. If socket is set to
+ * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
+ * immediately.
+ *
+ * @param host Hostname of the remote host
+ * @param port Port of the remote host
+ * @param data Buffer of data to send to the host
+ * @param size Size of the buffer in bytes
+ * @return Number of sent bytes on success, negative error
+ * code on failure
+ */
+ int sendto(const char *host, uint16_t port, const void *data, unsigned size);
+
+ /** Send a packet over a UDP socket
+ *
+ * Sends data to the specified address. Returns the number of bytes
+ * sent from the buffer.
+ *
+ * By default, sendto blocks until data is sent. If socket is set to
+ * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
+ * immediately.
+ *
+ * @param address The SocketAddress of the remote host
+ * @param data Buffer of data to send to the host
+ * @param size Size of the buffer in bytes
+ * @return Number of sent bytes on success, negative error
+ * code on failure
+ */
+ int sendto(const SocketAddress &address, const void *data, unsigned size);
+
+ /** Receive a packet over a UDP socket
+ *
+ * Receives data and stores the source address in address if address
+ * is not NULL. Returns the number of bytes received into the buffer.
+ *
+ * By default, recvfrom blocks until data is sent. If socket is set to
+ * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
+ * immediately.
+ *
+ * @param address Destination for the source address or NULL
+ * @param data Destination buffer for data received from the host
+ * @param size Size of the buffer in bytes
+ * @return Number of received bytes on success, negative error
+ * code on failure
+ */
+ int recvfrom(SocketAddress *address, void *data, unsigned size);
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkSocketAPI/WiFiInterface.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,68 @@
+/* WiFiInterface
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_INTERFACE_H
+#define WIFI_INTERFACE_H
+
+#include "NetworkStack.h"
+
+/** Enum of WiFi encryption types
+ *
+ * The security type specifies a particular security to use when
+ * connected to a WiFi network
+ *
+ * @enum nsapi_protocol_t
+ */
+enum nsapi_security_t {
+ NSAPI_SECURITY_NONE = 0, /*!< open access point */
+ NSAPI_SECURITY_WEP, /*!< phrase conforms to WEP */
+ NSAPI_SECURITY_WPA, /*!< phrase conforms to WPA */
+ NSAPI_SECURITY_WPA2, /*!< phrase conforms to WPA2 */
+};
+
+/** WiFiInterface class
+ *
+ * Common interface that is shared between WiFi devices
+ */
+class WiFiInterface
+{
+public:
+ /** Start the interface
+ *
+ * Attempts to connect to a WiFi network. If passphrase is invalid,
+ * NSAPI_ERROR_AUTH_ERROR is returned.
+ *
+ * @param ssid Name of the network to connect to
+ * @param pass Security passphrase to connect to the network
+ * @param security Type of encryption for connection
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE) = 0;
+
+ /** Stop the interface
+ *
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int disconnect() = 0;
+
+ /** Get the local MAC address
+ *
+ * @return Null-terminated representation of the local MAC address
+ */
+ virtual const char *get_mac_address() = 0;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/X_NUCLEO_IDW01M1v2/NOTICE.txt Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,7 @@ +This library is originated from: https://developer.mbed.org/teams/ST/code/X_NUCLEO_IDW01M1v2/#0368732b5b9d +"class SpwfSAInterface" is extended with: + - method to setup WiFi module security parameters + - method to initiate hardware reset of WiFi module + - security socket support + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/X_NUCLEO_IDW01M1v2/SPWF01SA/ATParser.lib Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,1 @@ +https://developer.mbed.org/teams/ST/code/ATParser/#ea155e6b1fb1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/X_NUCLEO_IDW01M1v2/SPWF01SA/NOTICE.txt Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,12 @@ +This library is originated from https://developer.mbed.org/teams/ST/code/SPWF01SA/#419285201dba +It is extended with: + - TLS parameters setup + - Increased ATParser buffer size + - next wifi parameters are hardcoded to obtain higher robustness of WiFi Module: + * high-speed transfer mode is switched off + * operational rate is limited to 1 Mbit + * basic data rates are limited to 802.11ab + * transmit power is forced to maximum + * power saving and sleep mode is switched off + * dhcp is forced to be switched on + * dhcp timeout is forced to 20 seconds
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/X_NUCLEO_IDW01M1v2/SPWF01SA/SPWFSA01.cpp Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,492 @@
+/* SPWFInterface Example
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SPWFSA01.h"
+#include "mbed_debug.h"
+#include "stdint.h"
+
+#define SPWFSA01_CONNECT_TIMEOUT 15000
+#define SPWFSA01_SEND_TIMEOUT 500
+#define SPWFSA01_RECV_TIMEOUT 1500//some commands like AT&F/W takes some time to get the result back!
+#define SPWFSA01_MISC_TIMEOUT 500
+#define SPWFSA01_SOCKQ_TIMEOUT 3000
+
+#define EPOCH_TIME 1453727657//Human time (GMT): Mon, 25 Jan 2016 13:14:17 GMT
+
+ SPWFSA01::SPWFSA01(PinName tx, PinName rx, PinName reset, PinName wakeup, bool debug)
+ : _serial(tx, rx, 1024), _parser(_serial,"\r\n", 2048),
+ _wakeup(wakeup, PIN_OUTPUT, PullNone, 0),
+ _reset(reset, PIN_OUTPUT, PullNone, 1),
+ dbg_on(debug)
+{
+ _serial.baud(115200); // LICIO FIXME increase the speed
+ _parser.debugOn(debug);
+}
+
+bool SPWFSA01::startup(int mode)
+{
+ _parser.setTimeout(SPWFSA01_MISC_TIMEOUT);
+ /*Test module before reset*/
+ waitSPWFReady();
+ /*Reset module*/
+ reset();
+
+ /*set local echo to 0*/
+ if(!(_parser.send("AT+S.SCFG=localecho1,%d\r", 0) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error local echo set\r\n");
+ return false;
+ }
+ /*reset factory settings*/
+ if(!(_parser.send("AT&F") && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error AT&F\r\n");
+ return false;
+ }
+
+ /*set Wi-Fi mode and rate to b/g*/
+ if(!(_parser.send("AT+S.SCFG=wifi_ht_mode,%d\r", 0) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error setting ht_mode\r\n");
+ return false;
+ }
+
+ //if(!(_parser.send("AT+S.SCFG=wifi_opr_rate_mask,0x003FFFCF\r") && _parser.recv("OK")))
+ if(!(_parser.send("AT+S.SCFG=wifi_opr_rate_mask,0x00000001\r") && _parser.recv("OK")))// set most effective speed for such kind of device
+ {
+ debug_if(dbg_on, "SPWF> error setting operational rates\r\n");
+ return false;
+ }
+
+ if(!(_parser.send("AT+S.SCFG=wifi_bas_rate_mask,0x0000000F\r") && _parser.recv("OK")))// set most effective speed for such kind of device
+ {
+ debug_if(dbg_on, "SPWF> error setting basic rates\r\n");
+ return false;
+ }
+
+ if(!(_parser.send("AT+S.SCFG=wifi_powersave,0\r") && _parser.recv("OK")))// set most effective speed for such kind of device
+ {
+ debug_if(dbg_on, "SPWF> error setting power save mode\r\n");
+ return false;
+ }
+
+ if(!(_parser.send("AT+S.SCFG=sleep_enabled,0\r") && _parser.recv("OK")))// set most effective speed for such kind of device
+ {
+ debug_if(dbg_on, "SPWF> error setting sleep mode\r\n");
+ return false;
+ }
+
+ if(!(_parser.send("AT+S.SCFG=wifi_tx_power,18\r") && _parser.recv("OK")))// set most effective speed for such kind of device
+ {
+ debug_if(dbg_on, "SPWF> error setting transmit power\r\n");
+ return false;
+ }
+
+ if(!(_parser.send("AT+S.SCFG=ip_use_dhcp,1\r") && _parser.recv("OK")))// set most effective speed for such kind of device
+ {
+ debug_if(dbg_on, "SPWF> error setting dhcp on\r\n");
+ return false;
+ }
+
+ if(!(_parser.send("AT+S.SCFG=ip_dhcp_timeout,20\r") && _parser.recv("OK")))// set most effective speed for such kind of device
+ {
+ debug_if(dbg_on, "SPWF> error setting dhcp timeout\r\n");
+ return false;
+ }
+
+ /*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/
+ if(!(_parser.send("AT+S.SCFG=wifi_mode,%d\r", mode) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error wifi mode set\r\n");
+ return false;
+ }
+
+ /* save current setting in flash */
+ if(!(_parser.send("AT&W") && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error AT&W\r\n");
+ return false;
+ }
+
+ /*reset again and send AT command and check for result (AT->OK)*/
+ reset();
+
+ return true;
+}
+
+bool SPWFSA01::hw_reset(void)
+{
+ if (_reset.is_connected()) {
+ /* reset the pin PC12 */
+ _reset.write(0);
+ wait_ms(200);
+ _reset.write(1);
+ wait_ms(100);
+ return 1;
+ } else { return 0; }
+}
+
+bool SPWFSA01::reset(void)
+{
+ if(!_parser.send("AT+CFUN=1")) return false;
+ while(1) {
+ if (_parser.recv("+WIND:32:WiFi Hardware Started\r")) {
+ return true;
+ }
+ }
+}
+
+void SPWFSA01::waitSPWFReady(void)
+{
+ //wait_ms(200);
+ while(1)
+ if(_parser.send("AT") && _parser.recv("OK"))
+ //till we get OK from AT command
+ //printf("\r\nwaiting for reset to complete..\n");
+ return;
+
+}
+
+/* Security Mode
+ None = 0,
+ WEP = 1,
+ WPA_Personal = 2,
+*/
+bool SPWFSA01::connect(const char *ap, const char *passPhrase, int securityMode)
+{
+ uint32_t n1, n2, n3, n4;
+
+ _parser.setTimeout(SPWFSA01_CONNECT_TIMEOUT);
+ //AT+S.SCFG=wifi_wpa_psk_text,%s\r
+ if(!(_parser.send("AT+S.SCFG=wifi_wpa_psk_text,%s", passPhrase) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error pass set\r\n");
+ return false;
+ }
+ //AT+S.SSIDTXT=%s\r
+ if(!(_parser.send("AT+S.SSIDTXT=%s", ap) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error ssid set\r\n");
+ return false;
+ }
+ //AT+S.SCFG=wifi_priv_mode,%d\r
+ if(!(_parser.send("AT+S.SCFG=wifi_priv_mode,%d", securityMode) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error security mode set\r\n");
+ return false;
+ }
+ //"AT+S.SCFG=wifi_mode,%d\r"
+ /*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/
+ if(!(_parser.send("AT+S.SCFG=wifi_mode,%d\r", 1) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error wifi mode set\r\n");
+ return false;
+ }
+ //AT&W
+ /* save current setting in flash */
+ if(!(_parser.send("AT&W") && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error AT&W\r\n");
+ return false;
+ }
+ //reset module
+ reset();
+
+ while(1)
+ if((_parser.recv("+WIND:24:WiFi Up:%u.%u.%u.%u",&n1, &n2, &n3, &n4)))
+ {
+ break;
+ }
+
+ return true;
+}
+
+bool SPWFSA01::disconnect(void)
+{
+ //"AT+S.SCFG=wifi_mode,%d\r"
+ /*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/
+ if(!(_parser.send("AT+S.SCFG=wifi_mode,%d\r", 0) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error wifi mode set\r\n");
+ return false;
+ }
+ //AT&W
+ /* save current setting in flash */
+ if(!(_parser.send("AT&W") && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error AT&W\r\n");
+ return false;
+ }
+ //reset module
+ reset();
+ return true;
+}
+
+bool SPWFSA01::dhcp(int mode)
+{
+ //only 3 valid modes
+ //0->off(ip_addr must be set by user), 1->on(auto set by AP), 2->on&customize(miniAP ip_addr can be set by user)
+ if(mode < 0 || mode > 2) {
+ return false;
+ }
+
+ return _parser.send("AT+S.SCFG=ip_use_dhcp,%d\r", mode)
+ && _parser.recv("OK");
+}
+
+
+const char *SPWFSA01::getIPAddress(void)
+{
+ uint32_t n1, n2, n3, n4;
+
+ if (!(_parser.send("AT+S.STS=ip_ipaddr")
+ && _parser.recv("# ip_ipaddr = %u.%u.%u.%u", &n1, &n2, &n3, &n4)
+ && _parser.recv("OK"))) {
+ debug_if(dbg_on, "SPWF> getIPAddress error\r\n");
+ return 0;
+ }
+
+ sprintf((char*)_ip_buffer,"%u.%u.%u.%u", n1, n2, n3, n4);
+
+ return _ip_buffer;
+}
+
+const char *SPWFSA01::getMACAddress(void)
+{
+ uint32_t n1, n2, n3, n4, n5, n6;
+
+ if (!(_parser.send("AT+S.GCFG=nv_wifi_macaddr")
+ && _parser.recv("# nv_wifi_macaddr = %x:%x:%x:%x:%x:%x", &n1, &n2, &n3, &n4, &n5, &n6)
+ && _parser.recv("OK"))) {
+ debug_if(dbg_on, "SPWF> getMACAddress error\r\n");
+ return 0;
+ }
+
+ sprintf((char*)_mac_buffer,"%02X:%02X:%02X:%02X:%02X:%02X", n1, n2, n3, n4, n5, n6);
+
+ return _mac_buffer;
+}
+
+bool SPWFSA01::isConnected(void)
+{
+ return getIPAddress() != 0;
+}
+
+bool SPWFSA01::open(const char *type, int* id, const char* addr, int port)
+{
+ Timer timer;
+ timer.start();
+ socket_closed = 0;
+
+ if(!_parser.send("AT+S.SOCKON=%s,%d,%s,ind", addr, port, type))
+ {
+ debug_if(dbg_on, "SPWF> error opening socket\r\n");
+ return false;
+ }
+
+ while(1)
+ {
+ if( _parser.recv(" ID: %d", id)
+ && _parser.recv("OK"))
+ break;
+
+ if (timer.read_ms() > SPWFSA01_CONNECT_TIMEOUT) {
+ return false;
+ }
+
+ //TODO:implement time-out functionality in case of no response
+ //if(timeout) return false;
+ //TODO: deal with errors like "ERROR: Failed to resolve name"
+ //TODO: deal with errors like "ERROR: Data mode not available"
+ }
+
+ return true;
+}
+
+bool SPWFSA01::send(int id, const void *data, uint32_t amount)
+{
+ char _buf[18];
+ _parser.setTimeout(SPWFSA01_SEND_TIMEOUT);
+
+ sprintf((char*)_buf,"AT+S.SOCKW=%d,%d\r", id, amount);
+
+ //May take a second try if device is busy
+ for (unsigned i = 0; i < 2; i++) {
+ if (_parser.write((char*)_buf, strlen(_buf)) >=0
+ && _parser.write((char*)data, (int)amount) >= 0
+ && _parser.recv("OK")) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+int32_t SPWFSA01::recv(int id, void *data, uint32_t amount)
+{
+ uint32_t recv_amount=0;
+ int wind_id;
+
+ if (socket_closed) {
+ socket_closed = 0;
+ return -3;
+ }
+ if(!(_parser.send("AT+S.SOCKQ=%d", id) //send a query (will be required for secure sockets)
+ && _parser.recv(" DATALEN: %u", &recv_amount)
+ && _parser.recv("OK"))) {
+ return -2;
+ }
+ if (recv_amount==0) { return -1; }
+ if(recv_amount > amount)
+ recv_amount = amount;
+
+ int par_timeout = _parser.getTimeout();
+ _parser.setTimeout(0);
+
+ while(_parser.recv("+WIND:%d:", &wind_id)) {
+// printf("Wind received: %d\n\r", wind_id);
+ if (wind_id == 58) {
+ socket_closed = 1;
+ _parser.flush();
+ }
+ }
+ _parser.setTimeout(par_timeout);
+
+ _parser.flush();
+ if(!(_parser.send("AT+S.SOCKR=%d,%d", id, recv_amount))){
+ return -2;
+ }
+ if(!((_parser.read((char*)data, recv_amount) >0)
+ && _parser.recv("OK"))) {
+ return -2;
+ }
+ return recv_amount;
+}
+
+bool SPWFSA01::close(int id)
+{
+ uint32_t recv_amount=0;
+ void * data = NULL;
+
+ _parser.setTimeout(SPWFSA01_MISC_TIMEOUT);
+ _parser.flush();
+ /* socket flush */
+ if(!(_parser.send("AT+S.SOCKQ=%d", id) //send a query (will be required for secure sockets)
+ && _parser.recv(" DATALEN: %u", &recv_amount)
+ && _parser.recv("OK"))) {
+ return -2;
+ }
+ if (recv_amount>0) {
+ data = malloc (recv_amount+4);
+ if(!(_parser.send("AT+S.SOCKR=%d,%d", id, recv_amount))) {
+ free (data);
+ return -2;
+ }
+ // printf ("--->>>Close flushing recv_amount: %d \n\r",recv_amount);
+ if(!((_parser.read((char*)data, recv_amount) >0)
+ && _parser.recv("OK"))) {
+ free (data);
+ return -2;
+ }
+ free (data);
+ }
+
+ //May take a second try if device is busy or error is returned
+ for (unsigned i = 0; i < 2; i++) {
+ if (_parser.send("AT+S.SOCKC=%d", id)
+ && _parser.recv("OK")) {
+ socket_closed = 1;
+ return true;
+ }
+ else
+ {
+ if(_parser.recv("ERROR: Pending data")) {
+ debug_if(dbg_on, "SPWF> ERROR!!!!\r\n");
+ return false;
+ }
+ }
+ //TODO: Deal with "ERROR: Pending data" (Closing a socket with pending data)
+ }
+ return false;
+}
+
+
+bool SPWFSA01::readable()
+{
+ return _serial.readable();
+}
+
+bool SPWFSA01::writeable()
+{
+ return _serial.writeable();
+}
+
+int SPWFSA01::setSocketClientSecurity(uint8_t* tls_mode, uint8_t* root_ca_server, uint8_t* client_cert, uint8_t* client_key, uint8_t* client_domain, uint32_t tls_epoch_time)
+{
+ int err = 0;
+ unsigned long epoch_time;
+
+ if(!(_parser.send("AT+S.TLSCERT2=clean,all\r", 0) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> TLSCERT2 cleared\r\n");
+ return -1;
+ }
+
+ if(tls_epoch_time==0)
+ epoch_time = EPOCH_TIME;
+ else
+ epoch_time = tls_epoch_time;
+
+ if(!(_parser.send("AT+S.SETTIME=%lu\r", (unsigned long)epoch_time) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> time is set to %d\r\n", epoch_time);
+ return -1;
+ }
+
+ /*AT+S.TLSCERT=f_ca,<size><CR><data>*/
+ if(!(_parser.send("AT+S.TLSCERT=f_ca,%d\r%s\r", strlen((const char *)root_ca_server) - 1, root_ca_server) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error TLSCERT=f_ca set\r\n");
+ return -1;
+ }
+
+ /*AT+S.TLSCERT=f_cert,<size><CR><data>*/
+ if(tls_mode[0]=='m')
+ {
+ if(!(_parser.send("AT+S.TLSCERT=f_cert,%d\r%s", strlen((const char *)client_cert) - 1, client_cert) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error TLSCERT=f_cert set\r\n");
+ return -1;
+ }
+
+ /*AT+S.TLSCERT=f_key,<size><CR><data>*/
+ if(!(_parser.send("AT+S.TLSCERT=f_key,%d\r%s", strlen((const char *)client_key) - 1, client_key) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error TLSCERT=f_key set\r\n");
+ return -1;
+ }
+ }
+
+ /*AT+S.TLSDOMAIN=f_domain,<server domain>*/
+ if(!(_parser.send("AT+S.TLSDOMAIN=f_domain,%s\r", client_domain) && _parser.recv("OK")))
+ {
+ debug_if(dbg_on, "SPWF> error TLSDOMAIN=f_domain set\r\n");
+ return -1;
+ }
+
+ return err;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/X_NUCLEO_IDW01M1v2/SPWF01SA/SPWFSA01.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,168 @@
+/* SPWFInterface Example
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SPWFSA01_H
+#define SPWFSA01_H
+
+#include "ATParser.h"
+
+/** SPWFSA01Interface class.
+ This is an interface to a SPWFSA01 module.
+ */
+class SPWFSA01
+{
+public:
+
+ SPWFSA01(PinName tx, PinName rx, PinName reset=NC, PinName wakeup=NC, bool debug=false);
+
+ /**
+ * Init the SPWFSA01
+ *
+ * @param mode mode in which to startup
+ * @return true only if SPWFSA01 has started up correctly
+ */
+ bool startup(int mode);
+
+ void waitSPWFReady(void);
+ /**
+ * Reset SPWFSA01
+ *
+ * @return true only if SPWFSA01 resets successfully
+ */
+ bool reset(void);
+
+ bool hw_reset(void);
+
+ /**
+ * Enable/Disable DHCP
+ *
+ * @param mode mode of DHCP 2-softAP, 1-on, 0-off
+ * @return true only if SPWFSA01 enables/disables DHCP successfully
+ */
+ bool dhcp(int mode);
+
+ /**
+ * Connect SPWFSA01 to AP
+ *
+ * @param ap the name of the AP
+ * @param passPhrase the password of AP
+ * @param securityMode the security mode of AP (WPA/WPA2, WEP, Open)
+ * @return true only if SPWFSA01 is connected successfully
+ */
+ bool connect(const char *ap, const char *passPhrase, int securityMode);
+
+ /**
+ * Disconnect SPWFSA01 from AP
+ *
+ * @return true only if SPWFSA01 is disconnected successfully
+ */
+ bool disconnect(void);
+
+ /**
+ * Get the IP address of SPWFSA01
+ *
+ * @return null-teriminated IP address or null if no IP address is assigned
+ */
+ const char *getIPAddress(void);
+
+ /**
+ * Get the MAC address of SPWFSA01
+ *
+ * @return null-terminated MAC address or null if no MAC address is assigned
+ */
+ const char *getMACAddress(void);
+
+ /**
+ * Check if SPWFSA01 is conenected
+ *
+ * @return true only if the chip has an IP address
+ */
+ bool isConnected(void);
+
+ /**
+ * @brief wifi_socket_client_security
+ * Set the security certificates and key for secure socket (TLS)
+ * @param None
+ * @retval return nonzero in case of error
+ */
+ int setSocketClientSecurity(uint8_t* tls_mode, uint8_t* root_ca_server, uint8_t* client_cert, uint8_t* client_key, uint8_t* client_domain, uint32_t tls_epoch_time);
+
+ /**
+ * Open a socketed connection
+ *
+ * @param type the type of socket to open "u" (UDP) or "t" (TCP)
+ * @param id id to get the new socket number, valid 0-7
+ * @param port port to open connection with
+ * @param addr the IP address of the destination
+ * @return true only if socket opened successfully
+ */
+ bool open(const char *type, int* id, const char* addr, int port);
+
+ /**
+ * Sends data to an open socket
+ *
+ * @param id id of socket to send to
+ * @param data data to be sent
+ * @param amount amount of data to be sent - max 1024
+ * @return true only if data sent successfully
+ */
+ bool send(int id, const void *data, uint32_t amount);
+
+ /**
+ * Receives data from an open socket
+ *
+ * @param id id to receive from
+ * @param data placeholder for returned information
+ * @param amount number of bytes to be received
+ * @return the number of bytes received
+ */
+ int32_t recv(int id, void *data, uint32_t amount);
+
+ /**
+ * Closes a socket
+ *
+ * @param id id of socket to close, valid only 0-4
+ * @return true only if socket is closed successfully
+ */
+ bool close(int id);
+
+
+ /**
+ * Checks if data is available
+ */
+ bool readable();
+
+ /**
+ * Checks if data can be written
+ */
+ bool writeable();
+
+private:
+ BufferedSerial _serial;
+ ATParser _parser;
+ DigitalInOut _wakeup;
+ DigitalInOut _reset;
+ char _ip_buffer[16];
+ char _mac_buffer[18];
+ bool dbg_on;
+// int _timeout; // FIXME LICIO we have "virtual" socket tmo, module socket tmo,
+// AT parser tmo, recv/send tmo, actually used the NetworksocketAPI socket tmo
+ unsigned int _recv_timeout; // see SO_RCVTIMEO setsockopt
+ unsigned int _send_timeout; // see SO_SNDTIMEO setsockopt
+ unsigned int socket_closed;
+};
+
+#endif //SPWFSA01_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/X_NUCLEO_IDW01M1v2/SpwfInterface.cpp Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,464 @@
+/* mbed Microcontroller Library
+* Copyright (c) 20015 ARM Limited
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+/**
+ ******************************************************************************
+ * @file SpwfInterface.cpp
+ * @author STMicroelectronics
+ * @brief Implementation of the NetworkStack for the SPWF Device
+ ******************************************************************************
+ * @copy
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+#include "SpwfInterface.h"
+
+// Various timeouts for different SPWF operations
+#define SPWF_CONNECT_TIMEOUT 20000
+#define SPWF_SEND_TIMEOUT 500
+#define SPWF_RECV_TIMEOUT 500
+#define SPWF_MISC_TIMEOUT 15000
+
+/** spwf_socket class
+ * Implementation of SPWF socket structure
+ */
+struct spwf_socket {
+ int id;
+ int server_port;
+ nsapi_protocol_t proto;
+ bool connected;
+};
+
+
+/**
+* @brief SpwfSAInterface constructor
+* @param tx: Pin USART TX
+* rx: Pin USART RX
+* rst: reset pin for Spwf module
+* wkup: reset pin for Spwf module
+* rts: Pin USART RTS
+* debug : not used
+* @retval none
+*/
+SpwfSAInterface::SpwfSAInterface(PinName tx, PinName rx, bool debug)
+ : _spwf(tx, rx, PC_12, PC_8, debug)
+{
+ memset(_ids, 0, sizeof(_ids));
+ isInitialized = false;
+ isListening = false;
+}
+
+SpwfSAInterface::SpwfSAInterface(PinName tx, PinName rx, PinName reset, PinName wakeup, bool debug)
+ : _spwf(tx, rx, reset, wakeup, debug)
+{
+ memset(_ids, 0, sizeof(_ids));
+ isInitialized = false;
+ isListening = false;
+}
+
+/**
+* @brief SpwfSAInterface destructor
+* @param none
+* @retval none
+*/
+SpwfSAInterface::~SpwfSAInterface()
+{
+}
+
+/**
+* @brief init function
+ initializes SPWF FW and module
+* @param none
+* @retval error value
+*/
+int SpwfSAInterface::init(void)
+{
+ if(_spwf.startup(0)) {
+ isInitialized=true;
+ return true;
+ }
+ else return NSAPI_ERROR_DEVICE_ERROR;
+}
+
+/**
+* @brief network connect
+ connects to Access Point
+* @param ap: Access Point (AP) Name String
+* pass_phrase: Password String for AP
+* security: type of NSAPI security supported
+* @retval NSAPI Error Type
+*/
+int SpwfSAInterface::connect(const char *ap,
+ const char *pass_phrase,
+ nsapi_security_t security)
+{
+ int mode;
+
+ //initialize the device before connecting
+ if(!isInitialized)
+ {
+ if(!init())
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ switch(security)
+ {
+ case NSAPI_SECURITY_NONE:
+ mode = 0;
+ pass_phrase = NULL;
+ break;
+ case NSAPI_SECURITY_WEP:
+ mode = 1;
+ break;
+ case NSAPI_SECURITY_WPA:
+ case NSAPI_SECURITY_WPA2:
+ mode = 2;
+ break;
+ default:
+ mode = 2;
+ break;
+ }
+ return (_spwf.connect((char*)ap, (char*)pass_phrase, mode));
+}
+
+/**
+* @brief network disconnect
+ disconnects from Access Point
+* @param none
+* @retval NSAPI Error Type
+*/
+int SpwfSAInterface::disconnect()
+{
+ return (_spwf.disconnect());
+}
+
+/**
+* @brief Get the local IP address
+* @param none
+* @retval Null-terminated representation of the local IP address
+* or null if not yet connected
+*/
+const char *SpwfSAInterface::get_ip_address()
+{
+ return _spwf.getIPAddress();
+}
+
+/**
+* @brief Get the MAC address
+* @param none
+* @retval Null-terminated representation of the MAC address
+* or null if not yet connected
+*/
+const char *SpwfSAInterface::get_mac_address()
+{
+ return _spwf.getMACAddress();
+}
+
+/**
+* @brief open a socket handle
+* @param handle: Pointer to handle
+* proto: TCP/UDP protocol
+* @retval NSAPI Error Type
+*/
+int SpwfSAInterface::socket_open(void **handle, nsapi_protocol_t proto)
+{
+ int id = -1;
+
+ struct spwf_socket *socket = new struct spwf_socket;
+ if (!socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ socket->id = id;
+ socket->server_port = id;
+ socket->proto = proto;
+ socket->connected = false;
+ *handle = socket;
+ return 0;
+}
+
+/**
+* @brief connect to a remote socket
+* @param handle: Pointer to socket handle
+* addr: Address to connect to
+* @retval NSAPI Error Type
+*/
+int SpwfSAInterface::socket_connect(void *handle, const SocketAddress &addr)
+{
+ int sock_id = 99;
+ struct spwf_socket *socket = (struct spwf_socket *)handle;
+ const char *proto;
+
+ switch (socket->proto)
+ {
+ case NSAPI_UDP:
+ proto = "u";
+ break;
+
+ case NSAPI_TCP:
+ proto = "t";
+ break;
+
+ case NSAPI_TLS:
+ proto = "s";
+ break;
+ default:
+ return NSAPI_ERROR_UNSUPPORTED;
+ break;// defensive programming
+ }
+
+ if (!_spwf.open(proto, &sock_id, addr.get_ip_address(), addr.get_port())) {;//sock ID is allocated NOW
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ //TODO: Maintain a socket table to map socket ID to host & port
+ //TODO: lookup on client table to see if already socket is allocated to same host/port
+ //multimap <char *, vector <uint16_t> > ::iterator i = c_table.find((char*)ip);
+
+ if(sock_id <= SPWFSA_SOCKET_COUNT)
+ {
+ socket->id = sock_id;//the socket ID of this Socket instance
+ _ids[socket->id] = true;
+ socket->connected = true;
+ }
+ else
+ return NSAPI_ERROR_NO_SOCKET;
+
+ return 0;
+}
+
+/**
+* @brief bind to a port number and address
+* @param handle: Pointer to socket handle
+* proto: address to bind to
+* @retval NSAPI Error Type
+*/
+int SpwfSAInterface::socket_bind(void *handle, const SocketAddress &address)
+{
+ struct spwf_socket *socket = (struct spwf_socket *)handle;
+ socket->server_port = address.get_port();
+ return 0;
+}
+
+/**
+* @brief start listening on a port and address
+* @param handle: Pointer to handle
+* backlog: not used (always value is 1)
+* @retval NSAPI Error Type
+*/
+int SpwfSAInterface::socket_listen(void *handle, int backlog)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+/**
+* @brief accept connections from remote sockets
+* @param handle: Pointer to handle of client socket (connecting)
+* proto: handle of server socket which will accept connections
+* @retval NSAPI Error Type
+*/
+int SpwfSAInterface::socket_accept(void **handle, void *server)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+/**
+* @brief close a socket
+* @param handle: Pointer to handle
+* @retval NSAPI Error Type
+*/
+int SpwfSAInterface::socket_close(void *handle)
+{
+ struct spwf_socket *socket = (struct spwf_socket *)handle;
+ int err = 0;
+
+ if(socket->id!=-1)
+ {
+ if (_spwf.close(socket->id)) {
+ if(socket->id==SERVER_SOCKET_NO)
+ isListening = false;
+ else
+ _ids[socket->id] = false;
+ }
+ else err = NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ delete socket;
+ return err;
+}
+
+/**
+* @brief write to a socket
+* @param handle: Pointer to handle
+* data: pointer to data
+* size: size of data
+* @retval no of bytes sent
+*/
+int SpwfSAInterface::socket_send(void *handle, const void *data, unsigned size)
+{
+ struct spwf_socket *socket = (struct spwf_socket *)handle;
+ //int err;
+
+ /*if(socket->id==SERVER_SOCKET_NO)
+ {
+ if(socket->server_port==-1 || !isListening)
+ return NSAPI_ERROR_NO_SOCKET; //server socket not bound or not listening
+
+ err = _spwf.socket_server_write((uint16_t)size, (char*)data);
+ }
+ else
+ {
+ err = _spwf.send(socket->id, (char*)data, (uint32_t)size);
+ }*/
+ if (!_spwf.send(socket->id, (char*)data, (uint32_t)size)) {
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ return size;
+}
+
+/**
+* @brief receive data on a socket
+* @param handle: Pointer to handle
+* data: pointer to data
+* size: size of data
+* @retval no of bytes read
+*/
+int SpwfSAInterface::socket_recv(void *handle, void *data, unsigned size)
+{
+ struct spwf_socket *socket = (struct spwf_socket *)handle;
+ int32_t recv;
+
+ //CHECK:Receive for both Client and Server Sockets same?
+ recv = _spwf.recv(socket->id, (char*)data, (uint32_t)size);
+ if (recv < 0) {
+ //wait_ms(1);//delay of 1ms <for F4>??
+ //printf(".");
+ if (recv == -1) return NSAPI_ERROR_WOULD_BLOCK;//send this if we want to block call (else timeout will happen)
+ else if (recv == -2)return NSAPI_ERROR_DEVICE_ERROR;
+ else if (recv == -3)return NSAPI_ERROR_NO_CONNECTION;
+ }
+ return recv;
+}
+
+/**
+* @brief send data to a udp socket
+* @param handle: Pointer to handle
+* addr: address of udp socket
+* data: pointer to data
+* size: size of data
+* @retval no of bytes sent
+*/
+int SpwfSAInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size)
+{
+ struct spwf_socket *socket = (struct spwf_socket *)handle;
+ if (!socket->connected) {
+ int err = socket_connect(socket, addr);
+ if (err < 0) {
+ return err;
+ }
+ }
+
+ return socket_send(socket, data, size);
+}
+
+/**
+* @brief receive data on a udp socket
+* @param handle: Pointer to handle
+* addr: address of udp socket
+* data: pointer to data
+* size: size of data
+* @retval no of bytes read
+*/
+int SpwfSAInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size)
+{
+ struct spwf_socket *socket = (struct spwf_socket *)handle;
+ return socket_recv(socket, data, size);
+}
+
+/**
+* @brief attach function/callback to the socket
+* Not used
+* @param handle: Pointer to handle
+* callback: callback function pointer
+* data: pointer to data
+* @retval none
+*/
+void SpwfSAInterface::socket_attach(void *handle, void (*callback)(void *), void *data)
+{
+ //No implementation yet
+}
+
+/**
+* @brief utility debug function for printing to serial terminal
+* @param string: Pointer to data
+* @retval none
+*/
+void SpwfSAInterface::debug(const char * string)
+{
+ //_spwf.debug_print(string);
+}
+
+/**
+* @brief Set the socket options
+* Not used
+* @param handle: Pointer to handle
+* level: SOL_SOCKET
+* optname: option name
+* optval: pointer to option value
+* optlen: option length
+@retval NSAPI Error Type
+*/
+int SpwfSAInterface::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen)
+{
+// struct spwf_socket *socket = (struct spwf_socket *)handle;
+
+ switch (optname) {
+ case NSAPI_REUSEADDR: /*!< Allow bind to reuse local addresses */
+ case NSAPI_KEEPALIVE: /*!< Enables sending of keepalive messages */
+ case NSAPI_LINGER: /*!< Keeps close from returning until queues empty */
+ case NSAPI_SNDBUF: /*!< Sets send buffer size */
+ case NSAPI_RCVBUF: /*!< Sets recv buffer size */
+ default:
+ printf("SpwfSAInterface::setsockopt> ERROR!!!! Unknown optname: %d \r\n", optname);
+ return -1;
+ }
+ return NSAPI_ERROR_UNSUPPORTED;// defensive programming
+}
+
+/**
+* @brief Get the socket options
+* Not used
+* @param handle: Pointer to handle
+* level: SOL_SOCKET
+* optname: option name
+* optval: pointer to option value
+* optlen: pointer to option length
+@retval NSAPI Error Type
+*/
+int SpwfSAInterface::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/X_NUCLEO_IDW01M1v2/SpwfInterface.h Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,99 @@
+/* mbed Microcontroller Library
+* Copyright (c) 20015 ARM Limited
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+/**
+ ******************************************************************************
+ * @file SpwfInterface.h
+ * @author STMicroelectronics
+ * @brief Header file of the NetworkStack for the SPWF Device
+ ******************************************************************************
+ * @copy
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+#ifndef SPWFSA_INTERFACE_H
+#define SPWFSA_INTERFACE_H
+
+#include "WiFiInterface.h"
+#include "SPWFSA01.h"
+
+#define SPWFSA_SOCKET_COUNT 8
+#define SERVER_SOCKET_NO 9
+
+/** SpwfSAInterface class
+ * Implementation of the NetworkStack for the SPWF Device
+ */
+class SpwfSAInterface : public NetworkStack, public WiFiInterface
+{
+public:
+ SpwfSAInterface(PinName tx, PinName rx, bool debug);
+ SpwfSAInterface(PinName tx, PinName rx, PinName reset = PC_12, PinName wakeup = PC_8, bool debug = false);
+ virtual ~SpwfSAInterface();
+
+ // Implementation of WiFiInterface
+ virtual int connect(const char *ssid,
+ const char *pass,
+ nsapi_security_t security = NSAPI_SECURITY_NONE);
+
+ inline int setSocketClientSecurity(uint8_t* tls_mode, uint8_t* root_ca_server, uint8_t* client_cert, uint8_t* client_key, uint8_t* client_domain, uint32_t tls_epoch_time)
+ {
+ return _spwf.setSocketClientSecurity(tls_mode, root_ca_server, client_cert, client_key, client_domain, tls_epoch_time);
+ }
+
+ virtual int disconnect();
+ virtual const char *get_mac_address();
+ void debug(const char * string);
+ inline bool reset_chip() {return _spwf.hw_reset();};
+
+ //Implementation of NetworkStack
+ virtual const char *get_ip_address();
+
+protected:
+ //Implementation of NetworkStack
+ virtual int socket_open(void **handle, nsapi_protocol_t proto);
+ virtual int socket_close(void *handle);
+ virtual int socket_bind(void *handle, const SocketAddress &address); //not supported
+ virtual int socket_listen(void *handle, int backlog);
+ virtual int socket_connect(void *handle, const SocketAddress &address);
+ virtual int socket_accept(void **handle, void *server);
+ virtual int socket_send(void *handle, const void *data, unsigned size);
+ virtual int socket_recv(void *handle, void *data, unsigned size);
+ virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size);
+ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size);
+ virtual void socket_attach(void *handle, void (*callback)(void *), void *data);
+ virtual int setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen);
+ virtual int getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen);
+
+private:
+ int init(void);
+
+ SPWFSA01 _spwf;
+ bool _ids[SPWFSA_SOCKET_COUNT];
+ bool isListening;
+ bool isInitialized;
+};
+
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/X_NUCLEO_IKS01A1.lib Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,1 @@ +https://developer.mbed.org/teams/ST/code/X_NUCLEO_IKS01A1/#d17ab29129ce
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Wed Sep 27 14:40:52 2017 +0300
@@ -0,0 +1,399 @@
+/* SpwfInterface NetworkSocketAPI Example Program
+ * Copyright (c) 2015 ARM Limited
+ * Copyright (c) 2017 KLIKA TECH, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Contributors:
+ * Klika Tech - completely adopted to Amazon AWS IoT service
+
+ */
+
+#include "mbed.h"
+#include "SpwfInterface.h"
+#include "TCPSocket.h"
+#include "MQTTClient.h"
+#include "MQTTWiFi.h"
+#include <ctype.h>
+#include "x_nucleo_iks01a1.h"
+
+//------------------------------------
+// Hyperterminal default configuration
+// 9600 bauds, 8-bit data, no parity
+//------------------------------------
+Serial pc(SERIAL_TX, SERIAL_RX);
+DigitalOut myled(LED2);
+DigitalOut butled(LED3);
+InterruptIn mybutton(USER_BUTTON);
+
+bool myButtonPressed = false;
+
+#define MQTT_MAX_PACKET_SIZE 350
+#define MQTT_MAX_PAYLOAD_SIZE 300
+
+#define AWS_IOT_MQTT_HOST "xxxxxxxxxx.iot.us-east-1.amazonaws.com" //Use your own host.
+#define AWS_IOT_MQTT_PORT 8883
+#define AWS_IOT_MQTT_CLIENT_ID "Nucleo" //Should be kept if you are using same device clent.
+#define AWS_IOT_MY_THING_NAME "Nucleo" //Should be kept if you are using same device thing name.
+#define AWS_IOT_MQTT_TOPIC_TEST "Nucleo/test"
+#define AWS_IOT_MQTT_TOPIC_DATA "Nucleo/data"
+#define AWS_IOT_MQTT_TOPIC_SHADOW "$aws/things/Nucleo/shadow/update"
+#define AWS_IOT_ID ""
+#define AWS_IOT_AUTH_TOKEN ""
+
+// WiFi network credential
+#define SSID "" // Network must be visible otherwise it can't connect
+#define PASSW ""
+#error "Wifi SSID & password empty"
+
+#include "stdint.h"
+
+
+/**********************************************************************************************
+***********************************************************************************************
+ Root CA certificate: Never modify
+***********************************************************************************************
+***********************************************************************************************/
+
+//This root CA can be used.
+const uint8_t rootCA[] = "\
+-----BEGIN CERTIFICATE-----\n\
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\
+ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\
+aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL\
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln\
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\
+aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1\
+nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex\
+t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz\
+SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG\
+BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+\
+rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/\
+NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\
+BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\
+BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv\
+MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE\
+p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y\
+5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK\
+WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ\
+4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N\
+hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao8WNq\n\
+-----END CERTIFICATE-----\n";
+
+/**********************************************************************************************
+***********************************************************************************************
+ Device Identity Certificates: Modify for your AWS IoT Thing
+***********************************************************************************************
+***********************************************************************************************/
+
+/****************************************
+(somecode)-certificate.pem.crt - Amazon signed PEM sertificate.
+*****************************************/
+
+//This Client cert is example. Use own instead.
+const uint8_t clientCRT[] = "\
+-----BEGIN CERTIFICATE-----\n\
+MIIDBjCCAe6gAwIBAgIUVph856omeIxW3UPioq+UrX1DbwowDQYJKoZIhvcNAQEL\
+BQAwTTFLMEkGA1UECwxCQW1hem9uIFdlYiBTZXJ2aWNlcyBPPUFtYXpvbi5jb20g\
+SW5jLiBMPVNlYXR0bGUgU1Q9V2FzaGluZ3RvbiBDPVVTMB4XDTE3MDUyNTExNTEy\
+OVoXDEQ5MTIzMEIzNTk1OVowgZUxCzAJBgNVBAETAkJZMQ4wDAYDVQQIDAVNaW5z\
+azEOMAwGA1UEBwwFTWluc2sxFzAVBgNVBAoMDktsaWthLVRlY2ggTExDMRcwFQYD\
+VQQLDA5LbGlrYS1UZWNoIExMQzEMMAoGA1UEAwwDUm5EMSYwJAYJKoZIhvcNAQkB\
+FhdtdmF0YExldUBrbGlrYS10ZWNoLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH\
+A0IABCJgOQJmoTBJVPfEi9Hm/JVixaxkY5rtlgrYO3hSl633A2hg0P/ue0wXDbF3\
+aQ0X57IRFE4k4FEbr3UXjT/IczKjYDBeMB8GA1UdIwQYMBaAFK3YzTUPlYB2Li75\
+i/z8rEogr1d6MB0GA1UdDgQWBBT18HXBaXFJuER/0SwegnxJ+pyJ6TAMBgNVHRMB\
+Af8EAjAAMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAb0Ux1aH5\
+RLxjrfGqXN6rPVqh8QQRS+AyBfzmaQN8HaPZMkX5WxXLvcn0A3uWlwQxPPkcZ4zf\
+51GHtFFQWB4YZ8dx8mUQ0v/j7onHjCJgZ8iDgwOyKMGtnsDEWCakQw+a6cj+NrMZ\
+tzhjwCzEEP6EPcbXwErI5OOzLuWns2L/JEr2wWNkokgRuS8ewr/SQ9OLWIWa2rFM\
+ahPNTb3y/qBeWdjeJmhI+TOxdqIpsF8roWP25zwo/zkzCHCjXFBrL+0CA4MpxIl9\
+x02i7aAhlJ6ys80lDxdeWeeQJXRKkGknP8mcmKn3iEqqJ5s1dQePj2b5d3ldatya\
+wsxQBqqZXzIWEw==\
+\n\
+-----END CERTIFICATE-----\n";
+
+
+
+/**********************************************************************************************
+***********************************************************************************************
+ Private Key: Modify for your AWS IoT Thing
+***********************************************************************************************
+***********************************************************************************************/
+
+/********************************************************************8****************************************
+nucleo.key.pem - client key generated according to readme.
+**************************************************************************************************************/
+
+//This Client Key is example. Use own instead.
+const uint8_t clientKey[] ="\
+-----BEGIN EC PARAMETERS-----\n\
+BggqhEEOPQMBEw==\
+-----END EC PARAMETERS-----\n\
+-----BEGIN EC PRIVATE KEY-----\n\
+MHcCAQEEIHPRfWSC8/k/BsqDWKuP15dXsI9fGwpkTIsLZe6mIrAEoAoGCCqGSM49\
+AwEHoUQDQEAEImAEAEahMElU9+WL0eb8lWLFrGRjmu2WCtg7eFKXrfcDaGDQ/+57\
+TBcNsXdpDRfnshEETiTgURuvdReNP8hEMg==\
+-----END EC PRIVATE KEY-----\n";
+
+int connack_rc = 0; // MQTT connack return code
+int connectTimeout = 1000;
+int retryAttempt = 0;
+
+PressureSensor *pressure_sensor;
+HumiditySensor *humidity_sensor;
+TempSensor *temp_sensor1;
+MagneticSensor *magnetic_sensor;
+GyroSensor *gyro_sensor;
+MotionSensor *accel_sensor;
+
+MQTT::Message message;
+MQTTString TopicName= { AWS_IOT_MQTT_TOPIC_TEST };
+MQTT::MessageData MsgData(TopicName, message);
+
+void subscribe_cb(MQTT::MessageData & msgMQTT) {
+ char msg[MQTT_MAX_PAYLOAD_SIZE];
+ msg[0]='\0';
+ strncat (msg, (char*)msgMQTT.message.payload, msgMQTT.message.payloadlen);
+ printf ("--->>> subscribe_cb msg: %s\n\r", msg);
+}
+
+int subscribe(MQTT::Client<MQTTWiFi, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTWiFi* ipstack)
+{
+ char* pubTopic = AWS_IOT_MQTT_TOPIC_TEST;
+ return client->subscribe(pubTopic, MQTT::QOS0, subscribe_cb);
+}
+
+int connect(MQTT::Client<MQTTWiFi, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTWiFi* ipstack)
+{
+ SpwfSAInterface& WiFi = ipstack->getWiFi();
+
+ // Network debug statements
+ LOG("=====================================\n\r");
+ LOG("Connecting WiFi.\n\r");
+ LOG("Nucleo IP ADDRESS: %s\n\r", WiFi.get_ip_address());
+ LOG("Nucleo MAC ADDRESS: %s\n\r", WiFi.get_mac_address());
+ LOG("Server Hostname: %s port: %d\n\r", AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT);
+ LOG("Client ID: %s\n\r", AWS_IOT_MQTT_CLIENT_ID);
+ //LOG("Topic: %s\n\r", AWS_IOT_MQTT_TOPIC_TEST);
+ //LOG("Subscription URL: %s\n\r", subscription_url);
+ LOG("=====================================\n\r");
+
+ ipstack->open(&ipstack->getWiFi());
+
+ int rc=ipstack->getNTPtime();
+
+ if (rc != 0)
+ {
+ ERROR("Get NTP time error: %d\n", rc);
+ return rc;
+ }
+
+ rc = WiFi.setSocketClientSecurity((uint8_t *)"m", (uint8_t *)rootCA, (uint8_t *)clientCRT, (uint8_t *)clientKey, (uint8_t *)AWS_IOT_MQTT_HOST, ipstack->getTime());
+
+ if (rc != 0)
+ {
+ ERROR("Set security params error: %d\n", rc);
+ return rc;
+ }
+
+ rc = ipstack->connect(AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT, connectTimeout);
+
+ if (rc != 0)
+ {
+ WARN("IP Stack connect returned: %d\n", rc);
+ return rc;
+ }
+
+ printf ("--->TCP Connected\n\r");
+
+ // MQTT Connect
+ MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+ data.MQTTVersion = 4;
+ data.struct_version=0;
+ data.clientID.cstring = AWS_IOT_MQTT_CLIENT_ID;
+ //data.username.cstring = "use-token-auth";
+ //data.password.cstring = AWS_IOT_AUTH_TOKEN;
+
+ if ((rc = client->connect(data)) == 0)
+ {
+ printf ("--->MQTT Connected\n\r");
+
+ if (!subscribe(client, ipstack)) printf ("--->>>MQTT subscribed to: %s\n\r",AWS_IOT_MQTT_TOPIC_TEST);
+ }
+ else
+ {
+ WARN("MQTT connect returned %d\n", rc);
+ }
+ if (rc >= 0)
+ connack_rc = rc;
+ return rc;
+}
+
+int getConnTimeout(int attemptNumber)
+{ // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
+ // after 20 attempts, retry every 10 minutes
+ return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
+}
+
+void attemptConnect(MQTT::Client<MQTTWiFi, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTWiFi* ipstack)
+{
+ while (connect(client, ipstack) != MQTT_CONNECTION_ACCEPTED)
+ {
+ if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD)
+ {
+ printf ("File: %s, Line: %d Error: %d\n\r",__FILE__,__LINE__, connack_rc);
+ return; // don't reattempt to connect if credentials are wrong
+ }
+
+ int timeout = getConnTimeout(++retryAttempt);
+ WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout);
+
+ // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
+ // or maybe just add the proper members to do this disconnect and call attemptConnect(...)
+ // this works - reset the system when the retry count gets to a threshold
+ if (retryAttempt == 5)
+ {
+ ipstack->getWiFi().reset_chip();
+ NVIC_SystemReset();
+ }
+ else
+ wait(timeout);
+ }
+}
+
+int publish(MQTT::Client<MQTTWiFi, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTWiFi* ipstack)
+{
+ MQTT::Message message;
+ char* pubTopic = AWS_IOT_MQTT_TOPIC_SHADOW;
+
+ char buf[MQTT_MAX_PAYLOAD_SIZE];
+ float temp, press, hum;
+ int32_t magnet[3];
+ int32_t gyro[3];
+ int32_t accel[3];
+
+ temp_sensor1->GetTemperature(&temp);
+ pressure_sensor->GetPressure(&press);
+ humidity_sensor->GetHumidity(&hum);
+ magnetic_sensor->Get_M_Axes(magnet);
+ gyro_sensor->Get_G_Axes(gyro);
+ accel_sensor->Get_X_Axes(accel);
+
+ /*sprintf(buf,
+ "{\"d\":{\"ST\":\"Nucleo-IoT-mbed\",\"Temp\":%0.4f,\"Pressure\":%0.4f,\"Humidity\":%0.4f}}",
+ temp, press, hum);*/
+
+ if (!myButtonPressed)
+ {
+ butled = 1;
+ sprintf(buf, "{\"state\": {\"reported\": {\"temperature\": %f, \"humidity\": %f, \"pressure\": %f, \"accelerometer\": [%f, %f, %f], \"gyroscope\": [%f, %f, %f], \"magnetometer\": [%f, %f, %f]}}}",
+ temp, hum, press, accel[0]/1000.0, accel[1]/1000.0, accel[2]/1000.0, gyro[0]/1000.0, gyro[1]/1000.0, gyro[2]/1000.0, magnet[0]/10.0, magnet[1]/10.0, magnet[2]/10.0);
+ }
+ else
+ {
+ myButtonPressed = false; // reset state
+ butled = 0;
+
+ sprintf(buf, "{\"temperature\": %f, \"humidity\": %f, \"pressure\": %f, \"accelerometer\": [%f, %f, %f], \"gyroscope\": [%f, %f, %f], \"magnetometer\": [%f, %f, %f], \"marker\": true}",
+ temp, hum, press, accel[0]/1000.0, accel[1]/1000.0, accel[2]/1000.0, gyro[0]/1000.0, gyro[1]/1000.0, gyro[2]/1000.0, magnet[0]/10.0, magnet[1]/10.0, magnet[2]/10.0);
+ pubTopic = AWS_IOT_MQTT_TOPIC_DATA;
+ }
+
+ message.qos = MQTT::QOS0;
+ message.retained = false;
+ message.dup = false;
+ message.payload = (void*)buf;
+ message.payloadlen = strlen(buf);
+
+ printf("Length - %d, Publishing %s\n\r", strlen(buf), buf);
+
+ return client->publish(pubTopic, message);
+}
+
+void pressed()
+{
+ myButtonPressed = true;
+}
+
+int main()
+{
+ const char * ssid = SSID; // Network must be visible otherwise it can't connect
+ const char * seckey = PASSW;
+
+ pc.baud(115200);
+
+ SpwfSAInterface spwf(D8, D2, false);
+
+ myled=0;
+ DevI2C *i2c = new DevI2C(I2C_SDA, I2C_SCL);
+ i2c->frequency(400000);
+
+ mybutton.fall(&pressed);
+
+ X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance(i2c);
+ pressure_sensor = mems_expansion_board->pt_sensor;
+ temp_sensor1 = mems_expansion_board->ht_sensor;
+ humidity_sensor = mems_expansion_board->ht_sensor;
+ magnetic_sensor = mems_expansion_board->magnetometer;
+ gyro_sensor = mems_expansion_board->GetGyroscope();
+ accel_sensor = mems_expansion_board->GetAccelerometer();
+
+ pc.printf("\r\nX-NUCLEO-IDW01M1 mbed Application\r\n");
+ pc.printf("\r\nconnecting to AP\r\n");
+
+ MQTTWiFi ipstack(spwf, ssid, seckey, NSAPI_SECURITY_WPA2);
+
+ LOG("Connected to WiFI.\r\n");
+
+ MQTT::Client<MQTTWiFi, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack);
+
+ attemptConnect(&client, &ipstack);
+
+ if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD)
+ {
+ while (true)
+ wait(1.0); // Permanent failures - don't retry
+ }
+
+ myled=1;
+
+ int count = 0;
+
+ while (true)
+ {
+ if (++count == 100)
+ {
+ myled = 0;
+ // Publish a message every second
+ if (publish(&client, &ipstack) != 0)
+ {
+ myled=0;
+ ipstack.getWiFi().reset_chip();
+ NVIC_SystemReset();
+ attemptConnect(&client, &ipstack); // if we have lost the connection
+ }
+ else myled=1;
+
+ count = 0;
+ }
+
+ client.yield(10); // allow the MQTT client to receive messages
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Sep 27 14:40:52 2017 +0300 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/2e9cc70d1897 \ No newline at end of file