demo project
Dependencies: AX-12A Dynamixel mbed iothub_client EthernetInterface NTPClient ConfigFile SDFileSystem iothub_amqp_transport mbed-rtos proton-c-mbed wolfSSL
Revision 21:051751f9ca9e, committed 2016-01-26
- Comitter:
- henryrawas
- Date:
- Tue Jan 26 20:19:43 2016 +0000
- Parent:
- 20:891b5270845a
- Child:
- 22:f9c13c5f75c1
- Commit message:
- Use private modified iothub client and eliminate extra thread.
Changed in this revision
--- a/IothubRobotArm.cpp Tue Jan 26 17:34:51 2016 +0000 +++ b/IothubRobotArm.cpp Tue Jan 26 20:19:43 2016 +0000 @@ -9,7 +9,7 @@ #include "mbed/mbedtime.h" #include <NTPClient.h> -#include "iothub_client.h" +#include "iothub_mod_client.h" #include "iothub_message.h" #include "threadapi.h" #include "crt_abstractions.h" @@ -107,7 +107,7 @@ // a larger MESSAGE_COUNT results in being able to send as data is available // but requires more heap space to hold buffers -#define MESSAGE_COUNT 2 +#define MESSAGE_COUNT 4 EVENT_INSTANCE messages[MESSAGE_COUNT]; // sending thread timeout @@ -125,6 +125,9 @@ #define SEND_CONFIRM_TO 30000 RtosTimer* confirmTimer; +// object for IoTHub interface +IothubRobotArm iotRobot; + // pass received commands to device extern void ControlArmCommands(const char* cmd); @@ -171,6 +174,12 @@ IoTHubMessage_Destroy(eventInstance->messageHandle); } + +static void SendCallback(IOTHUB_CLIENT_HANDLE iotHubClientHandle, void* userContextCallback) +{ + iotRobot.SendMessage(iotHubClientHandle, userContextCallback); +} + // communication timeout void CommunicationTO(void const * tid) { @@ -178,59 +187,26 @@ ShowLedColor(2); } - -// IoT Hub thread -static THREAD_HANDLE IotThread; -static bool IotThreadClose; - -// entry point for ITHub sending thread -int IothubThread(void *args) -{ - (void)printf("Iothub thread start\r\n"); - IotThreadClose = false; - IothubRobotArm iotRobot; - - confirmTimer = new RtosTimer(CommunicationTO, osTimerOnce, (void *)osThreadGetId()); - - iotRobot.Init(); - // wait for connection establishment for SSL - ThreadAPI_Sleep(15000); - - while (1) - { - if (IotThreadClose) - { - (void)printf("Iothub thread close\r\n"); - iotRobot.Terminate(); - break; - } - else - { - iotRobot.SendMessage(); - } - ThreadAPI_Sleep(SEND_POLL_MS); - } - - return 0; -} - - +// entry point to start IoTHub connection bool StartIothubThread() { InitEthernet(); - ThreadAPI_Create(&IotThread, IothubThread, NULL); + confirmTimer = new RtosTimer(CommunicationTO, osTimerOnce, (void *)osThreadGetId()); + + iotRobot.Init(); return true; } - +// stop IoTHub connection void EndIothubThread() { - IotThreadClose = true; + iotRobot.Terminate(); } - +// IoTHub connection for RobotArm +// sends and receives messages between RobotArm and IoTHub IothubRobotArm::IothubRobotArm() { iotHubClientHandle = NULL; @@ -244,7 +220,7 @@ (void)printf("Starting the IoTHub RobotArm sample AMQP...\r\n"); - if ((iotHubClientHandle = IoTHubClient_CreateFromConnectionString(connectionString, AMQP_Protocol)) == NULL) + if ((iotHubClientHandle = IoTHubClient_Mod_CreateFromConnectionString(connectionString, AMQP_Protocol)) == NULL) { (void)printf("ERROR: iotHubClientHandle is NULL!\r\n"); return false; @@ -254,16 +230,15 @@ #ifdef MBED_BUILD_TIMESTAMP (void)printf("INFO: IoTHubClient_SetOption\r\n"); // For mbed add the certificate information - if (IoTHubClient_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK) + if (IoTHubClient_Mod_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK) { printf("failure to set option \"TrustedCerts\"\r\n"); return false; } #endif // MBED_BUILD_TIMESTAMP - (void)printf("INFO: IoTHubClient_SetMessageCallback\r\n"); /* Setting Message call back, so we can receive Commands. */ - if (IoTHubClient_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, &receiveContext) != IOTHUB_CLIENT_OK) + if (IoTHubClient_Mod_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, &receiveContext) != IOTHUB_CLIENT_OK) { (void)printf("ERROR: IoTHubClient_SetMessageCallback..........FAILED!\r\n"); return false; @@ -272,6 +247,17 @@ { (void)printf("IoTHubClient_SetMessageCallback...successful.\r\n"); } + + /* Setting Send call back, so we can send from worker thread. */ + if (IoTHubClient_Mod_SetSendCallback(iotHubClientHandle, SendCallback, &receiveContext) != IOTHUB_CLIENT_OK) + { + (void)printf("ERROR: IoTHubClient_SetSendCallback..........FAILED!\r\n"); + return false; + } + else + { + (void)printf("IoTHubClient_SetSendCallback...successful.\r\n"); + } } return true; } @@ -280,13 +266,13 @@ { if (iotHubClientHandle != NULL) { - IoTHubClient_Destroy(iotHubClientHandle); + IoTHubClient_Mod_Destroy(iotHubClientHandle); iotHubClientHandle = NULL; } } - -void IothubRobotArm::SendMessage(void) +// Invoked from callback +void IothubRobotArm::SendMessage(IOTHUB_CLIENT_HANDLE iotHubClient, void* userContextCallback) { // send until circular buf empty or no sending buffers avail // may drop message if confirmations are slow @@ -313,9 +299,9 @@ else { messages[i].messageTrackingId = msgNumber; - + confirmTimer->stop(); - if (IoTHubClient_SendEventAsync(iotHubClientHandle, messages[i].messageHandle, SendConfirmationCallback, &messages[i]) != IOTHUB_CLIENT_OK) + if (IoTHubClient_Mod_SendEventAsync(iotHubClient, messages[i].messageHandle, SendConfirmationCallback, &messages[i]) != IOTHUB_CLIENT_OK) { (void)printf("ERROR: IoTHubClient_SendEventAsync..........FAILED!\r\n"); }
--- a/IothubRobotArm.h Tue Jan 26 17:34:51 2016 +0000 +++ b/IothubRobotArm.h Tue Jan 26 20:19:43 2016 +0000 @@ -4,7 +4,7 @@ #ifndef IOTHUB_ROBOTARM_H #define IOTHUB_ROBOTARM_H -#include "iothub_client.h" +#include "iothub_mod_client.h" #include "IothubSerial.h" @@ -17,7 +17,7 @@ void Terminate(); - void SendMessage(void); + void SendMessage(IOTHUB_CLIENT_HANDLE iotHubClient, void* userContextCallback); private:
--- a/Utils/MeasureBuf.h Tue Jan 26 17:34:51 2016 +0000 +++ b/Utils/MeasureBuf.h Tue Jan 26 20:19:43 2016 +0000 @@ -9,7 +9,7 @@ #include "RobotArmCfg.h" -#define MeasureBufSize 4 +#define MeasureBufSize 8 class MeasureGroup
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utils/iothub_mod_client.c Tue Jan 26 20:19:43 2016 +0000 @@ -0,0 +1,415 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// iothub_mod_client.c : modified version of iothub_client.c + +#include <stdlib.h> +#ifdef _CRTDBG_MAP_ALLOC +#include <crtdbg.h> +#endif +#include "gballoc.h" + +#include <stdlib.h> +#include <signal.h> +#include "crt_abstractions.h" +#include "iothub_mod_client.h" +#include "iothub_client_ll.h" +#include "threadapi.h" +#include "lock.h" +#include "iot_logging.h" + +typedef struct IOTHUB_CLIENT_INSTANCE_TAG +{ + IOTHUB_CLIENT_LL_HANDLE IoTHubClientLLHandle; + THREAD_HANDLE ThreadHandle; + LOCK_HANDLE LockHandle; + sig_atomic_t StopThread; + IOTHUB_CLIENT_SEND_CALLBACK SendCallback; + void* SendContext; +} IOTHUB_CLIENT_INSTANCE; + +static int ScheduleWork_Mod_Thread(void* threadArgument) +{ + IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)threadArgument; + + /* Codes_SRS_IOTHUBCLIENT_01_038: [The thread shall exit when IoTHubClient_Destroy is called.] */ + while (!iotHubClientInstance->StopThread) + { + /* Codes_SRS_IOTHUBCLIENT_01_039: [All calls to IoTHubClient_LL_DoWork shall be protected by the lock created in IotHubClient_Create.] */ + /* Codes_SRS_IOTHUBCLIENT_01_040: [If acquiring the lock fails, IoTHubClient_LL_DoWork shall not be called.] */ + if (Lock(iotHubClientInstance->LockHandle) == LOCK_OK) + { + /* Codes_SRS_IOTHUBCLIENT_01_037: [The thread created by IoTHubClient_SendEvent or IoTHubClient_SetMessageCallback shall call IoTHubClient_LL_DoWork every 1 ms.] */ + IoTHubClient_LL_DoWork(iotHubClientInstance->IoTHubClientLLHandle); + /* Codes_SRS_IOTHUBCLIENT_01_039: [All calls to IoTHubClient_LL_DoWork shall be protected by the lock created in IotHubClient_Create.] */ + Unlock(iotHubClientInstance->LockHandle); + } + if (iotHubClientInstance->SendCallback != NULL) + { + iotHubClientInstance->SendCallback(iotHubClientInstance, iotHubClientInstance->SendContext); + } + ThreadAPI_Sleep(1); + } + + return 0; +} + +static void StartWorkerThreadIfNeeded_Mod(IOTHUB_CLIENT_INSTANCE* iotHubClientInstance) +{ + if (iotHubClientInstance->ThreadHandle == NULL) + { + iotHubClientInstance->StopThread = 0; + if (ThreadAPI_Create(&iotHubClientInstance->ThreadHandle, ScheduleWork_Mod_Thread, iotHubClientInstance) != THREADAPI_OK) + { + iotHubClientInstance->ThreadHandle = NULL; + } + } +} + +IOTHUB_CLIENT_HANDLE IoTHubClient_Mod_CreateFromConnectionString(const char* connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) +{ + IOTHUB_CLIENT_INSTANCE* result = NULL; + + /* Codes_SRS_IOTHUBCLIENT_12_003: [IoTHubClient_CreateFromConnectionString shall verify the input parameter and if it is NULL then return NULL] */ + if (connectionString == NULL) + { + LogError("Input parameter is NULL: connectionString\r\n"); + } + else if (protocol == NULL) + { + LogError("Input parameter is NULL: protocol\r\n"); + } + else + { + /* Codes_SRS_IOTHUBCLIENT_12_004: [IoTHubClient_CreateFromConnectionString shall allocate a new IoTHubClient instance.] */ + result = malloc(sizeof(IOTHUB_CLIENT_INSTANCE)); + + /* Codes_SRS_IOTHUBCLIENT_12_011: [If the allocation failed, IoTHubClient_CreateFromConnectionString returns NULL] */ + if (result == NULL) + { + LogError("Malloc failed\r\n"); + } + else + { + /* Codes_SRS_IOTHUBCLIENT_12_005: [IoTHubClient_CreateFromConnectionString shall create a lock object to be used later for serializing IoTHubClient calls] */ + result->LockHandle = Lock_Init(); + if (result->LockHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_12_009: [If lock creation failed, IoTHubClient_CreateFromConnectionString shall do clean up and return NULL] */ + free(result); + result = NULL; + LogError("Lock_Init failed\r\n"); + } + else + { + /* Codes_SRS_IOTHUBCLIENT_12_006: [IoTHubClient_CreateFromConnectionString shall instantiate a new IoTHubClient_LL instance by calling IoTHubClient_LL_CreateFromConnectionString and passing the connectionString] */ + result->IoTHubClientLLHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, protocol); + if (result->IoTHubClientLLHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_12_010: [If IoTHubClient_LL_CreateFromConnectionString fails then IoTHubClient_CreateFromConnectionString shall do clean - up and return NULL] */ + Lock_Deinit(result->LockHandle); + free(result); + result = NULL; + LogError("IoTHubClient_LL_CreateFromConnectionString failed\r\n"); + } + else + { + result->ThreadHandle = NULL; + result->SendCallback = NULL; + } + } + } + } + return result; +} + + +IOTHUB_CLIENT_HANDLE IoTHubClient_Mod_Create(const IOTHUB_CLIENT_CONFIG* config) +{ + /* Codes_SRS_IOTHUBCLIENT_01_001: [IoTHubClient_Create shall allocate a new IoTHubClient instance and return a non-NULL handle to it.] */ + IOTHUB_CLIENT_INSTANCE* result = (IOTHUB_CLIENT_INSTANCE*)malloc(sizeof(IOTHUB_CLIENT_INSTANCE)); + + /* Codes_SRS_IOTHUBCLIENT_01_004: [If allocating memory for the new IoTHubClient instance fails, then IoTHubClient_Create shall return NULL.] */ + if (result != NULL) + { + result->ThreadHandle = NULL; + result->SendCallback = NULL; + + /* Codes_SRS_IOTHUBCLIENT_01_029: [IoTHubClient_Create shall create a lock object to be used later for serializing IoTHubClient calls.] */ + result->LockHandle = Lock_Init(); + if (result->LockHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_01_030: [If creating the lock fails, then IoTHubClient_Create shall return NULL.] */ + /* Codes_SRS_IOTHUBCLIENT_01_031: [If IoTHubClient_Create fails, all resources allocated by it shall be freed.] */ + free(result); + result = NULL; + } + else + { + /* Codes_SRS_IOTHUBCLIENT_01_002: [IoTHubClient_Create shall instantiate a new IoTHubClient_LL instance by calling IoTHubClient_LL_Create and passing the config argument.] */ + result->IoTHubClientLLHandle = IoTHubClient_LL_Create(config); + if (result->IoTHubClientLLHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_01_003: [If IoTHubClient_LL_Create fails, then IoTHubClient_Create shall return NULL.] */ + /* Codes_SRS_IOTHUBCLIENT_01_031: [If IoTHubClient_Create fails, all resources allocated by it shall be freed.] */ + Lock_Deinit(result->LockHandle); + free(result); + result = NULL; + } + } + } + + return result; +} + +/* Codes_SRS_IOTHUBCLIENT_01_005: [IoTHubClient_Destroy shall free all resources associated with the iotHubClientHandle instance.] */ +void IoTHubClient_Mod_Destroy(IOTHUB_CLIENT_HANDLE iotHubClientHandle) +{ + /* Codes_SRS_IOTHUBCLIENT_01_008: [IoTHubClient_Destroy shall do nothing if parameter iotHubClientHandle is NULL.] */ + if (iotHubClientHandle != NULL) + { + IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)iotHubClientHandle; + + /* Codes_SRS_IOTHUBCLIENT_01_007: [The thread created as part of executing IoTHubClient_SendEventAsync or IoTHubClient_SetMessageCallback shall be joined.] */ + if (iotHubClientInstance->ThreadHandle != NULL) + { + int res; + iotHubClientInstance->StopThread = 1; + if (ThreadAPI_Join(iotHubClientInstance->ThreadHandle, &res) != THREADAPI_OK) + { + LogError("ThreadAPI_Join failed\r\n"); + } + } + + /* Codes_SRS_IOTHUBCLIENT_01_006: [That includes destroying the IoTHubClient_LL instance by calling IoTHubClient_LL_Destroy.] */ + IoTHubClient_LL_Destroy(iotHubClientInstance->IoTHubClientLLHandle); + + /* Codes_SRS_IOTHUBCLIENT_01_032: [The lock allocated in IoTHubClient_Create shall be also freed.] */ + Lock_Deinit(iotHubClientInstance->LockHandle); + free(iotHubClientInstance); + } +} + +IOTHUB_CLIENT_RESULT IoTHubClient_Mod_SendEventAsync(IOTHUB_CLIENT_HANDLE iotHubClientHandle, IOTHUB_MESSAGE_HANDLE eventMessageHandle, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK eventConfirmationCallback, void* userContextCallback) +{ + IOTHUB_CLIENT_RESULT result; + + if (iotHubClientHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_01_011: [If iotHubClientHandle is NULL, IoTHubClient_SendEventAsync shall return IOTHUB_CLIENT_INVALID_ARG.] */ + result = IOTHUB_CLIENT_INVALID_ARG; + LogError("NULL iothubClientHandle\r\n"); + } + else + { + IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)iotHubClientHandle; + + /* Codes_SRS_IOTHUBCLIENT_01_025: [IoTHubClient_SendEventAsync shall be made thread-safe by using the lock created in IoTHubClient_Create.] */ + if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK) + { + /* Codes_SRS_IOTHUBCLIENT_01_026: [If acquiring the lock fails, IoTHubClient_SendEventAsync shall return IOTHUB_CLIENT_ERROR.] */ + result = IOTHUB_CLIENT_ERROR; + LogError("Could not acquire lock\r\n"); + } + else + { + /* Codes_SRS_IOTHUBCLIENT_01_009: [IoTHubClient_SendEventAsync shall start the worker thread if it was not previously started.] */ + StartWorkerThreadIfNeeded_Mod(iotHubClientInstance); + + if (iotHubClientInstance->ThreadHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_01_010: [If starting the thread fails, IoTHubClient_SendEventAsync shall return IOTHUB_CLIENT_ERROR.] */ + result = IOTHUB_CLIENT_ERROR; + LogError("Could not start worker thread\r\n"); + } + else + { + /* Codes_SRS_IOTHUBCLIENT_01_012: [IoTHubClient_SendEventAsync shall call IoTHubClient_LL_SendEventAsync, while passing the IoTHubClient_LL handle created by IoTHubClient_Create and the parameters eventMessageHandle, eventConfirmationCallback and userContextCallback.] */ + /* Codes_SRS_IOTHUBCLIENT_01_013: [When IoTHubClient_LL_SendEventAsync is called, IoTHubClient_SendEventAsync shall return the result of IoTHubClient_LL_SendEventAsync.] */ + result = IoTHubClient_LL_SendEventAsync(iotHubClientInstance->IoTHubClientLLHandle, eventMessageHandle, eventConfirmationCallback, userContextCallback); + } + + /* Codes_SRS_IOTHUBCLIENT_01_025: [IoTHubClient_SendEventAsync shall be made thread-safe by using the lock created in IoTHubClient_Create.] */ + (void)Unlock(iotHubClientInstance->LockHandle); + } + } + + return result; +} + +IOTHUB_CLIENT_RESULT IoTHubClient_Mod_GetSendStatus(IOTHUB_CLIENT_HANDLE iotHubClientHandle, IOTHUB_CLIENT_STATUS *iotHubClientStatus) +{ + IOTHUB_CLIENT_RESULT result; + + if (iotHubClientHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_01_023: [If iotHubClientHandle is NULL, IoTHubClient_ GetSendStatus shall return IOTHUB_CLIENT_INVALID_ARG.] */ + result = IOTHUB_CLIENT_INVALID_ARG; + LogError("NULL iothubClientHandle\r\n"); + } + else + { + IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)iotHubClientHandle; + + /* Codes_SRS_IOTHUBCLIENT_01_033: [IoTHubClient_GetSendStatus shall be made thread-safe by using the lock created in IoTHubClient_Create.] */ + if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK) + { + /* Codes_SRS_IOTHUBCLIENT_01_034: [If acquiring the lock fails, IoTHubClient_GetSendStatus shall return IOTHUB_CLIENT_ERROR.] */ + result = IOTHUB_CLIENT_ERROR; + LogError("Could not acquire lock\r\n"); + } + else + { + /* Codes_SRS_IOTHUBCLIENT_01_022: [IoTHubClient_GetSendStatus shall call IoTHubClient_LL_GetSendStatus, while passing the IoTHubClient_LL handle created by IoTHubClient_Create and the parameter iotHubClientStatus.] */ + /* Codes_SRS_IOTHUBCLIENT_01_024: [Otherwise, IoTHubClient_GetSendStatus shall return the result of IoTHubClient_LL_GetSendStatus.] */ + result = IoTHubClient_LL_GetSendStatus(iotHubClientInstance->IoTHubClientLLHandle, iotHubClientStatus); + + /* Codes_SRS_IOTHUBCLIENT_01_033: [IoTHubClient_GetSendStatus shall be made thread-safe by using the lock created in IoTHubClient_Create.] */ + (void)Unlock(iotHubClientInstance->LockHandle); + } + } + + return result; +} + +IOTHUB_CLIENT_RESULT IoTHubClient_Mod_SetMessageCallback(IOTHUB_CLIENT_HANDLE iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC messageCallback, void* userContextCallback) +{ + IOTHUB_CLIENT_RESULT result; + + if (iotHubClientHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_01_016: [If iotHubClientHandle is NULL, IoTHubClient_SetMessageCallback shall return IOTHUB_CLIENT_INVALID_ARG.] */ + result = IOTHUB_CLIENT_INVALID_ARG; + LogError("NULL iothubClientHandle\r\n"); + } + else + { + IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)iotHubClientHandle; + + /* Codes_SRS_IOTHUBCLIENT_01_027: [IoTHubClient_SetMessageCallback shall be made thread-safe by using the lock created in IoTHubClient_Create.] */ + if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK) + { + /* Codes_SRS_IOTHUBCLIENT_01_028: [If acquiring the lock fails, IoTHubClient_SetMessageCallback shall return IOTHUB_CLIENT_ERROR.] */ + result = IOTHUB_CLIENT_ERROR; + LogError("Could not acquire lock\r\n"); + } + else + { + /* Codes_SRS_IOTHUBCLIENT_01_014: [IoTHubClient_SetMessageCallback shall start the worker thread if it was not previously started.] */ + StartWorkerThreadIfNeeded_Mod(iotHubClientInstance); + + if (iotHubClientInstance->ThreadHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_01_015: [If starting the thread fails, IoTHubClient_SetMessageCallback shall return IOTHUB_CLIENT_ERROR.] */ + result = IOTHUB_CLIENT_ERROR; + LogError("Could not start worker thread\r\n"); + } + else + { + /* Codes_SRS_IOTHUBCLIENT_01_017: [IoTHubClient_SetMessageCallback shall call IoTHubClient_LL_SetMessageCallback, while passing the IoTHubClient_LL handle created by IoTHubClient_Create and the parameters messageCallback and userContextCallback.] */ + result = IoTHubClient_LL_SetMessageCallback(iotHubClientInstance->IoTHubClientLLHandle, messageCallback, userContextCallback); + } + + /* Codes_SRS_IOTHUBCLIENT_01_027: [IoTHubClient_SetMessageCallback shall be made thread-safe by using the lock created in IoTHubClient_Create.] */ + Unlock(iotHubClientInstance->LockHandle); + } + } + + return result; +} + +IOTHUB_CLIENT_RESULT IoTHubClient_Mod_SetSendCallback(IOTHUB_CLIENT_HANDLE iotHubClientHandle, IOTHUB_CLIENT_SEND_CALLBACK sendCallback, void* userContextCallback) +{ + IOTHUB_CLIENT_RESULT result; + + if (iotHubClientHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_01_016: [If iotHubClientHandle is NULL, IoTHubClient_SetMessageCallback shall return IOTHUB_CLIENT_INVALID_ARG.] */ + result = IOTHUB_CLIENT_INVALID_ARG; + LogError("NULL iothubClientHandle\r\n"); + } + else + { + IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)iotHubClientHandle; + + /* Codes_SRS_IOTHUBCLIENT_01_027: [IoTHubClient_SetMessageCallback shall be made thread-safe by using the lock created in IoTHubClient_Create.] */ + if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK) + { + /* Codes_SRS_IOTHUBCLIENT_01_028: [If acquiring the lock fails, IoTHubClient_SetMessageCallback shall return IOTHUB_CLIENT_ERROR.] */ + result = IOTHUB_CLIENT_ERROR; + LogError("Could not acquire lock\r\n"); + } + else + { + iotHubClientInstance->SendCallback = sendCallback; + iotHubClientInstance->SendContext = userContextCallback; + + /* Codes_SRS_IOTHUBCLIENT_01_027: [IoTHubClient_SetMessageCallback shall be made thread-safe by using the lock created in IoTHubClient_Create.] */ + Unlock(iotHubClientInstance->LockHandle); + } + } + + return result; +} + +IOTHUB_CLIENT_RESULT IoTHubClient_Mod_GetLastMessageReceiveTime(IOTHUB_CLIENT_HANDLE iotHubClientHandle, time_t* lastMessageReceiveTime) +{ + IOTHUB_CLIENT_RESULT result; + + if (iotHubClientHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_01_020: [If iotHubClientHandle is NULL, IoTHubClient_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_INVALID_ARG.] */ + result = IOTHUB_CLIENT_INVALID_ARG; + LogError("NULL iothubClientHandle\r\n"); + } + else + { + IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)iotHubClientHandle; + + /* Codes_SRS_IOTHUBCLIENT_01_035: [IoTHubClient_GetLastMessageReceiveTime shall be made thread-safe by using the lock created in IoTHubClient_Create.] */ + if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK) + { + /* Codes_SRS_IOTHUBCLIENT_01_036: [If acquiring the lock fails, IoTHubClient_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_ERROR.] */ + result = IOTHUB_CLIENT_ERROR; + LogError("Could not acquire lock\r\n"); + } + else + { + /* Codes_SRS_IOTHUBCLIENT_01_019: [IoTHubClient_GetLastMessageReceiveTime shall call IoTHubClient_LL_GetLastMessageReceiveTime, while passing the IoTHubClient_LL handle created by IoTHubClient_Create and the parameter lastMessageReceiveTime.] */ + /* Codes_SRS_IOTHUBCLIENT_01_021: [Otherwise, IoTHubClient_GetLastMessageReceiveTime shall return the result of IoTHubClient_LL_GetLastMessageReceiveTime.] */ + result = IoTHubClient_LL_GetLastMessageReceiveTime(iotHubClientInstance->IoTHubClientLLHandle, lastMessageReceiveTime); + + /* Codes_SRS_IOTHUBCLIENT_01_035: [IoTHubClient_GetLastMessageReceiveTime shall be made thread-safe by using the lock created in IoTHubClient_Create.] */ + Unlock(iotHubClientInstance->LockHandle); + } + } + + return result; +} + +IOTHUB_CLIENT_RESULT IoTHubClient_Mod_SetOption(IOTHUB_CLIENT_HANDLE iotHubClientHandle, const char* optionName, const void* value) +{ + IOTHUB_CLIENT_RESULT result; + /*Codes_SRS_IOTHUBCLIENT_02_034: [If parameter iotHubClientHandle is NULL then IoTHubClient_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.] */ + if ( + (iotHubClientHandle == NULL) || + (optionName == NULL) || + (value == NULL) + ) + { + result = IOTHUB_CLIENT_INVALID_ARG; + LogError("invalid arg (NULL)r\n"); + } + else + { + IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)iotHubClientHandle; + /*Codes_SRS_IOTHUBCLIENT_02_038: [If optionName doesn't match one of the options handled by this module then IoTHubClient_SetOption shall call IoTHubClient_LL_SetOption passing the same parameters and return what IoTHubClient_LL_SetOption returns.] */ + result = IoTHubClient_LL_SetOption(iotHubClientInstance->IoTHubClientLLHandle, optionName, value); + + if (result != IOTHUB_CLIENT_OK) + { + LogError("IoTHubClient_LL_SetOption failed\r\n"); + } + } + return result; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utils/iothub_mod_client.h Tue Jan 26 20:19:43 2016 +0000 @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// iothub_mod_client.h : modified version of iothub_client.h + +/** @file iothub_client.h +* @brief Extends the IoTHubCLient_LL module with additional features. +* +* @details IoTHubClient is a module that extends the IoTHubCLient_LL +* module with 2 features: +* - scheduling the work for the IoTHubCLient from a +* thread, so that the user does not need to create their +* own thread +* - thread-safe APIs +*/ + +#ifndef IOTHUB_MOD_CLIENT_H + +#include "iothub_client_ll.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef void* IOTHUB_CLIENT_HANDLE; + + typedef void (*IOTHUB_CLIENT_SEND_CALLBACK)(IOTHUB_CLIENT_HANDLE iotHubClientHandle, void* userContextCallback); + + /** + * @brief Creates a IoT Hub client for communication with an existing + * IoT Hub using the specified connection string parameter. + * + * @param connectionString Pointer to a character string + * @param protocol Function pointer for protocol implementation + * + * Sample connection string: + * <blockquote> + * <pre>HostName=[IoT Hub name goes here].[IoT Hub suffix goes here, e.g., private.azure-devices-int.net];DeviceId=[Device ID goes here];SharedAccessKey=[Device key goes here];</pre> + * </blockquote> + * + * @return A non-NULL @c IOTHUB_CLIENT_HANDLE value that is used when + * invoking other functions for IoT Hub client and @c NULL on failure. + */ + extern IOTHUB_CLIENT_HANDLE IoTHubClient_Mod_CreateFromConnectionString(const char* connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol); + + /** + * @brief Creates a IoT Hub client for communication with an existing IoT + * Hub using the specified parameters. + * + * @param config Pointer to an @c IOTHUB_CLIENT_CONFIG structure + * + * The API does not allow sharing of a connection across multiple + * devices. This is a blocking call. + * + * @return A non-NULL @c IOTHUB_CLIENT_HANDLE value that is used when + * invoking other functions for IoT Hub client and @c NULL on failure. + */ + extern IOTHUB_CLIENT_HANDLE IoTHubClient_Mod_Create(const IOTHUB_CLIENT_CONFIG* config); + + /** + * @brief Disposes of resources allocated by the IoT Hub client. This is a + * blocking call. + * + * @param iotHubClientHandle The handle created by a call to the create function. + */ + extern void IoTHubClient_Mod_Destroy(IOTHUB_CLIENT_HANDLE iotHubClientHandle); + + /** + * @brief Asynchronous call to send the message specified by @p eventMessageHandle. + * + * @param iotHubClientHandle The handle created by a call to the create function. + * @param eventMessageHandle The handle to an IoT Hub message. + * @param eventConfirmationCallback The callback specified by the device for receiving + * confirmation of the delivery of the IoT Hub message. + * This callback can be expected to invoke the + * ::IoTHubClient_SendEventAsync function for the + * same message in an attempt to retry sending a failing + * message. The user can specify a @c NULL value here to + * indicate that no callback is required. + * @param userContextCallback User specified context that will be provided to the + * callback. This can be @c NULL. + * + * @b NOTE: The application behavior is undefined if the user calls + * the ::IoTHubClient_Destroy function from within any callback. + * + * @return IOTHUB_CLIENT_OK upon success or an error code upon failure. + */ + extern IOTHUB_CLIENT_RESULT IoTHubClient_Mod_SendEventAsync(IOTHUB_CLIENT_HANDLE iotHubClientHandle, IOTHUB_MESSAGE_HANDLE eventMessageHandle, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK eventConfirmationCallback, void* userContextCallback); + + /** + * @brief This function returns the current sending status for IoTHubClient. + * + * @param iotHubClientHandle The handle created by a call to the create function. + * @param iotHubClientStatus The sending state is populated at the address pointed + * at by this parameter. The value will be set to + * @c IOTHUBCLIENT_SENDSTATUS_IDLE if there is currently + * no item to be sent and @c IOTHUBCLIENT_SENDSTATUS_BUSY + * if there are. + * + * @return IOTHUB_CLIENT_OK upon success or an error code upon failure. + */ + extern IOTHUB_CLIENT_RESULT IoTHubClient_Mod_GetSendStatus(IOTHUB_CLIENT_HANDLE iotHubClientHandle, IOTHUB_CLIENT_STATUS *iotHubClientStatus); + + /** + * @brief Sets up the message callback to be invoked when IoT Hub issues a + * message to the device. This is a blocking call. + * + * @param iotHubClientHandle The handle created by a call to the create function. + * @param messageCallback The callback specified by the device for receiving + * messages from IoT Hub. + * @param userContextCallback User specified context that will be provided to the + * callback. This can be @c NULL. + * + * @b NOTE: The application behavior is undefined if the user calls + * the ::IoTHubClient_Destroy function from within any callback. + * + * @return IOTHUB_CLIENT_OK upon success or an error code upon failure. + */ + extern IOTHUB_CLIENT_RESULT IoTHubClient_Mod_SetMessageCallback(IOTHUB_CLIENT_HANDLE iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC messageCallback, void* userContextCallback); + + /** + * @brief Sets up the callback to be invoked from IoT Hub worker thread. + * Can call SendAsync from here without blocking on lock. + * + * @param iotHubClientHandle The handle created by a call to the create function. + * @param sendCallback The callback specified by the device for sending + * messages to IoT Hub. + * @param userContextCallback User specified context that will be provided to the + * callback. This can be @c NULL. + * + * @b NOTE: The application behavior is undefined if the user calls + * the ::IoTHubClient_Destroy function from within any callback. + * + * @return IOTHUB_CLIENT_OK upon success or an error code upon failure. + */ + extern IOTHUB_CLIENT_RESULT IoTHubClient_Mod_SetSendCallback(IOTHUB_CLIENT_HANDLE iotHubClientHandle, IOTHUB_CLIENT_SEND_CALLBACK messageCallback, void* userContextCallback); + + /** + * @brief This function returns in the out parameter @p lastMessageReceiveTime + * what was the value of the @c time function when the last message was + * received at the client. + * + * @param iotHubClientHandle The handle created by a call to the create function. + * @param lastMessageReceiveTime Out parameter containing the value of @c time function + * when the last message was received. + * + * @return IOTHUB_CLIENT_OK upon success or an error code upon failure. + */ + extern IOTHUB_CLIENT_RESULT IoTHubClient_Mod_GetLastMessageReceiveTime(IOTHUB_CLIENT_HANDLE iotHubClientHandle, time_t* lastMessageReceiveTime); + + /** + * @brief This API sets a runtime option identified by parameter @p optionName + * to a value pointed to by @p value. @p optionName and the data type + * @p value is pointing to are specific for every option. + * + * @param iotHubClientHandle The handle created by a call to the create function. + * @param optionName Name of the option. + * @param value The value. + * + * The options that can be set via this API are: + * - @b timeout - the maximum time in milliseconds a communication is + * allowed to use. @p value is a pointer to an @c unsigned @c int with + * the timeout value in milliseconds. This is only supported for the HTTP + * protocol as of now. When the HTTP protocol uses CURL, the meaning of + * the parameter is <em>total request time</em>. When the HTTP protocol uses + * winhttp, the meaning is the same as the @c dwSendTimeout and + * @c dwReceiveTimeout parameters of the + * <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384116(v=vs.85).aspx"> + * WinHttpSetTimeouts</a> API. + * - @b CURLOPT_LOW_SPEED_LIMIT - only available for HTTP protocol and only + * when CURL is used. It has the same meaning as CURL's option with the same + * name. @p value is pointer to a long. + * - @b CURLOPT_LOW_SPEED_TIME - only available for HTTP protocol and only + * when CURL is used. It has the same meaning as CURL's option with the same + * name. @p value is pointer to a long. + * - @b CURLOPT_FORBID_REUSE - only available for HTTP protocol and only + * when CURL is used. It has the same meaning as CURL's option with the same + * name. @p value is pointer to a long. + * - @b CURLOPT_FRESH_CONNECT - only available for HTTP protocol and only + * when CURL is used. It has the same meaning as CURL's option with the same + * name. @p value is pointer to a long. + * - @b CURLOPT_VERBOSE - only available for HTTP protocol and only + * when CURL is used. It has the same meaning as CURL's option with the same + * name. @p value is pointer to a long. + * + * @return IOTHUB_CLIENT_OK upon success or an error code upon failure. + */ + extern IOTHUB_CLIENT_RESULT IoTHubClient_Mod_SetOption(IOTHUB_CLIENT_HANDLE iotHubClientHandle, const char* optionName, const void* value); + +#ifdef __cplusplus +} +#endif + +#endif /* IOTHUB_CLIENT_H */