esp8266: update iotc and improve sample (#65)
- update iotc (improvements and fixes) - show connection recovery - add more comments
This commit is contained in:
Родитель
4b8ab14947
Коммит
4e51477c0f
|
@ -1,102 +1,85 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full
|
||||
// license information.
|
||||
|
||||
#include "src/iotc/iotc.h"
|
||||
#include "src/iotc/common/string_buffer.h"
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "src/iotc/common/string_buffer.h"
|
||||
#include "src/iotc/iotc.h"
|
||||
|
||||
// #define WIFI_SSID "<ENTER WIFI SSID HERE>"
|
||||
// #define WIFI_PASSWORD "<ENTER WIFI PASSWORD HERE>"
|
||||
#define WIFI_SSID "<ENTER WIFI SSID HERE>"
|
||||
#define WIFI_PASSWORD "<ENTER WIFI PASSWORD HERE>"
|
||||
|
||||
// const char* scopeId = "<ENTER SCOPE ID HERE>";
|
||||
// const char* deviceId = "<ENTER DEVICE ID HERE>";
|
||||
// const char* deviceKey = "<ENTER DEVICE primary/secondary KEY HERE>";
|
||||
const char* SCOPE_ID = "<ENTER SCOPE ID HERE>";
|
||||
const char* DEVICE_ID = "<ENTER DEVICE ID HERE>";
|
||||
const char* DEVICE_KEY = "<ENTER DEVICE primary/secondary KEY HERE>";
|
||||
|
||||
static IOTContext context = NULL;
|
||||
void on_event(IOTContext ctx, IOTCallbackInfo* callbackInfo);
|
||||
#include "src/connection.h"
|
||||
|
||||
void connect_wifi() {
|
||||
Serial.begin(9600);
|
||||
void on_event(IOTContext ctx, IOTCallbackInfo* callbackInfo) {
|
||||
// ConnectionStatus
|
||||
if (strcmp(callbackInfo->eventName, "ConnectionStatus") == 0) {
|
||||
LOG_VERBOSE("Is connected ? %s (%d)",
|
||||
callbackInfo->statusCode == IOTC_CONNECTION_OK ? "YES" : "NO",
|
||||
callbackInfo->statusCode);
|
||||
isConnected = callbackInfo->statusCode == IOTC_CONNECTION_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||
// payload buffer doesn't have a null ending.
|
||||
// add null ending in another buffer before print
|
||||
AzureIOT::StringBuffer buffer;
|
||||
if (callbackInfo->payloadLength > 0) {
|
||||
buffer.initialize(callbackInfo->payload, callbackInfo->payloadLength);
|
||||
}
|
||||
|
||||
LOG_VERBOSE("Connecting WiFi..");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
}
|
||||
LOG_VERBOSE("- [%s] event was received. Payload => %s\n",
|
||||
callbackInfo->eventName, buffer.getLength() ? *buffer : "EMPTY");
|
||||
|
||||
if (strcmp(callbackInfo->eventName, "Command") == 0) {
|
||||
LOG_VERBOSE("- Command name was => %s\r\n", callbackInfo->tag);
|
||||
}
|
||||
}
|
||||
|
||||
static bool isConnected = false;
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
void onEvent(IOTContext ctx, IOTCallbackInfo *callbackInfo) {
|
||||
if (strcmp(callbackInfo->eventName, "ConnectionStatus") == 0) {
|
||||
LOG_VERBOSE("Is connected ? %s (%d)", callbackInfo->statusCode == IOTC_CONNECTION_OK ? "YES" : "NO", callbackInfo->statusCode);
|
||||
isConnected = callbackInfo->statusCode == IOTC_CONNECTION_OK;
|
||||
}
|
||||
connect_wifi(WIFI_SSID, WIFI_PASSWORD);
|
||||
connect_client(SCOPE_ID, DEVICE_ID, DEVICE_KEY);
|
||||
|
||||
AzureIOT::StringBuffer buffer;
|
||||
if (callbackInfo->payloadLength > 0) {
|
||||
buffer.initialize(callbackInfo->payload, callbackInfo->payloadLength);
|
||||
}
|
||||
LOG_VERBOSE("- [%s] event was received. Payload => %s", callbackInfo->eventName, buffer.getLength() ? *buffer : "EMPTY");
|
||||
|
||||
if (strcmp(callbackInfo->eventName, "Command") == 0) {
|
||||
LOG_VERBOSE("- Command name was => %s\r\n", callbackInfo->tag);
|
||||
}
|
||||
if (context != NULL) {
|
||||
lastTick = 0; // set timer in the past to enable first telemetry a.s.a.p
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned prevMillis = 0, loopId = 0;
|
||||
void setup()
|
||||
{
|
||||
connect_wifi();
|
||||
void loop() {
|
||||
if (isConnected) {
|
||||
unsigned long ms = millis();
|
||||
if (ms - lastTick > 10000) { // send telemetry every 10 seconds
|
||||
char msg[64] = {0};
|
||||
int pos = 0, errorCode = 0;
|
||||
|
||||
// Azure IOT Central setup
|
||||
int errorCode = iotc_init_context(&context);
|
||||
if (errorCode != 0) {
|
||||
LOG_ERROR("Error initializing IOTC. Code %d", errorCode);
|
||||
return;
|
||||
lastTick = ms;
|
||||
if (loopId++ % 2 == 0) { // send telemetry
|
||||
pos = snprintf(msg, sizeof(msg) - 1, "{\"accelerometerX\": %d}",
|
||||
10 + (rand() % 20));
|
||||
errorCode = iotc_send_telemetry(context, msg, pos);
|
||||
} else { // send property
|
||||
pos = snprintf(msg, sizeof(msg) - 1, "{\"dieNumber\":%d}",
|
||||
1 + (rand() % 5));
|
||||
errorCode = iotc_send_property(context, msg, pos);
|
||||
}
|
||||
msg[pos] = 0;
|
||||
|
||||
if (errorCode != 0) {
|
||||
LOG_ERROR("Sending message has failed with error code %d", errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
iotc_set_logging(IOTC_LOGGING_API_ONLY);
|
||||
|
||||
// for the simplicity of this sample, used same callback for all the events below
|
||||
iotc_on(context, "MessageSent", onEvent, NULL);
|
||||
iotc_on(context, "Command", onEvent, NULL);
|
||||
iotc_on(context, "ConnectionStatus", onEvent, NULL);
|
||||
iotc_on(context, "SettingsUpdated", onEvent, NULL);
|
||||
iotc_on(context, "Error", onEvent, NULL);
|
||||
|
||||
errorCode = iotc_connect(context, scopeId, deviceKey, deviceId, IOTC_CONNECT_SYMM_KEY);
|
||||
if (errorCode != 0) {
|
||||
LOG_ERROR("Error @ iotc_connect. Code %d", errorCode);
|
||||
return;
|
||||
}
|
||||
prevMillis = millis();
|
||||
iotc_do_work(context); // do background work for iotc
|
||||
} else {
|
||||
iotc_free_context(context);
|
||||
context = NULL;
|
||||
connect_client(SCOPE_ID, DEVICE_ID, DEVICE_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (isConnected) {
|
||||
unsigned long ms = millis();
|
||||
if (ms - prevMillis > 15000) { // send telemetry every 15 seconds
|
||||
char msg[64] = {0};
|
||||
int pos = 0, errorCode = 0;
|
||||
|
||||
prevMillis = ms;
|
||||
if (loopId++ % 2 == 0) { // send telemetry
|
||||
pos = snprintf(msg, sizeof(msg) - 1, "{\"accelerometerX\": %d}", 10 + (rand() % 20));
|
||||
errorCode = iotc_send_telemetry(context, msg, pos);
|
||||
} else { // send property
|
||||
pos = snprintf(msg, sizeof(msg) - 1, "{\"dieNumber\":%d}", 1 + (rand() % 5));
|
||||
errorCode = iotc_send_property(context, msg, pos);
|
||||
}
|
||||
msg[pos] = 0;
|
||||
|
||||
if (errorCode != 0) {
|
||||
LOG_ERROR("Sending message has failed with error code %d", errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
iotc_do_work(context); // do background work for iotc
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
- Grab `scopeId`, `device Id` and `primary key` and fill the necessary parts under `ESP8266.ino`
|
||||
|
||||
```
|
||||
// #define WIFI_SSID "<ENTER WIFI SSID HERE>"
|
||||
// #define WIFI_PASSWORD "<ENTER WIFI PASSWORD HERE>"
|
||||
#define WIFI_SSID "<ENTER WIFI SSID HERE>"
|
||||
#define WIFI_PASSWORD "<ENTER WIFI PASSWORD HERE>"
|
||||
|
||||
// const char* scopeId = "<ENTER SCOPE ID HERE>";
|
||||
// const char* deviceId = "<ENTER DEVICE ID HERE>";
|
||||
// const char* deviceKey = "<ENTER DEVICE primary/secondary KEY HERE>";
|
||||
const char* SCOPE_ID = "<ENTER SCOPE ID HERE>";
|
||||
const char* DEVICE_ID = "<ENTER DEVICE ID HERE>";
|
||||
const char* DEVICE_KEY = "<ENTER DEVICE primary/secondary KEY HERE>";
|
||||
```
|
||||
|
||||
Compile it! and deploy to your device. (see below)
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// src/connection.h
|
||||
|
||||
bool isConnected = false;
|
||||
unsigned long lastTick = 0, loopId = 0;
|
||||
IOTContext context = NULL;
|
||||
|
||||
void connect_client(const char* scopeId, const char* deviceId,
|
||||
const char* deviceKey) {
|
||||
// initialize iotc context (per device client)
|
||||
int errorCode = iotc_init_context(&context);
|
||||
if (errorCode != 0) {
|
||||
LOG_ERROR("Error initializing IOTC. Code %d", errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
iotc_set_logging(IOTC_LOGGING_API_ONLY);
|
||||
|
||||
// set up event callbacks. they are all declared under the ESP8266.ino file
|
||||
// for simplicity, track all of them from the same callback function
|
||||
iotc_on(context, "MessageSent", on_event, NULL);
|
||||
iotc_on(context, "Command", on_event, NULL);
|
||||
iotc_on(context, "ConnectionStatus", on_event, NULL);
|
||||
iotc_on(context, "SettingsUpdated", on_event, NULL);
|
||||
|
||||
// connect to Azure IoT
|
||||
errorCode = iotc_connect(context, scopeId, deviceKey, deviceId,
|
||||
IOTC_CONNECT_SYMM_KEY);
|
||||
if (errorCode != 0) {
|
||||
LOG_ERROR("Error @ iotc_connect. Code %d", errorCode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void connect_wifi(const char* wifi_ssid, const char* wifi_password) {
|
||||
WiFi.begin(wifi_ssid, wifi_password);
|
||||
|
||||
LOG_VERBOSE("Connecting to WiFi..");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
}
|
||||
}
|
|
@ -10,12 +10,12 @@
|
|||
#define PubSubClient_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "IPAddress.h"
|
||||
#include "Client.h"
|
||||
#include "IPAddress.h"
|
||||
#include "Stream.h"
|
||||
|
||||
#define MQTT_VERSION_3_1 3
|
||||
#define MQTT_VERSION_3_1_1 4
|
||||
#define MQTT_VERSION_3_1 3
|
||||
#define MQTT_VERSION_3_1_1 4
|
||||
|
||||
// MQTT_VERSION : Pick the version
|
||||
//#define MQTT_VERSION MQTT_VERSION_3_1
|
||||
|
@ -25,7 +25,7 @@
|
|||
|
||||
// MQTT_MAX_PACKET_SIZE : Maximum packet size
|
||||
#ifndef MQTT_MAX_PACKET_SIZE
|
||||
#define MQTT_MAX_PACKET_SIZE 512
|
||||
#define MQTT_MAX_PACKET_SIZE 2048
|
||||
#endif
|
||||
|
||||
// MQTT_KEEPALIVE : keepAlive interval in Seconds
|
||||
|
@ -44,113 +44,124 @@
|
|||
// #define MQTT_MAX_TRANSFER_SIZE 80
|
||||
|
||||
// Possible values for client.state()
|
||||
#define MQTT_CONNECTION_TIMEOUT -4
|
||||
#define MQTT_CONNECTION_LOST -3
|
||||
#define MQTT_CONNECT_FAILED -2
|
||||
#define MQTT_DISCONNECTED -1
|
||||
#define MQTT_CONNECTED 0
|
||||
#define MQTT_CONNECT_BAD_PROTOCOL 1
|
||||
#define MQTT_CONNECT_BAD_CLIENT_ID 2
|
||||
#define MQTT_CONNECT_UNAVAILABLE 3
|
||||
#define MQTT_CONNECTION_TIMEOUT -4
|
||||
#define MQTT_CONNECTION_LOST -3
|
||||
#define MQTT_CONNECT_FAILED -2
|
||||
#define MQTT_DISCONNECTED -1
|
||||
#define MQTT_CONNECTED 0
|
||||
#define MQTT_CONNECT_BAD_PROTOCOL 1
|
||||
#define MQTT_CONNECT_BAD_CLIENT_ID 2
|
||||
#define MQTT_CONNECT_UNAVAILABLE 3
|
||||
#define MQTT_CONNECT_BAD_CREDENTIALS 4
|
||||
#define MQTT_CONNECT_UNAUTHORIZED 5
|
||||
#define MQTT_CONNECT_UNAUTHORIZED 5
|
||||
|
||||
#define MQTTCONNECT 1 << 4 // Client request to connect to Server
|
||||
#define MQTTCONNACK 2 << 4 // Connect Acknowledgment
|
||||
#define MQTTPUBLISH 3 << 4 // Publish message
|
||||
#define MQTTPUBACK 4 << 4 // Publish Acknowledgment
|
||||
#define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1)
|
||||
#define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2)
|
||||
#define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3)
|
||||
#define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request
|
||||
#define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment
|
||||
#define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request
|
||||
#define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment
|
||||
#define MQTTPINGREQ 12 << 4 // PING Request
|
||||
#define MQTTPINGRESP 13 << 4 // PING Response
|
||||
#define MQTTDISCONNECT 14 << 4 // Client is Disconnecting
|
||||
#define MQTTReserved 15 << 4 // Reserved
|
||||
#define MQTTCONNECT 1 << 4 // Client request to connect to Server
|
||||
#define MQTTCONNACK 2 << 4 // Connect Acknowledgment
|
||||
#define MQTTPUBLISH 3 << 4 // Publish message
|
||||
#define MQTTPUBACK 4 << 4 // Publish Acknowledgment
|
||||
#define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1)
|
||||
#define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2)
|
||||
#define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3)
|
||||
#define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request
|
||||
#define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment
|
||||
#define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request
|
||||
#define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment
|
||||
#define MQTTPINGREQ 12 << 4 // PING Request
|
||||
#define MQTTPINGRESP 13 << 4 // PING Response
|
||||
#define MQTTDISCONNECT 14 << 4 // Client is Disconnecting
|
||||
#define MQTTReserved 15 << 4 // Reserved
|
||||
|
||||
#define MQTTQOS0 (0 << 1)
|
||||
#define MQTTQOS1 (1 << 1)
|
||||
#define MQTTQOS2 (2 << 1)
|
||||
#define MQTTQOS0 (0 << 1)
|
||||
#define MQTTQOS1 (1 << 1)
|
||||
#define MQTTQOS2 (2 << 1)
|
||||
|
||||
// Maximum size of fixed header and variable length size header
|
||||
#define MQTT_MAX_HEADER_SIZE 5
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
#include <functional>
|
||||
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
|
||||
#define MQTT_CALLBACK_SIGNATURE \
|
||||
std::function<void(char*, uint8_t*, unsigned int)> callback
|
||||
#else
|
||||
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
|
||||
#endif
|
||||
|
||||
#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;}
|
||||
#define CHECK_STRING_LENGTH(l, s) \
|
||||
if (l + 2 + strlen(s) > MQTT_MAX_PACKET_SIZE) { \
|
||||
_client->stop(); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
class PubSubClient : public Print {
|
||||
private:
|
||||
Client* _client;
|
||||
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
|
||||
uint16_t nextMsgId;
|
||||
unsigned long lastOutActivity;
|
||||
unsigned long lastInActivity;
|
||||
bool pingOutstanding;
|
||||
MQTT_CALLBACK_SIGNATURE;
|
||||
uint16_t readPacket(uint8_t*);
|
||||
boolean readByte(uint8_t * result);
|
||||
boolean readByte(uint8_t * result, uint16_t * index);
|
||||
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
|
||||
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
|
||||
// Build up the header ready to send
|
||||
// Returns the size of the header
|
||||
// Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start
|
||||
// (MQTT_MAX_HEADER_SIZE - <returned size>) bytes into the buffer
|
||||
size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length);
|
||||
IPAddress ip;
|
||||
const char* domain;
|
||||
uint16_t port;
|
||||
Stream* stream;
|
||||
int _state;
|
||||
public:
|
||||
PubSubClient(const char*, uint16_t, Client* client);
|
||||
private:
|
||||
Client* _client;
|
||||
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
|
||||
uint16_t nextMsgId;
|
||||
unsigned long lastOutActivity;
|
||||
unsigned long lastInActivity;
|
||||
bool pingOutstanding;
|
||||
MQTT_CALLBACK_SIGNATURE;
|
||||
uint16_t readPacket(uint8_t*);
|
||||
boolean readByte(uint8_t* result);
|
||||
boolean readByte(uint8_t* result, uint16_t* index);
|
||||
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
|
||||
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
|
||||
// Build up the header ready to send
|
||||
// Returns the size of the header
|
||||
// Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE
|
||||
// bytes, so will start
|
||||
// (MQTT_MAX_HEADER_SIZE - <returned size>) bytes into the buffer
|
||||
size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length);
|
||||
IPAddress ip;
|
||||
const char* domain;
|
||||
uint16_t port;
|
||||
Stream* stream;
|
||||
int _state;
|
||||
|
||||
PubSubClient& setServer(IPAddress ip, uint16_t port);
|
||||
PubSubClient& setServer(uint8_t * ip, uint16_t port);
|
||||
PubSubClient& setServer(const char * domain, uint16_t port);
|
||||
PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE);
|
||||
PubSubClient& setClient(Client* client);
|
||||
PubSubClient& setStream(Stream& stream);
|
||||
public:
|
||||
PubSubClient(const char*, uint16_t, Client* client);
|
||||
|
||||
boolean connect(const char* id, const char* user, const char* pass);
|
||||
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession);
|
||||
void disconnect();
|
||||
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
|
||||
// Start to publish a message.
|
||||
// This API:
|
||||
// beginPublish(...)
|
||||
// one or more calls to write(...)
|
||||
// endPublish()
|
||||
// Allows for arbitrarily large payloads to be sent without them having to be copied into
|
||||
// a new buffer and held in memory at one time
|
||||
// Returns 1 if the message was started successfully, 0 if there was an error
|
||||
boolean beginPublish(const char* topic, unsigned int plength, boolean retained);
|
||||
// Finish off this publish message (started with beginPublish)
|
||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||
int endPublish();
|
||||
// Write a single byte of payload (only to be used with beginPublish/endPublish)
|
||||
virtual size_t write(uint8_t);
|
||||
// Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish)
|
||||
// Returns the number of bytes written
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
boolean subscribe(const char* topic);
|
||||
boolean subscribe(const char* topic, uint8_t qos);
|
||||
boolean unsubscribe(const char* topic);
|
||||
boolean loop();
|
||||
boolean connected();
|
||||
int state();
|
||||
PubSubClient& setServer(IPAddress ip, uint16_t port);
|
||||
PubSubClient& setServer(uint8_t* ip, uint16_t port);
|
||||
PubSubClient& setServer(const char* domain, uint16_t port);
|
||||
PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE);
|
||||
PubSubClient& setClient(Client* client);
|
||||
PubSubClient& setStream(Stream& stream);
|
||||
|
||||
boolean connect(const char* id, const char* user, const char* pass);
|
||||
boolean connect(const char* id, const char* user, const char* pass,
|
||||
const char* willTopic, uint8_t willQos, boolean willRetain,
|
||||
const char* willMessage, boolean cleanSession);
|
||||
void disconnect();
|
||||
boolean publish(const char* topic, const uint8_t* payload,
|
||||
unsigned int plength, boolean retained);
|
||||
// Start to publish a message.
|
||||
// This API:
|
||||
// beginPublish(...)
|
||||
// one or more calls to write(...)
|
||||
// endPublish()
|
||||
// Allows for arbitrarily large payloads to be sent without them having to be
|
||||
// copied into a new buffer and held in memory at one time Returns 1 if the
|
||||
// message was started successfully, 0 if there was an error
|
||||
boolean beginPublish(const char* topic, unsigned int plength,
|
||||
boolean retained);
|
||||
// Finish off this publish message (started with beginPublish)
|
||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||
int endPublish();
|
||||
// Write a single byte of payload (only to be used with
|
||||
// beginPublish/endPublish)
|
||||
virtual size_t write(uint8_t);
|
||||
// Write size bytes from buffer into the payload (only to be used with
|
||||
// beginPublish/endPublish) Returns the number of bytes written
|
||||
virtual size_t write(const uint8_t* buffer, size_t size);
|
||||
boolean subscribe(const char* topic);
|
||||
boolean subscribe(const char* topic, uint8_t qos);
|
||||
boolean unsubscribe(const char* topic);
|
||||
boolean loop();
|
||||
boolean connected();
|
||||
int state();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif // ARDUINO
|
||||
#endif // ARDUINO
|
|
@ -1,20 +1,18 @@
|
|||
// Copyright (c) Oguz Bastemur. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "../common/iotc_platform.h"
|
||||
#if defined(ARDUINO) && defined(USE_LIGHT_CLIENT)
|
||||
#include "../common/json.h"
|
||||
#include "../common/iotc_internal.h"
|
||||
#include <SPI.h>
|
||||
#include <stdarg.h>
|
||||
#include "../common/iotc_internal.h"
|
||||
#include "../common/iotc_platform.h"
|
||||
#include "../common/json.h"
|
||||
|
||||
int mqtt_publish(IOTContextInternal *internal, const char* topic, unsigned long topic_length,
|
||||
const char* msg, unsigned long msg_length) {
|
||||
|
||||
if (!internal->mqttClient->publish(topic, (const uint8_t*)msg, msg_length, false)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
int mqtt_publish(IOTContextInternal* internal, const char* topic,
|
||||
unsigned long topic_length, const char* msg,
|
||||
unsigned long msg_length) {
|
||||
if (!internal->mqttClient->publish(topic, (const uint8_t*)msg, msg_length,
|
||||
false)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // defined(ARDUINO) && defined(USE_LIGHT_CLIENT)
|
||||
|
|
|
@ -1,109 +1,113 @@
|
|||
// Copyright (c) Oguz Bastemur. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "../common/iotc_platform.h"
|
||||
#if defined(ARDUINO) && defined(USE_LIGHT_CLIENT)
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "../common/json.h"
|
||||
#include "../common/iotc_internal.h"
|
||||
#include "../common/json.h"
|
||||
|
||||
unsigned long _getNow()
|
||||
{
|
||||
int retryCount = 0;
|
||||
const int NTP_PACKET_SIZE = 48;
|
||||
byte packetBuffer[NTP_PACKET_SIZE];
|
||||
unsigned long retVal = 0;
|
||||
unsigned long _getNow() {
|
||||
int retryCount = 0;
|
||||
const int NTP_PACKET_SIZE = 48;
|
||||
byte packetBuffer[NTP_PACKET_SIZE];
|
||||
unsigned long retVal = 0;
|
||||
|
||||
retry_getNow:
|
||||
IPAddress address(129, 6, 15, retryCount % 2 == 1 ? 28 : 29); // time.nist.gov NTP server
|
||||
WiFiUDP Udp;
|
||||
if (Udp.begin(2390) == 0) {
|
||||
if (retryCount < 5) {
|
||||
retryCount++;
|
||||
goto retry_getNow;
|
||||
}
|
||||
IOTC_LOG(F("ERROR: couldn't fetch the time from NTP."));
|
||||
return retVal;
|
||||
IPAddress address(129, 6, 15,
|
||||
retryCount % 2 == 1 ? 28 : 29); // time.nist.gov NTP server
|
||||
WiFiUDP Udp;
|
||||
if (Udp.begin(2390) == 0) {
|
||||
if (retryCount < 5) {
|
||||
retryCount++;
|
||||
goto retry_getNow;
|
||||
}
|
||||
|
||||
memset(packetBuffer, 0, NTP_PACKET_SIZE);
|
||||
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
packetBuffer[2] = 6; // Polling Interval
|
||||
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
packetBuffer[12] = 49;
|
||||
packetBuffer[13] = 0x4E;
|
||||
packetBuffer[14] = 49;
|
||||
packetBuffer[15] = 52;
|
||||
Udp.beginPacket(address, 123);
|
||||
Udp.write(packetBuffer, NTP_PACKET_SIZE);
|
||||
Udp.endPacket();
|
||||
|
||||
// wait to see if a reply is available
|
||||
WAITMS(1000);
|
||||
|
||||
if (Udp.parsePacket() ) {
|
||||
Udp.read(packetBuffer, NTP_PACKET_SIZE);
|
||||
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
|
||||
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
|
||||
unsigned long secsSince1900 = highWord << 16 | lowWord;
|
||||
|
||||
retVal = (secsSince1900 - 2208988800UL);
|
||||
} else {
|
||||
if (retryCount < 5) {
|
||||
retryCount++;
|
||||
goto retry_getNow;
|
||||
}
|
||||
IOTC_LOG(F("ERROR: couldn't fetch the time from NTP."));
|
||||
}
|
||||
|
||||
Udp.stop();
|
||||
IOTC_LOG(F("ERROR: couldn't fetch the time from NTP."));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
memset(packetBuffer, 0, NTP_PACKET_SIZE);
|
||||
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
packetBuffer[2] = 6; // Polling Interval
|
||||
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
packetBuffer[12] = 49;
|
||||
packetBuffer[13] = 0x4E;
|
||||
packetBuffer[14] = 49;
|
||||
packetBuffer[15] = 52;
|
||||
Udp.beginPacket(address, 123);
|
||||
Udp.write(packetBuffer, NTP_PACKET_SIZE);
|
||||
Udp.endPacket();
|
||||
|
||||
// wait to see if a reply is available
|
||||
WAITMS(1000);
|
||||
|
||||
if (Udp.parsePacket()) {
|
||||
Udp.read(packetBuffer, NTP_PACKET_SIZE);
|
||||
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
|
||||
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
|
||||
unsigned long secsSince1900 = highWord << 16 | lowWord;
|
||||
|
||||
retVal = (secsSince1900 - 2208988800UL);
|
||||
} else {
|
||||
if (retryCount < 5) {
|
||||
retryCount++;
|
||||
goto retry_getNow;
|
||||
}
|
||||
IOTC_LOG(F("ERROR: couldn't fetch the time from NTP."));
|
||||
}
|
||||
|
||||
Udp.stop();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static unsigned long g_udpTime = 0, g_lastRead = 0;
|
||||
unsigned long getNow() {
|
||||
unsigned long ms = millis();
|
||||
if (g_udpTime == 0 || ms - g_lastRead > NTP_SYNC_PERIOD) {
|
||||
g_udpTime = _getNow();
|
||||
g_lastRead = ms;
|
||||
}
|
||||
return g_udpTime + ((ms - g_lastRead) / 1000);
|
||||
unsigned long ms = millis();
|
||||
if (g_udpTime == 0 || ms - g_lastRead > NTP_SYNC_PERIOD) {
|
||||
g_udpTime = _getNow();
|
||||
g_lastRead = ms;
|
||||
}
|
||||
return g_udpTime + ((ms - g_lastRead) / 1000);
|
||||
}
|
||||
|
||||
int _getOperationId(const char* dpsEndpoint, const char* scopeId, const char* deviceId,
|
||||
const char* authHeader, char *operationId, char *hostName) {
|
||||
ARDUINO_WIFI_SSL_CLIENT client;
|
||||
int exitCode = 0;
|
||||
int _getOperationId(const char* dpsEndpoint, const char* scopeId,
|
||||
const char* deviceId, const char* authHeader,
|
||||
char* operationId, char* hostName) {
|
||||
ARDUINO_WIFI_SSL_CLIENT client;
|
||||
int exitCode = 0;
|
||||
|
||||
#ifndef USES_WIFI101
|
||||
#ifndef AXTLS_DEPRECATED
|
||||
client.setCACert((const uint8_t*)SSL_CA_PEM_DEF, strlen((const char*)SSL_CA_PEM_DEF));
|
||||
#else // AXTLS_DEPRECATED
|
||||
BearSSL::X509List certList(SSL_CA_PEM_DEF);
|
||||
client.setX509Time(g_udpTime);
|
||||
client.setTrustAnchors(&certList);
|
||||
#endif // AXTLS_DEPRECATED
|
||||
#endif // USES_WIFI101
|
||||
client.setCACert((const uint8_t*)SSL_CA_PEM_DEF,
|
||||
strlen((const char*)SSL_CA_PEM_DEF));
|
||||
#else // AXTLS_DEPRECATED
|
||||
BearSSL::X509List certList(SSL_CA_PEM_DEF);
|
||||
client.setX509Time(g_udpTime);
|
||||
client.setTrustAnchors(&certList);
|
||||
#endif // AXTLS_DEPRECATED
|
||||
#endif // USES_WIFI101
|
||||
|
||||
int retry = 0;
|
||||
while (retry < 5 && !client.connect(dpsEndpoint, AZURE_HTTPS_SERVER_PORT)) retry++;
|
||||
if (!client.connected()) {
|
||||
IOTC_LOG(F("ERROR: DPS endpoint %s call has failed."), hostName == NULL ? "PUT" : "GET");
|
||||
return 1;
|
||||
}
|
||||
int retry = 0;
|
||||
while (retry < 5 && !client.connect(dpsEndpoint, AZURE_HTTPS_SERVER_PORT))
|
||||
retry++;
|
||||
if (!client.connected()) {
|
||||
IOTC_LOG(F("ERROR: DPS endpoint %s call has failed."),
|
||||
hostName == NULL ? "PUT" : "GET");
|
||||
return 1;
|
||||
}
|
||||
|
||||
AzureIOT::StringBuffer tmpBuffer(STRING_BUFFER_1024);
|
||||
AzureIOT::StringBuffer deviceIdEncoded(deviceId, strlen(deviceId));
|
||||
deviceIdEncoded.urlEncode();
|
||||
AzureIOT::StringBuffer tmpBuffer(STRING_BUFFER_1024);
|
||||
AzureIOT::StringBuffer deviceIdEncoded(deviceId, strlen(deviceId));
|
||||
deviceIdEncoded.urlEncode();
|
||||
|
||||
size_t size = 0;
|
||||
if (hostName == NULL) {
|
||||
size = strlen("{\"registrationId\":\"%s\"}") + strlen(deviceId) - 2;
|
||||
size = snprintf(*tmpBuffer, STRING_BUFFER_1024, "\
|
||||
size_t size = 0;
|
||||
if (hostName == NULL) {
|
||||
size = strlen("{\"registrationId\":\"%s\"}") + strlen(deviceId) - 2;
|
||||
size = snprintf(*tmpBuffer, STRING_BUFFER_1024,
|
||||
"\
|
||||
PUT /%s/registrations/%s/register?api-version=2018-11-01 HTTP/1.1\r\n\
|
||||
Host: %s\r\n\
|
||||
content-type: application/json; charset=utf-8\r\n\
|
||||
|
@ -115,10 +119,12 @@ connection: close\r\n\
|
|||
\r\n\
|
||||
{\"registrationId\":\"%s\"}\r\n\
|
||||
",
|
||||
scopeId, *deviceIdEncoded, dpsEndpoint,
|
||||
AZURE_IOT_CENTRAL_CLIENT_SIGNATURE, size, authHeader, deviceId);
|
||||
} else {
|
||||
size = snprintf(*tmpBuffer, STRING_BUFFER_1024, "\
|
||||
scopeId, *deviceIdEncoded, dpsEndpoint,
|
||||
AZURE_IOT_CENTRAL_CLIENT_SIGNATURE, size, authHeader,
|
||||
deviceId);
|
||||
} else {
|
||||
size = snprintf(*tmpBuffer, STRING_BUFFER_1024,
|
||||
"\
|
||||
GET /%s/registrations/%s/operations/%s?api-version=2018-11-01 HTTP/1.1\r\n\
|
||||
Host: %s\r\n\
|
||||
content-type: application/json; charset=utf-8\r\n\
|
||||
|
@ -127,248 +133,279 @@ accept: */*\r\n\
|
|||
%s\r\n\
|
||||
connection: close\r\n\
|
||||
\r\n",
|
||||
scopeId, *deviceIdEncoded, operationId, dpsEndpoint,
|
||||
AZURE_IOT_CENTRAL_CLIENT_SIGNATURE, authHeader);
|
||||
}
|
||||
assert(size != 0 && size < STRING_BUFFER_1024);
|
||||
tmpBuffer.setLength(size);
|
||||
scopeId, *deviceIdEncoded, operationId, dpsEndpoint,
|
||||
AZURE_IOT_CENTRAL_CLIENT_SIGNATURE, authHeader);
|
||||
}
|
||||
assert(size != 0 && size < STRING_BUFFER_1024);
|
||||
tmpBuffer.setLength(size);
|
||||
|
||||
client.println(*tmpBuffer);
|
||||
int index = 0;
|
||||
while(!client.available()) {
|
||||
WAITMS(100);
|
||||
if (index++ > IOTC_SERVER_RESPONSE_TIMEOUT * 10) {
|
||||
// 20 secs..
|
||||
client.stop();
|
||||
IOTC_LOG(F("ERROR: DPS (%s) request has failed. (Server didn't answer within 20 secs.)"), hostName == NULL ? "PUT" : "GET");
|
||||
return 1;
|
||||
}
|
||||
client.println(*tmpBuffer);
|
||||
int index = 0;
|
||||
while (!client.available()) {
|
||||
WAITMS(100);
|
||||
if (index++ > IOTC_SERVER_RESPONSE_TIMEOUT * 10) {
|
||||
// 20 secs..
|
||||
client.stop();
|
||||
IOTC_LOG(F("ERROR: DPS (%s) request has failed. (Server didn't answer "
|
||||
"within 20 secs.)"),
|
||||
hostName == NULL ? "PUT" : "GET");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
index = 0;
|
||||
bool enableSaving = false;
|
||||
while (client.available() && index < STRING_BUFFER_1024 - 1) {
|
||||
char ch = (char)client.read();
|
||||
if (ch == '{') {
|
||||
enableSaving = true; // don't use memory for headers
|
||||
}
|
||||
|
||||
index = 0;
|
||||
bool enableSaving = false;
|
||||
while (client.available() && index < STRING_BUFFER_1024 - 1) {
|
||||
char ch = (char) client.read();
|
||||
if (ch == '{') {
|
||||
enableSaving = true; // don't use memory for headers
|
||||
}
|
||||
|
||||
if (enableSaving) {
|
||||
(*tmpBuffer)[index++] = ch;
|
||||
}
|
||||
if (enableSaving) {
|
||||
(*tmpBuffer)[index++] = ch;
|
||||
}
|
||||
tmpBuffer.setLength(index);
|
||||
}
|
||||
tmpBuffer.setLength(index);
|
||||
|
||||
const char* lookFor = hostName == NULL ? "{\"operationId\":\"" : "\"assignedHub\":\"";
|
||||
index = tmpBuffer.indexOf(lookFor, strlen(lookFor), 0);
|
||||
if (index == -1) {
|
||||
error_exit:
|
||||
IOTC_LOG(F("ERROR: DPS (%s) request has failed.\r\n%s"), hostName == NULL ? "PUT" : "GET", *tmpBuffer);
|
||||
exitCode = 1;
|
||||
goto exit_operationId;
|
||||
} else {
|
||||
index += strlen(lookFor);
|
||||
int index2 = tmpBuffer.indexOf("\"", 1, index + 1);
|
||||
if (index2 == -1) goto error_exit;
|
||||
tmpBuffer.setLength(index2);
|
||||
strcpy(hostName == NULL ? operationId : hostName, (*tmpBuffer) + index);
|
||||
}
|
||||
const char* lookFor =
|
||||
hostName == NULL ? "{\"operationId\":\"" : "\"assignedHub\":\"";
|
||||
index = tmpBuffer.indexOf(lookFor, strlen(lookFor), 0);
|
||||
if (index == -1) {
|
||||
error_exit:
|
||||
IOTC_LOG(F("ERROR: DPS (%s) request has failed.\r\n%s"),
|
||||
hostName == NULL ? "PUT" : "GET", *tmpBuffer);
|
||||
exitCode = 1;
|
||||
goto exit_operationId;
|
||||
} else {
|
||||
index += strlen(lookFor);
|
||||
int index2 = tmpBuffer.indexOf("\"", 1, index + 1);
|
||||
if (index2 == -1) goto error_exit;
|
||||
tmpBuffer.setLength(index2);
|
||||
strcpy(hostName == NULL ? operationId : hostName, (*tmpBuffer) + index);
|
||||
}
|
||||
|
||||
exit_operationId:
|
||||
client.stop();
|
||||
return exitCode;
|
||||
client.stop();
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
int getHubHostName(const char* dpsEndpoint, const char *scopeId, const char* deviceId, const char* key, char *hostName) {
|
||||
AzureIOT::StringBuffer authHeader(STRING_BUFFER_256);
|
||||
size_t size = 0;
|
||||
int getHubHostName(const char* dpsEndpoint, const char* scopeId,
|
||||
const char* deviceId, const char* key, char* hostName) {
|
||||
AzureIOT::StringBuffer authHeader(STRING_BUFFER_256);
|
||||
size_t size = 0;
|
||||
|
||||
IOTC_LOG(F("- iotc.dps : getting auth..."));
|
||||
if (getDPSAuthString(scopeId, deviceId, key, *authHeader, STRING_BUFFER_256, size)) {
|
||||
IOTC_LOG(F("ERROR: getDPSAuthString has failed"));
|
||||
return 1;
|
||||
}
|
||||
IOTC_LOG(F("- iotc.dps : getting operation id..."));
|
||||
AzureIOT::StringBuffer operationId(STRING_BUFFER_64);
|
||||
int retval = 0;
|
||||
if ((retval = _getOperationId(dpsEndpoint, scopeId, deviceId, *authHeader, *operationId, NULL)) == 0) {
|
||||
WAITMS(4000);
|
||||
IOTC_LOG(F("- iotc.dps : getting host name..."));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
retval = _getOperationId(dpsEndpoint, scopeId, deviceId, *authHeader, *operationId, hostName);
|
||||
if (retval == 0) break;
|
||||
WAITMS(3000);
|
||||
}
|
||||
IOTC_LOG(F("- iotc.dps : getting auth..."));
|
||||
if (getDPSAuthString(scopeId, deviceId, key, *authHeader, STRING_BUFFER_256,
|
||||
size)) {
|
||||
IOTC_LOG(F("ERROR: getDPSAuthString has failed"));
|
||||
return 1;
|
||||
}
|
||||
IOTC_LOG(F("- iotc.dps : getting operation id..."));
|
||||
AzureIOT::StringBuffer operationId(STRING_BUFFER_64);
|
||||
int retval = 0;
|
||||
if ((retval = _getOperationId(dpsEndpoint, scopeId, deviceId, *authHeader,
|
||||
*operationId, NULL)) == 0) {
|
||||
WAITMS(4000);
|
||||
IOTC_LOG(F("- iotc.dps : getting host name..."));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
retval = _getOperationId(dpsEndpoint, scopeId, deviceId, *authHeader,
|
||||
*operationId, hostName);
|
||||
if (retval == 0) break;
|
||||
WAITMS(3000);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void messageArrived(char* topic, byte* data, unsigned int length) {
|
||||
handlePayload((char*)data, length, topic, topic ? strlen(topic) : 0);
|
||||
handlePayload((char*)data, length, topic, topic ? strlen(topic) : 0);
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_free_context(IOTContext ctx) {
|
||||
MUST_CALL_AFTER_INIT(ctx);
|
||||
MUST_CALL_AFTER_INIT(ctx);
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
if (internal->endpoint != NULL) {
|
||||
free(internal->endpoint);
|
||||
}
|
||||
IOTContextInternal* internal = (IOTContextInternal*)ctx;
|
||||
if (internal->endpoint != NULL) {
|
||||
free(internal->endpoint);
|
||||
}
|
||||
|
||||
iotc_disconnect(ctx);
|
||||
iotc_disconnect(ctx);
|
||||
|
||||
free(internal);
|
||||
setSingletonContext(NULL);
|
||||
free(internal);
|
||||
setSingletonContext(NULL);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iotc_connect(IOTContext ctx, const char* scope, const char* keyORcert,
|
||||
const char* deviceId, IOTConnectType type) {
|
||||
const char* deviceId, IOTConnectType type) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
GET_LENGTH_NOT_NULL(keyORcert, 512);
|
||||
|
||||
CHECK_NOT_NULL(ctx)
|
||||
GET_LENGTH_NOT_NULL(keyORcert, 512);
|
||||
AzureIOT::StringBuffer hostName;
|
||||
AzureIOT::StringBuffer username;
|
||||
AzureIOT::StringBuffer password;
|
||||
IOTContextInternal* internal = (IOTContextInternal*)ctx;
|
||||
|
||||
AzureIOT::StringBuffer hostName;
|
||||
AzureIOT::StringBuffer username;
|
||||
AzureIOT::StringBuffer password;
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
|
||||
if (type == IOTC_CONNECT_CONNECTION_STRING) {
|
||||
getUsernameAndPasswordFromConnectionString(keyORcert,
|
||||
strlen(keyORcert), hostName, internal->deviceId, username, password);
|
||||
} else if (type == IOTC_CONNECT_SYMM_KEY) {
|
||||
assert(scope != NULL && deviceId != NULL);
|
||||
AzureIOT::StringBuffer tmpHostname(STRING_BUFFER_128);
|
||||
if (getHubHostName(internal->endpoint == NULL ?
|
||||
DEFAULT_ENDPOINT : internal->endpoint, scope, deviceId, keyORcert, *tmpHostname)) {
|
||||
return 1;
|
||||
}
|
||||
AzureIOT::StringBuffer cstr(STRING_BUFFER_256);
|
||||
int rc = snprintf(*cstr, STRING_BUFFER_256,
|
||||
"HostName=%s;DeviceId=%s;SharedAccessKey=%s", *tmpHostname, deviceId, keyORcert);
|
||||
assert(rc > 0 && rc < STRING_BUFFER_256);
|
||||
cstr.setLength(rc);
|
||||
|
||||
// TODO: move into iotc_dps and do not re-parse from connection string
|
||||
getUsernameAndPasswordFromConnectionString(*cstr, rc, hostName, internal->deviceId, username, password);
|
||||
} else if (type == IOTC_CONNECT_X509_CERT) {
|
||||
IOTC_LOG(F("ERROR: IOTC_CONNECT_X509_CERT NOT IMPLEMENTED"));
|
||||
connectionStatusCallback(IOTC_CONNECTION_DEVICE_DISABLED, (IOTContextInternal*)ctx);
|
||||
return 1;
|
||||
if (type == IOTC_CONNECT_CONNECTION_STRING) {
|
||||
getUsernameAndPasswordFromConnectionString(keyORcert, strlen(keyORcert),
|
||||
hostName, internal->deviceId,
|
||||
username, password);
|
||||
} else if (type == IOTC_CONNECT_SYMM_KEY) {
|
||||
assert(scope != NULL && deviceId != NULL);
|
||||
AzureIOT::StringBuffer tmpHostname(STRING_BUFFER_128);
|
||||
if (getHubHostName(
|
||||
internal->endpoint == NULL ? DEFAULT_ENDPOINT : internal->endpoint,
|
||||
scope, deviceId, keyORcert, *tmpHostname)) {
|
||||
return 1;
|
||||
}
|
||||
AzureIOT::StringBuffer cstr(STRING_BUFFER_256);
|
||||
int rc = snprintf(*cstr, STRING_BUFFER_256,
|
||||
"HostName=%s;DeviceId=%s;SharedAccessKey=%s",
|
||||
*tmpHostname, deviceId, keyORcert);
|
||||
assert(rc > 0 && rc < STRING_BUFFER_256);
|
||||
cstr.setLength(rc);
|
||||
|
||||
internal->tlsClient = new ARDUINO_WIFI_SSL_CLIENT();
|
||||
// TODO: move into iotc_dps and do not re-parse from connection string
|
||||
getUsernameAndPasswordFromConnectionString(
|
||||
*cstr, rc, hostName, internal->deviceId, username, password);
|
||||
} else if (type == IOTC_CONNECT_X509_CERT) {
|
||||
IOTC_LOG(F("ERROR: IOTC_CONNECT_X509_CERT NOT IMPLEMENTED"));
|
||||
connectionStatusCallback(IOTC_CONNECTION_DEVICE_DISABLED,
|
||||
(IOTContextInternal*)ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
internal->tlsClient = new ARDUINO_WIFI_SSL_CLIENT();
|
||||
|
||||
#ifndef USES_WIFI101
|
||||
#ifndef AXTLS_DEPRECATED
|
||||
internal->tlsClient->setCACert((const uint8_t*)SSL_CA_PEM_DEF, strlen((const char*)SSL_CA_PEM_DEF));
|
||||
#else // AXTLS_DEPRECATED
|
||||
BearSSL::X509List certList(SSL_CA_PEM_DEF);
|
||||
internal->tlsClient->setX509Time(g_udpTime);
|
||||
internal->tlsClient->setTrustAnchors(&certList);
|
||||
#endif // AXTLS_DEPRECATED
|
||||
#endif // USES_WIFI101
|
||||
internal->tlsClient->setCACert((const uint8_t*)SSL_CA_PEM_DEF,
|
||||
strlen((const char*)SSL_CA_PEM_DEF));
|
||||
#else // AXTLS_DEPRECATED
|
||||
BearSSL::X509List certList(SSL_CA_PEM_DEF);
|
||||
internal->tlsClient->setX509Time(g_udpTime);
|
||||
internal->tlsClient->setTrustAnchors(&certList);
|
||||
#endif // AXTLS_DEPRECATED
|
||||
#endif // USES_WIFI101
|
||||
|
||||
internal->mqttClient = new PubSubClient(*hostName, AZURE_MQTT_SERVER_PORT, internal->tlsClient);
|
||||
internal->mqttClient->setCallback(messageArrived);
|
||||
internal->mqttClient =
|
||||
new PubSubClient(*hostName, AZURE_MQTT_SERVER_PORT, internal->tlsClient);
|
||||
internal->mqttClient->setCallback(messageArrived);
|
||||
|
||||
int retry = 0;
|
||||
while(retry < 10 && !internal->mqttClient->connected()) {
|
||||
if (internal->mqttClient->connect(*internal->deviceId, *username, *password)) {
|
||||
break;
|
||||
} else {
|
||||
WAITMS(2000);
|
||||
retry++;
|
||||
}
|
||||
int retry = 0;
|
||||
while (retry < 10 && !internal->mqttClient->connected()) {
|
||||
if (internal->mqttClient->connect(*internal->deviceId, *username,
|
||||
*password)) {
|
||||
break;
|
||||
} else {
|
||||
WAITMS(2000);
|
||||
retry++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!internal->mqttClient->connected()) {
|
||||
IOTC_LOG(F("ERROR: MQTT client connect attempt failed. Check host, deviceId, username and password. (state %d)"),
|
||||
internal->mqttClient->state());
|
||||
connectionStatusCallback(IOTC_CONNECTION_BAD_CREDENTIAL, (IOTContextInternal*)ctx);
|
||||
delete internal->tlsClient;
|
||||
delete internal->mqttClient;
|
||||
internal->tlsClient = NULL;
|
||||
internal->mqttClient = NULL;
|
||||
return 1;
|
||||
}
|
||||
if (!internal->mqttClient->connected()) {
|
||||
IOTC_LOG(F("ERROR: MQTT client connect attempt failed. Check host, "
|
||||
"deviceId, username and password. (state %d)"),
|
||||
internal->mqttClient->state());
|
||||
connectionStatusCallback(IOTC_CONNECTION_BAD_CREDENTIAL,
|
||||
(IOTContextInternal*)ctx);
|
||||
delete internal->tlsClient;
|
||||
delete internal->mqttClient;
|
||||
internal->tlsClient = NULL;
|
||||
internal->mqttClient = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
AzureIOT::StringBuffer buffer(STRING_BUFFER_64);
|
||||
buffer.setLength(snprintf(*buffer, 63, "devices/%s/messages/events/#", *internal->deviceId));
|
||||
AzureIOT::StringBuffer buffer(STRING_BUFFER_64);
|
||||
buffer.setLength(snprintf(*buffer, 63, "devices/%s/messages/events/#",
|
||||
*internal->deviceId));
|
||||
|
||||
int errorCode = 0;
|
||||
if ( (errorCode = internal->mqttClient->subscribe(*buffer)) == 0)
|
||||
IOTC_LOG(F("ERROR: mqttClient couldn't subscribe to %s. error code => %d"), *buffer, errorCode);
|
||||
int errorCode = 0;
|
||||
if ((errorCode = internal->mqttClient->subscribe(*buffer)) == 0)
|
||||
IOTC_LOG(F("ERROR: mqttClient couldn't subscribe to %s. error code => %d"),
|
||||
*buffer, errorCode);
|
||||
|
||||
buffer.setLength(snprintf(*buffer, 63, "devices/%s/messages/devicebound/#", *internal->deviceId));
|
||||
buffer.setLength(snprintf(*buffer, 63, "devices/%s/messages/devicebound/#",
|
||||
*internal->deviceId));
|
||||
|
||||
if ( (errorCode = internal->mqttClient->subscribe(*buffer)) == 0)
|
||||
IOTC_LOG(F("ERROR: mqttClient couldn't subscribe to %s. error code => %d"), *buffer, errorCode);
|
||||
if ((errorCode = internal->mqttClient->subscribe(*buffer)) == 0)
|
||||
IOTC_LOG(F("ERROR: mqttClient couldn't subscribe to %s. error code => %d"),
|
||||
*buffer, errorCode);
|
||||
|
||||
errorCode = internal->mqttClient->subscribe("$iothub/twin/PATCH/properties/desired/#"); // twin desired property changes
|
||||
errorCode += internal->mqttClient->subscribe("$iothub/twin/res/#"); // twin properties response
|
||||
errorCode += internal->mqttClient->subscribe("$iothub/methods/POST/#");
|
||||
errorCode = internal->mqttClient->subscribe(
|
||||
"$iothub/twin/PATCH/properties/desired/#"); // twin desired property
|
||||
// changes
|
||||
errorCode += internal->mqttClient->subscribe(
|
||||
"$iothub/twin/res/#"); // twin properties response
|
||||
errorCode += internal->mqttClient->subscribe("$iothub/methods/POST/#");
|
||||
|
||||
if (errorCode < 3) {
|
||||
IOTC_LOG(F("ERROR: mqttClient couldn't subscribe to twin/methods etc. error code sum => %d"), errorCode);
|
||||
}
|
||||
if (errorCode < 3) {
|
||||
IOTC_LOG(F("ERROR: mqttClient couldn't subscribe to twin/methods etc. "
|
||||
"error code sum => %d"),
|
||||
errorCode);
|
||||
}
|
||||
|
||||
connectionStatusCallback(IOTC_CONNECTION_OK, (IOTContextInternal*)ctx);
|
||||
connectionStatusCallback(IOTC_CONNECTION_OK, (IOTContextInternal*)ctx);
|
||||
|
||||
iotc_do_work(internal);
|
||||
const char* twin_topic = "$iothub/twin/GET/?$rid=0";
|
||||
internal->messageId++; // next rid=1
|
||||
if (mqtt_publish(internal, twin_topic, strlen(twin_topic), " ", 1) != 0) {
|
||||
IOTC_LOG(F("ERROR: Couldn't send the TWIN update request message"));
|
||||
}
|
||||
iotc_do_work(internal);
|
||||
return 0;
|
||||
iotc_do_work(internal);
|
||||
const char* twin_topic = "$iothub/twin/GET/?$rid=0";
|
||||
internal->messageId++; // next rid=1
|
||||
if (mqtt_publish(internal, twin_topic, strlen(twin_topic), " ", 1) != 0) {
|
||||
IOTC_LOG(F("ERROR: Couldn't send the TWIN update request message"));
|
||||
}
|
||||
iotc_do_work(internal);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_disconnect(IOTContext ctx) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(ctx)
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
IOTContextInternal* internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
|
||||
if (internal->mqttClient) {
|
||||
if(internal->mqttClient->connected()) {
|
||||
internal->mqttClient->disconnect();
|
||||
}
|
||||
delete internal->mqttClient;
|
||||
internal->mqttClient = NULL;
|
||||
if (internal->mqttClient) {
|
||||
if (internal->mqttClient->connected()) {
|
||||
internal->mqttClient->disconnect();
|
||||
}
|
||||
delete internal->mqttClient;
|
||||
internal->mqttClient = NULL;
|
||||
}
|
||||
|
||||
connectionStatusCallback(IOTC_CONNECTION_DISCONNECTED, (IOTContextInternal*)ctx);
|
||||
return 0;
|
||||
if (internal->tlsClient) {
|
||||
delete internal->tlsClient;
|
||||
internal->tlsClient = NULL;
|
||||
}
|
||||
|
||||
connectionStatusCallback(IOTC_CONNECTION_DISCONNECTED,
|
||||
(IOTContextInternal*)ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_do_work(IOTContext ctx) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(ctx)
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
IOTContextInternal* internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
|
||||
if (!internal->mqttClient->loop()) {
|
||||
if (!internal->mqttClient->connected()) {
|
||||
connectionStatusCallback(IOTC_CONNECTION_DISCONNECTED, (IOTContextInternal*)ctx);
|
||||
delete internal->mqttClient;
|
||||
internal->mqttClient = NULL;
|
||||
}
|
||||
return 1;
|
||||
if (!internal->mqttClient->loop()) {
|
||||
if (!internal->mqttClient->connected()) {
|
||||
connectionStatusCallback(IOTC_CONNECTION_DISCONNECTED,
|
||||
(IOTContextInternal*)ctx);
|
||||
delete internal->mqttClient;
|
||||
internal->mqttClient = NULL;
|
||||
}
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_set_network_interface(void* networkInterface) {
|
||||
// NO-OP
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // __MBED__
|
||||
// NO-OP
|
||||
return 0;
|
||||
}
|
|
@ -1,142 +1,150 @@
|
|||
|
||||
/*Copyright (C) 2013 Adam Rudd
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO
|
||||
#include "base64.h"
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
const char PROGMEM b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const char PROGMEM b64_alphabet[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
/* 'Private' declarations */
|
||||
inline void a3_to_a4(unsigned char * a4, unsigned char * a3);
|
||||
inline void a4_to_a3(unsigned char * a3, unsigned char * a4);
|
||||
inline void a3_to_a4(unsigned char *a4, unsigned char *a3);
|
||||
inline void a4_to_a3(unsigned char *a3, unsigned char *a4);
|
||||
inline unsigned char b64_lookup(char c);
|
||||
|
||||
int base64_encode(char *output, char *input, int inputLen) {
|
||||
int i = 0, j = 0;
|
||||
int encLen = 0;
|
||||
unsigned char a3[3];
|
||||
unsigned char a4[4];
|
||||
int i = 0, j = 0;
|
||||
int encLen = 0;
|
||||
unsigned char a3[3];
|
||||
unsigned char a4[4];
|
||||
|
||||
while(inputLen--) {
|
||||
a3[i++] = *(input++);
|
||||
if(i == 3) {
|
||||
a3_to_a4(a4, a3);
|
||||
while (inputLen--) {
|
||||
a3[i++] = *(input++);
|
||||
if (i == 3) {
|
||||
a3_to_a4(a4, a3);
|
||||
|
||||
for(i = 0; i < 4; i++) {
|
||||
output[encLen++] = pgm_read_byte(&b64_alphabet[a4[i]]);
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
output[encLen++] = pgm_read_byte(&b64_alphabet[a4[i]]);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j < 3; j++) {
|
||||
a3[j] = '\0';
|
||||
}
|
||||
|
||||
if(i) {
|
||||
for(j = i; j < 3; j++) {
|
||||
a3[j] = '\0';
|
||||
}
|
||||
a3_to_a4(a4, a3);
|
||||
|
||||
a3_to_a4(a4, a3);
|
||||
|
||||
for(j = 0; j < i + 1; j++) {
|
||||
output[encLen++] = pgm_read_byte(&b64_alphabet[a4[j]]);
|
||||
}
|
||||
|
||||
while((i++ < 3)) {
|
||||
output[encLen++] = '=';
|
||||
}
|
||||
for (j = 0; j < i + 1; j++) {
|
||||
output[encLen++] = pgm_read_byte(&b64_alphabet[a4[j]]);
|
||||
}
|
||||
output[encLen] = '\0';
|
||||
return encLen;
|
||||
|
||||
while ((i++ < 3)) {
|
||||
output[encLen++] = '=';
|
||||
}
|
||||
}
|
||||
output[encLen] = '\0';
|
||||
return encLen;
|
||||
}
|
||||
|
||||
int base64_decode(char * output, char * input, int inputLen) {
|
||||
int i = 0, j = 0;
|
||||
int decLen = 0;
|
||||
unsigned char a3[3];
|
||||
unsigned char a4[4];
|
||||
int base64_decode(char *output, char *input, int inputLen) {
|
||||
int i = 0, j = 0;
|
||||
int decLen = 0;
|
||||
unsigned char a3[3];
|
||||
unsigned char a4[4];
|
||||
|
||||
|
||||
while (inputLen--) {
|
||||
if(*input == '=') {
|
||||
break;
|
||||
}
|
||||
|
||||
a4[i++] = *(input++);
|
||||
if (i == 4) {
|
||||
for (i = 0; i <4; i++) {
|
||||
a4[i] = b64_lookup(a4[i]);
|
||||
}
|
||||
|
||||
a4_to_a3(a3,a4);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
output[decLen++] = a3[i];
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
while (inputLen--) {
|
||||
if (*input == '=') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j < 4; j++) {
|
||||
a4[j] = '\0';
|
||||
}
|
||||
a4[i++] = *(input++);
|
||||
if (i == 4) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
a4[i] = b64_lookup(a4[i]);
|
||||
}
|
||||
|
||||
for (j = 0; j <4; j++) {
|
||||
a4[j] = b64_lookup(a4[j]);
|
||||
}
|
||||
a4_to_a3(a3, a4);
|
||||
|
||||
a4_to_a3(a3,a4);
|
||||
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
output[decLen++] = a3[j];
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
output[decLen++] = a3[i];
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
output[decLen] = '\0';
|
||||
return decLen;
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j < 4; j++) {
|
||||
a4[j] = '\0';
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
a4[j] = b64_lookup(a4[j]);
|
||||
}
|
||||
|
||||
a4_to_a3(a3, a4);
|
||||
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
output[decLen++] = a3[j];
|
||||
}
|
||||
}
|
||||
output[decLen] = '\0';
|
||||
return decLen;
|
||||
}
|
||||
|
||||
int base64_enc_len(int plainLen) {
|
||||
int n = plainLen;
|
||||
return (n + 2 - ((n + 2) % 3)) / 3 * 4;
|
||||
int n = plainLen;
|
||||
return (n + 2 - ((n + 2) % 3)) / 3 * 4;
|
||||
}
|
||||
|
||||
int base64_dec_len(char * input, int inputLen) {
|
||||
int i = 0;
|
||||
int numEq = 0;
|
||||
for(i = inputLen - 1; input[i] == '='; i--) {
|
||||
numEq++;
|
||||
}
|
||||
int base64_dec_len(char *input, int inputLen) {
|
||||
int i = 0;
|
||||
int numEq = 0;
|
||||
for (i = inputLen - 1; input[i] == '='; i--) {
|
||||
numEq++;
|
||||
}
|
||||
|
||||
return ((6 * inputLen) / 8) - numEq;
|
||||
return ((6 * inputLen) / 8) - numEq;
|
||||
}
|
||||
|
||||
inline void a3_to_a4(unsigned char * a4, unsigned char * a3) {
|
||||
a4[0] = (a3[0] & 0xfc) >> 2;
|
||||
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
|
||||
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
|
||||
a4[3] = (a3[2] & 0x3f);
|
||||
inline void a3_to_a4(unsigned char *a4, unsigned char *a3) {
|
||||
a4[0] = (a3[0] & 0xfc) >> 2;
|
||||
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
|
||||
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
|
||||
a4[3] = (a3[2] & 0x3f);
|
||||
}
|
||||
|
||||
inline void a4_to_a3(unsigned char * a3, unsigned char * a4) {
|
||||
a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
|
||||
a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
|
||||
a3[2] = ((a4[2] & 0x3) << 6) + a4[3];
|
||||
inline void a4_to_a3(unsigned char *a3, unsigned char *a4) {
|
||||
a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
|
||||
a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
|
||||
a3[2] = ((a4[2] & 0x3) << 6) + a4[3];
|
||||
}
|
||||
|
||||
inline unsigned char b64_lookup(char c) {
|
||||
if(c >='A' && c <='Z') return c - 'A';
|
||||
if(c >='a' && c <='z') return c - 71;
|
||||
if(c >='0' && c <='9') return c + 4;
|
||||
if(c == '+') return 62;
|
||||
if(c == '/') return 63;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // ARDUINO
|
||||
if (c >= 'A' && c <= 'Z') return c - 'A';
|
||||
if (c >= 'a' && c <= 'z') return c - 71;
|
||||
if (c >= '0' && c <= '9') return c + 4;
|
||||
if (c == '+') return 62;
|
||||
if (c == '/') return 63;
|
||||
return -1;
|
||||
}
|
|
@ -17,10 +17,9 @@ extern const char b64_alphabet[];
|
|||
* Description:
|
||||
* Encode a string of characters as base64
|
||||
* Parameters:
|
||||
* output: the output buffer for the encoding, stores the encoded string
|
||||
* input: the input buffer for the encoding, stores the binary to be encoded
|
||||
* inputLen: the length of the input buffer, in bytes
|
||||
* Return value:
|
||||
* output: the output buffer for the encoding, stores the encoded
|
||||
* string input: the input buffer for the encoding, stores the binary to be
|
||||
* encoded inputLen: the length of the input buffer, in bytes Return value:
|
||||
* Returns the length of the encoded string
|
||||
* Requirements:
|
||||
* 1. output must not be null or empty
|
||||
|
@ -49,15 +48,10 @@ int base64_decode(char *output, char *input, int inputLen);
|
|||
|
||||
/* base64_enc_len:
|
||||
* Description:
|
||||
* Returns the length of a base64 encoded string whose decoded
|
||||
* form is inputLen bytes long
|
||||
* Parameters:
|
||||
* inputLen: the length of the decoded string
|
||||
* Return value:
|
||||
* The length of a base64 encoded string whose decoded form
|
||||
* is inputLen bytes long
|
||||
* Requirements:
|
||||
* None
|
||||
* Returns the length of a base64 encoded string whose
|
||||
* decoded form is inputLen bytes long Parameters: inputLen: the length of the
|
||||
* decoded string Return value: The length of a base64 encoded string whose
|
||||
* decoded form is inputLen bytes long Requirements: None
|
||||
*/
|
||||
int base64_enc_len(int inputLen);
|
||||
|
||||
|
@ -77,5 +71,5 @@ int base64_enc_len(int inputLen);
|
|||
*/
|
||||
int base64_dec_len(char *input, int inputLen);
|
||||
|
||||
#endif // _BASE64_H
|
||||
#endif // _BASE64_H
|
||||
#endif
|
|
@ -1,107 +1,115 @@
|
|||
// Copyright (c) Oguz Bastemur. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "iotc_internal.h"
|
||||
|
||||
/* extern */
|
||||
int iotc_on(IOTContext ctx, const char* eventName, IOTCallback callback, void* appContext) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
GET_LENGTH_NOT_NULL_NOT_EMPTY(eventName, 64);
|
||||
int iotc_on(IOTContext ctx, const char* eventName, IOTCallback callback,
|
||||
void* appContext) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
GET_LENGTH_NOT_NULL_NOT_EMPTY(eventName, 64);
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_INIT(internal);
|
||||
IOTContextInternal* internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_INIT(internal);
|
||||
|
||||
#define SETCB_(x, a, b) x.callback=a;x.appContext=b;
|
||||
if (strcmp(eventName, "ConnectionStatus") == 0) {
|
||||
SETCB_(internal->callbacks[/*IOTCallbacks::*/::ConnectionStatus], callback, appContext);
|
||||
} else if (strcmp(eventName, "MessageSent") == 0) {
|
||||
SETCB_(internal->callbacks[/*IOTCallbacks::*/::MessageSent], callback, appContext);
|
||||
} else if (strcmp(eventName, "Error") == 0) {
|
||||
SETCB_(internal->callbacks[/*IOTCallbacks::*/::Error], callback, appContext);
|
||||
} else if (strcmp(eventName, "SettingsUpdated") == 0) {
|
||||
SETCB_(internal->callbacks[/*IOTCallbacks::*/::SettingsUpdated], callback, appContext);
|
||||
} else if (strcmp(eventName, "Command") == 0) {
|
||||
SETCB_(internal->callbacks[/*IOTCallbacks::*/::Command], callback, appContext);
|
||||
} else {
|
||||
IOTC_LOG(F("ERROR: (iotc_on) Unknown event definition. (%s)"), eventName);
|
||||
return 1;
|
||||
}
|
||||
#define SETCB_(x, a, b) \
|
||||
x.callback = a; \
|
||||
x.appContext = b;
|
||||
if (strcmp(eventName, "ConnectionStatus") == 0) {
|
||||
SETCB_(internal->callbacks[/*IOTCallbacks::*/ ::ConnectionStatus], callback,
|
||||
appContext);
|
||||
} else if (strcmp(eventName, "MessageSent") == 0) {
|
||||
SETCB_(internal->callbacks[/*IOTCallbacks::*/ ::MessageSent], callback,
|
||||
appContext);
|
||||
} else if (strcmp(eventName, "Error") == 0) {
|
||||
SETCB_(internal->callbacks[/*IOTCallbacks::*/ ::Error], callback,
|
||||
appContext);
|
||||
} else if (strcmp(eventName, "SettingsUpdated") == 0) {
|
||||
SETCB_(internal->callbacks[/*IOTCallbacks::*/ ::SettingsUpdated], callback,
|
||||
appContext);
|
||||
} else if (strcmp(eventName, "Command") == 0) {
|
||||
SETCB_(internal->callbacks[/*IOTCallbacks::*/ ::Command], callback,
|
||||
appContext);
|
||||
} else {
|
||||
IOTC_LOG(F("ERROR: (iotc_on) Unknown event definition. (%s)"), eventName);
|
||||
return 1;
|
||||
}
|
||||
#undef SETCB_
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_send_state (IOTContext ctx, const char* payload, unsigned length) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(payload)
|
||||
int iotc_send_state(IOTContext ctx, const char* payload, unsigned length) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(payload)
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
IOTContextInternal* internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
|
||||
return iotc_send_telemetry((IOTContext)internal, payload, length);
|
||||
return iotc_send_telemetry((IOTContext)internal, payload, length);
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_send_event (IOTContext ctx, const char* payload, unsigned length) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(payload)
|
||||
int iotc_send_event(IOTContext ctx, const char* payload, unsigned length) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(payload)
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
IOTContextInternal* internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
|
||||
return iotc_send_telemetry((IOTContext)internal, payload, length);
|
||||
return iotc_send_telemetry((IOTContext)internal, payload, length);
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_set_global_endpoint(IOTContext ctx, const char* endpoint_uri) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
GET_LENGTH_NOT_NULL_NOT_EMPTY(endpoint_uri, 1024);
|
||||
CHECK_NOT_NULL(ctx)
|
||||
GET_LENGTH_NOT_NULL_NOT_EMPTY(endpoint_uri, 1024);
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_INIT(internal);
|
||||
IOTContextInternal* internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_INIT(internal);
|
||||
|
||||
// todo: do not fragment the memory
|
||||
if (internal->endpoint != NULL) {
|
||||
free(internal->endpoint);
|
||||
}
|
||||
internal->endpoint = (char*) malloc(endpoint_uri_len + 1);
|
||||
CHECK_NOT_NULL(internal->endpoint);
|
||||
// todo: do not fragment the memory
|
||||
if (internal->endpoint != NULL) {
|
||||
free(internal->endpoint);
|
||||
}
|
||||
internal->endpoint = (char*)malloc(endpoint_uri_len + 1);
|
||||
CHECK_NOT_NULL(internal->endpoint);
|
||||
|
||||
strcpy(internal->endpoint, endpoint_uri);
|
||||
*(internal->endpoint + endpoint_uri_len) = 0;
|
||||
return 0;
|
||||
strcpy(internal->endpoint, endpoint_uri);
|
||||
*(internal->endpoint + endpoint_uri_len) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_set_trusted_certs(IOTContext ctx, const char* certs) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
GET_LENGTH_NOT_NULL_NOT_EMPTY(certs, 4096);
|
||||
CHECK_NOT_NULL(ctx)
|
||||
GET_LENGTH_NOT_NULL_NOT_EMPTY(certs, 4096);
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
IOTContextInternal* internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
|
||||
IOTC_LOG(F("ERROR: (iotc_set_trusted_certs) Not implemented."));
|
||||
IOTC_LOG(F("ERROR: (iotc_set_trusted_certs) Not implemented."));
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_set_proxy(IOTContext ctx, IOTC_HTTP_PROXY_OPTIONS proxy) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(ctx)
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_INIT(internal);
|
||||
IOTContextInternal* internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_INIT(internal);
|
||||
|
||||
IOTC_LOG(F("ERROR: (iotc_set_proxy) Not implemented."));
|
||||
return 1;
|
||||
IOTC_LOG(F("ERROR: (iotc_set_proxy) Not implemented."));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_set_logging(IOTLogLevel level) {
|
||||
if (level < IOTC_LOGGING_DISABLED || level > IOTC_LOGGING_ALL) {
|
||||
IOTC_LOG(F("ERROR: (iotc_set_logging) invalid argument. ERROR:0x0001"));
|
||||
return 1;
|
||||
}
|
||||
setLogLevel(level);
|
||||
return 0;
|
||||
if (level < IOTC_LOGGING_DISABLED || level > IOTC_LOGGING_ALL) {
|
||||
IOTC_LOG(F("ERROR: (iotc_set_logging) invalid argument. ERROR:0x0001"));
|
||||
return 1;
|
||||
}
|
||||
setLogLevel(level);
|
||||
return 0;
|
||||
}
|
|
@ -1,53 +1,53 @@
|
|||
// Copyright (c) Oguz Bastemur. All rights reserved.
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef AZURE_IOTC_LITE_DEFINITIONS_H
|
||||
#define AZURE_IOTC_LITE_DEFINITIONS_H
|
||||
|
||||
#define AZURE_MQTT_SERVER_PORT 8883
|
||||
#define AZURE_HTTPS_SERVER_PORT 443
|
||||
#define AZURE_MQTT_SERVER_PORT 8883
|
||||
#define AZURE_HTTPS_SERVER_PORT 443
|
||||
|
||||
#define IOTC_SERVER_RESPONSE_TIMEOUT 20 // seconds
|
||||
#define IOTC_SERVER_RESPONSE_TIMEOUT 20 // seconds
|
||||
|
||||
#define SSL_CLIENT_CERT_PEM NULL
|
||||
#define SSL_CLIENT_CERT_PEM NULL
|
||||
#define SSL_CLIENT_PRIVATE_KEY_PEM NULL
|
||||
|
||||
/* Baltimore */
|
||||
#define SSL_CA_PEM_DEF \
|
||||
"-----BEGIN CERTIFICATE-----\r\n" \
|
||||
"MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\r\n" \
|
||||
"RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\r\n" \
|
||||
"VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\r\n" \
|
||||
"DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\r\n" \
|
||||
"ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\r\n" \
|
||||
"VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\r\n" \
|
||||
"mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\r\n" \
|
||||
"IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\r\n" \
|
||||
"mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\r\n" \
|
||||
"XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\r\n" \
|
||||
"dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\r\n" \
|
||||
"jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\r\n" \
|
||||
"BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\r\n" \
|
||||
"DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\r\n" \
|
||||
"9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\r\n" \
|
||||
"jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\r\n" \
|
||||
"Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\r\n" \
|
||||
"ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\r\n" \
|
||||
"R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\r\n" \
|
||||
"-----END CERTIFICATE-----\r\n"
|
||||
#define SSL_CA_PEM_DEF \
|
||||
"-----BEGIN CERTIFICATE-----\r\n" \
|
||||
"MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\r\n" \
|
||||
"RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\r\n" \
|
||||
"VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\r\n" \
|
||||
"DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\r\n" \
|
||||
"ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\r\n" \
|
||||
"VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\r\n" \
|
||||
"mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\r\n" \
|
||||
"IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\r\n" \
|
||||
"mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\r\n" \
|
||||
"XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\r\n" \
|
||||
"dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\r\n" \
|
||||
"jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\r\n" \
|
||||
"BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\r\n" \
|
||||
"DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\r\n" \
|
||||
"9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\r\n" \
|
||||
"jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\r\n" \
|
||||
"Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\r\n" \
|
||||
"ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\r\n" \
|
||||
"R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\r\n" \
|
||||
"-----END CERTIFICATE-----\r\n"
|
||||
|
||||
// GENERAL
|
||||
#define TO_STRING_(s) #s
|
||||
#define TO_STRING(s) TO_STRING_(s)
|
||||
#define iotc_max(a,b) (a > b ? a : b)
|
||||
#define iotc_min(a,b) (a < b ? a : b)
|
||||
#define iotc_max(a, b) (a > b ? a : b)
|
||||
#define iotc_min(a, b) (a < b ? a : b)
|
||||
|
||||
#define STRING_BUFFER_16 16
|
||||
#define STRING_BUFFER_32 32
|
||||
#define STRING_BUFFER_64 64
|
||||
#define STRING_BUFFER_128 128
|
||||
#define STRING_BUFFER_256 256
|
||||
#define STRING_BUFFER_512 512
|
||||
#define STRING_BUFFER_16 16
|
||||
#define STRING_BUFFER_32 32
|
||||
#define STRING_BUFFER_64 64
|
||||
#define STRING_BUFFER_128 128
|
||||
#define STRING_BUFFER_256 256
|
||||
#define STRING_BUFFER_512 512
|
||||
#define STRING_BUFFER_1024 1024
|
||||
#define STRING_BUFFER_4096 4096
|
||||
|
||||
|
@ -56,16 +56,22 @@
|
|||
#define AZIOTC_API_MAJOR_VERSION 0.
|
||||
#define AZIOTC_API_MINOR_VERSION 2.
|
||||
#define AZIOTC_API_PATCH_VERSION 0
|
||||
#define AZIOTC_API_VERSION TO_STRING(AZIOTC_API_MAJOR_VERSION \
|
||||
AZIOTC_API_MINOR_VERSION AZIOTC_API_PATCH_VERSION) "-msiotc"
|
||||
#define AZIOTC_API_VERSION \
|
||||
TO_STRING(AZIOTC_API_MAJOR_VERSION AZIOTC_API_MINOR_VERSION \
|
||||
AZIOTC_API_PATCH_VERSION) \
|
||||
"-msiotc"
|
||||
|
||||
#define AZURE_IOT_CENTRAL_CLIENT_SIGNATURE "user-agent: iot-central-client/" AZIOTC_API_VERSION
|
||||
#define AZURE_IOT_CENTRAL_CLIENT_SIGNATURE \
|
||||
"user-agent: iot-central-client/" AZIOTC_API_VERSION
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
#define ASSERT_OR_FAIL_FAST(x) assert(x)
|
||||
#else // defined(_DEBUG) || defined(DEBUG)
|
||||
#define ASSERT_OR_FAIL_FAST(x) if (!(x)) { LOG_ERROR(TO_STRING(x) "condition has failed"); }
|
||||
#endif // defined(_DEBUG) || defined(DEBUG)
|
||||
#else // defined(_DEBUG) || defined(DEBUG)
|
||||
#define ASSERT_OR_FAIL_FAST(x) \
|
||||
if (!(x)) { \
|
||||
LOG_ERROR(TO_STRING(x) "condition has failed"); \
|
||||
}
|
||||
#endif // defined(_DEBUG) || defined(DEBUG)
|
||||
|
||||
#ifdef MBED_STATIC_ASSERT
|
||||
#define ASSERT_STATIC MBED_STATIC_ASSERT
|
||||
|
@ -73,4 +79,4 @@ AZIOTC_API_MINOR_VERSION AZIOTC_API_PATCH_VERSION) "-msiotc"
|
|||
#define ASSERT_STATIC static_assert
|
||||
#endif
|
||||
|
||||
#endif // AZURE_IOTC_LITE_DEFINITIONS_H
|
||||
#endif // AZURE_IOTC_LITE_DEFINITIONS_H
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) Oguz Bastemur. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "iotc_internal.h"
|
||||
#include "../common/json.h"
|
||||
|
@ -9,401 +9,453 @@ IOTLogLevel gLogLevel = IOTC_LOGGING_DISABLED;
|
|||
void setLogLevel(IOTLogLevel l) { gLogLevel = l; }
|
||||
IOTLogLevel getLogLevel() { return gLogLevel; }
|
||||
|
||||
unsigned strlen_s_(const char* str, int max_expected) {
|
||||
int ret_val = 0;
|
||||
while(*(str++) != 0) {
|
||||
ret_val++;
|
||||
if (ret_val >= max_expected) return max_expected;
|
||||
}
|
||||
unsigned strlen_s_(const char *str, int max_expected) {
|
||||
int ret_val = 0;
|
||||
while (*(str++) != 0) {
|
||||
ret_val++;
|
||||
if (ret_val >= max_expected) return max_expected;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
#if defined(USE_LIGHT_CLIENT)
|
||||
unsigned long getNow();
|
||||
|
||||
// Self MQTT option supports singletonContext only.
|
||||
static IOTContextInternal *singletonContext = NULL;
|
||||
|
||||
IOTContextInternal* getSingletonContext() { return singletonContext; }
|
||||
void setSingletonContext(IOTContextInternal* ctx) { singletonContext = ctx; }
|
||||
IOTContextInternal *getSingletonContext() { return singletonContext; }
|
||||
void setSingletonContext(IOTContextInternal *ctx) { singletonContext = ctx; }
|
||||
|
||||
int getUsernameAndPasswordFromConnectionString(const char* connectionString, size_t connectionStringLength,
|
||||
int getUsernameAndPasswordFromConnectionString(
|
||||
const char *connectionString, size_t connectionStringLength,
|
||||
AzureIOT::StringBuffer &hostName, AzureIOT::StringBuffer &deviceId,
|
||||
AzureIOT::StringBuffer &username, AzureIOT::StringBuffer &password) {
|
||||
// TODO: improve this so we don't depend on a particular order in connection string
|
||||
AzureIOT::StringBuffer connStr(connectionString, connectionStringLength);
|
||||
// TODO: improve this so we don't depend on a particular order in connection
|
||||
// string
|
||||
AzureIOT::StringBuffer connStr(connectionString, connectionStringLength);
|
||||
|
||||
int32_t hostIndex = connStr.indexOf(HOSTNAME_STRING, HOSTNAME_LENGTH);
|
||||
size_t length = connStr.getLength();
|
||||
if (hostIndex != 0) {
|
||||
IOTC_LOG(F("ERROR: connectionString doesn't start with HostName= RESULT:%d"), hostIndex);
|
||||
return 1;
|
||||
}
|
||||
int32_t hostIndex = connStr.indexOf(HOSTNAME_STRING, HOSTNAME_LENGTH);
|
||||
size_t length = connStr.getLength();
|
||||
if (hostIndex != 0) {
|
||||
IOTC_LOG(
|
||||
F("ERROR: connectionString doesn't start with HostName= RESULT:%d"),
|
||||
hostIndex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t deviceIndex = connStr.indexOf(DEVICEID_STRING, DEVICEID_LENGTH);
|
||||
if (deviceIndex == -1) {
|
||||
IOTC_LOG(F("ERROR: ;DeviceId= not found in the connectionString"));
|
||||
return 1;
|
||||
}
|
||||
int32_t deviceIndex = connStr.indexOf(DEVICEID_STRING, DEVICEID_LENGTH);
|
||||
if (deviceIndex == -1) {
|
||||
IOTC_LOG(F("ERROR: ;DeviceId= not found in the connectionString"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t keyIndex = connStr.indexOf(KEY_STRING, KEY_LENGTH);
|
||||
if (keyIndex == -1) {
|
||||
IOTC_LOG(F("ERROR: ;SharedAccessKey= not found in the connectionString"));
|
||||
return 1;
|
||||
}
|
||||
int32_t keyIndex = connStr.indexOf(KEY_STRING, KEY_LENGTH);
|
||||
if (keyIndex == -1) {
|
||||
IOTC_LOG(F("ERROR: ;SharedAccessKey= not found in the connectionString"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostName.initialize(connectionString + HOSTNAME_LENGTH, deviceIndex - HOSTNAME_LENGTH);
|
||||
deviceId.initialize(connectionString + (deviceIndex + DEVICEID_LENGTH), keyIndex - (deviceIndex + DEVICEID_LENGTH));
|
||||
hostName.initialize(connectionString + HOSTNAME_LENGTH,
|
||||
deviceIndex - HOSTNAME_LENGTH);
|
||||
deviceId.initialize(connectionString + (deviceIndex + DEVICEID_LENGTH),
|
||||
keyIndex - (deviceIndex + DEVICEID_LENGTH));
|
||||
|
||||
AzureIOT::StringBuffer keyBuffer(length - (keyIndex + KEY_LENGTH));
|
||||
memcpy(*keyBuffer, connectionString + (keyIndex + KEY_LENGTH), keyBuffer.getLength());
|
||||
AzureIOT::StringBuffer keyBuffer(length - (keyIndex + KEY_LENGTH));
|
||||
memcpy(*keyBuffer, connectionString + (keyIndex + KEY_LENGTH),
|
||||
keyBuffer.getLength());
|
||||
|
||||
AzureIOT::StringBuffer hostURLEncoded(hostName);
|
||||
hostURLEncoded.urlEncode();
|
||||
AzureIOT::StringBuffer hostURLEncoded(hostName);
|
||||
hostURLEncoded.urlEncode();
|
||||
|
||||
size_t expires = getNow() + EXPIRES;
|
||||
size_t expires = getNow() + EXPIRES;
|
||||
|
||||
AzureIOT::StringBuffer stringToSign(hostURLEncoded.getLength() + STRING_BUFFER_128);
|
||||
AzureIOT::StringBuffer deviceIdEncoded(deviceId);
|
||||
deviceIdEncoded.urlEncode();
|
||||
size_t keyLength = snprintf(*stringToSign, stringToSign.getLength(), "%s%s%s\n%lu000",
|
||||
*hostURLEncoded, "%2Fdevices%2F", *deviceIdEncoded, expires);
|
||||
stringToSign.setLength(keyLength);
|
||||
AzureIOT::StringBuffer stringToSign(hostURLEncoded.getLength() +
|
||||
STRING_BUFFER_128);
|
||||
AzureIOT::StringBuffer deviceIdEncoded(deviceId);
|
||||
deviceIdEncoded.urlEncode();
|
||||
size_t keyLength =
|
||||
snprintf(*stringToSign, stringToSign.getLength(), "%s%s%s\n%lu000",
|
||||
*hostURLEncoded, "%2Fdevices%2F", *deviceIdEncoded, expires);
|
||||
stringToSign.setLength(keyLength);
|
||||
|
||||
keyBuffer.base64Decode();
|
||||
stringToSign.hash(*keyBuffer, keyBuffer.getLength());
|
||||
if (!stringToSign.base64Encode() || !stringToSign.urlEncode()) {
|
||||
IOTC_LOG(F("ERROR: stringToSign base64Encode / urlEncode has failed."));
|
||||
return 1;
|
||||
}
|
||||
keyBuffer.base64Decode();
|
||||
stringToSign.hash(*keyBuffer, keyBuffer.getLength());
|
||||
if (!stringToSign.base64Encode() || !stringToSign.urlEncode()) {
|
||||
IOTC_LOG(F("ERROR: stringToSign base64Encode / urlEncode has failed."));
|
||||
return 1;
|
||||
}
|
||||
|
||||
AzureIOT::StringBuffer passwordBuffer(STRING_BUFFER_512);
|
||||
size_t passLength = snprintf(*passwordBuffer, STRING_BUFFER_512,
|
||||
"SharedAccessSignature sr=%s%s%s&sig=%s&se=%lu000",
|
||||
*hostURLEncoded, "%2Fdevices%2F", *deviceIdEncoded, *stringToSign, expires);
|
||||
AzureIOT::StringBuffer passwordBuffer(STRING_BUFFER_512);
|
||||
size_t passLength = snprintf(
|
||||
*passwordBuffer, STRING_BUFFER_512,
|
||||
"SharedAccessSignature sr=%s%s%s&sig=%s&se=%lu000", *hostURLEncoded,
|
||||
"%2Fdevices%2F", *deviceIdEncoded, *stringToSign, expires);
|
||||
|
||||
assert(passLength && passLength < STRING_BUFFER_512);
|
||||
passwordBuffer.setLength(passLength);
|
||||
assert(passLength && passLength < STRING_BUFFER_512);
|
||||
passwordBuffer.setLength(passLength);
|
||||
|
||||
password.initialize(*passwordBuffer, passwordBuffer.getLength());
|
||||
password.initialize(*passwordBuffer, passwordBuffer.getLength());
|
||||
|
||||
const char * usernameTemplate = "%s/%s/api-version=2016-11-14";
|
||||
AzureIOT::StringBuffer usernameBuffer((strlen(usernameTemplate) - 3 /* %s twice */)
|
||||
+ hostName.getLength() + deviceId.getLength());
|
||||
const char *usernameTemplate = "%s/%s/api-version=2016-11-14";
|
||||
AzureIOT::StringBuffer usernameBuffer(
|
||||
(strlen(usernameTemplate) - 3 /* %s twice */) + hostName.getLength() +
|
||||
deviceId.getLength());
|
||||
|
||||
size_t expLength = snprintf(*usernameBuffer, usernameBuffer.getLength(),
|
||||
usernameTemplate, *hostName, *deviceId);
|
||||
assert(expLength <= usernameBuffer.getLength());
|
||||
size_t expLength = snprintf(*usernameBuffer, usernameBuffer.getLength(),
|
||||
usernameTemplate, *hostName, *deviceId);
|
||||
assert(expLength <= usernameBuffer.getLength());
|
||||
|
||||
username.initialize(*usernameBuffer, usernameBuffer.getLength());
|
||||
username.initialize(*usernameBuffer, usernameBuffer.getLength());
|
||||
|
||||
IOTC_LOG(F(
|
||||
"\r\n"\
|
||||
"hostname: %s\r\n"\
|
||||
"deviceId: %s\r\n"\
|
||||
"username: %s\r\n"\
|
||||
"password: %s\r\n"),
|
||||
*hostName, *deviceId, *username, *password);
|
||||
IOTC_LOG(F("\r\n"
|
||||
"hostname: %s\r\n"
|
||||
"deviceId: %s\r\n"
|
||||
"username: %s\r\n"
|
||||
"password: %s\r\n"),
|
||||
*hostName, *deviceId, *username, *password);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getDPSAuthString(const char* scopeId, const char* deviceId, const char* key,
|
||||
char *buffer, int bufferSize, size_t &outLength) {
|
||||
size_t expires = getNow() + EXPIRES;
|
||||
int getDPSAuthString(const char *scopeId, const char *deviceId, const char *key,
|
||||
char *buffer, int bufferSize, size_t &outLength) {
|
||||
size_t expires = getNow() + EXPIRES;
|
||||
|
||||
AzureIOT::StringBuffer deviceIdEncoded(deviceId, strlen(deviceId));
|
||||
deviceIdEncoded.urlEncode();
|
||||
AzureIOT::StringBuffer deviceIdEncoded(deviceId, strlen(deviceId));
|
||||
deviceIdEncoded.urlEncode();
|
||||
|
||||
AzureIOT::StringBuffer stringToSign(STRING_BUFFER_256);
|
||||
size_t size = snprintf(*stringToSign, STRING_BUFFER_256, "%s%%2Fregistrations%%2F%s", scopeId, *deviceIdEncoded);
|
||||
assert(size < STRING_BUFFER_256);
|
||||
stringToSign.setLength(size);
|
||||
AzureIOT::StringBuffer stringToSign(STRING_BUFFER_256);
|
||||
size_t size =
|
||||
snprintf(*stringToSign, STRING_BUFFER_256, "%s%%2Fregistrations%%2F%s",
|
||||
scopeId, *deviceIdEncoded);
|
||||
assert(size < STRING_BUFFER_256);
|
||||
stringToSign.setLength(size);
|
||||
|
||||
AzureIOT::StringBuffer sr(stringToSign);
|
||||
size = snprintf(*stringToSign, STRING_BUFFER_256, "%s\n%lu000", *sr, expires);
|
||||
assert(size < STRING_BUFFER_256);
|
||||
stringToSign.setLength(size);
|
||||
AzureIOT::StringBuffer sr(stringToSign);
|
||||
size = snprintf(*stringToSign, STRING_BUFFER_256, "%s\n%lu000", *sr, expires);
|
||||
assert(size < STRING_BUFFER_256);
|
||||
stringToSign.setLength(size);
|
||||
|
||||
size = 0;
|
||||
AzureIOT::StringBuffer keyDecoded(key, strlen(key));
|
||||
keyDecoded.base64Decode();
|
||||
stringToSign.hash(*keyDecoded, keyDecoded.getLength());
|
||||
if (!stringToSign.base64Encode() || !stringToSign.urlEncode()) {
|
||||
IOTC_LOG(F("ERROR: stringToSign base64Encode / urlEncode has failed."));
|
||||
return 1;
|
||||
}
|
||||
size = 0;
|
||||
AzureIOT::StringBuffer keyDecoded(key, strlen(key));
|
||||
keyDecoded.base64Decode();
|
||||
stringToSign.hash(*keyDecoded, keyDecoded.getLength());
|
||||
if (!stringToSign.base64Encode() || !stringToSign.urlEncode()) {
|
||||
IOTC_LOG(F("ERROR: stringToSign base64Encode / urlEncode has failed."));
|
||||
return 1;
|
||||
}
|
||||
|
||||
outLength = snprintf(buffer, bufferSize, "authorization: SharedAccessSignature sr=%s&sig=%s&se=%lu000&skn=registration",
|
||||
*sr, *stringToSign, expires);
|
||||
assert(outLength > 0 && outLength < bufferSize);
|
||||
buffer[outLength] = 0;
|
||||
outLength = snprintf(buffer, bufferSize,
|
||||
"authorization: SharedAccessSignature "
|
||||
"sr=%s&sig=%s&se=%lu000&skn=registration",
|
||||
*sr, *stringToSign, expires);
|
||||
assert(outLength > 0 && outLength < bufferSize);
|
||||
buffer[outLength] = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// send telemetry etc. confirmation callback
|
||||
/* MessageSent */
|
||||
void sendConfirmationCallback(const char* buffer, size_t size) {
|
||||
IOTContextInternal *internal = (IOTContextInternal*)singletonContext;
|
||||
int result = 0;
|
||||
void sendConfirmationCallback(const char *buffer, size_t size) {
|
||||
IOTContextInternal *internal = (IOTContextInternal *)singletonContext;
|
||||
int result = 0;
|
||||
|
||||
if (internal->callbacks[/*IOTCallbacks::*/MessageSent].callback) {
|
||||
IOTCallbackInfo info;
|
||||
info.eventName = "MessageSent";
|
||||
info.tag = NULL;
|
||||
info.payload = (const char*) buffer;
|
||||
info.payloadLength = (unsigned) size;
|
||||
info.appContext = internal->callbacks[/*IOTCallbacks::*/::MessageSent].appContext;
|
||||
info.statusCode = (int)result;
|
||||
info.callbackResponse = NULL;
|
||||
internal->callbacks[/*IOTCallbacks::*/::MessageSent].callback(internal, &info);
|
||||
}
|
||||
if (internal->callbacks[/*IOTCallbacks::*/ MessageSent].callback) {
|
||||
IOTCallbackInfo info;
|
||||
info.eventName = "MessageSent";
|
||||
info.tag = NULL;
|
||||
info.payload = (const char *)buffer;
|
||||
info.payloadLength = (unsigned)size;
|
||||
info.appContext =
|
||||
internal->callbacks[/*IOTCallbacks::*/ ::MessageSent].appContext;
|
||||
info.statusCode = (int)result;
|
||||
info.callbackResponse = NULL;
|
||||
internal->callbacks[/*IOTCallbacks::*/ ::MessageSent].callback(internal,
|
||||
&info);
|
||||
}
|
||||
}
|
||||
|
||||
/* Command */
|
||||
static int onCommand(const char* method_name, const char* payload,
|
||||
size_t size, char** response, size_t* resp_size, void* userContextCallback) {
|
||||
static int onCommand(const char *method_name, const char *payload, size_t size,
|
||||
char **response, size_t *resp_size,
|
||||
void *userContextCallback) {
|
||||
assert(response != NULL && resp_size != NULL);
|
||||
*response = NULL;
|
||||
*resp_size = 0;
|
||||
IOTContextInternal *internal = (IOTContextInternal *)userContextCallback;
|
||||
assert(internal != NULL);
|
||||
|
||||
assert(response != NULL && resp_size != NULL);
|
||||
*response = NULL;
|
||||
*resp_size = 0;
|
||||
IOTContextInternal *internal = (IOTContextInternal*)userContextCallback;
|
||||
assert(internal != NULL);
|
||||
if (internal->callbacks[/*IOTCallbacks::*/ ::Command].callback) {
|
||||
IOTCallbackInfo info;
|
||||
info.eventName = "Command";
|
||||
info.tag = method_name;
|
||||
info.payload = (const char *)payload;
|
||||
info.payloadLength = (unsigned)size;
|
||||
info.appContext =
|
||||
internal->callbacks[/*IOTCallbacks::*/ ::Command].appContext;
|
||||
info.statusCode = 0;
|
||||
info.callbackResponse = NULL;
|
||||
internal->callbacks[/*IOTCallbacks::*/ ::Command].callback(internal, &info);
|
||||
|
||||
if (internal->callbacks[/*IOTCallbacks::*/::Command].callback) {
|
||||
IOTCallbackInfo info;
|
||||
info.eventName = "Command";
|
||||
info.tag = method_name;
|
||||
info.payload = (const char*) payload;
|
||||
info.payloadLength = (unsigned) size;
|
||||
info.appContext = internal->callbacks[/*IOTCallbacks::*/::Command].appContext;
|
||||
info.statusCode = 0;
|
||||
info.callbackResponse = NULL;
|
||||
internal->callbacks[/*IOTCallbacks::*/::Command].callback(internal, &info);
|
||||
|
||||
if (info.callbackResponse != NULL) {
|
||||
*response = (char*) info.callbackResponse;
|
||||
*resp_size = strlen((char*) info.callbackResponse);
|
||||
}
|
||||
return 200;
|
||||
if (info.callbackResponse != NULL) {
|
||||
*response = (char *)info.callbackResponse;
|
||||
*resp_size = strlen((char *)info.callbackResponse);
|
||||
}
|
||||
return 200;
|
||||
}
|
||||
|
||||
return 500;
|
||||
return 500;
|
||||
}
|
||||
|
||||
/* ConnectionStatus */
|
||||
void connectionStatusCallback(IOTConnectionState status, IOTContextInternal *internal) {
|
||||
if (internal->callbacks[/*IOTCallbacks::*/::ConnectionStatus].callback) {
|
||||
IOTCallbackInfo info;
|
||||
info.eventName = "ConnectionStatus";
|
||||
info.tag = NULL;
|
||||
info.payload = NULL;
|
||||
info.payloadLength = 0;
|
||||
info.appContext = internal->callbacks[/*IOTCallbacks::*/::ConnectionStatus].appContext;
|
||||
info.statusCode = status;
|
||||
info.callbackResponse = NULL;
|
||||
internal->callbacks[/*IOTCallbacks::*/::ConnectionStatus].callback(internal, &info);
|
||||
}
|
||||
void connectionStatusCallback(IOTConnectionState status,
|
||||
IOTContextInternal *internal) {
|
||||
if (internal->callbacks[/*IOTCallbacks::*/ ::ConnectionStatus].callback) {
|
||||
IOTCallbackInfo info;
|
||||
info.eventName = "ConnectionStatus";
|
||||
info.tag = NULL;
|
||||
info.payload = NULL;
|
||||
info.payloadLength = 0;
|
||||
info.appContext =
|
||||
internal->callbacks[/*IOTCallbacks::*/ ::ConnectionStatus].appContext;
|
||||
info.statusCode = status;
|
||||
info.callbackResponse = NULL;
|
||||
internal->callbacks[/*IOTCallbacks::*/ ::ConnectionStatus].callback(
|
||||
internal, &info);
|
||||
}
|
||||
}
|
||||
|
||||
void sendOnError(IOTContextInternal *internal, const char* message) {
|
||||
if (internal->callbacks[/*IOTCallbacks::*/::Error].callback) {
|
||||
IOTCallbackInfo info;
|
||||
info.eventName = "Error";
|
||||
info.tag = message; // message lifetime should be managed by us
|
||||
info.payload = NULL;
|
||||
info.payloadLength = 0;
|
||||
info.appContext = internal->callbacks[/*IOTCallbacks::*/::Error].appContext;
|
||||
info.statusCode = 1;
|
||||
info.callbackResponse = NULL;
|
||||
internal->callbacks[/*IOTCallbacks::*/::Error].callback(internal, &info);
|
||||
}
|
||||
void sendOnError(IOTContextInternal *internal, const char *message) {
|
||||
if (internal->callbacks[/*IOTCallbacks::*/ ::Error].callback) {
|
||||
IOTCallbackInfo info;
|
||||
info.eventName = "Error";
|
||||
info.tag = message; // message lifetime should be managed by us
|
||||
info.payload = NULL;
|
||||
info.payloadLength = 0;
|
||||
info.appContext =
|
||||
internal->callbacks[/*IOTCallbacks::*/ ::Error].appContext;
|
||||
info.statusCode = 1;
|
||||
info.callbackResponse = NULL;
|
||||
internal->callbacks[/*IOTCallbacks::*/ ::Error].callback(internal, &info);
|
||||
}
|
||||
}
|
||||
|
||||
void echoDesired(IOTContextInternal *internal, const char *propertyName,
|
||||
AzureIOT::StringBuffer &message, const char *status, int statusCode) {
|
||||
AzureIOT::JSObject rootObject(*message);
|
||||
AzureIOT::JSObject propertyNameObject;
|
||||
AzureIOT::StringBuffer &message, const char *status,
|
||||
int statusCode) {
|
||||
AzureIOT::JSObject rootObject(*message);
|
||||
AzureIOT::JSObject propertyNameObject;
|
||||
|
||||
rootObject.getObjectByName(propertyName, &propertyNameObject);
|
||||
rootObject.getObjectByName(propertyName, &propertyNameObject);
|
||||
|
||||
double value = 0, desiredVersion = 0;
|
||||
propertyName = rootObject.getNameAt(0);
|
||||
double value = 0, desiredVersion = 0;
|
||||
propertyName = rootObject.getNameAt(0);
|
||||
|
||||
value = propertyNameObject.getNumberByName("value");
|
||||
desiredVersion = rootObject.getNumberByName("$version");
|
||||
value = propertyNameObject.getNumberByName("value");
|
||||
desiredVersion = rootObject.getNumberByName("$version");
|
||||
|
||||
const char* echoTemplate = "{\"%s\":{\"value\":%d,\"statusCode\":%d,\
|
||||
const char *echoTemplate =
|
||||
"{\"%s\":{\"value\":%d,\"statusCode\":%d,\
|
||||
\"status\":\"%s\",\"desiredVersion\":%d}}";
|
||||
uint32_t buffer_size = strlen(echoTemplate) + 23 /* x64 value */ + 3 /* statusCode */
|
||||
+ 32 /* status */ + 23 /* version max */;
|
||||
buffer_size = iotc_min(buffer_size, 512);
|
||||
AzureIOT::StringBuffer buffer(buffer_size);
|
||||
uint32_t buffer_size = strlen(echoTemplate) + 23 /* x64 value */ +
|
||||
3 /* statusCode */
|
||||
+ 32 /* status */ + 23 /* version max */;
|
||||
buffer_size = iotc_min(buffer_size, 512);
|
||||
AzureIOT::StringBuffer buffer(buffer_size);
|
||||
|
||||
size_t size = snprintf(*buffer, buffer_size, echoTemplate, propertyName,
|
||||
(int) value, statusCode, status, (int) desiredVersion);
|
||||
buffer.setLength(size);
|
||||
size_t size = snprintf(*buffer, buffer_size, echoTemplate, propertyName,
|
||||
(int)value, statusCode, status, (int)desiredVersion);
|
||||
buffer.setLength(size);
|
||||
|
||||
const char* topicName = "$iothub/twin/PATCH/properties/reported/?$rid=%d";
|
||||
AzureIOT::StringBuffer topic(strlen(topicName) + 21); // + 2 for %d == +23 in case requestId++ overflows
|
||||
topic.setLength(snprintf(*topic, topic.getLength(), topicName, internal->messageId++));
|
||||
const char *topicName = "$iothub/twin/PATCH/properties/reported/?$rid=%d";
|
||||
AzureIOT::StringBuffer topic(
|
||||
strlen(topicName) +
|
||||
21); // + 2 for %d == +23 in case requestId++ overflows
|
||||
topic.setLength(
|
||||
snprintf(*topic, topic.getLength(), topicName, internal->messageId++));
|
||||
|
||||
if (mqtt_publish(internal, *topic, topic.getLength(), *buffer, size) != 0) {
|
||||
IOTC_LOG(F("ERROR: (echoDesired) MQTTClient publish has failed."));
|
||||
}
|
||||
if (mqtt_publish(internal, *topic, topic.getLength(), *buffer, size) != 0) {
|
||||
IOTC_LOG("ERROR: (echoDesired) MQTTClient publish has failed => %s",
|
||||
*buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void callDesiredCallback(IOTContextInternal *internal, const char *propertyName, AzureIOT::StringBuffer &payload) {
|
||||
const char* response = "completed";
|
||||
if (internal->callbacks[/*IOTCallbacks::*/::SettingsUpdated].callback) {
|
||||
IOTCallbackInfo info;
|
||||
info.eventName = "SettingsUpdated";
|
||||
info.tag = propertyName;
|
||||
info.payload = *payload;
|
||||
info.payloadLength = payload.getLength();
|
||||
info.appContext = internal->callbacks[/*IOTCallbacks::*/::SettingsUpdated].appContext;
|
||||
info.statusCode = 200;
|
||||
info.callbackResponse = NULL;
|
||||
internal->callbacks[/*IOTCallbacks::*/::SettingsUpdated].callback(internal, &info);
|
||||
if (info.callbackResponse) {
|
||||
response = (const char*)info.callbackResponse;
|
||||
}
|
||||
echoDesired(internal, propertyName, payload, response, info.statusCode);
|
||||
void callDesiredCallback(IOTContextInternal *internal, const char *propertyName,
|
||||
AzureIOT::StringBuffer &payload) {
|
||||
const char *response = "completed";
|
||||
if (internal->callbacks[/*IOTCallbacks::*/ ::SettingsUpdated].callback) {
|
||||
IOTCallbackInfo info;
|
||||
info.eventName = "SettingsUpdated";
|
||||
info.tag = propertyName;
|
||||
info.payload = *payload;
|
||||
info.payloadLength = payload.getLength();
|
||||
info.appContext =
|
||||
internal->callbacks[/*IOTCallbacks::*/ ::SettingsUpdated].appContext;
|
||||
info.statusCode = 200;
|
||||
info.callbackResponse = NULL;
|
||||
internal->callbacks[/*IOTCallbacks::*/ ::SettingsUpdated].callback(internal,
|
||||
&info);
|
||||
if (info.callbackResponse) {
|
||||
response = (const char *)info.callbackResponse;
|
||||
}
|
||||
echoDesired(internal, propertyName, payload, response, info.statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
static void deviceTwinGetStateCallback(DEVICE_TWIN_UPDATE_STATE update_state,
|
||||
AzureIOT::StringBuffer &payload, void* userContextCallback) {
|
||||
AzureIOT::StringBuffer &payload,
|
||||
void *userContextCallback) {
|
||||
IOTContextInternal *internal = (IOTContextInternal *)userContextCallback;
|
||||
assert(internal != NULL);
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)userContextCallback;
|
||||
assert(internal != NULL);
|
||||
AzureIOT::JSObject desired(*payload);
|
||||
|
||||
AzureIOT::JSObject desired(*payload);
|
||||
|
||||
for (unsigned i = 0, count = desired.getCount(); i < count; i++) {
|
||||
const char * itemName = desired.getNameAt(i);
|
||||
if (itemName != NULL && itemName[0] != '$') {
|
||||
callDesiredCallback(internal, itemName, payload);
|
||||
}
|
||||
for (unsigned i = 0, count = desired.getCount(); i < count; i++) {
|
||||
const char *itemName = desired.getNameAt(i);
|
||||
if (itemName != NULL && itemName[0] != '$') {
|
||||
callDesiredCallback(internal, itemName, payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handlePayload(char *msg, unsigned long msg_length, char *topic, unsigned long topic_length) {
|
||||
if (topic_length) {
|
||||
assert(topic != NULL);
|
||||
AzureIOT::StringBuffer topicName(topic, topic_length);
|
||||
if (topicName.startsWith("$iothub/twin/res", strlen("$iothub/twin/res"))) return;
|
||||
void handlePayload(char *msg, unsigned long msg_length, char *topic,
|
||||
unsigned long topic_length) {
|
||||
if (topic_length) {
|
||||
assert(topic != NULL);
|
||||
AzureIOT::StringBuffer topicName(topic, topic_length);
|
||||
if (topicName.startsWith("$iothub/twin/res", strlen("$iothub/twin/res")))
|
||||
return;
|
||||
|
||||
AzureIOT::StringBuffer payload;
|
||||
if (msg_length) {
|
||||
payload.initialize(msg, msg_length);
|
||||
}
|
||||
|
||||
if (topicName.startsWith("$iothub/twin/PATCH/properties/desired/", strlen("$iothub/twin/PATCH/properties/desired/"))) {
|
||||
deviceTwinGetStateCallback(DEVICE_TWIN_UPDATE_ALL, payload, singletonContext);
|
||||
} else if (topicName.startsWith("$iothub/methods", strlen("$iothub/methods"))) {
|
||||
int index = topicName.indexOf("$rid=", 5, 0);
|
||||
if (index == -1) {
|
||||
IOTC_LOG(F("ERROR: corrupt C2D message topic => %s"), *topicName);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* topicId = (*topicName + index + 5);
|
||||
const char* topicTemplate = "$iothub/methods/POST/";
|
||||
const int topicTemplateLength = strlen(topicTemplate);
|
||||
index = topicName.indexOf("/", 1, topicTemplateLength + 1);
|
||||
if (index == -1) {
|
||||
IOTC_LOG(F("ERROR: corrupt C2D message topic (methodName) => %s"), *topicName);
|
||||
return;
|
||||
}
|
||||
|
||||
AzureIOT::StringBuffer methodName(topic + topicTemplateLength, index - topicTemplateLength);
|
||||
|
||||
const char* constResponse = "{}";
|
||||
char* response = NULL;
|
||||
size_t respSize = 0;
|
||||
int rc = onCommand(*methodName, msg, msg_length, &response, &respSize, getSingletonContext());
|
||||
if (respSize == 0) {
|
||||
respSize = 2;
|
||||
} else {
|
||||
constResponse = response;
|
||||
}
|
||||
|
||||
AzureIOT::StringBuffer respTopic(STRING_BUFFER_128);
|
||||
respTopic.setLength(snprintf(*respTopic, STRING_BUFFER_128, "$iothub/methods/res/%d/?$rid=%s", rc, topicId));
|
||||
|
||||
if (mqtt_publish(getSingletonContext(), *respTopic, respTopic.getLength(), constResponse, respSize) != 0) {
|
||||
IOTC_LOG(F("ERROR: mqtt_publish has failed during C2D with response topic '%s' and response '%s'"), *respTopic, constResponse);
|
||||
}
|
||||
if (response != constResponse) {
|
||||
free(response);
|
||||
}
|
||||
} else {
|
||||
IOTC_LOG(F("ERROR: unknown twin topic: %s, msg: %s"), topic, msg_length ? msg : "NULL");
|
||||
}
|
||||
AzureIOT::StringBuffer payload;
|
||||
if (msg_length) {
|
||||
payload.initialize(msg, msg_length);
|
||||
}
|
||||
|
||||
if (topicName.startsWith(
|
||||
"$iothub/twin/PATCH/properties/desired/",
|
||||
strlen("$iothub/twin/PATCH/properties/desired/"))) {
|
||||
deviceTwinGetStateCallback(DEVICE_TWIN_UPDATE_ALL, payload,
|
||||
singletonContext);
|
||||
} else if (topicName.startsWith("$iothub/methods",
|
||||
strlen("$iothub/methods"))) {
|
||||
int index = topicName.indexOf("$rid=", 5, 0);
|
||||
if (index == -1) {
|
||||
IOTC_LOG(F("ERROR: corrupt C2D message topic => %s"), *topicName);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *topicId = (*topicName + index + 5);
|
||||
const char *topicTemplate = "$iothub/methods/POST/";
|
||||
const int topicTemplateLength = strlen(topicTemplate);
|
||||
index = topicName.indexOf("/", 1, topicTemplateLength + 1);
|
||||
if (index == -1) {
|
||||
IOTC_LOG(F("ERROR: corrupt C2D message topic (methodName) => %s"),
|
||||
*topicName);
|
||||
return;
|
||||
}
|
||||
|
||||
AzureIOT::StringBuffer methodName(topic + topicTemplateLength,
|
||||
index - topicTemplateLength);
|
||||
|
||||
const char *constResponse = "{}";
|
||||
char *response = NULL;
|
||||
size_t respSize = 0;
|
||||
int rc = onCommand(*methodName, msg, msg_length, &response, &respSize,
|
||||
getSingletonContext());
|
||||
if (respSize == 0) {
|
||||
respSize = 2;
|
||||
} else {
|
||||
constResponse = response;
|
||||
}
|
||||
|
||||
AzureIOT::StringBuffer respTopic(STRING_BUFFER_128);
|
||||
respTopic.setLength(snprintf(*respTopic, STRING_BUFFER_128,
|
||||
"$iothub/methods/res/%d/?$rid=%s", rc,
|
||||
topicId));
|
||||
|
||||
if (mqtt_publish(getSingletonContext(), *respTopic, respTopic.getLength(),
|
||||
constResponse, respSize) != 0) {
|
||||
IOTC_LOG(
|
||||
"ERROR: mqtt_publish has failed during C2D with response "
|
||||
"topic '%s' and response '%s'",
|
||||
*respTopic, constResponse);
|
||||
}
|
||||
if (response != constResponse) {
|
||||
free(response);
|
||||
}
|
||||
} else {
|
||||
IOTC_LOG(F("ERROR: unknown twin topic: %s, msg: %s"), topic,
|
||||
msg_length ? msg : "NULL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_send_telemetry(IOTContext ctx, const char* payload, unsigned length) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(payload)
|
||||
int iotc_send_telemetry(IOTContext ctx, const char *payload, unsigned length) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(payload)
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
IOTContextInternal *internal = (IOTContextInternal *)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
|
||||
AzureIOT::StringBuffer topic(internal->deviceId.getLength() + strlen("devices/ /messages/events/"));
|
||||
topic.setLength(snprintf(*topic, topic.getLength(), "devices/%s/messages/events/", *internal->deviceId));
|
||||
if (mqtt_publish(internal, *topic, topic.getLength(), payload, length) != 0) {
|
||||
IOTC_LOG(F("ERROR: (iotc_send_telemetry) MQTTClient publish has failed."));
|
||||
return 1;
|
||||
}
|
||||
AzureIOT::StringBuffer topic(internal->deviceId.getLength() +
|
||||
strlen("devices/ /messages/events/"));
|
||||
topic.setLength(snprintf(*topic, topic.getLength(),
|
||||
"devices/%s/messages/events/", *internal->deviceId));
|
||||
if (mqtt_publish(internal, *topic, topic.getLength(), payload, length) != 0) {
|
||||
IOTC_LOG("ERROR: (iotc_send_telemetry) MQTTClient publish has failed => %s",
|
||||
payload);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sendConfirmationCallback(payload, length);
|
||||
return 0;
|
||||
sendConfirmationCallback(payload, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_send_property (IOTContext ctx, const char* payload, unsigned length) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(payload)
|
||||
int iotc_send_property(IOTContext ctx, const char *payload, unsigned length) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(payload)
|
||||
|
||||
IOTContextInternal *internal = (IOTContextInternal*)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
IOTContextInternal *internal = (IOTContextInternal *)ctx;
|
||||
MUST_CALL_AFTER_CONNECT(internal);
|
||||
|
||||
const char* topicName = "$iothub/twin/PATCH/properties/reported/?$rid=%d";
|
||||
AzureIOT::StringBuffer topic(strlen(topicName) + 21); // + 2 for %d == +23 in case requestId++ overflows
|
||||
topic.setLength(snprintf(*topic, topic.getLength(), topicName, internal->messageId++));
|
||||
const char *topicName = "$iothub/twin/PATCH/properties/reported/?$rid=%d";
|
||||
AzureIOT::StringBuffer topic(
|
||||
strlen(topicName) +
|
||||
21); // + 2 for %d == +23 in case requestId++ overflows
|
||||
topic.setLength(
|
||||
snprintf(*topic, topic.getLength(), topicName, internal->messageId++));
|
||||
|
||||
if (mqtt_publish(internal, *topic, topic.getLength(), payload, length) != 0) {
|
||||
IOTC_LOG(F("ERROR: (iotc_send_property) MQTTClient publish has failed."));
|
||||
return 1;
|
||||
}
|
||||
if (mqtt_publish(internal, *topic, topic.getLength(), payload, length) != 0) {
|
||||
IOTC_LOG("ERROR: (iotc_send_property) MQTTClient publish has failed => %s",
|
||||
payload);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sendConfirmationCallback(payload, length);
|
||||
return 0;
|
||||
sendConfirmationCallback(payload, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extern */
|
||||
int iotc_init_context(IOTContext *ctx) {
|
||||
CHECK_NOT_NULL(ctx)
|
||||
CHECK_NOT_NULL(ctx)
|
||||
|
||||
if (getSingletonContext() != NULL) {
|
||||
IOTC_LOG(F("ERROR: (iotc_init_context) Self MQTT version supports singleton context only."));
|
||||
return 1;
|
||||
}
|
||||
if (getSingletonContext() != NULL) {
|
||||
IOTC_LOG("ERROR: (iotc_init_context) Device context was already created.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
MUST_CALL_BEFORE_INIT((*ctx));
|
||||
IOTContextInternal *internal = (IOTContextInternal*)malloc(sizeof(IOTContextInternal));
|
||||
CHECK_NOT_NULL(internal);
|
||||
memset(internal, 0, sizeof(IOTContextInternal));
|
||||
*ctx = (void*)internal;
|
||||
MUST_CALL_BEFORE_INIT((*ctx));
|
||||
IOTContextInternal *internal =
|
||||
(IOTContextInternal *)malloc(sizeof(IOTContextInternal));
|
||||
CHECK_NOT_NULL(internal);
|
||||
memset(internal, 0, sizeof(IOTContextInternal));
|
||||
*ctx = (void *)internal;
|
||||
|
||||
setSingletonContext(internal);
|
||||
setSingletonContext(internal);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // USE_LIGHT_CLIENT
|
||||
return 0;
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
// Copyright (c) Oguz Bastemur. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef AZURE_IOTC_INTERNAL_H
|
||||
#define AZURE_IOTC_INTERNAL_H
|
||||
|
||||
#include "iotc_platform.h"
|
||||
#include "iotc_definitions.h"
|
||||
#include "iotc_platform.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h> // size_t etc.
|
||||
#include <limits.h>
|
||||
#include <stddef.h> // size_t etc.
|
||||
#include "../iotc.h"
|
||||
#include "string_buffer.h"
|
||||
|
||||
|
@ -19,147 +19,142 @@
|
|||
#define TO_STR(s) TO_STR_(s)
|
||||
|
||||
typedef enum IOTCallbacks_TAG {
|
||||
ConnectionStatus = 0x01,
|
||||
MessageSent,
|
||||
Command,
|
||||
Error,
|
||||
SettingsUpdated
|
||||
ConnectionStatus = 0x01,
|
||||
MessageSent,
|
||||
Command,
|
||||
Error,
|
||||
SettingsUpdated
|
||||
} IOTCallbacks;
|
||||
|
||||
typedef struct CallbackBase_TAG {
|
||||
IOTCallback callback;
|
||||
void *appContext;
|
||||
CallbackBase_TAG() { callback = NULL; appContext = NULL; }
|
||||
CallbackBase_TAG() {
|
||||
callback = NULL;
|
||||
appContext = NULL;
|
||||
}
|
||||
} CallbackBase;
|
||||
|
||||
typedef struct IOTContextInternal_TAG {
|
||||
char *endpoint;
|
||||
IOTProtocol protocol;
|
||||
CallbackBase callbacks[8];
|
||||
#if defined(USE_LIGHT_CLIENT)
|
||||
int messageId;
|
||||
AzureIOT::StringBuffer deviceId;
|
||||
#else // use azure iot client
|
||||
IOTHUB_CLIENT_LL_HANDLE clientHandle;
|
||||
#endif // USE_LIGHT_CLIENT
|
||||
char *endpoint;
|
||||
IOTProtocol protocol;
|
||||
CallbackBase callbacks[8];
|
||||
|
||||
#ifdef USE_LIGHT_CLIENT
|
||||
#if defined(__MBED__)
|
||||
AzureIOT::TLSClient *tlsClient;
|
||||
MQTT::Client<AzureIOT::TLSClient, Countdown, STRING_BUFFER_1024, 5>* mqttClient;
|
||||
#elif defined(ARDUINO)
|
||||
ARDUINO_WIFI_SSL_CLIENT *tlsClient;
|
||||
PubSubClient *mqttClient;
|
||||
#endif // __MBED__
|
||||
#endif // USE_LIGHT_CLIENT
|
||||
int messageId;
|
||||
AzureIOT::StringBuffer deviceId;
|
||||
ARDUINO_WIFI_SSL_CLIENT *tlsClient;
|
||||
PubSubClient *mqttClient;
|
||||
} IOTContextInternal;
|
||||
|
||||
#define CHECK_NOT_NULL(x) if (x == NULL) { IOTC_LOG(F(TO_STR(x) "is NULL")); return 1; }
|
||||
#define CHECK_NOT_NULL(x) \
|
||||
if (x == NULL) { \
|
||||
IOTC_LOG(F(TO_STR(x) "is NULL")); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define GET_LENGTH_NOT_NULL_NOT_EMPTY(x, maxlen) \
|
||||
unsigned x ## _len = 0; \
|
||||
do { \
|
||||
CHECK_NOT_NULL(x) \
|
||||
x ## _len = strlen_s_(x, INT_MAX); \
|
||||
if (x ## _len == 0 || x ## _len > maxlen) { \
|
||||
IOTC_LOG(F("ERROR: " TO_STR(x) "has length %d"), x ## _len); return 1; \
|
||||
} \
|
||||
} while(0)
|
||||
#define GET_LENGTH_NOT_NULL_NOT_EMPTY(x, maxlen) \
|
||||
unsigned x##_len = 0; \
|
||||
do { \
|
||||
CHECK_NOT_NULL(x) \
|
||||
x##_len = strlen_s_(x, INT_MAX); \
|
||||
if (x##_len == 0 || x##_len > maxlen) { \
|
||||
IOTC_LOG(F("ERROR: " TO_STR(x) "has length %d"), x##_len); \
|
||||
return 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define GET_LENGTH_NOT_NULL(x, maxlen) \
|
||||
unsigned x ## _len = 0; \
|
||||
do { \
|
||||
CHECK_NOT_NULL(x) \
|
||||
x ## _len = strlen_s_(x, INT_MAX); \
|
||||
if (x ## _len > maxlen) { \
|
||||
IOTC_LOG(F("ERROR: " TO_STR(x) " has length %d"), x ## _len); return 1; \
|
||||
} \
|
||||
} while(0)
|
||||
#define GET_LENGTH_NOT_NULL(x, maxlen) \
|
||||
unsigned x##_len = 0; \
|
||||
do { \
|
||||
CHECK_NOT_NULL(x) \
|
||||
x##_len = strlen_s_(x, INT_MAX); \
|
||||
if (x##_len > maxlen) { \
|
||||
IOTC_LOG(F("ERROR: " TO_STR(x) " has length %d"), x##_len); \
|
||||
return 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MUST_CALL_BEFORE_INIT(x) \
|
||||
if (x != NULL) { \
|
||||
IOTC_LOG(F("ERROR: Client was already initialized. ERR:0x0006")); \
|
||||
return 6; \
|
||||
}
|
||||
#define MUST_CALL_BEFORE_INIT(x) \
|
||||
if (x != NULL) { \
|
||||
IOTC_LOG(F("ERROR: Client was already initialized. ERR:0x0006")); \
|
||||
return 6; \
|
||||
}
|
||||
|
||||
#define MUST_CALL_AFTER_INIT(x) \
|
||||
if (x == NULL) { \
|
||||
IOTC_LOG(F("ERROR: Client was not initialized. ERR:0x0007")); \
|
||||
return 7; \
|
||||
}
|
||||
#define MUST_CALL_AFTER_INIT(x) \
|
||||
if (x == NULL) { \
|
||||
IOTC_LOG(F("ERROR: Client was not initialized. ERR:0x0007")); \
|
||||
return 7; \
|
||||
}
|
||||
|
||||
#ifdef USE_LIGHT_CLIENT
|
||||
#define MUST_CALL_AFTER_CONNECT(x) \
|
||||
if (x == NULL || x->mqttClient == NULL) { \
|
||||
IOTC_LOG(F("ERROR: Client was not connected.")); \
|
||||
return 1; \
|
||||
}
|
||||
#else // USE_LIGHT_CLIENT
|
||||
#define MUST_CALL_AFTER_CONNECT(x) \
|
||||
if (x == NULL || x->clientHandle == NULL) { \
|
||||
IOTC_LOG(F("ERROR: Client was not connected.")); \
|
||||
return 1; \
|
||||
}
|
||||
#endif // USE_LIGHT_CLIENT
|
||||
#define MUST_CALL_AFTER_CONNECT(x) \
|
||||
if (x == NULL || x->mqttClient == NULL) { \
|
||||
IOTC_LOG(F("ERROR: Client was not connected.")); \
|
||||
return 1; \
|
||||
}
|
||||
#else // USE_LIGHT_CLIENT
|
||||
#define MUST_CALL_AFTER_CONNECT(x) \
|
||||
if (x == NULL || x->clientHandle == NULL) { \
|
||||
IOTC_LOG(F("ERROR: Client was not connected.")); \
|
||||
return 1; \
|
||||
}
|
||||
#endif // USE_LIGHT_CLIENT
|
||||
|
||||
// when the auth token expires
|
||||
#define EXPIRES 21600 // 6 hours
|
||||
#define EXPIRES 21600 // 6 hours
|
||||
|
||||
typedef enum IOTHUBMESSAGE_DISPOSITION_RESULT_TAG {
|
||||
IOTHUBMESSAGE_ACCEPTED = 0x01,
|
||||
IOTHUBMESSAGE_ABANDONED
|
||||
IOTHUBMESSAGE_ACCEPTED = 0x01,
|
||||
IOTHUBMESSAGE_ABANDONED
|
||||
} IOTHUBMESSAGE_DISPOSITION_RESULT;
|
||||
|
||||
typedef enum DEVICE_TWIN_UPDATE_STATE_TAG {
|
||||
DEVICE_TWIN_UPDATE_PARTIAL = 0,
|
||||
DEVICE_TWIN_UPDATE_ALL = 1
|
||||
DEVICE_TWIN_UPDATE_PARTIAL = 0,
|
||||
DEVICE_TWIN_UPDATE_ALL = 1
|
||||
} DEVICE_TWIN_UPDATE_STATE;
|
||||
|
||||
#define HOSTNAME_STRING "HostName="
|
||||
#define DEVICEID_STRING ";DeviceId="
|
||||
#define KEY_STRING ";SharedAccessKey="
|
||||
#define KEY_STRING ";SharedAccessKey="
|
||||
#define HOSTNAME_LENGTH (sizeof(HOSTNAME_STRING) - 1)
|
||||
#define DEVICEID_LENGTH (sizeof(DEVICEID_STRING) - 1)
|
||||
#define KEY_LENGTH (sizeof(KEY_STRING) - 1)
|
||||
#define KEY_LENGTH (sizeof(KEY_STRING) - 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned strlen_s_(const char* str, int max_expected);
|
||||
int getUsernameAndPasswordFromConnectionString(const char* connectionString, size_t connectionStringLength,
|
||||
unsigned strlen_s_(const char *str, int max_expected);
|
||||
int getUsernameAndPasswordFromConnectionString(
|
||||
const char *connectionString, size_t connectionStringLength,
|
||||
AzureIOT::StringBuffer &hostName, AzureIOT::StringBuffer &deviceId,
|
||||
AzureIOT::StringBuffer &username, AzureIOT::StringBuffer &password);
|
||||
|
||||
int getDPSAuthString(const char* scopeId, const char* deviceId, const char* key,
|
||||
char *buffer, int bufferSize, size_t &outLength);
|
||||
int getDPSAuthString(const char *scopeId, const char *deviceId, const char *key,
|
||||
char *buffer, int bufferSize, size_t &outLength);
|
||||
|
||||
void setLogLevel(IOTLogLevel l);
|
||||
IOTLogLevel getLogLevel();
|
||||
|
||||
void handlePayload(char *msg, unsigned long msg_length, char *topic, unsigned long topic_length);
|
||||
int getHubHostName(const char* dpsEndpoint, const char *scopeId, const char* deviceId, const char* key, char *hostName);
|
||||
void connectionStatusCallback(IOTConnectionState status, IOTContextInternal *internal);
|
||||
IOTContextInternal* getSingletonContext();
|
||||
void setSingletonContext(IOTContextInternal* ctx);
|
||||
void sendConfirmationCallback(const char* buffer, size_t size);
|
||||
void handlePayload(char *msg, unsigned long msg_length, char *topic,
|
||||
unsigned long topic_length);
|
||||
int getHubHostName(const char *dpsEndpoint, const char *scopeId,
|
||||
const char *deviceId, const char *key, char *hostName);
|
||||
void connectionStatusCallback(IOTConnectionState status,
|
||||
IOTContextInternal *internal);
|
||||
IOTContextInternal *getSingletonContext();
|
||||
void setSingletonContext(IOTContextInternal *ctx);
|
||||
void sendConfirmationCallback(const char *buffer, size_t size);
|
||||
|
||||
int mqtt_publish(IOTContextInternal *internal, const char* topic, unsigned long topic_length,
|
||||
const char* msg, unsigned long msg_length);
|
||||
int mqtt_publish(IOTContextInternal *internal, const char *topic,
|
||||
unsigned long topic_length, const char *msg,
|
||||
unsigned long msg_length);
|
||||
|
||||
#ifdef ARDUINO
|
||||
#define IOTC_LOG(...) \
|
||||
if (getLogLevel() > IOTC_LOGGING_DISABLED) { \
|
||||
Serial.printf(" - "); \
|
||||
Serial.printf(__VA_ARGS__); \
|
||||
Serial.printf("\r\n"); \
|
||||
}
|
||||
#define IOTC_LOG(...) \
|
||||
if (getLogLevel() > IOTC_LOGGING_DISABLED) { \
|
||||
Serial.printf(" - "); \
|
||||
Serial.printf(__VA_ARGS__); \
|
||||
Serial.printf("\r\n"); \
|
||||
}
|
||||
#undef F
|
||||
#define F(x) x
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // AZURE_IOTC_INTERNAL_H
|
||||
#endif // AZURE_IOTC_INTERNAL_H
|
|
@ -1,69 +1,25 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef IOTC_COMMON_PLATFORM_H
|
||||
#define IOTC_COMMON_PLATFORM_H
|
||||
|
||||
#ifdef ARDUINO_SAMD_FEATHER_M0
|
||||
#include <Adafruit_WINC1500.h>
|
||||
#include <Adafruit_WINC1500SSLClient.h>
|
||||
#define ARDUINO_WIFI_SSL_CLIENT Adafruit_WINC1500SSLClient
|
||||
|
||||
#elif defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#define ARDUINO_WIFI_SSL_CLIENT WiFiClientSecure
|
||||
|
||||
#elif defined(ARDUINO_SAMD_MKR1010)
|
||||
#include <WiFi101.h>
|
||||
#include <WiFiNINA.h>
|
||||
#define ARDUINO_WIFI_SSL_CLIENT WiFiSSLClient
|
||||
#define USES_WIFI101
|
||||
|
||||
#elif defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000)
|
||||
#include <WiFi101.h>
|
||||
#include <WifiSSLClient.h>
|
||||
#define ARDUINO_WIFI_SSL_CLIENT WiFiSSLClient
|
||||
#define USES_WIFI101
|
||||
|
||||
#endif // ARDUINO_SAMD_FEATHER_M0
|
||||
|
||||
#if defined(ARDUINO_WIFI_SSL_CLIENT)
|
||||
#define USE_LIGHT_CLIENT 1
|
||||
#endif // ARDUINO_WIFI_SSL_CLIENT
|
||||
|
||||
#if defined(__MBED__)
|
||||
|
||||
#if defined(ARDUINO)
|
||||
#error "Both __MBED__ and ARDUINO were defined"
|
||||
#endif // defined(ARDUINO)
|
||||
|
||||
#define USE_LIGHT_CLIENT 1
|
||||
|
||||
#include <mbed.h>
|
||||
#include "MQTTmbed.h"
|
||||
#include "MQTTClient.h"
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/base64.h>
|
||||
#include "../mbed_os/mbed_tls_client.h"
|
||||
#define WAITMS wait_ms
|
||||
#define SERIAL_PRINT printf
|
||||
|
||||
#define F(x) x
|
||||
|
||||
#elif defined (ARDUINO)
|
||||
#include <Arduino.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "../arduino/PubSubClient.h"
|
||||
#include "WiFiUdp.h"
|
||||
#include "base64.h"
|
||||
#include "sha256.h"
|
||||
#include "../arduino/PubSubClient.h"
|
||||
#define WAITMS delay
|
||||
#define SERIAL_PRINT Serial.print
|
||||
#else
|
||||
#error "NOT SUPPORTED"
|
||||
#endif // defined(__MBED__)
|
||||
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM
|
||||
#endif
|
||||
|
||||
#endif // IOTC_COMMON_PLATFORM_H
|
||||
#endif // IOTC_COMMON_PLATFORM_H
|
||||
|
|
|
@ -4,115 +4,126 @@
|
|||
#ifndef AZURE_IOT_COMMON_JSON_H
|
||||
#define AZURE_IOT_COMMON_JSON_H
|
||||
|
||||
#include "parson.h"
|
||||
#include "../iotc.h"
|
||||
#include "parson.h"
|
||||
|
||||
namespace AzureIOT
|
||||
{
|
||||
class JSObject
|
||||
{
|
||||
private:
|
||||
JSON_Value* value;
|
||||
JSON_Object* object;
|
||||
bool isSubObject;
|
||||
namespace AzureIOT {
|
||||
class JSObject {
|
||||
private:
|
||||
JSON_Value* value;
|
||||
JSON_Object* object;
|
||||
bool isSubObject;
|
||||
|
||||
JSON_Object* toObject() {
|
||||
object = json_value_get_object(value);
|
||||
if (object == NULL) {
|
||||
LOG_ERROR("JSON value is not an object");
|
||||
return NULL;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
public:
|
||||
JSObject(): value(NULL), object(NULL), isSubObject(false) { }
|
||||
JSON_Object* toObject() {
|
||||
object = json_value_get_object(value);
|
||||
if (object == NULL) {
|
||||
LOG_ERROR("JSON value is not an object");
|
||||
return NULL;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
JSObject(const char * json_string) : isSubObject(false) {
|
||||
value = json_parse_string(json_string);
|
||||
if (value == NULL) {
|
||||
LOG_ERROR("parsing JSON failed");
|
||||
}
|
||||
public:
|
||||
JSObject() : value(NULL), object(NULL), isSubObject(false) {}
|
||||
|
||||
object = toObject();
|
||||
if (object == NULL) {
|
||||
LOG_ERROR("json data: %s", json_string);
|
||||
}
|
||||
}
|
||||
JSObject(const char* json_string) : isSubObject(false) {
|
||||
value = json_parse_string(json_string);
|
||||
if (value == NULL) {
|
||||
LOG_ERROR("parsing JSON failed");
|
||||
}
|
||||
|
||||
const char * getNameAt(unsigned index) {
|
||||
if (object == NULL) { LOG_ERROR("(getNameAt) object == NULL!"); return NULL; }
|
||||
object = toObject();
|
||||
if (object == NULL) {
|
||||
LOG_ERROR("json data: %s", json_string);
|
||||
}
|
||||
}
|
||||
|
||||
return json_object_get_name(object, index);
|
||||
}
|
||||
const char* getNameAt(unsigned index) {
|
||||
if (object == NULL) {
|
||||
LOG_ERROR("(getNameAt) object == NULL!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned getCount() {
|
||||
return object ? (unsigned)json_object_get_count(object) : 0;
|
||||
}
|
||||
return json_object_get_name(object, index);
|
||||
}
|
||||
|
||||
bool hasProperty(const char * name) {
|
||||
return object ? json_object_has_value(object, name) == 1 : false;
|
||||
}
|
||||
unsigned getCount() {
|
||||
return object ? (unsigned)json_object_get_count(object) : 0;
|
||||
}
|
||||
|
||||
const char * toString() {
|
||||
if (object == NULL) { LOG_ERROR("(toString) object == NULL!"); return NULL; }
|
||||
bool hasProperty(const char* name) {
|
||||
return object ? json_object_has_value(object, name) == 1 : false;
|
||||
}
|
||||
|
||||
JSON_Value * val = json_object_get_wrapping_value(object);
|
||||
if (val == NULL) return NULL;
|
||||
return json_value_get_string(val);
|
||||
}
|
||||
const char* toString() {
|
||||
if (object == NULL) {
|
||||
LOG_ERROR("(toString) object == NULL!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
~JSObject() {
|
||||
if (value != NULL && isSubObject == false) {
|
||||
json_value_free(value);
|
||||
value = NULL;
|
||||
}
|
||||
}
|
||||
JSON_Value* val = json_object_get_wrapping_value(object);
|
||||
if (val == NULL) return NULL;
|
||||
return json_value_get_string(val);
|
||||
}
|
||||
|
||||
bool getObjectAt(unsigned index, JSObject * outJSObject) {
|
||||
if (index >= getCount()) return false;
|
||||
~JSObject() {
|
||||
if (value != NULL && isSubObject == false) {
|
||||
json_value_free(value);
|
||||
value = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
JSON_Value * subValue = json_object_get_value_at(object, index);
|
||||
if (subValue == NULL) return false;
|
||||
bool getObjectAt(unsigned index, JSObject* outJSObject) {
|
||||
if (index >= getCount()) return false;
|
||||
|
||||
outJSObject->isSubObject = true;
|
||||
outJSObject->value = subValue;
|
||||
outJSObject->toObject();
|
||||
if (outJSObject->object == NULL) return false;
|
||||
JSON_Value* subValue = json_object_get_value_at(object, index);
|
||||
if (subValue == NULL) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
outJSObject->isSubObject = true;
|
||||
outJSObject->value = subValue;
|
||||
outJSObject->toObject();
|
||||
if (outJSObject->object == NULL) return false;
|
||||
|
||||
bool getObjectByName(const char * name, JSObject * outJSObject) {
|
||||
JSON_Object* subObject = json_object_get_object(object, name);
|
||||
if (subObject == NULL) {
|
||||
// outJSObject->value memory freed by it's own de-constructor.
|
||||
return false; // let consumer file the log
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
outJSObject->value = json_object_get_wrapping_value(object);
|
||||
outJSObject->object = subObject;
|
||||
outJSObject->isSubObject = true;
|
||||
return true;
|
||||
}
|
||||
bool getObjectByName(const char* name, JSObject* outJSObject) {
|
||||
JSON_Object* subObject = json_object_get_object(object, name);
|
||||
if (subObject == NULL) {
|
||||
// outJSObject->value memory freed by it's own de-constructor.
|
||||
return false; // let consumer file the log
|
||||
}
|
||||
|
||||
const char * getStringByName(const char * name) {
|
||||
if (object == NULL) { LOG_ERROR("(getStringByName) object == NULL!"); return NULL; }
|
||||
outJSObject->value = json_object_get_wrapping_value(object);
|
||||
outJSObject->object = subObject;
|
||||
outJSObject->isSubObject = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char * text = json_object_get_string(object, name);
|
||||
if (text == NULL) {
|
||||
return NULL; // let consumer file the log
|
||||
}
|
||||
const char* getStringByName(const char* name) {
|
||||
if (object == NULL) {
|
||||
LOG_ERROR("(getStringByName) object == NULL!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
const char* text = json_object_get_string(object, name);
|
||||
if (text == NULL) {
|
||||
return NULL; // let consumer file the log
|
||||
}
|
||||
|
||||
double getNumberByName(const char * name) {
|
||||
if (object == NULL) { LOG_ERROR("(getNumberByName) object == NULL!"); return 0; }
|
||||
// API returns 0.0 on fail hence it doesn't actually have a good
|
||||
// fail discovery strategy
|
||||
return json_object_get_number(object, name);
|
||||
}
|
||||
};
|
||||
} // namespace AzureIOT
|
||||
return text;
|
||||
}
|
||||
|
||||
#endif // AZURE_IOT_COMMON_JSON_H
|
||||
double getNumberByName(const char* name) {
|
||||
if (object == NULL) {
|
||||
LOG_ERROR("(getNumberByName) object == NULL!");
|
||||
return 0;
|
||||
}
|
||||
// API returns 0.0 on fail hence it doesn't actually have a good
|
||||
// fail discovery strategy
|
||||
return json_object_get_number(object, name);
|
||||
}
|
||||
};
|
||||
} // namespace AzureIOT
|
||||
|
||||
#endif // AZURE_IOT_COMMON_JSON_H
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -23,143 +23,167 @@
|
|||
|
||||
#ifndef parson_parson_h
|
||||
#define parson_parson_h
|
||||
|
||||
#if defined(__MBED__) || defined(ESP_PLATFORM) || defined(ARDUINO)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
/* Types and enums */
|
||||
typedef struct json_object_t JSON_Object;
|
||||
typedef struct json_array_t JSON_Array;
|
||||
typedef struct json_value_t JSON_Value;
|
||||
typedef struct json_array_t JSON_Array;
|
||||
typedef struct json_value_t JSON_Value;
|
||||
|
||||
enum json_value_type {
|
||||
JSONError = -1,
|
||||
JSONNull = 1,
|
||||
JSONString = 2,
|
||||
JSONNumber = 3,
|
||||
JSONObject = 4,
|
||||
JSONArray = 5,
|
||||
JSONBoolean = 6
|
||||
JSONError = -1,
|
||||
JSONNull = 1,
|
||||
JSONString = 2,
|
||||
JSONNumber = 3,
|
||||
JSONObject = 4,
|
||||
JSONArray = 5,
|
||||
JSONBoolean = 6
|
||||
};
|
||||
typedef int JSON_Value_Type;
|
||||
|
||||
enum json_result_t {
|
||||
JSONSuccess = 0,
|
||||
JSONFailure = -1
|
||||
};
|
||||
enum json_result_t { JSONSuccess = 0, JSONFailure = -1 };
|
||||
typedef int JSON_Status;
|
||||
|
||||
typedef void * (*JSON_Malloc_Function)(size_t);
|
||||
typedef void (*JSON_Free_Function)(void *);
|
||||
typedef void *(*JSON_Malloc_Function)(size_t);
|
||||
typedef void (*JSON_Free_Function)(void *);
|
||||
|
||||
/* Call only once, before calling any other function from parson API. If not called, malloc and free
|
||||
from stdlib will be used for all allocations */
|
||||
void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun);
|
||||
/* Call only once, before calling any other function from parson API. If not
|
||||
called, malloc and free from stdlib will be used for all allocations */
|
||||
void json_set_allocation_functions(JSON_Malloc_Function malloc_fun,
|
||||
JSON_Free_Function free_fun);
|
||||
|
||||
/* Parses first JSON value in a file, returns NULL in case of error */
|
||||
JSON_Value * json_parse_file(const char *filename);
|
||||
JSON_Value *json_parse_file(const char *filename);
|
||||
|
||||
/* Parses first JSON value in a file and ignores comments (/ * * / and //),
|
||||
returns NULL in case of error */
|
||||
JSON_Value * json_parse_file_with_comments(const char *filename);
|
||||
JSON_Value *json_parse_file_with_comments(const char *filename);
|
||||
|
||||
/* Parses first JSON value in a string, returns NULL in case of error */
|
||||
JSON_Value * json_parse_string(const char *string);
|
||||
JSON_Value *json_parse_string(const char *string);
|
||||
|
||||
/* Parses first JSON value in a string and ignores comments (/ * * / and //),
|
||||
returns NULL in case of error */
|
||||
JSON_Value * json_parse_string_with_comments(const char *string);
|
||||
JSON_Value *json_parse_string_with_comments(const char *string);
|
||||
|
||||
/* Serialization */
|
||||
size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */
|
||||
JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
|
||||
JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename);
|
||||
char * json_serialize_to_string(const JSON_Value *value);
|
||||
size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */
|
||||
JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf,
|
||||
size_t buf_size_in_bytes);
|
||||
JSON_Status json_serialize_to_file(const JSON_Value *value,
|
||||
const char *filename);
|
||||
char *json_serialize_to_string(const JSON_Value *value);
|
||||
|
||||
/* Pretty serialization */
|
||||
size_t json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */
|
||||
JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
|
||||
JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename);
|
||||
char * json_serialize_to_string_pretty(const JSON_Value *value);
|
||||
size_t json_serialization_size_pretty(
|
||||
const JSON_Value *value); /* returns 0 on fail */
|
||||
JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf,
|
||||
size_t buf_size_in_bytes);
|
||||
JSON_Status json_serialize_to_file_pretty(const JSON_Value *value,
|
||||
const char *filename);
|
||||
char *json_serialize_to_string_pretty(const JSON_Value *value);
|
||||
|
||||
void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */
|
||||
void json_free_serialized_string(
|
||||
char *string); /* frees string from json_serialize_to_string and
|
||||
json_serialize_to_string_pretty */
|
||||
|
||||
/* Comparing */
|
||||
int json_value_equals(const JSON_Value *a, const JSON_Value *b);
|
||||
int json_value_equals(const JSON_Value *a, const JSON_Value *b);
|
||||
|
||||
/* Validation
|
||||
This is *NOT* JSON Schema. It validates json by checking if object have identically
|
||||
named fields with matching types.
|
||||
For example schema {"name":"", "age":0} will validate
|
||||
This is *NOT* JSON Schema. It validates json by checking if object have
|
||||
identically named fields with matching types. For example schema {"name":"",
|
||||
"age":0} will validate
|
||||
{"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"},
|
||||
but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}.
|
||||
In case of arrays, only first value in schema is checked against all values in tested array.
|
||||
Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays,
|
||||
null validates values of every type.
|
||||
In case of arrays, only first value in schema is checked against all values
|
||||
in tested array. Empty objects ({}) validate all objects, empty arrays ([])
|
||||
validate all arrays, null validates values of every type.
|
||||
*/
|
||||
JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value);
|
||||
|
||||
/*
|
||||
* JSON Object
|
||||
*/
|
||||
JSON_Value * json_object_get_value (const JSON_Object *object, const char *name);
|
||||
const char * json_object_get_string (const JSON_Object *object, const char *name);
|
||||
JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
|
||||
JSON_Array * json_object_get_array (const JSON_Object *object, const char *name);
|
||||
double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
|
||||
int json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
|
||||
JSON_Value *json_object_get_value(const JSON_Object *object, const char *name);
|
||||
const char *json_object_get_string(const JSON_Object *object, const char *name);
|
||||
JSON_Object *json_object_get_object(const JSON_Object *object,
|
||||
const char *name);
|
||||
JSON_Array *json_object_get_array(const JSON_Object *object, const char *name);
|
||||
double json_object_get_number(const JSON_Object *object,
|
||||
const char *name); /* returns 0 on fail */
|
||||
int json_object_get_boolean(const JSON_Object *object,
|
||||
const char *name); /* returns -1 on fail */
|
||||
|
||||
/* dotget functions enable addressing values with dot notation in nested objects,
|
||||
just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
|
||||
Because valid names in JSON can contain dots, some values may be inaccessible
|
||||
this way. */
|
||||
JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name);
|
||||
const char * json_object_dotget_string (const JSON_Object *object, const char *name);
|
||||
JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
|
||||
JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name);
|
||||
double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
|
||||
int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
|
||||
/* dotget functions enable addressing values with dot notation in nested
|
||||
objects, just like in structs or c++/java/c# objects (e.g.
|
||||
objectA.objectB.value). Because valid names in JSON can contain dots, some
|
||||
values may be inaccessible this way. */
|
||||
JSON_Value *json_object_dotget_value(const JSON_Object *object,
|
||||
const char *name);
|
||||
const char *json_object_dotget_string(const JSON_Object *object,
|
||||
const char *name);
|
||||
JSON_Object *json_object_dotget_object(const JSON_Object *object,
|
||||
const char *name);
|
||||
JSON_Array *json_object_dotget_array(const JSON_Object *object,
|
||||
const char *name);
|
||||
double json_object_dotget_number(const JSON_Object *object,
|
||||
const char *name); /* returns 0 on fail */
|
||||
int json_object_dotget_boolean(const JSON_Object *object,
|
||||
const char *name); /* returns -1 on fail */
|
||||
|
||||
/* Functions to get available names */
|
||||
size_t json_object_get_count (const JSON_Object *object);
|
||||
const char * json_object_get_name (const JSON_Object *object, size_t index);
|
||||
JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index);
|
||||
JSON_Value * json_object_get_wrapping_value(const JSON_Object *object);
|
||||
size_t json_object_get_count(const JSON_Object *object);
|
||||
const char *json_object_get_name(const JSON_Object *object, size_t index);
|
||||
JSON_Value *json_object_get_value_at(const JSON_Object *object, size_t index);
|
||||
JSON_Value *json_object_get_wrapping_value(const JSON_Object *object);
|
||||
|
||||
/* Functions to check if object has a value with a specific name. Returned value is 1 if object has
|
||||
* a value and 0 if it doesn't. dothas functions behave exactly like dotget functions. */
|
||||
int json_object_has_value (const JSON_Object *object, const char *name);
|
||||
int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
|
||||
/* Functions to check if object has a value with a specific name. Returned value
|
||||
* is 1 if object has a value and 0 if it doesn't. dothas functions behave
|
||||
* exactly like dotget functions. */
|
||||
int json_object_has_value(const JSON_Object *object, const char *name);
|
||||
int json_object_has_value_of_type(const JSON_Object *object, const char *name,
|
||||
JSON_Value_Type type);
|
||||
|
||||
int json_object_dothas_value (const JSON_Object *object, const char *name);
|
||||
int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
|
||||
int json_object_dothas_value(const JSON_Object *object, const char *name);
|
||||
int json_object_dothas_value_of_type(const JSON_Object *object,
|
||||
const char *name, JSON_Value_Type type);
|
||||
|
||||
/* Creates new name-value pair or frees and replaces old value with a new one.
|
||||
* json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */
|
||||
JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value);
|
||||
JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string);
|
||||
JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number);
|
||||
JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean);
|
||||
* json_object_set_value does not copy passed value so it shouldn't be freed
|
||||
* afterwards. */
|
||||
JSON_Status json_object_set_value(JSON_Object *object, const char *name,
|
||||
JSON_Value *value);
|
||||
JSON_Status json_object_set_string(JSON_Object *object, const char *name,
|
||||
const char *string);
|
||||
JSON_Status json_object_set_number(JSON_Object *object, const char *name,
|
||||
double number);
|
||||
JSON_Status json_object_set_boolean(JSON_Object *object, const char *name,
|
||||
int boolean);
|
||||
JSON_Status json_object_set_null(JSON_Object *object, const char *name);
|
||||
|
||||
/* Works like dotget functions, but creates whole hierarchy if necessary.
|
||||
* json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */
|
||||
JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value);
|
||||
JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string);
|
||||
JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number);
|
||||
JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean);
|
||||
* json_object_dotset_value does not copy passed value so it shouldn't be freed
|
||||
* afterwards. */
|
||||
JSON_Status json_object_dotset_value(JSON_Object *object, const char *name,
|
||||
JSON_Value *value);
|
||||
JSON_Status json_object_dotset_string(JSON_Object *object, const char *name,
|
||||
const char *string);
|
||||
JSON_Status json_object_dotset_number(JSON_Object *object, const char *name,
|
||||
double number);
|
||||
JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name,
|
||||
int boolean);
|
||||
JSON_Status json_object_dotset_null(JSON_Object *object, const char *name);
|
||||
|
||||
/* Frees and removes name-value pair */
|
||||
JSON_Status json_object_remove(JSON_Object *object, const char *name);
|
||||
|
||||
/* Works like dotget function, but removes name-value pair only on exact match. */
|
||||
/* Works like dotget function, but removes name-value pair only on exact match.
|
||||
*/
|
||||
JSON_Status json_object_dotremove(JSON_Object *object, const char *key);
|
||||
|
||||
/* Removes all name-value pairs in object */
|
||||
|
@ -168,33 +192,42 @@ JSON_Status json_object_clear(JSON_Object *object);
|
|||
/*
|
||||
*JSON Array
|
||||
*/
|
||||
JSON_Value * json_array_get_value (const JSON_Array *array, size_t index);
|
||||
const char * json_array_get_string (const JSON_Array *array, size_t index);
|
||||
JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
|
||||
JSON_Array * json_array_get_array (const JSON_Array *array, size_t index);
|
||||
double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */
|
||||
int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */
|
||||
size_t json_array_get_count (const JSON_Array *array);
|
||||
JSON_Value * json_array_get_wrapping_value(const JSON_Array *array);
|
||||
JSON_Value *json_array_get_value(const JSON_Array *array, size_t index);
|
||||
const char *json_array_get_string(const JSON_Array *array, size_t index);
|
||||
JSON_Object *json_array_get_object(const JSON_Array *array, size_t index);
|
||||
JSON_Array *json_array_get_array(const JSON_Array *array, size_t index);
|
||||
double json_array_get_number(const JSON_Array *array,
|
||||
size_t index); /* returns 0 on fail */
|
||||
int json_array_get_boolean(const JSON_Array *array,
|
||||
size_t index); /* returns -1 on fail */
|
||||
size_t json_array_get_count(const JSON_Array *array);
|
||||
JSON_Value *json_array_get_wrapping_value(const JSON_Array *array);
|
||||
|
||||
/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist.
|
||||
/* Frees and removes value at given index, does nothing and returns JSONFailure
|
||||
* if index doesn't exist.
|
||||
* Order of values in array may change during execution. */
|
||||
JSON_Status json_array_remove(JSON_Array *array, size_t i);
|
||||
|
||||
/* Frees and removes from array value at given index and replaces it with given one.
|
||||
* Does nothing and returns JSONFailure if index doesn't exist.
|
||||
* json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */
|
||||
JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value);
|
||||
JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string);
|
||||
JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number);
|
||||
JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean);
|
||||
/* Frees and removes from array value at given index and replaces it with given
|
||||
* one. Does nothing and returns JSONFailure if index doesn't exist.
|
||||
* json_array_replace_value does not copy passed value so it shouldn't be freed
|
||||
* afterwards. */
|
||||
JSON_Status json_array_replace_value(JSON_Array *array, size_t i,
|
||||
JSON_Value *value);
|
||||
JSON_Status json_array_replace_string(JSON_Array *array, size_t i,
|
||||
const char *string);
|
||||
JSON_Status json_array_replace_number(JSON_Array *array, size_t i,
|
||||
double number);
|
||||
JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i,
|
||||
int boolean);
|
||||
JSON_Status json_array_replace_null(JSON_Array *array, size_t i);
|
||||
|
||||
/* Frees and removes all values from array */
|
||||
JSON_Status json_array_clear(JSON_Array *array);
|
||||
|
||||
/* Appends new value at the end of array.
|
||||
* json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */
|
||||
* json_array_append_value does not copy passed value so it shouldn't be freed
|
||||
* afterwards. */
|
||||
JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value);
|
||||
JSON_Status json_array_append_string(JSON_Array *array, const char *string);
|
||||
JSON_Status json_array_append_number(JSON_Array *array, double number);
|
||||
|
@ -204,34 +237,34 @@ JSON_Status json_array_append_null(JSON_Array *array);
|
|||
/*
|
||||
*JSON Value
|
||||
*/
|
||||
JSON_Value * json_value_init_object (void);
|
||||
JSON_Value * json_value_init_array (void);
|
||||
JSON_Value * json_value_init_string (const char *string); /* copies passed string */
|
||||
JSON_Value * json_value_init_number (double number);
|
||||
JSON_Value * json_value_init_boolean(int boolean);
|
||||
JSON_Value * json_value_init_null (void);
|
||||
JSON_Value * json_value_deep_copy (const JSON_Value *value);
|
||||
void json_value_free (JSON_Value *value);
|
||||
JSON_Value *json_value_init_object(void);
|
||||
JSON_Value *json_value_init_array(void);
|
||||
JSON_Value *json_value_init_string(
|
||||
const char *string); /* copies passed string */
|
||||
JSON_Value *json_value_init_number(double number);
|
||||
JSON_Value *json_value_init_boolean(int boolean);
|
||||
JSON_Value *json_value_init_null(void);
|
||||
JSON_Value *json_value_deep_copy(const JSON_Value *value);
|
||||
void json_value_free(JSON_Value *value);
|
||||
|
||||
JSON_Value_Type json_value_get_type (const JSON_Value *value);
|
||||
JSON_Object * json_value_get_object (const JSON_Value *value);
|
||||
JSON_Array * json_value_get_array (const JSON_Value *value);
|
||||
const char * json_value_get_string (const JSON_Value *value);
|
||||
double json_value_get_number (const JSON_Value *value);
|
||||
int json_value_get_boolean(const JSON_Value *value);
|
||||
JSON_Value * json_value_get_parent (const JSON_Value *value);
|
||||
JSON_Value_Type json_value_get_type(const JSON_Value *value);
|
||||
JSON_Object *json_value_get_object(const JSON_Value *value);
|
||||
JSON_Array *json_value_get_array(const JSON_Value *value);
|
||||
const char *json_value_get_string(const JSON_Value *value);
|
||||
double json_value_get_number(const JSON_Value *value);
|
||||
int json_value_get_boolean(const JSON_Value *value);
|
||||
JSON_Value *json_value_get_parent(const JSON_Value *value);
|
||||
|
||||
/* Same as above, but shorter */
|
||||
JSON_Value_Type json_type (const JSON_Value *value);
|
||||
JSON_Object * json_object (const JSON_Value *value);
|
||||
JSON_Array * json_array (const JSON_Value *value);
|
||||
const char * json_string (const JSON_Value *value);
|
||||
double json_number (const JSON_Value *value);
|
||||
int json_boolean(const JSON_Value *value);
|
||||
JSON_Value_Type json_type(const JSON_Value *value);
|
||||
JSON_Object *json_object(const JSON_Value *value);
|
||||
JSON_Array *json_array(const JSON_Value *value);
|
||||
const char *json_string(const JSON_Value *value);
|
||||
double json_number(const JSON_Value *value);
|
||||
int json_boolean(const JSON_Value *value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // defined(__MBED__) || defined(ESP_PLATFORM)
|
||||
#endif // parson_parson_h
|
||||
#endif // parson_parson_h
|
|
@ -1,30 +1,30 @@
|
|||
#ifdef ARDUINO
|
||||
|
||||
#include <string.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sha256.h"
|
||||
|
||||
const uint32_t SHA256_K[] PROGMEM = {
|
||||
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||||
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||||
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||||
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||||
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||||
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||||
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||||
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
};
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
|
||||
|
||||
const uint8_t SHA256_INIT_STATE[] PROGMEM = {
|
||||
0x67,0xe6,0x09,0x6a, // H0
|
||||
0x85,0xae,0x67,0xbb, // H1
|
||||
0x72,0xf3,0x6e,0x3c, // H2
|
||||
0x3a,0xf5,0x4f,0xa5, // H3
|
||||
0x7f,0x52,0x0e,0x51, // H4
|
||||
0x8c,0x68,0x05,0x9b, // H5
|
||||
0xab,0xd9,0x83,0x1f, // H6
|
||||
0x19,0xcd,0xe0,0x5b // H7
|
||||
0x67, 0xe6, 0x09, 0x6a, // H0
|
||||
0x85, 0xae, 0x67, 0xbb, // H1
|
||||
0x72, 0xf3, 0x6e, 0x3c, // H2
|
||||
0x3a, 0xf5, 0x4f, 0xa5, // H3
|
||||
0x7f, 0x52, 0x0e, 0x51, // H4
|
||||
0x8c, 0x68, 0x05, 0x9b, // H5
|
||||
0xab, 0xd9, 0x83, 0x1f, // H6
|
||||
0x19, 0xcd, 0xe0, 0x5b // H7
|
||||
};
|
||||
|
||||
#define ror32(num, bits) ((num << (32 - bits)) | (num >> bits))
|
||||
|
@ -37,34 +37,41 @@ void Sha256::init(void) {
|
|||
|
||||
void Sha256::hashBlock() {
|
||||
uint8_t i;
|
||||
uint32_t a,b,c,d,e,f,g,h,t1,t2;
|
||||
uint32_t a, b, c, d, e, f, g, h, t1, t2;
|
||||
|
||||
a=state.w[0];
|
||||
b=state.w[1];
|
||||
c=state.w[2];
|
||||
d=state.w[3];
|
||||
e=state.w[4];
|
||||
f=state.w[5];
|
||||
g=state.w[6];
|
||||
h=state.w[7];
|
||||
a = state.w[0];
|
||||
b = state.w[1];
|
||||
c = state.w[2];
|
||||
d = state.w[3];
|
||||
e = state.w[4];
|
||||
f = state.w[5];
|
||||
g = state.w[6];
|
||||
h = state.w[7];
|
||||
|
||||
for (i=0; i<64; i++) {
|
||||
if (i>=16) {
|
||||
t1 = buffer.w[i&15] + buffer.w[(i-7)&15];
|
||||
t2 = buffer.w[(i-2)&15];
|
||||
t1 += ror32(t2,17) ^ ror32(t2,19) ^ (t2>>10);
|
||||
t2 = buffer.w[(i-15)&15];
|
||||
t1 += ror32(t2,7) ^ ror32(t2,18) ^ (t2>>3);
|
||||
buffer.w[i&15] = t1;
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (i >= 16) {
|
||||
t1 = buffer.w[i & 15] + buffer.w[(i - 7) & 15];
|
||||
t2 = buffer.w[(i - 2) & 15];
|
||||
t1 += ror32(t2, 17) ^ ror32(t2, 19) ^ (t2 >> 10);
|
||||
t2 = buffer.w[(i - 15) & 15];
|
||||
t1 += ror32(t2, 7) ^ ror32(t2, 18) ^ (t2 >> 3);
|
||||
buffer.w[i & 15] = t1;
|
||||
}
|
||||
t1 = h;
|
||||
t1 += ror32(e,6) ^ ror32(e,11) ^ ror32(e,25); // ∑1(e)
|
||||
t1 += g ^ (e & (g ^ f)); // Ch(e,f,g)
|
||||
t1 += pgm_read_dword(SHA256_K + i); // Ki
|
||||
t1 += buffer.w[i&15]; // Wi
|
||||
t2 = ror32(a,2) ^ ror32(a,13) ^ ror32(a,22); // ∑0(a)
|
||||
t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c)
|
||||
h=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2;
|
||||
t1 += ror32(e, 6) ^ ror32(e, 11) ^ ror32(e, 25); // ∑1(e)
|
||||
t1 += g ^ (e & (g ^ f)); // Ch(e,f,g)
|
||||
t1 += pgm_read_dword(SHA256_K + i); // Ki
|
||||
t1 += buffer.w[i & 15]; // Wi
|
||||
t2 = ror32(a, 2) ^ ror32(a, 13) ^ ror32(a, 22); // ∑0(a)
|
||||
t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c)
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
state.w[0] += a;
|
||||
state.w[1] += b;
|
||||
|
@ -122,13 +129,13 @@ uint8_t* Sha256::result(void) {
|
|||
|
||||
// Swap byte order back
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
uint32_t a,b;
|
||||
a=state.w[i];
|
||||
b=a<<24;
|
||||
b|=(a<<8) & 0x00ff0000;
|
||||
b|=(a>>8) & 0x0000ff00;
|
||||
b|=a>>24;
|
||||
state.w[i]=b;
|
||||
uint32_t a, b;
|
||||
a = state.w[i];
|
||||
b = a << 24;
|
||||
b |= (a << 8) & 0x00ff0000;
|
||||
b |= (a >> 8) & 0x0000ff00;
|
||||
b |= a >> 24;
|
||||
state.w[i] = b;
|
||||
}
|
||||
|
||||
// Return pointer to hash
|
||||
|
@ -138,12 +145,12 @@ uint8_t* Sha256::result(void) {
|
|||
#define HMAC_IPAD 0x36
|
||||
#define HMAC_OPAD 0x5c
|
||||
|
||||
void Sha256::initHmac(const uint8_t *key, size_t keyLength) {
|
||||
void Sha256::initHmac(const uint8_t* key, size_t keyLength) {
|
||||
memset(keyBuffer, 0, BLOCK_LENGTH);
|
||||
if (keyLength > BLOCK_LENGTH) {
|
||||
// Hash long keys
|
||||
init();
|
||||
for (;keyLength--;) write(*key++);
|
||||
for (; keyLength--;) write(*key++);
|
||||
memcpy(keyBuffer, result(), HASH_LENGTH);
|
||||
} else {
|
||||
// Block length keys are used as is
|
||||
|
@ -169,6 +176,4 @@ void Sha256::reset(void) {
|
|||
for (uint8_t i = 0; i < BLOCK_LENGTH; i++) {
|
||||
write(keyBuffer[i] ^ HMAC_IPAD);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ARDUINO
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
#ifdef ARDUINO
|
||||
|
||||
#ifndef Sha256_h
|
||||
#define Sha256_h
|
||||
|
||||
|
@ -10,7 +8,6 @@
|
|||
#define BLOCK_LENGTH 64
|
||||
|
||||
class Sha256 : public Print {
|
||||
|
||||
union Buffer {
|
||||
uint8_t b[BLOCK_LENGTH];
|
||||
uint32_t w[BLOCK_LENGTH / 4];
|
||||
|
@ -21,37 +18,35 @@ class Sha256 : public Print {
|
|||
uint32_t w[HASH_LENGTH / 4];
|
||||
};
|
||||
|
||||
public:
|
||||
void init(void);
|
||||
void initHmac(const uint8_t *key, size_t keyLength);
|
||||
public:
|
||||
void init(void);
|
||||
void initHmac(const uint8_t* key, size_t keyLength);
|
||||
|
||||
// Reset to initial state, but preserve key material.
|
||||
void reset(void);
|
||||
// Reset to initial state, but preserve key material.
|
||||
void reset(void);
|
||||
|
||||
uint8_t* result(void);
|
||||
uint8_t* resultHmac(void);
|
||||
uint8_t* result(void);
|
||||
uint8_t* resultHmac(void);
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(uint8_t);
|
||||
#else
|
||||
virtual void write(uint8_t);
|
||||
virtual void write(uint8_t);
|
||||
#endif
|
||||
using Print::write;
|
||||
using Print::write;
|
||||
|
||||
private:
|
||||
void hashBlock();
|
||||
void padBlock();
|
||||
void push(uint8_t data);
|
||||
private:
|
||||
void hashBlock();
|
||||
void padBlock();
|
||||
void push(uint8_t data);
|
||||
|
||||
uint32_t byteCount;
|
||||
uint32_t byteCount;
|
||||
|
||||
uint8_t keyBuffer[BLOCK_LENGTH];
|
||||
uint8_t innerHash[HASH_LENGTH];
|
||||
uint8_t keyBuffer[BLOCK_LENGTH];
|
||||
uint8_t innerHash[HASH_LENGTH];
|
||||
|
||||
State state;
|
||||
Buffer buffer;
|
||||
uint8_t bufferOffset;
|
||||
State state;
|
||||
Buffer buffer;
|
||||
uint8_t bufferOffset;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // ARDUINO
|
||||
#endif
|
|
@ -1,132 +1,129 @@
|
|||
// Copyright (c) Oguz Bastemur. All rights reserved.
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "iotc_internal.h"
|
||||
|
||||
namespace AzureIOT {
|
||||
|
||||
static char convertToHex(char ch) {
|
||||
static const char * lst = "0123456789ABCDEF";
|
||||
return *(lst + (ch & 15));
|
||||
static const char *lst = "0123456789ABCDEF";
|
||||
return *(lst + (ch & 15));
|
||||
}
|
||||
|
||||
static char convertFromHex(char ch) {
|
||||
assert(isdigit(ch) || isalpha(ch)); // isalnum ?
|
||||
if (ch <= '9') {
|
||||
return ch - '0';
|
||||
assert(isdigit(ch) || isalpha(ch)); // isalnum ?
|
||||
if (ch <= '9') {
|
||||
return ch - '0';
|
||||
} else {
|
||||
if (ch <= 'Z') {
|
||||
ch = ch - 'A';
|
||||
} else {
|
||||
if (ch <= 'Z') {
|
||||
ch = ch - 'A';
|
||||
} else {
|
||||
ch = ch - 'a';
|
||||
}
|
||||
|
||||
return ch + 10;
|
||||
ch = ch - 'a';
|
||||
}
|
||||
|
||||
return ch + 10;
|
||||
}
|
||||
}
|
||||
|
||||
bool StringBuffer::startsWith(const char* str, size_t len) {
|
||||
if (len > length) return false;
|
||||
bool StringBuffer::startsWith(const char *str, size_t len) {
|
||||
if (len > length) return false;
|
||||
|
||||
const char *buffer = data == NULL ? immutable : data;
|
||||
assert(buffer != NULL);
|
||||
const char *buffer = data == NULL ? immutable : data;
|
||||
assert(buffer != NULL);
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (str[i] != buffer[i]) return false;
|
||||
}
|
||||
return true;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (str[i] != buffer[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t StringBuffer::indexOf(const char* look_for, size_t look_for_length,
|
||||
int32_t start_index) {
|
||||
|
||||
const char *buffer = data == NULL ? immutable : data;
|
||||
assert(buffer != NULL);
|
||||
|
||||
if (look_for_length > length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t pos = start_index; pos < length; pos++) {
|
||||
if (length - pos < look_for_length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer[pos] == *look_for) {
|
||||
size_t sub = 1;
|
||||
for (; sub < look_for_length; sub++) {
|
||||
if (buffer[pos + sub] != look_for[sub]) break;
|
||||
}
|
||||
|
||||
if (sub == look_for_length) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
int32_t StringBuffer::indexOf(const char *look_for, size_t look_for_length,
|
||||
int32_t start_index) {
|
||||
const char *buffer = data == NULL ? immutable : data;
|
||||
assert(buffer != NULL);
|
||||
|
||||
if (look_for_length > length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t pos = start_index; pos < length; pos++) {
|
||||
if (length - pos < look_for_length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer[pos] == *look_for) {
|
||||
size_t sub = 1;
|
||||
for (; sub < look_for_length; sub++) {
|
||||
if (buffer[pos + sub] != look_for[sub]) break;
|
||||
}
|
||||
|
||||
if (sub == look_for_length) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool StringBuffer::urlEncode() {
|
||||
assert(data != NULL);
|
||||
size_t buffer_length = (length * 3) + 1;
|
||||
char *buffer = (char*) malloc(buffer_length);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
assert(data != NULL);
|
||||
size_t buffer_length = (length * 3) + 1;
|
||||
char *buffer = (char *)malloc(buffer_length);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char *tmp = buffer;
|
||||
assert(buffer != NULL);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
char ch = data[i];
|
||||
if (isalnum(ch) || ch == '_' || ch == '-' || ch == '~' || ch == '.') {
|
||||
*tmp = ch;
|
||||
} else if (ch == ' ') {
|
||||
*tmp = '+';
|
||||
} else {
|
||||
*tmp++ = '%';
|
||||
*tmp++ = convertToHex(ch >> 4);
|
||||
*tmp = convertToHex(ch & 15);
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
*tmp = 0;
|
||||
|
||||
char *tmp = buffer;
|
||||
assert(buffer != NULL);
|
||||
clear(); // free prev memory
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
char ch = data[i];
|
||||
if (isalnum(ch) ||
|
||||
ch == '_' || ch == '-' || ch == '~' || ch == '.') {
|
||||
*tmp = ch;
|
||||
} else if (ch == ' ') {
|
||||
*tmp = '+';
|
||||
} else {
|
||||
*tmp++ = '%';
|
||||
*tmp++ = convertToHex(ch >> 4);
|
||||
*tmp = convertToHex(ch & 15);
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
*tmp = 0;
|
||||
|
||||
clear(); // free prev memory
|
||||
|
||||
data = buffer;
|
||||
length = (size_t)tmp - (size_t)buffer;
|
||||
return true;
|
||||
data = buffer;
|
||||
length = (size_t)tmp - (size_t)buffer;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringBuffer::urlDecode() { // in-memory
|
||||
assert(data != NULL);
|
||||
char *tmp = data; // fast
|
||||
bool StringBuffer::urlDecode() { // in-memory
|
||||
assert(data != NULL);
|
||||
char *tmp = data; // fast
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
char ch = data[i];
|
||||
if (ch == '%') {
|
||||
if (i + 2 < length) {
|
||||
*tmp = convertFromHex(data[i + 1]) << 4 |
|
||||
convertFromHex(data[i + 2]);
|
||||
i += 2;
|
||||
}
|
||||
} else if (ch == '+') {
|
||||
*tmp = ' ';
|
||||
} else {
|
||||
*tmp = ch;
|
||||
}
|
||||
tmp++;
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
char ch = data[i];
|
||||
if (ch == '%') {
|
||||
if (i + 2 < length) {
|
||||
*tmp = convertFromHex(data[i + 1]) << 4 | convertFromHex(data[i + 2]);
|
||||
i += 2;
|
||||
}
|
||||
} else if (ch == '+') {
|
||||
*tmp = ' ';
|
||||
} else {
|
||||
*tmp = ch;
|
||||
}
|
||||
*tmp = 0;
|
||||
length = (size_t)tmp - (size_t)data;
|
||||
tmp++;
|
||||
}
|
||||
*tmp = 0;
|
||||
length = (size_t)tmp - (size_t)data;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef TARGET_MXCHIP
|
||||
|
@ -137,175 +134,179 @@ bool StringBuffer::base64Decode() { abort(); }
|
|||
bool StringBuffer::base64Encode() { abort(); }
|
||||
|
||||
#elif defined(__MBED__)
|
||||
bool StringBuffer::hash(const char *key, unsigned key_length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
mbedtls_md_type_t md = MBEDTLS_MD_SHA256;
|
||||
const mbedtls_md_info_t *md_info;
|
||||
mbedtls_md_context_t ctx;
|
||||
bool StringBuffer::hash(const char *key, unsigned key_length) {
|
||||
assert(data != NULL);
|
||||
mbedtls_md_type_t md = MBEDTLS_MD_SHA256;
|
||||
const mbedtls_md_info_t *md_info;
|
||||
mbedtls_md_context_t ctx;
|
||||
|
||||
md_info = mbedtls_md_info_from_type(md);
|
||||
unsigned hash_size = (unsigned) mbedtls_md_get_size(md_info);
|
||||
unsigned char *hmac_hash = (unsigned char*) malloc(hash_size + 1);
|
||||
md_info = mbedtls_md_info_from_type(md);
|
||||
unsigned hash_size = (unsigned)mbedtls_md_get_size(md_info);
|
||||
unsigned char *hmac_hash = (unsigned char *)malloc(hash_size + 1);
|
||||
|
||||
mbedtls_md_init(&ctx);
|
||||
mbedtls_md_setup(&ctx, md_info, 1);
|
||||
mbedtls_md_hmac_starts(&ctx, (const unsigned char*) key, key_length);
|
||||
mbedtls_md_hmac_update(&ctx, (const unsigned char*) data, length);
|
||||
mbedtls_md_hmac_finish(&ctx, hmac_hash);
|
||||
mbedtls_md_init(&ctx);
|
||||
mbedtls_md_setup(&ctx, md_info, 1);
|
||||
mbedtls_md_hmac_starts(&ctx, (const unsigned char *)key, key_length);
|
||||
mbedtls_md_hmac_update(&ctx, (const unsigned char *)data, length);
|
||||
mbedtls_md_hmac_finish(&ctx, hmac_hash);
|
||||
|
||||
free(data);
|
||||
data = (char*)hmac_hash;
|
||||
setLength(hash_size);
|
||||
mbedtls_md_free(&ctx);
|
||||
free(data);
|
||||
data = (char *)hmac_hash;
|
||||
setLength(hash_size);
|
||||
mbedtls_md_free(&ctx);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringBuffer::base64Decode() {
|
||||
assert(data != NULL && length > 0);
|
||||
char *decoded = (char*) malloc(length + 1); assert(decoded != NULL);
|
||||
size_t keyLength = 0;
|
||||
mbedtls_base64_decode((unsigned char*)decoded, length, &keyLength,
|
||||
(const unsigned char*)data, getLength());
|
||||
assert(keyLength > 0);
|
||||
free(data);
|
||||
data = (char*) malloc(keyLength + 1); assert(data != NULL);
|
||||
memcpy(data, decoded, keyLength);
|
||||
setLength(keyLength);
|
||||
free(decoded);
|
||||
return true;
|
||||
assert(data != NULL && length > 0);
|
||||
char *decoded = (char *)malloc(length + 1);
|
||||
assert(decoded != NULL);
|
||||
size_t keyLength = 0;
|
||||
mbedtls_base64_decode((unsigned char *)decoded, length, &keyLength,
|
||||
(const unsigned char *)data, getLength());
|
||||
assert(keyLength > 0);
|
||||
free(data);
|
||||
data = (char *)malloc(keyLength + 1);
|
||||
assert(data != NULL);
|
||||
memcpy(data, decoded, keyLength);
|
||||
setLength(keyLength);
|
||||
free(decoded);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringBuffer::base64Encode() {
|
||||
assert(data != NULL && length > 0);
|
||||
char *decoded = (char*) malloc(length * 3); assert(decoded != NULL);
|
||||
size_t keyLength = 0;
|
||||
mbedtls_base64_encode((unsigned char*)decoded, length * 3, &keyLength,
|
||||
(const unsigned char*)data, getLength());
|
||||
assert(keyLength > 0);
|
||||
free(data);
|
||||
data = (char*) malloc(keyLength + 1); assert(data != NULL);
|
||||
memcpy(data, decoded, keyLength);
|
||||
setLength(keyLength);
|
||||
free(decoded);
|
||||
return true;
|
||||
assert(data != NULL && length > 0);
|
||||
char *decoded = (char *)malloc(length * 3);
|
||||
assert(decoded != NULL);
|
||||
size_t keyLength = 0;
|
||||
mbedtls_base64_encode((unsigned char *)decoded, length * 3, &keyLength,
|
||||
(const unsigned char *)data, getLength());
|
||||
assert(keyLength > 0);
|
||||
free(data);
|
||||
data = (char *)malloc(keyLength + 1);
|
||||
assert(data != NULL);
|
||||
memcpy(data, decoded, keyLength);
|
||||
setLength(keyLength);
|
||||
free(decoded);
|
||||
return true;
|
||||
}
|
||||
#elif defined(ARDUINO)
|
||||
bool StringBuffer::hash(const char *key, unsigned key_length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
bool StringBuffer::hash(const char *key, unsigned key_length) {
|
||||
assert(data != NULL);
|
||||
|
||||
Sha256 *sha256 = new Sha256();
|
||||
sha256->initHmac((const uint8_t*)key, (size_t)key_length);
|
||||
sha256->print(data);
|
||||
char* sign = (char*) sha256->resultHmac();
|
||||
if (length < HASH_LENGTH) {
|
||||
free(data);
|
||||
data = (char*) malloc(HASH_LENGTH + 1);
|
||||
}
|
||||
memcpy(data, sign, HASH_LENGTH);
|
||||
setLength(HASH_LENGTH);
|
||||
delete sha256;
|
||||
return true;
|
||||
Sha256 *sha256 = new Sha256();
|
||||
sha256->initHmac((const uint8_t *)key, (size_t)key_length);
|
||||
sha256->print(data);
|
||||
char *sign = (char *)sha256->resultHmac();
|
||||
if (length < HASH_LENGTH) {
|
||||
free(data);
|
||||
data = (char *)malloc(HASH_LENGTH + 1);
|
||||
}
|
||||
memcpy(data, sign, HASH_LENGTH);
|
||||
setLength(HASH_LENGTH);
|
||||
delete sha256;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringBuffer::base64Decode() {
|
||||
assert(data != NULL && length > 0);
|
||||
char *decoded = (char*) malloc(length + 1); assert(decoded != NULL);
|
||||
size_t size = base64_decode(decoded, data, length);
|
||||
assert (size <= length + 1);
|
||||
free(data);
|
||||
data = (char*) malloc(size + 1); assert(data != NULL);
|
||||
memcpy(data, decoded, size);
|
||||
setLength(size);
|
||||
free(decoded);
|
||||
return true;
|
||||
assert(data != NULL && length > 0);
|
||||
char *decoded = (char *)malloc(length + 1);
|
||||
assert(decoded != NULL);
|
||||
size_t size = base64_decode(decoded, data, length);
|
||||
assert(size <= length + 1);
|
||||
free(data);
|
||||
data = (char *)malloc(size + 1);
|
||||
assert(data != NULL);
|
||||
memcpy(data, decoded, size);
|
||||
setLength(size);
|
||||
free(decoded);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringBuffer::base64Encode() {
|
||||
assert(data != NULL && length > 0);
|
||||
char *decoded = (char*) malloc(length * 3); assert(decoded != NULL);
|
||||
size_t size = base64_encode(decoded, data, length);
|
||||
assert (size < length * 3);
|
||||
free(data);
|
||||
data = (char*) malloc(size + 1); assert(data != NULL);
|
||||
memcpy(data, decoded, size);
|
||||
setLength(size);
|
||||
free(decoded);
|
||||
return true;
|
||||
assert(data != NULL && length > 0);
|
||||
char *decoded = (char *)malloc(length * 3);
|
||||
assert(decoded != NULL);
|
||||
size_t size = base64_encode(decoded, data, length);
|
||||
assert(size < length * 3);
|
||||
free(data);
|
||||
data = (char *)malloc(size + 1);
|
||||
assert(data != NULL);
|
||||
memcpy(data, decoded, size);
|
||||
setLength(size);
|
||||
free(decoded);
|
||||
return true;
|
||||
}
|
||||
#endif // __MBED__
|
||||
#endif // __MBED__
|
||||
|
||||
StringBuffer::StringBuffer(StringBuffer &buffer): data(NULL), immutable(NULL) {
|
||||
StringBuffer::StringBuffer(StringBuffer &buffer) : data(NULL), immutable(NULL) {
|
||||
length = 0;
|
||||
|
||||
initialize(buffer.data, buffer.length);
|
||||
}
|
||||
|
||||
StringBuffer::StringBuffer(const char *str, unsigned int lengthStr, bool isCopy)
|
||||
: data(NULL), immutable(NULL) {
|
||||
if (isCopy) {
|
||||
length = 0;
|
||||
|
||||
initialize(buffer.data, buffer.length);
|
||||
}
|
||||
|
||||
StringBuffer::StringBuffer(const char * str, unsigned int lengthStr, bool isCopy):
|
||||
data(NULL), immutable(NULL) {
|
||||
if (isCopy) {
|
||||
length = 0;
|
||||
if (str != NULL) {
|
||||
initialize(str, lengthStr);
|
||||
}
|
||||
} else {
|
||||
assert(str != NULL);
|
||||
immutable = str;
|
||||
length = lengthStr;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuffer::StringBuffer(unsigned lengthStr): data(NULL), immutable(NULL) {
|
||||
length = 0;
|
||||
|
||||
alloc(lengthStr + 1);
|
||||
assert(data != NULL); // out of memory?
|
||||
|
||||
length = lengthStr;
|
||||
}
|
||||
|
||||
void StringBuffer::initialize(const char * str, unsigned lengthStr) {
|
||||
if (str != NULL) {
|
||||
alloc(lengthStr + 1); // +1 for \0
|
||||
assert(data != NULL && immutable == NULL); // out of memory?
|
||||
|
||||
memcpy(data, str, lengthStr);
|
||||
data[lengthStr] = char(0);
|
||||
length = lengthStr;
|
||||
initialize(str, lengthStr);
|
||||
}
|
||||
} else {
|
||||
assert(str != NULL);
|
||||
immutable = str;
|
||||
length = lengthStr;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuffer::StringBuffer(unsigned lengthStr) : data(NULL), immutable(NULL) {
|
||||
length = 0;
|
||||
|
||||
alloc(lengthStr + 1);
|
||||
assert(data != NULL); // out of memory?
|
||||
|
||||
length = lengthStr;
|
||||
}
|
||||
|
||||
void StringBuffer::initialize(const char *str, unsigned lengthStr) {
|
||||
if (str != NULL) {
|
||||
alloc(lengthStr + 1); // +1 for \0
|
||||
assert(data != NULL && immutable == NULL); // out of memory?
|
||||
|
||||
memcpy(data, str, lengthStr);
|
||||
data[lengthStr] = char(0);
|
||||
length = lengthStr;
|
||||
}
|
||||
}
|
||||
|
||||
void StringBuffer::alloc(unsigned lengthStr) {
|
||||
ASSERT_OR_FAIL_FAST(lengthStr != 0 && data == NULL && immutable == NULL);
|
||||
ASSERT_OR_FAIL_FAST(lengthStr != 0 && data == NULL && immutable == NULL);
|
||||
|
||||
data = (char*) malloc(lengthStr);
|
||||
data = (char *)malloc(lengthStr);
|
||||
|
||||
ASSERT_OR_FAIL_FAST(data != NULL);
|
||||
memset(data, 0, lengthStr);
|
||||
ASSERT_OR_FAIL_FAST(data != NULL);
|
||||
memset(data, 0, lengthStr);
|
||||
}
|
||||
|
||||
void StringBuffer::set(unsigned index, char c) {
|
||||
assert(index < length && data != NULL);
|
||||
data[index] = c;
|
||||
assert(index < length && data != NULL);
|
||||
data[index] = c;
|
||||
}
|
||||
|
||||
void StringBuffer::clear() {
|
||||
if (data != NULL) {
|
||||
free(data);
|
||||
data = NULL;
|
||||
}
|
||||
if (data != NULL) {
|
||||
free(data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuffer::~StringBuffer() {
|
||||
this->clear();
|
||||
}
|
||||
StringBuffer::~StringBuffer() { this->clear(); }
|
||||
|
||||
void StringBuffer::setLength(unsigned l) {
|
||||
ASSERT_OR_FAIL_FAST(data != NULL);
|
||||
length = l;
|
||||
data[l] = char(0);
|
||||
ASSERT_OR_FAIL_FAST(data != NULL);
|
||||
length = l;
|
||||
data[l] = char(0);
|
||||
}
|
||||
|
||||
} // namespace AzureIOT
|
||||
} // namespace AzureIOT
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Oguz Bastemur. All rights reserved.
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef AZURE_IOTC_LITE_STRING_BUFFER_H
|
||||
|
@ -7,42 +7,43 @@
|
|||
namespace AzureIOT {
|
||||
|
||||
class StringBuffer {
|
||||
char * data;
|
||||
const char * immutable;
|
||||
unsigned length;
|
||||
char* data;
|
||||
const char* immutable;
|
||||
unsigned length;
|
||||
|
||||
public:
|
||||
StringBuffer(): data(NULL), immutable(NULL), length(0) { }
|
||||
public:
|
||||
StringBuffer() : data(NULL), immutable(NULL), length(0) {}
|
||||
|
||||
StringBuffer(StringBuffer &buffer);
|
||||
StringBuffer(StringBuffer& buffer);
|
||||
|
||||
StringBuffer(const char * str, unsigned int lengthStr, bool isCopy = true);
|
||||
StringBuffer(const char* str, unsigned int lengthStr, bool isCopy = true);
|
||||
|
||||
StringBuffer(unsigned lengthStr);
|
||||
StringBuffer(unsigned lengthStr);
|
||||
|
||||
void initialize(const char * str, unsigned lengthStr);
|
||||
void alloc(unsigned lengthStr);
|
||||
void set(unsigned index, char c);
|
||||
void clear();
|
||||
~StringBuffer();
|
||||
void initialize(const char* str, unsigned lengthStr);
|
||||
void alloc(unsigned lengthStr);
|
||||
void set(unsigned index, char c);
|
||||
void clear();
|
||||
~StringBuffer();
|
||||
|
||||
char* operator*() { return data; }
|
||||
unsigned getLength() { return length; }
|
||||
void setLength(unsigned l);
|
||||
bool startsWith(const char* str, size_t len);
|
||||
int32_t indexOf(const char* look_for, size_t look_for_length, int32_t start_index = 0);
|
||||
char* operator*() { return data; }
|
||||
unsigned getLength() { return length; }
|
||||
void setLength(unsigned l);
|
||||
bool startsWith(const char* str, size_t len);
|
||||
int32_t indexOf(const char* look_for, size_t look_for_length,
|
||||
int32_t start_index = 0);
|
||||
|
||||
#if defined(__MBED__) || defined(ARDUINO)
|
||||
bool hash(const char* key, unsigned key_length);
|
||||
bool hash(const char* key, unsigned key_length);
|
||||
#endif
|
||||
|
||||
bool urlDecode();
|
||||
bool urlEncode();
|
||||
bool urlDecode();
|
||||
bool urlEncode();
|
||||
|
||||
bool base64Decode();
|
||||
bool base64Encode();
|
||||
bool base64Decode();
|
||||
bool base64Encode();
|
||||
};
|
||||
|
||||
} // namespace AzureIOTCLite
|
||||
} // namespace AzureIOT
|
||||
|
||||
#endif // AZURE_IOTC_LITE_STRING_BUFFER_H
|
||||
#endif // AZURE_IOTC_LITE_STRING_BUFFER_H
|
|
@ -1,31 +1,18 @@
|
|||
// Copyright (c) Oguz Bastemur. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef AZURE_IOTC_API
|
||||
#define AZURE_IOTC_API
|
||||
|
||||
#if !defined(ESP_PLATFORM) && !defined(__MBED__)
|
||||
// MXCHIP
|
||||
#define TARGET_MXCHIP_AZ3166
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_MXCHIP_AZ3166
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#define AZIOTC_MAJOR_VERSION 0
|
||||
#define AZIOTC_MINOR_VERSION 1
|
||||
#define AZIOTC_PATCH_VERSION 0
|
||||
#define AZIOTC_VERSION \
|
||||
TO_STRING(AZIOTC_MAJOR_VERSION) "." TO_STRING(AZIOTC_MINOR_VERSION) "." TO_STRING(AZIOTC_PATCH_VERSION)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#define AZIOTC_PATCH_VERSION 1
|
||||
#define AZIOTC_VERSION \
|
||||
TO_STRING(AZIOTC_MAJOR_VERSION) \
|
||||
"." TO_STRING(AZIOTC_MINOR_VERSION) "." TO_STRING(AZIOTC_PATCH_VERSION)
|
||||
|
||||
// ***** Type definitions *****
|
||||
typedef struct IOTC_HTTP_PROXY_OPTIONS_TAG
|
||||
{
|
||||
typedef struct IOTC_HTTP_PROXY_OPTIONS_TAG {
|
||||
const char* host_address;
|
||||
int port;
|
||||
const char* username;
|
||||
|
@ -36,12 +23,12 @@ typedef struct IOTCallbackInfo_TAG {
|
|||
const char* eventName;
|
||||
const char* tag;
|
||||
const char* payload;
|
||||
unsigned payloadLength;
|
||||
unsigned payloadLength;
|
||||
|
||||
void *appContext;
|
||||
void* appContext;
|
||||
|
||||
int statusCode;
|
||||
void *callbackResponse;
|
||||
void* callbackResponse;
|
||||
} IOTCallbackInfo;
|
||||
|
||||
typedef void* IOTContext;
|
||||
|
@ -54,27 +41,27 @@ typedef short IOTProtocol;
|
|||
|
||||
#define IOTC_LOGGING_DISABLED 0x01
|
||||
#define IOTC_LOGGING_API_ONLY 0x02
|
||||
#define IOTC_LOGGING_ALL 0x10
|
||||
#define IOTC_LOGGING_ALL 0x10
|
||||
typedef short IOTLogLevel;
|
||||
|
||||
#define IOTC_CONNECT_SYMM_KEY 0x01
|
||||
#define IOTC_CONNECT_X509_CERT 0x02
|
||||
#define IOTC_CONNECT_SYMM_KEY 0x01
|
||||
#define IOTC_CONNECT_X509_CERT 0x02
|
||||
#define IOTC_CONNECT_CONNECTION_STRING 0x04
|
||||
typedef short IOTConnectType;
|
||||
|
||||
#define IOTC_CONNECTION_EXPIRED_SAS_TOKEN 0x01
|
||||
#define IOTC_CONNECTION_DEVICE_DISABLED 0x02
|
||||
#define IOTC_CONNECTION_BAD_CREDENTIAL 0x04
|
||||
#define IOTC_CONNECTION_RETRY_EXPIRED 0x08
|
||||
#define IOTC_CONNECTION_NO_NETWORK 0x10
|
||||
#define IOTC_CONNECTION_COMMUNICATION_ERROR 0x20
|
||||
#define IOTC_CONNECTION_OK 0x40
|
||||
#define IOTC_CONNECTION_DISCONNECTED 0x80
|
||||
#define IOTC_CONNECTION_EXPIRED_SAS_TOKEN 0x01
|
||||
#define IOTC_CONNECTION_DEVICE_DISABLED 0x02
|
||||
#define IOTC_CONNECTION_BAD_CREDENTIAL 0x04
|
||||
#define IOTC_CONNECTION_RETRY_EXPIRED 0x08
|
||||
#define IOTC_CONNECTION_NO_NETWORK 0x10
|
||||
#define IOTC_CONNECTION_COMMUNICATION_ERROR 0x20
|
||||
#define IOTC_CONNECTION_OK 0x40
|
||||
#define IOTC_CONNECTION_DISCONNECTED 0x80
|
||||
typedef short IOTConnectionState;
|
||||
|
||||
#define IOTC_MESSAGE_ACCEPTED 0x01
|
||||
#define IOTC_MESSAGE_REJECTED 0x02
|
||||
#define IOTC_MESSAGE_ABANDONED 0x04
|
||||
#define IOTC_MESSAGE_ACCEPTED 0x01
|
||||
#define IOTC_MESSAGE_REJECTED 0x02
|
||||
#define IOTC_MESSAGE_ABANDONED 0x04
|
||||
typedef short IOTMessageStatus;
|
||||
|
||||
// ***** API *****
|
||||
|
@ -82,9 +69,10 @@ typedef short IOTMessageStatus;
|
|||
// returns 0 if there is no error. Otherwise, error code will be returned.
|
||||
int iotc_set_logging(IOTLogLevel level);
|
||||
|
||||
// Initialize the device context. The context variable will be used by rest of the API
|
||||
// returns 0 if there is no error. Otherwise, error code will be returned.
|
||||
int iotc_init_context(IOTContext *ctx);
|
||||
// Initialize the device context. The context variable will be used by rest of
|
||||
// the API returns 0 if there is no error. Otherwise, error code will be
|
||||
// returned.
|
||||
int iotc_init_context(IOTContext* ctx);
|
||||
|
||||
// Free device context.
|
||||
// Call this after `init_context`
|
||||
|
@ -95,16 +83,15 @@ int iotc_free_context(IOTContext ctx);
|
|||
// Call this after `init_context`
|
||||
// returns 0 if there is no error. Otherwise, error code will be returned.
|
||||
int iotc_connect(IOTContext ctx, const char* scope, const char* keyORcert,
|
||||
const char* deviceId, IOTConnectType type);
|
||||
const char* deviceId, IOTConnectType type);
|
||||
|
||||
// Disconnect
|
||||
// returns 0 if there is no error. Otherwise, error code will be returned.
|
||||
int iotc_disconnect(IOTContext ctx);
|
||||
|
||||
// If your endpoint is different than the default AzureIoTCentral endpoint, set it
|
||||
// using this API.
|
||||
// Call this before `connect`
|
||||
// returns 0 if there is no error. Otherwise, error code will be returned.
|
||||
// If your endpoint is different than the default AzureIoTCentral endpoint, set
|
||||
// it using this API. Call this before `connect` returns 0 if there is no error.
|
||||
// Otherwise, error code will be returned.
|
||||
int iotc_set_global_endpoint(IOTContext ctx, const char* endpoint_uri);
|
||||
|
||||
// Set the custom certificates for custom endpoints
|
||||
|
@ -125,17 +112,17 @@ int iotc_send_telemetry(IOTContext ctx, const char* payload, unsigned length);
|
|||
// Sends a state payload (JSON)
|
||||
// Call this after `connect`
|
||||
// returns 0 if there is no error. Otherwise, error code will be returned.
|
||||
int iotc_send_state (IOTContext ctx, const char* payload, unsigned length);
|
||||
int iotc_send_state(IOTContext ctx, const char* payload, unsigned length);
|
||||
|
||||
// Sends an event payload (JSON)
|
||||
// Call this after `connect`
|
||||
// returns 0 if there is no error. Otherwise, error code will be returned.
|
||||
int iotc_send_event (IOTContext ctx, const char* payload, unsigned length);
|
||||
int iotc_send_event(IOTContext ctx, const char* payload, unsigned length);
|
||||
|
||||
// Sends a property payload (JSON)
|
||||
// Call this after `connect`
|
||||
// returns 0 if there is no error. Otherwise, error code will be returned.
|
||||
int iotc_send_property (IOTContext ctx, const char* payload, unsigned length);
|
||||
int iotc_send_property(IOTContext ctx, const char* payload, unsigned length);
|
||||
|
||||
/*
|
||||
eventName:
|
||||
|
@ -145,12 +132,13 @@ eventName:
|
|||
SettingsUpdated
|
||||
Error
|
||||
*/
|
||||
typedef void(*IOTCallback)(IOTContext, IOTCallbackInfo*);
|
||||
typedef void (*IOTCallback)(IOTContext, IOTCallbackInfo*);
|
||||
|
||||
// Register to one of the events listed above
|
||||
// Call this after `init_context`
|
||||
// returns 0 if there is no error. Otherwise, error code will be returned.
|
||||
int iotc_on(IOTContext ctx, const char* eventName, IOTCallback callback, void* appContext);
|
||||
int iotc_on(IOTContext ctx, const char* eventName, IOTCallback callback,
|
||||
void* appContext);
|
||||
|
||||
// Lets SDK to do background work
|
||||
// Call this after `connect`
|
||||
|
@ -160,10 +148,11 @@ int iotc_do_work(IOTContext ctx);
|
|||
// Provide platform dependent NetworkInterface
|
||||
int iotc_set_network_interface(void* networkInterface);
|
||||
|
||||
#ifndef LOG_VERBOSE
|
||||
#ifdef ARDUINO
|
||||
#define SERIAL_PRINT Serial.printf
|
||||
#define SERIAL_PRINT Serial.printf
|
||||
#else
|
||||
#define SERIAL_PRINT printf
|
||||
#define SERIAL_PRINT printf
|
||||
#endif
|
||||
|
||||
#define SERIAL_VERBOSE_LOGGING_ENABLED 1
|
||||
|
@ -172,25 +161,22 @@ int iotc_set_network_interface(void* networkInterface);
|
|||
#if SERIAL_VERBOSE_LOGGING_ENABLED != 1
|
||||
#define LOG_VERBOSE(...)
|
||||
#else
|
||||
#define LOG_VERBOSE(...) \
|
||||
do { \
|
||||
SERIAL_PRINT(" - "); \
|
||||
SERIAL_PRINT(__VA_ARGS__); \
|
||||
SERIAL_PRINT("\r\n"); \
|
||||
} while(0)
|
||||
#endif // SERIAL_VERBOSE_LOGGING_ENABLED != 1
|
||||
#define LOG_VERBOSE(...) \
|
||||
do { \
|
||||
SERIAL_PRINT(" - "); \
|
||||
SERIAL_PRINT(__VA_ARGS__); \
|
||||
SERIAL_PRINT("\r\n"); \
|
||||
} while (0)
|
||||
#endif // SERIAL_VERBOSE_LOGGING_ENABLED != 1
|
||||
|
||||
// Log Errors no matter what
|
||||
#define LOG_ERROR(...) \
|
||||
do { \
|
||||
SERIAL_PRINT("X - Error at %s:%d\r\n\t", __FILE__, __LINE__); \
|
||||
SERIAL_PRINT(__VA_ARGS__); \
|
||||
SERIAL_PRINT("\r\n"); \
|
||||
} while(0)
|
||||
#endif // !LOG_VERBOSE
|
||||
#define LOG_ERROR(...) \
|
||||
do { \
|
||||
SERIAL_PRINT("X - Error at %s:%d\r\n\t", __FILE__, __LINE__); \
|
||||
SERIAL_PRINT(__VA_ARGS__); \
|
||||
SERIAL_PRINT("\r\n"); \
|
||||
} while (0)
|
||||
#endif // !LOG_VERBOSE
|
||||
#endif // LOG_VERBOSE
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // AZURE_IOTC_API
|
||||
#endif // AZURE_IOTC_API
|
Загрузка…
Ссылка в новой задаче