Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: SDFileSystem
Fork of ATT_AWS_IoT_demo by
IoT Starter Kit Powered by AWS Demo
This program demonstrates the AT&T IoT Starter Kit sending data directly into AWS IoT. It's explained and used in the Getting Started with the IoT Starter Kit Powered by AWS on starterkit.att.com.
What's required
- AT&T IoT LTE Add-on (also known as the Cellular Shield)
- NXP K64F - for programming
- microSD card - used to store your AWS security credentials
- AWS account
- Python, locally installed
If you don't already have an IoT Starter Kit, you can purchase a kit here. The IoT Starter Kit Powered by AWS includes the LTE cellular shield, K64F, and a microSD card.
Revision 15:6f2798e45099, committed 2016-12-01
- Comitter:
- ampembeng
- Date:
- Thu Dec 01 18:05:38 2016 +0000
- Parent:
- 14:339320b096c5
- Child:
- 16:02008a2a2569
- Commit message:
- Initial commit. Demo works with both the FRDM wired Ethernet and the Avnet Shield wireless modem.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_config.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 aws_iot_config.h
+ * @brief AWS IoT specific configuration file
+ */
+
+#ifndef SRC_SHADOW_IOT_SHADOW_CONFIG_H_
+#define SRC_SHADOW_IOT_SHADOW_CONFIG_H_
+
+// Get from console
+// =================================================
+#define AWS_IOT_MQTT_HOST "TODO" ///< Customer specific MQTT HOST. The same will be used for Thing Shadow
+#define AWS_IOT_MQTT_PORT 8883 ///< default port for MQTT/S
+#define AWS_IOT_MQTT_CLIENT_ID "TODO" ///< MQTT client ID should be unique for every device
+#define AWS_IOT_MY_THING_NAME "TODO" ///< Thing Name of the Shadow this device is associated with
+
+// NOTE: Since the FRDM board mbed-os does not use a file system these are unused (see certs.pp)
+#define AWS_IOT_ROOT_CA_FILENAME "rootCA-certificate.crt" ///< Root CA file name
+#define AWS_IOT_CERTIFICATE_FILENAME "certificate.pem.crt" ///< device signed certificate file name
+#define AWS_IOT_PRIVATE_KEY_FILENAME "private.pem.key" ///< Device private key filename
+// =================================================
+
+// MQTT PubSub
+#define AWS_IOT_MQTT_TX_BUF_LEN 512 ///< Any time a message is sent out through the MQTT layer. The message is copied into this buffer anytime a publish is done. This will also be used in the case of Thing Shadow
+#define AWS_IOT_MQTT_RX_BUF_LEN 512 ///< Any message that comes into the device should be less than this buffer size. If a received message is bigger than this buffer size the message will be dropped.
+#define AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS 5 ///< Maximum number of topic filters the MQTT client can handle at any given time. This should be increased appropriately when using Thing Shadow
+
+// Thing Shadow specific configs
+#define SHADOW_MAX_SIZE_OF_RX_BUFFER AWS_IOT_MQTT_RX_BUF_LEN+1 ///< Maximum size of the SHADOW buffer to store the received Shadow message
+#define MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES 80 ///< Maximum size of the Unique Client Id. For More info on the Client Id refer \ref response "Acknowledgments"
+#define MAX_SIZE_CLIENT_ID_WITH_SEQUENCE MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES + 10 ///< This is size of the extra sequence number that will be appended to the Unique client Id
+#define MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE MAX_SIZE_CLIENT_ID_WITH_SEQUENCE + 20 ///< This is size of the the total clientToken key and value pair in the JSON
+#define MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME 10 ///< At Any given time we will wait for this many responses. This will correlate to the rate at which the shadow actions are requested
+#define MAX_THINGNAME_HANDLED_AT_ANY_GIVEN_TIME 10 ///< We could perform shadow action on any thing Name and this is maximum Thing Names we can act on at any given time
+#define MAX_JSON_TOKEN_EXPECTED 120 ///< These are the max tokens that is expected to be in the Shadow JSON document. Include the metadata that gets published
+#define MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME 60 ///< All shadow actions have to be published or subscribed to a topic which is of the format $aws/things/{thingName}/shadow/update/accepted. This refers to the size of the topic without the Thing Name
+#define MAX_SIZE_OF_THING_NAME 20 ///< The Thing Name should not be bigger than this value. Modify this if the Thing Name needs to be bigger
+#define MAX_SHADOW_TOPIC_LENGTH_BYTES MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME + MAX_SIZE_OF_THING_NAME ///< This size includes the length of topic with Thing Name
+
+// Auto Reconnect specific config
+#define AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL 1000 ///< Minimum time before the First reconnect attempt is made as part of the exponential back-off algorithm
+#define AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL 8000 ///< Maximum time interval after which exponential back-off will stop attempting to reconnect.
+
+// Links to our certs from certs.cpp
+extern const unsigned char AWS_IOT_ROOT_CA[];
+extern const unsigned char AWS_IOT_CERTIFICATE[];
+extern const unsigned char AWS_IOT_PRIVATE_KEY[];
+
+#endif /* SRC_SHADOW_IOT_SHADOW_CONFIG_H_ */
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/aws_iot_mqtt_embedded_client_wrapper.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 "timer_interface.h"
+#include "aws_iot_mqtt_interface.h"
+#include "MQTTClient.h"
+#include "aws_iot_config.h"
+#include "aws_iot_log.h"
+
+static Client c;
+
+static iot_disconnect_handler clientDisconnectHandler;
+
+static unsigned char writebuf[AWS_IOT_MQTT_TX_BUF_LEN];
+static unsigned char readbuf[AWS_IOT_MQTT_RX_BUF_LEN];
+
+const MQTTConnectParams MQTTConnectParamsDefault = {
+ .enableAutoReconnect = 0,
+ .pHostURL = AWS_IOT_MQTT_HOST,
+ .port = AWS_IOT_MQTT_PORT,
+ .pRootCALocation = NULL,
+ .pDeviceCertLocation = NULL,
+ .pDevicePrivateKeyLocation = NULL,
+ .pClientID = NULL,
+ .pUserName = NULL,
+ .pPassword = NULL,
+ .MQTTVersion = MQTT_3_1_1,
+ .KeepAliveInterval_sec = 10,
+ .isCleansession = true,
+ .isWillMsgPresent = false,
+ .will={.pTopicName = NULL, .pMessage = NULL, .isRetained = false, .qos = QOS_0},
+ .mqttCommandTimeout_ms = 1000,
+ .tlsHandshakeTimeout_ms = 2000,
+ .isSSLHostnameVerify = true,
+ .disconnectHandler = NULL
+};
+
+const MQTTPublishParams MQTTPublishParamsDefault={
+ .pTopic = NULL,
+ .MessageParams = {.qos = QOS_0, .isRetained=false, .isDuplicate = false, .id = 0, .pPayload = NULL, .PayloadLen = 0}
+};
+const MQTTSubscribeParams MQTTSubscribeParamsDefault={
+ .pTopic = NULL,
+ .qos = QOS_0,
+ .mHandler = NULL
+};
+const MQTTCallbackParams MQTTCallbackParamsDefault={
+ .pTopicName = NULL,
+ .TopicNameLen = 0,
+ .MessageParams = {.qos = QOS_0, .isRetained=false, .isDuplicate = false, .id = 0, .pPayload = NULL, .PayloadLen = 0}
+};
+const MQTTMessageParams MQTTMessageParamsDefault={
+ .qos = QOS_0,
+ .isRetained=false,
+ .isDuplicate = false,
+ .id = 0,
+ .pPayload = NULL,
+ .PayloadLen = 0
+};
+const MQTTwillOptions MQTTwillOptionsDefault={
+ .pTopicName = NULL,
+ .pMessage = NULL,
+ .isRetained = false,
+ .qos = QOS_0
+};
+
+#define GETLOWER4BYTES 0x0FFFFFFFF
+void pahoMessageCallback(MessageData* md) {
+ MQTTMessage* message = md->message;
+ MQTTCallbackParams params;
+
+ // early exit if we do not have a valid callback pointer
+ if (md->applicationHandler == NULL) {
+ return;
+ }
+
+ if (NULL != md->topicName->lenstring.data) {
+ params.pTopicName = md->topicName->lenstring.data;
+ params.TopicNameLen = (uint16_t)(md->topicName->lenstring.len);
+ }
+ if (NULL != message) {
+ params.MessageParams.PayloadLen = message->payloadlen & GETLOWER4BYTES;
+ params.MessageParams.pPayload = (char*) message->payload;
+ params.MessageParams.isDuplicate = message->dup;
+ params.MessageParams.qos = (QoSLevel)message->qos;
+ params.MessageParams.isRetained = message->retained;
+ params.MessageParams.id = message->id;
+ }
+
+ ((iot_message_handler)(md->applicationHandler))(params);
+}
+
+void pahoDisconnectHandler(void) {
+ if(NULL != clientDisconnectHandler) {
+ clientDisconnectHandler();
+ }
+}
+
+static bool isPowerCycle = true;
+
+IoT_Error_t aws_iot_mqtt_connect(MQTTConnectParams *pParams) {
+ IoT_Error_t rc = NONE_ERROR;
+ MQTTReturnCode pahoRc = SUCCESS;
+
+ if(NULL == pParams || NULL == pParams->pClientID || NULL == pParams->pHostURL) {
+ return NULL_VALUE_ERROR;
+ }
+
+ TLSConnectParams TLSParams;
+ TLSParams.DestinationPort = pParams->port;
+ TLSParams.pDestinationURL = pParams->pHostURL;
+ TLSParams.pDeviceCertLocation = pParams->pDeviceCertLocation;
+ TLSParams.pDevicePrivateKeyLocation = pParams->pDevicePrivateKeyLocation;
+ TLSParams.pRootCALocation = pParams->pRootCALocation;
+ TLSParams.timeout_ms = pParams->tlsHandshakeTimeout_ms;
+ TLSParams.ServerVerificationFlag = pParams->isSSLHostnameVerify;
+
+ DEBUG("...subscribe");
+ // This implementation assumes you are not going to switch between cleansession 1 to 0
+ // As we don't have a default subscription handler support in the MQTT client every time a device power cycles it has to re-subscribe to let the MQTT client to pass the message up to the application callback.
+ // The default message handler will be implemented in the future revisions.
+ if(pParams->isCleansession || isPowerCycle){
+ pahoRc = MQTTClient(&c, (unsigned int)(pParams->mqttCommandTimeout_ms), writebuf,
+ AWS_IOT_MQTT_TX_BUF_LEN, readbuf, AWS_IOT_MQTT_RX_BUF_LEN,
+ pParams->enableAutoReconnect, iot_tls_init, &TLSParams);
+ if(SUCCESS != pahoRc) {
+ return CONNECTION_ERROR;
+ }
+ isPowerCycle = false;
+ }
+
+ MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+
+ DEBUG("...MQTTVersion");
+ data.willFlag = pParams->isWillMsgPresent;
+ // compatible type for MQTT_Ver_t
+ switch (pParams->MQTTVersion) {
+ case MQTT_3_1:
+ data.MQTTVersion = (unsigned char) (3);
+ break;
+ case MQTT_3_1_1:
+ data.MQTTVersion = (unsigned char) (4);
+ break;
+ default:
+ data.MQTTVersion = (unsigned char) (4); // default MQTT version = 3.1.1
+ }
+
+ // register our disconnect handler, save customer's handler
+ setDisconnectHandler(&c, pahoDisconnectHandler);
+ clientDisconnectHandler = pParams->disconnectHandler;
+
+ data.clientID.cstring = pParams->pClientID;
+ data.username.cstring = pParams->pUserName;
+ data.password.cstring = pParams->pPassword;
+ data.will.topicName.cstring = (char*)pParams->will.pTopicName;
+ data.will.message.cstring = (char*)pParams->will.pMessage;
+ data.will.qos = (enum QoS)pParams->will.qos;
+ data.will.retained = pParams->will.isRetained;
+ data.keepAliveInterval = pParams->KeepAliveInterval_sec;
+ data.cleansession = pParams->isCleansession;
+
+ DEBUG("...MQTTConnect");
+ pahoRc = MQTTConnect(&c, &data);
+ if(MQTT_NETWORK_ALREADY_CONNECTED_ERROR == pahoRc) {
+ rc = NETWORK_ALREADY_CONNECTED;
+ } else if(SUCCESS != pahoRc) {
+ rc = CONNECTION_ERROR;
+ }
+
+ return rc;
+}
+
+IoT_Error_t aws_iot_mqtt_subscribe(MQTTSubscribeParams *pParams) {
+ IoT_Error_t rc = NONE_ERROR;
+
+ if (0 != MQTTSubscribe(&c, pParams->pTopic, (enum QoS)pParams->qos, pahoMessageCallback, (void (*)(void))(pParams->mHandler))) {
+ rc = SUBSCRIBE_ERROR;
+ }
+ return rc;
+}
+
+IoT_Error_t aws_iot_mqtt_publish(MQTTPublishParams *pParams) {
+ IoT_Error_t rc = NONE_ERROR;
+
+ MQTTMessage Message;
+ Message.dup = pParams->MessageParams.isDuplicate;
+ Message.id = pParams->MessageParams.id;
+ Message.payload = pParams->MessageParams.pPayload;
+ Message.payloadlen = pParams->MessageParams.PayloadLen;
+ Message.qos = (enum QoS)pParams->MessageParams.qos;
+ Message.retained = pParams->MessageParams.isRetained;
+
+ if(0 != MQTTPublish(&c, pParams->pTopic, &Message)){
+ rc = PUBLISH_ERROR;
+ }
+
+ return rc;
+}
+
+IoT_Error_t aws_iot_mqtt_unsubscribe(char *pTopic) {
+ IoT_Error_t rc = NONE_ERROR;
+
+ if(0 != MQTTUnsubscribe(&c, pTopic)){
+ rc = UNSUBSCRIBE_ERROR;
+ }
+ return rc;
+}
+
+IoT_Error_t aws_iot_mqtt_disconnect() {
+ IoT_Error_t rc = NONE_ERROR;
+
+ if(0 != MQTTDisconnect(&c)){
+ rc = DISCONNECT_ERROR;
+ }
+
+ return rc;
+}
+
+IoT_Error_t aws_iot_mqtt_yield(int timeout) {
+ MQTTReturnCode pahoRc = MQTTYield(&c, timeout);
+ IoT_Error_t rc = NONE_ERROR;
+ if(MQTT_NETWORK_RECONNECTED == pahoRc){
+ INFO("aws_iot_mqtt_yield() RECONNECT_SUCCESSFUL");
+ rc = RECONNECT_SUCCESSFUL;
+ } else if(SUCCESS == pahoRc){
+ //INFO("aws_iot_mqtt_yield() NONE_ERROR");
+ rc = NONE_ERROR;
+ } else if(MQTT_NULL_VALUE_ERROR == pahoRc) {
+ INFO("aws_iot_mqtt_yield() NULL_VALUE_ERROR");
+ rc = NULL_VALUE_ERROR;
+ } else if(MQTT_NETWORK_DISCONNECTED_ERROR == pahoRc) {
+ INFO("aws_iot_mqtt_yield() NETWORK_DISCONNECTED");
+ rc = NETWORK_DISCONNECTED;
+ } else if(MQTT_RECONNECT_TIMED_OUT == pahoRc) {
+ INFO("aws_iot_mqtt_yield() NETWORK_RECONNECT_TIMED_OUT");
+ rc = NETWORK_RECONNECT_TIMED_OUT;
+ } else if(MQTT_ATTEMPTING_RECONNECT == pahoRc) {
+ INFO("aws_iot_mqtt_yield() NETWORK_ATTEMPTING_RECONNECT");
+ rc = NETWORK_ATTEMPTING_RECONNECT;
+ } else if(MQTT_BUFFER_RX_MESSAGE_INVALID == pahoRc){
+ INFO("aws_iot_mqtt_yield() RX_MESSAGE_INVALID");
+ rc = RX_MESSAGE_INVALID;
+ } else if(MQTTPACKET_BUFFER_TOO_SHORT == pahoRc){
+ INFO("aws_iot_mqtt_yield() RX_MESSAGE_BIGGER_THAN_MQTT_RX_BUF");
+ rc = RX_MESSAGE_BIGGER_THAN_MQTT_RX_BUF;
+ } else {
+ INFO("aws_iot_mqtt_yield() YIELD_ERROR");
+ rc = YIELD_ERROR;
+ }
+
+ return rc;
+}
+
+IoT_Error_t aws_iot_mqtt_attempt_reconnect() {
+ MQTTReturnCode pahoRc = MQTTAttemptReconnect(&c);
+ IoT_Error_t rc = RECONNECT_SUCCESSFUL;
+ if(MQTT_NETWORK_RECONNECTED == pahoRc){
+ rc = RECONNECT_SUCCESSFUL;
+ } else if(MQTT_NULL_VALUE_ERROR == pahoRc) {
+ rc = NULL_VALUE_ERROR;
+ } else if(MQTT_NETWORK_DISCONNECTED_ERROR == pahoRc) {
+ rc = NETWORK_DISCONNECTED;
+ } else if(MQTT_RECONNECT_TIMED_OUT == pahoRc) {
+ rc = NETWORK_RECONNECT_TIMED_OUT;
+ } else if(MQTT_NETWORK_ALREADY_CONNECTED_ERROR == pahoRc) {
+ rc = NETWORK_ALREADY_CONNECTED;
+ } else {
+ rc = GENERIC_ERROR;
+ }
+
+ return rc;
+}
+
+IoT_Error_t aws_iot_mqtt_autoreconnect_set_status(bool value) {
+ MQTTReturnCode rc = setAutoReconnectEnabled(&c, (uint8_t) value);
+
+ if(MQTT_NULL_VALUE_ERROR == rc) {
+ return NULL_VALUE_ERROR;
+ }
+
+ return NONE_ERROR;
+}
+
+bool aws_iot_is_mqtt_connected(void) {
+ return MQTTIsConnected(&c);
+}
+
+bool aws_iot_is_autoreconnect_enabled(void) {
+ return MQTTIsAutoReconnectEnabled(&c);
+}
+
+void aws_iot_mqtt_init(MQTTClient_t *pClient){
+ pClient->connect = aws_iot_mqtt_connect;
+ pClient->disconnect = aws_iot_mqtt_disconnect;
+ pClient->isConnected = aws_iot_is_mqtt_connected;
+ pClient->reconnect = aws_iot_mqtt_attempt_reconnect;
+ pClient->publish = aws_iot_mqtt_publish;
+ pClient->subscribe = aws_iot_mqtt_subscribe;
+ pClient->unsubscribe = aws_iot_mqtt_unsubscribe;
+ pClient->yield = aws_iot_mqtt_yield;
+ pClient->isAutoReconnectEnabled = aws_iot_is_autoreconnect_enabled;
+ pClient->setAutoReconnectStatus = aws_iot_mqtt_autoreconnect_set_status;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/network_interface.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 network_interface.h
+ * @brief Network interface definition for MQTT client.
+ *
+ * Defines an interface to the TLS layer to be used by the MQTT client.
+ * Starting point for porting the SDK to the networking layer of a new platform.
+ */
+
+#ifndef __NETWORK_INTERFACE_H_
+#define __NETWORK_INTERFACE_H_
+
+//=====================================================================================================================
+//
+// NOTE: Internet Connection
+// The Avnet M14A2A Cellular Shield uses the AT&T LTE network by default. If you want to debug with the
+// FRDM-K64F wired Ethernet comment this define out.
+//
+#define USING_AVNET_SHIELD
+//=====================================================================================================================
+
+#ifdef USING_AVNET_SHIELD
+// TODO including this here breaks the compile because of "Timer"
+//#include "WNCTCPSocketConnection.h"
+// Exposes the Avnet socket
+//extern WNCTCPSocketConnection* _tcpsocket;
+#else
+#include "TCPSocket.h"
+// Exposes the FRDM socket
+extern TCPSocket* _tcpsocket;
+#endif
+
+/**
+ * @brief Network Type
+ *
+ * Defines a type for the network struct. See structure definition below.
+ */
+typedef struct Network Network;
+
+/**
+ * @brief TLS Connection Parameters
+ *
+ * Defines a type containing TLS specific parameters to be passed down to the
+ * TLS networking layer to create a TLS secured socket.
+ */
+typedef struct{
+ char* pRootCALocation; ///< Pointer to string containing the filename (including path) of the root CA file.
+ char* pDeviceCertLocation; ///< Pointer to string containing the filename (including path) of the device certificate.
+ char* pDevicePrivateKeyLocation; ///< Pointer to string containing the filename (including path) of the device private key file.
+ char* pDestinationURL; ///< Pointer to string containing the endpoint of the MQTT service.
+ int DestinationPort; ///< Integer defining the connection port of the MQTT service.
+ unsigned int timeout_ms; ///< Unsigned integer defining the TLS handshake timeout value in milliseconds.
+ unsigned char ServerVerificationFlag; ///< Boolean. True = perform server certificate hostname validation. False = skip validation \b NOT recommended.
+}TLSConnectParams;
+
+/**
+ * @brief Network Structure
+ *
+ * Structure for defining a network connection.
+ */
+struct Network{
+ int my_socket; ///< Integer holding the socket file descriptor
+ int (*connect) (Network *, TLSConnectParams);
+ int (*mqttread) (Network*, unsigned char*, int, int); ///< Function pointer pointing to the network function to read from the network
+ int (*mqttwrite) (Network*, unsigned char*, int, int); ///< Function pointer pointing to the network function to write to the network
+ void (*disconnect) (Network*); ///< Function pointer pointing to the network function to disconnect from the network
+ int (*isConnected) (Network*); ///< Function pointer pointing to the network function to check if physical layer is connected
+ int (*destroy) (Network*); ///< Function pointer pointing to the network function to destroy the network object
+};
+
+/**
+ * @brief Boots the WNC modem
+ */
+int net_modem_boot(void);
+
+/**
+ * @brief Initialize the TLS implementation
+ *
+ * Perform any initialization required by the TLS layer.
+ * Connects the interface to implementation by setting up
+ * the network layer function pointers to platform implementations.
+ *
+ * @param pNetwork - Pointer to a Network struct defining the network interface.
+ * @return integer defining successful initialization or TLS error
+ */
+int iot_tls_init(Network *pNetwork);
+
+/**
+ * @brief Create a TLS socket and open the connection
+ *
+ * Creates an open socket connection including TLS handshake.
+ *
+ * @param pNetwork - Pointer to a Network struct defining the network interface.
+ * @param TLSParams - TLSConnectParams defines the properties of the TLS connection.
+ * @return integer - successful connection or TLS error
+ */
+int iot_tls_connect(Network *pNetwork, TLSConnectParams TLSParams);
+
+/**
+ * @brief Write bytes to the network socket
+ *
+ * @param Network - Pointer to a Network struct defining the network interface.
+ * @param unsigned char pointer - buffer to write to socket
+ * @param integer - number of bytes to write
+ * @param integer - write timeout value in milliseconds
+ * @return integer - number of bytes written or TLS error
+ */
+int iot_tls_write(Network*, unsigned char*, int, int);
+
+/**
+ * @brief Read bytes from the network socket
+ *
+ * @param Network - Pointer to a Network struct defining the network interface.
+ * @param unsigned char pointer - pointer to buffer where read bytes should be copied
+ * @param integer - number of bytes to read
+ * @param integer - read timeout value in milliseconds
+ * @return integer - number of bytes read or TLS error
+ */
+int iot_tls_read(Network*, unsigned char*, int, int);
+
+/**
+ * @brief Disconnect from network socket
+ *
+ * @param Network - Pointer to a Network struct defining the network interface.
+ */
+void iot_tls_disconnect(Network *pNetwork);
+
+/**
+ * @brief Perform any tear-down or cleanup of TLS layer
+ *
+ * Called to cleanup any resources required for the TLS layer.
+ *
+ * @param Network - Pointer to a Network struct defining the network interface.
+ * @return integer - successful cleanup or TLS error
+ */
+int iot_tls_destroy(Network *pNetwork);
+
+/**
+ * @brief Check if TLS layer is still connected
+ *
+ * Called to check if the TLS layer is still connected or not.
+ *
+ * @param Network - Pointer to a Network struct defining the network interface.
+ * @return int - integer indicating status of network physical layer connection
+ */
+int iot_tls_is_connected(Network *pNetwork);
+
+#endif //__NETWORK_INTERFACE_H_
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/common/timer.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,45 @@
+/**
+ * @file timer.c
+ * @brief mbed-os implementation of the timer interface needed for AWS.
+ */
+
+#include <stddef.h>
+#include "timer_interface.h"
+
+TimerExt::TimerExt() {
+ unsigned int timeout_ms = 0;
+};
+
+char expired(Timer* timer) {
+ if (timer->read_ms() > timer->timeout_ms)
+ return 1;
+
+ return 0;
+}
+
+void countdown_ms(Timer* timer, unsigned int timeout) {
+ timer->timeout_ms = timeout;
+ timer->reset();
+ timer->start();
+}
+
+void countdown(Timer* timer, unsigned int timeout) {
+ timer->timeout_ms = (timeout * 1000);
+ timer->reset();
+ timer->start();
+}
+
+uint32_t left_ms(Timer* timer) {
+ if (timer->read_ms() < timer->timeout_ms)
+ return (timer->timeout_ms - timer->read_ms());
+
+ return 0;
+}
+
+void InitTimer(Timer* timer) {
+ timer->stop();
+ timer->reset();
+ timer->timeout_ms = 0;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/common/timer_platform.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 SRC_PROTOCOL_MQTT_AWS_IOT_EMBEDDED_CLIENT_WRAPPER_PLATFORM_LINUX_COMMON_TIMER_PLATFORM_H_
+#define SRC_PROTOCOL_MQTT_AWS_IOT_EMBEDDED_CLIENT_WRAPPER_PLATFORM_LINUX_COMMON_TIMER_PLATFORM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "Timer.h"
+
+/**
+ * Extension of the Platform specific Timer class
+ */
+class TimerExt : public mbed::Timer {
+public:
+ TimerExt();
+ int timeout_ms;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SRC_PROTOCOL_MQTT_AWS_IOT_EMBEDDED_CLIENT_WRAPPER_PLATFORM_LINUX_COMMON_TIMER_PLATFORM_H_ */
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/mbedtls/network_mbedtls_wrapper.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,440 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 <stdbool.h>
+#include <string.h>
+
+
+#include "aws_iot_config.h"
+#include "aws_iot_error.h"
+#include "aws_iot_log.h"
+#include "network_interface.h"
+#include "mbedtls/config.h"
+
+#include "mbedtls/net.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/certs.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/error.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/timing.h"
+#include "mbedtls/net_sockets.h"
+#include "pem.h"
+
+#include "platform.h"
+#include "WNCTCPSocketConnection.h"
+
+#ifdef USING_AVNET_SHIELD
+// Used for BIO connections
+extern WNCTCPSocketConnection* _tcpsocket;
+#endif
+
+/*
+ * This is a function to do further verification if needed on the cert received
+ */
+static int myCertVerify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) {
+ char buf[1024];
+ ((void) data);
+
+ DEBUG("\nVerify requested for (Depth %d):\n", depth);
+ mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
+ DEBUG("%s", buf);
+
+ if ((*flags) == 0) {
+ DEBUG(" This certificate has no flags\n");
+ } else {
+ DEBUG(buf, sizeof(buf), " ! ", *flags); DEBUG("%s\n", buf);
+ }
+
+ return (0);
+}
+
+static int ret = 0, i;
+static mbedtls_entropy_context entropy;
+static mbedtls_ctr_drbg_context ctr_drbg;
+static mbedtls_ssl_context ssl;
+static mbedtls_ssl_config conf;
+static uint32_t flags;
+static mbedtls_x509_crt cacert;
+static mbedtls_x509_crt clicert;
+static mbedtls_pk_context pkey;
+static mbedtls_net_context server_fd;
+
+// TODO: We can modify these functions to pull certs from an SD card
+int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n )
+{
+ //FILE *f;
+ //long size;
+
+ // Assign cert/key based on 'path'
+ /*
+ switch (path[0])
+ {
+ case 'r':
+ *n = (size_t)(sizeof(AWS_IOT_ROOT_CA)/sizeof(AWS_IOT_ROOT_CA[0]));
+ *buf = AWS_IOT_ROOT_CA;
+ break;
+ case 'c':
+ *n = (size_t)(sizeof(AWS_IOT_CERTIFICATE)/sizeof(AWS_IOT_CERTIFICATE[0]));
+ *buf = AWS_IOT_CERTIFICATE;
+ break;
+ case 'p':
+ *n = (size_t)sizeof (AWS_IOT_PRIVATE_KEY);
+ *buf = (unsigned char *) AWS_IOT_PRIVATE_KEY;
+
+ //ret = mbedtls_pk_parse_key(&pkey, (unsigned char *) AWS_IOT_PRIVATE_KEY, sizeof (AWS_IOT_PRIVATE_KEY), NULL, 0 );
+ break;
+ default:
+ ERROR(" failed\n ! Unknown option for cert/key\n\r");
+ }*/
+
+ /*
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
+
+ fseek( f, 0, SEEK_END );
+ if( ( size = ftell( f ) ) == -1 )
+ {
+ fclose( f );
+ return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
+ }
+ fseek( f, 0, SEEK_SET );
+
+ *n = (size_t) size;
+
+ if( *n + 1 == 0 ||
+ ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
+ {
+ //fclose( f );
+ return( MBEDTLS_ERR_PK_ALLOC_FAILED );
+ }
+
+ if( fread( *buf, 1, *n, f ) != *n )
+ {
+ fclose( f );
+ mbedtls_free( *buf );
+ return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
+ }
+
+ fclose( f );
+
+ (*buf)[*n] = '\0';
+
+ if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
+ ++*n;
+ */
+
+ return( 0 );
+}
+// Implementation that should never be optimized out by the compiler
+static void mbedtls_zeroize( unsigned char *v, size_t n ) {
+ volatile unsigned char *p = v; while( n-- ) *p++ = 0;
+}
+int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path )
+{
+ int ret;
+ size_t n;
+ unsigned char *buf;
+
+ if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 )
+ return( ret );
+
+ DEBUG("...CRT Parse");
+ ret = mbedtls_x509_crt_parse( chain, buf, n );
+
+ //mbedtls_zeroize( buf, n );
+ //mbedtls_free( buf );
+
+ return( ret );
+}
+int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx,
+ const char *path, const char *pwd )
+{
+ int ret;
+ size_t n;
+ unsigned char *buf;
+
+ if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 )
+ return( ret );
+
+ DEBUG("...Key Parse");
+ if( pwd == NULL ) {
+ DEBUG("...Using PWD");
+ ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 );
+ }
+ else {
+ DEBUG("...No PWD");
+ ret = mbedtls_pk_parse_key( ctx, buf, n, (const unsigned char *) pwd, strlen( pwd ) );
+ }
+
+ //mbedtls_zeroize( buf, n );
+ //mbedtls_free( buf );
+
+ return( ret );
+}
+// TODO: File system functions end
+
+/* personalization string for the drbg */
+const char *DRBG_PERS = "mbed TLS helloword client";
+
+int iot_tls_init(Network *pNetwork) {
+ IoT_Error_t ret_val = NONE_ERROR;
+ const char *pers = "aws_iot_tls_wrapper";
+ unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1];
+
+ mbedtls_net_init(&server_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ mbedtls_x509_crt_init(&cacert);
+ mbedtls_x509_crt_init(&clicert);
+ mbedtls_pk_init(&pkey);
+
+ DEBUG("...Seeding the random number generator");
+ mbedtls_entropy_init(&entropy);
+ if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) DRBG_PERS, sizeof (DRBG_PERS))) != 0) {
+ ERROR(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret);
+ return ret_val;
+ }
+ DEBUG(" ok\n");
+
+ pNetwork->my_socket = 0;
+ pNetwork->connect = iot_tls_connect;
+ pNetwork->mqttread = iot_tls_read;
+ pNetwork->mqttwrite = iot_tls_write;
+ pNetwork->disconnect = iot_tls_disconnect;
+ pNetwork->isConnected = iot_tls_is_connected;
+ pNetwork->destroy = iot_tls_destroy;
+
+ return ret_val;
+}
+
+int iot_tls_is_connected(Network *pNetwork) {
+ /* Use this to add implementation which can check for physical layer disconnect */
+ return 1;
+}
+
+int iot_tls_connect(Network *pNetwork, TLSConnectParams params) {
+ const char *pers = "aws_iot_tls_wrapper";
+
+ DEBUG("...Loading the CA root certificate");
+ // TODO: We can pull the cert from an SD card
+ //ret = mbedtls_x509_crt_parse_file(&cacert, params.pRootCALocation);
+ ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *)AWS_IOT_ROOT_CA, strlen ((const char *)AWS_IOT_ROOT_CA)+1);
+
+ if (ret < 0) {
+ ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
+ return ret;
+ }
+ DEBUG(" ok (%d skipped)", ret);
+
+
+ DEBUG("...Loading the client cert");
+ // TODO: We can pull the cert from an SD card
+ //ret = mbedtls_x509_crt_parse_file(&clicert, params.pDeviceCertLocation);
+ ret = mbedtls_x509_crt_parse(&clicert, (const unsigned char *)AWS_IOT_CERTIFICATE, strlen ((const char *)AWS_IOT_CERTIFICATE)+1);
+ if (ret != 0) {
+ ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
+ return ret;
+ }
+ DEBUG(" ok");
+
+
+ DEBUG("...Loading the client key");
+ // TODO: We can pull the cert from an SD card
+ //ret = mbedtls_pk_parse_keyfile(&pkey, params.pDevicePrivateKeyLocation, "");
+ ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *)AWS_IOT_PRIVATE_KEY, strlen ((const char *)AWS_IOT_PRIVATE_KEY)+1, NULL, 0 );
+ if (ret != 0) {
+ ERROR(" failed\n ! mbedtls_pk_parse_key returned -0x%x\n\n", -ret);
+ return ret;
+ }
+ DEBUG(" ok");
+
+
+ char portBuffer[6];
+ sprintf(portBuffer, "%d", params.DestinationPort);
+ DEBUG("...Connecting to %s/%s", params.pDestinationURL, portBuffer);
+ if ((ret = mbedtls_net_connect(&server_fd, params.pDestinationURL, portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) {
+ ERROR(" failed\n ! mbedtls_net_connect returned -0x%x\n\n", -ret);
+ return ret;
+ }
+
+
+ ret = mbedtls_net_set_block(&server_fd);
+ if (ret != 0) {
+ ERROR(" failed\n ! net_set_(non)block() returned -0x%x\n\n", -ret);
+ return ret;
+ }
+ DEBUG(" ok");
+
+
+ DEBUG("...Setting up the SSL/TLS structure");
+ if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ ERROR(" failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret);
+ return ret;
+ }
+
+
+ mbedtls_ssl_conf_verify(&conf, myCertVerify, NULL);
+ if (params.ServerVerificationFlag == true) {
+ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+ } else {
+ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
+ }
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+
+ mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
+ if ((ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey)) != 0) {
+ ERROR(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
+ return ret;
+ }
+
+ mbedtls_ssl_conf_read_timeout(&conf, params.timeout_ms);
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ ERROR(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", -ret);
+ return ret;
+ }
+ if ((ret = mbedtls_ssl_set_hostname(&ssl, params.pDestinationURL)) != 0) {
+ ERROR(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
+ return ret;
+ }
+
+ DEBUG("...Set Socket I/O Functions");
+ mbedtls_ssl_set_bio(&ssl, static_cast<void *>(_tcpsocket), mbedtls_net_send, NULL, mbedtls_net_recv_timeout );
+ DEBUG(" ok");
+
+
+ DEBUG("...Performing the SSL/TLS handshake");
+ while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ ERROR(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n", -ret);
+ if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
+ ERROR(" Unable to verify the server's certificate. "
+ "Either it is invalid,\n"
+ " or you didn't set ca_file or ca_path "
+ "to an appropriate value.\n"
+ " Alternatively, you may want to use "
+ "auth_mode=optional for testing purposes.\n");
+ }
+ return ret;
+ }
+ }
+
+
+ DEBUG(" ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n", mbedtls_ssl_get_version(&ssl), mbedtls_ssl_get_ciphersuite(&ssl));
+ if ((ret = mbedtls_ssl_get_record_expansion(&ssl)) >= 0) {
+ DEBUG(" [ Record expansion is %d ]\n", ret);
+ } else {
+ DEBUG(" [ Record expansion is unknown (compression) ]\n");
+ }
+
+
+ DEBUG("...Verifying peer X.509 certificate");
+ if (params.ServerVerificationFlag == true) {
+ if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
+ char vrfy_buf[512];
+ ERROR(" failed\n");
+ mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
+ ERROR("%s\n", vrfy_buf);
+ } else {
+ DEBUG(" ok\n");
+ ret = NONE_ERROR;
+ }
+ } else {
+ DEBUG(" Server Verification skipped\n");
+ ret = NONE_ERROR;
+ }
+
+
+ DEBUG("...SSL get peer cert");
+ if (mbedtls_ssl_get_peer_cert(&ssl) != NULL) {
+ DEBUG("...Peer certificate information");
+ const uint32_t buf_size = 1024;
+ char *buf = new char[buf_size];
+ mbedtls_x509_crt_info(buf, buf_size, " ", mbedtls_ssl_get_peer_cert(&ssl));
+ DEBUG("...Server certificate:\r\n%s\r", buf);
+ }
+
+ mbedtls_ssl_conf_read_timeout(&conf, 10);
+
+ return ret;
+}
+
+int iot_tls_write(Network *pNetwork, unsigned char *pMsg, int len, int timeout_ms) {
+
+ int written;
+ int frags;
+
+ for (written = 0, frags = 0; written < len; written += ret, frags++) {
+ while ((ret = mbedtls_ssl_write(&ssl, pMsg + written, len - written)) <= 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ ERROR(" failed\n ! mbedtls_ssl_write returned -0x%x\n\n", -ret);
+ return ret;
+ }
+ }
+ }
+
+ return written;
+}
+
+int iot_tls_read(Network *pNetwork, unsigned char *pMsg, int len, int timeout_ms) {
+ int rxLen = 0;
+ bool isErrorFlag = false;
+ bool isCompleteFlag = false;
+
+ // TODO check this against base
+ //mbedtls_ssl_conf_read_timeout(&conf, timeout_ms);
+
+ do {
+ ret = mbedtls_ssl_read(&ssl, pMsg, len);
+ if (ret > 0) {
+ rxLen += ret;
+ } else if (ret != MBEDTLS_ERR_SSL_WANT_READ) {
+ isErrorFlag = true;
+ }
+ if (rxLen >= len) {
+ isCompleteFlag = true;
+ }
+ } while (!isErrorFlag && !isCompleteFlag);
+
+ return ret;
+}
+
+void iot_tls_disconnect(Network *pNetwork) {
+ do {
+ ret = mbedtls_ssl_close_notify(&ssl);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+}
+
+int iot_tls_destroy(Network *pNetwork) {
+
+ mbedtls_net_free(&server_fd);
+
+ mbedtls_x509_crt_free(&clicert);
+ mbedtls_x509_crt_free(&cacert);
+ mbedtls_pk_free(&pkey);
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+
+ return 0;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/openssl/network.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,201 @@
+/**
+ * @file timer.c
+ * @brief mbed-os implementation of the network interface needed for AWS.
+ */
+#include "network_interface.h"
+#include "EthernetInterface.h"
+
+#include "aws_iot_config.h"
+#include "aws_iot_log.h"
+
+#include "mbedtls/net_sockets.h"
+
+//=====================================================================================================================
+//
+// Uses Avnet Sheild (AT&T wireless LTE)
+//
+//=====================================================================================================================
+#ifdef USING_AVNET_SHIELD
+#include "WNCInterface.h"
+#include "WNCTCPSocketConnection.h"
+
+// Expose serial for WNC boot
+extern MODSERIAL pc;
+
+// Network socket
+WNCTCPSocketConnection* _tcpsocket;
+
+int net_modem_boot()
+{
+ INFO("Booting WNC modem...");
+ int rc = -1;
+ WNCInterface eth_iface;
+
+ INFO("...Using Avnet AT&T wireless Shield");
+ rc = eth_iface.init(NULL, &pc);
+ INFO("WNC Module %s initialized (%02X).", rc?"IS":"IS NOT", rc);
+ if( !rc ) {
+ ERROR("DHCP failed.");
+ return rc;
+ }
+
+ eth_iface.connect();
+ INFO("...IP Address: %s ", eth_iface.getIPAddress());
+ return rc;
+}
+
+void mbedtls_net_init( mbedtls_net_context *ctx )
+{
+ DEBUG("...mbedtls_net_init()");
+
+ _tcpsocket = new WNCTCPSocketConnection;
+
+ return;
+}
+
+int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto )
+{
+ DEBUG("...mbedtls_net_connect");
+ int ret = -1;
+
+ /* Connect to the server */
+ INFO("Connecting with %s\r\n", host);
+ ret = _tcpsocket->connect(host, AWS_IOT_MQTT_PORT); //TODO
+
+ return ret;
+}
+
+int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, uint32_t timeout )
+{
+ DEBUG("...mbedtls_net_recv_timeout len: %d, timeout: %d", len, timeout);
+ return (int)_tcpsocket->receive((char*)buf, len);
+}
+
+int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
+{
+ DEBUG("...mbedtls_net_send");
+ return _tcpsocket->send((char*)buf, len);
+}
+
+int mbedtls_net_set_block( mbedtls_net_context *ctx )
+{
+ _tcpsocket->set_blocking (false,1500);
+ return 0;
+}
+
+void mbedtls_net_free( mbedtls_net_context *ctx )
+{
+ DEBUG("...TODO: mbedtls_net_free");
+ return;
+}
+
+
+//=====================================================================================================================
+//
+// Uses FRDM-K64F wired ethernet
+//
+//=====================================================================================================================
+#else
+// Network Socket
+TCPSocket* _tcpsocket;
+
+int net_modem_boot()
+{
+ // Do nothing
+}
+
+void mbedtls_net_init( mbedtls_net_context *ctx )
+{
+ DEBUG("...mbedtls_net_init()");
+ EthernetInterface eth_iface;
+
+ eth_iface.connect();
+ INFO("...Using FRDM-K64F Ethernet LWIP");
+ const char *ip_addr = eth_iface.get_ip_address();
+ if (ip_addr) {
+ INFO("...Client IP Address is %s", ip_addr);
+ } else {
+ INFO("...No Client IP Address");
+ }
+ _tcpsocket = new TCPSocket(ð_iface);
+
+ //ctx->fd = -1;
+ return;
+}
+
+int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto )
+{
+ DEBUG("...mbedtls_net_connect");
+ int ret;
+ uint16_t _port = AWS_IOT_MQTT_PORT; // TODO
+
+ INFO("...Connecting with %s", host);
+ ret = _tcpsocket->connect(host, _port);
+ _tcpsocket->bind(host, _port);
+ if (ret != NSAPI_ERROR_OK) {
+ ERROR("Failed to connect");
+ return ret;
+ }
+
+ INFO("...Connected to Amazon!");
+ return ret;
+}
+
+int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, uint32_t timeout )
+{
+ DEBUG("...mbedtls_net_recv_timeout len: %d, timeout: %d", len, timeout);
+
+ int recv = -1;
+ //TCPSocket *socket = static_cast<TCPSocket *>(ctx);
+ //socket->set_blocking(false);
+ //recv = socket->recv(buf, len);
+ //_tcpsocket->set_blocking(true);
+ _tcpsocket->set_timeout(timeout);
+ recv = _tcpsocket->recv(buf, len);
+
+ if(NSAPI_ERROR_WOULD_BLOCK == recv ||
+ recv == 0){
+ DEBUG("...NSAPI_ERROR_WOULD_BLOCK");
+ return 0;
+ }else if(recv < 0){
+ ERROR("...RECV FAIL");
+ return -1;
+ }else{
+ DEBUG("...RECV OK: %d, %d", len, recv);
+ return recv;
+ }
+}
+
+int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
+{
+ DEBUG("...mbedtls_net_send");
+
+ int size = -1;
+ //TCPSocket *socket = static_cast<TCPSocket *>(ctx);
+ //size = socket->send(buf, len);
+ size = _tcpsocket->send(buf, len);
+
+ if(NSAPI_ERROR_WOULD_BLOCK == size){
+ DEBUG("...SEND OK, len = %d", len);
+ return len;
+ }else if(size < 0){
+ ERROR("...SEND FAIL");
+ return -1;
+ }else{
+ DEBUG("...SEND OK, size = %d", size);
+ return size;
+ }
+}
+
+int mbedtls_net_set_block( mbedtls_net_context *ctx )
+{
+ _tcpsocket->set_blocking(false);
+ return 0;
+}
+
+void mbedtls_net_free( mbedtls_net_context *ctx )
+{
+ DEBUG("...TODO: mbedtls_net_free");
+ return;
+}
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/timer_interface.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * 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:
+ * Allan Stockdill-Mander - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+/**
+ * @file timer_interface.h
+ * @brief Timer interface definition for MQTT client.
+ *
+ * Defines an interface to timers that can be used by other system
+ * components. MQTT client requires timers to handle timeouts and
+ * MQTT keep alive.
+ * Starting point for porting the SDK to the timer hardware layer of a new platform.
+ */
+
+#ifndef __TIMER_INTERFACE_H_
+#define __TIMER_INTERFACE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The platform specific timer header that defines the Timer struct
+ */
+#include "timer_platform.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/**
+ * @brief Timer Type
+ *
+ * Forward declaration of a timer struct. The definition of this struct is
+ * platform dependent. When porting to a new platform add this definition
+ * in "timer_<platform>.h" and include that file above.
+ *
+ */
+//typedef mbed::Timer Timer;
+typedef TimerExt Timer;
+
+char expired(Timer* timer);
+void countdown(Timer* timer, unsigned int timeout);
+void InitTimer(Timer* timer);
+
+/**
+ * @brief Check if a timer is expired
+ *
+ * Call this function passing in a timer to check if that timer has expired.
+ *
+ * @param Timer - pointer to the timer to be checked for expiration
+ * @return bool - true = timer expired, false = timer not expired
+ */
+bool has_timer_expired(Timer *);
+//bool has_timer_expired(mbed::Timer object); //TODO: modified to mbed::timer
+
+/**
+ * @brief Create a timer (milliseconds)
+ *
+ * Sets the timer to expire in a specified number of milliseconds.
+ *
+ * @param Timer - pointer to the timer to be set to expire in milliseconds
+ * @param uint32_t - set the timer to expire in this number of milliseconds
+ */
+void countdown_ms(Timer *, uint32_t);
+//void countdown_ms(mbed::Timer object, uint32_t);
+
+/**
+ * @brief Create a timer (seconds)
+ *
+ * Sets the timer to expire in a specified number of seconds.
+ *
+ * @param Timer - pointer to the timer to be set to expire in seconds
+ * @param uint32_t - set the timer to expire in this number of seconds
+ */
+void countdown_sec(Timer *, uint32_t);
+//void countdown_sec(mbed::Timer object, uint32_t);
+
+/**
+ * @brief Check the time remaining on a given timer
+ *
+ * Checks the input timer and returns the number of milliseconds remaining on the timer.
+ *
+ * @param Timer - pointer to the timer to be set to checked
+ * @return int - milliseconds left on the countdown timer
+ */
+uint32_t left_ms(Timer *);
+//uint32_t left_ms(mbed::Timer object);
+
+/**
+ * @brief Initialize a timer
+ *
+ * Performs any initialization required to the timer passed in.
+ *
+ * @param Timer - pointer to the timer to be initialized
+ */
+void init_timer(Timer *);
+//void init_timer(mbed::Timer object);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__TIMER_INTERFACE_H_
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_mqtt_interface.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 aws_iot_mqtt_interface.h
+ * @brief Interface definition for MQTT client.
+ */
+
+#ifndef AWS_IOT_SDK_SRC_IOT_MQTT_INTERFACE_H_
+#define AWS_IOT_SDK_SRC_IOT_MQTT_INTERFACE_H_
+
+#include "stddef.h"
+#include "stdbool.h"
+#include "stdint.h"
+#include "aws_iot_error.h"
+
+/**
+ * @brief MQTT Version Type
+ *
+ * Defining an MQTT version type.
+ *
+ */
+typedef enum {
+ MQTT_3_1 = 3, ///< MQTT 3.1 (protocol message byte = 3)
+ MQTT_3_1_1 = 4 ///< MQTT 3.1.1 (protocol message byte = 4)
+} MQTT_Ver_t;
+
+/**
+ * @brief Quality of Service Type
+ *
+ * Defining a QoS type.
+ * @note QoS 2 is \b NOT supported by the AWS IoT Service at the time of this SDK release.
+ *
+ */
+typedef enum {
+ QOS_0, ///< QoS 0 = at most once delivery
+ QOS_1, ///< QoS 1 = at least once delivery
+ QOS_2 ///< QoS 2 is NOT supported
+} QoSLevel;
+
+/**
+ * @brief Last Will and Testament Definition
+ *
+ * Defining a type for LWT parameters.
+ * @note Retained messages are \b NOT supported by the AWS IoT Service at the time of this SDK release.
+ *
+ */
+typedef struct {
+ const char *pTopicName; ///< LWT Topic
+ const char *pMessage; ///< Message to be delivered as LWT
+ bool isRetained; ///< NOT supported
+ QoSLevel qos; ///< QoS of LWT message
+} MQTTwillOptions;
+extern const MQTTwillOptions MQTTwillOptionsDefault;
+
+/**
+ * @brief Disconnect Callback Handler Type
+ *
+ * Defining a TYPE for definition of disconnect callback function pointers.
+ *
+ */
+typedef void (*iot_disconnect_handler)(void);
+
+/**
+ * @brief MQTT Connection Parameters
+ *
+ * Defining a type for MQTT connection parameters. Passed into client when establishing a connection.
+ *
+ */
+typedef struct {
+ uint8_t enableAutoReconnect; ///< Set to true to enable auto reconnect
+ char *pHostURL; ///< Pointer to a string defining the endpoint for the MQTT service
+ uint16_t port; ///< MQTT service listening port
+ char *pRootCALocation; ///< Pointer to a string defining the Root CA file (full file, not path)
+ char *pDeviceCertLocation; ///< Pointer to a string defining the device identity certificate file (full file, not path)
+ char *pDevicePrivateKeyLocation; ///< Pointer to a string defining the device private key file (full file, not path)
+ char *pClientID; ///< Pointer to a string defining the MQTT client ID (this needs to be unique \b per \b device across your AWS account)
+ char *pUserName; ///< Not used in the AWS IoT Service
+ char *pPassword; ///< Not used in the AWS IoT Service
+ MQTT_Ver_t MQTTVersion; ///< Desired MQTT version used during connection
+ uint16_t KeepAliveInterval_sec; ///< MQTT keep alive interval in seconds. Defines inactivity time allowed before determining the connection has been lost.
+ bool isCleansession; ///< MQTT clean session. True = this session is to be treated as clean. Previous server state is cleared and no stated is retained from this connection.
+ bool isWillMsgPresent; ///< Is there a LWT associated with this connection?
+ MQTTwillOptions will; ///< MQTT LWT parameters.
+ uint32_t mqttCommandTimeout_ms; ///< Timeout for MQTT blocking calls. In milliseconds.
+ uint32_t tlsHandshakeTimeout_ms; ///< TLS handshake timeout. In milliseconds.
+ bool isSSLHostnameVerify; ///< Client should perform server certificate hostname validation.
+ iot_disconnect_handler disconnectHandler; ///< Callback to be invoked upon connection loss.
+} MQTTConnectParams;
+extern const MQTTConnectParams MQTTConnectParamsDefault;
+
+/**
+ * @brief MQTT Message Parameters
+ *
+ * Defines a type for properties of MQTT messages including topic, payload an QoS.
+ *
+ */
+typedef struct {
+ QoSLevel qos; ///< Message Quality of Service
+ bool isRetained; ///< Retained messages are \b NOT supported by the AWS IoT Service at the time of this SDK release.
+ bool isDuplicate; ///< Is this message a duplicate QoS > 0 message? Handled automatically by the MQTT client.
+ uint16_t id; ///< Message sequence identifier. Handled automatically by the MQTT client.
+ void *pPayload; ///< Pointer to MQTT message payload (bytes).
+ uint32_t PayloadLen; ///< Length of MQTT payload.
+} MQTTMessageParams;
+extern const MQTTMessageParams MQTTMessageParamsDefault;
+/**
+ * @brief MQTT Callback Function Parameters
+ *
+ * Defines a type for parameters returned to the user upon receipt of a publish message on a subscribed topic.
+ *
+ */
+typedef struct {
+ char *pTopicName; ///< Pointer to the topic string on which the message was delivered. In the case of a wildcard subscription this is the actual topic, not the wildcard filter.
+ uint16_t TopicNameLen; ///< Length of the topic string.
+ MQTTMessageParams MessageParams; ///< Message parameters structure.
+} MQTTCallbackParams;
+extern const MQTTCallbackParams MQTTCallbackParamsDefault;
+
+/**
+ * @brief MQTT Callback Function
+ *
+ * Defines a type for the function pointer which stores the message callback function.
+ * A pointer to the desired callback function to be invoked upon receipt of a message on a subscribed toipc.
+ * Supplied upon subscribing to a topic.
+ *
+ */
+typedef int32_t (*iot_message_handler)(MQTTCallbackParams params);
+
+/**
+ * @brief MQTT Subscription Parameters
+ *
+ * Defines the parameters needed when subscribing to an MQTT topic.
+ *
+ */
+typedef struct {
+ char *pTopic; ///< Pointer to the string defining the desired subscription topic.
+ QoSLevel qos; ///< Quality of service of the subscription.
+ iot_message_handler mHandler; ///< Callback to be invoked upon receipt of a message on the subscribed topic.
+} MQTTSubscribeParams;
+extern const MQTTSubscribeParams MQTTSubscribeParamsDefault;
+
+/**
+ * @brief MQTT Publish Parameters
+ *
+ * Defines a type for parameters supplied when publishing an MQTT message.
+ *
+ */
+typedef struct {
+ char *pTopic; ///< Pointer to the string defining the desired publishing topic.
+ MQTTMessageParams MessageParams; ///< Parameters defining the message to be published.
+} MQTTPublishParams;
+extern const MQTTPublishParams MQTTPublishParamsDefault;
+
+/**
+ * @brief MQTT Connection Function
+ *
+ * Called to establish an MQTT connection with the AWS IoT Service
+ *
+ * @param pParams Pointer to MQTT connection parameters
+ * @return An IoT Error Type defining successful/failed connection
+ */
+IoT_Error_t aws_iot_mqtt_connect(MQTTConnectParams *pParams);
+
+/**
+ * @brief Publish an MQTT message on a topic
+ *
+ * Called to publish an MQTT message on a topic.
+ * @note Call is blocking. In the case of a QoS 0 message the function returns
+ * after the message was successfully passed to the TLS layer. In the case of QoS 1
+ * the function returns after the receipt of the PUBACK control packet.
+ *
+ * @param pParams Pointer to MQTT publish parameters
+ * @return An IoT Error Type defining successful/failed publish
+ */
+IoT_Error_t aws_iot_mqtt_publish(MQTTPublishParams *pParams);
+
+/**
+ * @brief Subscribe to an MQTT topic.
+ *
+ * Called to send a subscribe message to the broker requesting a subscription
+ * to an MQTT topic.
+ * @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
+ *
+ * @param pParams Pointer to MQTT subscribe parameters
+ * @return An IoT Error Type defining successful/failed subscription
+ */
+IoT_Error_t aws_iot_mqtt_subscribe(MQTTSubscribeParams *pParams);
+
+/**
+ * @brief Unsubscribe to an MQTT topic.
+ *
+ * Called to send an usubscribe message to the broker requesting removal of a subscription
+ * to an MQTT topic.
+ * @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet.
+ *
+ * @param pTopic Pointer to the requested topic string. Ensure the string is null terminated
+ * @return An IoT Error Type defining successful/failed unsubscription
+ */
+IoT_Error_t aws_iot_mqtt_unsubscribe(char *pTopic);
+
+/**
+ * @brief MQTT Manual Re-Connection Function
+ *
+ * Called to establish an MQTT connection with the AWS IoT Service
+ * using parameters from the last time a connection was attempted
+ * Use after disconnect to start the reconnect process manually
+ * Makes only one reconnect attempt
+ *
+ * @return An IoT Error Type defining successful/failed connection
+ */
+IoT_Error_t aws_iot_mqtt_attempt_reconnect(void);
+
+/**
+ * @brief Disconnect an MQTT Connection
+ *
+ * Called to send a disconnect message to the broker.
+ *
+ * @return An IoT Error Type defining successful/failed send of the disconnect control packet.
+ */
+IoT_Error_t aws_iot_mqtt_disconnect(void);
+
+/**
+ * @brief Yield to the MQTT client
+ *
+ * Called to yield the current thread to the underlying MQTT client. This time is used by
+ * the MQTT client to manage PING requests to monitor the health of the TCP connection as
+ * well as periodically check the socket receive buffer for subscribe messages. Yield()
+ * must be called at a rate faster than the keepalive interval. It must also be called
+ * at a rate faster than the incoming message rate as this is the only way the client receives
+ * processing time to manage incoming messages.
+ *
+ * @param timeout Maximum number of milliseconds to pass thread execution to the client.
+ * @return An IoT Error Type defining successful/failed client processing.
+ * If this call results in an error it is likely the MQTT connection has dropped.
+ * iot_is_mqtt_connected can be called to confirm.
+ */
+IoT_Error_t aws_iot_mqtt_yield(int timeout);
+
+/**
+ * @brief Is the MQTT client currently connected?
+ *
+ * Called to determine if the MQTT client is currently connected. Used to support logic
+ * in the device application around reconnecting and managing offline state.
+ *
+ * @return true = connected, false = not currently connected
+ */
+bool aws_iot_is_mqtt_connected(void);
+
+/**
+ * @brief Is the MQTT client set to reconnect automatically?
+ *
+ * Called to determine if the MQTT client is set to reconnect automatically.
+ * Used to support logic in the device application around reconnecting
+ *
+ * @return true = enabled, false = disabled
+ */
+bool aws_iot_is_autoreconnect_enabled(void);
+
+/**
+ * @brief Enable or Disable AutoReconnect on Network Disconnect
+ *
+ * Called to enable or disabled the auto reconnect features provided with the SDK
+ *
+ * @param value set to true for enabling and false for disabling
+ *
+ * @return IoT_Error_t Type defining successful/failed API call
+ */
+IoT_Error_t aws_iot_mqtt_autoreconnect_set_status(bool value);
+
+typedef IoT_Error_t (*pConnectFunc_t)(MQTTConnectParams *pParams);
+typedef IoT_Error_t (*pPublishFunc_t)(MQTTPublishParams *pParams);
+typedef IoT_Error_t (*pSubscribeFunc_t)(MQTTSubscribeParams *pParams);
+typedef IoT_Error_t (*pUnsubscribeFunc_t)(char *pTopic);
+typedef IoT_Error_t (*pDisconnectFunc_t)(void);
+typedef IoT_Error_t (*pYieldFunc_t)(int timeout);
+typedef bool (*pIsConnectedFunc_t)(void);
+typedef bool (*pIsAutoReconnectEnabledFunc_t)(void);
+typedef IoT_Error_t (*pReconnectFunc_t)();
+typedef IoT_Error_t (*pSetAutoReconnectStatusFunc_t)(bool);
+/**
+ * @brief MQTT Client Type Definition
+ *
+ * Defines a structure of function pointers, each implementing a corresponding iot_mqtt_*
+ * function. In this way any MQTT client which implements the iot_mqtt_* interface
+ * can be swapped in under the MQTT/Shadow layer.
+ *
+ */
+typedef struct{
+ pConnectFunc_t connect; ///< function implementing the iot_mqtt_connect function
+ pPublishFunc_t publish; ///< function implementing the iot_mqtt_publish function
+ pSubscribeFunc_t subscribe; ///< function implementing the iot_mqtt_subscribe function
+ pUnsubscribeFunc_t unsubscribe; ///< function implementing the iot_mqtt_unsubscribe function
+ pDisconnectFunc_t disconnect; ///< function implementing the iot_mqtt_disconnect function
+ pYieldFunc_t yield; ///< function implementing the iot_mqtt_yield function
+ pIsConnectedFunc_t isConnected; ///< function implementing the iot_is_mqtt_connected function
+ pReconnectFunc_t reconnect; ///< function implementing the iot_mqtt_reconnect function
+ pIsAutoReconnectEnabledFunc_t isAutoReconnectEnabled; ///< function implementing the iot_is_autoreconnect_enabled function
+ pSetAutoReconnectStatusFunc_t setAutoReconnectStatus; ///< function implementing the iot_mqtt_autoreconnect_set_status function
+}MQTTClient_t;
+
+
+/**
+ * @brief Set the MQTT client
+ *
+ * This function provides a way to pass in an MQTT client implementation to the
+ * AWS IoT MQTT wrapper layer. This is done through function pointers to the
+ * interface functions.
+ *
+ */
+void aws_iot_mqtt_init(MQTTClient_t *pClient);
+
+
+#endif /* AWS_IOT_SDK_SRC_IOT_MQTT_INTERFACE_H_ */
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 "aws_iot_error.h"
+#include "aws_iot_log.h"
+#include "aws_iot_shadow_actions.h"
+#include "aws_iot_shadow_json.h"
+#include "aws_iot_shadow_key.h"
+#include "aws_iot_shadow_records.h"
+
+const ShadowParameters_t ShadowParametersDefault = {
+ .pMyThingName = AWS_IOT_MY_THING_NAME,
+ .pMqttClientId = AWS_IOT_MQTT_CLIENT_ID,
+ .pHost = AWS_IOT_MQTT_HOST,
+ .port = AWS_IOT_MQTT_PORT,
+ .pRootCA = NULL,
+ .pClientCRT = NULL,
+ .pClientKey = NULL
+};
+
+void aws_iot_shadow_reset_last_received_version(void) {
+ shadowJsonVersionNum = 0;
+}
+
+uint32_t aws_iot_shadow_get_last_received_version(void) {
+ return shadowJsonVersionNum;
+}
+
+void aws_iot_shadow_enable_discard_old_delta_msgs(void) {
+ shadowDiscardOldDeltaFlag = true;
+}
+
+void aws_iot_shadow_disable_discard_old_delta_msgs(void) {
+ shadowDiscardOldDeltaFlag = false;
+}
+
+IoT_Error_t aws_iot_shadow_init(MQTTClient_t *pClient) {
+
+ IoT_Error_t rc = NONE_ERROR;
+
+ if (pClient == NULL) {
+ return NULL_VALUE_ERROR;
+ }
+
+ resetClientTokenSequenceNum();
+ aws_iot_shadow_reset_last_received_version();
+ initDeltaTokens();
+ return NONE_ERROR;
+}
+
+IoT_Error_t aws_iot_shadow_connect(MQTTClient_t *pClient, ShadowParameters_t *pParams) {
+ IoT_Error_t rc = NONE_ERROR;
+
+ MQTTConnectParams ConnectParams = MQTTConnectParamsDefault;
+ if (pClient == NULL) {
+ return NULL_VALUE_ERROR;
+ }
+
+ if (pClient->connect == NULL) {
+ return NULL_VALUE_ERROR;
+ }
+
+ snprintf(myThingName, MAX_SIZE_OF_THING_NAME, "%s", pParams->pMyThingName );
+ snprintf(mqttClientID, MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES, "%s", pParams->pMqttClientId );
+
+ INFO("...Thing Name %s", myThingName);
+ INFO("...MQTT Client ID %s", mqttClientID);
+
+ ConnectParams.KeepAliveInterval_sec = 10;
+ ConnectParams.MQTTVersion = MQTT_3_1_1;
+ ConnectParams.mqttCommandTimeout_ms = 10000;//2000;
+ ConnectParams.tlsHandshakeTimeout_ms = 10000;
+ ConnectParams.isCleansession = true;
+ ConnectParams.isSSLHostnameVerify = true;
+ ConnectParams.isWillMsgPresent = false;
+ ConnectParams.pClientID = pParams->pMqttClientId;
+ ConnectParams.pDeviceCertLocation = pParams->pClientCRT;
+ ConnectParams.pDevicePrivateKeyLocation = pParams->pClientKey;
+ ConnectParams.pRootCALocation = pParams->pRootCA;
+ ConnectParams.pPassword = NULL;
+ ConnectParams.pUserName = NULL;
+ ConnectParams.pHostURL = pParams->pHost;
+ ConnectParams.port = pParams->port;
+ ConnectParams.disconnectHandler = NULL;
+
+ rc = pClient->connect(&ConnectParams);
+
+ if(rc == NONE_ERROR){
+ initializeRecords(pClient);
+ }
+
+ return rc;
+}
+
+IoT_Error_t aws_iot_shadow_register_delta(MQTTClient_t *pClient, jsonStruct_t *pStruct) {
+ IoT_Error_t rc = NONE_ERROR;
+
+ if (!(pClient->isConnected())) {
+ return CONNECTION_ERROR;
+ }
+
+ rc = registerJsonTokenOnDelta(pStruct);
+
+ return rc;
+}
+
+IoT_Error_t aws_iot_shadow_yield(MQTTClient_t *pClient, int timeout) {
+ HandleExpiredResponseCallbacks();
+ return pClient->yield(timeout);
+}
+
+IoT_Error_t aws_iot_shadow_disconnect(MQTTClient_t *pClient) {
+ return pClient->disconnect();
+}
+
+IoT_Error_t aws_iot_shadow_update(MQTTClient_t *pClient, const char *pThingName, char *pJsonString,
+ fpActionCallback_t callback, void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe) {
+
+ IoT_Error_t ret_val = NONE_ERROR;
+
+ if (!(pClient->isConnected())) {
+ return CONNECTION_ERROR;
+ }
+
+ ret_val = iot_shadow_action(pClient, pThingName, SHADOW_UPDATE, pJsonString, callback, pContextData,
+ timeout_seconds, isPersistentSubscribe);
+
+ return ret_val;
+}
+
+IoT_Error_t aws_iot_shadow_delete(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
+ void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe) {
+ IoT_Error_t ret_val = NONE_ERROR;
+
+ if (!(pClient->isConnected())) {
+ return CONNECTION_ERROR;
+ }
+
+ char deleteRequestJsonBuf[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
+ iot_shadow_delete_request_json(deleteRequestJsonBuf);
+ ret_val = iot_shadow_action(pClient, pThingName, SHADOW_DELETE, deleteRequestJsonBuf, callback, pContextData,
+ timeout_seconds, isPersistentSubscribe);
+
+ return ret_val;
+}
+
+IoT_Error_t aws_iot_shadow_get(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
+ void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe) {
+
+ IoT_Error_t ret_val = NONE_ERROR;
+
+ if (!(pClient->isConnected())) {
+ return CONNECTION_ERROR;
+ }
+
+ char getRequestJsonBuf[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
+
+ iot_shadow_get_request_json(getRequestJsonBuf);
+
+ ret_val = iot_shadow_action(pClient, pThingName, SHADOW_GET, getRequestJsonBuf, callback, pContextData,
+ timeout_seconds, isPersistentSubscribe);
+
+ return ret_val;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_actions.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 "aws_iot_shadow_actions.h"
+
+#include "aws_iot_log.h"
+#include "aws_iot_shadow_json.h"
+#include "aws_iot_shadow_records.h"
+#include "aws_iot_config.h"
+
+IoT_Error_t iot_shadow_action(MQTTClient_t *pClient, const char *pThingName, ShadowActions_t action,
+ const char *pJsonDocumentToBeSent, fpActionCallback_t callback, void *pCallbackContext,
+ uint32_t timeout_seconds, bool isSticky) {
+
+ IoT_Error_t ret_val = NONE_ERROR;
+ bool isCallbackPresent = false;
+ bool isClientTokenPresent = false;
+ bool isAckWaitListFree = false;
+ uint8_t indexAckWaitList;
+
+ if(pClient == NULL || pThingName == NULL || pJsonDocumentToBeSent == NULL){
+ return NULL_VALUE_ERROR;
+ }
+
+ if (callback != NULL) {
+ isCallbackPresent = true;
+ }
+
+ char extractedClientToken[MAX_SIZE_CLIENT_ID_WITH_SEQUENCE];
+ isClientTokenPresent = extractClientToken(pJsonDocumentToBeSent, extractedClientToken);
+
+ if (isClientTokenPresent && isCallbackPresent) {
+ if (getNextFreeIndexOfAckWaitList(&indexAckWaitList)) {
+ isAckWaitListFree = true;
+ }
+
+ if(isAckWaitListFree) {
+ if (!isSubscriptionPresent(pThingName, action)) {
+ ret_val = subscribeToShadowActionAcks(pThingName, action, isSticky);
+ } else {
+ incrementSubscriptionCnt(pThingName, action, isSticky);
+ }
+ }
+ else {
+ ret_val = GENERIC_ERROR;
+ }
+ }
+
+
+ if (ret_val == NONE_ERROR) {
+ ret_val = publishToShadowAction(pThingName, action, pJsonDocumentToBeSent);
+ }
+
+ if (isClientTokenPresent && isCallbackPresent && ret_val == NONE_ERROR && isAckWaitListFree) {
+ addToAckWaitList(indexAckWaitList, pThingName, action, extractedClientToken, callback, pCallbackContext,
+ timeout_seconds);
+ }
+ return ret_val;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_actions.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 SRC_SHADOW_AWS_IOT_SHADOW_ACTIONS_H_ +#define SRC_SHADOW_AWS_IOT_SHADOW_ACTIONS_H_ + +#include "aws_iot_shadow_interface.h" + +IoT_Error_t iot_shadow_action(MQTTClient_t *pClient, const char *pThingName, ShadowActions_t action, + const char *pJsonDocumentToBeSent, fpActionCallback_t callback, void *pCallbackContext, + uint32_t timeout_seconds, bool isSticky); + +#endif /* SRC_SHADOW_AWS_IOT_SHADOW_ACTIONS_H_ */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_interface.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 AWS_IOT_SDK_SRC_IOT_SHADOW_H_
+#define AWS_IOT_SDK_SRC_IOT_SHADOW_H_
+
+
+/**
+ * @file aws_iot_shadow_interface.h
+ * @brief Interface for thing shadow
+ *
+ * These are the functions and structs to manage/interact the Thing Shadow(in the cloud).
+ * This SDK will let you interact with your own thing shadow or any other shadow using its Thing Name.
+ * There are totally 3 actions a device can perform on the shadow - Get, Update and Delete.
+ *
+ * Currently the device should use MQTT/S underneath. In the future this will also support other protocols. As it supports MQTT, the shadow needs to connect and disconnect.
+ * It will also work on the pub/sub model. On performing any action, the acknowledgment will be received in either accepted or rejected. For Example:
+ * If we want to perform a GET on the thing shadow the following messages will be sent and received:
+ * 1. A MQTT Publish on the topic - $aws/things/{thingName}/shadow/get
+ * 2. Subscribe to MQTT topics - $aws/things/{thingName}/shadow/get/accepted and $aws/things/{thingName}/shadow/get/rejected.
+ * If the request was successful we will receive the things json document in the accepted topic.
+ *
+ *
+ */
+#include "aws_iot_mqtt_interface.h"
+#include "aws_iot_shadow_json_data.h"
+
+/*!
+ * @brief Shadow Connect parameters
+ *
+ * As the Shadow SDK uses MQTT underneath, it could be connected and disconnected on events to save some battery.
+ * @note Always use the \c ShadowParametersDefault to initialize this struct
+ *
+ *
+ *
+ */
+typedef struct {
+ char *pMyThingName; ///< Every device has a Thing Shadow and this is the placeholder for name
+ char *pMqttClientId; ///< Currently the Shadow uses MQTT to connect and it is important to ensure we have unique client id
+ char *pHost; ///< This will be unique to a customer and can be retrieved from the console
+ int port; ///< By default the port is 8883
+ char *pRootCA; ///< Location with the Filename of the Root CA
+ char *pClientCRT; ///< Location of Device certs signed by AWS IoT service
+ char *pClientKey; ///< Location of Device private key
+} ShadowParameters_t;
+
+/*!
+ * @brief This is set to defaults from the configuration file
+ * The certs are set to NULL because they need the path to the file. shadow_sample.c file demonstrates on how to get the relative path
+ *
+ * \relates ShadowParameters_t
+ */
+extern const ShadowParameters_t ShadowParametersDefault;
+
+
+/**
+ * @brief Initialize the Thing Shadow before use
+ *
+ * This function takes care of initializing the internal book-keeping data structures
+ *
+ * @param pClient MQTT Client used as the protocol layer
+ * @return An IoT Error Type defining successful/failed Initialization
+ */
+IoT_Error_t aws_iot_shadow_init(MQTTClient_t *pClient);
+/**
+ * @brief Connect to the AWS IoT Thing Shadow service over MQTT
+ *
+ * This function does the TLSv1.2 handshake and establishes the MQTT connection
+ *
+ * @param pClient MQTT Client used as the protocol layer
+ * @param pParams Shadow Conenction parameters like TLS cert location
+ * @return An IoT Error Type defining successful/failed Connection
+ */
+IoT_Error_t aws_iot_shadow_connect(MQTTClient_t *pClient, ShadowParameters_t *pParams);
+/**
+ * @brief Yield function to let the background tasks of MQTT and Shadow
+ *
+ * This function could be use in a separate thread waiting for the incoming messages, ensuring the connection is kept alive with the AWS Service.
+ * It also ensures the expired requests of Shadow actions are cleared and Timeout callback is executed.
+ * @note All callbacks ever used in the SDK will be executed in the context of this function.
+ *
+ * @param pClient MQTT Client used as the protocol layer
+ * @param timeout in milliseconds, This is the maximum time the yield function will wait for a message and/or read the messages from the TLS buffer
+ * @return An IoT Error Type defining successful/failed Yield
+ */
+IoT_Error_t aws_iot_shadow_yield(MQTTClient_t *pClient, int timeout);
+/**
+ * @brief Disconnect from the AWS IoT Thing Shadow service over MQTT
+ *
+ * This will close the underlying TCP connection, MQTT connection will also be closed
+ *
+ * @param pClient MQTT Client used as the protocol layer
+ * @return An IoT Error Type defining successful/failed disconnect status
+ */
+IoT_Error_t aws_iot_shadow_disconnect(MQTTClient_t *pClient);
+
+/**
+ * @brief Thing Shadow Acknowledgment enum
+ *
+ * This enum type is use in the callback for the action response
+ *
+ */
+typedef enum {
+ SHADOW_ACK_TIMEOUT, SHADOW_ACK_REJECTED, SHADOW_ACK_ACCEPTED
+} Shadow_Ack_Status_t;
+
+/**
+ * @brief Thing Shadow Action type enum
+ *
+ * This enum type is use in the callback for the action response
+ *
+ */
+typedef enum {
+ SHADOW_GET, SHADOW_UPDATE, SHADOW_DELETE
+} ShadowActions_t;
+
+
+/**
+ * @brief Function Pointer typedef used as the callback for every action
+ *
+ * This function will be called from the context of \c aws_iot_shadow_yield() context
+ *
+ * @param pThingName Thing Name of the response received
+ * @param action The response of the action
+ * @param status Informs if the action was Accepted/Rejected or Timed out
+ * @param pReceivedJsonDocument Received JSON document
+ * @param pContextData the void* data passed in during the action call(update, get or delete)
+ *
+ */
+typedef void (*fpActionCallback_t)(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
+ const char *pReceivedJsonDocument, void *pContextData);
+
+/**
+ * @brief This function is the one used to perform an Update action to a Thing Name's Shadow.
+ *
+ * update is one of the most frequently used functionality by a device. In most cases the device may be just reporting few params to update the thing shadow in the cloud
+ * Update Action if no callback or if the JSON document does not have a client token then will just publish the update and not track it.
+ *
+ * @note The update has to subscribe to two topics update/accepted and update/rejected. This function waits 2 seconds to ensure the subscriptions are registered before publishing the update message.
+ * The following steps are performed on using this function:
+ * 1. Subscribe to Shadow topics - $aws/things/{thingName}/shadow/update/accepted and $aws/things/{thingName}/shadow/update/rejected
+ * 2. wait for 2 seconds for the subscription to take effect
+ * 3. Publish on the update topic - $aws/things/{thingName}/shadow/update
+ * 4. In the \c aws_iot_shadow_yield() function the response will be handled. In case of timeout or if the response is received, the subscription to shadow response topics are un-subscribed from.
+ * On the contrary if the persistent subscription is set to true then the un-subscribe will not be done. The topics will always be listened to.
+ *
+ * @param pClient MQTT Client used as the protocol layer
+ * @param pThingName Thing Name of the shadow that needs to be Updated
+ * @param pJsonString The update action expects a JSON document to send. The JSO String should be a null terminated string. This JSON document should adhere to the AWS IoT Thing Shadow specification. To help in the process of creating this document- SDK provides apis in \c aws_iot_shadow_json_data.h
+ * @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
+ * @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
+ * @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
+ * @param isPersistentSubscribe As mentioned above, every time if a device updates the same shadow then this should be set to true to avoid repeated subscription and unsubscription. If the Thing Name is one off update then this should be set to false
+ * @return An IoT Error Type defining successful/failed update action
+ */
+IoT_Error_t aws_iot_shadow_update(MQTTClient_t *pClient, const char *pThingName, char *pJsonString,
+ fpActionCallback_t callback, void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe);
+
+/**
+ * @brief This function is the one used to perform an Get action to a Thing Name's Shadow.
+ *
+ * One use of this function is usually to get the config of a device at boot up.
+ * It is similar to the Update function internally except it does not take a JSON document as the input. The entire JSON document will be sent over the accepted topic
+ *
+ * @param pClient MQTT Client used as the protocol layer
+ * @param pThingName Thing Name of the JSON document that is needed
+ * @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
+ * @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
+ * @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
+ * @param isPersistentSubscribe As mentioned above, every time if a device gets the same Sahdow (JSON document) then this should be set to true to avoid repeated subscription and un-subscription. If the Thing Name is one off get then this should be set to false
+ * @return An IoT Error Type defining successful/failed get action
+ */
+IoT_Error_t aws_iot_shadow_get(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
+ void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe);
+/**
+ * @brief This function is the one used to perform an Delete action to a Thing Name's Shadow.
+ *
+ * This is not a very common use case for device. It is generally the responsibility of the accompanying app to do the delete.
+ * It is similar to the Update function internally except it does not take a JSON document as the input. The Thing Shadow referred by the ThingName will be deleted.
+ *
+ * @param pClient MQTT Client used as the protocol layer
+ * @param pThingName Thing Name of the Shadow that should be deleted
+ * @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
+ * @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
+ * @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
+ * @param isPersistentSubscribe As mentioned above, every time if a device deletes the same Sahdow (JSON document) then this should be set to true to avoid repeated subscription and un-subscription. If the Thing Name is one off delete then this should be set to false
+ * @return An IoT Error Type defining successful/failed delete action
+ */
+IoT_Error_t aws_iot_shadow_delete(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
+ void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscriptions);
+
+/**
+ * @brief This function is used to listen on the delta topic of #AWS_IOT_MY_THING_NAME mentioned in the aws_iot_config.h file.
+ *
+ * Any time a delta is published the Json document will be delivered to the pStruct->cb. If you don't want the parsing done by the SDK then use the jsonStruct_t key set to "state". A good example of this is displayed in the sample_apps/shadow_console_echo.c
+ *
+ * @param pClient MQTT Client used as the protocol layer
+ * @param pStruct The struct used to parse JSON value
+ * @return An IoT Error Type defining successful/failed delta registering
+ */
+IoT_Error_t aws_iot_shadow_register_delta(MQTTClient_t *pClient, jsonStruct_t *pStruct);
+
+/**
+ * @brief Reset the last received version number to zero.
+ * This will be useful if the Thing Shadow is deleted and would like to to reset the local version
+ * @return no return values
+ *
+ */
+void aws_iot_shadow_reset_last_received_version(void);
+/**
+ * @brief Version of a document is received with every accepted/rejected and the SDK keeps track of the last received version of the JSON document of #AWS_IOT_MY_THING_NAME shadow
+ *
+ * One exception to this version tracking is that, the SDK will ignore the version from update/accepted topic. Rest of the responses will be scanned to update the version number.
+ * Accepting version change for update/accepted may cause version conflicts for delta message if the update message is received before the delta.
+ *
+ * @return version number of the last received response
+ *
+ */
+uint32_t aws_iot_shadow_get_last_received_version(void);
+/**
+ * @brief Enable the ignoring of delta messages with old version number
+ *
+ * As we use MQTT underneath, there could be more than 1 of the same message if we use QoS 0. To avoid getting called for the same message, this functionality should be enabled. All the old message will be ignored
+ */
+void aws_iot_shadow_enable_discard_old_delta_msgs(void);
+/**
+ * @brief Disable the ignoring of delta messages with old version number
+ */
+void aws_iot_shadow_disable_discard_old_delta_msgs(void);
+
+#endif //AWS_IOT_SDK_SRC_IOT_SHADOW_H_
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_json.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 "aws_iot_shadow_json.h"
+
+#include <string.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include "aws_iot_json_utils.h"
+#include "aws_iot_log.h"
+#include "aws_iot_shadow_key.h"
+#include "aws_iot_config.h"
+
+extern char mqttClientID[MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES];
+
+static uint32_t clientTokenNum = 0;
+
+//helper functions
+static IoT_Error_t convertDataToString(char *pStringBuffer, size_t maxSizoStringBuffer, JsonPrimitiveType type,
+ void *pData);
+
+void resetClientTokenSequenceNum(void) {
+ clientTokenNum = 0;
+}
+
+static void emptyJsonWithClientToken(char *pJsonDocument) {
+ sprintf(pJsonDocument, "{\"clientToken\":\"");
+ FillWithClientToken(pJsonDocument + strlen(pJsonDocument));
+ sprintf(pJsonDocument + strlen(pJsonDocument), "\"}");
+}
+
+void iot_shadow_get_request_json(char *pJsonDocument) {
+ emptyJsonWithClientToken(pJsonDocument);
+}
+
+void iot_shadow_delete_request_json(char *pJsonDocument) {
+ emptyJsonWithClientToken(pJsonDocument);
+}
+
+static inline IoT_Error_t checkReturnValueOfSnPrintf(int32_t snPrintfReturn, size_t maxSizeOfJsonDocument) {
+
+ if (snPrintfReturn >= maxSizeOfJsonDocument) {
+ return SHADOW_JSON_BUFFER_TRUNCATED;
+ } else if (snPrintfReturn < 0) {
+ return SHADOW_JSON_ERROR;
+ }
+ return NONE_ERROR;
+}
+
+IoT_Error_t aws_iot_shadow_init_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument) {
+
+ IoT_Error_t ret_val = NONE_ERROR;
+ int32_t snPrintfReturn = 0;
+
+ if (pJsonDocument == NULL) {
+ return NULL_VALUE_ERROR;
+ }
+ snPrintfReturn = snprintf(pJsonDocument, maxSizeOfJsonDocument, "{\"state\":{");
+
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, maxSizeOfJsonDocument);
+
+ return ret_val;
+
+}
+
+IoT_Error_t aws_iot_shadow_add_desired(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...) {
+ IoT_Error_t ret_val = NONE_ERROR;
+ int32_t tempSize = 0;
+ int8_t i;
+ size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
+ int32_t snPrintfReturn = 0;
+ va_list pArgs;
+ va_start(pArgs, count);
+ jsonStruct_t *pTemporary;
+
+ if (pJsonDocument == NULL) {
+ return NULL_VALUE_ERROR;
+ }
+
+ tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+ if(tempSize <= 1){
+ return SHADOW_JSON_ERROR;
+ }
+ remSizeOfJsonBuffer = tempSize;
+
+ snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"desired\":{");
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+
+ if (ret_val != NONE_ERROR) {
+ return ret_val;
+ }
+
+ for (i = 0; i < count; i++) {
+ tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+ if(tempSize <= 1){
+ return SHADOW_JSON_ERROR;
+ }
+ remSizeOfJsonBuffer = tempSize;
+ pTemporary = va_arg (pArgs, jsonStruct_t *);
+ if (pTemporary != NULL) {
+ snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"%s\":",
+ pTemporary->pKey);
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+ if (ret_val != NONE_ERROR) {
+ return ret_val;
+ }
+ if (pTemporary->pKey != NULL && pTemporary->pData != NULL) {
+ ret_val = convertDataToString(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer,
+ pTemporary->type, pTemporary->pData);
+ } else {
+ return NULL_VALUE_ERROR;
+ }
+ if (ret_val != NONE_ERROR) {
+ return ret_val;
+ }
+ } else {
+ return NULL_VALUE_ERROR;
+ }
+ }
+
+ va_end(pArgs);
+ snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "},");
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+ return ret_val;
+}
+
+IoT_Error_t aws_iot_shadow_add_reported(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...) {
+ IoT_Error_t ret_val = NONE_ERROR;
+
+ int8_t i;
+ size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
+ int32_t snPrintfReturn = 0;
+ int32_t tempSize = 0;
+ va_list pArgs;
+ va_start(pArgs, count);
+ jsonStruct_t *pTemporary;
+
+ if (pJsonDocument == NULL) {
+ return NULL_VALUE_ERROR;
+ }
+
+
+ tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+ if(tempSize <= 1){
+ return SHADOW_JSON_ERROR;
+ }
+ remSizeOfJsonBuffer = tempSize;
+
+ snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"reported\":{");
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+
+ if (ret_val != NONE_ERROR) {
+ return ret_val;
+ }
+
+ for (i = 0; i < count; i++) {
+ tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+ if(tempSize <= 1){
+ return SHADOW_JSON_ERROR;
+ }
+ remSizeOfJsonBuffer = tempSize;
+
+ pTemporary = va_arg (pArgs, jsonStruct_t *);
+ if (pTemporary != NULL) {
+ snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"%s\":",
+ pTemporary->pKey);
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+ if (ret_val != NONE_ERROR) {
+ return ret_val;
+ }
+ if (pTemporary->pKey != NULL && pTemporary->pData != NULL) {
+ ret_val = convertDataToString(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer,
+ pTemporary->type, pTemporary->pData);
+ } else {
+ return NULL_VALUE_ERROR;
+ }
+ if (ret_val != NONE_ERROR) {
+ return ret_val;
+ }
+ } else {
+ return NULL_VALUE_ERROR;
+ }
+ }
+
+ va_end(pArgs);
+ snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "},");
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+ return ret_val;
+}
+
+
+int32_t FillWithClientTokenSize(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument) {
+ int32_t snPrintfReturn;
+ snPrintfReturn = snprintf(pBufferToBeUpdatedWithClientToken, maxSizeOfJsonDocument, "%s-%d", mqttClientID,
+ clientTokenNum++);
+
+ return snPrintfReturn;
+}
+
+IoT_Error_t aws_iot_fill_with_client_token(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument){
+
+ int32_t snPrintfRet = 0;
+ snPrintfRet = FillWithClientTokenSize(pBufferToBeUpdatedWithClientToken, maxSizeOfJsonDocument);
+ return checkReturnValueOfSnPrintf(snPrintfRet, maxSizeOfJsonDocument);
+
+}
+
+IoT_Error_t aws_iot_finalize_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument) {
+ size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
+ int32_t snPrintfReturn = 0;
+ int32_t tempSize = 0;
+ IoT_Error_t ret_val = NONE_ERROR;
+
+ if (pJsonDocument == NULL) {
+ return NULL_VALUE_ERROR;
+ }
+
+ tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+ if(tempSize <= 1){
+ return SHADOW_JSON_ERROR;
+ }
+ remSizeOfJsonBuffer = tempSize;
+
+ // strlen(ShadowTxBuffer) - 1 is to ensure we remove the last ,(comma) that was added
+ snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "}, \"%s\":\"",
+ SHADOW_CLIENT_TOKEN_STRING);
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+
+ if (ret_val != NONE_ERROR) {
+ return ret_val;
+ }
+ // refactor this XXX repeated code
+ tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+ if(tempSize <= 1){
+ return SHADOW_JSON_ERROR;
+ }
+ remSizeOfJsonBuffer = tempSize;
+
+
+ snPrintfReturn = FillWithClientTokenSize(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer);
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+
+ if (ret_val != NONE_ERROR) {
+ return ret_val;
+ }
+ tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+ if(tempSize <= 1){
+ return SHADOW_JSON_ERROR;
+ }
+ remSizeOfJsonBuffer = tempSize;
+
+
+ snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"}");
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+
+ return ret_val;
+}
+
+void FillWithClientToken(char *pBufferToBeUpdatedWithClientToken) {
+ sprintf(pBufferToBeUpdatedWithClientToken, "%s-%d", mqttClientID, clientTokenNum++);
+}
+
+static IoT_Error_t convertDataToString(char *pStringBuffer, size_t maxSizoStringBuffer, JsonPrimitiveType type,
+ void *pData) {
+ int32_t snPrintfReturn = 0;
+ IoT_Error_t ret_val = NONE_ERROR;
+
+ if (maxSizoStringBuffer == 0) {
+ return SHADOW_JSON_ERROR;
+ }
+
+ if (type == SHADOW_JSON_INT32) {
+ //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi32",", *(int32_t * )(pData));
+ snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%li,", *(int32_t * )(pData));
+ } else if (type == SHADOW_JSON_INT16) {
+ //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi16",", *(int16_t * )(pData));
+ snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%i,", *(int16_t * )(pData));
+ } else if (type == SHADOW_JSON_INT8) {
+ //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi8",", *(int8_t * )(pData));
+ snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%i,", *(int8_t * )(pData));
+ } else if (type == SHADOW_JSON_UINT32) {
+ //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu32",", *(uint32_t * )(pData));
+ snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%lu,", *(uint32_t * )(pData));
+ } else if (type == SHADOW_JSON_UINT16) {
+ //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu16",", *(uint16_t * )(pData));
+ snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%u,", *(uint16_t * )(pData));
+ } else if (type == SHADOW_JSON_UINT8) {
+ //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu8",", *(uint8_t * )(pData));
+ snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%u,", *(uint8_t * )(pData));
+ } else if (type == SHADOW_JSON_DOUBLE) {
+ snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(double * )(pData));
+ } else if (type == SHADOW_JSON_FLOAT) {
+ snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(float * )(pData));
+ } else if (type == SHADOW_JSON_BOOL) {
+ snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%s,", *(bool *)(pData)?"true":"false");
+ } else if (type == SHADOW_JSON_STRING) {
+ snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "\"%s\",", (char * )(pData));
+ }
+
+ ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, maxSizoStringBuffer);
+
+ return ret_val;
+}
+static jsmn_parser shadowJsonParser;
+static jsmntok_t jsonTokenStruct[MAX_JSON_TOKEN_EXPECTED];
+
+bool isJsonValidAndParse(const char *pJsonDocument, void *pJsonHandler, int32_t *pTokenCount) {
+ int32_t tokenCount;
+
+ jsmn_init(&shadowJsonParser);
+
+ tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
+ sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
+
+ if (tokenCount < 0) {
+ WARN("Failed to parse JSON: %d\n", tokenCount);
+ return false;
+ }
+
+ /* Assume the top-level element is an object */
+ if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
+ WARN("Top Level is not an object\n");
+ return false;
+ }
+
+ pJsonHandler = (void *) jsonTokenStruct;
+ *pTokenCount = tokenCount;
+
+ return true;
+}
+
+static IoT_Error_t UpdateValueIfNoObject(const char *pJsonString, jsonStruct_t *pDataStruct, jsmntok_t token) {
+ IoT_Error_t ret_val = NONE_ERROR;
+ if (pDataStruct->type == SHADOW_JSON_BOOL) {
+ ret_val = parseBooleanValue((bool *)pDataStruct->pData, pJsonString, &token);
+ } else if (pDataStruct->type == SHADOW_JSON_INT32) {
+ ret_val = parseInteger32Value((int32_t *)pDataStruct->pData, pJsonString, &token);
+ } else if (pDataStruct->type == SHADOW_JSON_INT16) {
+ ret_val = parseInteger16Value((int16_t *)pDataStruct->pData, pJsonString, &token);
+ } else if (pDataStruct->type == SHADOW_JSON_INT8) {
+ ret_val = parseInteger8Value((int8_t *)pDataStruct->pData, pJsonString, &token);
+ } else if (pDataStruct->type == SHADOW_JSON_UINT32) {
+ ret_val = parseUnsignedInteger32Value((uint32_t *)pDataStruct->pData, pJsonString, &token);
+ } else if (pDataStruct->type == SHADOW_JSON_UINT16) {
+ ret_val = parseUnsignedInteger16Value((uint16_t *)pDataStruct->pData, pJsonString, &token);
+ } else if (pDataStruct->type == SHADOW_JSON_UINT8) {
+ ret_val = parseUnsignedInteger8Value((uint8_t *)pDataStruct->pData, pJsonString, &token);
+ } else if (pDataStruct->type == SHADOW_JSON_FLOAT) {
+ ret_val = parseFloatValue((float *)pDataStruct->pData, pJsonString, &token);
+ } else if (pDataStruct->type == SHADOW_JSON_DOUBLE) {
+ ret_val = parseDoubleValue((double *)pDataStruct->pData, pJsonString, &token);
+ }
+
+ return ret_val;
+}
+
+bool isJsonKeyMatchingAndUpdateValue(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount,
+ jsonStruct_t *pDataStruct, uint32_t *pDataLength, int32_t *pDataPosition) {
+ int32_t i;
+
+ jsmntok_t *pJsonTokenStruct;
+
+ pJsonTokenStruct = (jsmntok_t *) pJsonHandler;
+ for (i = 1; i < tokenCount; i++) {
+ if (jsoneq(pJsonDocument, &(jsonTokenStruct[i]), pDataStruct->pKey) == 0) {
+ jsmntok_t dataToken = jsonTokenStruct[i + 1];
+ uint32_t dataLength = dataToken.end - dataToken.start;
+ UpdateValueIfNoObject(pJsonDocument, pDataStruct, dataToken);
+ *pDataPosition = dataToken.start;
+ *pDataLength = dataLength;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isReceivedJsonValid(const char *pJsonDocument) {
+ int32_t tokenCount;
+
+ jsmn_init(&shadowJsonParser);
+
+ tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
+ sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
+
+ if (tokenCount < 0) {
+ WARN("Failed to parse JSON: %d\n", tokenCount);
+ return false;
+ }
+
+ /* Assume the top-level element is an object */
+ if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
+ return false;
+ }
+
+ return true;
+}
+
+bool extractClientToken(const char *pJsonDocument, char *pExtractedClientToken) {
+ bool ret_val = false;
+ jsmn_init(&shadowJsonParser);
+ int32_t tokenCount, i;
+ jsmntok_t ClientJsonToken;
+
+ tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
+ sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
+
+ if (tokenCount < 0) {
+ WARN("Failed to parse JSON: %d\n", tokenCount);
+ return false;
+ }
+
+ /* Assume the top-level element is an object */
+ if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
+ return false;
+ }
+
+ for (i = 1; i < tokenCount; i++) {
+ if (jsoneq(pJsonDocument, &jsonTokenStruct[i], SHADOW_CLIENT_TOKEN_STRING) == 0) {
+ ClientJsonToken = jsonTokenStruct[i + 1];
+ uint8_t length = ClientJsonToken.end - ClientJsonToken.start;
+ strncpy(pExtractedClientToken, pJsonDocument + ClientJsonToken.start, length);
+ pExtractedClientToken[length] = '\0';
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool extractVersionNumber(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount, uint32_t *pVersionNumber) {
+ int32_t i;
+ jsmntok_t *pJsonTokenStruct;
+ IoT_Error_t ret_val = NONE_ERROR;
+
+ pJsonTokenStruct = (jsmntok_t *) pJsonHandler;
+ for (i = 1; i < tokenCount; i++) {
+ if (jsoneq(pJsonDocument, &(jsonTokenStruct[i]), SHADOW_VERSION_STRING) == 0) {
+ jsmntok_t dataToken = jsonTokenStruct[i + 1];
+ uint32_t dataLength = dataToken.end - dataToken.start;
+ ret_val = parseUnsignedInteger32Value(pVersionNumber, pJsonDocument, &dataToken);
+ if (ret_val == NONE_ERROR) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_json.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 AWS_IOT_SDK_SRC_IOT_SHADOW_JSON_H_ +#define AWS_IOT_SDK_SRC_IOT_SHADOW_JSON_H_ + +#include <stdint.h> +#include <stdbool.h> +#include <stdarg.h> + +#include "aws_iot_error.h" +#include "aws_iot_shadow_json_data.h" + +bool isJsonValidAndParse(const char *pJsonDocument, void *pJsonHandler, int32_t *pTokenCount); +bool isJsonKeyMatchingAndUpdateValue(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount, + jsonStruct_t *pDataStruct, uint32_t *pDataLength, int32_t *pDataPosition); + +void iot_shadow_get_request_json(char *pJsonDocument); +void iot_shadow_delete_request_json(char *pJsonDocument); +void resetClientTokenSequenceNum(void); + + +bool isReceivedJsonValid(const char *pJsonDocument); +void FillWithClientToken(char *pStringToUpdateClientToken); +bool extractClientToken(const char *pJsonDocumentToBeSent, char *pExtractedClientToken); +bool extractVersionNumber(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount, uint32_t *pVersionNumber); +#endif // AWS_IOT_SDK_SRC_IOT_SHADOW_JSON_H_ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_json_data.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 SRC_SHADOW_AWS_IOT_SHADOW_JSON_DATA_H_
+#define SRC_SHADOW_AWS_IOT_SHADOW_JSON_DATA_H_
+
+/**
+ * @file aws_iot_shadow_json_data.h
+ * @brief This file is the interface for all the Shadow related JSON functions.
+ */
+
+#include <stddef.h>
+
+/**
+ * @brief This is a static JSON object that could be used in code
+ *
+ */
+typedef struct jsonStruct jsonStruct_t;
+/**
+ * @brief Every JSON name value can have a callback. The callback should follow this signature
+ */
+typedef void (*jsonStructCallback_t)(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t);
+
+/**
+ * @brief All the JSON object types enum
+ *
+ * JSON number types need to be split into proper integer / floating point data types and sizes on embedded platforms.
+ */
+typedef enum {
+ SHADOW_JSON_INT32,
+ SHADOW_JSON_INT16,
+ SHADOW_JSON_INT8,
+ SHADOW_JSON_UINT32,
+ SHADOW_JSON_UINT16,
+ SHADOW_JSON_UINT8,
+ SHADOW_JSON_FLOAT,
+ SHADOW_JSON_DOUBLE,
+ SHADOW_JSON_BOOL,
+ SHADOW_JSON_STRING,
+ SHADOW_JSON_OBJECT
+} JsonPrimitiveType;
+
+/**
+ * @brief This is the struct form of a JSON Key value pair
+ */
+struct jsonStruct {
+ const char *pKey; ///< JSON key
+ void *pData; ///< pointer to the data (JSON value)
+ JsonPrimitiveType type; ///< type of JSON
+ jsonStructCallback_t cb; ///< callback to be executed on receiving the Key value pair
+};
+
+/**
+ * @brief Initialize the JSON document with Shadow expected name/value
+ *
+ * This Function will fill the JSON Buffer with a null terminated string. Internally it uses snprintf
+ * This function should always be used First, followed by iot_shadow_add_reported and/or iot_shadow_add_desired.
+ * Always finish the call sequence with iot_finalize_json_document
+ *
+ * @note Ensure the size of the Buffer is enough to hold the entire JSON Document.
+ *
+ *
+ * @param pJsonDocument The JSON Document filled in this char buffer
+ * @param maxSizeOfJsonDocument maximum size of the pJsonDocument that can be used to fill the JSON document
+ * @return An IoT Error Type defining if the buffer was null or the entire string was not filled up
+ */
+IoT_Error_t aws_iot_shadow_init_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument);
+
+/**
+ * @brief Add the reported section of the JSON document of jsonStruct_t
+ *
+ * This is a variadic function and please be careful with the usage. count is the number of jsonStruct_t types that you would like to add in the reported section
+ * This function will add "reported":{<all the values that needs to be added>}
+ *
+ * @note Ensure the size of the Buffer is enough to hold the reported section + the init section. Always use the same JSON document buffer used in the iot_shadow_init_json_document function. This function will accommodate the size of previous null terminated string, so pass teh max size of the buffer
+ *
+ *
+ * @param pJsonDocument The JSON Document filled in this char buffer
+ * @param maxSizeOfJsonDocument maximum size of the pJsonDocument that can be used to fill the JSON document
+ * @param count total number of arguments(jsonStruct_t object) passed in the arguments
+ * @return An IoT Error Type defining if the buffer was null or the entire string was not filled up
+ */
+IoT_Error_t aws_iot_shadow_add_reported(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...);
+
+/**
+ * @brief Add the desired section of the JSON document of jsonStruct_t
+ *
+ * This is a variadic function and please be careful with the usage. count is the number of jsonStruct_t types that you would like to add in the reported section
+ * This function will add "desired":{<all the values that needs to be added>}
+ *
+ * @note Ensure the size of the Buffer is enough to hold the reported section + the init section. Always use the same JSON document buffer used in the iot_shadow_init_json_document function. This function will accommodate the size of previous null terminated string, so pass the max size of the buffer
+ *
+ *
+ * @param pJsonDocument The JSON Document filled in this char buffer
+ * @param maxSizeOfJsonDocument maximum size of the pJsonDocument that can be used to fill the JSON document
+ * @param count total number of arguments(jsonStruct_t object) passed in the arguments
+ * @return An IoT Error Type defining if the buffer was null or the entire string was not filled up
+ */
+IoT_Error_t aws_iot_shadow_add_desired(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...);
+
+/**
+ * @brief Finalize the JSON document with Shadow expected client Token.
+ *
+ * This function will automatically increment the client token every time this function is called.
+ *
+ * @note Ensure the size of the Buffer is enough to hold the entire JSON Document. If the finalized section is not invoked then the JSON doucment will not be valid
+ *
+ *
+ * @param pJsonDocument The JSON Document filled in this char buffer
+ * @param maxSizeOfJsonDocument maximum size of the pJsonDocument that can be used to fill the JSON document
+ * @return An IoT Error Type defining if the buffer was null or the entire string was not filled up
+ */
+IoT_Error_t aws_iot_finalize_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument);
+
+/**
+ * @brief Fill the given buffer with client token for tracking the Repsonse.
+ *
+ * This function will add the AWS_IOT_MQTT_CLIENT_ID with a sequence number. Every time this function is used the sequence number gets incremented
+ *
+ *
+ * @param pBufferToBeUpdatedWithClientToken buffer to be updated with the client token string
+ * @param maxSizeOfJsonDocument maximum size of the pBufferToBeUpdatedWithClientToken that can be used
+ * @return An IoT Error Type defining if the buffer was null or the entire string was not filled up
+ */
+
+IoT_Error_t aws_iot_fill_with_client_token(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument);
+
+#endif /* SRC_SHADOW_AWS_IOT_SHADOW_JSON_DATA_H_ */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_key.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 SRC_SHADOW_AWS_IOT_SHADOW_KEY_H_ +#define SRC_SHADOW_AWS_IOT_SHADOW_KEY_H_ + +#define SHADOW_CLIENT_TOKEN_STRING "clientToken" +#define SHADOW_VERSION_STRING "version" + +#endif /* SRC_SHADOW_AWS_IOT_SHADOW_KEY_H_ */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_records.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,486 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 "aws_iot_shadow_records.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include "timer_interface.h"
+#include "aws_iot_json_utils.h"
+#include "aws_iot_log.h"
+#include "aws_iot_shadow_json.h"
+#include "aws_iot_config.h"
+
+typedef struct {
+ char clientTokenID[MAX_SIZE_CLIENT_ID_WITH_SEQUENCE];
+ char thingName[MAX_SIZE_OF_THING_NAME];
+ ShadowActions_t action;
+ fpActionCallback_t callback;
+ void *pCallbackContext;
+ bool isFree;
+ Timer timer;
+} ToBeReceivedAckRecord_t;
+
+typedef struct {
+ const char *pKey;
+ void *pStruct;
+ jsonStructCallback_t callback;
+ bool isFree;
+} JsonTokenTable_t;
+
+typedef struct {
+ char Topic[MAX_SHADOW_TOPIC_LENGTH_BYTES];
+ uint8_t count;
+ bool isFree;
+ bool isSticky;
+} SubscriptionRecord_t;
+
+typedef enum {
+ SHADOW_ACCEPTED, SHADOW_REJECTED, SHADOW_ACTION
+} ShadowAckTopicTypes_t;
+
+ToBeReceivedAckRecord_t AckWaitList[MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME];
+
+MQTTClient_t *pMqttClient;
+
+char myThingName[MAX_SIZE_OF_THING_NAME];
+char mqttClientID[MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES];
+
+char shadowDeltaTopic[MAX_SHADOW_TOPIC_LENGTH_BYTES];
+
+#define MAX_TOPICS_AT_ANY_GIVEN_TIME 2*MAX_THINGNAME_HANDLED_AT_ANY_GIVEN_TIME
+SubscriptionRecord_t SubscriptionList[MAX_TOPICS_AT_ANY_GIVEN_TIME];
+
+#define SUBSCRIBE_SETTLING_TIME 2
+char shadowRxBuf[SHADOW_MAX_SIZE_OF_RX_BUFFER];
+
+static JsonTokenTable_t tokenTable[MAX_JSON_TOKEN_EXPECTED];
+static uint32_t tokenTableIndex = 0;
+static bool deltaTopicSubscribedFlag = false;
+uint32_t shadowJsonVersionNum = 0;
+bool shadowDiscardOldDeltaFlag = true;
+
+// local helper functions
+static int AckStatusCallback(MQTTCallbackParams params);
+static int shadow_delta_callback(MQTTCallbackParams params);
+static void topicNameFromThingAndAction(char *pTopic, const char *pThingName, ShadowActions_t action,
+ ShadowAckTopicTypes_t ackType);
+static int16_t getNextFreeIndexOfSubscriptionList(void);
+static void unsubscribeFromAcceptedAndRejected(uint8_t index);
+
+void initDeltaTokens(void) {
+ uint32_t i;
+ for (i = 0; i < MAX_JSON_TOKEN_EXPECTED; i++) {
+ tokenTable[i].isFree = true;
+ }
+ tokenTableIndex = 0;
+ deltaTopicSubscribedFlag = false;
+}
+
+IoT_Error_t registerJsonTokenOnDelta(jsonStruct_t *pStruct) {
+
+ IoT_Error_t rc = NONE_ERROR;
+
+ if (!deltaTopicSubscribedFlag) {
+ MQTTSubscribeParams subParams;
+ subParams.mHandler = shadow_delta_callback;
+ snprintf(shadowDeltaTopic,MAX_SHADOW_TOPIC_LENGTH_BYTES, "$aws/things/%s/shadow/update/delta", myThingName);
+ subParams.pTopic = shadowDeltaTopic;
+ subParams.qos = QOS_0;
+ rc = pMqttClient->subscribe(&subParams);
+ DEBUG("delta topic %s", shadowDeltaTopic);
+ deltaTopicSubscribedFlag = true;
+ }
+
+ if (tokenTableIndex >= MAX_JSON_TOKEN_EXPECTED) {
+ return GENERIC_ERROR;
+ }
+
+ tokenTable[tokenTableIndex].pKey = pStruct->pKey;
+ tokenTable[tokenTableIndex].callback = pStruct->cb;
+ tokenTable[tokenTableIndex].pStruct = pStruct;
+ tokenTable[tokenTableIndex].isFree = false;
+ tokenTableIndex++;
+
+ return rc;
+}
+
+static int16_t getNextFreeIndexOfSubscriptionList(void) {
+ uint8_t i;
+ for (i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
+ if (SubscriptionList[i].isFree) {
+ SubscriptionList[i].isFree = false;
+ return i;
+ }
+ }
+ return -1;
+}
+
+static void topicNameFromThingAndAction(char *pTopic, const char *pThingName, ShadowActions_t action,
+ ShadowAckTopicTypes_t ackType) {
+
+ char actionBuf[10];
+ char ackTypeBuf[10];
+
+ if (action == SHADOW_GET) {
+ strcpy(actionBuf, "get");
+ } else if (action == SHADOW_UPDATE) {
+ strcpy(actionBuf, "update");
+ } else if (action == SHADOW_DELETE) {
+ strcpy(actionBuf, "delete");
+ }
+
+ if (ackType == SHADOW_ACCEPTED) {
+ strcpy(ackTypeBuf, "accepted");
+ } else if (ackType == SHADOW_REJECTED) {
+ strcpy(ackTypeBuf, "rejected");
+ }
+
+ if (ackType == SHADOW_ACTION) {
+ sprintf(pTopic, "$aws/things/%s/shadow/%s", pThingName, actionBuf);
+ } else {
+ sprintf(pTopic, "$aws/things/%s/shadow/%s/%s", pThingName, actionBuf, ackTypeBuf);
+ }
+}
+
+static bool isAckForMyThingName(const char *pTopicName) {
+ if (strstr(pTopicName, myThingName) != NULL && ((strstr(pTopicName, "get/accepted") != NULL) || (strstr(pTopicName, "delta") != NULL))) {
+ return true;
+ }
+ return false;
+}
+
+static int AckStatusCallback(MQTTCallbackParams params) {
+ int32_t tokenCount;
+ int32_t i;
+ void *pJsonHandler;
+ char temporaryClientToken[MAX_SIZE_CLIENT_ID_WITH_SEQUENCE];
+
+ if (params.MessageParams.PayloadLen > SHADOW_MAX_SIZE_OF_RX_BUFFER) {
+ return GENERIC_ERROR;
+ }
+
+ memcpy(shadowRxBuf, params.MessageParams.pPayload, params.MessageParams.PayloadLen);
+ shadowRxBuf[params.MessageParams.PayloadLen] = '\0'; // jsmn_parse relies on a string
+
+ if (!isJsonValidAndParse(shadowRxBuf, pJsonHandler, &tokenCount)) {
+ WARN("Received JSON is not valid");
+ return GENERIC_ERROR;
+ }
+
+ if (isAckForMyThingName(params.pTopicName)) {
+ uint32_t tempVersionNumber = 0;
+ if (extractVersionNumber(shadowRxBuf, pJsonHandler, tokenCount, &tempVersionNumber)) {
+ if (tempVersionNumber > shadowJsonVersionNum) {
+ shadowJsonVersionNum = tempVersionNumber;
+ }
+ }
+ }
+
+ if (extractClientToken(shadowRxBuf, temporaryClientToken)) {
+ for (i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
+ if (!AckWaitList[i].isFree) {
+ if (strcmp(AckWaitList[i].clientTokenID, temporaryClientToken) == 0) {
+ Shadow_Ack_Status_t status;
+ if (strstr(params.pTopicName, "accepted") != NULL) {
+ status = SHADOW_ACK_ACCEPTED;
+ } else if (strstr(params.pTopicName, "rejected") != NULL) {
+ status = SHADOW_ACK_REJECTED;
+ }
+ if (status == SHADOW_ACK_ACCEPTED || status == SHADOW_ACK_REJECTED) {
+ if (AckWaitList[i].callback != NULL) {
+ AckWaitList[i].callback(AckWaitList[i].thingName, AckWaitList[i].action, status,
+ shadowRxBuf, AckWaitList[i].pCallbackContext);
+ }
+ unsubscribeFromAcceptedAndRejected(i);
+ AckWaitList[i].isFree = true;
+ return NONE_ERROR;
+ }
+ }
+ }
+ }
+ }
+
+ return GENERIC_ERROR;
+}
+
+static int16_t findIndexOfSubscriptionList(const char *pTopic) {
+ uint8_t i;
+ for (i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
+ if (!SubscriptionList[i].isFree) {
+ if ((strcmp(pTopic, SubscriptionList[i].Topic) == 0)) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+static void unsubscribeFromAcceptedAndRejected(uint8_t index) {
+
+ char TemporaryTopicNameAccepted[MAX_SHADOW_TOPIC_LENGTH_BYTES];
+ char TemporaryTopicNameRejected[MAX_SHADOW_TOPIC_LENGTH_BYTES];
+ IoT_Error_t ret_val = NONE_ERROR;
+
+ topicNameFromThingAndAction(TemporaryTopicNameAccepted, AckWaitList[index].thingName, AckWaitList[index].action,
+ SHADOW_ACCEPTED);
+ topicNameFromThingAndAction(TemporaryTopicNameRejected, AckWaitList[index].thingName, AckWaitList[index].action,
+ SHADOW_REJECTED);
+
+ int16_t indexSubList;
+
+ indexSubList = findIndexOfSubscriptionList(TemporaryTopicNameAccepted);
+ if ((indexSubList >= 0)) {
+ if (!SubscriptionList[indexSubList].isSticky && (SubscriptionList[indexSubList].count == 1)) {
+ ret_val = pMqttClient->unsubscribe(TemporaryTopicNameAccepted);
+ if (ret_val == NONE_ERROR) {
+ SubscriptionList[indexSubList].isFree = true;
+ }
+ } else if (SubscriptionList[indexSubList].count > 1) {
+ SubscriptionList[indexSubList].count--;
+ }
+ }
+
+ indexSubList = findIndexOfSubscriptionList(TemporaryTopicNameRejected);
+ if ((indexSubList >= 0)) {
+ if (!SubscriptionList[indexSubList].isSticky && (SubscriptionList[indexSubList].count == 1)) {
+ ret_val = pMqttClient->unsubscribe(TemporaryTopicNameRejected);
+ if (ret_val == NONE_ERROR) {
+ SubscriptionList[indexSubList].isFree = true;
+ }
+ } else if (SubscriptionList[indexSubList].count > 1) {
+ SubscriptionList[indexSubList].count--;
+ }
+ }
+}
+
+void initializeRecords(MQTTClient_t *pClient) {
+ uint8_t i;
+ for (i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
+ AckWaitList[i].isFree = true;
+ }
+ for (i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
+ SubscriptionList[i].isFree = true;
+ SubscriptionList[i].count = 0;
+ SubscriptionList[i].isSticky = false;
+ }
+ pMqttClient = pClient;
+}
+
+bool isSubscriptionPresent(const char *pThingName, ShadowActions_t action) {
+
+ uint8_t i = 0;
+ bool isAcceptedPresent = false;
+ bool isRejectedPresent = false;
+ char TemporaryTopicNameAccepted[MAX_SHADOW_TOPIC_LENGTH_BYTES];
+ char TemporaryTopicNameRejected[MAX_SHADOW_TOPIC_LENGTH_BYTES];
+
+ topicNameFromThingAndAction(TemporaryTopicNameAccepted, pThingName, action, SHADOW_ACCEPTED);
+ topicNameFromThingAndAction(TemporaryTopicNameRejected, pThingName, action, SHADOW_REJECTED);
+
+ for (i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
+ if (!SubscriptionList[i].isFree) {
+ if ((strcmp(TemporaryTopicNameAccepted, SubscriptionList[i].Topic) == 0)) {
+ isAcceptedPresent = true;
+ } else if ((strcmp(TemporaryTopicNameRejected, SubscriptionList[i].Topic) == 0)) {
+ isRejectedPresent = true;
+ }
+ }
+ }
+
+ if (isRejectedPresent && isAcceptedPresent) {
+ return true;
+ }
+
+ return false;
+}
+
+IoT_Error_t subscribeToShadowActionAcks(const char *pThingName, ShadowActions_t action, bool isSticky) {
+ IoT_Error_t ret_val = NONE_ERROR;
+ MQTTSubscribeParams subParams = MQTTSubscribeParamsDefault;
+
+ bool clearBothEntriesFromList = true;
+ int16_t indexAcceptedSubList = 0;
+ int16_t indexRejectedSubList = 0;
+ indexAcceptedSubList = getNextFreeIndexOfSubscriptionList();
+ indexRejectedSubList = getNextFreeIndexOfSubscriptionList();
+
+ if (indexAcceptedSubList >= 0 && indexRejectedSubList >= 0) {
+ topicNameFromThingAndAction(SubscriptionList[indexAcceptedSubList].Topic, pThingName, action, SHADOW_ACCEPTED);
+ subParams.mHandler = AckStatusCallback;
+ subParams.qos = QOS_0;
+ subParams.pTopic = SubscriptionList[indexAcceptedSubList].Topic;
+ ret_val = pMqttClient->subscribe(&subParams);
+ if (ret_val == NONE_ERROR) {
+ SubscriptionList[indexAcceptedSubList].count = 1;
+ SubscriptionList[indexAcceptedSubList].isSticky = isSticky;
+ topicNameFromThingAndAction(SubscriptionList[indexRejectedSubList].Topic, pThingName, action,
+ SHADOW_REJECTED);
+ subParams.pTopic = SubscriptionList[indexRejectedSubList].Topic;
+ ret_val = pMqttClient->subscribe(&subParams);
+ if (ret_val == NONE_ERROR) {
+ SubscriptionList[indexRejectedSubList].count = 1;
+ SubscriptionList[indexRejectedSubList].isSticky = isSticky;
+ clearBothEntriesFromList = false;
+
+ // wait for SUBSCRIBE_SETTLING_TIME seconds to let the subscription take effect
+ Timer subSettlingtimer;
+ InitTimer(&subSettlingtimer);
+ countdown(&subSettlingtimer, SUBSCRIBE_SETTLING_TIME);
+ while(!expired(&subSettlingtimer));
+
+ }
+ }
+ }
+
+ if (clearBothEntriesFromList) {
+ if (indexAcceptedSubList >= 0) {
+ SubscriptionList[indexAcceptedSubList].isFree = true;
+ } else if (indexRejectedSubList >= 0) {
+ SubscriptionList[indexRejectedSubList].isFree = true;
+ }
+ if (SubscriptionList[indexAcceptedSubList].count == 1) {
+ pMqttClient->unsubscribe(SubscriptionList[indexAcceptedSubList].Topic);
+ }
+ }
+
+ return ret_val;
+}
+
+void incrementSubscriptionCnt(const char *pThingName, ShadowActions_t action, bool isSticky) {
+ char TemporaryTopicNameAccepted[MAX_SHADOW_TOPIC_LENGTH_BYTES];
+ char TemporaryTopicNameRejected[MAX_SHADOW_TOPIC_LENGTH_BYTES];
+ uint8_t i;
+ topicNameFromThingAndAction(TemporaryTopicNameAccepted, pThingName, action, SHADOW_ACCEPTED);
+ topicNameFromThingAndAction(TemporaryTopicNameRejected, pThingName, action, SHADOW_REJECTED);
+
+ for (i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
+ if (!SubscriptionList[i].isFree) {
+ if ((strcmp(TemporaryTopicNameAccepted, SubscriptionList[i].Topic) == 0)
+ || (strcmp(TemporaryTopicNameRejected, SubscriptionList[i].Topic) == 0)) {
+ SubscriptionList[i].count++;
+ SubscriptionList[i].isSticky = isSticky;
+ }
+ }
+ }
+}
+
+IoT_Error_t publishToShadowAction(const char * pThingName, ShadowActions_t action, const char *pJsonDocumentToBeSent) {
+ IoT_Error_t ret_val = NONE_ERROR;
+ char TemporaryTopicName[MAX_SHADOW_TOPIC_LENGTH_BYTES];
+ topicNameFromThingAndAction(TemporaryTopicName, pThingName, action, SHADOW_ACTION);
+
+ MQTTPublishParams pubParams = MQTTPublishParamsDefault;
+ pubParams.pTopic = TemporaryTopicName;
+ MQTTMessageParams msgParams = MQTTMessageParamsDefault;
+ msgParams.qos = QOS_0;
+ msgParams.PayloadLen = strlen(pJsonDocumentToBeSent) + 1;
+ msgParams.pPayload = (char *) pJsonDocumentToBeSent;
+ pubParams.MessageParams = msgParams;
+ ret_val = pMqttClient->publish(&pubParams);
+
+ return ret_val;
+}
+
+bool getNextFreeIndexOfAckWaitList(uint8_t *pIndex) {
+ uint8_t i;
+ if (pIndex != NULL) {
+ for (i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
+ if (AckWaitList[i].isFree) {
+ *pIndex = i;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void addToAckWaitList(uint8_t indexAckWaitList, const char *pThingName, ShadowActions_t action,
+ const char *pExtractedClientToken, fpActionCallback_t callback, void *pCallbackContext,
+ uint32_t timeout_seconds) {
+ AckWaitList[indexAckWaitList].callback = callback;
+ strncpy(AckWaitList[indexAckWaitList].clientTokenID, pExtractedClientToken, MAX_SIZE_CLIENT_ID_WITH_SEQUENCE);
+ strncpy(AckWaitList[indexAckWaitList].thingName, pThingName, MAX_SIZE_OF_THING_NAME);
+ AckWaitList[indexAckWaitList].pCallbackContext = pCallbackContext;
+ AckWaitList[indexAckWaitList].action = action;
+ InitTimer(&(AckWaitList[indexAckWaitList].timer));
+ countdown(&(AckWaitList[indexAckWaitList].timer), timeout_seconds);
+ AckWaitList[indexAckWaitList].isFree = false;
+}
+
+void HandleExpiredResponseCallbacks(void) {
+ uint8_t i;
+ for (i = 0; i < MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME; i++) {
+ if (!AckWaitList[i].isFree) {
+ if (expired(&(AckWaitList[i].timer))) {
+ if (AckWaitList[i].callback != NULL) {
+ AckWaitList[i].callback(AckWaitList[i].thingName, AckWaitList[i].action, SHADOW_ACK_TIMEOUT,
+ shadowRxBuf, AckWaitList[i].pCallbackContext);
+ }
+ AckWaitList[i].isFree = true;
+ unsubscribeFromAcceptedAndRejected(i);
+ }
+ }
+ }
+}
+
+static int shadow_delta_callback(MQTTCallbackParams params) {
+
+ int32_t tokenCount;
+ uint32_t i = 0;
+ void *pJsonHandler;
+ int32_t DataPosition;
+ uint32_t dataLength;
+
+ if (params.MessageParams.PayloadLen > SHADOW_MAX_SIZE_OF_RX_BUFFER) {
+ return GENERIC_ERROR;
+ }
+
+ memcpy(shadowRxBuf, params.MessageParams.pPayload, params.MessageParams.PayloadLen);
+ shadowRxBuf[params.MessageParams.PayloadLen] = '\0'; // jsmn_parse relies on a string
+
+ if (!isJsonValidAndParse(shadowRxBuf, pJsonHandler, &tokenCount)) {
+ WARN("Received JSON is not valid");
+ return GENERIC_ERROR;
+ }
+
+ if (shadowDiscardOldDeltaFlag) {
+ uint32_t tempVersionNumber = 0;
+ if (extractVersionNumber(shadowRxBuf, pJsonHandler, tokenCount, &tempVersionNumber)) {
+ if (tempVersionNumber > shadowJsonVersionNum) {
+ shadowJsonVersionNum = tempVersionNumber;
+ DEBUG("New Version number: %d", shadowJsonVersionNum);
+ } else {
+ WARN("Old Delta Message received - Ignoring rx: %d local: %d", tempVersionNumber, shadowJsonVersionNum);
+ return GENERIC_ERROR;
+ }
+ }
+ }
+
+ for (i = 0; i < tokenTableIndex; i++) {
+ if (!tokenTable[i].isFree) {
+ if (isJsonKeyMatchingAndUpdateValue(shadowRxBuf, pJsonHandler, tokenCount, (jsonStruct_t *)tokenTable[i].pStruct,
+ &dataLength, &DataPosition)) {
+ if (tokenTable[i].callback != NULL) {
+ tokenTable[i].callback(shadowRxBuf + DataPosition, dataLength, (jsonStruct_t *)tokenTable[i].pStruct);
+ }
+ }
+ }
+ }
+
+ return NONE_ERROR;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_records.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 SRC_SHADOW_AWS_IOT_SHADOW_RECORDS_H_ +#define SRC_SHADOW_AWS_IOT_SHADOW_RECORDS_H_ + +#include <stdbool.h> + +#include "aws_iot_shadow_interface.h" +#include "aws_iot_config.h" + + +extern uint32_t shadowJsonVersionNum; +extern bool shadowDiscardOldDeltaFlag; + +extern char myThingName[MAX_SIZE_OF_THING_NAME]; +extern char mqttClientID[MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES]; + +void initializeRecords(MQTTClient_t *pClient); +bool isSubscriptionPresent(const char *pThingName, ShadowActions_t action); +IoT_Error_t subscribeToShadowActionAcks(const char *pThingName, ShadowActions_t action, bool isSticky); +void incrementSubscriptionCnt(const char *pThingName, ShadowActions_t action, bool isSticky); + +IoT_Error_t publishToShadowAction(const char * pThingName, ShadowActions_t action, const char *pJsonDocumentToBeSent); +void addToAckWaitList(uint8_t indexAckWaitList, const char *pThingName, ShadowActions_t action, + const char *pExtractedClientToken, fpActionCallback_t callback, void *pCallbackContext, + uint32_t timeout_seconds); +bool getNextFreeIndexOfAckWaitList(uint8_t *pIndex); +void HandleExpiredResponseCallbacks(void); +void initDeltaTokens(void); +IoT_Error_t registerJsonTokenOnDelta(jsonStruct_t *pStruct); + +#endif /* SRC_SHADOW_AWS_IOT_SHADOW_RECORDS_H_ */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/utils/aws_iot_error.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 aws_iot_error.h
+ * @brief Definition of error types for the SDK.
+ */
+
+#ifndef AWS_IOT_SDK_SRC_IOT_ERROR_H_
+#define AWS_IOT_SDK_SRC_IOT_ERROR_H_
+
+
+/*! \public
+ * @brief IoT Error enum
+ *
+ * Enumeration of return values from the IoT_* functions within the SDK.
+ */
+typedef enum {
+ /** Return value of yield function to indicate auto-reconnect was successful */
+ RECONNECT_SUCCESSFUL = 1,
+ /** Success return value - no error occurred. */
+ NONE_ERROR = 0,
+ /** A generic error. A placeholder for a more specific error. */
+ GENERIC_ERROR = -1,
+ /** A required parameter was passed as null. */
+ NULL_VALUE_ERROR = -2,
+ /** A connection could not be established. */
+ CONNECTION_ERROR = -3,
+ /** The subscribe failed. A SUBACK was not returned from the service. */
+ SUBSCRIBE_ERROR = -4,
+ /** The publish failed. In the case of a QoS 1 message a PUBACK was not received. */
+ PUBLISH_ERROR = -5,
+ /** The disconnect failed. The disconnect control packet could not be sent. */
+ DISCONNECT_ERROR = -6,
+ /** An error occurred when yielding to the IoT MQTT client. A possible cause is an unexpected TCP socket disconnect. */
+ YIELD_ERROR = -7,
+ /** The TCP socket could not be established. */
+ TCP_CONNECT_ERROR = -8,
+ /** The TLS handshake failed. */
+ SSL_CONNECT_ERROR = -9,
+ /** Error associated with setting up the parameters of a Socket */
+ TCP_SETUP_ERROR =-10,
+ /** A timeout occurred while waiting for the TLS handshake to complete. */
+ SSL_CONNECT_TIMEOUT_ERROR = -11,
+ /** A Generic write error based on the platform used */
+ SSL_WRITE_ERROR = -12,
+ /** SSL initialization error at the TLS layer */
+ SSL_INIT_ERROR = -13,
+ /** An error occurred when loading the certificates. The certificates could not be located or are incorrectly formatted. */
+ SSL_CERT_ERROR= -14,
+ /** The unsubscribe failed. The unsubscribe control packet could not be sent. */
+ UNSUBSCRIBE_ERROR = -15,
+ /** An error occurred while parsing the JSON string. Usually malformed JSON. */
+ JSON_PARSE_ERROR = -16,
+ /** Shadow: The response Ack table is currently full waiting for previously published updates */
+ WAIT_FOR_PUBLISH = -17,
+ /** SSL Write times out */
+ SSL_WRITE_TIMEOUT_ERROR = -18,
+ /** SSL Read times out */
+ SSL_READ_TIMEOUT_ERROR = -19,
+ /** A Generic error based on the platform used */
+ SSL_READ_ERROR = -20,
+ /** Any time an snprintf writes more than size value, this error will be returned */
+ SHADOW_JSON_BUFFER_TRUNCATED = -21,
+ /** Any time an snprintf encounters an encoding error or not enough space in the given buffer */
+ SHADOW_JSON_ERROR = -22,
+ /** Returned when the Network is disconnected and reconnect is either disabled or physical layer is disconnected */
+ NETWORK_DISCONNECTED = -23,
+ /** Returned when the Network is disconnected and the reconnect attempt has timed out */
+ NETWORK_RECONNECT_TIMED_OUT = -24,
+ /** Returned when the Network is disconnected and the reconnect attempt is in progress */
+ NETWORK_ATTEMPTING_RECONNECT = -25,
+ /** Returned when the Network is already connected and a connection attempt is made */
+ NETWORK_ALREADY_CONNECTED = -26,
+ /** The MQTT RX buffer received corrupt message */
+ RX_MESSAGE_INVALID = -27,
+ /** The MQTT RX buffer received a bigger message. The message will be dropped */
+ RX_MESSAGE_BIGGER_THAN_MQTT_RX_BUF = -28
+}IoT_Error_t;
+
+#endif /* AWS_IOT_SDK_SRC_IOT_ERROR_H_ */
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/utils/aws_iot_json_utils.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 aws_json_utils.c
+ * @brief Utilities for manipulating JSON
+ *
+ * json_utils provides JSON parsing utilities for use with the IoT SDK.
+ * Underlying JSON parsing relies on the Jasmine JSON parser.
+ *
+ */
+
+#include "aws_iot_json_utils.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include "aws_iot_log.h"
+
+int8_t jsoneq(const char *json, jsmntok_t *tok, const char *s) {
+ if (tok->type == JSMN_STRING) {
+ if ((int) strlen(s) == tok->end - tok->start) {
+ if (strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+IoT_Error_t parseUnsignedInteger32Value(uint32_t *i, const char *jsonString, jsmntok_t *token) {
+ if (token->type != JSMN_PRIMITIVE) {
+ WARN("Token was not an integer");
+ return JSON_PARSE_ERROR;
+ }
+
+ //if (1 != sscanf(jsonString + token->start, "%"PRIu32, i)) {
+ if (1 != sscanf(jsonString + token->start, "%lu", i)) {
+ WARN("Token was not an integer.");
+ return JSON_PARSE_ERROR;
+ }
+
+ return NONE_ERROR;
+}
+
+IoT_Error_t parseUnsignedInteger16Value(uint16_t *i, const char *jsonString, jsmntok_t *token) {
+ if (token->type != JSMN_PRIMITIVE) {
+ WARN("Token was not an integer");
+ return JSON_PARSE_ERROR;
+ }
+
+ //if (1 != sscanf(jsonString + token->start, "%"PRIu16, i)) {
+ if (1 != sscanf(jsonString + token->start, "%u", i)) {
+ WARN("Token was not an integer.");
+ return JSON_PARSE_ERROR;
+ }
+
+ return NONE_ERROR;
+}
+
+IoT_Error_t parseUnsignedInteger8Value(uint8_t *i, const char *jsonString, jsmntok_t *token) {
+ if (token->type != JSMN_PRIMITIVE) {
+ WARN("Token was not an integer");
+ return JSON_PARSE_ERROR;
+ }
+
+ //if (1 != sscanf(jsonString + token->start, "%"PRIu8, i)) {
+ if (1 != sscanf(jsonString + token->start, "%u", i)) {
+ WARN("Token was not an integer.");
+ return JSON_PARSE_ERROR;
+ }
+
+ return NONE_ERROR;
+}
+
+IoT_Error_t parseInteger32Value(int32_t *i, const char *jsonString, jsmntok_t *token) {
+ if (token->type != JSMN_PRIMITIVE) {
+ WARN("Token was not an integer");
+ return JSON_PARSE_ERROR;
+ }
+
+ //if (1 != sscanf(jsonString + token->start, "%"PRIi32, i)) {
+ if (1 != sscanf(jsonString + token->start, "%li", i)) {
+ WARN("Token was not an integer.");
+ return JSON_PARSE_ERROR;
+ }
+
+ return NONE_ERROR;
+}
+
+IoT_Error_t parseInteger16Value(int16_t *i, const char *jsonString, jsmntok_t *token) {
+ if (token->type != JSMN_PRIMITIVE) {
+ WARN("Token was not an integer");
+ return JSON_PARSE_ERROR;
+ }
+
+ //if (1 != sscanf(jsonString + token->start, "%"PRIi16, i)) {
+ if (1 != sscanf(jsonString + token->start, "%i", i)) {
+ WARN("Token was not an integer.");
+ return JSON_PARSE_ERROR;
+ }
+
+ return NONE_ERROR;
+}
+
+IoT_Error_t parseInteger8Value(int8_t *i, const char *jsonString, jsmntok_t *token) {
+ if (token->type != JSMN_PRIMITIVE) {
+ WARN("Token was not an integer");
+ return JSON_PARSE_ERROR;
+ }
+
+ //if (1 != sscanf(jsonString + token->start, "%"PRIi8, i)) {
+ if (1 != sscanf(jsonString + token->start, "%i", i)) {
+ WARN("Token was not an integer.");
+ return JSON_PARSE_ERROR;
+ }
+
+ return NONE_ERROR;
+}
+
+IoT_Error_t parseFloatValue(float *f, const char *jsonString, jsmntok_t *token) {
+ if (token->type != JSMN_PRIMITIVE) {
+ WARN("Token was not a float.");
+ return JSON_PARSE_ERROR;
+ }
+
+ if (1 != sscanf(jsonString + token->start, "%f", f)) {
+ WARN("Token was not a float.");
+ return JSON_PARSE_ERROR;
+ }
+
+ return NONE_ERROR;
+}
+
+IoT_Error_t parseDoubleValue(double *d, const char *jsonString, jsmntok_t *token) {
+ if (token->type != JSMN_PRIMITIVE) {
+ WARN("Token was not a double.");
+ return JSON_PARSE_ERROR;
+ }
+
+ if (1 != sscanf(jsonString + token->start, "%lf", d)) {
+ WARN("Token was not a double.");
+ return JSON_PARSE_ERROR;
+ }
+
+ return NONE_ERROR;
+}
+
+IoT_Error_t parseBooleanValue(bool *b, const char *jsonString, jsmntok_t *token) {
+ if (token->type != JSMN_PRIMITIVE) {
+ WARN("Token was not a primitive.");
+ return JSON_PARSE_ERROR;
+ }
+ if (jsonString[token->start] == 't' && jsonString[token->start + 1] == 'r' && jsonString[token->start + 2] == 'u'
+ && jsonString[token->start + 3] == 'e') {
+ *b = true;
+ } else if (jsonString[token->start] == 'f' && jsonString[token->start + 1] == 'a'
+ && jsonString[token->start + 2] == 'l' && jsonString[token->start + 3] == 's'
+ && jsonString[token->start + 4] == 'e') {
+ *b = false;
+ } else {
+ WARN("Token was not a bool.");
+ return JSON_PARSE_ERROR;
+ }
+ return NONE_ERROR;
+}
+
+IoT_Error_t parseStringValue(char *buf, const char *jsonString, jsmntok_t *token) {
+ uint16_t size = 0;
+ if (token->type != JSMN_STRING) {
+ WARN("Token was not a string.");
+ return JSON_PARSE_ERROR;
+ }
+ size = token->end - token->start;
+ memcpy(buf, jsonString + token->start, size);
+ buf[size] = '\0';
+ return NONE_ERROR;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_iot_src/utils/aws_iot_json_utils.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,190 @@ +/* + * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 aws_json_utils.h + * @brief Utilities for manipulating JSON + * + * json_utils provides JSON parsing utilities for use with the IoT SDK. + * Underlying JSON parsing relies on the Jasmine JSON parser. + * + */ + +#ifndef AWS_IOT_SDK_SRC_JSON_UTILS_H_ +#define AWS_IOT_SDK_SRC_JSON_UTILS_H_ + +#include <stdbool.h> +#include <stdint.h> + +#include "aws_iot_error.h" +#include "jsmn.h" + +// utility functions +/** + * @brief JSON Equality Check + * + * Given a token pointing to a particular JSON node and an + * input string, check to see if the key is equal to the string. + * + * @param json json string + * @param tok json token - pointer to key to test for equality + * @param s input string for key to test equality + * + * @return 0 if equal, 1 otherwise + */ +int8_t jsoneq(const char *json, jsmntok_t *tok, const char *s); + +/** + * @brief Parse a signed 32-bit integer value from a JSON node. + * + * Given a JSON node parse the integer value from the value. + * + * @param jsonString json string + * @param tok json token - pointer to JSON node + * @param i address of int32_t to be updated + * + * @return NONE_ERROR - success + * @return JSON_PARSE_ERROR - error parsing value + */ +IoT_Error_t parseInteger32Value(int32_t *i, const char *jsonString, jsmntok_t *token); + +/** + * @brief Parse a signed 16-bit integer value from a JSON node. + * + * Given a JSON node parse the integer value from the value. + * + * @param jsonString json string + * @param tok json token - pointer to JSON node + * @param i address of int16_t to be updated + * + * @return NONE_ERROR - success + * @return JSON_PARSE_ERROR - error parsing value + */ +IoT_Error_t parseInteger16Value(int16_t *i, const char *jsonString, jsmntok_t *token); + +/** + * @brief Parse a signed 8-bit integer value from a JSON node. + * + * Given a JSON node parse the integer value from the value. + * + * @param jsonString json string + * @param tok json token - pointer to JSON node + * @param i address of int8_t to be updated + * + * @return NONE_ERROR - success + * @return JSON_PARSE_ERROR - error parsing value + */ +IoT_Error_t parseInteger8Value(int8_t *i, const char *jsonString, jsmntok_t *token); + +/** + * @brief Parse an unsigned 32-bit integer value from a JSON node. + * + * Given a JSON node parse the integer value from the value. + * + * @param jsonString json string + * @param tok json token - pointer to JSON node + * @param i address of uint32_t to be updated + * + * @return NONE_ERROR - success + * @return JSON_PARSE_ERROR - error parsing value + */ +IoT_Error_t parseUnsignedInteger32Value(uint32_t *i, const char *jsonString, jsmntok_t *token); + +/** + * @brief Parse an unsigned 16-bit integer value from a JSON node. + * + * Given a JSON node parse the integer value from the value. + * + * @param jsonString json string + * @param tok json token - pointer to JSON node + * @param i address of uint16_t to be updated + * + * @return NONE_ERROR - success + * @return JSON_PARSE_ERROR - error parsing value + */ +IoT_Error_t parseUnsignedInteger16Value(uint16_t *i, const char *jsonString, jsmntok_t *token); + +/** + * @brief Parse an unsigned 8-bit integer value from a JSON node. + * + * Given a JSON node parse the integer value from the value. + * + * @param jsonString json string + * @param tok json token - pointer to JSON node + * @param i address of uint8_t to be updated + * + * @return NONE_ERROR - success + * @return JSON_PARSE_ERROR - error parsing value + */ +IoT_Error_t parseUnsignedInteger8Value(uint8_t *i, const char *jsonString, jsmntok_t *token); + +/** + * @brief Parse a float value from a JSON node. + * + * Given a JSON node parse the float value from the value. + * + * @param jsonString json string + * @param tok json token - pointer to JSON node + * @param f address of float to be updated + * + * @return NONE_ERROR - success + * @return JSON_PARSE_ERROR - error parsing value + */ +IoT_Error_t parseFloatValue(float *f, const char *jsonString, jsmntok_t *token); + +/** + * @brief Parse a double value from a JSON node. + * + * Given a JSON node parse the double value from the value. + * + * @param jsonString json string + * @param tok json token - pointer to JSON node + * @param d address of double to be updated + * + * @return NONE_ERROR - success + * @return JSON_PARSE_ERROR - error parsing value + */ +IoT_Error_t parseDoubleValue(double *d, const char *jsonString, jsmntok_t *token); + +/** + * @brief Parse a boolean value from a JSON node. + * + * Given a JSON node parse the boolean value from the value. + * + * @param jsonString json string + * @param tok json token - pointer to JSON node + * @param b address of boolean to be updated + * + * @return NONE_ERROR - success + * @return JSON_PARSE_ERROR - error parsing value + */ +IoT_Error_t parseBooleanValue(bool *b, const char *jsonString, jsmntok_t *token); + +/** + * @brief Parse a string value from a JSON node. + * + * Given a JSON node parse the string value from the value. + * + * @param jsonString json string + * @param tok json token - pointer to JSON node + * @param s address of string to be updated + * + * @return NONE_ERROR - success + * @return JSON_PARSE_ERROR - error parsing value + */ +IoT_Error_t parseStringValue(char *buf, const char *jsonString, jsmntok_t *token); + +#endif /* AWS_IOT_SDK_SRC_JSON_UTILS_H_ */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/utils/aws_iot_log.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 aws_iot_log.h
+ * @brief Logging macros for the SDK.
+ * This file defines common logging macros with log levels to be used within the SDK.
+ * These macros can also be used in the IoT application code as a common way to output
+ * logs. The log levels can be tuned by modifying the makefile. Removing (commenting
+ * out) the IOT_* statement in the makefile disables that log level.
+ *
+ * It is expected that the macros below will be modified or replaced when porting to
+ * specific hardware platforms as printf may not be the desired behavior.
+ */
+
+// Change to a number between 1 and 4 to debug the TLS connection
+// WARNING: the large number of prints may cause timeouts during the connection.
+#define DEBUG_LEVEL 0
+
+#ifndef _IOT_LOG_H
+#define _IOT_LOG_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "platform.h"
+
+// Exposes USB Serial function
+void pc_print(const char * format, ...);
+
+/**
+ * @brief Debug level logging macro.
+ *
+ * Macro to expose function, line number as well as desired log message.
+ */
+#ifdef IOT_DEBUG
+#define DEBUG(...) \
+ {\
+ printf("DEBUG: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+ }
+#else
+
+#if DEBUG_LEVEL > 0
+#define DEBUG(...) pc_print(__VA_ARGS__); \
+ pc_print("\r\n");
+#else
+#define DEBUG(...)
+#endif
+
+#endif
+
+/**
+ * @brief Info level logging macro.
+ *
+ * Macro to expose desired log message. Info messages do not include automatic function names and line numbers.
+ */
+#ifdef IOT_INFO
+#define INFO(...) \
+ {\
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+ }
+#else
+#define INFO(...) pc_print(__VA_ARGS__); \
+ pc_print("\r\n");
+#endif
+
+/**
+ * @brief Warn level logging macro.
+ *
+ * Macro to expose function, line number as well as desired log message.
+ */
+#ifdef IOT_WARN
+#define WARN(...) \
+ { \
+ printf("WARN: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+ }
+#else
+#define WARN(...) pc_print("WARN: "); \
+ pc_print(__VA_ARGS__); \
+ pc_print("\r\n");
+#endif
+
+/**
+ * @brief Error level logging macro.
+ *
+ * Macro to expose function, line number as well as desired log message.
+ */
+#ifdef IOT_ERROR
+#define ERROR(...) \
+ { \
+ printf("ERROR: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+ }
+#else
+#define ERROR(...) pc_print("ERROR: "); \
+ pc_print(__VA_ARGS__); \
+ pc_print("\r\n");
+#endif
+
+#endif // _IOT_LOG_H
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_iot_src/utils/aws_iot_version.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 aws_iot_version.h + * @brief Constants defining the release version of the SDK. + * + * This file contains constants defining the release version of the SDK. + * This file is modified by AWS upon release of the SDK and should not be + * modified by the consumer of the SDK. The provided samples show example + * usage of these constants. + * + * Versioning of the SDK follows the MAJOR.MINOR.PATCH Semantic Versioning guidelines. + * @see http://semver.org/ + */ +#ifndef SRC_UTILS_AWS_IOT_VERSION_H_ +#define SRC_UTILS_AWS_IOT_VERSION_H_ + +/** + * @brief MAJOR version, incremented when incompatible API changes are made. + */ +#define VERSION_MAJOR 1 +/** + * @brief MINOR version when functionality is added in a backwards-compatible manner. + */ +#define VERSION_MINOR 1 +/** + * @brief PATCH version when backwards-compatible bug fixes are made. + */ +#define VERSION_PATCH 2 +/** + * @brief TAG is an (optional) tag appended to the version if a more descriptive verion is needed. + */ +#define VERSION_TAG "" + +#endif /* SRC_UTILS_AWS_IOT_VERSION_H_ */ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/utils/jsmn.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2010 Serge A. Zaitsev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file jsmn.c
+ * @brief Implementation of the JSMN (Jasmine) JSON parser.
+ *
+ * For more information on JSMN:
+ * @see http://zserge.com/jsmn.html
+ */
+
+#include <stdlib.h>
+
+#include "jsmn.h"
+
+/**
+ * Allocates a fresh unused token from the token pull.
+ */
+static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
+ size_t num_tokens) {
+ jsmntok_t *tok;
+ if (parser->toknext >= num_tokens) {
+ return NULL;
+ }
+ tok = &tokens[parser->toknext++];
+ tok->start = tok->end = -1;
+ tok->size = 0;
+#ifdef JSMN_PARENT_LINKS
+ tok->parent = -1;
+#endif
+ return tok;
+}
+
+/**
+ * Fills token type and boundaries.
+ */
+static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start,
+ int end) {
+ token->type = type;
+ token->start = start;
+ token->end = end;
+ token->size = 0;
+}
+
+/**
+ * Fills next available token with JSON primitive.
+ */
+static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+ size_t len, jsmntok_t *tokens, size_t num_tokens) {
+ jsmntok_t *token;
+ int start;
+
+ start = parser->pos;
+
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+ switch (js[parser->pos]) {
+#ifndef JSMN_STRICT
+ /* In strict mode primitive must be followed by "," or "}" or "]" */
+ case ':':
+#endif
+ case '\t':
+ case '\r':
+ case '\n':
+ case ' ':
+ case ',':
+ case ']':
+ case '}':
+ goto found;
+ }
+ if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+#ifdef JSMN_STRICT
+ /* In strict mode primitive must be followed by a comma/object/array */
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+#endif
+
+ found: if (tokens == NULL) {
+ parser->pos--;
+ return (jsmnerr_t) 0;
+ }
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL) {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+ token->parent = parser->toksuper;
+#endif
+ parser->pos--;
+ return (jsmnerr_t) 0;
+}
+
+/**
+ * Filsl next token with JSON string.
+ */
+static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
+ size_t len, jsmntok_t *tokens, size_t num_tokens) {
+ jsmntok_t *token;
+
+ int start = parser->pos;
+
+ parser->pos++;
+
+ /* Skip starting quote */
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+ char c = js[parser->pos];
+
+ /* Quote: end of string */
+ if (c == '\"') {
+ if (tokens == NULL) {
+ return (jsmnerr_t) 0;
+ }
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL) {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+ token->parent = parser->toksuper;
+#endif
+ return (jsmnerr_t) 0;
+ }
+
+ /* Backslash: Quoted symbol expected */
+ if (c == '\\') {
+ parser->pos++;
+ switch (js[parser->pos]) {
+ /* Allowed escaped symbols */
+ case '\"':
+ case '/':
+ case '\\':
+ case 'b':
+ case 'f':
+ case 'r':
+ case 'n':
+ case 't':
+ break;
+ /* Allows escaped symbol \uXXXX */
+ case 'u':
+ parser->pos++;
+ int i;
+ for (i = 0; i < 4 && js[parser->pos] != '\0'; i++) {
+ /* If it isn't a hex character we have an error */
+ if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
+ (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
+ (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ parser->pos++;
+ }
+ parser->pos--;
+ break;
+ /* Unexpected symbol */
+ default:
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ }
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+}
+
+/**
+ * Parse JSON string and fill tokens.
+ */
+jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
+ jsmntok_t *tokens, unsigned int num_tokens) {
+ jsmnerr_t r;
+ int i;
+ jsmntok_t *token;
+ int count = 0;
+
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+ char c;
+ jsmntype_t type;
+
+ c = js[parser->pos];
+ switch (c) {
+ case '{':
+ case '[':
+ count++;
+ if (tokens == NULL) {
+ break;
+ }
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL)
+ return JSMN_ERROR_NOMEM;
+ if (parser->toksuper != -1) {
+ tokens[parser->toksuper].size++;
+#ifdef JSMN_PARENT_LINKS
+ token->parent = parser->toksuper;
+#endif
+ }
+ token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
+ token->start = parser->pos;
+ parser->toksuper = parser->toknext - 1;
+ break;
+ case '}':
+ case ']':
+ if (tokens == NULL)
+ break;
+ type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
+#ifdef JSMN_PARENT_LINKS
+ if (parser->toknext < 1) {
+ return JSMN_ERROR_INVAL;
+ }
+ token = &tokens[parser->toknext - 1];
+ for (;;) {
+ if (token->start != -1 && token->end == -1) {
+ if (token->type != type) {
+ return JSMN_ERROR_INVAL;
+ }
+ token->end = parser->pos + 1;
+ parser->toksuper = token->parent;
+ break;
+ }
+ if (token->parent == -1) {
+ break;
+ }
+ token = &tokens[token->parent];
+ }
+#else
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ token = &tokens[i];
+ if (token->start != -1 && token->end == -1) {
+ if (token->type != type) {
+ return JSMN_ERROR_INVAL;
+ }
+ parser->toksuper = -1;
+ token->end = parser->pos + 1;
+ break;
+ }
+ }
+ /* Error if unmatched closing bracket */
+ if (i == -1)
+ return JSMN_ERROR_INVAL;
+ for (; i >= 0; i--) {
+ token = &tokens[i];
+ if (token->start != -1 && token->end == -1) {
+ parser->toksuper = i;
+ break;
+ }
+ }
+#endif
+ break;
+ case '\"':
+ r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
+ if (r < 0)
+ return r;
+ count++;
+ if (parser->toksuper != -1 && tokens != NULL)
+ tokens[parser->toksuper].size++;
+ break;
+ case '\t':
+ case '\r':
+ case '\n':
+ case ':':
+ case ',':
+ case ' ':
+ break;
+#ifdef JSMN_STRICT
+ /* In strict mode primitives are: numbers and booleans */
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 't':
+ case 'f':
+ case 'n':
+#else
+ /* In non-strict mode every unquoted value is a primitive */
+ default:
+#endif
+ r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
+ if (r < 0)
+ return r;
+ count++;
+ if (parser->toksuper != -1 && tokens != NULL)
+ tokens[parser->toksuper].size++;
+ break;
+
+#ifdef JSMN_STRICT
+ /* Unexpected char in strict mode */
+ default:
+ return JSMN_ERROR_INVAL;
+#endif
+ }
+ }
+
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ /* Unmatched opened object or array */
+ if (tokens[i].start != -1 && tokens[i].end == -1) {
+ return JSMN_ERROR_PART;
+ }
+ }
+
+ return (jsmnerr_t) count;
+}
+
+/**
+ * Creates a new parser based over a given buffer with an array of tokens
+ * available.
+ */
+void jsmn_init(jsmn_parser *parser) {
+ parser->pos = 0;
+ parser->toknext = 0;
+ parser->toksuper = -1;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_iot_src/utils/jsmn.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2010 Serge A. Zaitsev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file jsmn.h
+ * @brief Definition of the JSMN (Jasmine) JSON parser.
+ *
+ * For more information on JSMN:
+ * @see http://zserge.com/jsmn.html
+ */
+
+#ifndef __JSMN_H_
+#define __JSMN_H_
+#include <stddef.h>
+#define JSMN_STRICT
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * JSON type identifier. Basic types are:
+ * o Object
+ * o Array
+ * o String
+ * o Other primitive: number, boolean (true/false) or null
+ */
+typedef enum {
+ JSMN_PRIMITIVE = 0, JSMN_OBJECT = 1, JSMN_ARRAY = 2, JSMN_STRING = 3
+} jsmntype_t;
+
+typedef enum {
+ /* Not enough tokens were provided */
+ JSMN_ERROR_NOMEM = -1,
+ /* Invalid character inside JSON string */
+ JSMN_ERROR_INVAL = -2,
+ /* The string is not a full JSON packet, more bytes expected */
+ JSMN_ERROR_PART = -3,
+} jsmnerr_t;
+
+/**
+ * JSON token description.
+ * @param type type (object, array, string etc.)
+ * @param start start position in JSON data string
+ * @param end end position in JSON data string
+ */
+typedef struct {
+ jsmntype_t type;
+ int start;
+ int end;
+ int size;
+#ifdef JSMN_PARENT_LINKS
+ int parent;
+#endif
+} jsmntok_t;
+
+/**
+ * JSON parser. Contains an array of token blocks available. Also stores
+ * the string being parsed now and current position in that string
+ */
+typedef struct {
+ unsigned int pos; /* offset in the JSON string */
+ unsigned int toknext; /* next token to allocate */
+ int toksuper; /* superior token node, e.g parent object or array */
+} jsmn_parser;
+
+/**
+ * Create JSON parser over an array of tokens
+ */
+void jsmn_init(jsmn_parser *parser);
+
+/**
+ * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
+ * a single JSON object.
+ */
+jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
+ jsmntok_t *tokens, unsigned int num_tokens);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JSMN_H_ */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTClient_C/src/MQTTClient.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,1068 @@
+/*******************************************************************************
+ * 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:
+ * Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTClient.h"
+#include <string.h>
+#include "aws_iot_log.h"
+
+static void MQTTForceDisconnect(Client *c);
+
+void NewMessageData(MessageData *md, MQTTString *aTopicName, MQTTMessage *aMessage, pApplicationHandler_t applicationHandler) {
+ md->topicName = aTopicName;
+ md->message = aMessage;
+ md->applicationHandler = applicationHandler;
+}
+
+uint16_t getNextPacketId(Client *c) {
+ return c->nextPacketId = (uint16_t)((MAX_PACKET_ID == c->nextPacketId) ? 1 : (c->nextPacketId + 1));
+}
+
+MQTTReturnCode sendPacket(Client *c, uint32_t length, Timer *timer) {
+ int32_t sentLen = 0;
+ uint32_t sent = 0, i;
+
+ if(NULL == c || NULL == timer) {
+ ERROR("...MQTT_NULL_VALUE_ERROR");
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ if(length >= c->bufSize) {
+ ERROR("...MQTTPACKET_BUFFER_TOO_SHORT");
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ while(sent < length && !expired(timer)) {
+ sentLen = c->networkStack.mqttwrite(&(c->networkStack), &c->buf[sent], (int)length, left_ms(timer));
+ if(sentLen < 0) {
+ /* there was an error writing the data */
+ ERROR("...there was an error writing the data");
+ break;
+ }
+ sent = sent + (uint32_t)sentLen;
+ }
+
+ if(sent == length) {
+ /* record the fact that we have successfully sent the packet */
+ //countdown(&c->pingTimer, c->keepAliveInterval);
+ return SUCCESS;
+ }
+
+ ERROR("...sendPacket FAILURE, sent = %d, length = %d", sent, length);
+ return FAILURE;
+}
+
+void copyMQTTConnectData(MQTTPacket_connectData *destination, MQTTPacket_connectData *source) {
+ if(NULL == destination || NULL == source) {
+ return;
+ }
+ destination->willFlag = source->willFlag;
+ destination->MQTTVersion = source->MQTTVersion;
+ destination->clientID.cstring = source->clientID.cstring;
+ destination->username.cstring = source->username.cstring;
+ destination->password.cstring = source->password.cstring;
+ destination->will.topicName.cstring = source->will.topicName.cstring;
+ destination->will.message.cstring = source->will.message.cstring;
+ destination->will.qos = source->will.qos;
+ destination->will.retained = source->will.retained;
+ destination->keepAliveInterval = source->keepAliveInterval;
+ destination->cleansession = source->cleansession;
+}
+
+MQTTReturnCode MQTTClient(Client *c, uint32_t commandTimeoutMs,
+ unsigned char *buf, size_t bufSize, unsigned char *readbuf,
+ size_t readBufSize, uint8_t enableAutoReconnect,
+ networkInitHandler_t networkInitHandler,
+ TLSConnectParams *tlsConnectParams) {
+ uint32_t i;
+ MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
+
+ if(NULL == c || NULL == tlsConnectParams || NULL == buf || NULL == readbuf
+ || NULL == networkInitHandler) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ for(i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
+ c->messageHandlers[i].topicFilter = NULL;
+ c->messageHandlers[i].fp = NULL;
+ c->messageHandlers[i].applicationHandler = NULL;
+ c->messageHandlers[i].qos = (QoS)0;
+ }
+
+ c->commandTimeoutMs = commandTimeoutMs;
+ c->buf = buf;
+ c->bufSize = bufSize;
+ c->readbuf = readbuf;
+ c->readBufSize = readBufSize;
+ c->isConnected = 0;
+ c->isPingOutstanding = 0;
+ c->wasManuallyDisconnected = 0;
+ c->counterNetworkDisconnected = 0;
+ c->isAutoReconnectEnabled = enableAutoReconnect;
+ c->defaultMessageHandler = NULL;
+ c->disconnectHandler = NULL;
+ copyMQTTConnectData(&(c->options), &default_options);
+
+ c->networkInitHandler = networkInitHandler;
+ c->tlsConnectParams.DestinationPort = tlsConnectParams->DestinationPort;
+ c->tlsConnectParams.pDestinationURL = tlsConnectParams->pDestinationURL;
+ c->tlsConnectParams.pDeviceCertLocation = tlsConnectParams->pDeviceCertLocation;
+ c->tlsConnectParams.pDevicePrivateKeyLocation = tlsConnectParams->pDevicePrivateKeyLocation;
+ c->tlsConnectParams.pRootCALocation = tlsConnectParams->pRootCALocation;
+ c->tlsConnectParams.timeout_ms = tlsConnectParams->timeout_ms;
+ c->tlsConnectParams.ServerVerificationFlag = tlsConnectParams->ServerVerificationFlag;
+
+ InitTimer(&(c->pingTimer));
+ InitTimer(&(c->reconnectDelayTimer));
+
+ return SUCCESS;
+}
+
+MQTTReturnCode decodePacket(Client *c, uint32_t *value, uint32_t timeout) {
+ unsigned char i;
+ uint32_t multiplier = 1;
+ uint32_t len = 0;
+ const uint32_t MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
+
+ if(NULL == c || NULL == value) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ *value = 0;
+
+ do {
+ if(++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) {
+ /* bad data */
+ return MQTTPACKET_READ_ERROR;
+ }
+
+ if((c->networkStack.mqttread(&(c->networkStack), &i, 1, (int)timeout)) != 1) {
+ /* The value argument is the important value. len is just used temporarily
+ * and never used by the calling function for anything else */
+ return FAILURE;
+ }
+
+ *value += ((i & 127) * multiplier);
+ multiplier *= 128;
+ }while((i & 128) != 0);
+
+ /* The value argument is the important value. len is just used temporarily
+ * and never used by the calling function for anything else */
+ return SUCCESS;
+}
+
+MQTTReturnCode readPacket(Client *c, Timer *timer, uint8_t *packet_type) {
+ MQTTHeader header = {0};
+ uint32_t len = 0;
+ uint32_t rem_len = 0;
+ uint32_t total_bytes_read = 0;
+ uint32_t bytes_to_be_read = 0;
+ int32_t ret_val = 0;
+ MQTTReturnCode rc;
+
+ if(NULL == c || NULL == timer) {
+ ERROR("readPacket() MQTT_NULL_VALUE_ERROR");
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ /* 1. read the header byte. This has the packet type in it */
+ if(1 != c->networkStack.mqttread(&(c->networkStack), c->readbuf, 1, left_ms(timer))) {
+ /* If a network disconnect has occurred it would have been caught by keepalive already.
+ * If nothing is found at this point means there was nothing to read. Not 100% correct,
+ * but the only way to be sure is to pass proper error codes from the network stack
+ * which the mbedtls/openssl implementations do not return */
+ return MQTT_NOTHING_TO_READ;
+ }
+
+ len = 1;
+ /* 2. read the remaining length. This is variable in itself */
+ rc = decodePacket(c, &rem_len, (uint32_t)left_ms(timer));
+ if(SUCCESS != rc) {
+ ERROR("readPacket() SUCCESS != rc");
+ return rc;
+ }
+
+ /* if the buffer is too short then the message will be dropped silently */
+ if (rem_len >= c->readBufSize) {
+ bytes_to_be_read = c->readBufSize;
+ do {
+ ret_val = c->networkStack.mqttread(&(c->networkStack), c->readbuf, bytes_to_be_read, left_ms(timer));
+ if (ret_val > 0) {
+ total_bytes_read += ret_val;
+ if((rem_len - total_bytes_read) >= c->readBufSize){
+ bytes_to_be_read = c->readBufSize;
+ }
+ else{
+ bytes_to_be_read = rem_len - total_bytes_read;
+ }
+ }
+ } while (total_bytes_read < rem_len && ret_val > 0);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ /* put the original remaining length back into the buffer */
+ len += MQTTPacket_encode(c->readbuf + 1, rem_len);
+
+ /* 3. read the rest of the buffer using a callback to supply the rest of the data */
+ if(rem_len > 0 && (c->networkStack.mqttread(&(c->networkStack), c->readbuf + len, (int)rem_len, left_ms(timer)) != (int)rem_len)) {
+ ERROR("readPacket() FAILURE");
+ return FAILURE;
+ }
+
+ header.byte = c->readbuf[0];
+ *packet_type = header.bits.type;
+
+ return SUCCESS;
+}
+
+// assume topic filter and name is in correct format
+// # can only be at end
+// + and # can only be next to separator
+char isTopicMatched(char *topicFilter, MQTTString *topicName) {
+ char *curf = NULL;
+ char *curn = NULL;
+ char *curn_end = NULL;
+
+ if(NULL == topicFilter || NULL == topicName) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ curf = topicFilter;
+ curn = topicName->lenstring.data;
+ 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 == '#') {
+ /* skip until end of string */
+ curn = curn_end - 1;
+ }
+
+ curf++;
+ curn++;
+ };
+
+ return (curn == curn_end) && (*curf == '\0');
+}
+
+MQTTReturnCode deliverMessage(Client *c, MQTTString *topicName, MQTTMessage *message) {
+ uint32_t i;
+ MessageData md;
+
+ if(NULL == c || NULL == topicName || NULL == message) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ // we have to find the right message handler - indexed by topic
+ for(i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
+ if((c->messageHandlers[i].topicFilter != 0)
+ && (MQTTPacket_equals(topicName, (char*)c->messageHandlers[i].topicFilter) ||
+ isTopicMatched((char*)c->messageHandlers[i].topicFilter, topicName))) {
+ if(c->messageHandlers[i].fp != NULL) {
+ NewMessageData(&md, topicName, message, c->messageHandlers[i].applicationHandler);
+ c->messageHandlers[i].fp(&md);
+ return SUCCESS;
+ }
+ }
+ }
+
+ if(NULL != c->defaultMessageHandler) {
+ NewMessageData(&md, topicName, message, NULL);
+ c->defaultMessageHandler(&md);
+ return SUCCESS;
+ }
+
+ /* Message handler not found for topic */
+ return FAILURE;
+}
+
+MQTTReturnCode handleDisconnect(Client *c) {
+ MQTTReturnCode rc;
+
+ if(NULL == c) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ rc = MQTTDisconnect(c);
+ if(rc != SUCCESS){
+ // If the sendPacket prevents us from sending a disconnect packet then we have to clean the stack
+ MQTTForceDisconnect(c);
+ }
+
+ if(NULL != c->disconnectHandler) {
+ c->disconnectHandler();
+ }
+
+ /* Reset to 0 since this was not a manual disconnect */
+ c->wasManuallyDisconnected = 0;
+ return MQTT_NETWORK_DISCONNECTED_ERROR;
+}
+
+MQTTReturnCode MQTTAttemptReconnect(Client *c) {
+ MQTTReturnCode rc = MQTT_ATTEMPTING_RECONNECT;
+
+ if(NULL == c) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ if(1 == c->isConnected) {
+ return MQTT_NETWORK_ALREADY_CONNECTED_ERROR;
+ }
+
+ /* Ignoring return code. failures expected if network is disconnected */
+ rc = MQTTConnect(c, NULL);
+
+ /* If still disconnected handle disconnect */
+ if(0 == c->isConnected) {
+ return MQTT_ATTEMPTING_RECONNECT;
+ }
+
+ rc = MQTTResubscribe(c);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ return MQTT_NETWORK_RECONNECTED;
+}
+
+MQTTReturnCode handleReconnect(Client *c) {
+ int8_t isPhysicalLayerConnected = 1;
+ MQTTReturnCode rc = MQTT_NETWORK_RECONNECTED;
+
+ if(NULL == c) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ if(!expired(&(c->reconnectDelayTimer))) {
+ /* Timer has not expired. Not time to attempt reconnect yet.
+ * Return attempting reconnect */
+ return MQTT_ATTEMPTING_RECONNECT;
+ }
+
+ if(NULL != c->networkStack.isConnected) {
+ isPhysicalLayerConnected = (int8_t)c->networkStack.isConnected(&(c->networkStack));
+ }
+
+ if(isPhysicalLayerConnected) {
+ rc = MQTTAttemptReconnect(c);
+ if(MQTT_NETWORK_RECONNECTED == rc) {
+ return MQTT_NETWORK_RECONNECTED;
+ }
+ }
+
+ c->currentReconnectWaitInterval *= 2;
+
+ if(MAX_RECONNECT_WAIT_INTERVAL < c->currentReconnectWaitInterval) {
+ return MQTT_RECONNECT_TIMED_OUT;
+ }
+ countdown_ms(&(c->reconnectDelayTimer), c->currentReconnectWaitInterval);
+ return rc;
+}
+
+MQTTReturnCode keepalive(Client *c) {
+ MQTTReturnCode rc = SUCCESS;
+ Timer timer;
+ uint32_t serialized_len = 0;
+
+ if(NULL == c) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ if(0 == c->keepAliveInterval) {
+ return SUCCESS;
+ }
+
+ if(!expired(&c->pingTimer)) {
+ return SUCCESS;
+ }
+
+ if(c->isPingOutstanding) {
+ return handleDisconnect(c);
+ }
+
+ /* there is no ping outstanding - send one */
+ InitTimer(&timer);
+ countdown_ms(&timer, c->commandTimeoutMs);
+ rc = MQTTSerialize_pingreq(c->buf, c->bufSize, &serialized_len);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ /* send the ping packet */
+ rc = sendPacket(c, serialized_len, &timer);
+ if(SUCCESS != rc) {
+ //If sending a PING fails we can no longer determine if we are connected. In this case we decide we are disconnected and begin reconnection attempts
+ return handleDisconnect(c);
+ }
+
+ c->isPingOutstanding = 1;
+ /* start a timer to wait for PINGRESP from server */
+ countdown(&c->pingTimer, c->keepAliveInterval / 2);
+
+ return SUCCESS;
+}
+
+MQTTReturnCode handlePublish(Client *c, Timer *timer) {
+ MQTTString topicName;
+ MQTTMessage msg;
+ MQTTReturnCode rc;
+ uint32_t len = 0;
+
+ rc = MQTTDeserialize_publish((unsigned char *) &msg.dup, (QoS *) &msg.qos, (unsigned char *) &msg.retained,
+ (uint16_t *)&msg.id, &topicName,
+ (unsigned char **) &msg.payload, (uint32_t *) &msg.payloadlen, c->readbuf,
+ c->readBufSize);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ rc = deliverMessage(c, &topicName, &msg);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ if(QOS0 == msg.qos) {
+ /* No further processing required for QOS0 */
+ return SUCCESS;
+ }
+
+ if(QOS1 == msg.qos) {
+ rc = MQTTSerialize_ack(c->buf, c->bufSize, PUBACK, 0, msg.id, &len);
+ } else { /* Message is not QOS0 or 1 means only option left is QOS2 */
+ rc = MQTTSerialize_ack(c->buf, c->bufSize, PUBREC, 0, msg.id, &len);
+ }
+
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ rc = sendPacket(c, len, timer);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ return SUCCESS;
+}
+
+MQTTReturnCode handlePubrec(Client *c, Timer *timer) {
+ uint16_t packet_id;
+ unsigned char dup, type;
+ MQTTReturnCode rc;
+ uint32_t len;
+
+ rc = MQTTDeserialize_ack(&type, &dup, &packet_id, c->readbuf, c->readBufSize);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ rc = MQTTSerialize_ack(c->buf, c->bufSize, PUBREL, 0, packet_id, &len);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ /* send the PUBREL packet */
+ rc = sendPacket(c, len, timer);
+ if(SUCCESS != rc) {
+ /* there was a problem */
+ return rc;
+ }
+
+ return SUCCESS;
+}
+
+MQTTReturnCode cycle(Client *c, Timer *timer, uint8_t *packet_type) {
+ MQTTReturnCode rc;
+ if(NULL == c || NULL == timer) {
+ ERROR("cycle() MQTT_NULL_VALUE_ERROR");
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ /* read the socket, see what work is due */
+ rc = readPacket(c, timer, packet_type);
+ if(MQTT_NOTHING_TO_READ == rc) {
+ /* Nothing to read, not a cycle failure */
+ return SUCCESS;
+ }
+ if(SUCCESS != rc) {
+ ERROR("cycle() SUCCESS != rc");
+ return rc;
+ }
+
+ switch(*packet_type) {
+ case CONNACK:
+ case PUBACK:
+ case SUBACK:
+ case UNSUBACK:
+ break;
+ case PUBLISH: {
+ rc = handlePublish(c, timer);
+ break;
+ }
+ case PUBREC: {
+ rc = handlePubrec(c, timer);
+ break;
+ }
+ case PUBCOMP:
+ break;
+ case PINGRESP: {
+ c->isPingOutstanding = 0;
+ countdown(&c->pingTimer, c->keepAliveInterval);
+ break;
+ }
+ default: {
+ /* Either unknown packet type or Failure occurred
+ * Should not happen */
+ ERROR("cycle() Either unknown packet type or Failure occurred");
+ return MQTT_BUFFER_RX_MESSAGE_INVALID;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+MQTTReturnCode MQTTYield(Client *c, uint32_t timeout_ms) {
+ MQTTReturnCode rc = SUCCESS;
+ Timer timer;
+ uint8_t packet_type;
+
+ if(NULL == c) {
+ ERROR("MQTTYield() MQTT_NULL_VALUE_ERROR");
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ /* Check if network was manually disconnected */
+ if(0 == c->isConnected && 1 == c->wasManuallyDisconnected) {
+ ERROR("MQTTYield() MQTT_NETWORK_MANUALLY_DISCONNECTED");
+ return MQTT_NETWORK_MANUALLY_DISCONNECTED;
+ }
+
+ /* Check if network is disconnected and auto-reconnect is not enabled */
+ if(0 == c->isConnected && 0 == c->isAutoReconnectEnabled) {
+ ERROR("MQTTYield() MQTT_NETWORK_DISCONNECTED_ERROR");
+ return MQTT_NETWORK_DISCONNECTED_ERROR;
+ }
+
+ InitTimer(&timer);
+ countdown_ms(&timer, timeout_ms);
+
+ while(!expired(&timer)) {
+ if(0 == c->isConnected) {
+ if(MAX_RECONNECT_WAIT_INTERVAL < c->currentReconnectWaitInterval) {
+ rc = MQTT_RECONNECT_TIMED_OUT;
+ ERROR("MQTTYield() MQTT_RECONNECT_TIMED_OUT");
+ break;
+ }
+
+ rc = handleReconnect(c);
+ /* Network reconnect attempted, check if yield timer expired before
+ * doing anything else */
+ continue;
+ }
+
+ rc = cycle(c, &timer, &packet_type);
+ if(SUCCESS != rc) {
+ ERROR("MQTTYield() SUCCESS != rc");
+ break;
+ }
+
+ rc = keepalive(c);
+ if(MQTT_NETWORK_DISCONNECTED_ERROR == rc && 1 == c->isAutoReconnectEnabled) {
+ c->currentReconnectWaitInterval = MIN_RECONNECT_WAIT_INTERVAL;
+ countdown_ms(&(c->reconnectDelayTimer), c->currentReconnectWaitInterval);
+ c->counterNetworkDisconnected++;
+ /* Depending on timer values, it is possible that yield timer has expired
+ * Set to rc to attempting reconnect to inform client that autoreconnect
+ * attempt has started */
+ INFO("MQTTYield() MQTT_ATTEMPTING_RECONNECT");
+ rc = MQTT_ATTEMPTING_RECONNECT;
+ } else if(SUCCESS != rc) {
+ ERROR("MQTTYield() SUCCESS != rc");
+ break;
+ }
+ }
+
+ return rc;
+}
+
+/* only used in single-threaded mode where one command at a time is in process */
+MQTTReturnCode waitfor(Client *c, uint8_t packet_type, Timer *timer) {
+ MQTTReturnCode rc = FAILURE;
+ uint8_t read_packet_type = 0, retry = 2;
+
+
+
+ if(NULL == c || NULL == timer) {
+ ERROR("waitfor() MQTT_NULL_VALUE_ERROR");
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ do {
+ if(expired(timer)) {
+ /* we timed out */
+ ERROR("waitfor() timer expired");
+ break;
+
+ //countdown_ms(timer, 10);
+ }
+
+ rc = cycle(c, timer, &read_packet_type);
+ }while(MQTT_NETWORK_DISCONNECTED_ERROR != rc && read_packet_type != packet_type);
+
+ if(MQTT_NETWORK_DISCONNECTED_ERROR != rc && read_packet_type != packet_type) {
+ ERROR("waitfor() MQTT_NETWORK_DISCONNECTED_ERROR");
+ return FAILURE;
+ }
+
+ /* Something failed or we didn't receive the expected packet, return error code */
+ return rc;
+}
+
+MQTTReturnCode MQTTConnect(Client *c, MQTTPacket_connectData *options) {
+ Timer connect_timer;
+ MQTTReturnCode connack_rc = FAILURE;
+ char sessionPresent = 0;
+ uint32_t len = 0;
+ MQTTReturnCode rc = FAILURE;
+
+ if(NULL == c) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ DEBUG("...connect_timer");
+ InitTimer(&connect_timer);
+ countdown_ms(&connect_timer, c->commandTimeoutMs);
+
+ if(c->isConnected) {
+ /* Don't send connect packet again if we are already connected */
+ ERROR("...MQTT_NETWORK_ALREADY_CONNECTED_ERROR");
+ return MQTT_NETWORK_ALREADY_CONNECTED_ERROR;
+ }
+
+ if(NULL != options) {
+ /* override default options if new options were supplied */
+ copyMQTTConnectData(&(c->options), options);
+ }
+
+ DEBUG("...TLS Connect");
+ c->networkInitHandler(&(c->networkStack));
+ rc = (MQTTReturnCode)c->networkStack.connect(&(c->networkStack), c->tlsConnectParams);
+ if(0 != rc) {
+ /* TLS Connect failed, return error */
+ ERROR("...TLS Connect failed, return error");
+ return FAILURE;
+ }
+
+ c->keepAliveInterval = c->options.keepAliveInterval;
+ rc = MQTTSerialize_connect(c->buf, c->bufSize, &(c->options), &len);
+ if(SUCCESS != rc || 0 >= len) {
+ ERROR("...MQTTSerialize_connect FAIL");
+ return FAILURE;
+ }
+
+ /* send the connect packet */
+ rc = sendPacket(c, len, &connect_timer);
+ if(SUCCESS != rc) {
+ ERROR("...sendPacket FAIL");
+ return rc;
+ }
+
+ /* this will be a blocking call, wait for the CONNACK */
+ rc = waitfor(c, CONNACK, &connect_timer);
+ if(SUCCESS != rc) {
+ ERROR("...waitfor FAIL");
+ return rc;
+ }
+
+ /* Received CONNACK, check the return code */
+ rc = MQTTDeserialize_connack((unsigned char *)&sessionPresent, &connack_rc, c->readbuf, c->readBufSize);
+ if(SUCCESS != rc) {
+ ERROR("...MQTTDeserialize_connack FAIL");
+ return rc;
+ }
+
+ if(MQTT_CONNACK_CONNECTION_ACCEPTED != connack_rc) {
+ ERROR("...MQTT_CONNACK_CONNECTION_ACCEPTED FAIL");
+ return connack_rc;
+ }
+
+ DEBUG("...isConnected");
+ c->isConnected = 1;
+ c->wasManuallyDisconnected = 0;
+ c->isPingOutstanding = 0;
+ countdown(&c->pingTimer, c->keepAliveInterval);
+
+ return SUCCESS;
+}
+
+/* Return MAX_MESSAGE_HANDLERS value if no free index is available */
+uint32_t GetFreeMessageHandlerIndex(Client *c) {
+ uint32_t itr;
+ for(itr = 0; itr < MAX_MESSAGE_HANDLERS; itr++) {
+ if(c->messageHandlers[itr].topicFilter == NULL) {
+ break;
+ }
+ }
+
+ return itr;
+}
+
+MQTTReturnCode MQTTSubscribe(Client *c, const char *topicFilter, QoS qos,
+ messageHandler messageHandler, pApplicationHandler_t applicationHandler) {
+ MQTTReturnCode rc = FAILURE;
+ Timer timer;
+ uint32_t len = 0;
+ uint32_t indexOfFreeMessageHandler;
+ uint32_t count = 0;
+ QoS grantedQoS[3] = {QOS0, QOS0, QOS0};
+ uint16_t packetId;
+ MQTTString topic = MQTTString_initializer;
+
+ if(NULL == c || NULL == topicFilter
+ || NULL == messageHandler || NULL == applicationHandler) {
+ ERROR("...MQTT_NULL_VALUE_ERROR FAIL");
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ if(!c->isConnected) {
+ ERROR("...MQTT_NETWORK_DISCONNECTED_ERROR FAIL");
+ return MQTT_NETWORK_DISCONNECTED_ERROR;
+ }
+
+ topic.cstring = (char *)topicFilter;
+
+ InitTimer(&timer);
+ countdown_ms(&timer, c->commandTimeoutMs);
+
+ rc = MQTTSerialize_subscribe(c->buf, c->bufSize, 0, getNextPacketId(c), 1, &topic, &qos, &len);
+ if(SUCCESS != rc) {
+ ERROR("...MQTTSerialize_subscribe FAIL");
+ return rc;
+ }
+
+ indexOfFreeMessageHandler = GetFreeMessageHandlerIndex(c);
+ if(MAX_MESSAGE_HANDLERS <= indexOfFreeMessageHandler) {
+ ERROR("...MQTT_MAX_SUBSCRIPTIONS_REACHED_ERROR FAIL");
+ return MQTT_MAX_SUBSCRIPTIONS_REACHED_ERROR;
+ }
+
+ /* send the subscribe packet */
+ rc = sendPacket(c, len, &timer);
+ if(SUCCESS != rc) {
+ ERROR("...send the subscribe packet FAIL");
+ return rc;
+ }
+
+ /* wait for suback */
+ rc = waitfor(c, SUBACK, &timer);
+ if(SUCCESS != rc) {
+ ERROR("...wait for suback FAIL");
+ return rc;
+ }
+
+ /* Granted QoS can be 0, 1 or 2 */
+ rc = MQTTDeserialize_suback(&packetId, 1, &count, grantedQoS, c->readbuf, c->readBufSize);
+ if(SUCCESS != rc) {
+ ERROR("...Granted QoS can be 0, 1 or 2");
+ return rc;
+ }
+
+ c->messageHandlers[indexOfFreeMessageHandler].topicFilter =
+ topicFilter;
+ c->messageHandlers[indexOfFreeMessageHandler].fp = messageHandler;
+ c->messageHandlers[indexOfFreeMessageHandler].applicationHandler =
+ applicationHandler;
+ c->messageHandlers[indexOfFreeMessageHandler].qos = qos;
+
+ DEBUG("...MQTTSubscribe SUCCESS");
+ return SUCCESS;
+}
+
+MQTTReturnCode MQTTResubscribe(Client *c) {
+ MQTTReturnCode rc = FAILURE;
+ Timer timer;
+ uint32_t len = 0;
+ uint32_t count = 0;
+ QoS grantedQoS[3] = {QOS0, QOS0, QOS0};
+ uint16_t packetId;
+ uint32_t existingSubCount = 0;
+ uint32_t itr = 0;
+
+ if(NULL == c) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ if(!c->isConnected) {
+ return MQTT_NETWORK_DISCONNECTED_ERROR;
+ }
+
+ existingSubCount = GetFreeMessageHandlerIndex(c);
+
+ for(itr = 0; itr < existingSubCount; itr++) {
+ MQTTString topic = MQTTString_initializer;
+ topic.cstring = (char *)c->messageHandlers[itr].topicFilter;
+
+ InitTimer(&timer);
+ countdown_ms(&timer, c->commandTimeoutMs);
+
+ rc = MQTTSerialize_subscribe(c->buf, c->bufSize, 0, getNextPacketId(c), 1,
+ &topic, &(c->messageHandlers[itr].qos), &len);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ /* send the subscribe packet */
+ rc = sendPacket(c, len, &timer);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ /* wait for suback */
+ rc = waitfor(c, SUBACK, &timer);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ /* Granted QoS can be 0, 1 or 2 */
+ rc = MQTTDeserialize_suback(&packetId, 1, &count, grantedQoS, c->readbuf, c->readBufSize);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+ }
+
+ return SUCCESS;
+}
+
+MQTTReturnCode MQTTUnsubscribe(Client *c, const char *topicFilter) {
+ MQTTReturnCode rc = FAILURE;
+ Timer timer;
+ MQTTString topic = MQTTString_initializer;
+ uint32_t len = 0;
+ uint32_t i = 0;
+ uint16_t packet_id;
+
+ if(NULL == c || NULL == topicFilter) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ topic.cstring = (char *)topicFilter;
+
+ if(!c->isConnected) {
+ return MQTT_NETWORK_DISCONNECTED_ERROR;
+ }
+
+ InitTimer(&timer);
+ countdown_ms(&timer, c->commandTimeoutMs);
+
+ rc = MQTTSerialize_unsubscribe(c->buf, c->bufSize, 0, getNextPacketId(c), 1, &topic, &len);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ /* send the unsubscribe packet */
+ rc = sendPacket(c, len, &timer);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ rc = waitfor(c, UNSUBACK, &timer);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ rc = MQTTDeserialize_unsuback(&packet_id, c->readbuf, c->readBufSize);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ /* Remove from message handler array */
+ for(i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
+ if(c->messageHandlers[i].topicFilter != NULL &&
+ (strcmp(c->messageHandlers[i].topicFilter, topicFilter) == 0)) {
+ c->messageHandlers[i].topicFilter = NULL;
+ /* We don't want to break here, if the same topic is registered
+ * with 2 callbacks. Unlikely scenario */
+ }
+ }
+
+ return SUCCESS;
+}
+
+MQTTReturnCode MQTTPublish(Client *c, const char *topicName, MQTTMessage *message) {
+ Timer timer;
+ MQTTString topic = MQTTString_initializer;
+ uint32_t len = 0;
+ uint8_t waitForAck = 0;
+ uint8_t packetType = PUBACK;
+ uint16_t packet_id;
+ unsigned char dup, type;
+ MQTTReturnCode rc = FAILURE;
+
+ if(NULL == c || NULL == topicName || NULL == message) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ topic.cstring = (char *)topicName;
+
+ if(!c->isConnected) {
+ return MQTT_NETWORK_DISCONNECTED_ERROR;
+ }
+
+ InitTimer(&timer);
+ countdown_ms(&timer, c->commandTimeoutMs);
+
+ if(QOS1 == message->qos || QOS2 == message->qos) {
+ message->id = getNextPacketId(c);
+ waitForAck = 1;
+ if(QOS2 == message->qos) {
+ packetType = PUBCOMP;
+ }
+ }
+
+ rc = MQTTSerialize_publish(c->buf, c->bufSize, 0, message->qos, message->retained, message->id,
+ topic, (unsigned char*)message->payload, message->payloadlen, &len);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ /* send the publish packet */
+ rc = sendPacket(c, len, &timer);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ /* Wait for ack if QoS1 or QoS2 */
+ if(1 == waitForAck) {
+ rc = waitfor(c, packetType, &timer);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ rc = MQTTDeserialize_ack(&type, &dup, &packet_id, c->readbuf, c->readBufSize);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+ }
+
+ return SUCCESS;
+}
+/**
+ * This is for the case when the sendPacket Fails.
+ */
+static void MQTTForceDisconnect(Client *c){
+ c->isConnected = 0;
+ c->networkStack.disconnect(&(c->networkStack));
+ c->networkStack.destroy(&(c->networkStack));
+}
+
+MQTTReturnCode MQTTDisconnect(Client *c) {
+ MQTTReturnCode rc = FAILURE;
+ /* We might wait for incomplete incoming publishes to complete */
+ Timer timer;
+ uint32_t serialized_len = 0;
+
+ if(NULL == c) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ if(0 == c->isConnected) {
+ /* Network is already disconnected. Do nothing */
+ return MQTT_NETWORK_DISCONNECTED_ERROR;
+ }
+
+ rc = MQTTSerialize_disconnect(c->buf, c->bufSize, &serialized_len);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+
+ InitTimer(&timer);
+ countdown_ms(&timer, c->commandTimeoutMs);
+
+ /* send the disconnect packet */
+ if(serialized_len > 0) {
+ rc = sendPacket(c, serialized_len, &timer);
+ if(SUCCESS != rc) {
+ return rc;
+ }
+ }
+
+ /* Clean network stack */
+ c->networkStack.disconnect(&(c->networkStack));
+ rc = (MQTTReturnCode)c->networkStack.destroy(&(c->networkStack));
+ if(0 != rc) {
+ /* TLS Destroy failed, return error */
+ return FAILURE;
+ }
+
+ c->isConnected = 0;
+
+ /* Always set to 1 whenever disconnect is called. Keepalive resets to 0 */
+ c->wasManuallyDisconnected = 1;
+
+ return SUCCESS;
+}
+
+uint8_t MQTTIsConnected(Client *c) {
+ if(NULL == c) {
+ return 0;
+ }
+
+ return c->isConnected;
+}
+
+uint8_t MQTTIsAutoReconnectEnabled(Client *c) {
+ if(NULL == c) {
+ return 0;
+ }
+
+ return c->isAutoReconnectEnabled;
+}
+
+MQTTReturnCode setDisconnectHandler(Client *c, disconnectHandler_t disconnectHandler) {
+ if(NULL == c || NULL == disconnectHandler) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ c->disconnectHandler = disconnectHandler;
+ return SUCCESS;
+}
+
+MQTTReturnCode setAutoReconnectEnabled(Client *c, uint8_t value) {
+ if(NULL == c) {
+ return FAILURE;
+ }
+ c->isAutoReconnectEnabled = value;
+ return SUCCESS;
+}
+
+uint32_t MQTTGetNetworkDisconnectedCount(Client *c) {
+ return c->counterNetworkDisconnected;
+}
+
+void MQTTResetNetworkDisconnectedCount(Client *c) {
+ c->counterNetworkDisconnected = 0;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTClient_C/src/MQTTClient.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * 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:
+ * Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef __MQTT_CLIENT_C_
+#define __MQTT_CLIENT_C_
+
+/* Library Header files */
+#include "stdio.h"
+#include "stdint.h"
+#include "stddef.h"
+
+/* MQTT Specific header files */
+#include "MQTTReturnCodes.h"
+#include "MQTTMessage.h"
+#include "MQTTPacket.h"
+
+/* AWS Specific header files */
+#include "aws_iot_config.h"
+
+/* Platform specific implementation header files */
+#include "network_interface.h"
+#include "timer_interface.h"
+
+#define MAX_PACKET_ID 65535
+#define MAX_MESSAGE_HANDLERS AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS
+
+#define MIN_RECONNECT_WAIT_INTERVAL AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
+#define MAX_RECONNECT_WAIT_INTERVAL AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
+
+void NewTimer(Timer *);
+
+typedef struct Client Client;
+
+typedef struct MessageData MessageData;
+
+typedef void (*messageHandler)(MessageData *);
+typedef void (*pApplicationHandler_t)(void);
+typedef void (*disconnectHandler_t)(void);
+typedef int (*networkInitHandler_t)(Network *);
+
+struct MessageData {
+ MQTTMessage *message;
+ MQTTString *topicName;
+ pApplicationHandler_t applicationHandler;
+};
+
+MQTTReturnCode MQTTConnect(Client *c, MQTTPacket_connectData *options);
+MQTTReturnCode MQTTPublish (Client *, const char *, MQTTMessage *);
+MQTTReturnCode MQTTSubscribe(Client *c, const char *topicFilter, QoS qos,
+ messageHandler messageHandler, pApplicationHandler_t applicationHandler);
+MQTTReturnCode MQTTResubscribe(Client *c);
+MQTTReturnCode MQTTUnsubscribe(Client *c, const char *topicFilter);
+MQTTReturnCode MQTTDisconnect (Client *);
+MQTTReturnCode MQTTYield (Client *, uint32_t);
+MQTTReturnCode MQTTAttemptReconnect(Client *c);
+
+uint8_t MQTTIsConnected(Client *);
+uint8_t MQTTIsAutoReconnectEnabled(Client *c);
+
+void setDefaultMessageHandler(Client *, messageHandler);
+MQTTReturnCode setDisconnectHandler(Client *c, disconnectHandler_t disconnectHandler);
+MQTTReturnCode setAutoReconnectEnabled(Client *c, uint8_t value);
+
+MQTTReturnCode MQTTClient(Client *, uint32_t, unsigned char *, size_t, unsigned char *,
+ size_t, uint8_t, networkInitHandler_t, TLSConnectParams *);
+
+uint32_t MQTTGetNetworkDisconnectedCount(Client *c);
+void MQTTResetNetworkDisconnectedCount(Client *c);
+
+struct Client {
+ uint8_t isConnected;
+ uint8_t wasManuallyDisconnected;
+ uint8_t isPingOutstanding;
+ uint8_t isAutoReconnectEnabled;
+
+ uint16_t nextPacketId;
+
+ uint32_t commandTimeoutMs;
+ uint32_t keepAliveInterval;
+ uint32_t currentReconnectWaitInterval;
+ uint32_t counterNetworkDisconnected;
+
+ size_t bufSize;
+ size_t readBufSize;
+
+ unsigned char *buf;
+ unsigned char *readbuf;
+
+ TLSConnectParams tlsConnectParams;
+ MQTTPacket_connectData options;
+
+ Network networkStack;
+ Timer pingTimer;
+ Timer reconnectDelayTimer;
+
+ struct MessageHandlers {
+ const char *topicFilter;
+ void (*fp) (MessageData *);
+ pApplicationHandler_t applicationHandler;
+ QoS qos;
+ } messageHandlers[MAX_MESSAGE_HANDLERS]; /* Message handlers are indexed by subscription topic */
+
+ void (* defaultMessageHandler) (MessageData *);
+ disconnectHandler_t disconnectHandler;
+ networkInitHandler_t networkInitHandler;
+};
+
+#define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0}
+
+#endif
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTConnect.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * 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
+ * Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTCONNECT_H_
+#define MQTTCONNECT_H_
+
+#if !defined(DLLImport)
+ #define DLLImport
+#endif
+#if !defined(DLLExport)
+ #define DLLExport
+#endif
+
+
+typedef union {
+ uint8_t all; /**< all connect flags */
+#if defined(REVERSED)
+ struct
+ {
+ unsigned int username : 1; /**< 3.1 user name */
+ unsigned int password : 1; /**< 3.1 password */
+ unsigned int willRetain : 1; /**< will retain setting */
+ unsigned int willQoS : 2; /**< will QoS value */
+ unsigned int will : 1; /**< will flag */
+ unsigned int cleansession : 1; /**< clean session flag */
+ unsigned int : 1; /**< unused */
+ } bits;
+#else
+ struct
+ {
+ unsigned int : 1; /**< unused */
+ unsigned int cleansession : 1; /**< cleansession flag */
+ unsigned int will : 1; /**< will flag */
+ unsigned int willQoS : 2; /**< will QoS value */
+ unsigned int willRetain : 1; /**< will retain setting */
+ unsigned int password : 1; /**< 3.1 password */
+ unsigned int username : 1; /**< 3.1 user name */
+ } bits;
+#endif
+} MQTTConnectFlags; /**< connect flags byte */
+
+
+
+/**
+ * Defines the MQTT "Last Will and Testament" (LWT) settings for
+ * the connect packet.
+ */
+typedef struct {
+ /** The eyecatcher for this structure. must be MQTW. */
+ char struct_id[4];
+ /** The version number of this structure. Must be 0 */
+ uint8_t struct_version;
+ /** The LWT topic to which the LWT message will be published. */
+ MQTTString topicName;
+ /** The LWT payload. */
+ MQTTString message;
+ /**
+ * The retained flag for the LWT message (see MQTTAsync_message.retained).
+ */
+ uint8_t retained;
+ /**
+ * The quality of service setting for the LWT message (see
+ * MQTTAsync_message.qos and @ref qos).
+ */
+ QoS qos;
+} MQTTPacket_willOptions;
+
+
+#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, (QoS)0 }
+
+typedef struct {
+ /** The eyecatcher for this structure. must be MQTC. */
+ char struct_id[4];
+ /** The version number of this structure. Must be 0 */
+ uint8_t struct_version;
+ /** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1
+ */
+ uint8_t MQTTVersion;
+ MQTTString clientID;
+ uint16_t keepAliveInterval;
+ uint8_t cleansession;
+ uint8_t willFlag;
+ MQTTPacket_willOptions will;
+ MQTTString username;
+ MQTTString password;
+} MQTTPacket_connectData;
+
+typedef union
+{
+ uint8_t all; /**< all connack flags */
+#if defined(REVERSED)
+ struct
+ {
+ unsigned int sessionpresent : 1; /**< session present flag */
+ unsigned int : 7; /**< unused */
+ } bits;
+#else
+ struct
+ {
+ unsigned int : 7; /**< unused */
+ unsigned int sessionpresent : 1; /**< session present flag */
+ } bits;
+#endif
+} MQTTConnackFlags; /**< connack flags byte */
+
+typedef enum {
+ CONNACK_CONNECTION_ACCEPTED = 0,
+ CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = 1,
+ CONNACK_IDENTIFIER_REJECTED_ERROR = 2,
+ CONNACK_SERVER_UNAVAILABLE_ERROR = 3,
+ CONNACK_BAD_USERDATA_ERROR = 4,
+ CONNACK_NOT_AUTHORIZED_ERROR = 5
+}MQTTConnackReturnCodes;
+
+#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
+ MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
+
+DLLExport MQTTReturnCode MQTTSerialize_connect(unsigned char *buf, size_t buflen,
+ MQTTPacket_connectData *options,
+ uint32_t *serialized_len);
+
+DLLExport MQTTReturnCode MQTTDeserialize_connack(unsigned char *sessionPresent,
+ MQTTReturnCode *connack_rc,
+ unsigned char *buf, size_t buflen);
+
+DLLExport MQTTReturnCode MQTTSerialize_disconnect(unsigned char *buf, size_t buflen,
+ uint32_t *serialized_length);
+
+DLLExport MQTTReturnCode MQTTSerialize_pingreq(unsigned char *buf, size_t buflen,
+ uint32_t *serialized_length);
+
+#endif /* MQTTCONNECT_H_ */
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTConnectClient.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,295 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+ * Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
+ * @param options the options to be used to build the connect packet
+ * @param the length of buffer needed to contain the serialized version of the packet
+ * @return MQTTReturnCode indicating function execution status
+ */
+size_t MQTTSerialize_GetConnectLength(MQTTPacket_connectData *options) {
+ size_t len = 0;
+ FUNC_ENTRY;
+
+ /* variable depending on MQTT or MQIsdp */
+ if(3 == options->MQTTVersion) {
+ len = 12;
+ } else if(4 == options->MQTTVersion) {
+ len = 10;
+ }
+
+ len += MQTTstrlen(options->clientID) + 2;
+
+ if(options->willFlag) {
+ len += MQTTstrlen(options->will.topicName) + 2 + MQTTstrlen(options->will.message) + 2;
+ }
+
+ if(options->username.cstring || options->username.lenstring.data) {
+ len += MQTTstrlen(options->username) + 2;
+ }
+
+ if(options->password.cstring || options->password.lenstring.data) {
+ len += MQTTstrlen(options->password) + 2;
+ }
+
+ FUNC_EXIT_RC(len);
+ return len;
+}
+
+/**
+ * Serializes the connect options into the buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param len the length in bytes of the supplied buffer
+ * @param options the options to be used to build the connect packet
+ * @param serialized length
+ * @return MQTTReturnCode indicating function execution status
+ */
+MQTTReturnCode MQTTSerialize_connect(unsigned char *buf, size_t buflen,
+ MQTTPacket_connectData *options,
+ uint32_t *serialized_len) {
+ unsigned char *ptr = buf;
+ MQTTHeader header = {0};
+ MQTTConnectFlags flags = {0};
+ size_t len = 0;
+ MQTTReturnCode rc = MQTTPacket_InitHeader(&header, CONNECT, QOS0, 0, 0);
+
+ FUNC_ENTRY;
+ if(NULL == buf || NULL == options || NULL == serialized_len) {
+ FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ len = MQTTSerialize_GetConnectLength(options);
+ if(MQTTPacket_len(len) > buflen) {
+ FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ if(SUCCESS != rc) {
+ FUNC_EXIT_RC(rc);
+ return rc;
+ }
+
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
+
+ if(4 == options->MQTTVersion) {
+ writeCString(&ptr, "MQTT");
+ writeChar(&ptr, (char) 4);
+ } else {
+ writeCString(&ptr, "MQIsdp");
+ writeChar(&ptr, (char) 3);
+ }
+
+ flags.all = 0;
+ flags.bits.cleansession = (options->cleansession) ? 1 : 0;
+ flags.bits.will = (options->willFlag) ? 1 : 0;
+ if(flags.bits.will) {
+ flags.bits.willQoS = options->will.qos;
+ flags.bits.willRetain = (options->will.retained) ? 1 : 0;
+ }
+
+ if(options->username.cstring || options->username.lenstring.data) {
+ flags.bits.username = 1;
+ }
+
+ if(options->password.cstring || options->password.lenstring.data) {
+ flags.bits.password = 1;
+ }
+
+ writeChar(&ptr, flags.all);
+ writeInt(&ptr, options->keepAliveInterval);
+ writeMQTTString(&ptr, options->clientID);
+ if(options->willFlag) {
+ writeMQTTString(&ptr, options->will.topicName);
+ writeMQTTString(&ptr, options->will.message);
+ }
+
+ if(flags.bits.username) {
+ writeMQTTString(&ptr, options->username);
+ }
+
+ if(flags.bits.password) {
+ writeMQTTString(&ptr, options->password);
+ }
+
+ *serialized_len = (uint32_t)(ptr - buf);
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+/**
+ * Deserializes the supplied (wire) buffer into connack data - return code
+ * @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
+ * @param connack_rc returned integer value of the connack return code
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return MQTTReturnCode indicating function execution status
+ */
+MQTTReturnCode MQTTDeserialize_connack(unsigned char *sessionPresent,
+ MQTTReturnCode *connack_rc,
+ unsigned char *buf, size_t buflen) {
+ MQTTHeader header = {0};
+ unsigned char *curdata = buf;
+ unsigned char *enddata = NULL;
+ MQTTReturnCode rc = FAILURE;
+ uint32_t decodedLen = 0;
+ uint32_t readBytesLen = 0;
+ MQTTConnackFlags flags = {0};
+ unsigned char connack_rc_char;
+ FUNC_ENTRY;
+ if(NULL == sessionPresent || NULL == connack_rc || NULL == buf) {
+ FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ /* CONNACK header size is fixed at two bytes for fixed and 2 bytes for variable,
+ * using that as minimum size
+ * MQTT v3.1.1 Specification 3.2.1 */
+ if(4 > buflen) {
+ FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ header.byte = readChar(&curdata);
+ if(CONNACK != header.bits.type) {
+ FUNC_EXIT_RC(FAILURE);
+ return FAILURE;
+ }
+
+ /* read remaining length */
+ rc = MQTTPacket_decodeBuf(curdata, &decodedLen, &readBytesLen);
+ if(SUCCESS != rc) {
+ FUNC_EXIT_RC(rc);
+ return rc;
+ }
+
+ curdata += (readBytesLen);
+ enddata = curdata + decodedLen;
+ if(enddata - curdata < 2) {
+ FUNC_EXIT_RC(FAILURE);
+ return FAILURE;
+ }
+
+ flags.all = readChar(&curdata);
+ *sessionPresent = flags.bits.sessionpresent;
+
+ connack_rc_char = readChar(&curdata);
+ switch(connack_rc_char) {
+ case CONNACK_CONNECTION_ACCEPTED:
+ *connack_rc = MQTT_CONNACK_CONNECTION_ACCEPTED;
+ break;
+ case CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR:
+ *connack_rc = MQTT_CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR;
+ break;
+ case CONNACK_IDENTIFIER_REJECTED_ERROR:
+ *connack_rc = MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR;
+ break;
+ case CONNACK_SERVER_UNAVAILABLE_ERROR:
+ *connack_rc = MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR;
+ break;
+ case CONNACK_BAD_USERDATA_ERROR:
+ *connack_rc = MQTT_CONNACK_BAD_USERDATA_ERROR;
+ break;
+ case CONNACK_NOT_AUTHORIZED_ERROR:
+ *connack_rc = MQTT_CONNACK_NOT_AUTHORIZED_ERROR;
+ break;
+ default:
+ *connack_rc = MQTT_CONNACK_UNKNOWN_ERROR;
+ break;
+ }
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+/**
+ * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+ * @param packettype the message type
+ * @param serialized length
+ * @return MQTTReturnCode indicating function execution status
+ */
+MQTTReturnCode MQTTSerialize_zero(unsigned char *buf, size_t buflen,
+ unsigned char packetType,
+ uint32_t *serialized_length) {
+ MQTTHeader header = {0};
+ unsigned char *ptr = buf;
+ MQTTReturnCode rc = MQTTPacket_InitHeader(&header, (MessageTypes)packetType, QOS0, 0, 0);
+
+ FUNC_ENTRY;
+ if(NULL == buf || NULL == serialized_length) {
+ FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ /* Buffer should have at least 2 bytes for the header */
+ if(4 > buflen) {
+ FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ if(SUCCESS != rc) {
+ FUNC_EXIT_RC(rc);
+ return rc;
+ }
+
+ /* write header */
+ writeChar(&ptr, header.byte);
+
+ /* write remaining length */
+ ptr += MQTTPacket_encode(ptr, 0);
+ *serialized_length = (uint32_t)(ptr - buf);
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+
+/**
+ * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+ * @param serialized length
+ * @return MQTTReturnCode indicating function execution status
+ */
+MQTTReturnCode MQTTSerialize_disconnect(unsigned char *buf, size_t buflen,
+ uint32_t *serialized_length) {
+ return MQTTSerialize_zero(buf, buflen, DISCONNECT, serialized_length);
+}
+
+
+/**
+ * Serializes a pingreq packet into the supplied buffer, ready for writing to a socket
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+ * @param serialized length
+ * @return MQTTReturnCode indicating function execution status
+ */
+MQTTReturnCode MQTTSerialize_pingreq(unsigned char *buf, size_t buflen,
+ uint32_t *serialized_length) {
+ return MQTTSerialize_zero(buf, buflen, PINGREQ, serialized_length);
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTDeserializePublish.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+#include <string.h>
+
+/**
+ * Deserializes the supplied (wire) buffer into publish data
+ * @param dup returned integer - the MQTT dup flag
+ * @param qos returned integer - the MQTT QoS value
+ * @param retained returned integer - the MQTT retained flag
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param topicName returned MQTTString - the MQTT topic in the publish
+ * @param payload returned byte buffer - the MQTT publish payload
+ * @param payloadlen returned integer - the length of the MQTT payload
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success
+ */
+MQTTReturnCode MQTTDeserialize_publish(unsigned char *dup, QoS *qos,
+ unsigned char *retained, uint16_t *packetid,
+ MQTTString* topicName, unsigned char **payload,
+ uint32_t *payloadlen, unsigned char *buf, size_t buflen) {
+ MQTTHeader header = {0};
+ unsigned char *curdata = buf;
+ unsigned char *enddata = NULL;
+ MQTTReturnCode rc = FAILURE;
+ uint32_t decodedLen = 0;
+ uint32_t readBytesLen = 0;
+
+ FUNC_ENTRY;
+ if(NULL == dup || NULL == qos || NULL == retained || NULL == packetid) {
+ FUNC_EXIT_RC(FAILURE);
+ return FAILURE;
+ }
+
+ /* Publish header size is at least four bytes.
+ * Fixed header is two bytes.
+ * Variable header size depends on QoS And Topic Name.
+ * QoS level 0 doesn't have a message identifier (0 - 2 bytes)
+ * Topic Name length fields decide size of topic name field (at least 2 bytes)
+ * MQTT v3.1.1 Specification 3.3.1 */
+ if(4 > buflen) {
+ FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ header.byte = readChar(&curdata);
+ if(PUBLISH != header.bits.type) {
+ FUNC_EXIT_RC(FAILURE);
+ return FAILURE;
+ }
+
+ *dup = header.bits.dup;
+ *qos = (QoS)header.bits.qos;
+ *retained = header.bits.retain;
+
+ /* read remaining length */
+ rc = MQTTPacket_decodeBuf(curdata, &decodedLen, &readBytesLen);
+ if(SUCCESS != rc) {
+ FUNC_EXIT_RC(rc);
+ return rc;
+ }
+ curdata += (readBytesLen);
+ enddata = curdata + decodedLen;
+
+ /* do we have enough data to read the protocol version byte? */
+ if(SUCCESS != readMQTTLenString(topicName, &curdata, enddata) || (0 > (enddata - curdata))) {
+ FUNC_EXIT_RC(FAILURE);
+ return FAILURE;
+ }
+
+ if(QOS0 != *qos) {
+ *packetid = readPacketId(&curdata);
+ }
+
+ *payloadlen = (uint32_t)(enddata - curdata);
+ *payload = curdata;
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+/**
+ * Deserializes the supplied (wire) buffer into an ack
+ * @param packettype returned integer - the MQTT packet type
+ * @param dup returned integer - the MQTT dup flag
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+MQTTReturnCode MQTTDeserialize_ack(unsigned char *packettype, unsigned char *dup,
+ uint16_t *packetid, unsigned char *buf,
+ size_t buflen) {
+ MQTTReturnCode rc = FAILURE;
+ MQTTHeader header = {0};
+ unsigned char *curdata = buf;
+ unsigned char *enddata = NULL;
+ uint32_t decodedLen = 0;
+ uint32_t readBytesLen = 0;
+ FUNC_ENTRY;
+ if(NULL == packettype || NULL == dup || NULL == packetid || NULL == buf) {
+ FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ /* PUBACK fixed header size is two bytes, variable header is 2 bytes, MQTT v3.1.1 Specification 3.4.1 */
+ if(4 > buflen) {
+ FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ header.byte = readChar(&curdata);
+ *dup = header.bits.dup;
+ *packettype = header.bits.type;
+
+ /* read remaining length */
+ rc = MQTTPacket_decodeBuf(curdata, &decodedLen, &readBytesLen);
+ if(SUCCESS != rc) {
+ FUNC_EXIT_RC(rc);
+ return rc;
+ }
+ curdata += (readBytesLen);
+ enddata = curdata + decodedLen;
+
+ if(enddata - curdata < 2) {
+ FUNC_EXIT_RC(FAILURE);
+ return FAILURE;
+ }
+
+ *packetid = readPacketId(&curdata);
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTMessage.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 MQTTMessage.h
+ * @brief Definition of Messages for the MQTT Client
+ */
+
+#ifndef __MQTT_MESSAGE_H
+#define __MQTT_MESSAGE_H
+
+/* Enum order should match the packet ids array defined in MQTTFormat.c */
+typedef enum msgTypes {
+ UNKNOWN = -1,
+ CONNECT = 1,
+ CONNACK = 2,
+ PUBLISH = 3,
+ PUBACK = 4,
+ PUBREC = 5,
+ PUBREL = 6,
+ PUBCOMP = 7,
+ SUBSCRIBE = 8,
+ SUBACK = 9,
+ UNSUBSCRIBE = 10,
+ UNSUBACK = 11,
+ PINGREQ = 12,
+ PINGRESP = 13,
+ DISCONNECT = 14
+}MessageTypes;
+
+typedef enum QoS {
+ QOS0 = 0,
+ QOS1 = 1,
+ QOS2 = 2
+}QoS;
+
+typedef struct {
+ QoS qos;
+ uint8_t retained;
+ uint8_t dup;
+ uint16_t id;
+ void *payload;
+ size_t payloadlen;
+}MQTTMessage;
+
+#endif //__MQTT_MESSAGE_H
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTPacket.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,391 @@
+/*******************************************************************************
+ * 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
+ * Sergio R. Caprile - non-blocking packet read functions for stream transport
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+
+#include <string.h>
+
+/**
+ * Encodes the message length according to the MQTT algorithm
+ * @param buf the buffer into which the encoded data is written
+ * @param length the length to be encoded
+ * @return the number of bytes written to buffer
+ */
+uint32_t MQTTPacket_encode(unsigned char *buf, size_t length) {
+ uint32_t outLen = 0;
+
+ FUNC_ENTRY;
+ do {
+ int16_t d = length % 128;
+ length /= 128;
+ /* if there are more digits to encode, set the top bit of this digit */
+ if(length > 0) {
+ d |= 0x80;
+ }
+ buf[outLen++] = (unsigned char)d;
+ }while(length > 0);
+
+ FUNC_EXIT_RC(outLen);
+ return outLen;
+}
+
+/**
+ * Decodes the message length according to the MQTT algorithm
+ * @param getcharfn pointer to function to read the next character from the data source
+ * @param value the decoded length returned
+ * @return the number of bytes read from the socket
+ */
+MQTTReturnCode MQTTPacket_decode(uint32_t (*getcharfn)(unsigned char *, uint32_t), uint32_t *value, uint32_t *readBytesLen) {
+ unsigned char c;
+ uint32_t multiplier = 1;
+ uint32_t len = 0;
+ uint32_t getLen = 0;
+#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
+
+ FUNC_ENTRY;
+ *value = 0;
+ do {
+ if(++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) {
+ /* bad data */
+ FUNC_EXIT_RC(MQTTPACKET_READ_ERROR);
+ return MQTTPACKET_READ_ERROR;
+ }
+ getLen = (*getcharfn)(&c, 1);
+ if(1 != getLen) {
+ FUNC_EXIT_RC(FAILURE);
+ return FAILURE;
+ }
+ *value += (c & 127) * multiplier;
+ multiplier *= 128;
+ }while((c & 128) != 0);
+
+ *readBytesLen = len;
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+size_t MQTTPacket_len(size_t rem_len) {
+ rem_len += 1; /* header byte */
+
+ /* now remaining_length field */
+ if(rem_len < 128) {
+ rem_len += 1;
+ } else if (rem_len < 16384) {
+ rem_len += 2;
+ } else if (rem_len < 2097151) {
+ rem_len += 3;
+ } else {
+ rem_len += 4;
+ }
+
+ return rem_len;
+}
+
+static unsigned char *bufptr;
+
+uint32_t bufchar(unsigned char *c, uint32_t count) {
+ uint32_t i;
+
+ for(i = 0; i < count; ++i) {
+ *c = *bufptr++;
+ }
+
+ return count;
+}
+
+MQTTReturnCode MQTTPacket_decodeBuf(unsigned char *buf, uint32_t *value, uint32_t *readBytesLen) {
+ bufptr = buf;
+ return MQTTPacket_decode(bufchar, value, readBytesLen);
+}
+
+/**
+ * Calculates an integer from two bytes read from the input buffer
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the integer value calculated
+ */
+int32_t readInt(unsigned char **pptr) {
+ unsigned char *ptr = *pptr;
+ int32_t len = 256*(*ptr) + (*(ptr+1));
+ *pptr += 2;
+ return len;
+}
+
+/**
+ * Calculates an integer from two bytes read from the input buffer
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the integer value calculated
+ */
+size_t readSizeT(unsigned char **pptr) {
+ unsigned char *ptr = *pptr;
+ size_t firstByte = (size_t)(*ptr);
+ size_t secondByte = (size_t)(*(ptr+1));
+ size_t size = 256 * firstByte + secondByte;
+ *pptr += 2;
+ return size;
+}
+
+/**
+ * Calculates uint16 packet id from two bytes read from the input buffer
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the value calculated
+ */
+uint16_t readPacketId(unsigned char **pptr) {
+ unsigned char *ptr = *pptr;
+ uint8_t firstByte = (uint8_t)(*ptr);
+ uint8_t secondByte = (uint8_t)(*(ptr + 1));
+ uint16_t len = (uint16_t)(secondByte + (256 * firstByte));
+ *pptr += 2;
+ return len;
+}
+
+/**
+ * Reads one character from the input buffer.
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the character read
+ */
+unsigned char readChar(unsigned char **pptr) {
+ unsigned char c = **pptr;
+ (*pptr)++;
+ return c;
+}
+
+/**
+ * Writes one character to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param c the character to write
+ */
+void writeChar(unsigned char **pptr, unsigned char c) {
+ **pptr = c;
+ (*pptr)++;
+}
+
+/**
+ * Writes an integer as 2 bytes to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param anInt the integer to write
+ */
+void writePacketId(unsigned char** pptr, uint16_t anInt) {
+ **pptr = (unsigned char)(anInt / 256);
+ (*pptr)++;
+ **pptr = (unsigned char)(anInt % 256);
+ (*pptr)++;
+}
+
+/**
+ * Writes an integer as 2 bytes to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param anInt the integer to write
+ */
+void writeInt(unsigned char **pptr, int32_t anInt) {
+ **pptr = (unsigned char)(anInt / 256);
+ (*pptr)++;
+ **pptr = (unsigned char)(anInt % 256);
+ (*pptr)++;
+}
+
+/**
+ * Writes size as 2 bytes to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param anInt the integer to write
+ */
+void writeSizeT(unsigned char **pptr, size_t size) {
+ **pptr = (unsigned char)(size / 256);
+ (*pptr)++;
+ **pptr = (unsigned char)(size % 256);
+ (*pptr)++;
+}
+
+/**
+ * Writes a "UTF" string to an output buffer. Converts C string to length-delimited.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param string the C string to write
+ */
+void writeCString(unsigned char **pptr, const char *string) {
+ size_t len = strlen(string);
+ writeSizeT(pptr, len);
+ memcpy(*pptr, string, len);
+ *pptr += len;
+}
+
+void writeMQTTString(unsigned char **pptr, MQTTString mqttstring) {
+ if(mqttstring.lenstring.len > 0) {
+ writeSizeT(pptr, mqttstring.lenstring.len);
+ memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
+ *pptr += mqttstring.lenstring.len;
+ } else if (mqttstring.cstring) {
+ writeCString(pptr, mqttstring.cstring);
+ } else {
+ writeInt(pptr, 0);
+ }
+}
+
+/**
+ * @param mqttstring the MQTTString structure into which the data is to be read
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param enddata pointer to the end of the data: do not read beyond
+ * @return SUCCESS if successful, FAILURE if not
+ */
+MQTTReturnCode readMQTTLenString(MQTTString *mqttstring, unsigned char **pptr, unsigned char *enddata) {
+ MQTTReturnCode rc = FAILURE;
+
+ FUNC_ENTRY;
+ /* the first two bytes are the length of the string */
+ /* enough length to read the integer? */
+ if(enddata - (*pptr) > 1) {
+ mqttstring->lenstring.len = readSizeT(pptr); /* increments pptr to point past length */
+ if(&(*pptr)[mqttstring->lenstring.len] <= enddata) {
+ mqttstring->lenstring.data = (char*)*pptr;
+ *pptr += mqttstring->lenstring.len;
+ rc = SUCCESS;
+ }
+ }
+ mqttstring->cstring = NULL;
+
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+/**
+ * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
+ * @param mqttstring the string to return the length of
+ * @return the length of the string
+ */
+size_t MQTTstrlen(MQTTString mqttstring) {
+ size_t len = 0;
+
+ if(mqttstring.cstring) {
+ len = strlen(mqttstring.cstring);
+ } else {
+ len = mqttstring.lenstring.len;
+ }
+
+ return len;
+}
+
+/**
+ * Compares an MQTTString to a C string
+ * @param a the MQTTString to compare
+ * @param bptr the C string to compare
+ * @return boolean - equal or not
+ */
+uint8_t MQTTPacket_equals(MQTTString *a, char *bptr) {
+ size_t alen = 0;
+ size_t blen = 0;
+ char *aptr;
+
+ if(a->cstring) {
+ aptr = a->cstring;
+ alen = strlen(a->cstring);
+ } else {
+ aptr = a->lenstring.data;
+ alen = a->lenstring.len;
+ }
+ blen = strlen(bptr);
+
+ return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
+}
+
+/**
+ * Initialize the MQTTHeader structure. Used to ensure that Header bits are
+ * always initialized using the proper mappings. No Endianness issues here since
+ * the individual fields are all less than a byte. Also generates no warnings since
+ * all fields are initialized using hex constants
+ */
+MQTTReturnCode MQTTPacket_InitHeader(MQTTHeader *header, MessageTypes message_type,
+ QoS qos, uint8_t dup, uint8_t retained) {
+ if(NULL == header) {
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ /* Set all bits to zero */
+ header->byte = 0;
+ switch(message_type) {
+ case UNKNOWN:
+ /* Should never happen */
+ return MQTT_UNKNOWN_ERROR;
+ case CONNECT:
+ header->bits.type = 0x01;
+ break;
+ case CONNACK:
+ header->bits.type = 0x02;
+ break;
+ case PUBLISH:
+ header->bits.type = 0x03;
+ break;
+ case PUBACK:
+ header->bits.type = 0x04;
+ break;
+ case PUBREC:
+ header->bits.type = 0x05;
+ break;
+ case PUBREL:
+ header->bits.type = 0x06;
+ break;
+ case PUBCOMP:
+ header->bits.type = 0x07;
+ break;
+ case SUBSCRIBE:
+ header->bits.type = 0x08;
+ break;
+ case SUBACK:
+ header->bits.type = 0x09;
+ break;
+ case UNSUBSCRIBE:
+ header->bits.type = 0x0A;
+ break;
+ case UNSUBACK:
+ header->bits.type = 0x0B;
+ break;
+ case PINGREQ:
+ header->bits.type = 0x0C;
+ break;
+ case PINGRESP:
+ header->bits.type = 0x0D;
+ break;
+ case DISCONNECT:
+ header->bits.type = 0x0E;
+ break;
+ default:
+ /* Should never happen */
+ return MQTT_UNKNOWN_ERROR;
+ }
+
+ header->bits.dup = (1 == dup) ? 0x01 : 0x00;
+ switch(qos) {
+ case QOS0:
+ header->bits.qos = 0x00;
+ break;
+ case QOS1:
+ header->bits.qos = 0x01;
+ break;
+ case QOS2:
+ header->bits.qos = 0x02;
+ break;
+ default:
+ /* Using QOS0 as default */
+ header->bits.qos = 0x00;
+ break;
+ }
+
+ header->bits.retain = (1 == retained) ? 0x01 : 0x00;
+
+ return SUCCESS;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTPacket.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * 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
+ * Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTPACKET_H_
+#define MQTTPACKET_H_
+
+#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
+extern "C" {
+#endif
+
+#if defined(WIN32_DLL) || defined(WIN64_DLL)
+ #define DLLImport __declspec(dllimport)
+ #define DLLExport __declspec(dllexport)
+#elif defined(LINUX_SO)
+ #define DLLImport extern
+ #define DLLExport __attribute__ ((visibility ("default")))
+#else
+ #define DLLImport
+ #define DLLExport
+#endif
+
+#include "stdint.h"
+#include "stddef.h"
+#include "MQTTReturnCodes.h"
+#include "MQTTMessage.h"
+
+/**
+ * Bitfields for the MQTT header byte.
+ */
+typedef union {
+ unsigned char byte; /**< the whole byte */
+#if defined(REVERSED)
+ struct {
+ unsigned int type : 4; /**< message type nibble */
+ unsigned int dup : 1; /**< DUP flag bit */
+ unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
+ unsigned int retain : 1; /**< retained flag bit */
+ } bits;
+#else
+ struct {
+ unsigned int retain : 1; /**< retained flag bit */
+ unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
+ unsigned int dup : 1; /**< DUP flag bit */
+ unsigned int type : 4; /**< message type nibble */
+ } bits;
+#endif
+} MQTTHeader;
+
+typedef struct {
+ size_t len;
+ char *data;
+} MQTTLenString;
+
+typedef struct {
+ char *cstring;
+ MQTTLenString lenstring;
+} MQTTString;
+
+#define MQTTString_initializer {NULL, {0, NULL}}
+
+MQTTReturnCode MQTTPacket_InitHeader(MQTTHeader *header, MessageTypes message_type,
+ QoS qos, uint8_t dup, uint8_t retained);
+size_t MQTTstrlen(MQTTString mqttstring);
+
+#include "MQTTConnect.h"
+#include "MQTTPublish.h"
+#include "MQTTSubscribe.h"
+#include "MQTTUnsubscribe.h"
+
+MQTTReturnCode MQTTSerialize_ack(unsigned char *buf, size_t buflen,
+ unsigned char type, unsigned char dup, uint16_t packetid,
+ uint32_t *serialized_len);
+MQTTReturnCode MQTTDeserialize_ack(unsigned char *packettype, unsigned char *dup,
+ uint16_t *packetid, unsigned char *buf,
+ size_t buflen);
+
+size_t MQTTPacket_len(size_t rem_len);
+uint8_t MQTTPacket_equals(MQTTString *a, char *bptr);
+
+uint32_t MQTTPacket_encode(unsigned char *buf, size_t length);
+MQTTReturnCode MQTTPacket_decode(uint32_t (*getcharfn)(unsigned char *, uint32_t), uint32_t *value, uint32_t *readBytesLen);
+MQTTReturnCode MQTTPacket_decodeBuf(unsigned char *buf, uint32_t *value, uint32_t *readBytesLen);
+
+uint16_t readPacketId(unsigned char **pptr);
+void writePacketId(unsigned char** pptr, uint16_t anInt);
+
+int32_t readInt(unsigned char **pptr);
+size_t readSizeT(unsigned char **pptr);
+unsigned char readChar(unsigned char **pptr);
+void writeChar(unsigned char **pptr, unsigned char c);
+void writeInt(unsigned char **pptr, int32_t anInt);
+void writeSizeT(unsigned char **pptr, size_t size);
+MQTTReturnCode readMQTTLenString(MQTTString *mqttstring, unsigned char **pptr, unsigned char *enddata);
+void writeCString(unsigned char **pptr, const char *string);
+void writeMQTTString(unsigned char **pptr, MQTTString mqttstring);
+
+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
+}
+#endif
+
+
+#endif /* MQTTPACKET_H_ */
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTPublish.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,50 @@ +/******************************************************************************* + * 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 + * Xiang Rong - 442039 Add makefile to Embedded C client + *******************************************************************************/ + +#ifndef MQTTPUBLISH_H_ +#define MQTTPUBLISH_H_ + +#if !defined(DLLImport) + #define DLLImport +#endif +#if !defined(DLLExport) + #define DLLExport +#endif + +#include "MQTTMessage.h" + +DLLExport MQTTReturnCode MQTTSerialize_publish(unsigned char *buf, size_t buflen, uint8_t dup, + QoS qos, uint8_t retained, uint16_t packetid, + MQTTString topicName, unsigned char *payload, size_t payloadlen, + uint32_t *serialized_len); + +DLLExport MQTTReturnCode MQTTDeserialize_publish(unsigned char *dup, QoS *qos, + unsigned char *retained, uint16_t *packetid, + MQTTString* topicName, unsigned char **payload, + uint32_t *payloadlen, unsigned char *buf, size_t buflen); + +DLLExport MQTTReturnCode MQTTSerialize_puback(unsigned char* buf, size_t buflen, + uint16_t packetid, uint32_t *serialized_len); +DLLExport MQTTReturnCode MQTTSerialize_pubrel(unsigned char *buf, size_t buflen, + unsigned char dup, uint16_t packetid, + uint32_t *serialized_len); +DLLExport MQTTReturnCode MQTTSerialize_pubcomp(unsigned char *buf, size_t buflen, + uint16_t packetid, uint32_t *serialized_len); + +#endif /* MQTTPUBLISH_H_ */ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTReturnCodes.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 MQTTErrorCodes.h
+ * @brief Definition of error types for the MQTT Client
+ */
+
+#ifndef __MQTT_ERRORCODES_H
+#define __MQTT_ERRORCODES_H
+
+/* all failure return codes must be negative */
+typedef enum {
+ MQTT_NETWORK_MANUALLY_DISCONNECTED = 5,
+ MQTT_CONNACK_CONNECTION_ACCEPTED = 4,
+ MQTT_ATTEMPTING_RECONNECT = 3,
+ MQTT_NOTHING_TO_READ = 2,
+ MQTT_NETWORK_RECONNECTED = 1,
+ SUCCESS = 0,
+ FAILURE = -1,
+ BUFFER_OVERFLOW = -2,
+ MQTT_UNKNOWN_ERROR = -3,
+ MQTT_NETWORK_DISCONNECTED_ERROR = -4,
+ MQTT_NETWORK_ALREADY_CONNECTED_ERROR = -5,
+ MQTT_NULL_VALUE_ERROR = -6,
+ MQTT_MAX_SUBSCRIPTIONS_REACHED_ERROR = -7,
+ MQTT_RECONNECT_TIMED_OUT = -8,
+ MQTTPACKET_BUFFER_TOO_SHORT = -9,
+ MQTTPACKET_READ_ERROR = -10,
+ MQTTPACKET_READ_COMPLETE = -11,
+ MQTT_CONNACK_UNKNOWN_ERROR = -12,
+ MQTT_CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = -13,
+ MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR = -14,
+ MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR = -15,
+ MQTT_CONNACK_BAD_USERDATA_ERROR = -16,
+ MQTT_CONNACK_NOT_AUTHORIZED_ERROR = -17,
+ MQTT_BUFFER_RX_MESSAGE_INVALID = -18
+}MQTTReturnCode;
+
+#endif //__MQTT_ERRORCODES_H
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTSerializePublish.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * 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
+ * Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+ * Determines the length of the MQTT publish packet that would be produced using the supplied parameters
+ * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
+ * @param topicName the topic name to be used in the publish
+ * @param payloadlen the length of the payload to be sent
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+size_t MQTTSerialize_GetPublishLength(uint8_t qos, MQTTString topicName, size_t payloadlen) {
+ size_t len = 0;
+
+ len += 2 + MQTTstrlen(topicName) + payloadlen;
+ if(qos > 0) {
+ len += 2; /* packetid */
+ }
+ return len;
+}
+
+
+/**
+ * Serializes the supplied publish data into the supplied buffer, ready for sending
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param dup integer - the MQTT dup flag
+ * @param qos integer - the MQTT QoS value
+ * @param retained integer - the MQTT retained flag
+ * @param packetid integer - the MQTT packet identifier
+ * @param topicName MQTTString - the MQTT topic in the publish
+ * @param payload byte buffer - the MQTT publish payload
+ * @param payloadlen integer - the length of the MQTT payload
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+MQTTReturnCode MQTTSerialize_publish(unsigned char *buf, size_t buflen, uint8_t dup,
+ QoS qos, uint8_t retained, uint16_t packetid,
+ MQTTString topicName, unsigned char *payload, size_t payloadlen,
+ uint32_t *serialized_len) {
+ unsigned char *ptr = buf;
+ MQTTHeader header = {0};
+ size_t rem_len = 0;
+ MQTTReturnCode rc = MQTTPacket_InitHeader(&header, PUBLISH, qos, dup, retained);
+
+ FUNC_ENTRY;
+ if(NULL == buf || NULL == payload || NULL == serialized_len) {
+ FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ rem_len = MQTTSerialize_GetPublishLength(qos, topicName, payloadlen);
+ if(MQTTPacket_len(rem_len) > buflen) {
+ FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ if(SUCCESS != rc) {
+ FUNC_EXIT_RC(rc);
+ return rc;
+ }
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+ writeMQTTString(&ptr, topicName);
+
+ if(qos > 0) {
+ writeInt(&ptr, packetid);
+ }
+
+ memcpy(ptr, payload, payloadlen);
+ ptr += payloadlen;
+
+ *serialized_len = (uint32_t)(ptr - buf);
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+/**
+ * Serializes the ack packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param type the MQTT packet type
+ * @param dup the MQTT dup flag
+ * @param packetid the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+MQTTReturnCode MQTTSerialize_ack(unsigned char *buf, size_t buflen,
+ unsigned char type, uint8_t dup, uint16_t packetid,
+ uint32_t *serialized_len) {
+ MQTTHeader header = {0};
+ unsigned char *ptr = buf;
+ QoS requestQoS = (PUBREL == type) ? QOS1 : QOS0;
+ MQTTReturnCode rc = MQTTPacket_InitHeader(&header, (MessageTypes)type, requestQoS, dup, 0);
+
+ FUNC_ENTRY;
+ if(NULL == buf || serialized_len == NULL) {
+ FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ /* Minimum byte length required by ACK headers is
+ * 2 for fixed and 2 for variable part */
+ if(4 > buflen) {
+ FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ if(SUCCESS != rc) {
+ FUNC_EXIT_RC(rc);
+ return rc;
+ }
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+ writePacketId(&ptr, packetid);
+ *serialized_len = (uint32_t)(ptr - buf);
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+
+/**
+ * Serializes a puback packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param packetid integer - the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+MQTTReturnCode MQTTSerialize_puback(unsigned char* buf, size_t buflen,
+ uint16_t packetid, uint32_t *serialized_len) {
+ return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid, serialized_len);
+}
+
+
+/**
+ * Serializes a pubrel packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param dup integer - the MQTT dup flag
+ * @param packetid integer - the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+MQTTReturnCode MQTTSerialize_pubrel(unsigned char *buf, size_t buflen,
+ unsigned char dup, uint16_t packetid,
+ uint32_t *serialized_len) {
+ return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid, serialized_len);
+}
+
+
+/**
+ * Serializes a pubrel packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param packetid integer - the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+MQTTReturnCode MQTTSerialize_pubcomp(unsigned char *buf, size_t buflen,
+ uint16_t packetid, uint32_t *serialized_len) {
+ return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid, serialized_len);
+}
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTSubscribe.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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 + * Xiang Rong - 442039 Add makefile to Embedded C client + *******************************************************************************/ + +#ifndef MQTTSUBSCRIBE_H_ +#define MQTTSUBSCRIBE_H_ + +#if !defined(DLLImport) + #define DLLImport +#endif +#if !defined(DLLExport) + #define DLLExport +#endif + +DLLExport MQTTReturnCode MQTTSerialize_subscribe(unsigned char *buf, size_t buflen, + unsigned char dup, uint16_t packetid, uint32_t count, + MQTTString topicFilters[], QoS requestedQoSs[], + uint32_t *serialized_len); + +DLLExport MQTTReturnCode MQTTDeserialize_suback(uint16_t *packetid, uint32_t maxcount, + uint32_t *count, QoS grantedQoSs[], + unsigned char* buf, size_t buflen); + + +#endif /* MQTTSUBSCRIBE_H_ */ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTSubscribeClient.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+ * Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
+ * @param count the number of topic filter strings in topicFilters
+ * @param topicFilters the array of topic filter strings to be used in the publish
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+size_t MQTTSerialize_GetSubscribePacketLength(uint32_t count, MQTTString topicFilters[]) {
+ size_t i;
+ size_t len = 2; /* packetid */
+
+ for(i = 0; i < count; ++i) {
+ len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
+ }
+
+ return len;
+}
+
+/**
+ * Serializes the supplied subscribe data into the supplied buffer, ready for sending
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied bufferr
+ * @param dup integer - the MQTT dup flag
+ * @param packetid integer - the MQTT packet identifier
+ * @param count - number of members in the topicFilters and reqQos arrays
+ * @param topicFilters - array of topic filter names
+ * @param requestedQoSs - array of requested QoS
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+MQTTReturnCode MQTTSerialize_subscribe(unsigned char *buf, size_t buflen,
+ unsigned char dup, uint16_t packetid, uint32_t count,
+ MQTTString topicFilters[], QoS requestedQoSs[],
+ uint32_t *serialized_len) {
+ unsigned char *ptr = buf;
+ MQTTHeader header = {0};
+ size_t rem_len = 0;
+ uint32_t i = 0;
+ MQTTReturnCode rc = MQTTPacket_InitHeader(&header, SUBSCRIBE, (QoS)1, dup, 0);
+ FUNC_ENTRY;
+ if(NULL == buf || NULL == serialized_len) {
+ FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ if(MQTTPacket_len(rem_len = MQTTSerialize_GetSubscribePacketLength(count, topicFilters)) > buflen) {
+ FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ if(SUCCESS != rc) {
+ FUNC_EXIT_RC(rc);
+ return rc;
+ }
+ /* write header */
+ writeChar(&ptr, header.byte);
+
+ /* write remaining length */
+ ptr += MQTTPacket_encode(ptr, rem_len);
+
+ writePacketId(&ptr, packetid);
+
+ for(i = 0; i < count; ++i) {
+ writeMQTTString(&ptr, topicFilters[i]);
+ writeChar(&ptr, (unsigned char)requestedQoSs[i]);
+ }
+
+ *serialized_len = (uint32_t)(ptr - buf);
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+/**
+ * Deserializes the supplied (wire) buffer into suback data
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param maxcount - the maximum number of members allowed in the grantedQoSs array
+ * @param count returned integer - number of members in the grantedQoSs array
+ * @param grantedQoSs returned array of integers - the granted qualities of service
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+MQTTReturnCode MQTTDeserialize_suback(uint16_t *packetid, uint32_t maxcount,
+ uint32_t *count, QoS grantedQoSs[],
+ unsigned char *buf, size_t buflen) {
+ MQTTHeader header = {0};
+ unsigned char *curdata = buf;
+ unsigned char *enddata = NULL;
+ MQTTReturnCode decodeRc = FAILURE;
+ uint32_t decodedLen = 0;
+ uint32_t readBytesLen = 0;
+
+ FUNC_ENTRY;
+ if(NULL == packetid || NULL == count || NULL == grantedQoSs) {
+ FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ /* SUBACK header size is 4 bytes for header and at least one byte for QoS payload
+ * Need at least a 5 bytes buffer. MQTT3.1.1 specification 3.9
+ */
+ if(5 > buflen) {
+ FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ header.byte = readChar(&curdata);
+ if (header.bits.type != SUBACK) {
+ FUNC_EXIT_RC(FAILURE);
+ return FAILURE;
+ }
+
+ /* read remaining length */
+ decodeRc = MQTTPacket_decodeBuf(curdata, &decodedLen, &readBytesLen);
+ if(decodeRc != SUCCESS) {
+ return decodeRc;
+ }
+
+ curdata += (readBytesLen);
+ enddata = curdata + decodedLen;
+ if (enddata - curdata < 2) {
+ FUNC_EXIT_RC(FAILURE);
+ return FAILURE;
+ }
+
+ *packetid = readPacketId(&curdata);
+
+ *count = 0;
+ while(curdata < enddata) {
+ if(*count > maxcount) {
+ FUNC_EXIT_RC(FAILURE);
+ return FAILURE;
+ }
+ grantedQoSs[(*count)++] = (QoS)readChar(&curdata);
+ }
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTUnsubscribe.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,37 @@ +/******************************************************************************* + * 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 + * Xiang Rong - 442039 Add makefile to Embedded C client + *******************************************************************************/ + +#ifndef MQTTUNSUBSCRIBE_H_ +#define MQTTUNSUBSCRIBE_H_ + +#if !defined(DLLImport) + #define DLLImport +#endif +#if !defined(DLLExport) + #define DLLExport +#endif + +DLLExport MQTTReturnCode MQTTSerialize_unsubscribe(unsigned char* buf, size_t buflen, + uint8_t dup, uint16_t packetid, + uint32_t count, MQTTString topicFilters[], + uint32_t *serialized_len); + +DLLExport MQTTReturnCode MQTTDeserialize_unsuback(uint16_t *packetid, unsigned char *buf, size_t buflen); + +#endif /* MQTTUNSUBSCRIBE_H_ */ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/MQTTUnsubscribeClient.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+ * Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
+ * @param count the number of topic filter strings in topicFilters
+ * @param topicFilters the array of topic filter strings to be used in the publish
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+size_t MQTTSerialize_GetUnsubscribePacketLength(uint32_t count, MQTTString topicFilters[]) {
+ size_t i;
+ size_t len = 2; /* packetid */
+
+ for(i = 0; i < count; ++i) {
+ len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
+ }
+
+ return len;
+}
+
+/**
+ * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @param dup integer - the MQTT dup flag
+ * @param packetid integer - the MQTT packet identifier
+ * @param count - number of members in the topicFilters array
+ * @param topicFilters - array of topic filter names
+ * @param serialized_len - the length of the serialized data
+ * @return MQTTReturnCode indicating function execution status
+ */
+MQTTReturnCode MQTTSerialize_unsubscribe(unsigned char* buf, size_t buflen,
+ uint8_t dup, uint16_t packetid,
+ uint32_t count, MQTTString topicFilters[],
+ uint32_t *serialized_len) {
+ unsigned char *ptr = buf;
+ MQTTHeader header = {0};
+ size_t rem_len = 0;
+ uint32_t i = 0;
+ MQTTReturnCode rc = MQTTPacket_InitHeader(&header, UNSUBSCRIBE, (QoS)1, dup, 0);
+
+ FUNC_ENTRY;
+ if(NULL == buf || NULL == serialized_len) {
+ FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ rem_len = MQTTSerialize_GetUnsubscribePacketLength(count, topicFilters);
+ if(MQTTPacket_len(rem_len) > buflen) {
+ FUNC_EXIT_RC(MQTTPACKET_BUFFER_TOO_SHORT);
+ return MQTTPACKET_BUFFER_TOO_SHORT;
+ }
+
+ if(SUCCESS != rc) {
+ FUNC_EXIT_RC(rc);
+ return rc;
+ }
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */
+
+ writePacketId(&ptr, packetid);
+
+ for(i = 0; i < count; ++i) {
+ writeMQTTString(&ptr, topicFilters[i]);
+ }
+
+ *serialized_len = (uint32_t)(ptr - buf);
+
+ FUNC_EXIT_RC(SUCCESS);
+ return SUCCESS;
+}
+
+
+/**
+ * Deserializes the supplied (wire) buffer into unsuback data
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return MQTTReturnCode indicating function execution status
+ */
+MQTTReturnCode MQTTDeserialize_unsuback(uint16_t *packetid, unsigned char *buf, size_t buflen) {
+ unsigned char type = 0;
+ unsigned char dup = 0;
+ MQTTReturnCode rc = FAILURE;
+
+ FUNC_ENTRY;
+ if(NULL == packetid || NULL == buf) {
+ FUNC_EXIT_RC(MQTT_NULL_VALUE_ERROR);
+ return MQTT_NULL_VALUE_ERROR;
+ }
+
+ rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
+ if(SUCCESS == rc && UNSUBACK != type) {
+ rc = FAILURE;
+ }
+
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_mqtt_embedded_client_lib/MQTTPacket/src/StackTrace.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,80 @@ +/******************************************************************************* + * 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 + * Ian Craggs - fix for bug #434081 + *******************************************************************************/ + +#ifndef STACKTRACE_H_ +#define STACKTRACE_H_ + +#include <stdio.h> +#define NOSTACKTRACE 1 + +#if defined(NOSTACKTRACE) +#define FUNC_ENTRY +#define FUNC_ENTRY_NOLOG +#define FUNC_ENTRY_MED +#define FUNC_ENTRY_MAX +#define FUNC_EXIT +#define FUNC_EXIT_NOLOG +#define FUNC_EXIT_MED +#define FUNC_EXIT_MAX +#define FUNC_EXIT_RC(x) +#define FUNC_EXIT_MED_RC(x) +#define FUNC_EXIT_MAX_RC(x) + +#else + +#if defined(WIN32) +#define inline __inline +#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM) +#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1) +#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM) +#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM) +#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM) +#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1) +#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM) +#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM) +#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM) +#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM) +#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM) +#else +#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM) +#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1) +#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM) +#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM) +#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM) +#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1) +#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM) +#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM) +#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM) +#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM) +#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM) + +void StackTrace_entry(const char* name, int line, int trace); +void StackTrace_exit(const char* name, int line, void* return_value, int trace); + +void StackTrace_printStack(FILE* dest); +char* StackTrace_get(unsigned long); + +#endif + +#endif + + + + +#endif /* STACKTRACE_H_ */ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/certs/certs.cpp Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,39 @@ +#include "aws_iot_config.h" + +// The user needs to paste the AWS 'thing' certs into this file. +// Root CA: +// https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem +const unsigned char AWS_IOT_ROOT_CA[] = "-----BEGIN CERTIFICATE-----\n" +"MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\n" +"yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\n" +"ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\n" +"U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\n" +"ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\n" +"aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL\n" +"MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\n" +"ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln\n" +"biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\n" +"U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" +"aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1\n" +"nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex\n" +"t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz\n" +"SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG\n" +"BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+\n" +"rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/\n" +"NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\n" +"BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\n" +"BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\n" +"aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv\n" +"MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE\n" +"p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y\n" +"5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK\n" +"WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ\n" +"4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N\n" +"hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\n" +"-----END CERTIFICATE-----\0"; + +// Device signed certificate +const unsigned char AWS_IOT_CERTIFICATE[] = "TODO"; + +// Device private key +const unsigned char AWS_IOT_PRIVATE_KEY[] = "TODO"; \ No newline at end of file
--- a/README.md Fri Oct 28 13:30:20 2016 +0100 +++ b/README.md Thu Dec 01 18:05:38 2016 +0000 @@ -1,89 +1,3 @@ -# HTTPS File Download Example for TLS Client on mbed OS - -This application downloads a file from an HTTPS server (developer.mbed.org) and looks for a specific string in that file. - -## Getting started - -Set up your environment if you have not done so already. For instructions, refer to the [main readme](../README.md). - -## Required hardware - -This example also requires an Ethernet cable and connection to the internet additional to the hardware requirements in the [main readme](../README.md). - -The networking stack used in this example requires TLS functionality to be enabled on mbed TLS. On devices where hardware entropy is not present, TLS is disabled by default. This would result in compile time or linking failures. - -To learn why entropy is required, read the [TLS Porting guide](https://docs.mbed.com/docs/mbed-os-handbook/en/5.2/advanced/tls_porting/). - -## Monitoring the application - -__NOTE:__ Make sure that the Ethernet cable is plugged in correctly before running the application. - -The output in the terminal window should be similar to this: - -``` -Using Ethernet LWIP -Client IP Address is 10.2.203.43 -Connecting with developer.mbed.org -Starting the TLS handshake... -TLS connection to developer.mbed.org established -Server certificate: - cert. version : 3 - serial number : 11:21:B8:47:9B:21:6C:B1:C6:AF:BC:5D:0C:19:52:DC:D7:C3 - issuer name : C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - SHA256 - G2 - subject name : C=GB, ST=Cambridgeshire, L=Cambridge, O=ARM Ltd, CN=*.mbed.com - issued on : 2016-03-03 12:26:08 - expires on : 2017-04-05 10:31:02 - signed using : RSA with SHA-256 - RSA key size : 2048 bits - basic constraints : CA=false - subject alt name : *.mbed.com, mbed.org, *.mbed.org, mbed.com - key usage : Digital Signature, Key Encipherment - ext key usage : TLS Web Server Authentication, TLS Web Client Authentication -Certificate verification passed +# Avnet AT&T Amazon Web Service Internet-of-Things demo -HTTPS: Received 439 chars from server -HTTPS: Received 200 OK status ... [OK] -HTTPS: Received 'Hello world!' status ... [OK] -HTTPS: Received message: - -HTTP/1.1 200 OK -Server: nginx/1.7.10 -Date: Wed, 20 Jul 2016 10:00:35 GMT -Content-Type: text/plain -Content-Length: 14 -Connection: keep-alive -Last-Modified: Fri, 27 Jul 2012 13:30:34 GMT -Accept-Ranges: bytes -Cache-Control: max-age=36000 -Expires: Wed, 20 Jul 2016 20:00:35 GMT -X-Upstream-L3: 172.17.0.3:80 -X-Upstream-L2: developer-sjc-indigo-1-nginx -Strict-Transport-Security: max-age=31536000; includeSubdomains - -Hello world! -``` - -## Debugging the TLS connection - -To print out more debug information about the TLS connection, edit the file `main.cpp` and change the definition of `DEBUG_LEVEL` (near the top of the file) from 0 to a positive number: - -* Level 1 only prints non-zero return codes from SSL functions and information about the full certificate chain being verified. - -* Level 2 prints more information about internal state updates. - -* Level 3 is intermediate. - -* Level 4 (the maximum) includes full binary dumps of the packets. - - -The TLS connection can fail with an error similar to: - - mbedtls_ssl_write() failed: -0x2700 (-9984): X509 - Certificate verification failed, e.g. CRL, CA or signature check failed - Failed to fetch /media/uploads/mbed_official/hello.txt from developer.mbed.org:443 - -This probably means you need to update the contents of the `SSL_CA_PEM` constant (this can happen if you modify `HTTPS_SERVER_NAME`, or when `developer.mbed.org` switches to a new CA when updating its certificate). - -Another possible reason for this error is a proxy providing a different certificate. Proxies can be used in some network configurations or for performing man-in-the-middle attacks. If you choose to ignore this error and proceed with the connection anyway, you can change the definition of `UNSAFE` near the top of the file from 0 to 1. - -**Warning:** this removes all security against a possible active attacker, so use at your own risk or for debugging only! - +TODO \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WNCInterface.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,192 @@
+/* =====================================================================
+ Copyright © 2016, Avnet (R)
+
+ Contributors:
+ * James M Flynn, www.em.avnet.com
+
+ 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 WNCInterface.cpp
+ @version 1.0
+ @date Sept 2016
+ @author James Flynn
+
+======================================================================== */
+
+
+#ifndef __MODULE__
+#define __MODULE__ "WNCInterface.cpp"
+#endif
+
+#include "WNCInterface.h"
+
+/////////////////////////////////////////////////////
+// NXP GPIO Pins that are used to initialize the WNC Shield
+/////////////////////////////////////////////////////
+DigitalOut mdm_uart2_rx_boot_mode_sel(PTC17); // on powerup, 0 = boot mode, 1 = normal boot
+DigitalOut mdm_power_on(PTB9); // 0 = turn modem on, 1 = turn modem off (should be held high for >5 seconds to cycle modem)
+DigitalOut mdm_wakeup_in(PTC2); // 0 = let modem sleep, 1 = keep modem awake -- Note: pulled high on shield
+DigitalOut mdm_reset(PTC12); // active high
+DigitalOut shield_3v3_1v8_sig_trans_ena(PTC4); // 0 = disabled (all signals high impedence, 1 = translation active
+DigitalOut mdm_uart1_cts(PTD0);
+
+char * _fatal_err_loc; //GLOBAL::holds any error location info
+MODSERIAL * _dbgout;
+Mutex _WNCLock;
+
+using namespace WncControllerK64F_fk; // namespace for the controller class use
+
+// Define pin associations for the controller class to use be careful to
+// keep the order of the pins in the initialization list.
+WncGpioPinListK64F wncPinList = {
+ &mdm_uart2_rx_boot_mode_sel,
+ &mdm_power_on,
+ &mdm_wakeup_in,
+ &mdm_reset,
+ &shield_3v3_1v8_sig_trans_ena,
+ &mdm_uart1_cts
+};
+
+static MODSERIAL mdmUart(PTD3,PTD2,256,4096); //UART for WNC Module
+
+WncControllerK64F *WNCInterface::_pwnc;
+WncIpStats WNCInterface::myNetStats;
+string WNCInterface::mac;
+
+WNCInterface::WNCInterface() {
+ _dbgout = NULL;
+}
+
+void WNCInterface::doDebug( int v ) {
+ //basic debug = 0x01
+ //more debug = 0x02
+ //all debug = 0x03
+ M_LOCK;
+ _pwnc->enableDebug( (v&1), (v&2) );
+ M_ULOCK;
+}
+
+//
+// Power-up the WNC module. The caller can optionally configure.
+// Inputs:
+// apn - Caller can specify an APN. If none is provided will use "m2m.com.attz"
+// debug- specify the amount of debug the WNC controller should output:
+// 1 - Basic Debug output
+// 2 - Verbose Debug output
+// 3 - Full Debug output
+// Returns: 0 if unable to initialize the WNC module
+// -1 if successfully initialized
+//
+int WNCInterface::init(const char* apn, MODSERIAL * debug) {
+ int ret = 0;
+
+ M_LOCK;
+ if( debug ) {
+ _dbgout = debug;
+ _pwnc = new WncControllerK64F_fk::WncControllerK64F::WncControllerK64F(&wncPinList, &mdmUart, debug);
+#if WNC_DEBUG == 1
+ _pwnc->enableDebug(1,1);
+#endif
+ }
+ else
+ _pwnc = new WncControllerK64F_fk::WncControllerK64F::WncControllerK64F(&wncPinList, &mdmUart, NULL);
+
+ if( apn==NULL )
+ apn = APN_DEFAULT;
+
+ ret = ( _pwnc->powerWncOn(apn,40) )? 2:0;
+ ret |= ( _pwnc->setApnName(apn) )? 1:0;
+ ret |= ( _pwnc->getWncNetworkingStats(&myNetStats) )? 4:0;
+ M_ULOCK;
+
+ return ret;
+}
+
+//
+// check to see if we are connected to the internet or not. The
+// connection is supposed to happen during init. If we are
+// connected to the internet return 0 otherwise return -1
+//
+int WNCInterface::connect(void) {
+ return ( _pwnc->getWncStatus() == WNC_GOOD )? 0 : -1;
+}
+
+//
+// ok, the user wants to disconnect. At present, this isn't possible
+// with the WNC, so just fake it and say we did...
+//
+int WNCInterface::disconnect() {
+ return 0;
+}
+
+//
+// update the networking stats and return the IP Address
+//
+char * WNCInterface::getIPAddress() {
+ M_LOCK;
+ if ( _pwnc->getWncNetworkingStats(&myNetStats) ) {
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), null);
+ M_ULOCK;
+ return &myNetStats.ip[0];
+ }
+ M_ULOCK;
+ return NULL;
+}
+
+//
+// update the networking stats and return the Gateway Address
+//
+char * WNCInterface::getGateway() {
+ M_LOCK;
+ if ( _pwnc->getWncNetworkingStats(&myNetStats) ) {
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), null);
+ M_ULOCK;
+ return &WNCInterface::myNetStats.gateway[0];
+ }
+ M_ULOCK;
+ return NULL;
+}
+
+//
+// update the networking stats and return the Network Mask
+//
+char * WNCInterface::getNetworkMask() {
+ M_LOCK;
+ if ( _pwnc->getWncNetworkingStats(&myNetStats) ) {
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), null);
+ M_ULOCK;
+ return &WNCInterface::myNetStats.mask[0];
+ }
+ M_ULOCK;
+ return NULL;
+}
+
+//
+// return a pesudo-MAC address created from the ICCID
+//
+char* WNCInterface::getMACAddress( void ) {
+ string str;
+
+ M_LOCK;
+ if( _pwnc->getICCID(&str) ) {
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), null);
+ mac = str.substr(3,20);
+ mac[2]=mac[5]=mac[8]=mac[11]=mac[14]=':';
+ M_ULOCK;
+ return (char*)mac.c_str();
+ }
+ M_ULOCK;
+ return NULL;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WNCInterface.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,162 @@
+/* =====================================================================
+ Copyright © 2016, Avnet (R)
+
+ Contributors:
+ * James Flynn, www.em.avnet.com
+
+ 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 WNCInterface.h
+ @version 1.0
+ @date Sept 2016
+
+======================================================================== */
+
+
+#include <stddef.h>
+#include "WncControllerK64F/WncControllerK64F.h"
+#include "WncControllerK64F/WncController/WncController.h"
+#include <Mutex.h>
+
+#ifndef _WNCINTERFACE_H_
+#define _WNCINTERFACE_H_
+
+#define WNC_DEBUG 0 //1=enable the WNC startup debug output
+ //0=disable the WNC startup debug output
+#define STOP_ON_FE 1 //1=hang forever if a fatal error occurs
+ //0=simply return failed response for all socket calls
+#define DISPLAY_FE 1 //1 to display the fatal error when it occurs
+ //0 to NOT display the fatal error
+#define RESETON_FE 0 //1 to cause the MCU to reset on fatal error
+ //0 to NOT reset the MCU
+#define APN_DEFAULT "m2m.com.attz"
+
+//
+// WNC Error Handling macros & data
+//
+#define FATAL_FLAG WncController_fk::WncController::WNC_NO_RESPONSE
+#define WNC_GOOD WncController_fk::WncController::WNC_ON
+
+#define RETfail return -1
+#define RETvoid return
+#define RETnull return NULL
+#define RETresume
+
+#define DORET(x) RET##x
+
+#define TOSTR(x) #x
+#define INTSTR(x) TOSTR(x)
+#define FATAL_STR __FILE__ ":" INTSTR(__LINE__)
+
+
+#if RESETON_FE == 1
+#define MCURESET ((*((volatile unsigned long *)0xE000ED0CU))=(unsigned long)((0x5fa<<16) | 0x04L))
+#define RSTMSG "RESET MCU! "
+#else
+#define MCURESET
+#define RSTMSG ""
+#endif
+
+#if DISPLAY_FE == 1
+#define PFE {extern MODSERIAL *_dbgout;if(_dbgout)_dbgout->printf(RSTMSG "\r\n>>WNC FAILED @ %s\r\n", FATAL_STR);}
+#else
+#define PFE
+#endif
+
+#if STOP_ON_FE == 1
+#define FATAL_WNC_ERROR(v) {extern char *_fatal_err_loc;_fatal_err_loc=FATAL_STR;PFE;MCURESET;while(1);}
+#else
+#define FATAL_WNC_ERROR(v) {extern char *_fatal_err_loc;_fatal_err_loc=FATAL_STR;PFE;DORET(v);}
+#endif
+
+#define M_LOCK {extern Mutex _WNCLock; _WNCLock.lock();}
+#define M_ULOCK {extern Mutex _WNCLock; _WNCLock.unlock();}
+#define CHK_WNCFE(x,y) if( x ){M_ULOCK; FATAL_WNC_ERROR(y);}
+
+// Because the WncController has intermixed socket & interface functionallity
+// will need to make the Socket class a friend of the Interface class. This
+// will allow the Socket class to get to the WNC functions needed for the
+// socket. Forward reference the class
+
+class Socket;
+class Endpoint;
+class UDPSocket;
+class TCPSocketConnection;
+class WNCSms;
+
+class WNCInterface
+{
+ class WncControllerK64F; //forward reference the Controller Class
+ friend class TCPSocketConnection;
+ friend class UDPSocket;
+ friend class Endpoint;
+ friend class Socket;
+ friend class WNCSms;
+
+public:
+ /** Create WNC Data Module Interface Instance for the device (M14A2A) */
+ WNCInterface();
+
+ /** Initialize the interface (no connection at this point).
+ * \return 0 on success, a negative number on failure
+ */
+ static int init(const char* apn=NULL, MODSERIAL * debug=NULL);
+
+ /** Open an LTE internet data connection
+ @return 0 on success, error code on failure
+ */
+ int connect(void);
+
+ /** Disconnect
+ * Bring the interface down
+ * \return 0 on success, a negative number on failure
+ */
+ static int disconnect();
+
+ /** Because the WNCInterface is cellular based there is no MAC Ethernet address to return, so this function
+ * returns a bogus MAC address created from the ICCD on the SIM that is being used.
+ * \return a pointer to a pesudo-MAC string containing "NN:NN:NN:NN:NN:NN"
+ */
+ static char* getMACAddress();
+
+ /** Get the IP address of your Ethernet interface
+ * \return a pointer to a string containing the IP address
+ */
+ static char* getIPAddress();
+
+ /** Get the Gateway address of your Ethernet interface
+ * \return a pointer to a string containing the Gateway address
+ */
+ static char* getGateway();
+
+ /** Get the Network mask of your Ethernet interface
+ * \return a pointer to a string containing the Network mask
+ */
+ static char* getNetworkMask();
+
+ /** Manipulate the debug output of the WncController, for debug purposes.
+ * \return nothing.
+ */
+ void doDebug(int val); //doing this so I can get to the wnc controller pointer
+
+
+//private:
+ static WncController_fk::WncIpStats myNetStats; //maintaint the network statistics
+ static WncControllerK64F_fk::WncControllerK64F *_pwnc; //pointer to the WncController instance
+ static string mac;
+
+};
+
+#endif /* _WNCINTERFACE_ */
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WNCSocket/WNCEndpoint.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,79 @@
+/* =====================================================================
+ Copyright © 2016, Avnet (R)
+
+ Contributors:
+ * James M Flynn, www.em.avnet.com
+
+ 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 WNCInterface.cpp
+ @version 1.0
+ @date Sept 2016
+
+======================================================================== */
+
+#include "../WNCInterface.h"
+#include "WNCSocket.h"
+#include "WNCEndpoint.h"
+
+WNCEndpoint::WNCEndpoint() {
+ reset_address();
+}
+
+WNCEndpoint::~WNCEndpoint() {}
+
+void WNCEndpoint::reset_address(void) {
+ std::memset(&_epAddr, 0, sizeof(struct EndPointAddr));
+}
+
+//
+// It is possible to call set_address with either a URL or
+// an IP address. So try each in-turn and set the end point
+// address.
+//
+
+int WNCEndpoint::set_address(const char* host, const int port) {
+ // IP Address
+ char address[5];
+ int rslt;
+
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), fail);
+
+ reset_address();
+ _epAddr.port = port; //go ahead and save the port
+
+ // Dot-decimal notation?
+ rslt = std::sscanf(host, "%3u.%3u.%3u.%3u",
+ (unsigned int*)&address[0], (unsigned int*)&address[1],
+ (unsigned int*)&address[2], (unsigned int*)&address[3]);
+
+ M_LOCK;
+ if (rslt != 4) // No, need to resolve address with DNS
+ WNCInterface::_pwnc->resolveUrl(0,host);
+ else
+ WNCInterface::_pwnc->setIpAddr(0,host);
+
+ rslt = WNCInterface::_pwnc->getIpAddr(0,_epAddr.IP);
+ M_ULOCK;
+ return rslt;
+}
+
+char* WNCEndpoint::get_address() {
+ return _epAddr.IP;
+}
+
+int WNCEndpoint::get_port() {
+ return _epAddr.port;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WNCSocket/WNCEndpoint.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,72 @@
+/* =====================================================================
+ Copyright © 2016, Avnet (R)
+
+ Contributors:
+ * James M Flynn, www.em.avnet.com
+
+ 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 WNCInterface.cpp
+ @version 1.0
+ @date Sept 2016
+
+======================================================================== */
+
+#include "WNCSocket.h"
+
+#ifndef WNCENDPOINT_H
+#define WNCENDPOINT_H
+
+struct EndPointAddr {
+ char IP[16];
+ unsigned int port;
+ };
+
+class WNCUDPSocket;
+
+class WNCEndpoint {
+ friend class WNCUDPSocket;
+
+public:
+ WNCEndpoint(void);
+ ~WNCEndpoint(void);
+
+ /** Reset the address of the endpoint by clearning the internal endpoint IP address
+ \param none
+ \return none.
+ */
+ void reset_address(void);
+
+ /** Set the address of the endpoint
+ \param host The endpoint address (it can either be an IP Address or a hostname that will be resolved with DNS).
+ \param port The endpoint port
+ \return 0 on success, -1 on failure (when an hostname cannot be resolved by DNS).
+ */
+ int set_address(const char* host, const int port);
+
+ /** Get the IP address of the endpoint
+ \return The IP address of the endpoint.
+ */
+ char* get_address(void);
+
+ /** Get the port of the endpoint
+ \return The port of the endpoint
+ */
+ int get_port(void);
+
+private:
+ EndPointAddr _epAddr;
+};
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WNCSocket/WNCSocket.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,115 @@
+/* =====================================================================
+ Copyright © 2016, Avnet (R)
+
+ Contributors:
+ * James M Flynn, www.em.avnet.com
+
+ 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 WNCInterface.cpp
+ @version 1.0
+ @date Sept 2016
+
+======================================================================== */
+#include "../WNCInterface.h"
+#include "WNCSocket.h"
+#include <cstring>
+
+class WNCInterface;
+
+//
+// Set up the defaults in the constructor. If the caller doesn't change anything
+// the APN will be set for AT&T, port #40 and timeout 1.5 seconds
+//
+WNCSocket::WNCSocket() :
+ _sock_type(-1),
+ _timeout(1500) {
+}
+
+WNCSocket::~WNCSocket() {
+}
+
+
+//
+// ensure we have a WNC Controller attached and initialized by calling to get the
+// network status, This will provide us with all the network information. if we
+// are not connected, will return -1.
+//
+int WNCSocket::init(int timeout) {
+
+ _timeout = timeout;
+ M_LOCK;
+ int ret = WNCInterface::_pwnc->getWncNetworkingStats(&WNCInterface::myNetStats)? 0:-1;
+ M_ULOCK;
+ return ret;
+}
+
+//
+// Connect this socket to a user specified URL or IP address. It could be
+// either a TCP or UDP socket. The user is also expected to provide a port #.
+// If the connection failed for any reason return 0, otherwise, return 1;
+//
+int WNCSocket::connect(char *url, int type, int port) {
+ int rslt;
+ char address[5];
+
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), fail);
+
+ // lets determine if they passed in an IP or a URL
+ rslt = std::sscanf(url, "%3u.%3u.%3u.%3u",
+ (unsigned int*)&address[0], (unsigned int*)&address[1],
+ (unsigned int*)&address[2], (unsigned int*)&address[3]);
+ M_LOCK;
+ if (rslt == 4)
+ rslt = WNCInterface::_pwnc->setIpAddr(0,url);
+ else
+ rslt = WNCInterface::_pwnc->resolveUrl(0,url);
+
+ if( rslt ) {
+ _sock_type = type; //resolved the URL indicate socket 0 is open
+ rslt = WNCInterface::_pwnc->openSocket(0, port, (_sock_type==SOCK_STREAM)? 1:0, _timeout);
+ }
+ M_ULOCK;
+ return rslt;
+}
+
+
+//
+// disconnect the currently open socket.
+// -1 if there was an error
+// 0 if we disconnected
+//
+int WNCSocket::disconnect() {
+ if( _sock_type<0 )
+ return 0; //nothing is connected currently
+
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), fail);
+ M_LOCK;
+ int ret = !WNCInterface::_pwnc->closeSocket(0);
+ M_ULOCK;
+ return ret;
+}
+
+void WNCSocket::set_blocking(bool blocking, unsigned int timeout) {
+ blocking = blocking;
+ timeout= timeout;
+
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), void);
+ M_LOCK;
+ WNCInterface::_pwnc->setReadRetryWait(0, 0);
+ WNCInterface::_pwnc->setReadRetries(0, 0);
+ M_ULOCK;
+}
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WNCSocket/WNCSocket.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,55 @@
+/* =====================================================================
+ Copyright © 2016, Avnet (R)
+
+ Contributors:
+ * James M Flynn, www.em.avnet.com
+
+ 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 WNCInterface.cpp
+ @version 1.0
+ @date Sept 2016
+
+======================================================================== */
+
+
+#include <stddef.h>
+#include "WNCInterface.h"
+
+#ifndef WNCSOCKET_H_
+#define WNCSOCKET_H_
+
+#define SOCK_STREAM 1 //A TCP Socket type
+#define SOCK_DGRAM 2 //a UDP Socket type
+
+/** Socket file descriptor and select wrapper */
+class WNCSocket {
+
+public:
+ WNCSocket();
+ ~WNCSocket();
+
+ int init(int timeout=1500);
+
+ int connect(char *url, int type, int port);
+ int disconnect();
+ void set_blocking(bool blocking, unsigned int timeout); //not used
+
+private:
+ int _sock_type; //contains the type of socket this is
+ unsigned int _timeout; //default timeout for all socket transactions
+};
+
+
+#endif /* WNCSOCKET_H_ */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WNCSocket/WNCTCPSocketConnection.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,125 @@
+/* =====================================================================
+ Copyright © 2016, Avnet (R)
+ Contributors:
+ * James M Flynn, www.em.avnet.com
+
+ 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 WNCInterface.cpp
+ @version 1.0
+ @date Sept 2016
+======================================================================== */
+
+#include "../WNCInterface.h"
+
+#include "WNCSocket.h"
+#include "WNCTCPSocketConnection.h"
+#include <cstring>
+
+#define READ_EVERYMS 500 //number of milliseconds between WNC socket reads
+
+WNCTCPSocketConnection::WNCTCPSocketConnection() :
+ _is_blocking(0),
+ _btimeout(0){
+}
+
+//
+// blocking is used to make the WNC keep checking for incoming data for a
+// period of time.
+//
+void WNCTCPSocketConnection::set_blocking (bool blocking, unsigned int timeout) {
+ _is_blocking = blocking; // true if we want to wait for request
+ _btimeout = timeout; // user specs msec
+
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), void);
+ M_LOCK;
+ WNCInterface::_pwnc->setReadRetryWait(0, 0);
+ WNCInterface::_pwnc->setReadRetries(0, 0);
+ M_ULOCK;
+}
+
+
+int WNCTCPSocketConnection::connect(const char* host, const int port) {
+ WNCSocket::connect((char*)host, SOCK_STREAM, port);
+ _is_blocking = false; // start out not blocking, user will set it if desired
+ return ( WNCInterface::_pwnc->getWncStatus() == WncController_fk::WncController::WNC_ON )? 0:-1;
+}
+
+bool WNCTCPSocketConnection::is_connected(void) {
+ return ( WNCInterface::_pwnc->getWncStatus() == WncController_fk::WncController::WNC_ON )? 1:0;
+}
+
+int WNCTCPSocketConnection::send(char* data, int length) {
+ int ret = -1;
+
+ WncController_fk::WncController::WncState_e s = WNCInterface::_pwnc->getWncStatus();
+
+ CHK_WNCFE(( s == FATAL_FLAG ), fail);
+
+ if( s == WncController_fk::WncController::WNC_ON ) {
+ M_LOCK;
+ if( WNCInterface::_pwnc->write(0, data, length) )
+ ret = length;
+ M_ULOCK;
+ }
+ return ret;
+}
+
+int WNCTCPSocketConnection::receive(char *readBuf, int length) {
+ Timer t;
+ size_t done, cnt;
+ int ret=-1;
+ WncController_fk::WncController::WncState_e s = WNCInterface::_pwnc->getWncStatus();
+
+ CHK_WNCFE(( s == FATAL_FLAG ), fail);
+ if( s != WncController_fk::WncController::WNC_ON )
+ return ret;
+
+ M_LOCK;
+ t.start();
+ do {
+ if( !(t.read_ms() % READ_EVERYMS) )
+ cnt = WNCInterface::_pwnc->read(0, (uint8_t *)readBuf, (uint32_t) length);
+ if( _is_blocking )
+ done = cnt;
+ else
+ done = cnt | (t.read_ms() > _btimeout);
+ }
+ while( !done );
+ t.stop();
+ M_ULOCK;
+
+ if( WNCInterface::_pwnc->getWncStatus() == WNC_GOOD ) {
+ //readBuf[cnt] = '\0';
+ ret = (int)cnt;
+ }
+ else
+ ret = -1;
+
+ return ret;
+}
+
+int WNCTCPSocketConnection::send_all(char* data, int length) {
+ return send(data,length);
+}
+
+int WNCTCPSocketConnection::receive_all(char* data, int length) {
+ return receive(data,length);
+}
+
+int WNCTCPSocketConnection::close(void) {
+ WNCSocket::disconnect();
+ M_LOCK;
+ int ret = ( WNCInterface::_pwnc->getWncStatus() == WncController_fk::WncController::WNC_ON )? 0:-1;
+ M_ULOCK;
+ return ret;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WNCSocket/WNCTCPSocketConnection.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,98 @@
+/* =====================================================================
+ Copyright © 2016, Avnet (R)
+
+ Contributors:
+ * James M Flynn, www.em.avnet.com
+
+ 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 WNCInterface.cpp
+ @version 1.0
+ @date Sept 2016
+
+======================================================================== */
+
+#ifndef WNCTCPSOCKET_H
+#define WNCTCPSOCKET_H
+
+#include "WNCSocket/WNCSocket.h"
+#include "WNCSocket/WNCEndpoint.h"
+
+/**
+TCP socket connection
+*/
+class WNCTCPSocketConnection : public WNCSocket, public WNCEndpoint {
+
+public:
+ WNCTCPSocketConnection();
+
+ /** Connects this TCP socket to the server
+ \param host The host to connect to. It can either be an IP Address or a hostname that will be resolved with DNS.
+ \param port The host's port to connect to.
+ \return 0 on success, -1 on failure.
+ */
+ int connect(const char* host, const int port);
+
+ /** Check if the socket is connected
+ \return true if connected, false otherwise.
+ */
+ bool is_connected(void);
+
+ /** Send data to the remote host.
+ \param data The buffer to send to the host.
+ \param length The length of the buffer to send.
+ \return the number of written bytes on success (>=0) or -1 on failure
+ */
+ int send(char* data, int length);
+
+ /** Send all the data to the remote host.
+ \param data The buffer to send to the host.
+ \param length The length of the buffer to send.
+ \return the number of written bytes on success (>=0) or -1 on failure
+ */
+ int send_all(char* data, int length);
+
+ /** Receive data from the remote host.
+ \param data The buffer in which to store the data received from the host.
+ \param length The maximum length of the buffer.
+ \return the number of received bytes on success (>=0) or -1 on failure
+ */
+ int receive(char* data, int length);
+
+ /** Receive all the data from the remote host.
+ \param data The buffer in which to store the data received from the host.
+ \param length The maximum length of the buffer.
+ \return the number of received bytes on success (>=0) or -1 on failure
+ */
+ int receive_all(char* data, int length);
+
+ /** Set blocking or non-blocking mode of the socket and a timeout
+ \param blocking true for blocking mode, false for non-blocking mode.
+ \return none
+ */
+ void set_blocking (bool blocking, unsigned int timeout=1500);
+
+ /** Close the socket
+ \param none
+ \return 0 if closed successfully, -1 on failure
+ */
+ int close(void);
+
+private:
+ bool _is_blocking;
+ unsigned int _btimeout;
+
+};
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WNCSocket/WNCUDPSocket.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,106 @@
+/* =====================================================================
+ Copyright © 2016, Avnet (R)
+
+ Contributors:
+ * James M Flynn, www.em.avnet.com
+
+ 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 WNCInterface.cpp
+ @version 1.0
+ @date Sept 2016
+
+======================================================================== */
+
+#include "../WNCInterface.h"
+
+#include "WNCUDPSocket.h"
+#include <cstring>
+
+WNCUDPSocket::WNCUDPSocket() :
+ _is_blocking(0),
+ _btimeout(0){
+}
+
+WNCUDPSocket::~WNCUDPSocket() {
+}
+
+int WNCUDPSocket::init(void) {
+ _is_blocking = false; // start out not blocking, user will set it if desired
+ return ( WNCInterface::_pwnc->getWncStatus() == WNC_GOOD )? 0:-1;
+}
+
+
+int WNCUDPSocket::close(void) {
+ WNCSocket::disconnect();
+ return ( WNCInterface::_pwnc->getWncStatus() == WNC_GOOD )? 0:-1;
+}
+
+// -1 if unsuccessful, else number of bytes written
+int WNCUDPSocket::sendTo(WNCEndpoint &remote, char *packet, int length) {
+ int ret = -1;
+
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), fail);
+ if( remote._epAddr.port ) { //make sure the WNCEndpoint has an port assoicated with it
+ if( WNCSocket::connect(remote._epAddr.IP,SOCK_DGRAM,remote._epAddr.port) ) {
+ if( WNCInterface::_pwnc->write(0,packet,length) )
+ ret = length;
+ close();
+ }
+ }
+ return ret;
+}
+
+//
+// blocking is used to make the WNC keep checking for incoming data for a
+// period of time.
+
+void WNCUDPSocket::set_blocking (bool blocking, unsigned int timeout) {
+ _is_blocking = blocking; // true or false
+ _btimeout = timeout; // user specifies in msec
+
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), void);
+ WNCInterface::_pwnc->setReadRetryWait(0, 0);
+ WNCInterface::_pwnc->setReadRetries(0, 0);
+}
+
+// -1 if unsuccessful, else number of bytes received
+int WNCUDPSocket::receiveFrom(WNCEndpoint &remote, char *buffer, int length) {
+ const uint8_t *ptr;
+ Timer t;
+ int done, ret = -1;
+
+ //make sure the WNCEndpoint has an port assoicated with it
+ if( !remote._epAddr.port )
+ return -1;
+
+ CHK_WNCFE(( WNCInterface::_pwnc->getWncStatus() == FATAL_FLAG ), fail);
+ ret = WNCSocket::connect(remote._epAddr.IP,SOCK_DGRAM,remote._epAddr.port);
+
+ t.start();
+ do {
+ ret = WNCInterface::_pwnc->read(0, &ptr);
+ done = ret | (t.read_ms() > _btimeout);
+ }
+ while( _is_blocking && !done );
+ t.stop();
+
+ if( ret > length )
+ ret = length;
+ memcpy( buffer, ptr, ret );
+
+ return ret;
+}
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WNCSocket/WNCUDPSocket.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,78 @@
+/* =====================================================================
+ Copyright © 2016, Avnet (R)
+
+ Contributors:
+ * James M Flynn, www.em.avnet.com
+
+ 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 WNCInterface.cpp
+ @version 1.0
+ @date Sept 2016
+
+======================================================================== */
+
+
+#ifndef WNCUDPSOCKET_H
+#define WNCUDPSOCKET_H
+
+#include "WNCSocket.h"
+#include "WNCEndpoint.h"
+
+/**
+UDP WNCSocket
+*/
+class WNCUDPSocket : public WNCSocket, public WNCInterface {
+
+public:
+ WNCUDPSocket();
+ ~WNCUDPSocket();
+
+ int init(void);
+
+ /** sendTo - send data to the remote host.
+ \param remote, a pointer to the endpoint (class)
+ \param packet, pointer to the buffer to send to the host.
+ \param length The length of the buffer to send.
+ \return the number of written bytes on success (>=0) or -1 on failure
+ */
+ int sendTo(WNCEndpoint &remote, char *packet, int length);
+
+ /** receiveFrom - receive data from the remote host.
+ \param remote, a pointer to the endpoint (class)
+ \param packet, The buffer in which to store the data received from the host.
+ \param length The maximum length of the buffer.
+ \return the number of received bytes on success (>=0) or -1 on failure
+ */
+ int receiveFrom(WNCEndpoint &remote, char *buffer, int length);
+
+ /** Set blocking or non-blocking mode of the socket and a timeout
+ \param blocking true for blocking mode, false for non-blocking mode.
+ \return none.
+ */
+ void set_blocking (bool blocking, unsigned int timeout=1500);
+
+ /** Close the socket
+ \param none
+ \return 0 if closed successfully, -1 on failure
+ */
+ int close(void);
+
+private:
+ bool _is_blocking;
+ unsigned int _btimeout;
+};
+
+#endif
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/AddingDevice.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,34 @@ +/* + +To add another device some functions/macros need to be defined. +The Device folder shows examples of other devices. + +1. In MACROS.h the include to the macro file need to be added. + +2. A <NameOfYourFile.h> file needs to be added, it needs to include the ifdef(target) statement, and definitions for: +MODSERIAL_IRQ_REG --- register which enables/disables serial IRQs +DISABLE_TX_IRQ --- macro that disables TX IRQs +DISABLE_RX_IRQ --- macro that disables RX IRQs +ENABLE_TX_IRQ --- macro that enables TX IRQs +ENABLE_RX_IRQ --- macro that enables RX IRQs + +RESET_TX_FIFO --- macro that resets TX FIFO buffer, if applicable. If not, something like while(1==0) won't do anything and doesn't generate compiler warnings +RESET_RX_FIFO --- macro that resets RX FIFO buffer, if no hardware options, you can also read data until no more data is available + +MODSERIAL_READ_REG --- register where RX data is in +MODSERIAL_WRITE_REG --- register where TX data is in (can be same as previous) +MODSERIAL_READABLE --- returns true if new data is available in read_reg +MODSERIAL_WRITABLE --- returns true if we may write new data in write_reg + +RX_IRQ_ENABLED --- checks if RX IRQs are enabled by MODSERIAL. Only required if the device has no registers that tell which IRQ fired. If those registers are available (LPCs have then), may just be 'true' +TX_IRQ_ENABLED --- checks if TX IRQs are enabled by MODSERIAL. See previous + +3. A <NameOfYourFile.cpp> file needs to be added, it needs to include the ifdef(target) statement, and functions for: +void setBase(void) --- function that sets _base pointer to point to correct UART, and _IRQ pointer to point to correct IRQ. + +void initDevice(void)--- function that allows for setting registers after everything else is initialized, if required + +bool txIsBusy(void) --- function that returns true as long as long as device isn't done with transmitting + +*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_KL05Z.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,17 @@
+#ifdef TARGET_KL05Z
+#include "MODSERIAL.h"
+
+void MODSERIAL::setBase(void ) {
+ _base = UART0;
+ _IRQ = UART0_IRQn;
+}
+
+void MODSERIAL::initDevice(void) {};
+
+bool MODSERIAL::txIsBusy( void )
+{
+ return ( ((UARTLP_Type*)_base)->S1 & ( 1UL << 6 ) == 0 ) ? true : false;
+}
+#endif
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_KL05Z.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,20 @@ +#if defined(TARGET_KL05Z) + +#define MODSERIAL_IRQ_REG ((UARTLP_Type*)_base)->C2 +#define DISABLE_TX_IRQ MODSERIAL_IRQ_REG &= ~(1UL << UARTLP_C2_TIE_SHIFT) +#define DISABLE_RX_IRQ MODSERIAL_IRQ_REG &= ~(1UL << UARTLP_C2_RIE_SHIFT) +#define ENABLE_TX_IRQ MODSERIAL_IRQ_REG |= (1UL << UARTLP_C2_TIE_SHIFT) +#define ENABLE_RX_IRQ MODSERIAL_IRQ_REG |= (1UL << UARTLP_C2_RIE_SHIFT) + +#define MODSERIAL_READ_REG ((UARTLP_Type*)_base)->D +#define MODSERIAL_WRITE_REG ((UARTLP_Type*)_base)->D +#define MODSERIAL_READABLE ((((UARTLP_Type*)_base)->S1 & (1UL<<5)) != 0) +#define MODSERIAL_WRITABLE ((((UARTLP_Type*)_base)->S1 & (1UL<<7)) != 0) + +#define RESET_TX_FIFO while(0 == 1) +#define RESET_RX_FIFO while(MODSERIAL_READABLE) char dummy = MODSERIAL_READ_REG + +#define RX_IRQ_ENABLED ((MODSERIAL_IRQ_REG & (1UL << UARTLP_C2_RIE_SHIFT)) != 0 ) +#define TX_IRQ_ENABLED ((MODSERIAL_IRQ_REG & (1UL << UARTLP_C2_TIE_SHIFT)) != 0 ) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_KL25Z.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,21 @@
+#ifdef TARGET_KL25Z
+#include "MODSERIAL.h"
+
+void MODSERIAL::setBase(void ) {
+switch( _serial.index ) {
+ case 0: _base = UART0; _IRQ = UART0_IRQn; break;
+ case 1: _base = UART1; _IRQ = UART1_IRQn; break;
+ case 2: _base = UART2; _IRQ = UART2_IRQn; break;
+ default: _base = NULL; _IRQ = (IRQn_Type)NULL; break;
+ }
+}
+
+void MODSERIAL::initDevice(void) {};
+
+bool MODSERIAL::txIsBusy( void )
+{
+ return ( ((UART_Type*)_base)->S1 & ( 1UL << 6 ) == 0 ) ? true : false;
+}
+#endif
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_KL25Z.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,20 @@ +#if defined(TARGET_KL25Z) + +#define MODSERIAL_IRQ_REG ((UART_Type*)_base)->C2 +#define DISABLE_TX_IRQ MODSERIAL_IRQ_REG &= ~(1UL << UART_C2_TIE_SHIFT) +#define DISABLE_RX_IRQ MODSERIAL_IRQ_REG &= ~(1UL << UART_C2_RIE_SHIFT) +#define ENABLE_TX_IRQ MODSERIAL_IRQ_REG |= (1UL << UART_C2_TIE_SHIFT) +#define ENABLE_RX_IRQ MODSERIAL_IRQ_REG |= (1UL << UART_C2_RIE_SHIFT) + +#define MODSERIAL_READ_REG ((UART_Type*)_base)->D +#define MODSERIAL_WRITE_REG ((UART_Type*)_base)->D +#define MODSERIAL_READABLE ((((UART_Type*)_base)->S1 & (1UL<<5)) != 0) +#define MODSERIAL_WRITABLE ((((UART_Type*)_base)->S1 & (1UL<<7)) != 0) + +#define RESET_TX_FIFO while(0 == 1) +#define RESET_RX_FIFO while(MODSERIAL_READABLE) char dummy = MODSERIAL_READ_REG + +#define RX_IRQ_ENABLED ((MODSERIAL_IRQ_REG & (1UL << UART_C2_RIE_SHIFT)) != 0 ) +#define TX_IRQ_ENABLED ((MODSERIAL_IRQ_REG & (1UL << UART_C2_TIE_SHIFT)) != 0 ) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_KSDK.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,23 @@
+#ifdef TARGET_KPSDK_MCUS
+#include "MODSERIAL.h"
+
+void MODSERIAL::setBase(void ) {
+switch( _serial.index ) {
+ case 0: _base = UART0; _IRQ = UART0_RX_TX_IRQn; break;
+ case 1: _base = UART1; _IRQ = UART1_RX_TX_IRQn; break;
+ case 2: _base = UART2; _IRQ = UART2_RX_TX_IRQn; break;
+ #ifdef TARGET_K64F
+ case 3: _base = UART3; _IRQ = UART3_RX_TX_IRQn; break;
+ case 4: _base = UART4; _IRQ = UART4_RX_TX_IRQn; break;
+ #endif
+ default: _base = NULL; _IRQ = (IRQn_Type)NULL; break;
+ }
+}
+
+void MODSERIAL::initDevice(void) {};
+
+bool MODSERIAL::txIsBusy( void )
+{
+ return ( ((UART_Type*)_base)->S1 & ( 1UL << 6 ) == 0 ) ? true : false;
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_KSDK.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,20 @@ +#if defined (TARGET_KPSDK_MCUS) + +#define MODSERIAL_IRQ_REG ((UART_Type*)_base)->C2 +#define DISABLE_TX_IRQ MODSERIAL_IRQ_REG &= ~(1UL << UART_C2_TIE_SHIFT) +#define DISABLE_RX_IRQ MODSERIAL_IRQ_REG &= ~(1UL << UART_C2_RIE_SHIFT) +#define ENABLE_TX_IRQ MODSERIAL_IRQ_REG |= (1UL << UART_C2_TIE_SHIFT) +#define ENABLE_RX_IRQ MODSERIAL_IRQ_REG |= (1UL << UART_C2_RIE_SHIFT) + +#define MODSERIAL_READ_REG ((UART_Type*)_base)->D +#define MODSERIAL_WRITE_REG ((UART_Type*)_base)->D +#define MODSERIAL_READABLE ((((UART_Type*)_base)->S1 & (1UL<<5)) != 0) +#define MODSERIAL_WRITABLE ((((UART_Type*)_base)->S1 & (1UL<<7)) != 0) + +#define RESET_TX_FIFO while(0 == 1) +#define RESET_RX_FIFO while(MODSERIAL_READABLE) char dummy = MODSERIAL_READ_REG + +#define RX_IRQ_ENABLED ((MODSERIAL_IRQ_REG & (1UL << UART_C2_RIE_SHIFT)) != 0 ) +#define TX_IRQ_ENABLED ((MODSERIAL_IRQ_REG & (1UL << UART_C2_TIE_SHIFT)) != 0 ) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_LPC11U24.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,18 @@
+#ifdef TARGET_LPC11U24
+#include "MODSERIAL.h"
+
+void MODSERIAL::setBase(void ) {
+ _base = LPC_USART;
+ _IRQ = UART_IRQn;
+}
+
+void MODSERIAL::initDevice(void) {
+ ((LPC_USART_Type*)_base)->FCR = (1UL<<0) + (1UL<<1) + (1UL<<2);
+ }
+
+bool MODSERIAL::txIsBusy( void )
+{
+ return ( (((LPC_USART_Type*)_base)->LSR & ( 1UL << 6 )) == 0 ) ? true : false;
+}
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_LPC11U24.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,20 @@ +#if defined(TARGET_LPC11U24) + +#define MODSERIAL_IRQ_REG ((LPC_USART_Type*)_base)->IER +#define DISABLE_TX_IRQ MODSERIAL_IRQ_REG &= ~(1UL << 1) +#define DISABLE_RX_IRQ MODSERIAL_IRQ_REG &= ~(1UL << 0) +#define ENABLE_TX_IRQ MODSERIAL_IRQ_REG |= (1UL << 1) +#define ENABLE_RX_IRQ MODSERIAL_IRQ_REG |= (1UL << 0) + +#define RESET_TX_FIFO ((LPC_USART_Type*)_base)->FCR |= (1UL<<2) +#define RESET_RX_FIFO ((LPC_USART_Type*)_base)->FCR |= (1UL<<1) + +#define MODSERIAL_READ_REG ((LPC_USART_Type*)_base)->RBR +#define MODSERIAL_WRITE_REG ((LPC_USART_Type*)_base)->THR +#define MODSERIAL_READABLE ((((LPC_USART_Type*)_base)->LSR & (1UL<<0)) != 0) +#define MODSERIAL_WRITABLE ((((LPC_USART_Type*)_base)->LSR & (1UL<<5)) != 0) + +#define RX_IRQ_ENABLED true +#define TX_IRQ_ENABLED true + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_LPC1768.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,25 @@
+#ifdef TARGET_LPC1768
+#include "MODSERIAL.h"
+
+
+void MODSERIAL::setBase(void ) {
+switch( _serial.index ) {
+ case 0: _base = LPC_UART0; _IRQ = UART0_IRQn; break;
+ case 1: _base = LPC_UART1; _IRQ = UART1_IRQn; break;
+ case 2: _base = LPC_UART2; _IRQ = UART2_IRQn; break;
+ case 3: _base = LPC_UART3; _IRQ = UART3_IRQn; break;
+ default: _base = NULL; _IRQ = (IRQn_Type)NULL; break;
+ }
+}
+
+void MODSERIAL::initDevice(void) {
+ ((LPC_UART_TypeDef*)_base)->FCR = (1UL<<0) + (1UL<<1) + (1UL<<2);
+ }
+
+bool MODSERIAL::txIsBusy( void )
+{
+ return ( (((LPC_UART_TypeDef*)_base)->LSR & ( 1UL << 6 )) == 0 ) ? true : false;
+}
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_LPC1768.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,20 @@ +#if defined(TARGET_LPC1768) + +#define MODSERIAL_IRQ_REG ((LPC_UART_TypeDef*)_base)->IER +#define DISABLE_TX_IRQ MODSERIAL_IRQ_REG &= ~(1UL << 1) +#define DISABLE_RX_IRQ MODSERIAL_IRQ_REG &= ~(1UL << 0) +#define ENABLE_TX_IRQ MODSERIAL_IRQ_REG |= (1UL << 1) +#define ENABLE_RX_IRQ MODSERIAL_IRQ_REG |= (1UL << 0) + +#define RESET_TX_FIFO ((LPC_UART_TypeDef*)_base)->FCR |= (1UL<<2) +#define RESET_RX_FIFO ((LPC_UART_TypeDef*)_base)->FCR |= (1UL<<1) + +#define MODSERIAL_READ_REG ((LPC_UART_TypeDef*)_base)->RBR +#define MODSERIAL_WRITE_REG ((LPC_UART_TypeDef*)_base)->THR +#define MODSERIAL_READABLE ((((LPC_UART_TypeDef*)_base)->LSR & (1UL<<0)) != 0) +#define MODSERIAL_WRITABLE ((((LPC_UART_TypeDef*)_base)->LSR & (1UL<<5)) != 0) + +#define RX_IRQ_ENABLED true +#define TX_IRQ_ENABLED true + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_NUCLEO_F401RE.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,20 @@
+#ifdef TARGET_NUCLEO_F401RE
+#include "MODSERIAL.h"
+
+void MODSERIAL::setBase(void ) {
+switch( _serial.index ) {
+ case 0: _base = USART1; _IRQ = USART1_IRQn; break;
+ case 1: _base = USART2; _IRQ = USART2_IRQn; break;
+ case 2: _base = USART6; _IRQ = USART6_IRQn; break;
+ default: _base = NULL; _IRQ = (IRQn_Type)NULL; break;
+ }
+}
+
+void MODSERIAL::initDevice(void) {};
+
+bool MODSERIAL::txIsBusy( void )
+{
+ return ( (((USART_TypeDef*)_base)->SR & ( 1UL << 6 )) == 0 ) ? true : false;
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_NUCLEO_F401RE.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,20 @@ +#if defined(TARGET_NUCLEO_F401RE) + +#define MODSERIAL_IRQ_REG ((USART_TypeDef*)_base)->CR1 +#define DISABLE_TX_IRQ MODSERIAL_IRQ_REG &= ~USART_CR1_TXEIE +#define DISABLE_RX_IRQ MODSERIAL_IRQ_REG &= ~USART_CR1_RXNEIE +#define ENABLE_TX_IRQ MODSERIAL_IRQ_REG |= USART_CR1_TXEIE +#define ENABLE_RX_IRQ MODSERIAL_IRQ_REG |= USART_CR1_RXNEIE + +#define MODSERIAL_READ_REG ((USART_TypeDef*)_base)->DR +#define MODSERIAL_WRITE_REG ((USART_TypeDef*)_base)->DR +#define MODSERIAL_READABLE ((((USART_TypeDef*)_base)->SR & USART_SR_RXNE) != 0) +#define MODSERIAL_WRITABLE ((((USART_TypeDef*)_base)->SR & USART_SR_TXE) != 0) + +#define RESET_TX_FIFO while(0 == 1) +#define RESET_RX_FIFO while(MODSERIAL_READABLE) char dummy = MODSERIAL_READ_REG + +#define RX_IRQ_ENABLED ((MODSERIAL_IRQ_REG & USART_CR1_RXNEIE) != 0) +#define TX_IRQ_ENABLED ((MODSERIAL_IRQ_REG & USART_CR1_TXEIE) != 0) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_PAC_F401RB.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,21 @@
+#ifdef TARGET_PAC_F401RB
+#include "MODSERIAL.h"
+
+void MODSERIAL::setBase(void ) {
+switch( _serial.index ) {
+ case 0: _base = USART1; _IRQ = USART1_IRQn; break;
+ case 1: _base = USART2; _IRQ = USART2_IRQn; break;
+ case 2: _base = USART6; _IRQ = USART6_IRQn; break;
+ default: _base = NULL; _IRQ = (IRQn_Type)NULL; break;
+ }
+}
+
+void MODSERIAL::initDevice(void) {};
+
+bool MODSERIAL::txIsBusy( void )
+{
+ return ( (((USART_TypeDef*)_base)->SR & ( 1UL << 6 )) == 0 ) ? true : false;
+}
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WNCInterface/WncControllerK64F/MODSERIAL/Device/MODSERIAL_PAC_F401RB.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,21 @@ +#if defined(TARGET_PAC_F401RB) + +#define MODSERIAL_IRQ_REG ((USART_TypeDef*)_base)->CR1 +#define DISABLE_TX_IRQ MODSERIAL_IRQ_REG &= ~USART_CR1_TXEIE +#define DISABLE_RX_IRQ MODSERIAL_IRQ_REG &= ~USART_CR1_RXNEIE +#define ENABLE_TX_IRQ MODSERIAL_IRQ_REG |= USART_CR1_TXEIE +#define ENABLE_RX_IRQ MODSERIAL_IRQ_REG |= USART_CR1_RXNEIE + +#define MODSERIAL_READ_REG ((USART_TypeDef*)_base)->DR +#define MODSERIAL_WRITE_REG ((USART_TypeDef*)_base)->DR +#define MODSERIAL_READABLE ((((USART_TypeDef*)_base)->SR & USART_SR_RXNE) != 0) +#define MODSERIAL_WRITABLE ((((USART_TypeDef*)_base)->SR & USART_SR_TXE) != 0) + +#define RESET_TX_FIFO while(0 == 1) +#define RESET_RX_FIFO while(MODSERIAL_READABLE) char dummy = MODSERIAL_READ_REG + +#define RX_IRQ_ENABLED ((MODSERIAL_IRQ_REG & USART_CR1_RXNEIE) != 0) +#define TX_IRQ_ENABLED ((MODSERIAL_IRQ_REG & USART_CR1_TXEIE) != 0) + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/FLUSH.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,48 @@
+/*
+ Copyright (c) 2010 Andy Kirkham
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+void
+MODSERIAL::flushBuffer(IrqType type)
+{
+ uint32_t irq_req = MODSERIAL_IRQ_REG;
+ switch(type) {
+ case TxIrq: DISABLE_TX_IRQ; break;
+ case RxIrq: DISABLE_RX_IRQ; break;
+ }
+ buffer_in[type] = 0;
+ buffer_out[type] = 0;
+ buffer_count[type] = 0;
+ buffer_overflow[type] = 0;
+ switch(type) {
+ case TxIrq: RESET_TX_FIFO; break;
+ case RxIrq: RESET_RX_FIFO; break;
+ }
+ MODSERIAL_IRQ_REG = irq_req;
+}
+
+}; // namespace AjK ends
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/GETC.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,66 @@
+/*
+ Copyright (c) 2010 Andy Kirkham
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+int
+MODSERIAL::__getc(bool block)
+{
+ // If no buffer is in use fall back to standard RX FIFO usage.
+ // Note, we must block in this case and ignore bool "block"
+ // so as to maintain compat with Mbed Serial.
+ if (buffer_size[RxIrq] == 0 || buffer[RxIrq] == (char *)NULL) {
+ while(! MODSERIAL_READABLE ) ;
+ return (int)(MODSERIAL_READ_REG & 0xFF);
+ }
+
+ if (block) { while ( MODSERIAL_RX_BUFFER_EMPTY ) ; } // Blocks.
+ else if ( MODSERIAL_RX_BUFFER_EMPTY ) return -1;
+
+ int c = buffer[RxIrq][buffer_out[RxIrq]];
+ buffer_out[RxIrq]++;
+ if (buffer_out[RxIrq] >= buffer_size[RxIrq]) {
+ buffer_out[RxIrq] = 0;
+ }
+
+ // If we have made space in the RX Buffer then copy over
+ // any characters in the RX FIFO that my reside there.
+ // Temporarily disable the RX IRQ so that we do not re-enter
+ // it under interrupts.
+ if ( ! MODSERIAL_RX_BUFFER_FULL ) {
+ uint32_t irq_reg = MODSERIAL_IRQ_REG;
+ DISABLE_RX_IRQ;
+ isr_rx();
+ MODSERIAL_IRQ_REG = irq_reg;
+ }
+
+ __disable_irq();
+ buffer_count[RxIrq]--;
+ __enable_irq();
+ return c;
+}
+
+}; // namespace AjK ends
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/INIT.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ Copyright (c) 2010 Andy Kirkham
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "MODSERIAL.h"
+#include "MACROS.h"
+
+ #define MODSERIAL_FCR 0x08
+ #define _FCR *((char *)_base+MODSERIAL_FCR)
+
+ #define MODSERIAL_FIFO_ENABLE 1
+#define MODSERIAL_FIFO_RX_RESET 2
+#define MODSERIAL_FIFO_TX_RESET 4
+
+
+namespace AjK {
+
+void
+MODSERIAL::init( int txSize, int rxSize, PinName rx )
+{
+
+ NVIC_DisableIRQ(_IRQ);
+ setBase();
+
+ callbackInfo.setSerial(this);
+
+
+ if ( _base != NULL ) {
+ buffer_size[RxIrq] = rxSize;
+ buffer[RxIrq] = rxSize > 0 ? (char *)malloc(buffer_size[RxIrq]) : (char *)NULL;
+ buffer_in[RxIrq] = 0;
+ buffer_out[RxIrq] = 0;
+ buffer_count[RxIrq] = 0;
+ buffer_overflow[RxIrq] = 0;
+ Serial::attach( this, &MODSERIAL::isr_rx, Serial::RxIrq );
+
+ buffer_size[TxIrq] = txSize;
+ buffer[TxIrq] = txSize > 0 ? (char *)malloc(buffer_size[TxIrq]) : (char *)NULL;
+ buffer_in[TxIrq] = 0;
+ buffer_out[TxIrq] = 0;
+ buffer_count[TxIrq] = 0;
+ buffer_overflow[TxIrq] = 0;
+ Serial::attach( this, &MODSERIAL::isr_tx, Serial::TxIrq );
+ }
+ else {
+ error("MODSERIAL must have a defined UART to function.");
+ }
+
+
+ initDevice();
+
+ //_FCR = MODSERIAL_FIFO_ENABLE | MODSERIAL_FIFO_RX_RESET | MODSERIAL_FIFO_TX_RESET;
+
+ auto_detect_char = 0;
+
+ NVIC_EnableIRQ(_IRQ);
+}
+
+}; // namespace AjK ends
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/ISR_RX.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,63 @@
+/*
+ Copyright (c) 2010 Andy Kirkham
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+void
+MODSERIAL::isr_rx(void)
+{
+ if (RX_IRQ_ENABLED) {
+ if (! _base || buffer_size[RxIrq] == 0 || buffer[RxIrq] == (char *)NULL) {
+ _isr[RxIrq].call(&this->callbackInfo);
+ return;
+ }
+
+ while( MODSERIAL_READABLE ) {
+ rxc = (char)(MODSERIAL_READ_REG & 0xFF);
+ if ( MODSERIAL_RX_BUFFER_FULL ) {
+ buffer_overflow[RxIrq] = rxc; // Oh dear, no room in buffer.
+ _isr[RxOvIrq].call(&this->callbackInfo);
+ }
+ else {
+ if (buffer[RxIrq] != (char *)NULL) {
+ buffer[RxIrq][buffer_in[RxIrq]] = rxc;
+ buffer_count[RxIrq]++;
+ buffer_in[RxIrq]++;
+ if (buffer_in[RxIrq] >= buffer_size[RxIrq]) {
+ buffer_in[RxIrq] = 0;
+ }
+ }
+ _isr[RxIrq].call(&this->callbackInfo);
+ }
+ if (auto_detect_char == rxc) {
+ _isr[RxAutoDetect].call(&this->callbackInfo);
+ }
+ }
+ }
+}
+
+}; // namespace AjK ends
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/ISR_TX.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,56 @@
+/*
+ Copyright (c) 2010 Andy Kirkham
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK
+{
+
+void MODSERIAL::isr_tx(bool doCallback)
+{
+ if (TX_IRQ_ENABLED || MODSERIAL_TX_BUFFER_FULL ) {
+ if (! _base || buffer_size[TxIrq] == 0 || buffer[TxIrq] == (char *)NULL) {
+ _isr[TxIrq].call(&this->callbackInfo);
+ return;
+ }
+
+ while (! MODSERIAL_TX_BUFFER_EMPTY && MODSERIAL_WRITABLE ) {
+ MODSERIAL_WRITE_REG = txc = (uint8_t)(buffer[TxIrq][buffer_out[TxIrq]]);
+ buffer_count[TxIrq]--;
+ buffer_out[TxIrq]++;
+ if (buffer_out[TxIrq] >= buffer_size[TxIrq]) {
+ buffer_out[TxIrq] = 0;
+ }
+ if (doCallback) _isr[TxIrq].call(&this->callbackInfo);
+ }
+
+ if ( MODSERIAL_TX_BUFFER_EMPTY ) {
+ DISABLE_TX_IRQ;
+ _isr[TxEmpty].call(&this->callbackInfo);
+ }
+}
+}
+}; // namespace AjK ends
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WNCInterface/WncControllerK64F/MODSERIAL/MACROS.h Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,40 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef MODSERIAL_MACROS_H +#define MODSERIAL_MACROS_H + +#include "MODSERIAL_LPC1768.h" +#include "MODSERIAL_LPC11U24.h" +#include "MODSERIAL_KL25Z.h" +#include "MODSERIAL_KL05Z.h" +#include "MODSERIAL_KSDK.h" +#include "MODSERIAL_NUCLEO_F401RE.h" +#include "MODSERIAL_PAC_F401RB.h" + +#define MODSERIAL_TX_BUFFER_EMPTY (buffer_count[TxIrq]==0) +#define MODSERIAL_RX_BUFFER_EMPTY (buffer_count[RxIrq]==0) +#define MODSERIAL_TX_BUFFER_FULL (buffer_count[TxIrq]==buffer_size[TxIrq]) +#define MODSERIAL_RX_BUFFER_FULL (buffer_count[RxIrq]==buffer_size[RxIrq]) + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/MODSERIAL.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,123 @@
+/*
+ Copyright (c) 2010 Andy Kirkham
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ @file MODSERIAL.h
+ @purpose Extends Serial to provide fully buffered IO
+ @version 1.6
+ @date Nov 2010
+ @author Andy Kirkham
+*/
+
+#include "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+MODSERIAL::MODSERIAL( PinName tx, PinName rx, const char* name ) : Serial( tx, rx, name )
+{
+ init( MODSERIAL_DEFAULT_TX_BUFFER_SIZE, MODSERIAL_DEFAULT_RX_BUFFER_SIZE, rx );
+}
+
+MODSERIAL::MODSERIAL( PinName tx, PinName rx, int bufferSize, const char* name ) : Serial( tx, rx, name )
+{
+ init( bufferSize, bufferSize, rx );
+}
+
+MODSERIAL::MODSERIAL( PinName tx, PinName rx, int txSize, int rxSize, const char* name ) : Serial( tx, rx, name )
+{
+ init( txSize, rxSize, rx );
+}
+
+MODSERIAL::~MODSERIAL()
+{
+ NVIC_DisableIRQ(_IRQ);
+ if ( buffer[0] != NULL) free((char *)buffer[0] );
+ if ( buffer[1] != NULL) free((char *)buffer[1] );
+}
+
+bool MODSERIAL::txBufferFull( void )
+{
+ return MODSERIAL_TX_BUFFER_FULL;
+}
+
+bool MODSERIAL::rxBufferFull( void )
+{
+ return MODSERIAL_RX_BUFFER_FULL;
+}
+
+bool MODSERIAL::txBufferEmpty( void )
+{
+ return MODSERIAL_TX_BUFFER_EMPTY;
+}
+
+bool MODSERIAL::rxBufferEmpty( void )
+{
+ return MODSERIAL_RX_BUFFER_EMPTY;
+}
+
+
+int MODSERIAL::rxDiscardLastChar( void )
+{
+ // This function can only be called indirectly from
+ // an rxCallback function. Therefore, we know we
+ // just placed a char into the buffer.
+ char c = buffer[RxIrq][buffer_in[RxIrq]];
+
+ if (buffer_count[RxIrq]) {
+ buffer_count[RxIrq]--;
+ buffer_in[RxIrq]--;
+ if (buffer_in[RxIrq] < 0) {
+ buffer_in[RxIrq] = buffer_size[RxIrq] - 1;
+ }
+ }
+
+ return (int)c;
+}
+
+
+bool MODSERIAL::claim (FILE *stream) {
+#if 0
+ if ( _name == NULL) {
+ error("claim requires a name to be given in the instantiator of the MODSERIAL instance!\r\n");
+ }
+
+ //Add '/' before name:
+ char *path = new char[strlen(_name) + 2];
+ sprintf(path, "/%s", _name);
+
+ if (freopen(path, "w", stream) == NULL) {
+ // Failed, should not happen
+ return false;
+ }
+
+ delete(path);
+
+ //No buffering
+ setvbuf(stdout, NULL, _IONBF, buffer_size[TxIrq]);
+#endif
+
+ return true;
+}
+
+
+
+}; // namespace AjK ends
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/MODSERIAL.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,997 @@
+/*
+ Copyright (c) 2010 Andy Kirkham
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ @file MODSERIAL.h
+ @purpose Extends Serial to provide fully buffered IO
+ @version see ChangeLog.c
+ @date Nov 2010
+ @author Andy Kirkham
+*/
+
+#ifndef MODSERIAL_H
+#define MODSERIAL_H
+
+/** @defgroup API The MODSERIAL API */
+/** @defgroup MISC Misc MODSERIAL functions */
+/** @defgroup INTERNALS MODSERIAL Internals */
+
+#ifndef MODSERIAL_DEFAULT_RX_BUFFER_SIZE
+#define MODSERIAL_DEFAULT_RX_BUFFER_SIZE 256
+#endif
+
+#ifndef MODSERIAL_DEFAULT_TX_BUFFER_SIZE
+#define MODSERIAL_DEFAULT_TX_BUFFER_SIZE 256
+#endif
+
+#include "mbed.h"
+#include "serial_api.h"
+
+namespace AjK {
+
+// Forward reference.
+class MODSERIAL;
+
+/**
+ * @author Andy Kirkham
+ * @see http://mbed.org/cookbook/MODSERIAL
+ * @see example3a.cpp
+ * @see example3b.cpp
+ * @see API
+ *
+ * <b>MODSERIAL_IRQ_INFO</b> is a class used to pass information (and access to protected
+ * MODSERIAL functions) to IRQ callbacks.
+ */
+class MODSERIAL_IRQ_INFO
+{
+public:
+ friend class MODSERIAL;
+
+ MODSERIAL *serial;
+
+ MODSERIAL_IRQ_INFO() { serial = 0; }
+
+ /** rxDiscardLastChar()
+ *
+ * Remove the last char placed into the rx buffer.
+ * This is an operation that can only be performed
+ * by an rxCallback function.
+ * @ingroup API
+ * @return The byte removed from the buffer.
+ */
+ int rxDiscardLastChar(void);
+
+protected:
+
+ /** setSerial()
+ *
+ * Used internally by MODSERIAL to set the "this" pointer
+ * of the MODSERIAL that created this object.
+ * @ingroup INTERNAL
+ * @param A pointer to a MODSERIAL object instance.
+ */
+ void setSerial(MODSERIAL *s) { serial = s; }
+};
+
+// Forward reference dummy class.
+class MODSERIAL_callback_dummy;
+
+/**
+ * @author Andy Kirkham
+ * @see http://mbed.org/cookbook/MODSERIAL
+ * @see example3a.cpp
+ * @see example3b.cpp
+ * @see API
+ *
+ * <b>MODSERIAL_callback</b> is a class used to hold application callbacks that
+ * MODSERIAL can invoke on certain events.
+ */
+class MODSERIAL_callback
+{
+protected:
+
+ //! C callback function pointer.
+ void (*c_callback)(MODSERIAL_IRQ_INFO *);
+
+ //! C++ callback object/method pointer (the object part).
+ MODSERIAL_callback_dummy *obj_callback;
+
+ //! C++ callback object/method pointer (the method part).
+ void (MODSERIAL_callback_dummy::*method_callback)(MODSERIAL_IRQ_INFO *);
+
+public:
+
+ /** Constructor
+ */
+ MODSERIAL_callback() {
+ c_callback = 0;
+ obj_callback = 0;
+ method_callback = 0;
+ }
+
+ /** attach - Overloaded attachment function.
+ *
+ * Attach a C type function pointer as the callback.
+ *
+ * Note, the callback function prototype must be:-
+ * @code
+ * void myCallbackFunction(MODSERIAL_IRQ_INFO *);
+ * @endcode
+ * @param A C function pointer to call.
+ */
+ void attach(void (*function)(MODSERIAL_IRQ_INFO *) = 0) { c_callback = function; }
+
+ /** attach - Overloaded attachment function.
+ *
+ * Attach a C++ type object/method pointer as the callback.
+ *
+ * Note, the callback method prototype must be:-
+ * @code
+ * public:
+ * void myCallbackFunction(MODSERIAL_IRQ_INFO *);
+ * @endcode
+ * @param A C++ object pointer.
+ * @param A C++ method within the object to call.
+ */
+ template<class T>
+ void attach(T* item, void (T::*method)(MODSERIAL_IRQ_INFO *)) {
+ obj_callback = (MODSERIAL_callback_dummy *)item;
+ method_callback = (void (MODSERIAL_callback_dummy::*)(MODSERIAL_IRQ_INFO *))method;
+ }
+
+ /** call - Overloaded callback initiator.
+ *
+ * call the callback function.
+ *
+ * @param A pointer to a MODSERIAL_IRQ_INFO object.
+ */
+ void call(MODSERIAL_IRQ_INFO *arg) {
+ if (c_callback != 0) {
+ (*c_callback)(arg);
+ }
+ else {
+ if (obj_callback != 0 && method_callback != 0) {
+ (obj_callback->*method_callback)(arg);
+ }
+ }
+ }
+};
+
+/**
+ * @author Andy Kirkham
+ * @see http://mbed.org/cookbook/MODSERIAL
+ * @see http://mbed.org/handbook/Serial
+ * @see example1.cpp
+ * @see example2.cpp
+ * @see example3a.cpp
+ * @see example3b.cpp
+ * @see example_dma.cpp
+ * @see API
+ *
+ * <b>MODSERIAL</b> extends the Mbed library <a href="/handbook/Serial">Serial</a> to provide fully buffered
+ * TX and RX streams. Buffer length is fully customisable.
+ *
+ * Before using MODSERIAL users should be familar with Mbed's standard <a href="/handbook/Serial">Serial</a>
+ * library object. MODSERIAL is a direct "drop in" replacement for <a href="/handbook/Serial">Serial</a>. Where
+ * previously Serial was used, MODSERIAL can be used as adirect replacement instantly offering standard
+ * TX and RX buffering. By default, both TX and RX buffers are 256 bytes in length.
+ *
+ * @image html /media/uploads/mbedofficial/serial_interfaces.png
+ *
+ * Standard example:
+ * @code
+ * #include "mbed.h"
+ * #include "MODSERIAL.h"
+ *
+ * MODSERIAL pc(USBTX, USBRX); // tx, rx
+ *
+ * int main() {
+ * pc.printf("Hello World!");
+ * while(1) {
+ * pc.putc(pc.getc() + 1);
+ * }
+ * }
+ * @endcode
+ *
+ * Example with alternate buffer length:
+ * @code
+ * #include "mbed.h"
+ * #include "MODSERIAL.h"
+ *
+ * // Make TX and RX buffers 512byes in length
+ * MODSERIAL pc(USBTX, USBRX, 512); // tx, rx
+ *
+ * int main() {
+ * pc.printf("Hello World!");
+ * while(1) {
+ * pc.putc(pc.getc() + 1);
+ * }
+ * }
+ * @endcode
+ *
+ * Example with alternate buffer length:
+ * @code
+ * #include "mbed.h"
+ * #include "MODSERIAL.h"
+ *
+ * // Make TX 1024bytes and RX 512byes in length
+ * MODSERIAL pc(USBTX, USBRX, 1024, 512); // tx, rx
+ *
+ * int main() {
+ * pc.printf("Hello World!");
+ * while(1) {
+ * pc.putc(pc.getc() + 1);
+ * }
+ * }
+ * @endcode
+ */
+class MODSERIAL : public Serial
+{
+public:
+
+ // Allow instances of MODSERIAL_IRQ_INFO to use protected properties and methods.
+ friend class MODSERIAL_IRQ_INFO;
+
+ //! A copy of the Serial parity enum
+ /** @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.format */
+ enum Parity {
+ None = 0
+ , Odd
+ , Even
+ , Forced1
+ , Forced0
+ };
+
+ //! A copy of the Serial IrqType enum
+ enum IrqType {
+ RxIrq = 0
+ , TxIrq
+ , RxOvIrq
+ , TxOvIrq
+ , TxEmpty
+ , RxAutoDetect
+ , NumOfIrqTypes
+ };
+
+ //! Non-blocking functions return code.
+ enum Result {
+ Ok = 0 /*!< Ok. */
+ , NoMemory = -1 /*!< Memory allocation failed. */
+ , NoChar = -1 /*!< No character in buffer. */
+ , BufferOversize = -2 /*!< Oversized buffer. */
+ };
+
+ /**
+ * The MODSERIAL constructor is used to initialise the serial object.
+ *
+ * @param tx PinName of the TX pin.
+ * @param rx PinName of the TX pin.
+ */
+ MODSERIAL(PinName tx, PinName rx, const char* name = NULL);
+
+ /**
+ * The MODSERIAL constructor is used to initialise the serial object.
+ *
+ * @param tx PinName of the TX pin.
+ * @param rx PinName of the TX pin.
+ * @param bufferSize Integer of the TX and RX buffer sizes.
+ */
+ MODSERIAL(PinName tx, PinName rx, int bufferSize, const char* name = NULL);
+
+ /**
+ * The MODSERIAL constructor is used to initialise the serial object.
+ *
+ * @param tx PinName of the TX pin.
+ * @param rx PinName of the TX pin.
+ * @param txBufferSize Integer of the TX buffer sizes.
+ * @param rxBufferSize Integer of the RX buffer sizes.
+ */
+ MODSERIAL(PinName tx, PinName rx, int txBufferSize, int rxBufferSize, const char* name = NULL);
+
+ virtual ~MODSERIAL();
+
+ /**
+ * Function: attach
+ *
+ * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback
+ * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts
+ * to enable it's buffering system. However, after the byte has been received/sent under interrupt control,
+ * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not
+ * directly interact with the Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should
+ * be used.
+ *
+ * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty,
+ * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and
+ * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled
+ * so that when the TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY
+ * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character
+ * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may
+ * never come into play.
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "MODSERIAL.h"
+ *
+ * DigitalOut led1(LED1);
+ * DigitalOut led2(LED2);
+ * DigitalOut led3(LED3);
+ *
+ * // To test, connect p9 to p10 as a loopback.
+ * MODSERIAL pc(p9, p10);
+ *
+ * // This function is called when a character goes into the TX buffer.
+ * void txCallback(void) {
+ * led2 = !led2;
+ * }
+ *
+ * // This function is called when a character goes into the RX buffer.
+ * void rxCallback(void) {
+ * led3 = !led3;
+ * }
+ *
+ * int main() {
+ * pc.baud(115200);
+ * pc.attach(&txCallback, MODSERIAL::TxIrq);
+ * pc.attach(&rxCallback, MODSERIAL::RxIrq);
+ *
+ * while(1) {
+ * led1 = !led1;
+ * wait(0.5);
+ * pc.putc('A');
+ * wait(0.5);
+ * }
+ * ]
+ * @endcode
+ *
+ * @ingroup API
+ * @param fptr A pointer to a void function, or 0 to set as none
+ * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
+ */
+ void attach(void (*fptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { _isr[type].attach(fptr); }
+
+ /**
+ * Function: attach
+ *
+ * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback
+ * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts
+ * to enable it's buffering system. However, after the byte has been received/sent under interrupt control,
+ * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not
+ * directly interact with the Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should
+ * be used.
+ *
+ * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty,
+ * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and
+ * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled
+ * so that when the TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY
+ * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character
+ * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may
+ * never come into play.
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "MODSERIAL.h"
+ *
+ * DigitalOut led1(LED1);
+ * DigitalOut led2(LED2);
+ * DigitalOut led3(LED3);
+ *
+ * // To test, connect p9 to p10 as a loopback.
+ * MODSERIAL pc(p9, p10);
+ *
+ * class Foo {
+ * public:
+ * // This method is called when a character goes into the TX buffer.
+ * void txCallback(void) { led2 = !led2; }
+ *
+ * // This method is called when a character goes into the RX buffer.
+ * void rxCallback(void) { led3 = !led3; }
+ * };
+ *
+ * Foo foo;
+ *
+ * int main() {
+ * pc.baud(115200);
+ * pc.attach(&foo, &Foo::txCallback, MODSERIAL::TxIrq);
+ * pc.attach(&foo, &Foo::rxCallback, MODSERIAL::RxIrq);
+ *
+ * while(1) {
+ * led1 = !led1;
+ * wait(0.5);
+ * pc.putc('A');
+ * wait(0.5);
+ * }
+ * ]
+ * @endcode
+ *
+ * @ingroup API
+ * @param tptr A pointer to the object to call the member function on
+ * @param mptr A pointer to the member function to be called
+ * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
+ */
+ template<typename T>
+ void attach(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) {
+ if((mptr != 0) && (tptr != 0)) {
+ _isr[type].attach(tptr, mptr);
+ }
+ }
+
+ /**
+ * @see attach
+ * @ingroup API
+ */
+ void connect(void (*fptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { _isr[RxIrq].attach(fptr); }
+
+ /**
+ * @see attach
+ * @ingroup API
+ */
+ template<typename T>
+ void connect(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) {
+ if((mptr != 0) && (tptr != 0)) {
+ _isr[type].attach(tptr, mptr);
+ }
+ }
+
+ /**
+ * Function: writeable
+ *
+ * Determine if there is space available to write a byte
+ *
+ * @ingroup API
+ * @return 1 if there is space to write a character, else 0
+ */
+ int writeable() { return txBufferFull() ? 0 : 1; }
+
+ /**
+ * Function: readable
+ *
+ * Determine if there is a byte available to read
+ *
+ * @ingroup API
+ * @return 1 if there is a character available to read, else 0
+ */
+ int readable() { return rxBufferEmpty() ? 0 : 1; }
+
+ /**
+ * Function: txBufferSane
+ *
+ * Determine if the TX buffer has been initialized.
+ *
+ * @ingroup API
+ * @return true if the buffer is initialized, else false
+ */
+ bool txBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; }
+
+ /**
+ * Function: rxBufferSane
+ *
+ * Determine if the RX buffer has been initialized.
+ *
+ * @ingroup API
+ * @return true if the buffer is initialized, else false
+ */
+ bool rxBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; }
+
+ /**
+ * Function: txBufferGetCount
+ *
+ * Returns how many bytes are in the TX buffer
+ *
+ * @ingroup API
+ * @return The number of bytes in the TX buffer
+ */
+ int txBufferGetCount(void) { return buffer_count[TxIrq]; }
+
+ /**
+ * Function: rxBufferGetCount
+ *
+ * Returns how many bytes are in the RX buffer
+ *
+ * @ingroup API
+ * @return The number of bytes in the RX buffer
+ */
+ int rxBufferGetCount(void) { return buffer_count[RxIrq]; }
+
+ /**
+ * Function: txBufferGetSize
+ *
+ * Returns the current size of the TX buffer
+ *
+ * @ingroup API
+ * @return The length iof the TX buffer in bytes
+ */
+ int txBufferGetSize(int size) { return buffer_size[TxIrq]; }
+
+ /**
+ * Function: rxBufferGetSize
+ *
+ * Returns the current size of the RX buffer
+ *
+ * @ingroup API
+ * @return The length iof the RX buffer in bytes
+ */
+ int rxBufferGetSize(int size) { return buffer_size[RxIrq]; }
+
+ /**
+ * Function: txBufferFull
+ *
+ * Is the TX buffer full?
+ *
+ * @ingroup API
+ * @return true if the TX buffer is full, otherwise false
+ */
+ bool txBufferFull(void);
+
+ /**
+ * Function: rxBufferFull
+ *
+ * Is the RX buffer full?
+ *
+ * @ingroup API
+ * @return true if the RX buffer is full, otherwise false
+ */
+ bool rxBufferFull(void);
+
+ /**
+ * Function: txBufferEmpty
+ *
+ * Is the TX buffer empty?
+ *
+ * @ingroup API
+ * @return true if the TX buffer is empty, otherwise false
+ */
+ bool txBufferEmpty(void);
+
+ /**
+ * Function: rxBufferEmpty
+ *
+ * Is the RX buffer empty?
+ *
+ * @ingroup API
+ * @return true if the RX buffer is empty, otherwise false
+ */
+ bool rxBufferEmpty(void);
+
+ /**
+ * Function: txBufferSetSize
+ *
+ * Change the TX buffer size.
+ *
+ * @see Result
+ * @ingroup API
+ * @param size The new TX buffer size in bytes.
+ * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails.
+ * @return Result Ok on success.
+ */
+ int txBufferSetSize(int size, bool m) { return resizeBuffer(size, TxIrq, m); }
+
+ /**
+ * Function: rxBufferSetSize
+ *
+ * Change the RX buffer size.
+ *
+ * @see Result
+ * @ingroup API
+ * @param size The new RX buffer size in bytes.
+ * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails.
+ * @return Result Ok on success.
+ */
+ int rxBufferSetSize(int size, bool m) { return resizeBuffer(size, RxIrq, m); }
+
+ /**
+ * Function: txBufferSetSize
+ *
+ * Change the TX buffer size.
+ * Always performs a memory sanity check, halting the Mbed on failure.
+ *
+ * @see Result
+ * @ingroup API
+ * @param size The new TX buffer size in bytes.
+ * @return Result Ok on success.
+ */
+ int txBufferSetSize(int size) { return resizeBuffer(size, TxIrq, true); }
+
+ /**
+ * Function: rxBufferSetSize
+ *
+ * Change the RX buffer size.
+ * Always performs a memory sanity check, halting the Mbed on failure.
+ *
+ * @see Result
+ * @ingroup API
+ * @param size The new RX buffer size in bytes.
+ * @return Result Ok on success.
+ */
+ int rxBufferSetSize(int size) { return resizeBuffer(size, RxIrq, true); }
+
+ /**
+ * Function: txBufferFlush
+ *
+ * Remove all bytes from the TX buffer.
+ * @ingroup API
+ */
+ void txBufferFlush(void) { flushBuffer(TxIrq); }
+
+ /**
+ * Function: rxBufferFlush
+ *
+ * Remove all bytes from the RX buffer.
+ * @ingroup API
+ */
+ void rxBufferFlush(void) { flushBuffer(RxIrq); }
+
+ /**
+ * Function: getcNb
+ *
+ * Like getc() but is non-blocking. If no bytes are in the RX buffer this
+ * function returns Result::NoChar (-1)
+ *
+ * @ingroup API
+ * @return A byte from the RX buffer or Result::NoChar (-1) if bufer empty.
+ */
+ int getcNb() { return __getc(false); }
+
+ /**
+ * Function: getc
+ *
+ * Overloaded version of Serial::getc()
+ *
+ * This function blocks (if the RX buffer is empty the function will wait for a
+ * character to arrive and then return that character).
+ *
+ * @ingroup API
+ * @return A byte from the RX buffer
+ */
+ int getc() { return __getc(true); }
+
+ /**
+ * Function: txGetLastChar
+ *
+ * Rteurn the last byte to pass through the TX interrupt handler.
+ *
+ * @ingroup MISC
+ * @return The byte
+ */
+ char txGetLastChar(void) { return txc; }
+
+ /**
+ * Function: rxGetLastChar
+ *
+ * Return the last byte to pass through the RX interrupt handler.
+ *
+ * @ingroup MISC
+ * @return The byte
+ */
+ char rxGetLastChar(void) { return rxc; }
+
+
+
+ /**
+ * Function: autoDetectChar
+ *
+ * Set the char that, if seen incoming, invokes the AutoDetectChar callback.
+ *
+ * @ingroup API
+ * @param int c The character to detect.
+ */
+ void autoDetectChar(char c) { auto_detect_char = c; }
+
+ /**
+ * Function: move
+ *
+ * Move contents of RX buffer to external buffer. Stops if "end" detected.
+ *
+ * @ingroup API
+ * @param char *s The destination buffer address
+ * @param int max The maximum number of chars to move.
+ * @param char end If this char is detected stop moving.
+ */
+ int move(char *s, int max, char end) {
+ int counter = 0;
+ char c;
+ while(readable()) {
+ c = getc();
+ if (c == end) break;
+ *(s++) = c;
+ counter++;
+ if (counter == max) break;
+ }
+ return counter;
+ }
+
+ /**
+ * Function: move (overloaded)
+ *
+ * Move contents of RX buffer to external buffer. Stops if auto_detect_char detected.
+ *
+ * @ingroup API
+ * @param int max The maximum number of chars to move.
+ * @param char *s The destination buffer address
+ */
+ int move(char *s, int max) {
+ return move(s, max, auto_detect_char);
+ }
+
+ /**
+ * Function: claim
+ *
+ * Redirect a stream to this MODSERIAL object
+ *
+ * Important: A name parameter must have been added when creating the MODSERIAL object:
+ *
+ * @code
+ * #include "MODSERIAL.h"
+ * ...
+ * MODSERIAL pc(USBTX, USBRX, "modser");
+ *
+ * int main() {
+ * pc.claim() // capture <stdout>
+ * pc.printf("Uses the MODSERIAL library\r\n");
+ * printf("So does this!\r\n");
+ * }
+ * @endcode
+ *
+ * @ingroup API
+ * @param FILE *stream The stream to redirect (default = stdout)
+ * @return true if succeeded, else false
+ */
+ bool claim(FILE *stream = stdout);
+
+ #if 0 // Inhereted from Serial/Stream, for documentation only
+ /**
+ * Function: putc
+ *
+ * Write a character
+ * Inhereted from Serial/Stream
+ *
+ * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.putc
+ * @ingroup API
+ * @param c The character to write to the serial port
+ */
+ int putc(int c);
+ #endif
+
+ #if 0 // Inhereted from Serial/Stream, for documentation only
+ /**
+ * Function: printf
+ *
+ * Write a formated string
+ * Inhereted from Serial/Stream
+ *
+ * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.printf
+ * @ingroup API
+ * @param format A printf-style format string, followed by the variables to use in formating the string.
+ */
+ int printf(const char* format, ...);
+ #endif
+
+ #if 0 // Inhereted from Serial/Stream, for documentation only
+ /**
+ * Function: scanf
+ *
+ * Read a formated string
+ * Inhereted from Serial/Stream
+ *
+ * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.scanf
+ * @ingroup API
+ * @param format - A scanf-style format string, followed by the pointers to variables to store the results.
+ */
+ int scanf(const char* format, ...);
+ #endif
+
+protected:
+ /**
+ * Used to pass information to callbacks.
+ * @ingroup INTERNALS
+ */
+ MODSERIAL_IRQ_INFO callbackInfo;
+
+ /**
+ * Remove the last char placed into the rx buffer.
+ * This is an operation that can only be performed
+ * by an rxCallback function. To protect the buffers
+ * this function is defined protected so that a
+ * regular application cannot call it directly. It
+ * can only be called by the public version within a
+ * MODSERIAL_IRQ_INFO class.
+ * @ingroup INTERNALS
+ * @return The byte removed from the buffer.
+ */
+ int rxDiscardLastChar(void);
+
+private:
+
+ /**
+ * A pointer to the UART peripheral base address being used.
+ * @ingroup INTERNALS
+ */
+ void *_base;
+
+ /**
+ * The last byte to pass through the TX IRQ handler.
+ * @ingroup INTERNALS
+ */
+ volatile char txc;
+
+ /**
+ * The last byte to pass through the RX IRQ handler.
+ * @ingroup INTERNALS
+ */
+ volatile char rxc;
+
+ /**
+ * Pointers to the TX and RX buffers.
+ * @ingroup INTERNALS
+ */
+ volatile char *buffer[2];
+
+ /**
+ * Buffer in pointers.
+ * @ingroup INTERNALS
+ */
+ volatile int buffer_in[2];
+
+ /**
+ * Buffer out pointers.
+ * @ingroup INTERNALS
+ */
+ volatile int buffer_out[2];
+
+ /**
+ * Buffer lengths.
+ * @ingroup INTERNALS
+ */
+ volatile int buffer_size[2];
+
+ /**
+ * Buffer content counters.
+ * @ingroup INTERNALS
+ */
+ volatile int buffer_count[2];
+
+ /**
+ * Buffer overflow.
+ * @ingroup INTERNALS
+ */
+ volatile int buffer_overflow[2];
+
+ /**
+ * Auto-detect character.
+ * @ingroup INTERNALS
+ */
+ volatile char auto_detect_char;
+
+ /**
+ * Callback system.
+ * @ingroup INTERNALS
+ */
+ MODSERIAL_callback _isr[NumOfIrqTypes];
+
+ /**
+ * TX Interrupt Service Routine.
+ * @ingroup INTERNALS
+ */
+ void isr_tx(bool doCallback);
+
+ /**
+ * TX Interrupt Service Routine stub version.
+ * @ingroup INTERNALS
+ */
+ void isr_tx(void) { isr_tx(true); }
+
+
+ /**
+ * RX Interrupt Service Routine.
+ * @ingroup INTERNALS
+ */
+ void isr_rx(void);
+
+ /**
+ * Get a character from the RX buffer
+ * @ingroup INTERNALS
+ * @param bool True to block (wait for input)
+ * @return A byte from the buffer.
+ */
+ int __getc(bool);
+
+ /**
+ * Put a character from the TX buffer
+ * @ingroup INTERNALS
+ * @param bool True to block (wait for space in the TX buffer if full)
+ * @return 0 on success
+ */
+ int __putc(int c, bool);
+
+ /**
+ * Function: _putc
+ * Overloaded virtual function.
+ */
+ virtual int _putc(int c) { return __putc(c, true); }
+
+ /**
+ * Function: _getc
+ * Overloaded virtual function.
+ */
+ virtual int _getc() { return __getc(true); }
+
+ /**
+ * Function: init
+ * Initialize the MODSERIAL object
+ * @ingroup INTERNALS
+ */
+ void init(int txSize, int rxSize, PinName rx);
+
+ /**
+ * Function: flushBuffer
+ * @ingroup INTERNALS
+ */
+ void flushBuffer(IrqType type);
+
+ /**
+ * Function: resizeBuffer
+ * @ingroup INTERNALS
+ */
+ int resizeBuffer(int size, IrqType type = RxIrq, bool memory_check = true);
+
+ /**
+ * Function: moveRingBuffer
+ * @ingroup INTERNALS
+ */
+ void moveRingBuffer(char * newBuffer, IrqType type);
+
+
+
+
+//DEVICE SPECIFIC FUNCTIONS:
+ private:
+ /**
+ * Set pointers to UART and IRQ
+ */
+ void setBase( void );
+
+ /**
+ * If required, allows for adding specific settings
+ */
+ void initDevice( void );
+
+ IRQn_Type _IRQ;
+
+ public:
+ /**
+ * Function: txIsBusy
+ *
+ * If the Uart is still actively sending characters this
+ * function will return true.
+ *
+ * @ingroup API
+ * @return bool
+ */
+ bool txIsBusy(void);
+
+
+};
+
+}; // namespace AjK ends
+
+using namespace AjK;
+
+#endif
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/MODSERIAL_IRQ_INFO.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ Copyright (c) 2010 Andy Kirkham
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ @file MODSERIAL_IRQ_INFO.cpp
+ @author Andy Kirkham
+*/
+
+#include "MODSERIAL.h"
+
+namespace AjK {
+
+int
+MODSERIAL_IRQ_INFO::rxDiscardLastChar(void)
+{
+ if (!serial) return -1;
+
+ return serial->rxDiscardLastChar();
+}
+
+}; // namespace AjK ends
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/PUTC.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,82 @@
+/*
+ Copyright (c) 2010 Andy Kirkham
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+int
+MODSERIAL::__putc(int c, bool block) {
+
+ // If no buffer is in use fall back to standard TX FIFO usage.
+ // Note, we must block in this case and ignore bool "block"
+ // so as to maintain compat with Mbed Serial.
+ if (buffer[TxIrq] == (char *)NULL || buffer_size[TxIrq] == 0) {
+ while (! MODSERIAL_WRITABLE) ; // Wait for space in the TX FIFO.
+ MODSERIAL_WRITE_REG = (uint32_t)c;
+ return 0;
+ }
+
+ if ( MODSERIAL_WRITABLE && MODSERIAL_TX_BUFFER_EMPTY ) {
+ MODSERIAL_WRITE_REG = (uint32_t)c;
+ }
+ else {
+ if (block) {
+ uint32_t irq_reg = MODSERIAL_IRQ_REG; DISABLE_TX_IRQ;
+ while ( MODSERIAL_TX_BUFFER_FULL ) { // Blocks!
+ // If putc() is called from an ISR then we are stuffed
+ // because in an ISR no bytes from the TX buffer will
+ // get transferred to teh TX FIFOs while we block here.
+ // So, to work around this, instead of sitting in a
+ // loop waiting for space in the TX buffer (which will
+ // never happen in IRQ context), check to see if the
+ // TX FIFO has space available to move bytes from the
+ // TX buffer to TX FIFO to make space. The easiest way
+ // to do this is to poll the isr_tx() function while we
+ // are blocking.
+ isr_tx(false);
+ }
+ MODSERIAL_IRQ_REG = irq_reg;
+ }
+ else if( MODSERIAL_TX_BUFFER_FULL ) {
+ buffer_overflow[TxIrq] = c; // Oh dear, no room in buffer.
+ _isr[TxOvIrq].call(&this->callbackInfo);
+ return -1;
+ }
+ DISABLE_TX_IRQ;
+ buffer[TxIrq][buffer_in[TxIrq]] = c;
+ __disable_irq();
+ buffer_count[TxIrq]++;
+ __enable_irq();
+ buffer_in[TxIrq]++;
+ if (buffer_in[TxIrq] >= buffer_size[TxIrq]) {
+ buffer_in[TxIrq] = 0;
+ }
+ ENABLE_TX_IRQ;
+ }
+
+ return 0;
+}
+
+}; // namespace AjK ends
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/MODSERIAL/RESIZE.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,97 @@
+/*
+ Copyright (c) 2010 Andy Kirkham
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+int
+MODSERIAL::resizeBuffer(int size, IrqType type, bool memory_check)
+{
+ // Make sure the ISR cannot use the buffers while we are manipulating them.
+ NVIC_DisableIRQ(_IRQ);
+
+ // If the requested size is the same as the current size there's nothing to do,
+ // just continue to use the same buffer as it's fine as it is.
+ if (buffer_size[type] == size)
+ {
+ NVIC_EnableIRQ(_IRQ);
+ return Ok;
+ }
+
+ // is new buffer is big enough?
+ if (size <= buffer_count[type])
+ {
+ NVIC_EnableIRQ(_IRQ);
+ return BufferOversize;
+ }
+
+ // allocate new buffer
+ char * newBuffer = (char*)malloc(size);
+
+ // allocation failed?
+ if (newBuffer == (char*)NULL)
+ {
+ if (memory_check)
+ error("Failed to allocate memory for %s buffer", type == TxIrq ? "TX" : "RX");
+
+ return NoMemory;
+ }
+
+ // copy old buffer content to new one
+ moveRingBuffer(newBuffer, type);
+
+ // free old buffer and reset ring buffer cursor
+ free((char*)buffer[type]);
+
+ buffer[type] = newBuffer;
+ buffer_size[type] = size;
+ buffer_in[type] = buffer_count[type];
+ buffer_out[type] = 0;
+
+ // Start the ISR system again with the new buffers.
+ NVIC_EnableIRQ(_IRQ);
+ return Ok;
+}
+
+void MODSERIAL::moveRingBuffer(char * newBuffer, IrqType type)
+{
+ // copy old buffer content to new one
+ if(buffer_in[type] > buffer_out[type])
+ { // content in the middle of the ring buffer
+ memcpy(&newBuffer[0], (char*)&buffer[type][buffer_out[type]], buffer_count[type]);
+ }
+ else if(buffer_in[type] < buffer_out[type])
+ { // content split, free space in the middle
+ // copy last part of the old buffer
+ int end_count= buffer_size[type] - buffer_out[type];
+ memcpy(&newBuffer[0], (char*)&buffer[type][buffer_out[type]], end_count);
+
+ // copy first part of old buffer
+ memcpy(&newBuffer[end_count], (char*)buffer[type], buffer_in[type]);
+ }
+ // else old buffer empty
+}
+
+}; // namespace AjK ends
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/WncController/WncController.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,2217 @@
+/*
+ Copyright (c) 2016 Fred Kellerman
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ @file WncController.cpp
+ @purpose Controls WNC 14A2A Cellular Modem
+ @version 1.0
+ @date July 2016
+ @author Fred Kellerman
+*/
+
+
+#include <cstdlib>
+#include <cctype>
+#include "WncController.h"
+
+namespace WncController_fk {
+
+/////////////////////////////////////////////////////
+// Static initializers
+/////////////////////////////////////////////////////
+WncController::WncSocketInfo_s WncController::m_sSock[MAX_NUM_WNC_SOCKETS];
+const WncController::WncSocketInfo_s WncController::defaultSockStruct = { 0, false, "192.168.0.1", 80, 0, 25, true, 30 };
+
+WncController::WncState_e WncController::m_sState = WNC_OFF;
+uint16_t WncController::m_sCmdTimeoutMs = WNC_CMD_TIMEOUT_MS;
+string WncController::m_sApnStr = "NULL";
+string WncController::m_sWncStr;
+uint8_t WncController::m_sPowerUpTimeoutSecs = MAX_POWERUP_TIMEOUT;
+bool WncController::m_sDebugEnabled = false;
+bool WncController::m_sMoreDebugEnabled = false;
+bool WncController::m_sCheckNetStatus = false; // Turn on internet status check between every command
+const char * const WncController::INVALID_IP_STR = "";
+bool WncController::m_sReadyForSMS = false;
+
+
+/**
+ * C++ version 0.4 char* style "itoa":
+ * Written by Lukás Chmela
+ * Released under GPLv3.
+*/
+
+static char* itoa(int64_t value, char* result, int base)
+{
+ // check that the base is valid
+ if ( base < 2 || base > 36 ) {
+ *result = '\0';
+ return result;
+ }
+
+ char* ptr = result, *ptr1 = result, tmp_char;
+ int64_t tmp_value;
+
+ do {
+ tmp_value = value;
+ value /= base;
+ *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)];
+ } while ( value );
+
+ // Apply negative sign
+ if ( tmp_value < 0 )
+ *ptr++ = '-';
+
+ *ptr-- = '\0';
+
+ while ( ptr1 < ptr ) {
+ tmp_char = *ptr;
+ *ptr-- = *ptr1;
+ *ptr1++ = tmp_char;
+ }
+
+ return result;
+}
+
+const char * WncController::_to_string(int64_t value)
+{
+ static char str[21]; // room for signed 64-bit + null
+ itoa(value, str, 10);
+ return (str);
+}
+
+const char * WncController::_to_hex_string(uint8_t value)
+{
+ static char str[3]; // room for 8-bit + null
+ itoa(value, str, 16);
+ return (str);
+}
+
+/**
+ * \brief Constructor for UART controlled WNC
+ *
+ * \param [in] wnc_uart - Reference to a SerialBuffered object which will
+ * be used as the bus to control the WNC.
+ *
+ * \return None.
+ *
+ * \details Adding another way to talk to the WNC, like I2C or USB,
+ * a constructor should be added for each type just like the SerialBuffered
+ * constructor below.
+ */
+WncController::WncController(void)
+{
+ for(unsigned i; i<MAX_NUM_WNC_SOCKETS; i++)
+ m_sSock[i] = defaultSockStruct;
+}
+
+void WncController::enableDebug(bool on, bool moreDebugOn)
+{
+ m_sDebugEnabled = on;
+ m_sMoreDebugEnabled = moreDebugOn;
+}
+
+/**
+ * \brief Used internally but also make public for a user of the Class to interrogate state as well.
+ *
+ * \param [in] None.
+ *
+ * \return The state of the WNC Modem.
+ *
+ * \details None.
+ */
+WncController::WncState_e WncController::getWncStatus(void)
+{
+ return (m_sState);
+}
+
+/**
+ * \brief Return signal quality dBm level
+ *
+ * \param [in] None.
+ *
+ * \return The dBm signal level at the time of the request.
+ *
+ * \details This polls (at the time of the call) the cell signal.
+ */
+int16_t WncController::getDbmRssi(void)
+{
+ int16_t rssi, ber;
+ if (at_getrssiber_wnc(&rssi, &ber) == true)
+ return (rssi);
+ else
+ return (99);
+}
+
+int16_t WncController::get3gBer(void)
+{
+ int16_t rssi, ber;
+ if (at_getrssiber_wnc(&rssi, &ber) == true)
+ return (ber);
+ else
+ return (99);
+}
+
+
+/**
+ * \brief Power up and down (down not implemented yet)
+ *
+ * \param [in] on - set true to power on, otherwise false
+ *
+ * \return None.
+ *
+ * \details Power-on works but not power-down. This will manipulate WNC Shield hardware
+ * and bring it to life. It will also initialize the WNC enough to get it to be able to open sockets
+ * (with AT commands)
+ */
+bool WncController::powerWncOn(const char * const apn, uint8_t powerUpTimeoutSecs)
+{
+ dbgPuts("Waiting for WNC to Initialize...");
+ m_sPowerUpTimeoutSecs = powerUpTimeoutSecs;
+ m_sState = WNC_ON_NO_CELL_LINK; // Turn soft on to allow "AT" for init to be sent!
+ if (initWncModem(powerUpTimeoutSecs) == true) {
+ // Set the Apn
+ setApnName(apn);
+ if (false == softwareInitMdm()) {
+ dbgPuts("Software init failed!");
+ m_sState = WNC_OFF;
+ }
+ }
+ else {
+ dbgPuts("Power up failed!");
+ m_sState = WNC_OFF;
+ }
+
+ return ((m_sState == WNC_ON) || (m_sState == WNC_ON_NO_CELL_LINK));
+}
+
+size_t WncController::sendCustomCmd(const char * cmd, char * resp, size_t sizeRespBuf, int ms_timeout)
+{
+ string * respStr;
+
+ if (sizeRespBuf > 0) {
+ AtCmdErr_e r = at_send_wnc_cmd(cmd, &respStr, ms_timeout);
+ strncpy(resp, respStr->c_str(), sizeRespBuf);
+ if (respStr->size() > sizeRespBuf)
+ dbgPuts("sendCustomCmd truncated!");
+
+ return (respStr->size());
+ }
+
+ dbgPuts("sendCustomCmd: would have overrun!");
+
+ return (0);
+}
+
+bool WncController::pingUrl(const char * url)
+{
+ string ipAddr;
+
+ if (true == at_dnsresolve_wnc(url, &ipAddr))
+ return (pingIp(ipAddr.c_str()));
+ else
+ dbgPuts("pingUrl DNS resolve: failed!");
+
+ return (false);
+}
+
+bool WncController::pingIp(const char * ip)
+{
+ if (true == at_ping_wnc(ip))
+ return (true);
+ else
+ dbgPuts("pingIp: failed!");
+
+ return (false);
+}
+
+bool WncController::getWncNetworkingStats(WncIpStats * s)
+{
+ return (at_get_wnc_net_stats(s));
+}
+
+bool WncController::getIpAddr(uint16_t numSock, char myIpAddr[MAX_LEN_IP_STR])
+{
+ if (numSock < MAX_NUM_WNC_SOCKETS) {
+ strncpy(myIpAddr, m_sSock[numSock].myIpAddressStr.c_str(), MAX_LEN_IP_STR);
+ myIpAddr[MAX_LEN_IP_STR - 1] = '\0';
+ return (true);
+ }
+ else {
+ myIpAddr[0] = '\0';
+ return (false);
+ }
+}
+
+bool WncController::setApnName(const char * const apnStr)
+{
+ if (at_setapn_wnc(apnStr) == true)
+ {
+ m_sApnStr = apnStr;
+ return (true);
+ }
+ else
+ return (false);
+}
+
+
+/**
+ * \brief Look-up a URL text string and convert into an IP Address string.
+ *
+ * \param [in] url - the URL to lookup. numSock - the socket number to resolve.
+ *
+ * \return true - if the IP address has been resolved. false - if the URL could not be resolved.
+ *
+ * \details None.
+ */
+bool WncController::resolveUrl(uint16_t numSock, const char * url)
+{
+ bool cmdRes;
+
+ if (numSock < MAX_NUM_WNC_SOCKETS) {
+ if (strlen(url) > 0) {
+ cmdRes = at_dnsresolve_wnc(url, &m_sSock[numSock].myIpAddressStr);
+ if (cmdRes == false)
+ dbgPuts("Cannot resolve URL!");
+ return (cmdRes);
+ }
+ else
+ dbgPuts("Invalid URL");
+ }
+ else
+ dbgPuts("Invalid Sock num!");
+
+ return (false);
+}
+
+/**
+ * \brief Set IP Address string
+ *
+ * \param [in] numSock - socket reference to set the string for. ipStr - text string of the IP
+ * address you want to talk to. There is no sanity check - beware!!!
+ *
+ * \return true - if the IP address has been set. false - if the IP could not be set.
+ *
+ * \details None.
+ */
+bool WncController::setIpAddr(uint16_t numSock, const char * ipStr)
+{
+ if (numSock < MAX_NUM_WNC_SOCKETS) {
+ m_sSock[numSock].myIpAddressStr = ipStr;
+ return (true);
+ }
+ else {
+ dbgPuts("Bad socket num!");
+ return (false);
+ }
+}
+
+void WncController::setWncCmdTimeout(uint16_t toMs)
+{
+ m_sCmdTimeoutMs = toMs;
+}
+
+/**
+ * \brief Opens a WNC socket.
+ *
+ * \param [in] sockNum - the number of the socket to open. ipAddr - a string containing
+ * the IP address. port - the IP port number to open the socket connection.
+ *
+ * \return true - if the socket is/was opened. false otherwise.
+ *
+ * \details None.
+ */
+
+bool WncController::openSocketUrl(uint16_t numSock, const char * url, uint16_t port, bool tcp, uint16_t timeOutSec)
+{
+ if (resolveUrl(numSock, url) == true)
+ return (openSocket(numSock, port, tcp, timeOutSec));
+
+ return (false);
+}
+
+bool WncController::openSocketIpAddr(uint16_t numSock, const char * ipAddr, uint16_t port, bool tcp, uint16_t timeOutSec)
+{
+ if (setIpAddr(numSock, ipAddr) == true)
+ return (openSocket(numSock, port, tcp, timeOutSec));
+
+ return (false);
+}
+
+bool WncController::openSocket(uint16_t numSock, uint16_t port, bool tcp, uint16_t timeOutSec)
+{
+ if (numSock < MAX_NUM_WNC_SOCKETS) {
+ // IPV4 ip addr sanity check!
+ size_t lenIpStr = m_sSock[numSock].myIpAddressStr.size();
+ if (lenIpStr < 7 || lenIpStr > 15) {
+ dbgPuts("Invalid IP Address!");
+ return (false);
+ }
+
+ // Already open ? Must close if want to re-open with new settings.
+ if (m_sSock[numSock].open == true) {
+ dbgPuts("Socket already open, close then re-open!");
+ if (true == at_sockclose_wnc(m_sSock[numSock].numWncSock))
+ m_sSock[numSock].open = false;
+ else
+ return (false);
+ }
+
+ m_sSock[numSock].myPort = port;
+ m_sSock[numSock].isTcp = tcp;
+ m_sSock[numSock].timeOutSec = timeOutSec;
+
+ int16_t numWncSock = at_sockopen_wnc(m_sSock[numSock].myIpAddressStr.c_str(), port, numSock, tcp, timeOutSec);
+ m_sSock[numSock].numWncSock = numWncSock;
+ if (numWncSock > 0 && numWncSock <= MAX_NUM_WNC_SOCKETS)
+ m_sSock[numSock].open = true;
+ else {
+ m_sSock[numSock].open = false;
+ dbgPuts("Socket open fail!!!!");
+
+ // If the modem is not responding don't bother it.
+ if (WNC_NO_RESPONSE != getWncStatus()) {
+ // Work-around. If the sock open fails it needs to be told
+ // to close. If 6 sock opens happen with a fail, it further
+ // crashes the WNC. Not sure why the sock won't open.
+ at_sockclose_wnc(m_sSock[numSock].numWncSock);
+ }
+ }
+ }
+ else {
+ dbgPuts("Bad socket num or IP!");
+ return (false);
+ }
+
+ return (m_sSock[numSock].open);
+}
+
+/**
+ * \brief Write bytes of data to an open socket
+ *
+ * \param [in] sockNum - the number of the socket to write. s - a string containing
+ * the byte data to send must be less than = 1500.
+ *
+ * \return true - if the write was successful. false otherwise.
+ *
+ * \details The results of the write do not have anything to do with the data
+ * arriving at the endpoint.
+ */
+
+bool WncController::sockWrite(const char * const s, uint16_t n, uint16_t numSock, bool isTcp)
+{
+ bool result = true;
+
+ AtCmdErr_e cmdRes = at_sockwrite_wnc(s, n, m_sSock[numSock].numWncSock, isTcp);
+ if (cmdRes != WNC_AT_CMD_OK) {
+ if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME))
+ {
+ // This may throw away any data that hasn't been written out of the WNC
+ // but at this point with the way the WNC currently works we have
+ // no choice.
+ closeOpenSocket(numSock);
+ }
+ result = false;
+ }
+
+ return (result);
+}
+
+bool WncController::write(uint16_t numSock, const char * s, uint32_t n)
+{
+ bool result;
+
+ if (numSock < MAX_NUM_WNC_SOCKETS) {
+ if (m_sSock[numSock].open == true) {
+ if (n <= MAX_WNC_WRITE_BYTES) {
+ result = sockWrite(s, n, numSock, m_sSock[numSock].isTcp);
+ }
+ else {
+ uint16_t rem = n % MAX_WNC_WRITE_BYTES;
+ while (n >= MAX_WNC_WRITE_BYTES) {
+ n -= MAX_WNC_WRITE_BYTES;
+ result = sockWrite(s, MAX_WNC_WRITE_BYTES, numSock, m_sSock[numSock].isTcp);
+ if (result == false) {
+ n = 0;
+ rem = 0;
+ dbgPuts("Sock write fail!");
+ }
+ else
+ s += MAX_WNC_WRITE_BYTES;
+ }
+ if (rem > 0)
+ result = sockWrite(s, rem, numSock, m_sSock[numSock].isTcp);
+ }
+ }
+ else {
+ dbgPuts("Socket is closed for write!");
+ result = false;
+ }
+ }
+ else {
+ dbgPuts("Bad socket num!");
+ result = false;
+ }
+
+ return (result);
+}
+
+/**
+ * \brief Poll and read back data from the WNC (if it has any)
+ * If auto poll is enabled this read might fail (return with no data).
+ *
+ * \param [in] sockNum - the number of the socket to read. result - a string pointer containing
+ * the byte data readback from the WNC.
+ *
+ * \return The number of bytes/chars that are read from the socket.
+ *
+ * \details DO NOT use the same string as is passed to the auto poll setup method!
+ */
+
+size_t WncController::read(uint16_t numSock, const uint8_t ** readBuf)
+{
+ static string theBuf;
+ string readStr;
+
+ theBuf.erase(); // Clean-up from last time
+
+ if (numSock < MAX_NUM_WNC_SOCKETS) {
+ if (m_sSock[numSock].open == true) {
+ uint8_t i = m_sSock[numSock].readRetries;
+ uint16_t to = m_sSock[numSock].readRetryWaitMs;
+ bool foundData = false;
+ do {
+ AtCmdErr_e cmdRes;
+ cmdRes = at_sockread_wnc(&readStr, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp);
+ if (WNC_AT_CMD_OK == cmdRes) {
+ // This will let this loop read until the socket data is
+ // empty. If no data, then wait the retry amount of time.
+ if (readStr.size() > 0) {
+ theBuf += readStr;
+ foundData = true;
+ i = 1;
+ }
+ else {
+ // Once data is found start returning it asap
+ if (foundData == false)
+ waitMs(to);
+ }
+ }
+ else {
+ theBuf += readStr; // Append what if any we got before it errored.
+ dbgPuts("Sockread failed!");
+ if (WNC_NO_RESPONSE == getWncStatus()) {
+ i = 0;
+ }
+ else if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME))
+ {
+ // This may throw away any data that hasn't been read out of the WNC
+ // but at this point with the way the WNC currently works we have
+ // no choice.
+ closeOpenSocket(numSock);
+ i = 0;
+ }
+ else
+ waitMs(to);
+ }
+ } while (i-- > 0);
+ }
+ else {
+ dbgPuts("Socket is closed for read");
+ }
+ }
+ else {
+ dbgPuts("Bad socket num!");
+ }
+
+ *readBuf = (const uint8_t *)theBuf.c_str();
+
+ return (theBuf.size());
+}
+
+size_t WncController::read(uint16_t numSock, uint8_t * readBuf, uint32_t maxReadBufLen)
+{
+ uint32_t numCopied = 0;
+
+ if (numSock < MAX_NUM_WNC_SOCKETS) {
+ if (m_sSock[numSock].open == true) {
+ uint8_t i = m_sSock[numSock].readRetries;
+ uint16_t to = m_sSock[numSock].readRetryWaitMs;
+ bool foundData = false;
+ uint16_t numRead;
+ do {
+ AtCmdErr_e cmdRes;
+ if (maxReadBufLen < MAX_WNC_READ_BYTES)
+ cmdRes = at_sockread_wnc(readBuf, &numRead, maxReadBufLen, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp);
+ else
+ cmdRes = at_sockread_wnc(readBuf, &numRead, MAX_WNC_READ_BYTES, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp);
+
+ if (WNC_AT_CMD_OK == cmdRes) {
+ // This will let this loop read until the socket data is
+ // empty. If no data, then wait the retry amount of time.
+ if (numRead > 0) {
+ foundData = true;
+ i = 1;
+ if (numRead <= maxReadBufLen) {
+ maxReadBufLen -= numRead;
+ numCopied += numRead;
+ readBuf += numRead;
+ }
+ else {
+ i = 0; // No more room for data!
+ dbgPutsNoTime("No more room for read data!");
+ }
+ }
+ else {
+ // Once data is found start returning it asap
+ if (foundData == false)
+ waitMs(to);
+ }
+ }
+ else {
+ dbgPuts("Sockread failed!");
+ if (WNC_NO_RESPONSE == getWncStatus()) {
+ i = 0;
+ }
+ else if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME))
+ {
+ // This may throw away any data that hasn't been read out of the WNC
+ // but at this point with the way the WNC currently works we have
+ // no choice.
+ closeOpenSocket(numSock);
+ i = 0;
+ }
+ else
+ waitMs(to);
+ }
+ } while ((i-- > 0) && (maxReadBufLen > 0));
+ }
+ else {
+ dbgPuts("Socket is closed for read");
+ }
+ }
+ else {
+ dbgPuts("Bad socket num!");
+ }
+
+ return (numCopied);
+}
+
+/**
+ * \brief Set how many times the above read method will retry if data is not returned.
+ *
+ * \param [in] sockNum - the number of the socket to set. retries - how many times to
+ * poll until data is found.
+ *
+ * \return None.
+ *
+ * \details None.
+ */
+void WncController::setReadRetries(uint16_t numSock, uint16_t retries)
+{
+ if (numSock < MAX_NUM_WNC_SOCKETS)
+ m_sSock[numSock].readRetries = retries;
+ else
+ dbgPuts("Bad socket num!");
+}
+
+/**
+ * \brief Set how long between retries to wait.
+ *
+ * \param [in] sockNum - the number of the socket to set. readRetryWaitMs - how long to wait
+ * before doing the read poll (calling read(...)).
+ *
+ * \return None.
+ *
+ * \details None.
+ */
+void WncController::setReadRetryWait(uint16_t numSock, uint16_t readRetryWaitMs)
+{
+ if (numSock < MAX_NUM_WNC_SOCKETS)
+ m_sSock[numSock].readRetryWaitMs = readRetryWaitMs;
+ else
+ dbgPuts("Bad socket num!");
+}
+
+/**
+ * \brief Close the socket.
+ *
+ * \param [in] sockNum - the number of the socket to close.
+ *
+ * \return None.
+ *
+ * \details None.
+ */
+bool WncController::closeSocket(uint16_t numSock)
+{
+ if (numSock < MAX_NUM_WNC_SOCKETS) {
+
+ if (false == at_sockclose_wnc(m_sSock[numSock].numWncSock))
+ dbgPuts("Sock close may not have closed!");
+
+ // Even with an error the socket could have closed,
+ // can't tell for sure so just soft close it for now.
+ m_sSock[numSock].open = false;
+ }
+ else {
+ dbgPuts("Bad socket num!");
+ }
+
+ return (m_sSock[numSock].open == false);
+}
+
+// Note: If you want to make it more portable, create a
+// arecharsavailable() and readchar()
+size_t WncController::mdmGetline(string * buff, int timeout_ms)
+{
+ char chin = '\0';
+ char chin_last;
+ size_t len = 0;
+
+ startTimerB();
+ while ((len <= MAX_LEN_WNC_CMD_RESPONSE) && (getTimerTicksB_mS() < timeout_ms)) {
+ if (charReady()) {
+ chin_last = chin;
+ chin = getc();
+ if (isprint(chin)) {
+ *buff += chin;
+ len++; // Bound the copy length to something reaonable just in case
+ continue;
+ }
+ else if ((('\r' == chin_last) && ('\n' == chin)) || (('\n' == chin_last) && ('\r' == chin))) {
+ break;
+ }
+ }
+ }
+ stopTimerB();
+
+ if (len > MAX_LEN_WNC_CMD_RESPONSE)
+ dbgPuts("Max cmd length reply exceeded!");
+
+ return (len);
+}
+
+// Eventually this should try to reinstate the sockets open
+bool WncController::softwareInitMdm(void)
+{
+ static bool reportStatus = true;
+ unsigned i;
+
+ if (checkCellLink() == true) {
+ if (reportStatus == false) {
+ dbgPuts("Re-connected to cellular network!");
+ reportStatus = true;
+ }
+
+ // WNC has SIM and registered on network so
+ // soft initialize the WNC.
+ for (i = 0; i < WNC_SOFT_INIT_RETRY_COUNT; i++)
+ if (at_init_wnc() == true)
+ break;
+
+ // If it did not respond try a hardware init
+ if (i == WNC_SOFT_INIT_RETRY_COUNT)
+ {
+ at_reinitialize_mdm();
+ return (at_init_wnc(true)); // Hard reset occurred so make it go through the software init();
+ }
+ else
+ return (true);
+ }
+ else
+ {
+ if (reportStatus == true) {
+ dbgPuts("Not connected to cellular network!");
+ reportStatus = false;
+ }
+ return (false);
+ }
+}
+
+
+// Sets a global with failure or success, assumes 1 thread all the time
+WncController::AtCmdErr_e WncController::sendWncCmd(const char * const s, string ** r, int ms_timeout)
+{
+ if (checkCellLink() == false) {
+ static string noRespStr;
+
+ // Save some run-time!
+ if (m_sDebugEnabled)
+ {
+ dbgPuts("FAIL send cmd: ", false);
+ if (m_sMoreDebugEnabled && m_sDebugEnabled) {
+ dbgPutsNoTime(s);
+ }
+ else {
+ size_t n = strlen(s);
+ if (n <= WNC_TRUNC_DEBUG_LENGTH) {
+ dbgPutsNoTime(s);
+ }
+ else {
+ string truncStr(s,WNC_TRUNC_DEBUG_LENGTH/2);
+ truncStr += "..";
+ truncStr += &s[n-(WNC_TRUNC_DEBUG_LENGTH/2)];
+ dbgPutsNoTime(truncStr.c_str());
+ }
+ }
+ }
+
+ noRespStr.erase();
+ *r = &noRespStr;
+
+ return (WNC_AT_CMD_NO_CELL_LINK);
+ }
+
+ if (m_sCheckNetStatus)
+ {
+ if (m_sMoreDebugEnabled)
+ dbgPuts("[---------- Network Status -------------");
+ string * pRespStr;
+ at_send_wnc_cmd("AT@SOCKDIAL?", &pRespStr, m_sCmdTimeoutMs);
+ if (m_sMoreDebugEnabled)
+ dbgPuts("---------------------------------------]");
+ }
+
+ // If WNC ready, send user command
+ return (at_send_wnc_cmd(s, r, ms_timeout));
+}
+
+WncController::AtCmdErr_e WncController::at_send_wnc_cmd(const char * s, string ** r, int ms_timeout)
+{
+ // Save some run-time!
+ if (m_sDebugEnabled)
+ {
+ if (m_sMoreDebugEnabled) {
+ dbgPuts("TX: ", false); dbgPutsNoTime(s);
+ }
+ else {
+ if (m_sDebugEnabled) { // Save some run-time!
+ size_t n = strlen(s);
+ if (n <= WNC_TRUNC_DEBUG_LENGTH) {
+ dbgPuts("TX: ", false); dbgPutsNoTime(s);
+ }
+ else {
+ string truncStr(s,WNC_TRUNC_DEBUG_LENGTH/2);
+ truncStr += "..";
+ truncStr += &s[n - (WNC_TRUNC_DEBUG_LENGTH/2)];
+ dbgPuts("TX: ", false); dbgPutsNoTime(truncStr.c_str());
+ }
+ }
+ }
+ }
+
+ AtCmdErr_e atResult = mdmSendAtCmdRsp(s, ms_timeout, &m_sWncStr);
+ *r = &m_sWncStr; // Return a pointer to the static string
+
+ if (atResult != WNC_AT_CMD_TIMEOUT) {
+ // If a prior command timed out but a new one works then
+ // change the state back to ON. We don't know here in this
+ // method if the Cell Link is good so assume it is. When a command
+ // that depends on the cell link is made it will update the state.
+ if (m_sState == WNC_NO_RESPONSE)
+ m_sState = WNC_ON;
+
+ // Save some run-time!
+ if (m_sDebugEnabled)
+ {
+ dbgPuts("RX: ", false);
+ if (m_sMoreDebugEnabled) {
+ dbgPutsNoTime(m_sWncStr.c_str());
+ }
+ else {
+ if (m_sWncStr.size() <= WNC_TRUNC_DEBUG_LENGTH) {
+ dbgPutsNoTime(m_sWncStr.c_str());
+ }
+ else {
+ string truncStr = m_sWncStr.substr(0,WNC_TRUNC_DEBUG_LENGTH/2) + "..";
+ truncStr += m_sWncStr.substr(m_sWncStr.size() - (WNC_TRUNC_DEBUG_LENGTH/2), WNC_TRUNC_DEBUG_LENGTH/2);
+ dbgPutsNoTime(truncStr.c_str());
+ }
+ }
+ }
+ }
+ else {
+ m_sState = WNC_NO_RESPONSE;
+ dbgPuts("AT Cmd TIMEOUT!");
+ dbgPuts("RX: ", false); dbgPutsNoTime(m_sWncStr.c_str());
+ }
+
+ return (atResult);
+}
+
+void WncController::closeOpenSocket(uint16_t numSock)
+{
+ // Try to open and close the socket
+ do {
+ dbgPuts("Try to close and re-open socket");
+ if (false == at_sockclose_wnc(m_sSock[numSock].numWncSock)) {
+ if (WNC_NO_RESPONSE == getWncStatus()) {
+ dbgPuts("No response for closeOpenSocket1");
+ return ;
+ }
+ }
+
+ int numWncSock = at_sockopen_wnc(m_sSock[numSock].myIpAddressStr.c_str(), m_sSock[numSock].myPort, numSock, m_sSock[numSock].isTcp, m_sSock[numSock].timeOutSec);
+ m_sSock[numSock].numWncSock = numWncSock;
+ if (numWncSock > 0 && numWncSock <= MAX_NUM_WNC_SOCKETS)
+ m_sSock[numSock].open = true;
+ else {
+ m_sSock[numSock].open = false;
+ dbgPuts("Failed to re-open socket!");
+ }
+
+ if (WNC_NO_RESPONSE == getWncStatus()) {
+ dbgPuts("No response for closeOpenSocket2");
+ return ;
+ }
+ } while (m_sSock[numSock].open == false);
+}
+
+
+bool WncController::getICCID(string * iccid)
+{
+ if (at_geticcid_wnc(iccid) == false) {
+ dbgPuts("getICCID error!");
+ return (false);
+ }
+
+ return (true);
+}
+
+bool WncController::at_geticcid_wnc(string * iccid)
+{
+ string * respStr;
+
+ iccid->erase();
+
+ AtCmdErr_e r = at_send_wnc_cmd("AT%CCID", &respStr, m_sCmdTimeoutMs);
+
+ if (r != WNC_AT_CMD_OK || respStr->size() == 0)
+ return (false);
+
+ size_t pos = respStr->find("AT%CCID");
+ if (pos == string::npos)
+ return (false);
+
+ size_t posOK = respStr->rfind("OK");
+ if (posOK == string::npos)
+ return (false);
+
+ pos += 7; // Advanced to the number
+ *iccid = respStr->substr(pos, posOK - pos);
+
+ return (true);
+}
+
+
+bool WncController::convertICCIDtoMSISDN(const string & iccid, string * msisdn)
+{
+ msisdn->erase();
+
+ if (iccid.size() != 20 && iccid.size() != 19) {
+ dbgPuts("Invalid ICCID length!");
+ return (false);
+ }
+
+ *msisdn = "882350";
+
+ if (iccid.size() == 20)
+ *msisdn += iccid.substr(10,iccid.size() - 11);
+ else
+ *msisdn += iccid.substr(10,iccid.size() - 10);
+
+ return (true);
+}
+
+
+bool WncController::sendSMSText(const char * const phoneNum, const char * const text)
+{
+ if (at_sendSMStext_wnc(phoneNum, text) == true)
+ return (true);
+ else {
+ dbgPuts("sendSMSText: Failed!");
+ return (false);
+ }
+}
+
+bool WncController::readSMSLog(struct WncSmsList * log)
+{
+ string * logStr;
+ uint16_t i;
+
+ if (at_readSMSlog_wnc(&logStr) == false) {
+ dbgPuts("readSMSLog: Failed!");
+ return (false);
+ }
+
+ // Clean slate
+ log->msgCount = 0;
+
+ if (logStr->size() == 0)
+ return (false);
+
+ // Pick out the stuff from the string and convert to struct
+ string s;
+ size_t pos2;
+ size_t pos = logStr->find("+CMGL:");
+
+ for(i=0; i<MAX_WNC_SMS_MSG_SLOTS; i++) {
+ // Start with a clean slate, let parsing fill out later.
+ log->e[i].unread = false;
+ log->e[i].incoming = false;
+ log->e[i].unsent = false;
+ log->e[i].pduMode = false;
+ log->e[i].msgReceipt = false;
+
+ log->e[i].idx = logStr->at(pos + 7);
+ if (pos == string::npos)
+ return (false);
+ pos2 = logStr->find(",\"", pos);
+ if (pos2 == string::npos) {
+ // If the WNC acts wrong and receives a PDU mode
+ // SMS there will not be any quotes in the response,
+ // just take the whole reply and make it the message body for
+ // now, mark it as an unread message, set the pdu flag!
+ log->e[log->msgCount].unread = true;
+ log->e[log->msgCount].pduMode = true;
+ log->msgCount++;
+
+ pos2 = logStr->find("+CMGL", pos + 5);
+ if (pos2 == string::npos) {
+ pos2 = logStr->find("OK", pos + 5);
+ if (pos2 == string::npos) {
+ dbgPuts("Strange SMS Log Ending!");
+ return (false);
+ }
+ i = MAX_WNC_SMS_MSG_SLOTS;
+ }
+ log->e[log->msgCount].msg = logStr->substr(0, pos2 - pos);
+ pos = pos2; // for loop starts off expecting pos to point to next log msg
+ continue;
+ }
+ pos += 2; // Advance to the text we want
+ pos2 = logStr->find("\",", pos);
+ if ((pos2 == string::npos) || (pos >= pos2))
+ return (false);
+
+ // Setup attributes
+ s = logStr->substr(pos, pos2 - pos);
+ if (s.find("REC READ") != string::npos)
+ log->e[i].incoming = true;
+ if (s.find("REC UNREAD") != string::npos) {
+ log->e[i].unread = true;
+ log->e[i].incoming = true;
+ }
+ if (s.find("STO UNSENT") != string::npos)
+ log->e[i].unsent = true;
+ if (logStr->find(",,") == string::npos)
+ log->e[i].msgReceipt = true;
+
+ // Tele number
+ pos2 = logStr->find(",\"", pos2);
+ if (pos2 == string::npos)
+ return (false);
+ pos2 += 2; // Advance to next field
+ pos = logStr->find("\",", pos2);
+ if ((pos == string::npos) || (pos2 > pos))
+ return (false);
+ if (pos == pos2)
+ log->e[i].number.erase();
+ else
+ log->e[i].number = logStr->substr(pos2, pos - pos2);
+
+ // Date
+ pos = logStr->find(",\"", pos);
+ if (pos == string::npos)
+ return (false);
+ pos += 2; // Beginning of date field
+ pos2 = logStr->find(",", pos); // End of timestamp field
+ if ((pos2 == string::npos) || (pos > pos2))
+ return (false);
+ if (pos == pos2)
+ log->e[i].date.erase();
+ else
+ log->e[i].date = logStr->substr(pos, pos2 - pos);
+
+ // Timestamp
+ pos = logStr->find("\",", pos2); // End of timestamp
+ if (pos == string::npos)
+ return (false);
+ pos2 += 1; // Beginning of time field
+ if (pos < pos2)
+ return (false);
+ if (pos == pos2)
+ log->e[i].time.erase();
+ else
+ log->e[i].time = logStr->substr(pos2, pos - pos2);
+
+ // Message field
+
+ // We don't know how many messages we have so the next search
+ // could end with +CMGL or OK.
+ pos += 2; // Advanced to message text
+ pos2 = logStr->find("+CMGL", pos);
+ if (pos2 == string::npos) {
+ pos2 = logStr->find("OK", pos);
+ if (pos2 == string::npos) {
+ dbgPuts("Strange SMS Log Ending!");
+ return (false);
+ }
+ i = MAX_WNC_SMS_MSG_SLOTS; // break
+ }
+ if (pos > pos2)
+ return (false);
+ if (pos == pos2)
+ log->e[log->msgCount].msg.erase();
+ else
+ log->e[log->msgCount].msg = logStr->substr(pos, pos2 - pos);
+
+ log->msgCount++; // Message complete
+ }
+
+ return (true);
+}
+
+bool WncController::readUnreadSMSText(struct WncSmsList * w, bool deleteRead)
+{
+ struct WncController::WncSmsList tmp;
+
+ if (readSMSLog(&tmp) == false)
+ return (false);
+
+ w->msgCount = 0;
+ for(uint16_t i = 0; i < tmp.msgCount; i++) {
+ if (tmp.e[i].unread == true) {
+ w->e[w->msgCount] = tmp.e[i];
+ w->msgCount++;
+ if (deleteRead == true) {
+ // Clean up message that was copied out and read
+ deleteSMSTextFromMem(w->e[i].idx);
+ }
+ }
+ }
+
+ return (w->msgCount > 0);
+}
+
+size_t WncController::getSignalQuality(const char ** log)
+{
+ size_t n;
+
+ n = at_getSignalQuality_wnc(log);
+ if (n == 0)
+ dbgPuts("readSMSText: Failed!");
+
+ return (n);
+}
+
+size_t WncController::at_getSignalQuality_wnc(const char ** log)
+{
+ string * pRespStr;
+ static string logStr;
+
+ logStr.erase();
+
+ if (at_send_wnc_cmd("AT%MEAS=\"0\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) {
+ logStr = *pRespStr;
+ logStr += "\r\n";
+ }
+ else
+ dbgPuts("AT%MEAS=0: failed!");
+
+ if (at_send_wnc_cmd("AT%MEAS=\"1\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) {
+ logStr += *pRespStr;
+ logStr += "\r\n";
+ }
+ else
+ dbgPuts("AT%MEAS=1: failed!");
+
+ if (at_send_wnc_cmd("AT%MEAS=\"2\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) {
+ logStr += *pRespStr;
+ logStr += "\r\n";
+ }
+ else
+ dbgPuts("AT%MEAS=2: failed!");
+
+ if (at_send_wnc_cmd("AT%MEAS=\"3\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) {
+ logStr += *pRespStr;
+ logStr += "\r\n";
+ }
+ else
+ dbgPuts("AT%MEAS=3: failed!");
+
+ if (at_send_wnc_cmd("AT%MEAS=\"4\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) {
+ logStr += *pRespStr;
+ logStr += "\r\n";
+ }
+ else
+ dbgPuts("AT%MEAS=4: failed!");
+
+ if (at_send_wnc_cmd("AT%MEAS=\"5\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) {
+ logStr += *pRespStr;
+ logStr += "\r\n";
+ }
+ else
+ dbgPuts("AT%MEAS=5: failed!");
+
+ if (at_send_wnc_cmd("AT%MEAS=\"8\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) {
+ logStr += *pRespStr;
+ logStr += "\r\n";
+ }
+ else
+ dbgPuts("AT%MEAS=8: failed!");
+
+ if (at_send_wnc_cmd("AT%MEAS=\"98\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) {
+ logStr += *pRespStr;
+ logStr += "\r\n";
+ }
+ else
+ dbgPuts("AT%MEAS=98: failed!");
+
+ *log = logStr.c_str();
+
+ return (logStr.size());
+}
+
+bool WncController::getTimeDate(struct WncDateTime * tod)
+{
+ if (at_gettimedate_wnc(tod) == true)
+ return (true);
+ else {
+ dbgPuts("Get time date failed!");
+ return (false);
+ }
+}
+
+bool WncController::at_ping_wnc(const char * ip)
+{
+ string * pRespStr;
+ string cmdStr = "AT@PINGREQ=\"";
+ cmdStr += ip;
+ cmdStr += "\"";
+ return (at_send_wnc_cmd(cmdStr.c_str(), &pRespStr, WNC_PING_CMD_TIMEOUT_MS) == WNC_AT_CMD_OK);
+}
+
+bool WncController::at_gettimedate_wnc(struct WncDateTime * tod)
+{
+ string * pRespStr;
+ char * pEnd;
+
+ if (at_send_wnc_cmd("AT+CCLK?", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) {
+ if (pRespStr->size() > 0) {
+ size_t pos1 = pRespStr->find("+CCLK:");
+ if (pos1 != string::npos) {
+ pEnd = (char *)pRespStr->c_str() + pos1 + 8;
+ tod->year = strtol(pEnd, &pEnd, 10);
+ tod->month = strtol(pEnd+1, &pEnd, 10);
+ tod->day = strtol(pEnd+1, &pEnd, 10);
+ tod->hour = strtol(pEnd+1, &pEnd, 10);
+ tod->min = strtol(pEnd+1, &pEnd, 10);
+ tod->sec = strtol(pEnd+1, &pEnd, 10);
+ return (true);
+ }
+ }
+ }
+
+ return (false);
+}
+
+bool WncController::at_get_wnc_net_stats(WncIpStats * s)
+{
+ string * pRespStr;
+ AtCmdErr_e cmdRes = at_send_wnc_cmd("AT+CGCONTRDP=1", &pRespStr, m_sCmdTimeoutMs);
+
+ if (WNC_AT_CMD_OK == cmdRes) {
+ if (pRespStr->size() > 0) {
+ memset((void*)s, '\0', sizeof(*s)); // Clean-up
+ string ss;
+ size_t pe;
+ size_t ps = pRespStr->rfind("\"");
+ if (ps != string::npos) {
+ ps += 2; // Skip the , after the "
+ pe = ps;
+
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+
+ ss = pRespStr->substr(ps, pe - 1 - ps);
+ strncpy(s->ip, ss.c_str(), MAX_LEN_IP_STR);
+ s->ip[MAX_LEN_IP_STR - 1] = '\0';
+ ps = pe;
+
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(",", pe);
+
+ ss = pRespStr->substr(ps, pe - ps);
+ strncpy(s->mask, ss.c_str(), MAX_LEN_IP_STR);
+ s->mask[MAX_LEN_IP_STR - 1] = '\0';
+ ps = pe + 1;
+
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(",", pe);
+
+ ss = pRespStr->substr(ps, pe - ps);
+ strncpy(s->gateway, ss.c_str(), MAX_LEN_IP_STR);
+ s->gateway[MAX_LEN_IP_STR - 1] = '\0';
+ ps = pe + 1;
+
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(",", pe);
+
+
+ ss = pRespStr->substr(ps, pe - ps);
+ strncpy(s->dnsPrimary, ss.c_str(), MAX_LEN_IP_STR);
+ s->dnsPrimary[MAX_LEN_IP_STR - 1] = '\0';
+ ps = pe + 1;
+
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(".", pe);
+ if (pe == string::npos)
+ return (false);
+ else
+ pe += 1;
+ pe = pRespStr->find(",", pe);
+
+
+ ss = pRespStr->substr(ps, pe - ps);
+ strncpy(s->dnsSecondary, ss.c_str(), MAX_LEN_IP_STR);
+ s->dnsSecondary[MAX_LEN_IP_STR - 1] = '\0';
+
+ dbgPuts("~~~~~~~~~~ WNC IP Stats ~~~~~~~~~~~~");
+ dbgPuts("ip: ", false); dbgPutsNoTime(s->ip);
+ dbgPuts("mask: ", false); dbgPutsNoTime(s->mask);
+ dbgPuts("gateway: ", false); dbgPutsNoTime(s->gateway);
+ dbgPuts("dns pri: ", false); dbgPutsNoTime(s->dnsPrimary);
+ dbgPuts("dns sec: ", false); dbgPutsNoTime(s->dnsSecondary);
+ dbgPuts("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+
+ return (true);
+ }
+ }
+ }
+
+ return (false);
+}
+
+bool WncController::deleteSMSTextFromMem(char msgIdx)
+{
+ const char * err = "deleteSMSTextFromMem: Failed!";
+
+ switch (msgIdx)
+ {
+ case '*':
+ at_deleteSMSTextFromMem_wnc('1');
+ at_deleteSMSTextFromMem_wnc('2');
+ at_deleteSMSTextFromMem_wnc('3');
+ return (true); // WNC may error if slot empty, just ignore!
+
+ case '1':
+ case '2':
+ case '3':
+ if (true == at_deleteSMSTextFromMem_wnc(msgIdx))
+ return (true);
+ else {
+ dbgPuts(err);
+ return (false);
+ }
+
+ default:
+ dbgPuts(err);
+ return (false);
+ }
+}
+
+bool WncController::sendSMSTextFromMem(char msgIdx)
+{
+ const char * err = "deleteSMSTextFromMem: Failed!";
+
+ switch (msgIdx)
+ {
+ case '*':
+ at_sendSMStextMem_wnc('1');
+ at_sendSMStextMem_wnc('2');
+ at_sendSMStextMem_wnc('3');
+ return (true); // WNC may error if slot is empty, just ignore!
+
+ case '1':
+ case '2':
+ case '3':
+ if (at_sendSMStextMem_wnc(msgIdx) == true)
+ return (true);
+ else {
+ dbgPuts(err);
+ return (false);
+ }
+
+ default:
+ dbgPuts(err);
+ return (false);
+ }
+}
+
+bool WncController::at_deleteSMSTextFromMem_wnc(char n)
+{
+ string cmdStr, respStr;
+ // Message is stored in WNC, now send it!
+ cmdStr = "AT+CMGD=";
+ cmdStr += n;
+ cmdStr += "\r\n";
+ dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str(), false);
+ AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), m_sCmdTimeoutMs, &respStr);
+ dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str());
+ return (r == WNC_AT_CMD_OK);
+}
+
+bool WncController::at_sendSMStextMem_wnc(char n)
+{
+ string cmdStr, respStr;
+ // Message is stored in WNC, now send it!
+ cmdStr = "AT+CMSS=";
+ cmdStr += n;
+ cmdStr += "\r\n";
+ dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str(), false);
+ AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), m_sCmdTimeoutMs, &respStr);
+ dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str());
+ return (r == WNC_AT_CMD_OK);
+}
+
+bool WncController::at_sendSMStext_wnc(const char * const phoneNum, const char * const text)
+{
+ string respStr;
+ string * pRespStr;
+ size_t l = strlen(text);
+
+ if (l <= MAX_WNC_SMS_LENGTH)
+ {
+ // Check to see if the SMS service is available
+ checkCellLink();
+ if (m_sReadyForSMS == true) {
+ at_send_wnc_cmd("AT+CMGF=1", &pRespStr, m_sCmdTimeoutMs);
+ string cmdStr("AT+CMGS=\"");
+ cmdStr += phoneNum;
+ cmdStr += "\"";
+ dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str());
+ cmdStr += "\x0d"; // x0d = <ENTER>
+ // Send raw command with short timeout (the timeout will fail cause the WNC is not supposed to reply yet!
+ // And we want a delay before sending the actual text part of the string!
+ mdmSendAtCmdRsp(cmdStr.c_str(), 300, &respStr, false); // False turns off auto-addition of CR+LF (the WNC wants nothing here)
+ dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str());
+ if ((respStr.size() > 0) && (respStr.find("ERROR") == string::npos)) {
+ // Part 2 of the text, this is the actual text part:
+ cmdStr = text;
+ dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str());
+ cmdStr += "\x1A"; // <CTRL>-Z is what tells the WNC the message is complete to send!
+ AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), 10000, &respStr);
+ dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str());
+ if (respStr.size() == 0)
+ return (false);
+ else
+ return (r == WNC_AT_CMD_OK);
+ }
+ }
+ }
+
+ return (false);
+}
+
+bool WncController::saveSMSText(const char * const phoneNum, const char * const text, char * msgIdx)
+{
+ if (at_saveSMStext_wnc(phoneNum, text, msgIdx) == true)
+ return (true);
+ else {
+ dbgPuts("saveSMSTextToMem: failed!\r\n");
+ return (false);
+ }
+}
+
+bool WncController::at_saveSMStext_wnc(const char * const phoneNum, const char * const text, char * msgIdx)
+{
+ string respStr;
+ size_t l = strlen(text);
+
+ if (l <= MAX_WNC_SMS_LENGTH)
+ {
+ // Check to see if the SMS service is available
+ checkCellLink();
+ if (m_sReadyForSMS == true) {
+ string cmdStr("AT+CMGW=\"");
+ cmdStr += phoneNum;
+ cmdStr += "\"";
+ dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str());
+ cmdStr += "\x0d"; // x0d = <ENTER>
+ // Send raw command with short timeout (the timeout will fail cause the WNC is not supposed to reply yet!
+ // And we want a delay before sending the actual text part of the string!
+ mdmSendAtCmdRsp(cmdStr.c_str(), 300, &respStr, false); // False turns off auto-addition of CR+LF (the WNC wants nothing here)
+ dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str());
+ if ((respStr.size() > 0) && (respStr.find("ERROR") == string::npos)) {
+ // Part 2 of the text, this is the actual text part:
+ cmdStr = text;
+ dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str());
+ cmdStr += "\x1A"; // <CTRL>-Z is what tells the WNC the message is complete to save!
+ AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), 10000, &respStr);
+ dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str());
+ if (respStr.size() > 0) {
+ // respStr will have the SMS index
+ size_t pos1 = respStr.find("+CMGW: ");
+ size_t pos2 = respStr.rfind("OK");
+ if (pos1 != string::npos && pos2 != string::npos) {
+ *msgIdx = *string(respStr.substr(pos1+7, 1)).c_str();
+ return (true);
+ }
+ else {
+ *msgIdx = '!';
+ }
+ }
+ }
+ }
+ }
+
+ return (false);
+}
+
+bool WncController::at_readSMSlog_wnc(string ** log)
+{
+ return (at_send_wnc_cmd("AT+CMGL", log, m_sCmdTimeoutMs) == WNC_AT_CMD_OK);
+}
+
+size_t WncController::at_readSMStext_wnc(const char n, const char ** log)
+{
+ static string smsReadTxtStr;
+ string * pRespStr;
+ string cmdStr;
+
+ smsReadTxtStr.erase();
+ cmdStr = "AT+CMGR";
+ cmdStr += '1';
+ if (at_send_wnc_cmd("AT+CMGR", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK)
+ *log = pRespStr->c_str();
+ else
+ *log = "\0";
+
+ return (pRespStr->size());
+}
+
+bool WncController::at_at_wnc(void)
+{
+ string * pRespStr;
+ return (WNC_AT_CMD_OK == at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS)); // Heartbeat?
+}
+
+bool WncController::at_init_wnc(bool hardReset)
+{
+ string * pRespStr;
+ AtCmdErr_e cmdRes;
+
+ if (hardReset == true)
+ dbgPuts("Hard Soft Reset!");
+
+ dbgPuts("Start AT init of WNC:");
+
+ // Kick it twice to perhaps remove cued responses from an incomplete
+ // power cycle.
+ at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS);
+ at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS);
+
+ // Dump the firmware revision on the debug log:
+ at_send_wnc_cmd("AT+GMR", &pRespStr, m_sCmdTimeoutMs);
+
+ // Quick commands below do not need to check cellular connectivity
+ at_send_wnc_cmd("ATE0", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); // Echo Off
+ at_send_wnc_cmd("AT+CMEE=2", &pRespStr, m_sCmdTimeoutMs); // 2 - verbose error, 1 - numeric error, 0 - just ERROR
+
+ // Setup 3 memory slots in the WNC SIM for SMS usage.
+ at_send_wnc_cmd("AT+CMGF=1", &pRespStr, m_sCmdTimeoutMs);
+ at_send_wnc_cmd("AT+CPMS=\"SM\",\"SM\",\"SM\"", &pRespStr, m_sCmdTimeoutMs);
+
+ cmdRes = at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); // Heartbeat?
+
+ // If the simple commands are not working, no chance of more complex.
+ // I have seen re-trying commands make it worse.
+ if (cmdRes != WNC_AT_CMD_OK)
+ return (false);
+
+ cmdRes = at_send_wnc_cmd("AT@INTERNET=1", &pRespStr, m_sCmdTimeoutMs);
+ if (cmdRes != WNC_AT_CMD_OK)
+ return (false);
+
+ cmdRes = at_send_wnc_cmd("AT@SOCKDIAL=1", &pRespStr, m_sCmdTimeoutMs);
+ if (cmdRes != WNC_AT_CMD_OK)
+ return (false);
+
+ dbgPuts("SUCCESS: AT init of WNC!");
+
+ return (true);
+}
+
+
+int16_t WncController::at_sockopen_wnc(const char * const ip, uint16_t port, uint16_t numSock, bool tcp, uint16_t timeOutSec)
+{
+ string * pRespStr;
+ string cmd_str("AT@SOCKCREAT=");
+ AtCmdErr_e res;
+
+ if (tcp) cmd_str += "1"; // TCP
+ else cmd_str += "2"; // else UDP
+
+ cmd_str += ",0";
+ res = sendWncCmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs);
+ if (res == WNC_AT_CMD_OK && pRespStr->size() > 0)
+ {
+ size_t pos1 = pRespStr->find("T:");
+ size_t pos2 = pRespStr->rfind("OK");
+ if ((pos1 != string::npos) && (pos2 != string::npos)) {
+ size_t numLen = pos2 - (pos1 + 2);
+ string sockStr = pRespStr->substr(pos1 + 2, numLen);
+ cmd_str = "AT@SOCKCONN=";
+ cmd_str += sockStr;
+ cmd_str += ",\"";
+ cmd_str += ip;
+ cmd_str += "\",";
+ cmd_str += _to_string(port);
+ cmd_str += ",";
+ if (timeOutSec < 30)
+ timeOutSec = 30;
+ else if (timeOutSec > 360)
+ timeOutSec = 360;
+ cmd_str += _to_string(timeOutSec);
+ res = sendWncCmd(cmd_str.c_str(), &pRespStr, 1000 * timeOutSec + 1000);
+ if (m_sMoreDebugEnabled) {
+ at_send_wnc_cmd("AT@SOCKCREAT?", &pRespStr, m_sCmdTimeoutMs);
+ at_send_wnc_cmd("AT@SOCKCONN?", &pRespStr, m_sCmdTimeoutMs);
+ }
+ return (strtol(sockStr.c_str(), NULL, 10));
+ }
+ else {
+ dbgPuts("Invalid sockcreat response!");
+ return (0);
+ }
+ }
+ else
+ return (0);
+}
+
+bool WncController::at_sockclose_wnc(uint16_t numSock)
+{
+ string * pRespStr;
+ string cmd_str("AT@SOCKCLOSE=");
+
+ cmd_str += _to_string(numSock);
+
+ // Don't check the cell status to close the socket
+ AtCmdErr_e res = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs);
+
+ if ((res != WNC_AT_CMD_TIMEOUT) && (res != WNC_AT_CMD_OK)) {
+ for (unsigned i = 0; i < WNC_SOCK_CLOSE_RETRY_CNT; i++) {
+ res = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs);
+ if ((res == WNC_AT_CMD_TIMEOUT) || (res == WNC_AT_CMD_OK))
+ break;
+ }
+ }
+
+ return (res == WNC_AT_CMD_OK);
+}
+
+bool WncController::at_dnsresolve_wnc(const char * s, string * ipStr)
+{
+ string * pRespStr;
+ string str(s);
+ AtCmdErr_e r;
+
+ ipStr->erase(); // Clear out string until resolved!
+ str = "AT@DNSRESVDON=\"" + str;
+ str += "\"";
+ r = sendWncCmd(str.c_str(), &pRespStr, WNC_DNS_RESOLVE_WAIT_MS);
+ if (r == WNC_AT_CMD_OK && pRespStr->size() > 0) {
+ size_t pos_start = pRespStr->find(":\"") + 2;
+ if (pos_start != string::npos) {
+ size_t pos_end = pRespStr->find("\"", pos_start) - 1;
+ if (pos_end != string::npos) {
+ if (pos_end > pos_start) {
+ // Make a copy for use later (the source string is re-used)
+ *ipStr = pRespStr->substr(pos_start, pos_end - pos_start + 1);
+ return (true);
+ }
+ }
+ }
+ }
+
+ *ipStr = INVALID_IP_STR;
+
+ return (false);
+}
+
+bool WncController::waitForPowerOnModemToRespond(uint8_t timeoutSecs)
+{
+ // Now, give the modem x seconds to start responding by
+ // sending simple 'AT' commands to modem once per second.
+ if (timeoutSecs > 0) {
+ do {
+ timeoutSecs--;
+ dbgPutsNoTime("\rWaiting ", false); dbgPutsNoTime(_to_string(timeoutSecs), false);
+ dbgPutsNoTime(" ", false);
+ AtCmdErr_e rc = mdmSendAtCmdRsp("AT", 500, &m_sWncStr);
+ if (rc == WNC_AT_CMD_OK) {
+ dbgPutsNoTime(""); // CR LF
+ return true; //timer.read();
+ }
+ waitMs(500);
+ }
+ while (timeoutSecs > 0);
+ dbgPutsNoTime(""); // CR LF
+ }
+
+ return (false);
+}
+
+WncController::AtCmdErr_e WncController::at_sockwrite_wnc(const char * s, uint16_t n, uint16_t numSock, bool isTcp)
+{
+ AtCmdErr_e result;
+
+ if ((n > 0) && (n <= MAX_WNC_WRITE_BYTES)) {
+ string * pRespStr;
+ const char * num2str;
+ string cmd_str;
+
+ if (isTcp == true)
+ cmd_str="AT@SOCKWRITE=";
+ else
+ cmd_str="AT@SOCKWRITE="; // "AT@SOCKSEND=";
+
+ cmd_str += _to_string(numSock);
+ cmd_str += ",";
+ cmd_str += _to_string(n);
+ cmd_str += ",\"";
+ while(n > 0) {
+ n--;
+ num2str = _to_hex_string((uint8_t)*s++);
+ // Always 2-digit ascii hex:
+ if (num2str[1] == '\0')
+ cmd_str += '0';
+ cmd_str += num2str;
+ }
+ cmd_str += "\"";
+ result = sendWncCmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs);
+ }
+ else {
+ dbgPuts("sockwrite Err, string len bad!");
+ result = WNC_AT_CMD_ERR;
+ }
+
+ return (result);
+}
+
+WncController::AtCmdErr_e WncController::at_sockread_wnc(string * pS, uint16_t numSock, bool isTcp)
+{
+ AtCmdErr_e result = WNC_AT_CMD_OK;
+
+ string * pRespStr;
+ string cmd_str;
+ size_t pos_start, pos_end;
+ int i;
+
+ pS->erase(); // Start with a fresh string
+
+ if (isTcp == true)
+ cmd_str="AT@SOCKREAD=";
+ else
+ cmd_str="AT@SOCKREAD="; // "AT@SOCKRECV=";
+
+ cmd_str += _to_string(numSock);
+ cmd_str += ",";
+ cmd_str += _to_string(MAX_WNC_READ_BYTES);
+
+ // Experimental: read should not need to check cell net status
+ result = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs);
+ if (result == WNC_AT_CMD_OK) {
+ if (pRespStr->size() > 0) {
+ pos_start = pRespStr->find("\"");
+ pos_end = pRespStr->rfind("\"");
+ // Make sure search finds what it's looking for!
+ if (pos_start != string::npos && pos_end != string::npos) {
+ pos_start++;
+ i = pos_end - pos_start; // Num hex chars, 2 per byte
+ }
+ else
+ i = 0;
+ }
+ else
+ i = 0;
+
+ if ((i < 0) || ((i % 2) == 1))
+ dbgPuts("Invalid READ string!");
+
+ if (i > 2*MAX_WNC_READ_BYTES) {
+ i = 2*MAX_WNC_READ_BYTES;
+ dbgPuts("DANGER WNC read data does not match length!");
+ }
+
+ // If data, convert the hex string into byte values
+ while (i > 0) {
+ i -= 2;
+ *pS += (uint8_t)strtol(pRespStr->substr(pos_start, 2).c_str(), NULL, 16);
+ pos_start += 2;
+ }
+ }
+
+ return (result);
+}
+
+WncController::AtCmdErr_e WncController::at_sockread_wnc(uint8_t * pS, uint16_t * numRead, uint16_t n, uint16_t numSock, bool isTcp)
+{
+ AtCmdErr_e result = WNC_AT_CMD_OK;
+ *numRead = 0;
+
+ if ((n > 0) && (n <= MAX_WNC_READ_BYTES)) {
+ string * pRespStr;
+ string cmd_str;
+ size_t pos_start, pos_end;
+ int i;
+
+ if (isTcp == true)
+ cmd_str="AT@SOCKREAD=";
+ else
+ cmd_str="AT@SOCKREAD="; // "AT@SOCKRECV=";
+
+ cmd_str += _to_string(numSock);
+ cmd_str += ",";
+ cmd_str += _to_string(n);
+
+ // Experimental: read should not need to check cell net status
+ result = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs);
+ if (result == WNC_AT_CMD_OK) {
+ if (pRespStr->size() > 0) {
+ pos_start = pRespStr->find("\"");
+ pos_end = pRespStr->rfind("\"");
+ // Make sure search finds what it's looking for!
+ if (pos_start != string::npos && pos_end != string::npos) {
+ pos_start++;
+ i = pos_end - pos_start; // Num hex chars, 2 per byte
+ }
+ else
+ i = 0;
+ }
+ else
+ i = 0;
+
+ if ((i < 0) || ((i % 2) == 1))
+ dbgPuts("Invalid READ string!");
+
+ if (i > 2*n) {
+ // Bound the ill formated WNC read string!
+ i = 2*n;
+ dbgPuts("TRUNCATING read data!");
+ }
+
+ // If data, convert the hex string into byte values
+ i /= 2;
+ *numRead = i;
+ while (i > 0) {
+ i--;
+ *pS++ = (uint8_t)strtol(pRespStr->substr(pos_start, 2).c_str(), NULL, 16);
+ pos_start += 2;
+ }
+ }
+ }
+ else {
+ dbgPuts("sockread Err, to many to read!");
+ result = WNC_AT_CMD_ERR;
+ }
+
+ return (result);
+}
+
+bool WncController::at_reinitialize_mdm(void)
+{
+ // Atempt to re-register
+// string * pRespStr;
+// dbgPuts("Force re-register!");
+// at_send_wnc_cmd("AT+CFUN=0,0", &pRespStr, m_sCmdTimeoutMs);
+// waitMs(31000);
+// at_send_wnc_cmd("AT+CFUN=1,0", &pRespStr, m_sCmdTimeoutMs);
+// waitMs(31000);
+
+ // Initialize the modem
+ dbgPuts("Modem RE-initializing with SOFT Reset...");
+
+ string * pRespStr;
+ at_send_wnc_cmd("AT@DMREBOOT", &pRespStr, m_sCmdTimeoutMs);
+ waitMs(5000);
+
+ // Now, give the modem time to start responding by
+ // sending simple 'AT' commands to the modem once per second.
+ int timeoutSecs = WNC_REINIT_MAX_TIME_MS;
+ do {
+ dbgPuts("\rWaiting ", false); dbgPutsNoTime(_to_string(timeoutSecs), false);
+ AtCmdErr_e rc = mdmSendAtCmdRsp("AT", 500, &m_sWncStr);
+ if (rc == WNC_AT_CMD_OK) {
+ dbgPutsNoTime(""); // CR LF
+ break;
+ }
+ waitMs(500);
+ timeoutSecs--;
+ }
+ while (timeoutSecs > 0);
+
+ if (timeoutSecs <= 0)
+ dbgPuts("\r\nModem RE-init FAILED!");
+ else
+ dbgPuts("\r\nModem RE-init complete!");
+
+ return (timeoutSecs > 0);
+}
+
+WncController::AtCmdErr_e WncController::mdmSendAtCmdRsp(const char *cmd, int timeout_ms, string * rsp, bool crLf)
+{
+ rsp->erase(); // Clean up from possible prior cmd response
+
+ // Don't bother the WNC if user hasn't turned it on.
+ if (m_sState == WNC_OFF)
+ return (WNC_AT_CMD_WNC_NOT_ON);
+
+ size_t n = strlen(cmd);
+
+ // Wait per WNC advise
+ waitMs(WNC_WAIT_FOR_AT_CMD_MS);
+
+ if (cmd && n > 0) {
+ sendCmd(cmd, crLf);
+// sendCmd(cmd, n, 1000, crLf); // 3rd arg is micro seconds between chars sent
+ }
+
+ startTimerA();
+ while (getTimerTicksA_mS() < timeout_ms) {
+ n = mdmGetline(rsp, timeout_ms - getTimerTicksA_mS());
+
+ if (n == 0)
+ continue;
+
+ if (rsp->rfind("OK") != string::npos) {
+ stopTimerA();
+ return (WNC_AT_CMD_OK);
+ }
+
+ if (rsp->rfind("+CME ERROR") != string::npos) {
+ stopTimerA();
+ return (WNC_AT_CMD_ERRCME);
+ }
+
+ if (rsp->rfind("@EXTERR") != string::npos) {
+ stopTimerA();
+ return (WNC_AT_CMD_ERREXT);
+ }
+
+ if (rsp->rfind("ERROR") != string::npos) {
+ stopTimerA();
+ return (WNC_AT_CMD_ERR);
+ }
+ }
+ stopTimerA();
+
+ return (WNC_AT_CMD_TIMEOUT);
+}
+
+bool WncController::at_setapn_wnc(const char * const apnStr)
+{
+ string * pRespStr;
+
+ string cmd_str("AT%PDNSET=1,");
+ cmd_str += apnStr;
+ cmd_str += ",IP";
+ if (WNC_AT_CMD_OK == at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, WNC_APNSET_TIMEOUT_MS)) // Set APN, cmd seems to take a little longer sometimes
+ return (true);
+ else
+ return (false);
+}
+
+bool WncController::at_getrssiber_wnc(int16_t * dBm, int16_t * ber)
+{
+ string * pRespStr;
+ AtCmdErr_e cmdRes;
+ cmdRes = at_send_wnc_cmd("AT+CSQ", &pRespStr, m_sCmdTimeoutMs); // Check RSSI,BER
+ if (cmdRes != WNC_AT_CMD_OK)
+ return (false);
+
+ if (pRespStr->size() == 0) {
+ dbgPuts("Strange RSSI result!");
+ return (false);
+ }
+ else {
+ size_t pos1 = pRespStr->find("SQ:");
+ size_t pos2 = pRespStr->rfind(",");
+ // Sanity check
+ if ((pos1 != string::npos) && (pos2 != string::npos) && (pos2 > pos1)) {
+ string subStr = pRespStr->substr(pos1 + 4, pos2 - pos1 );
+ int rawRssi = atoi(subStr.c_str());
+
+ // Convert WNC RSSI into dBm range:
+ // 0 - -113 dBm
+ // 1 - -111 dBm
+ // 2..30 - -109 to -53 dBm
+ // 31 - -51dBm or >
+ // 99 - not known or not detectable
+ if (rawRssi == 99)
+ *dBm = -199;
+ else if (rawRssi == 0)
+ *dBm = -113;
+ else if (rawRssi == 1)
+ *dBm = -111;
+ else if (rawRssi == 31)
+ *dBm = -51;
+ else if (rawRssi >= 2 && rawRssi <= 30)
+ *dBm = -113 + 2 * rawRssi;
+ else {
+ dbgPuts("Invalid RSSI!");
+ return (false);
+ }
+ // Parse out BER: 0..7 as RXQUAL values in the table 3GPP TS 45.008 subclause 8.2.4
+ // 99 - unknown or undetectable
+ subStr = pRespStr->substr(pos2 + 1, pRespStr->length() - (pos2 + 1));
+ *ber = atoi(subStr.c_str());
+ }
+ else {
+ dbgPuts("Strange RSSI result2!");
+ return (false);
+ }
+ }
+
+ return (true);
+}
+
+bool WncController::checkCellLink(void)
+{
+ string * pRespStr;
+ size_t pos;
+ int regSts;
+ int cmdRes1, cmdRes2;
+
+ if (m_sState == WNC_OFF)
+ return (false);
+
+ m_sState = WNC_ON_NO_CELL_LINK;
+
+ if (m_sMoreDebugEnabled)
+ dbgPuts("<-------- Begin Cell Status ------------");
+
+ cmdRes1 = at_send_wnc_cmd("AT+CSQ", &pRespStr, m_sCmdTimeoutMs); // Check RSSI,BER
+
+ // If no response, don't bother with more commands
+ if (cmdRes1 != WNC_AT_CMD_TIMEOUT)
+ cmdRes2 = at_send_wnc_cmd("AT+CPIN?", &pRespStr, m_sCmdTimeoutMs); // Check if SIM locked
+ else {
+ if (m_sMoreDebugEnabled)
+ dbgPuts("------------ WNC No Response! --------->");
+
+ return (false);
+ }
+
+ if ((cmdRes1 != WNC_AT_CMD_OK) || (cmdRes2 != WNC_AT_CMD_OK) || (pRespStr->size() == 0))
+ {
+ if (m_sMoreDebugEnabled)
+ {
+ if ((cmdRes1 == WNC_AT_CMD_TIMEOUT) || (cmdRes2 == WNC_AT_CMD_TIMEOUT))
+ dbgPuts("------------ WNC No Response! --------->");
+ else
+ dbgPuts("------------ WNC Cmd Error! ----------->");
+ }
+
+ // If by a miracle it responds to the 2nd after the 1st, keep going
+ if ((cmdRes2 == WNC_AT_CMD_TIMEOUT) || (pRespStr->size() == 0))
+ return (false);
+ }
+
+ // If SIM Card not ready don't bother with commands!
+ if (pRespStr->find("CPIN: READY") == string::npos)
+ {
+ if (m_sMoreDebugEnabled)
+ dbgPuts("------------ WNC SIM Problem! --------->");
+
+ return (false);
+ }
+
+ // SIM card OK, now check for signal and cellular network registration
+ cmdRes1 = at_send_wnc_cmd("AT+CREG?", &pRespStr, m_sCmdTimeoutMs); // Check if registered on network
+ if (cmdRes1 != WNC_AT_CMD_OK || pRespStr->size() == 0)
+ {
+ if (m_sMoreDebugEnabled)
+ dbgPuts("------------ WNC +CREG? Fail! --------->");
+
+ return (false);
+ }
+ else
+ {
+ pos = pRespStr->find("CREG: ");
+ if (pos != string::npos)
+ {
+ // The registration is the 2nd arg in the comma separated list
+ *pRespStr = pRespStr->substr(pos+8, 1);
+ regSts = atoi(pRespStr->c_str());
+ switch (regSts) {
+ case 1:
+ case 5:
+ case 6:
+ case 7:
+ m_sReadyForSMS = true;
+ break;
+ default:
+ m_sReadyForSMS = false;
+ dbgPuts("SMS Service Down!");
+ }
+
+ // 1 - registered home, 5 - registered roaming
+ if ((regSts != 1) && (regSts != 5))
+ {
+ if (m_sMoreDebugEnabled)
+ dbgPuts("------ WNC Cell Link Down for Data! --->");
+
+ return (false);
+ }
+ }
+
+ if (m_sMoreDebugEnabled)
+ dbgPuts("------------ WNC Ready ---------------->");
+ }
+
+ // If we made it this far and the WNC did respond, keep the ON state
+ if (m_sState != WNC_NO_RESPONSE)
+ m_sState = WNC_ON;
+
+ return (true);
+}
+
+int WncController::dbgPutsNoTime(const char * s, bool crlf)
+{
+ if (m_sDebugEnabled == true) {
+ int r = dbgWriteChars(s);
+ if (crlf == true)
+ return (dbgWriteChars("\r\n"));
+ else
+ return (r);
+ }
+ else
+ return 0;
+};
+
+int WncController::dbgPuts(const char * s, bool crlf)
+{
+ dbgPutsNoTime("[*] ", false);
+ dbgPutsNoTime(_to_string(getLogTimerTicks()), false);
+ dbgPutsNoTime(" ", false);
+
+ int r = dbgPutsNoTime(s, false);
+
+ if (crlf == true)
+ return (dbgPutsNoTime("", true));
+ else
+ return (r);
+};
+
+void WncController::sendCmd(const char * cmd, bool crLf)
+{
+ puts(cmd);
+ if (crLf == true)
+ puts("\r\n");
+}
+
+// WNC used to have troubles handling full speed, seems to not need this now.
+void WncController::sendCmd(const char * cmd, unsigned n, unsigned wait_uS, bool crLf)
+{
+ while (n--) {
+ putc(*cmd++);
+ waitUs(wait_uS);
+ };
+ if (crLf == true) {
+ putc('\r');
+ waitUs(wait_uS);
+ putc('\n');
+ waitUs(wait_uS);
+ }
+}
+
+
+}; // End namespace WncController_fk
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/WncController/WncController.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,458 @@
+/*
+ Copyright (c) 2016 Fred Kellerman
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ @file WncController.h
+ @purpose Controls WNC Cellular Modem
+ @version 1.0
+ @date July 2016
+ @author Fred Kellerman
+
+ Notes: This code originates from the following mbed repository:
+
+ https://developer.mbed.org/teams/Avnet/code/WncControllerLibrary/
+*/
+
+
+#ifndef __WNCCONTROLLER_H_
+#define __WNCCONTROLLER_H_
+
+#include <string>
+#include <stdint.h>
+
+namespace WncController_fk {
+
+using namespace std;
+
+/**
+ * \file WncController.h
+ * \brief This mbed C++ class is for controlling the WNC
+ * Cellular modem via the AT command interface. This was
+ * developed with respect to version 1.3 of the WNC authored
+ * spec. This class is only designed to have 1 instantiation
+ * it is also not multi-thread safe.
+ */
+
+
+static const uint8_t MAX_LEN_IP_STR = 16; // Length includes room for the extra NULL
+
+/**
+ * \brief Contains info fields for the WNC Internet Attributes
+ */
+struct WncIpStats
+{
+ string wncMAC;
+ char ip[MAX_LEN_IP_STR];
+ char mask[MAX_LEN_IP_STR];
+ char gateway[MAX_LEN_IP_STR];
+ char dnsPrimary[MAX_LEN_IP_STR];
+ char dnsSecondary[MAX_LEN_IP_STR];
+};
+
+class WncController
+{
+public:
+ static const unsigned MAX_NUM_WNC_SOCKETS = 5; // Max number of simultaneous sockets that the WNC supports
+ static const unsigned MAX_POWERUP_TIMEOUT = 60; // How long the powerUp method will try to turn on the WNC Shield
+ // (this is the default if the user does not over-ride on power-up
+
+ // Tracks mode of the WNC Shield hardware
+ enum WncState_e {
+ WNC_OFF = 0,
+ WNC_ON, // This is intended to mean all systems go, including cell link up but socket may not be open
+ WNC_ON_NO_CELL_LINK,
+ WNC_NO_RESPONSE
+ };
+
+ /**
+ * \brief Constructor for UART controlled WNC
+ *
+ * \param [in] wnc_uart - Reference to a SerialBuffered object which will
+ * be used as the bus to control the WNC. apnStr = a text string for
+ * the cellular APN name.
+ *
+ * \return None.
+ *
+ * \details Adding another way to talk to the WNC, like I2C or USB,
+ * a constructor should be added for each type just like the SerialBuffered
+ * constructor below. Assumes UART is enabled, setup and ready to go. This
+ * class will read and write to this UART.
+ */
+ WncController(void);
+
+ // WncController( const char * const apnStr, MODSERIAL * wnc_uart, MODSERIAL * debug_uart = NULL);
+
+ /**
+ * \brief Used internally but also make public for a user of the Class to interrogate state as well.
+ *
+ * \param [in] None.
+ *
+ * \return The state of the WNC Modem.
+ *
+ * \details None.
+ */
+ WncState_e getWncStatus(void);
+
+ bool setApnName(const char * const apnStr);
+
+ /**
+ * \brief Return signal quality dBm level
+ *
+ * \param [in] None.
+ *
+ * \return The dBm signal level at the time of the request.
+ *
+ * \details This polls (at the time of the call) the cell signal.
+ */
+ int16_t getDbmRssi(void);
+ int16_t get3gBer(void);
+
+ /**
+ * \brief Power up and down (down not implemented yet)
+ *
+ * \param [in] NXP Pins that are critical for the initialization of the WNC Shield.
+ *
+ * \return true if request successful else false.
+ *
+ * \details Power-on works but not power-down. This will manipulate WNC Shield hardware
+ * and bring it to life. It will also initialize the WNC enough to get it to be able to open sockets
+ * (with AT commands)
+ */
+ bool powerWncOn(const char * const apn, uint8_t powerUpTimeoutSecs = MAX_POWERUP_TIMEOUT);
+
+ /**
+ * \brief Query the WNC modem for its Internet attributes
+ *
+ * \param [in] Pointer to a struct where to put the info.
+ *
+ * \return true if request successful else false.
+ *
+ * \details This method will do a few sanity checks and then gather the
+ * fields of the struct.
+ */
+ bool getWncNetworkingStats(WncIpStats * s);
+
+ /**
+ * \brief Look-up a URL text string and convert into an IP Address string.
+ *
+ * \param [in] url - the URL to lookup. numSock - the socket reference.
+ *
+ * \return true - if the IP address has been resolved. false - if the URL could not be resolved.
+ *
+ * \details None.
+ */
+ bool resolveUrl(uint16_t numSock, const char * url);
+
+ /**
+ * \brief Set IP Address string
+ *
+ * \param [in] numSock - socket reference to set the string for. ipStr - text string of the IP
+ * address you want to talk to. There is no sanity check - beware!!!
+ *
+ * \return true - if the IP address has been set. false - if the IP could not be set.
+ *
+ * \details None.
+ */
+ bool setIpAddr(uint16_t numSock, const char * ipStr);
+
+ /**
+ * \brief Opens a WNC socket.
+ *
+ * \param [in] sockNum - the number of the socket to open. ipAddr - a string containing
+ * the IP address. port - the IP port number to open the socket connection.
+ *
+ * \return true - if the socket is/was opened. false otherwise.
+ *
+ * \details None.
+ */
+ bool openSocket(uint16_t numSock, uint16_t port, bool tcp, uint16_t timeOutSec = 30);
+
+ bool openSocketUrl(uint16_t numSock, const char * url, uint16_t port, bool tcp, uint16_t timeOutSec = 30);
+
+ bool openSocketIpAddr(uint16_t numSock, const char * ipAddr, uint16_t port, bool tcp, uint16_t timeOutSec = 30);
+
+
+ /**
+ * \brief Write bytes of data to an open socket
+ *
+ * \param [in] sockNum - the number of the socket to write. s - a string containing
+ * the byte data to send.
+ *
+ * \return true - if the write was successful. false otherwise.
+ *
+ * \details The results of the write do not have anything to do with the data
+ * arriving at the endpoint.
+ */
+ bool write(uint16_t numSock, const char * s, uint32_t n);
+
+ /**
+ * \brief Poll and read back data from the WNC (if it has any)
+ * If auto poll is enabled this read might fail (return with no data).
+ *
+ * \param [in] sockNum - the number of the socket to read. result - a string pointer containing
+ * the byte data readback from the WNC.
+ *
+ * \return The number of bytes/chars that are read from the socket.
+ *
+ * \details DO NOT use the same string as is passed to the auto poll setup method!
+ */
+ size_t read(uint16_t numSock, uint8_t * readBuf, uint32_t maxReadBufLen);
+
+ size_t read(uint16_t numSock, const uint8_t ** readBuf);
+
+ /**
+ * \brief Set how many times the above read method will retry if data is not returned.
+ *
+ * \param [in] sockNum - the number of the socket to set. retries - how many times to
+ * poll until data is found.
+ *
+ * \return None.
+ *
+ * \details None.
+ */
+ void setReadRetries(uint16_t numSock, uint16_t retries);
+
+ /**
+ * \brief Set how long between retries to wait.
+ *
+ * \param [in] sockNum - the number of the socket to set. waitMs - how long to wait
+ * before doing the read poll (calling read(...)).
+ *
+ * \return None.
+ *
+ * \details None.
+ */
+ void setReadRetryWait(uint16_t numSock, uint16_t waitMs);
+
+ /**
+ * \brief Close the socket.
+ *
+ * \param [in] sockNum - the number of the socket to close.
+ *
+ * \return None.
+ *
+ * \details None.
+ */
+ bool closeSocket(uint16_t numSock);
+
+ void setWncCmdTimeout(uint16_t toMs);
+
+ bool getIpAddr(uint16_t numSock, char myIpAddr[MAX_LEN_IP_STR]);
+
+ void enableDebug(bool on, bool moreDebugOn);
+
+ ///////////////////////////////////////////
+ // SMS messaging
+ ///////////////////////////////////////////
+
+ static const uint16_t MAX_WNC_SMS_MSG_SLOTS = 3; // How many SMS messages the WNC can store and receive at a time.
+ static const uint16_t MAX_WNC_SMS_LENGTH = 160; // The maximum length of a 7-bit SMS message the WNC can send and receive.
+
+ struct WncSmsInfo
+ {
+ // Content
+ char idx;
+ string number;
+ string date;
+ string time;
+ string msg;
+
+ // Attributes
+ bool incoming;
+ bool unsent;
+ bool unread;
+ bool pduMode;
+ bool msgReceipt;
+ };
+
+ struct WncSmsList
+ {
+ uint8_t msgCount;
+ WncSmsInfo e[MAX_WNC_SMS_MSG_SLOTS];
+ };
+
+ bool sendSMSText(const char * const phoneNum, const char * const text);
+
+ bool readSMSLog(struct WncSmsList * log);
+
+ bool readUnreadSMSText(struct WncSmsList * w, bool deleteRead = true);
+
+ bool saveSMSText(const char * const phoneNum, const char * const text, char * msgIdx);
+
+ bool sendSMSTextFromMem(char msgIdx);
+
+ bool deleteSMSTextFromMem(char msgIdx);
+
+ bool getICCID(string * iccid);
+
+ bool convertICCIDtoMSISDN(const string & iccid, string * msisdn);
+
+ ///////////////////////////////////////////
+ // Neighborhood Cell Info
+ ///////////////////////////////////////////
+ size_t getSignalQuality(const char ** log);
+
+ // Date Time
+ struct WncDateTime
+ {
+ uint8_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t min;
+ uint8_t sec;
+ };
+
+ bool getTimeDate(struct WncDateTime * tod);
+
+ // Ping
+ bool pingUrl(const char * url);
+ bool pingIp(const char * ip);
+
+ // User command:
+ size_t sendCustomCmd(const char * cmd, char * resp, size_t sizeRespBuf, int ms_timeout);
+
+protected:
+
+ // Debug output methods
+ int dbgPutsNoTime(const char * s, bool crlf = true);
+ int dbgPuts(const char * s, bool crlf = true);
+ const char * _to_string(int64_t value);
+ const char * _to_hex_string(uint8_t value);
+
+ // Sends commands to WNC via
+ enum AtCmdErr_e {
+ WNC_AT_CMD_OK,
+ WNC_AT_CMD_ERR,
+ WNC_AT_CMD_ERREXT,
+ WNC_AT_CMD_ERRCME,
+ WNC_AT_CMD_INVALID_RESPONSE,
+ WNC_AT_CMD_TIMEOUT,
+ WNC_AT_CMD_NO_CELL_LINK,
+ WNC_AT_CMD_WNC_NOT_ON
+ };
+
+ // Users must define these functionalities:
+ virtual int putc(char c) = 0;
+ virtual int puts(const char * s) = 0;
+ virtual char getc(void) = 0;
+ virtual int charReady(void) = 0;
+ virtual int dbgWriteChar(char b) = 0;
+ virtual int dbgWriteChars(const char *b) = 0;
+ virtual void waitMs(int t) = 0;
+ virtual void waitUs(int t) = 0;
+ virtual bool initWncModem(uint8_t powerUpTimeoutSecs) = 0;
+
+ // Isolate OS timers
+ virtual int getLogTimerTicks(void) = 0;
+ virtual void startTimerA(void) = 0;
+ virtual void stopTimerA(void) = 0;
+ virtual int getTimerTicksA_mS(void) = 0;
+ virtual void startTimerB(void) = 0;
+ virtual void stopTimerB(void) = 0;
+ virtual int getTimerTicksB_mS(void) = 0;
+
+ bool waitForPowerOnModemToRespond(uint8_t powerUpTimeoutSecs);
+ AtCmdErr_e sendWncCmd(const char * const s, string ** r, int ms_timeout);
+
+private:
+
+ bool softwareInitMdm(void);
+ bool checkCellLink(void);
+ AtCmdErr_e mdmSendAtCmdRsp(const char * cmd, int timeout_ms, string * rsp, bool crLf = true);
+ size_t mdmGetline(string * buff, int timeout_ms);
+ bool at_at_wnc(void);
+ bool at_init_wnc(bool hardReset = false);
+ int16_t at_sockopen_wnc(const char * const ip, uint16_t port, uint16_t numSock, bool tcp, uint16_t timeOutSec);
+ bool at_sockclose_wnc(uint16_t numSock);
+ bool at_dnsresolve_wnc(const char * s, string * ipStr);
+ AtCmdErr_e at_sockwrite_wnc(const char * s, uint16_t n, uint16_t numSock, bool isTcp);
+ AtCmdErr_e at_sockread_wnc(uint8_t * pS, uint16_t * numRead, uint16_t n, uint16_t numSock, bool isTcp);
+ AtCmdErr_e at_sockread_wnc(string * pS, uint16_t numSock, bool isTcp);
+ bool at_reinitialize_mdm(void);
+ AtCmdErr_e at_send_wnc_cmd(const char * s, string ** r, int ms_timeout);
+ bool at_setapn_wnc(const char * const apnStr);
+ bool at_sendSMStext_wnc(const char * const phoneNum, const char * const text);
+ bool at_get_wnc_net_stats(WncIpStats * s);
+ bool at_readSMSlog_wnc(string ** log);
+ size_t at_readSMStext_wnc(const char ** log);
+ size_t at_readSMStext_wnc(const char n, const char ** log);
+ bool at_getrssiber_wnc(int16_t * dBm, int16_t * ber3g);
+ void closeOpenSocket(uint16_t numSock);
+ bool sockWrite(const char * const s, uint16_t n, uint16_t numSock, bool isTcp);
+ bool at_sendSMStextMem_wnc(char n);
+ bool at_deleteSMSTextFromMem_wnc(char n);
+ bool at_saveSMStext_wnc(const char * const phoneNum, const char * const text, char * msgIdx);
+ size_t at_getSignalQuality_wnc(const char ** log);
+ bool at_gettimedate_wnc(struct WncDateTime * tod);
+ bool at_ping_wnc(const char * ip);
+ bool at_geticcid_wnc(string * iccid);
+
+ // Utility methods
+ void sendCmd(const char * cmd, bool crLf);
+ void sendCmd(const char * cmd, unsigned n, unsigned wait_uS, bool crLf);
+ inline void rx_char_wait(void) {
+ // waitUs(1000);
+ }
+
+ // Important constants
+ static const uint16_t MAX_WNC_READ_BYTES = 1500; // This bounds the largest amount of data that the WNC read from a socket will return
+ static const uint16_t MAX_WNC_WRITE_BYTES = MAX_WNC_READ_BYTES; // This is the largest amount of data that the WNC can write per sockwrite.
+ static const uint16_t MAX_LEN_WNC_CMD_RESPONSE = (MAX_WNC_READ_BYTES * 2 + 100); // Max number of text characters in a WNC AT response *2 because bytes are converted into 2 hex-digits +100 for other AT@ chars.
+ static const uint16_t WNC_AUTO_POLL_MS = 250; // Sets default (may be overriden with method) poll interval (currently not used, future possible feature.
+ static const uint16_t WNC_CMD_TIMEOUT_MS = 40000; // Sets default (may be overriden) time that the software waits for an AT response from the WNC.
+ static const uint16_t WNC_QUICK_CMD_TIMEOUT_MS = 2000; // Used for simple commands that should immediately respond such as "AT", cmds that are quicker than WNC_CMD_TIMEOUT_MS.
+ static const uint16_t WNC_WAIT_FOR_AT_CMD_MS = 0; // Wait this much between multiple in a row AT commands to the WNC.
+ static const uint16_t WNC_SOFT_INIT_RETRY_COUNT = 10; // How many times the WNC will be tried to revive if it stops responding.
+ static const uint16_t WNC_DNS_RESOLVE_WAIT_MS = 60000; // How much time to wait for the WNC to respond to a DNS resolve/lookup.
+ static const uint16_t WNC_TRUNC_DEBUG_LENGTH = 80; // Always make this an even number, how many chars for the debug output before shortening the debug ouput, this is used when moreDebug = false.
+ static const uint16_t WNC_APNSET_TIMEOUT_MS = 60000; // How long to wait for the WNC to respond to setting the APN string.
+ static const uint16_t WNC_PING_CMD_TIMEOUT_MS = 60000; // Amount of time to wait for the WNC to respond to AT@PINGREQ (with cmd default params for timeout, does not change WNC cmd's timeout)
+ static const int WNC_REINIT_MAX_TIME_MS = 60000; // How long to wait for the WNC to reset after it was already up and running after power-up.
+ static const uint16_t WNC_SOCK_CLOSE_RETRY_CNT = 3; // How many times to try to close the socket if the WNC gives an error.
+ static const char * const INVALID_IP_STR; // Just a string set to an IP address when DNS resolve fails.
+
+ struct WncSocketInfo_s {
+ int16_t numWncSock;
+ bool open;
+ string myIpAddressStr;
+ uint16_t myPort;
+ uint8_t readRetries;
+ uint16_t readRetryWaitMs;
+ bool isTcp;
+ uint16_t timeOutSec;
+ };
+
+ static WncSocketInfo_s m_sSock[MAX_NUM_WNC_SOCKETS];
+ static const WncSocketInfo_s defaultSockStruct;
+ static WncState_e m_sState;
+ static uint16_t m_sCmdTimeoutMs;
+ static string m_sApnStr;
+ static string m_sWncStr;
+ static uint8_t m_sPowerUpTimeoutSecs;
+ static bool m_sDebugEnabled;
+ static bool m_sMoreDebugEnabled;
+ static bool m_sCheckNetStatus;
+ static bool m_sReadyForSMS;
+};
+
+}; // End namespace WncController_fk
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/WncControllerK64F.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,207 @@
+/*
+ Copyright (c) 2016 Fred Kellerman
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ @file WncController.cpp
+ @purpose Controls WNC Cellular Modem
+ @version 1.0
+ @date July 2016
+ @author Fred Kellerman
+*/
+
+#include "WncControllerK64F.h"
+
+using namespace WncControllerK64F_fk;
+
+WncControllerK64F::WncControllerK64F(struct WncGpioPinListK64F * pPins, MODSERIAL * wnc_uart, MODSERIAL * debug_uart)
+{
+ m_logTimer.start(); // Start the log timer now!
+ m_pDbgUart = debug_uart;
+ m_pWncUart = wnc_uart;
+ m_gpioPinList = *pPins;
+}
+
+bool WncControllerK64F::enterWncTerminalMode(MODSERIAL * pUart, bool echoOn)
+{
+ if (pUart == NULL)
+ return (false); // Need a uart!
+
+ string * resp;
+ AtCmdErr_e r = sendWncCmd("AT", &resp, 500);
+ if (r == WNC_AT_CMD_TIMEOUT)
+ return (false);
+
+ pUart->puts("\r\nEntering WNC Terminal Mode - press <CTRL>-Q to exit!\r\n");
+
+ while (1) {
+ if (pUart->readable()) {
+ char c = pUart->getc();
+ if (c == '\x11') {
+ pUart->puts("\r\nExiting WNC Terminal Mode!\r\n");
+ // Cleanup in case user doesn't finish command:
+ sendWncCmd("AT", &resp, 300);
+ // Above AT may fail but should get WNC back in sync
+ return (sendWncCmd("AT", &resp, 500) == WNC_AT_CMD_OK);
+ }
+ if (echoOn == true) {
+ pUart->putc(c);
+ }
+ m_pWncUart->putc(c);
+ }
+ if (m_pWncUart->readable())
+ pUart->putc(m_pWncUart->getc());
+ }
+}
+
+
+int WncControllerK64F::putc(char c)
+{
+ return (m_pWncUart->putc(c));
+}
+
+int WncControllerK64F::puts(const char * s)
+{
+ return (m_pWncUart->puts(s));
+}
+
+char WncControllerK64F::getc(void)
+{
+ return (m_pWncUart->getc());
+}
+
+int WncControllerK64F::charReady(void)
+{
+ return (m_pWncUart->readable());
+}
+
+int WncControllerK64F::dbgWriteChar(char b)
+{
+ if (m_pDbgUart != NULL)
+ return (m_pDbgUart->putc(b));
+ else
+ return (0);
+}
+
+int WncControllerK64F::dbgWriteChars(const char * b)
+{
+ if (m_pDbgUart != NULL)
+ return (m_pDbgUart->puts(b));
+ else
+ return (0);
+}
+
+bool WncControllerK64F::initWncModem(uint8_t powerUpTimeoutSecs)
+{
+ // Hard reset the modem (doesn't go through
+ // the signal level translator)
+ *m_gpioPinList.mdm_reset = 0;
+
+ // disable signal level translator (necessary
+ // for the modem to boot properly). All signals
+ // except mdm_reset go through the level translator
+ // and have internal pull-up/down in the module. While
+ // the level translator is disabled, these pins will
+ // be in the correct state.
+ *m_gpioPinList.shield_3v3_1v8_sig_trans_ena = 0;
+
+ // While the level translator is disabled and ouptut pins
+ // are tristated, make sure the inputs are in the same state
+ // as the WNC Module pins so that when the level translator is
+ // enabled, there are no differences.
+ *m_gpioPinList.mdm_uart2_rx_boot_mode_sel = 1; // UART2_RX should be high
+ *m_gpioPinList.mdm_power_on = 0; // powr_on should be low
+ *m_gpioPinList.mdm_wakeup_in = 1; // wake-up should be high
+ *m_gpioPinList.mdm_uart1_cts = 0; // indicate that it is ok to send
+
+ // Now, wait for the WNC Module to perform its initial boot correctly
+ waitMs(1000);
+
+ // The WNC module initializes comms at 115200 8N1 so set it up
+ m_pWncUart->baud(115200);
+
+ //Now, enable the level translator, the input pins should now be the
+ //same as how the M14A module is driving them with internal pull ups/downs.
+ //When enabled, there will be no changes in these 4 pins...
+ *m_gpioPinList.shield_3v3_1v8_sig_trans_ena = 1;
+
+ bool res = waitForPowerOnModemToRespond(powerUpTimeoutSecs);
+
+ // Toggle wakeup to prevent future dropped 'A' of "AT", this was
+ // suggested by ATT.
+ if (res == true) {
+ m_pDbgUart->puts("\r\nToggling Wakeup...\r\n");
+ waitMs(20);
+ *m_gpioPinList.mdm_wakeup_in = 0;
+ waitMs(2000);
+ *m_gpioPinList.mdm_wakeup_in = 1;
+ waitMs(20);
+ m_pDbgUart->puts("Toggling complete.\r\n");
+ }
+
+ return (res);
+}
+
+void WncControllerK64F::waitMs(int t)
+{
+ wait_ms(t);
+}
+
+void WncControllerK64F::waitUs(int t)
+{
+ wait_ms(t);
+}
+
+int WncControllerK64F::getLogTimerTicks(void)
+{
+ return (m_logTimer.read_us());
+}
+
+void WncControllerK64F::startTimerA(void)
+{
+ m_timerA.start();
+ m_timerA.reset();
+}
+
+void WncControllerK64F::stopTimerA(void)
+{
+ m_timerA.stop();
+}
+
+int WncControllerK64F::getTimerTicksA_mS(void)
+{
+ return (m_timerA.read_ms());
+}
+
+void WncControllerK64F::startTimerB(void)
+{
+ m_timerB.start();
+ m_timerB.reset();
+}
+
+void WncControllerK64F::stopTimerB(void)
+{
+ m_timerB.stop();
+}
+
+int WncControllerK64F::getTimerTicksB_mS(void)
+{
+ return (m_timerB.read_ms());
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WNCInterface/WncControllerK64F/WncControllerK64F.h Thu Dec 01 18:05:38 2016 +0000
@@ -0,0 +1,124 @@
+/*
+ Copyright (c) 2016 Fred Kellerman
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ @file WncController.h
+ @purpose Controls WNC Cellular Modem
+ @version 1.0
+ @date July 2016
+ @author Fred Kellerman
+*/
+
+#ifndef __WNCCONTROLLERK64F_H_
+#define __WNCCONTROLLERK64F_H_
+
+#include <string>
+#include <stdint.h>
+#include "mbed.h"
+#include "MODSERIAL.h"
+#include "WncController.h"
+
+namespace WncControllerK64F_fk {
+
+using namespace WncController_fk;
+using namespace std;
+
+struct WncGpioPinListK64F {
+ /////////////////////////////////////////////////////
+ // NXP GPIO Pins that are used to initialize the WNC Shield
+ /////////////////////////////////////////////////////
+ DigitalOut * mdm_uart2_rx_boot_mode_sel; // on powerup, 0 = boot mode, 1 = normal boot
+ DigitalOut * mdm_power_on; // 0 = turn modem on, 1 = turn modem off (should be held high for >5 seconds to cycle modem)
+ DigitalOut * mdm_wakeup_in; // 0 = let modem sleep, 1 = keep modem awake -- Note: pulled high on shield
+ DigitalOut * mdm_reset; // active high
+ DigitalOut * shield_3v3_1v8_sig_trans_ena; // 0 = disabled (all signals high impedence, 1 = translation active
+ DigitalOut * mdm_uart1_cts;
+};
+
+class WncControllerK64F : public WncController
+{
+public:
+ /**
+ * \brief Constructor for UART controlled WNC
+ *
+ * \param [in] wnc_uart - Reference to a SerialBuffered object which will
+ * be used as the bus to control the WNC. apnStr = a text string for
+ * the cellular APN name.
+ *
+ * \return None.
+ *
+ * \details Adding another way to talk to the WNC, like I2C or USB,
+ * a constructor should be added for each type just like the SerialBuffered
+ * constructor below. Assumes UART is enabled, setup and ready to go. This
+ * class will read and write to this UART.
+ */
+ WncControllerK64F(struct WncGpioPinListK64F * pPins, MODSERIAL * wnc_uart, MODSERIAL * debug_uart = NULL);
+
+ /**
+ * \brief Activates a mode where the user can send text to and from the K64F
+ * debug Serial port directly to the WNC.
+ *
+ * \param [in] echoOn - set to true to enable terminal echo
+ *
+ * \return true - if terminal mode was successfully entered and exited.
+ *
+ * \details Activates a mode where the user can send text to and from the K64F
+ * debug Serial port directly to the WNC. The mode is entered via this
+ * call. The mode is exited when the user types CTRL-Q. While in this
+ * mode all text to and from the WNC is consumed by the debug Serial port.
+ * No other methods in the class will receive any of the WNC output.
+ */
+ bool enterWncTerminalMode(MODSERIAL *pUart, bool echoOn);
+
+private:
+
+ // Disallow copy
+// WncControllerK64F operator=(WncControllerK64F lhs);
+
+ // Users must define these functionalities:
+ virtual int putc(char c);
+ virtual int puts(const char * s);
+ virtual char getc(void);
+ virtual int charReady(void);
+ virtual int dbgWriteChar(char b);
+ virtual int dbgWriteChars(const char *b);
+ virtual bool initWncModem(uint8_t powerUpTimeoutSecs);
+ virtual void waitMs(int t);
+ virtual void waitUs(int t);
+
+ virtual int getLogTimerTicks(void);
+ virtual void startTimerA(void);
+ virtual void stopTimerA(void);
+ virtual int getTimerTicksA_mS(void);
+ virtual void startTimerB(void);
+ virtual void stopTimerB(void);
+ virtual int getTimerTicksB_mS(void);
+
+ MODSERIAL * m_pDbgUart;
+ MODSERIAL * m_pWncUart;
+ WncGpioPinListK64F m_gpioPinList;
+ mbed::Timer m_logTimer;
+ mbed::Timer m_timerA;
+ mbed::Timer m_timerB;
+};
+
+}; // End namespace WncController_fk
+
+#endif
--- a/main.cpp Fri Oct 28 13:30:20 2016 +0100
+++ b/main.cpp Thu Dec 01 18:05:38 2016 +0000
@@ -1,448 +1,382 @@
/*
- * Hello world example of a TLS client: fetch an HTTPS page
- *
- * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
- * SPDX-License-Identifier: Apache-2.0
- *
- * 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.
- *
- * This file is part of mbed TLS (https://tls.mbed.org)
+ * AT&T IoT Starter Kit example using Amazon Web Service
*/
+#include "mbed.h"
+
+// Serial extension
+#include "MODSERIAL.h"
-/** \file main.cpp
- * \brief An example TLS Client application
- * This application sends an HTTPS request to developer.mbed.org and searches for a string in
- * the result.
- *
- * This example is implemented as a logic class (HelloHTTPS) wrapping a TCP socket.
- * The logic class handles all events, leaving the main loop to just check if the process
- * has finished.
- */
+// Network includes
+#include "WNCInterface.h"
+#include "network_interface.h"
-/* Change to a number between 1 and 4 to debug the TLS connection */
-#define DEBUG_LEVEL 0
-
-#include "mbed.h"
-#include "NetworkStack.h"
-
-#include "EthernetInterface.h"
-#include "TCPSocket.h"
-
-#include "mbedtls/platform.h"
-#include "mbedtls/ssl.h"
-#include "mbedtls/entropy.h"
-#include "mbedtls/ctr_drbg.h"
-#include "mbedtls/error.h"
+// AWS includes
+#include "aws_iot_log.h"
+#include "aws_iot_version.h"
+#include "aws_iot_shadow_interface.h"
+#include "aws_iot_shadow_json_data.h"
+#include "aws_iot_config.h"
+#include "aws_iot_mqtt_interface.h"
#if DEBUG_LEVEL > 0
#include "mbedtls/debug.h"
#endif
-namespace {
-
-const char *HTTPS_SERVER_NAME = "developer.mbed.org";
-const int HTTPS_SERVER_PORT = 443;
-const int RECV_BUFFER_SIZE = 600;
-
-const char HTTPS_PATH[] = "/media/uploads/mbed_official/hello.txt";
-const size_t HTTPS_PATH_LEN = sizeof(HTTPS_PATH) - 1;
-
-/* Test related data */
-const char *HTTPS_OK_STR = "200 OK";
-const char *HTTPS_HELLO_STR = "Hello world!";
-
-/* personalization string for the drbg */
-const char *DRBG_PERS = "mbed TLS helloword client";
+//=====================================================================================================================
+//
+// Defines
+//
+//=====================================================================================================================
+// LED Colors
+#define COLOR_OFF 0x00
+#define COLOR_RED 0x01
+#define COLOR_GREEN 0x02
+#define COLOR_BLUE 0x04
+#define COLOR_WHITE 0x07
+#define NUM_COLORS 5
-/* List of trusted root CA certificates
- * currently only GlobalSign, the CA for developer.mbed.org
- *
- * To add more than one root, just concatenate them.
- */
-const char SSL_CA_PEM[] = "-----BEGIN CERTIFICATE-----\n"
- "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n"
- "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n"
- "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n"
- "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n"
- "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n"
- "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n"
- "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n"
- "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n"
- "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n"
- "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n"
- "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n"
- "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n"
- "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n"
- "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n"
- "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n"
- "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n"
- "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n"
- "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n"
- "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n"
- "-----END CERTIFICATE-----\n";
-
-}
-
-/**
- * \brief HelloHTTPS implements the logic for fetching a file from a webserver
- * using a TCP socket and parsing the result.
- */
-class HelloHTTPS {
-public:
- /**
- * HelloHTTPS Constructor
- * Initializes the TCP socket, sets up event handlers and flags.
- *
- * @param[in] domain The domain name to fetch from
- * @param[in] port The port of the HTTPS server
- */
- HelloHTTPS(const char * domain, const uint16_t port, NetworkInterface *net_iface) :
- _domain(domain), _port(port)
- {
-
- _error = false;
- _gothello = false;
- _got200 = false;
- _bpos = 0;
- _request_sent = 0;
- _tcpsocket = new TCPSocket(net_iface);
+// AWS defines
+#define PATH_MAX 4096
+#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200 // NOTE: Be wary of this if your JSON doc grows
+#define SHADOW_SYNC_INTERVAL 3.0 // How often we sync with AWS Shadow (in seconds)
- mbedtls_entropy_init(&_entropy);
- mbedtls_ctr_drbg_init(&_ctr_drbg);
- mbedtls_x509_crt_init(&_cacert);
- mbedtls_ssl_init(&_ssl);
- mbedtls_ssl_config_init(&_ssl_conf);
- }
- /**
- * HelloHTTPS Desctructor
- */
- ~HelloHTTPS() {
- mbedtls_entropy_free(&_entropy);
- mbedtls_ctr_drbg_free(&_ctr_drbg);
- mbedtls_x509_crt_free(&_cacert);
- mbedtls_ssl_free(&_ssl);
- mbedtls_ssl_config_free(&_ssl_conf);
- }
- /**
- * Start the test.
- *
- * Starts by clearing test flags, then resolves the address with DNS.
- *
- * @param[in] path The path of the file to fetch from the HTTPS server
- * @return SOCKET_ERROR_NONE on success, or an error code on failure
- */
- void startTest(const char *path) {
- /* Initialize the flags */
- _got200 = false;
- _gothello = false;
- _error = false;
- _disconnected = false;
- _request_sent = false;
- /* Fill the request buffer */
- _bpos = snprintf(_buffer, sizeof(_buffer) - 1, "GET %s HTTP/1.1\nHost: %s\n\n", path, HTTPS_SERVER_NAME);
-
- /*
- * Initialize TLS-related stuf.
- */
- int ret;
- if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy,
- (const unsigned char *) DRBG_PERS,
- sizeof (DRBG_PERS))) != 0) {
- print_mbedtls_error("mbedtls_crt_drbg_init", ret);
- _error = true;
- return;
- }
-
- if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *) SSL_CA_PEM,
- sizeof (SSL_CA_PEM))) != 0) {
- print_mbedtls_error("mbedtls_x509_crt_parse", ret);
- _error = true;
- return;
- }
-
- if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf,
- MBEDTLS_SSL_IS_CLIENT,
- MBEDTLS_SSL_TRANSPORT_STREAM,
- MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
- print_mbedtls_error("mbedtls_ssl_config_defaults", ret);
- _error = true;
- return;
- }
-
- mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL);
- mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
-
- /* It is possible to disable authentication by passing
- * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode()
- */
- mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
-
-#if DEBUG_LEVEL > 0
- mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL);
- mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL);
- mbedtls_debug_set_threshold(DEBUG_LEVEL);
+// Comment out the following line if color is not supported on the terminal
+//#define USE_COLOR
+#ifdef USE_COLOR
+ #define BLK "\033[30m"
+ #define RED "\033[31m"
+ #define GRN "\033[32m"
+ #define YEL "\033[33m"
+ #define BLU "\033[34m"
+ #define MAG "\033[35m"
+ #define CYN "\033[36m"
+ #define WHT "\033[37m"
+ #define DEF "\033[39m"
+#else
+ #define BLK
+ #define RED
+ #define GRN
+ #define YEL
+ #define BLU
+ #define MAG
+ #define CYN
+ #define WHT
+ #define DEF
#endif
- if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) {
- print_mbedtls_error("mbedtls_ssl_setup", ret);
- _error = true;
- return;
- }
+//=====================================================================================================================
+//
+// Globals
+//
+//=====================================================================================================================
+// Controls LED color
+unsigned char ledColor = COLOR_OFF;
+
+// Color cycle array (used with SW3 button presses)
+unsigned char colorCycle[NUM_COLORS] = {COLOR_OFF, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_WHITE};
- mbedtls_ssl_set_hostname(&_ssl, HTTPS_SERVER_NAME);
+// Button interrupts
+bool buttonOverride = false;
+InterruptIn Interrupt(SW3);
+
+// Default cert location
+//char certDirectory[PATH_MAX + 1] = "../../../certs";
+
+// Default MQTT HOST URL is pulled from the aws_iot_config.h
+char HostAddress[255] = AWS_IOT_MQTT_HOST;
+
+// Default MQTT port is pulled from the aws_iot_config.h
+uint32_t port = AWS_IOT_MQTT_PORT;
- mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket),
- ssl_send, ssl_recv, NULL );
+//=====================================================================================================================
+//
+// Devices
+//
+//=====================================================================================================================
+// GPIOs for RGB LED
+DigitalOut led_green(LED_GREEN);
+DigitalOut led_red(LED_RED);
+DigitalOut led_blue(LED_BLUE);
+// USB Serial port (to PC)
+MODSERIAL pc(USBTX,USBRX,256,256);
- /* Connect to the server */
- mbedtls_printf("Connecting with %s\r\n", _domain);
- ret = _tcpsocket->connect(_domain, _port);
- if (ret != NSAPI_ERROR_OK) {
- mbedtls_printf("Failed to connect\r\n");
- onError(_tcpsocket, -1);
- return;
- }
+//=====================================================================================================================
+//
+// Functions
+//
+//=====================================================================================================================
+//*********************************************************************************************************************
+//* Prints the given format to the PC serial port. Exposed to all files via aws_iot_log.h
+//*********************************************************************************************************************
+void pc_print(const char * format, ...)
+{
+ va_list vl;
+ va_start(vl, format);
+ pc.vprintf(format, vl);
+ va_end(vl);
+}
- /* Start the handshake, the rest will be done in onReceive() */
- mbedtls_printf("Starting the TLS handshake...\r\n");
- ret = mbedtls_ssl_handshake(&_ssl);
- if (ret < 0) {
- if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
- ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
- print_mbedtls_error("mbedtls_ssl_handshake", ret);
- onError(_tcpsocket, -1 );
- }
- return;
- }
+//*********************************************************************************************************************
+//* Set the RGB LED's Color
+//* LED Color 0=Off to 7=White. 3 bits represent BGR (bit0=Red, bit1=Green, bit2=Blue)
+//*********************************************************************************************************************
+void SetLedColor(unsigned char ucColor)
+{
+ //Note that when an LED is on, you write a 0 to it:
+ led_red = !(ucColor & 0x1); //bit 0
+ led_green = !(ucColor & 0x2); //bit 1
+ led_blue = !(ucColor & 0x4); //bit 2
+}
- ret = mbedtls_ssl_write(&_ssl, (const unsigned char *) _buffer, _bpos);
- if (ret < 0) {
- if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
- ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
- print_mbedtls_error("mbedtls_ssl_write", ret);
- onError(_tcpsocket, -1 );
- }
- return;
- }
-
- /* It also means the handshake is done, time to print info */
- printf("TLS connection to %s established\r\n", HTTPS_SERVER_NAME);
+//*********************************************************************************************************************
+//* SW3 Button handler. Finds the current LED color and sets the button to the next color in colorCycle[]
+//*********************************************************************************************************************
+void sw3ButtonHandler()
+{
+ int i;
+ for(i=0; i < NUM_COLORS; i++) {
+ if (ledColor == colorCycle[i])
+ break;
+ }
+
+ // (circular-queue)
+ if (++i == NUM_COLORS)
+ i = 0;
+
+ ledColor = colorCycle[i];
+ SetLedColor(ledColor);
+ buttonOverride = true;
+}
- const uint32_t buf_size = 1024;
- char *buf = new char[buf_size];
- mbedtls_x509_crt_info(buf, buf_size, "\r ",
- mbedtls_ssl_get_peer_cert(&_ssl));
- mbedtls_printf("Server certificate:\r\n%s\r", buf);
+//=====================================================================================================================
+//
+// AWS Shadow Callbacks
+//
+//=====================================================================================================================
+//*********************************************************************************************************************
+//* This is the callback function that fires when an update is sent. It will print the update response status.
+//*********************************************************************************************************************
+void ShadowUpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
+ const char *pReceivedJsonDocument, void *pContextData) {
- uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
- if( flags != 0 )
- {
- mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags);
- printf("Certificate verification failed:\r\n%s\r\r\n", buf);
- }
- else
- printf("Certificate verification passed\r\n\r\n");
+ INFO("Shadow Update Status Callback");
+
+ if (status == SHADOW_ACK_TIMEOUT) {
+ INFO("Update Timeout--");
+ } else if (status == SHADOW_ACK_REJECTED) {
+ INFO("Update RejectedXX");
+ } else if (status == SHADOW_ACK_ACCEPTED) {
+ INFO("Update Accepted!!"); // Good
+ }
+}
-
- /* Read data out of the socket */
- ret = mbedtls_ssl_read(&_ssl, (unsigned char *) _buffer, sizeof(_buffer));
- if (ret < 0) {
- if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
- print_mbedtls_error("mbedtls_ssl_read", ret);
- onError(_tcpsocket, -1 );
- }
- delete[] buf;
- return;
+//*********************************************************************************************************************
+//* This is the callback function that fires when AWS has sends out a shadow update.
+//*********************************************************************************************************************
+void ledControl_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
+
+ INFO("LED Callback Detected.");
+
+ if (pContext != NULL) {
+ switch (*(unsigned char *)(pContext->pData)){
+ case COLOR_OFF:
+ INFO("LED -> OFF (%d)", *(unsigned char *)(pContext->pData));
+ break;
+ case COLOR_RED:
+ INFO("LED -> RED (%d)", *(unsigned char *)(pContext->pData));
+ break;
+ case COLOR_GREEN:
+ INFO("LED -> GREEN (%d)", *(unsigned char *)(pContext->pData));
+ break;
+ case COLOR_BLUE:
+ INFO("LED -> BLUE (%d)", *(unsigned char *)(pContext->pData));
+ break;
+ case COLOR_WHITE:
+ INFO("LED -> WHITE (%d)", *(unsigned char *)(pContext->pData));
+ break;
}
- _bpos = static_cast<size_t>(ret);
-
- _buffer[_bpos] = 0;
-
- /* Check each of the flags */
- _got200 = _got200 || strstr(_buffer, HTTPS_OK_STR) != NULL;
- _gothello = _gothello || strstr(_buffer, HTTPS_HELLO_STR) != NULL;
-
- /* Print status messages */
- mbedtls_printf("HTTPS: Received %d chars from server\r\n", _bpos);
- mbedtls_printf("HTTPS: Received 200 OK status ... %s\r\n", _got200 ? "[OK]" : "[FAIL]");
- mbedtls_printf("HTTPS: Received '%s' status ... %s\r\n", HTTPS_HELLO_STR, _gothello ? "[OK]" : "[FAIL]");
- mbedtls_printf("HTTPS: Received message:\r\n\r\n");
- mbedtls_printf("%s", _buffer);
- _error = !(_got200 && _gothello);
-
- _tcpsocket->close();
- delete[] buf;
+ }
+ else {
+ INFO("pContext was detected as NULL");
}
- /**
- * Check if the test has completed.
- * @return Returns true if done, false otherwise.
- */
- bool done() {
- return _error || (_got200 && _gothello);
- }
- /**
- * Check if there was an error
- * @return Returns true if there was an error, false otherwise.
- */
- bool error() {
- return _error;
+}
+
+//=====================================================================================================================
+//
+// Main
+//
+//=====================================================================================================================
+int main() {
+
+ // Set baud rate for PC Serial
+ pc.baud(115200);
+ INFO("Hello World from AT&T IoT Start Kit demo!");
+
+ IoT_Error_t rc = NONE_ERROR;
+ char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
+ size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);
+
+ // JSON struct for LED control
+ jsonStruct_t ledController;
+ ledController.cb = ledControl_Callback;
+ ledController.pData = &ledColor;
+ ledController.pKey = "ledColor";
+ ledController.type = SHADOW_JSON_UINT8;
+
+ // TODO Add FRDM temperature reading
+ /*
+ float temperature = 0.0;
+ jsonStruct_t temperatureHandler;
+ temperatureHandler.cb = NULL;
+ temperatureHandler.pKey = "temperature";
+ temperatureHandler.pData = &temperature;
+ temperatureHandler.type = SHADOW_JSON_FLOAT;
+ */
+
+ INFO("AWS IoT SDK Version(dev) %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
+
+ // TODO: We could try to pull the certs from an SD card
+ /*
+ char rootCA[PATH_MAX + 1];
+ char clientCRT[PATH_MAX + 1];
+ char clientKey[PATH_MAX + 1];
+ char CurrentWD[PATH_MAX + 1];
+ char cafileName[] = AWS_IOT_ROOT_CA_FILENAME;
+ char clientCRTName[] = AWS_IOT_CERTIFICATE_FILENAME;
+ char clientKeyName[] = AWS_IOT_PRIVATE_KEY_FILENAME;
+
+ getcwd(CurrentWD, sizeof(CurrentWD));
+ sprintf(rootCA, "%s/%s/%s", CurrentWD, certDirectory, cafileName);
+ sprintf(clientCRT, "%s/%s/%s", CurrentWD, certDirectory, clientCRTName);
+ sprintf(clientKey, "%s/%s/%s", CurrentWD, certDirectory, clientKeyName);
+
+ DEBUG("Using rootCA %s", rootCA);
+ DEBUG("Using clientCRT %s", clientCRT);
+ DEBUG("Using clientKey %s", clientKey);
+ */
+
+ // Blinks through RGB then turns off
+ SetLedColor(COLOR_RED);
+ wait(.5);
+ SetLedColor(COLOR_GREEN);
+ wait(.5);
+ SetLedColor(COLOR_BLUE);
+ wait(.5);
+ SetLedColor(COLOR_OFF);
+
+ // Setup SW3 button to falling edge interrupt
+ Interrupt.fall(&sw3ButtonHandler);
+
+ // Boot the Avnet Shield before any other operations
+ net_modem_boot();
+
+ INFO("Initialize the MQTT client...");
+ MQTTClient_t mqttClient;
+ aws_iot_mqtt_init(&mqttClient);
+
+ ShadowParameters_t sp = ShadowParametersDefault;
+ sp.pMyThingName = AWS_IOT_MY_THING_NAME;
+ sp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID;
+ sp.pHost = HostAddress;
+ sp.port = port;
+ //sp.pClientCRT = clientCRT;
+ //sp.pClientKey = clientKey;
+ //sp.pRootCA = rootCA;
+ sp.pClientCRT = AWS_IOT_CERTIFICATE_FILENAME;
+ sp.pClientKey = AWS_IOT_PRIVATE_KEY_FILENAME;
+ sp.pRootCA = AWS_IOT_ROOT_CA_FILENAME;
+
+ INFO("Shadow Init...");
+ rc = aws_iot_shadow_init(&mqttClient);
+ if (NONE_ERROR != rc) {
+ ERROR("Shadow Init Error %d", rc);
+ return rc;
}
- /**
- * Closes the TCP socket
- */
- void close() {
- _tcpsocket->close();
- while (!_disconnected)
- __WFI();
- }
-protected:
- /**
- * Helper for pretty-printing mbed TLS error codes
- */
- static void print_mbedtls_error(const char *name, int err) {
- char buf[128];
- mbedtls_strerror(err, buf, sizeof (buf));
- mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf);
+
+ INFO("Shadow Connect...");
+ rc = aws_iot_shadow_connect(&mqttClient, &sp);
+ if (NONE_ERROR != rc) {
+ ERROR("Shadow Connection Error %d", rc);
+ return rc;
}
-#if DEBUG_LEVEL > 0
- /**
- * Debug callback for mbed TLS
- * Just prints on the USB serial port
- */
- static void my_debug(void *ctx, int level, const char *file, int line,
- const char *str)
- {
- const char *p, *basename;
- (void) ctx;
+ // Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
+ // #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
+ // #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
+ rc = mqttClient.setAutoReconnectStatus(true);
+ if (NONE_ERROR != rc) {
+ ERROR("Unable to set Auto Reconnect to true - %d", rc);
+ return rc;
+ }
+
+ // Example line of how to delete a shadow (not used in this demo)
+ //aws_iot_shadow_delete(&mqttClient, AWS_IOT_MY_THING_NAME, ShadowUpdateStatusCallback, NULL, 8, true);
- /* Extract basename from file */
- for(p = basename = file; *p != '\0'; p++) {
- if(*p == '/' || *p == '\\') {
- basename = p + 1;
+ INFO("Shadow Register Delta...");
+ rc = aws_iot_shadow_register_delta(&mqttClient, &ledController);
+ if (NONE_ERROR != rc) {
+ ERROR("Shadow Register Delta Error");
+ return rc;
+ }
+
+ INFO("Will attempt to sync with device shadow every %f seconds.", SHADOW_SYNC_INTERVAL);
+ // Loop and publish changes from the FRDM board
+ while (NETWORK_ATTEMPTING_RECONNECT == rc || RECONNECT_SUCCESSFUL == rc || NONE_ERROR == rc) {
+
+ // Looks for incoming socket messages
+ rc = aws_iot_shadow_yield(&mqttClient, 200);
+ if (NETWORK_ATTEMPTING_RECONNECT == rc) {
+ // If the client is attempting to reconnect we will skip the rest of the loop.
+ INFO("Attempting to reconnect...");
+ wait(1);
+ continue;
+ }
+
+ INFO("\n=======================================================================================\n");
+ // Initialize JSON shadow document
+ rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
+ if (rc == NONE_ERROR) {
+
+ // If there has been a SW3 button press update the 'desired' color
+ if (buttonOverride) {
+ rc = aws_iot_shadow_add_desired(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 1, &ledController);
+ buttonOverride = false;
}
- }
-
- mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
+
+ // Updates the 'reported' color
+ rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 1, &ledController);
+
+ // TODO: format for adding temperature
+ //rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 2, &ledController, &temperatureHandler);
+
+ if (rc == NONE_ERROR) {
+ rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
+
+ if (rc == NONE_ERROR) {
+ INFO("Update Shadow: %s", JsonDocumentBuffer);
+ rc = aws_iot_shadow_update(&mqttClient, AWS_IOT_MY_THING_NAME, JsonDocumentBuffer,
+ ShadowUpdateStatusCallback, NULL, 8, true);
+ }
+ }
+ }
+ INFO("*****************************************************************************************\n");
+
+ // Set LED color then wait an loop again
+ SetLedColor(ledColor);
+ wait(SHADOW_SYNC_INTERVAL);
}
- /**
- * Certificate verification callback for mbed TLS
- * Here we only use it to display information on each cert in the chain
- */
- static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
- {
- const uint32_t buf_size = 1024;
- char *buf = new char[buf_size];
- (void) data;
-
- mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
- mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt);
- mbedtls_printf("%s", buf);
-
- if (*flags == 0)
- mbedtls_printf("No verification issue for this certificate\n");
- else
- {
- mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags);
- mbedtls_printf("%s\n", buf);
- }
-
- delete[] buf;
- return 0;
- }
-#endif
-
- /**
- * Receive callback for mbed TLS
- */
- static int ssl_recv(void *ctx, unsigned char *buf, size_t len) {
- int recv = -1;
- TCPSocket *socket = static_cast<TCPSocket *>(ctx);
- recv = socket->recv(buf, len);
-
- if(NSAPI_ERROR_WOULD_BLOCK == recv){
- return MBEDTLS_ERR_SSL_WANT_READ;
- }else if(recv < 0){
- return -1;
- }else{
- return recv;
- }
- }
-
- /**
- * Send callback for mbed TLS
- */
- static int ssl_send(void *ctx, const unsigned char *buf, size_t len) {
- int size = -1;
- TCPSocket *socket = static_cast<TCPSocket *>(ctx);
- size = socket->send(buf, len);
-
- if(NSAPI_ERROR_WOULD_BLOCK == size){
- return len;
- }else if(size < 0){
- return -1;
- }else{
- return size;
- }
+ if (NONE_ERROR != rc) {
+ ERROR("An error occurred in the loop %d", rc);
}
- void onError(TCPSocket *s, int error) {
- printf("MBED: Socket Error: %d\r\n", error);
- s->close();
- _error = true;
+ INFO("Disconnecting");
+ rc = aws_iot_shadow_disconnect(&mqttClient);
+
+ if (NONE_ERROR != rc) {
+ ERROR("Disconnect error %d", rc);
}
-protected:
- TCPSocket* _tcpsocket;
-
- const char *_domain; /**< The domain name of the HTTPS server */
- const uint16_t _port; /**< The HTTPS server port */
- char _buffer[RECV_BUFFER_SIZE]; /**< The response buffer */
- size_t _bpos; /**< The current offset in the response buffer */
- volatile bool _got200; /**< Status flag for HTTPS 200 */
- volatile bool _gothello; /**< Status flag for finding the test string */
- volatile bool _error; /**< Status flag for an error */
- volatile bool _disconnected;
- volatile bool _request_sent;
-
- mbedtls_entropy_context _entropy;
- mbedtls_ctr_drbg_context _ctr_drbg;
- mbedtls_x509_crt _cacert;
- mbedtls_ssl_context _ssl;
- mbedtls_ssl_config _ssl_conf;
-};
-
-/**
- * The main loop of the HTTPS Hello World test
- */
-int main() {
- /* The default 9600 bps is too slow to print full TLS debug info and could
- * cause the other party to time out. */
-
- /* Inititalise with DHCP, connect, and start up the stack */
- EthernetInterface eth_iface;
- eth_iface.connect();
- mbedtls_printf("Using Ethernet LWIP\r\n");
- const char *ip_addr = eth_iface.get_ip_address();
- if (ip_addr) {
- mbedtls_printf("Client IP Address is %s\r\n", ip_addr);
- } else {
- mbedtls_printf("No Client IP Address\r\n");
- }
-
- HelloHTTPS *hello = new HelloHTTPS(HTTPS_SERVER_NAME, HTTPS_SERVER_PORT, ð_iface);
- hello->startTest(HTTPS_PATH);
- delete hello;
-}
+ return rc;
+}
\ No newline at end of file
