From d930003d81d6ca94178e026f2f02e20ba712d608 Mon Sep 17 00:00:00 2001 From: Herwig Birke Date: Tue, 9 Mar 2021 16:11:58 +0100 Subject: [PATCH] initial commit --- .gitignore | 103 +- cairquality.cpp | 76 + cairquality.h | 26 + cmainwindow.cpp | 35 + cmainwindow.h | 28 + cmainwindow.ui | 22 + ctinkerforge.cpp | 21 + ctinkerforge.h | 21 + main.cpp | 11 + tinkerforge/brick_master.c | 5015 ++++++++++++++++++++++++ tinkerforge/brick_master.h | 3019 ++++++++++++++ tinkerforge/bricklet_air_quality.c | 1463 +++++++ tinkerforge/bricklet_air_quality.h | 941 +++++ tinkerforge/bricklet_outdoor_weather.c | 1083 +++++ tinkerforge/bricklet_outdoor_weather.h | 682 ++++ tinkerforge/ip_connection.c | 2695 +++++++++++++ tinkerforge/ip_connection.h | 716 ++++ weatherStation.pro | 39 + 18 files changed, 15955 insertions(+), 41 deletions(-) create mode 100644 cairquality.cpp create mode 100644 cairquality.h create mode 100644 cmainwindow.cpp create mode 100644 cmainwindow.h create mode 100644 cmainwindow.ui create mode 100644 ctinkerforge.cpp create mode 100644 ctinkerforge.h create mode 100644 main.cpp create mode 100644 tinkerforge/brick_master.c create mode 100644 tinkerforge/brick_master.h create mode 100644 tinkerforge/bricklet_air_quality.c create mode 100644 tinkerforge/bricklet_air_quality.h create mode 100644 tinkerforge/bricklet_outdoor_weather.c create mode 100644 tinkerforge/bricklet_outdoor_weather.h create mode 100644 tinkerforge/ip_connection.c create mode 100644 tinkerforge/ip_connection.h create mode 100644 weatherStation.pro diff --git a/.gitignore b/.gitignore index f147edf..fab7372 100644 --- a/.gitignore +++ b/.gitignore @@ -1,52 +1,73 @@ -# C++ objects and libs -*.slo -*.lo -*.o +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave *.a -*.la -*.lai +*.core +*.moc +*.o +*.obj +*.orig +*.rej *.so *.so.* -*.dll -*.dylib - -# Qt-es -object_script.*.Release -object_script.*.Debug -*_plugin_import.cpp +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc /.qmake.cache /.qmake.stash -*.pro.user -*.pro.user.* -*.qbs.user -*.qbs.user.* -*.moc -moc_*.cpp -moc_*.h -qrc_*.cpp -ui_*.h -*.qmlc -*.jsc -Makefile* -*build-* -*.qm -*.prl -# Qt unit tests -target_wrapper.* +# qtcreator generated files +*.pro.user* -# QtCreator -*.autosave +# xemacs temporary files +*.flc -# QtCreator Qml -*.qmlproject.user -*.qmlproject.user.* +# Vim temporary files +.*.swp -# QtCreator CMake -CMakeLists.txt.user* +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* -# QtCreator 4.8< compilation database -compile_commands.json +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe -# QtCreator local machine specific files for imported projects -*creator.user* diff --git a/cairquality.cpp b/cairquality.cpp new file mode 100644 index 0000000..bafdf7d --- /dev/null +++ b/cairquality.cpp @@ -0,0 +1,76 @@ +#include "cairquality.h" + + +cAirQuality::cAirQuality(cTinkerForge* tinkerForge, const QString& uid) : + m_tinkerForge(tinkerForge), + m_uid(uid) +{ + if(!m_tinkerForge) + return; + + air_quality_create(&m_airQuality, m_uid.toLocal8Bit().data(), m_tinkerForge->connection()); +} + +cAirQuality::~cAirQuality() +{ + air_quality_destroy(&m_airQuality); +} + +qint32 cAirQuality::iaqIndex() +{ + int32_t iaq_index; + uint8_t iaq_index_acuracy; + + if(air_quality_get_iaq_index(&m_airQuality, &iaq_index, &iaq_index_acuracy) < 0) + return(0.0); + return(iaq_index); +} + +double cAirQuality::temperature() +{ + int32_t temperature; + + if(air_quality_get_temperature(&m_airQuality, &temperature) < 0) + return(0.0); + return((double)temperature/100.0); +} + +double cAirQuality::humidity() +{ + int32_t humidity; + + if(air_quality_get_humidity(&m_airQuality, &humidity) < 0) + return(0.0); + return((double)humidity/100.0); +} + +double cAirQuality::airPressure() +{ + int32_t airPressure; + + if(air_quality_get_air_pressure(&m_airQuality, &airPressure) < 0) + return(0.0); + return((double)airPressure/100.0); +} + +QString cAirQuality::iaqIndexAccuracy() +{ + int32_t iaq_index; + uint8_t iaq_index_acuracy; + + if(air_quality_get_iaq_index(&m_airQuality, &iaq_index, &iaq_index_acuracy) < 0) + return("IAQ Index Accuracy: Unreliable"); + + switch(iaq_index_acuracy) + { + case AIR_QUALITY_ACCURACY_UNRELIABLE: + return("Unreliable"); + case AIR_QUALITY_ACCURACY_LOW: + return("Low"); + case AIR_QUALITY_ACCURACY_MEDIUM: + return("Medium"); + case AIR_QUALITY_ACCURACY_HIGH: + return("High"); + } + return("Unreliable"); +} diff --git a/cairquality.h b/cairquality.h new file mode 100644 index 0000000..4c4fc9b --- /dev/null +++ b/cairquality.h @@ -0,0 +1,26 @@ +#ifndef CAIRQUALITY_H +#define CAIRQUALITY_H + + +#include "ctinkerforge.h" +#include "tinkerforge/bricklet_air_quality.h" + + +class cAirQuality +{ +public: + cAirQuality(cTinkerForge* tinkerForge, const QString& uid); + ~cAirQuality(); + + qint32 iaqIndex(); + double temperature(); + double humidity(); + double airPressure(); + QString iaqIndexAccuracy(); +private: + cTinkerForge* m_tinkerForge; + QString m_uid; + AirQuality m_airQuality; +}; + +#endif // CAIRQUALITY_H diff --git a/cmainwindow.cpp b/cmainwindow.cpp new file mode 100644 index 0000000..a3f1020 --- /dev/null +++ b/cmainwindow.cpp @@ -0,0 +1,35 @@ +#include "cmainwindow.h" +#include "ui_cmainwindow.h" + +#include + + +cMainWindow::cMainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::cMainWindow), + m_tinkerForge(0), + m_airQuality(0) +{ + ui->setupUi(this); + + m_tinkerForge = new cTinkerForge("192.168.0.208", 4223); + m_airQuality = new cAirQuality(m_tinkerForge, "QqD"); + + qDebug() << "Temperatur: " << m_airQuality->temperature(); + qDebug() << "Luftfeuchte: " << m_airQuality->humidity(); + qDebug() << "Luftdruck: " << m_airQuality->airPressure(); + qDebug() << "Index: " << m_airQuality->iaqIndex(); + qDebug() << "Genauigkeit: " << m_airQuality->iaqIndexAccuracy(); +} + +cMainWindow::~cMainWindow() +{ + if(m_airQuality) + delete m_airQuality; + + if(m_tinkerForge) + delete m_tinkerForge; + + delete ui; +} + diff --git a/cmainwindow.h b/cmainwindow.h new file mode 100644 index 0000000..359b026 --- /dev/null +++ b/cmainwindow.h @@ -0,0 +1,28 @@ +#ifndef CMAINWINDOW_H +#define CMAINWINDOW_H + +#include + +#include "ctinkerforge.h" +#include "cairquality.h" + + +QT_BEGIN_NAMESPACE +namespace Ui { class cMainWindow; } +QT_END_NAMESPACE + +class cMainWindow : public QMainWindow +{ + Q_OBJECT + +public: + cMainWindow(QWidget *parent = nullptr); + ~cMainWindow(); + +private: + Ui::cMainWindow *ui; + + cTinkerForge* m_tinkerForge; + cAirQuality* m_airQuality; +}; +#endif // CMAINWINDOW_H diff --git a/cmainwindow.ui b/cmainwindow.ui new file mode 100644 index 0000000..7dddbe4 --- /dev/null +++ b/cmainwindow.ui @@ -0,0 +1,22 @@ + + + cMainWindow + + + + 0 + 0 + 800 + 600 + + + + cMainWindow + + + + + + + + diff --git a/ctinkerforge.cpp b/ctinkerforge.cpp new file mode 100644 index 0000000..9f75301 --- /dev/null +++ b/ctinkerforge.cpp @@ -0,0 +1,21 @@ +#include "ctinkerforge.h" + + +cTinkerForge::cTinkerForge(const QString& host, const int& port) +{ + ipcon_create(&m_ipConnection); + + if(ipcon_connect(&m_ipConnection, host.toLocal8Bit().data(), port) < 0) + return; + +} + +cTinkerForge::~cTinkerForge() +{ + ipcon_destroy(&m_ipConnection); +} + +IPConnection* cTinkerForge::connection() +{ + return(&m_ipConnection); +} diff --git a/ctinkerforge.h b/ctinkerforge.h new file mode 100644 index 0000000..60ef466 --- /dev/null +++ b/ctinkerforge.h @@ -0,0 +1,21 @@ +#ifndef CTINKERFORGE_H +#define CTINKERFORGE_H + + +#include "tinkerforge/ip_connection.h" + +#include + + +class cTinkerForge +{ +public: + cTinkerForge(const QString& host, const int &port); + ~cTinkerForge(); + + IPConnection* connection(); +private: + IPConnection m_ipConnection; +}; + +#endif // CTINKERFORGE_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..025da0a --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include "cmainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + cMainWindow w; + w.show(); + return a.exec(); +} diff --git a/tinkerforge/brick_master.c b/tinkerforge/brick_master.c new file mode 100644 index 0000000..7a47bf0 --- /dev/null +++ b/tinkerforge/brick_master.c @@ -0,0 +1,5015 @@ +/* *********************************************************** + * This file was automatically generated on 2021-01-15. * + * * + * C/C++ Bindings Version 2.1.31 * + * * + * If you have a bugfix for this file and want to commit it, * + * please fix the bug in the generator. You can find a link * + * to the generators git repository on tinkerforge.com * + *************************************************************/ + + +#define IPCON_EXPOSE_INTERNALS + +#include "brick_master.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +typedef void (*StackCurrent_CallbackFunction)(uint16_t current, void *user_data); + +typedef void (*StackVoltage_CallbackFunction)(uint16_t voltage, void *user_data); + +typedef void (*USBVoltage_CallbackFunction)(uint16_t voltage, void *user_data); + +typedef void (*StackCurrentReached_CallbackFunction)(uint16_t current, void *user_data); + +typedef void (*StackVoltageReached_CallbackFunction)(uint16_t voltage, void *user_data); + +typedef void (*USBVoltageReached_CallbackFunction)(uint16_t voltage, void *user_data); + +#if defined _MSC_VER || defined __BORLANDC__ + #pragma pack(push) + #pragma pack(1) + #define ATTRIBUTE_PACKED +#elif defined __GNUC__ + #ifdef _WIN32 + // workaround struct packing bug in GCC 4.7 on Windows + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 + #define ATTRIBUTE_PACKED __attribute__((gcc_struct, packed)) + #else + #define ATTRIBUTE_PACKED __attribute__((packed)) + #endif +#else + #error unknown compiler, do not know how to enable struct packing +#endif + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetStackVoltage_Request; + +typedef struct { + PacketHeader header; + uint16_t voltage; +} ATTRIBUTE_PACKED GetStackVoltage_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetStackCurrent_Request; + +typedef struct { + PacketHeader header; + uint16_t current; +} ATTRIBUTE_PACKED GetStackCurrent_Response; + +typedef struct { + PacketHeader header; + uint8_t extension; + uint32_t exttype; +} ATTRIBUTE_PACKED SetExtensionType_Request; + +typedef struct { + PacketHeader header; + uint8_t extension; +} ATTRIBUTE_PACKED GetExtensionType_Request; + +typedef struct { + PacketHeader header; + uint32_t exttype; +} ATTRIBUTE_PACKED GetExtensionType_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED IsChibiPresent_Request; + +typedef struct { + PacketHeader header; + uint8_t present; +} ATTRIBUTE_PACKED IsChibiPresent_Response; + +typedef struct { + PacketHeader header; + uint8_t address; +} ATTRIBUTE_PACKED SetChibiAddress_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetChibiAddress_Request; + +typedef struct { + PacketHeader header; + uint8_t address; +} ATTRIBUTE_PACKED GetChibiAddress_Response; + +typedef struct { + PacketHeader header; + uint8_t address; +} ATTRIBUTE_PACKED SetChibiMasterAddress_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetChibiMasterAddress_Request; + +typedef struct { + PacketHeader header; + uint8_t address; +} ATTRIBUTE_PACKED GetChibiMasterAddress_Response; + +typedef struct { + PacketHeader header; + uint8_t num; + uint8_t address; +} ATTRIBUTE_PACKED SetChibiSlaveAddress_Request; + +typedef struct { + PacketHeader header; + uint8_t num; +} ATTRIBUTE_PACKED GetChibiSlaveAddress_Request; + +typedef struct { + PacketHeader header; + uint8_t address; +} ATTRIBUTE_PACKED GetChibiSlaveAddress_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetChibiSignalStrength_Request; + +typedef struct { + PacketHeader header; + uint8_t signal_strength; +} ATTRIBUTE_PACKED GetChibiSignalStrength_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetChibiErrorLog_Request; + +typedef struct { + PacketHeader header; + uint16_t underrun; + uint16_t crc_error; + uint16_t no_ack; + uint16_t overflow; +} ATTRIBUTE_PACKED GetChibiErrorLog_Response; + +typedef struct { + PacketHeader header; + uint8_t frequency; +} ATTRIBUTE_PACKED SetChibiFrequency_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetChibiFrequency_Request; + +typedef struct { + PacketHeader header; + uint8_t frequency; +} ATTRIBUTE_PACKED GetChibiFrequency_Response; + +typedef struct { + PacketHeader header; + uint8_t channel; +} ATTRIBUTE_PACKED SetChibiChannel_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetChibiChannel_Request; + +typedef struct { + PacketHeader header; + uint8_t channel; +} ATTRIBUTE_PACKED GetChibiChannel_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED IsRS485Present_Request; + +typedef struct { + PacketHeader header; + uint8_t present; +} ATTRIBUTE_PACKED IsRS485Present_Response; + +typedef struct { + PacketHeader header; + uint8_t address; +} ATTRIBUTE_PACKED SetRS485Address_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetRS485Address_Request; + +typedef struct { + PacketHeader header; + uint8_t address; +} ATTRIBUTE_PACKED GetRS485Address_Response; + +typedef struct { + PacketHeader header; + uint8_t num; + uint8_t address; +} ATTRIBUTE_PACKED SetRS485SlaveAddress_Request; + +typedef struct { + PacketHeader header; + uint8_t num; +} ATTRIBUTE_PACKED GetRS485SlaveAddress_Request; + +typedef struct { + PacketHeader header; + uint8_t address; +} ATTRIBUTE_PACKED GetRS485SlaveAddress_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetRS485ErrorLog_Request; + +typedef struct { + PacketHeader header; + uint16_t crc_error; +} ATTRIBUTE_PACKED GetRS485ErrorLog_Response; + +typedef struct { + PacketHeader header; + uint32_t speed; + char parity; + uint8_t stopbits; +} ATTRIBUTE_PACKED SetRS485Configuration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetRS485Configuration_Request; + +typedef struct { + PacketHeader header; + uint32_t speed; + char parity; + uint8_t stopbits; +} ATTRIBUTE_PACKED GetRS485Configuration_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED IsWifiPresent_Request; + +typedef struct { + PacketHeader header; + uint8_t present; +} ATTRIBUTE_PACKED IsWifiPresent_Response; + +typedef struct { + PacketHeader header; + char ssid[32]; + uint8_t connection; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint16_t port; +} ATTRIBUTE_PACKED SetWifiConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifiConfiguration_Request; + +typedef struct { + PacketHeader header; + char ssid[32]; + uint8_t connection; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint16_t port; +} ATTRIBUTE_PACKED GetWifiConfiguration_Response; + +typedef struct { + PacketHeader header; + uint8_t encryption; + char key[50]; + uint8_t key_index; + uint8_t eap_options; + uint16_t ca_certificate_length; + uint16_t client_certificate_length; + uint16_t private_key_length; +} ATTRIBUTE_PACKED SetWifiEncryption_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifiEncryption_Request; + +typedef struct { + PacketHeader header; + uint8_t encryption; + char key[50]; + uint8_t key_index; + uint8_t eap_options; + uint16_t ca_certificate_length; + uint16_t client_certificate_length; + uint16_t private_key_length; +} ATTRIBUTE_PACKED GetWifiEncryption_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifiStatus_Request; + +typedef struct { + PacketHeader header; + uint8_t mac_address[6]; + uint8_t bssid[6]; + uint8_t channel; + int16_t rssi; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint32_t rx_count; + uint32_t tx_count; + uint8_t state; +} ATTRIBUTE_PACKED GetWifiStatus_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED RefreshWifiStatus_Request; + +typedef struct { + PacketHeader header; + uint16_t index; + uint8_t data[32]; + uint8_t data_length; +} ATTRIBUTE_PACKED SetWifiCertificate_Request; + +typedef struct { + PacketHeader header; + uint16_t index; +} ATTRIBUTE_PACKED GetWifiCertificate_Request; + +typedef struct { + PacketHeader header; + uint8_t data[32]; + uint8_t data_length; +} ATTRIBUTE_PACKED GetWifiCertificate_Response; + +typedef struct { + PacketHeader header; + uint8_t mode; +} ATTRIBUTE_PACKED SetWifiPowerMode_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifiPowerMode_Request; + +typedef struct { + PacketHeader header; + uint8_t mode; +} ATTRIBUTE_PACKED GetWifiPowerMode_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifiBufferInfo_Request; + +typedef struct { + PacketHeader header; + uint32_t overflow; + uint16_t low_watermark; + uint16_t used; +} ATTRIBUTE_PACKED GetWifiBufferInfo_Response; + +typedef struct { + PacketHeader header; + uint8_t domain; +} ATTRIBUTE_PACKED SetWifiRegulatoryDomain_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifiRegulatoryDomain_Request; + +typedef struct { + PacketHeader header; + uint8_t domain; +} ATTRIBUTE_PACKED GetWifiRegulatoryDomain_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetUSBVoltage_Request; + +typedef struct { + PacketHeader header; + uint16_t voltage; +} ATTRIBUTE_PACKED GetUSBVoltage_Response; + +typedef struct { + PacketHeader header; + char key[64]; +} ATTRIBUTE_PACKED SetLongWifiKey_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetLongWifiKey_Request; + +typedef struct { + PacketHeader header; + char key[64]; +} ATTRIBUTE_PACKED GetLongWifiKey_Response; + +typedef struct { + PacketHeader header; + char hostname[16]; +} ATTRIBUTE_PACKED SetWifiHostname_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifiHostname_Request; + +typedef struct { + PacketHeader header; + char hostname[16]; +} ATTRIBUTE_PACKED GetWifiHostname_Response; + +typedef struct { + PacketHeader header; + uint32_t period; +} ATTRIBUTE_PACKED SetStackCurrentCallbackPeriod_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetStackCurrentCallbackPeriod_Request; + +typedef struct { + PacketHeader header; + uint32_t period; +} ATTRIBUTE_PACKED GetStackCurrentCallbackPeriod_Response; + +typedef struct { + PacketHeader header; + uint32_t period; +} ATTRIBUTE_PACKED SetStackVoltageCallbackPeriod_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetStackVoltageCallbackPeriod_Request; + +typedef struct { + PacketHeader header; + uint32_t period; +} ATTRIBUTE_PACKED GetStackVoltageCallbackPeriod_Response; + +typedef struct { + PacketHeader header; + uint32_t period; +} ATTRIBUTE_PACKED SetUSBVoltageCallbackPeriod_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetUSBVoltageCallbackPeriod_Request; + +typedef struct { + PacketHeader header; + uint32_t period; +} ATTRIBUTE_PACKED GetUSBVoltageCallbackPeriod_Response; + +typedef struct { + PacketHeader header; + char option; + uint16_t min; + uint16_t max; +} ATTRIBUTE_PACKED SetStackCurrentCallbackThreshold_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetStackCurrentCallbackThreshold_Request; + +typedef struct { + PacketHeader header; + char option; + uint16_t min; + uint16_t max; +} ATTRIBUTE_PACKED GetStackCurrentCallbackThreshold_Response; + +typedef struct { + PacketHeader header; + char option; + uint16_t min; + uint16_t max; +} ATTRIBUTE_PACKED SetStackVoltageCallbackThreshold_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetStackVoltageCallbackThreshold_Request; + +typedef struct { + PacketHeader header; + char option; + uint16_t min; + uint16_t max; +} ATTRIBUTE_PACKED GetStackVoltageCallbackThreshold_Response; + +typedef struct { + PacketHeader header; + char option; + uint16_t min; + uint16_t max; +} ATTRIBUTE_PACKED SetUSBVoltageCallbackThreshold_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetUSBVoltageCallbackThreshold_Request; + +typedef struct { + PacketHeader header; + char option; + uint16_t min; + uint16_t max; +} ATTRIBUTE_PACKED GetUSBVoltageCallbackThreshold_Response; + +typedef struct { + PacketHeader header; + uint32_t debounce; +} ATTRIBUTE_PACKED SetDebouncePeriod_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetDebouncePeriod_Request; + +typedef struct { + PacketHeader header; + uint32_t debounce; +} ATTRIBUTE_PACKED GetDebouncePeriod_Response; + +typedef struct { + PacketHeader header; + uint16_t current; +} ATTRIBUTE_PACKED StackCurrent_Callback; + +typedef struct { + PacketHeader header; + uint16_t voltage; +} ATTRIBUTE_PACKED StackVoltage_Callback; + +typedef struct { + PacketHeader header; + uint16_t voltage; +} ATTRIBUTE_PACKED USBVoltage_Callback; + +typedef struct { + PacketHeader header; + uint16_t current; +} ATTRIBUTE_PACKED StackCurrentReached_Callback; + +typedef struct { + PacketHeader header; + uint16_t voltage; +} ATTRIBUTE_PACKED StackVoltageReached_Callback; + +typedef struct { + PacketHeader header; + uint16_t voltage; +} ATTRIBUTE_PACKED USBVoltageReached_Callback; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED IsEthernetPresent_Request; + +typedef struct { + PacketHeader header; + uint8_t present; +} ATTRIBUTE_PACKED IsEthernetPresent_Response; + +typedef struct { + PacketHeader header; + uint8_t connection; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint16_t port; +} ATTRIBUTE_PACKED SetEthernetConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetEthernetConfiguration_Request; + +typedef struct { + PacketHeader header; + uint8_t connection; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint16_t port; +} ATTRIBUTE_PACKED GetEthernetConfiguration_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetEthernetStatus_Request; + +typedef struct { + PacketHeader header; + uint8_t mac_address[6]; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint32_t rx_count; + uint32_t tx_count; + char hostname[32]; +} ATTRIBUTE_PACKED GetEthernetStatus_Response; + +typedef struct { + PacketHeader header; + char hostname[32]; +} ATTRIBUTE_PACKED SetEthernetHostname_Request; + +typedef struct { + PacketHeader header; + uint8_t mac_address[6]; +} ATTRIBUTE_PACKED SetEthernetMACAddress_Request; + +typedef struct { + PacketHeader header; + uint8_t sockets; + uint16_t port; +} ATTRIBUTE_PACKED SetEthernetWebsocketConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetEthernetWebsocketConfiguration_Request; + +typedef struct { + PacketHeader header; + uint8_t sockets; + uint16_t port; +} ATTRIBUTE_PACKED GetEthernetWebsocketConfiguration_Response; + +typedef struct { + PacketHeader header; + char secret[64]; +} ATTRIBUTE_PACKED SetEthernetAuthenticationSecret_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetEthernetAuthenticationSecret_Request; + +typedef struct { + PacketHeader header; + char secret[64]; +} ATTRIBUTE_PACKED GetEthernetAuthenticationSecret_Response; + +typedef struct { + PacketHeader header; + char secret[64]; +} ATTRIBUTE_PACKED SetWifiAuthenticationSecret_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifiAuthenticationSecret_Request; + +typedef struct { + PacketHeader header; + char secret[64]; +} ATTRIBUTE_PACKED GetWifiAuthenticationSecret_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetConnectionType_Request; + +typedef struct { + PacketHeader header; + uint8_t connection_type; +} ATTRIBUTE_PACKED GetConnectionType_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED IsWifi2Present_Request; + +typedef struct { + PacketHeader header; + uint8_t present; +} ATTRIBUTE_PACKED IsWifi2Present_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED StartWifi2Bootloader_Request; + +typedef struct { + PacketHeader header; + int8_t result; +} ATTRIBUTE_PACKED StartWifi2Bootloader_Response; + +typedef struct { + PacketHeader header; + uint8_t data[60]; + uint8_t length; +} ATTRIBUTE_PACKED WriteWifi2SerialPort_Request; + +typedef struct { + PacketHeader header; + int8_t result; +} ATTRIBUTE_PACKED WriteWifi2SerialPort_Response; + +typedef struct { + PacketHeader header; + uint8_t length; +} ATTRIBUTE_PACKED ReadWifi2SerialPort_Request; + +typedef struct { + PacketHeader header; + uint8_t data[60]; + uint8_t result; +} ATTRIBUTE_PACKED ReadWifi2SerialPort_Response; + +typedef struct { + PacketHeader header; + char secret[64]; +} ATTRIBUTE_PACKED SetWifi2AuthenticationSecret_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2AuthenticationSecret_Request; + +typedef struct { + PacketHeader header; + char secret[64]; +} ATTRIBUTE_PACKED GetWifi2AuthenticationSecret_Response; + +typedef struct { + PacketHeader header; + uint16_t port; + uint16_t websocket_port; + uint16_t website_port; + uint8_t phy_mode; + uint8_t sleep_mode; + uint8_t website; +} ATTRIBUTE_PACKED SetWifi2Configuration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2Configuration_Request; + +typedef struct { + PacketHeader header; + uint16_t port; + uint16_t websocket_port; + uint16_t website_port; + uint8_t phy_mode; + uint8_t sleep_mode; + uint8_t website; +} ATTRIBUTE_PACKED GetWifi2Configuration_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2Status_Request; + +typedef struct { + PacketHeader header; + uint8_t client_enabled; + uint8_t client_status; + uint8_t client_ip[4]; + uint8_t client_subnet_mask[4]; + uint8_t client_gateway[4]; + uint8_t client_mac_address[6]; + uint32_t client_rx_count; + uint32_t client_tx_count; + int8_t client_rssi; + uint8_t ap_enabled; + uint8_t ap_ip[4]; + uint8_t ap_subnet_mask[4]; + uint8_t ap_gateway[4]; + uint8_t ap_mac_address[6]; + uint32_t ap_rx_count; + uint32_t ap_tx_count; + uint8_t ap_connected_count; +} ATTRIBUTE_PACKED GetWifi2Status_Response; + +typedef struct { + PacketHeader header; + uint8_t enable; + char ssid[32]; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint8_t mac_address[6]; + uint8_t bssid[6]; +} ATTRIBUTE_PACKED SetWifi2ClientConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2ClientConfiguration_Request; + +typedef struct { + PacketHeader header; + uint8_t enable; + char ssid[32]; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint8_t mac_address[6]; + uint8_t bssid[6]; +} ATTRIBUTE_PACKED GetWifi2ClientConfiguration_Response; + +typedef struct { + PacketHeader header; + char hostname[32]; +} ATTRIBUTE_PACKED SetWifi2ClientHostname_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2ClientHostname_Request; + +typedef struct { + PacketHeader header; + char hostname[32]; +} ATTRIBUTE_PACKED GetWifi2ClientHostname_Response; + +typedef struct { + PacketHeader header; + char password[64]; +} ATTRIBUTE_PACKED SetWifi2ClientPassword_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2ClientPassword_Request; + +typedef struct { + PacketHeader header; + char password[64]; +} ATTRIBUTE_PACKED GetWifi2ClientPassword_Response; + +typedef struct { + PacketHeader header; + uint8_t enable; + char ssid[32]; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint8_t encryption; + uint8_t hidden; + uint8_t channel; + uint8_t mac_address[6]; +} ATTRIBUTE_PACKED SetWifi2APConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2APConfiguration_Request; + +typedef struct { + PacketHeader header; + uint8_t enable; + char ssid[32]; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint8_t encryption; + uint8_t hidden; + uint8_t channel; + uint8_t mac_address[6]; +} ATTRIBUTE_PACKED GetWifi2APConfiguration_Response; + +typedef struct { + PacketHeader header; + char password[64]; +} ATTRIBUTE_PACKED SetWifi2APPassword_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2APPassword_Request; + +typedef struct { + PacketHeader header; + char password[64]; +} ATTRIBUTE_PACKED GetWifi2APPassword_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED SaveWifi2Configuration_Request; + +typedef struct { + PacketHeader header; + uint8_t result; +} ATTRIBUTE_PACKED SaveWifi2Configuration_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2FirmwareVersion_Request; + +typedef struct { + PacketHeader header; + uint8_t firmware_version[3]; +} ATTRIBUTE_PACKED GetWifi2FirmwareVersion_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED EnableWifi2StatusLED_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED DisableWifi2StatusLED_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED IsWifi2StatusLEDEnabled_Request; + +typedef struct { + PacketHeader header; + uint8_t enabled; +} ATTRIBUTE_PACKED IsWifi2StatusLEDEnabled_Response; + +typedef struct { + PacketHeader header; + uint8_t enable; + uint8_t root_ip[4]; + uint8_t root_subnet_mask[4]; + uint8_t root_gateway[4]; + uint8_t router_bssid[6]; + uint8_t group_id[6]; + char group_ssid_prefix[16]; + uint8_t gateway_ip[4]; + uint16_t gateway_port; +} ATTRIBUTE_PACKED SetWifi2MeshConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2MeshConfiguration_Request; + +typedef struct { + PacketHeader header; + uint8_t enable; + uint8_t root_ip[4]; + uint8_t root_subnet_mask[4]; + uint8_t root_gateway[4]; + uint8_t router_bssid[6]; + uint8_t group_id[6]; + char group_ssid_prefix[16]; + uint8_t gateway_ip[4]; + uint16_t gateway_port; +} ATTRIBUTE_PACKED GetWifi2MeshConfiguration_Response; + +typedef struct { + PacketHeader header; + char ssid[32]; +} ATTRIBUTE_PACKED SetWifi2MeshRouterSSID_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2MeshRouterSSID_Request; + +typedef struct { + PacketHeader header; + char ssid[32]; +} ATTRIBUTE_PACKED GetWifi2MeshRouterSSID_Response; + +typedef struct { + PacketHeader header; + char password[64]; +} ATTRIBUTE_PACKED SetWifi2MeshRouterPassword_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2MeshRouterPassword_Request; + +typedef struct { + PacketHeader header; + char password[64]; +} ATTRIBUTE_PACKED GetWifi2MeshRouterPassword_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2MeshCommonStatus_Request; + +typedef struct { + PacketHeader header; + uint8_t status; + uint8_t root_node; + uint8_t root_candidate; + uint16_t connected_nodes; + uint32_t rx_count; + uint32_t tx_count; +} ATTRIBUTE_PACKED GetWifi2MeshCommonStatus_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2MeshClientStatus_Request; + +typedef struct { + PacketHeader header; + char hostname[32]; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint8_t mac_address[6]; +} ATTRIBUTE_PACKED GetWifi2MeshClientStatus_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetWifi2MeshAPStatus_Request; + +typedef struct { + PacketHeader header; + char ssid[32]; + uint8_t ip[4]; + uint8_t subnet_mask[4]; + uint8_t gateway[4]; + uint8_t mac_address[6]; +} ATTRIBUTE_PACKED GetWifi2MeshAPStatus_Response; + +typedef struct { + PacketHeader header; + uint32_t config; + uint32_t parameter1; + uint32_t parameter2; + uint8_t data[52]; +} ATTRIBUTE_PACKED SetBrickletXMCFlashConfig_Request; + +typedef struct { + PacketHeader header; + uint32_t return_value; + uint8_t return_data[60]; +} ATTRIBUTE_PACKED SetBrickletXMCFlashConfig_Response; + +typedef struct { + PacketHeader header; + uint8_t data[64]; +} ATTRIBUTE_PACKED SetBrickletXMCFlashData_Request; + +typedef struct { + PacketHeader header; + uint32_t return_data; +} ATTRIBUTE_PACKED SetBrickletXMCFlashData_Response; + +typedef struct { + PacketHeader header; + uint8_t bricklets_enabled; +} ATTRIBUTE_PACKED SetBrickletsEnabled_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetBrickletsEnabled_Request; + +typedef struct { + PacketHeader header; + uint8_t bricklets_enabled; +} ATTRIBUTE_PACKED GetBrickletsEnabled_Response; + +typedef struct { + PacketHeader header; + uint8_t enable_dynamic_baudrate; + uint32_t minimum_dynamic_baudrate; +} ATTRIBUTE_PACKED SetSPITFPBaudrateConfig_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetSPITFPBaudrateConfig_Request; + +typedef struct { + PacketHeader header; + uint8_t enable_dynamic_baudrate; + uint32_t minimum_dynamic_baudrate; +} ATTRIBUTE_PACKED GetSPITFPBaudrateConfig_Response; + +typedef struct { + PacketHeader header; + uint8_t communication_method; +} ATTRIBUTE_PACKED GetSendTimeoutCount_Request; + +typedef struct { + PacketHeader header; + uint32_t timeout_count; +} ATTRIBUTE_PACKED GetSendTimeoutCount_Response; + +typedef struct { + PacketHeader header; + char bricklet_port; + uint32_t baudrate; +} ATTRIBUTE_PACKED SetSPITFPBaudrate_Request; + +typedef struct { + PacketHeader header; + char bricklet_port; +} ATTRIBUTE_PACKED GetSPITFPBaudrate_Request; + +typedef struct { + PacketHeader header; + uint32_t baudrate; +} ATTRIBUTE_PACKED GetSPITFPBaudrate_Response; + +typedef struct { + PacketHeader header; + char bricklet_port; +} ATTRIBUTE_PACKED GetSPITFPErrorCount_Request; + +typedef struct { + PacketHeader header; + uint32_t error_count_ack_checksum; + uint32_t error_count_message_checksum; + uint32_t error_count_frame; + uint32_t error_count_overflow; +} ATTRIBUTE_PACKED GetSPITFPErrorCount_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED EnableStatusLED_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED DisableStatusLED_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED IsStatusLEDEnabled_Request; + +typedef struct { + PacketHeader header; + uint8_t enabled; +} ATTRIBUTE_PACKED IsStatusLEDEnabled_Response; + +typedef struct { + PacketHeader header; + char port; +} ATTRIBUTE_PACKED GetProtocol1BrickletName_Request; + +typedef struct { + PacketHeader header; + uint8_t protocol_version; + uint8_t firmware_version[3]; + char name[40]; +} ATTRIBUTE_PACKED GetProtocol1BrickletName_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetChipTemperature_Request; + +typedef struct { + PacketHeader header; + int16_t temperature; +} ATTRIBUTE_PACKED GetChipTemperature_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED Reset_Request; + +typedef struct { + PacketHeader header; + char port; + uint8_t offset; + uint8_t chunk[32]; +} ATTRIBUTE_PACKED WriteBrickletPlugin_Request; + +typedef struct { + PacketHeader header; + char port; + uint8_t offset; +} ATTRIBUTE_PACKED ReadBrickletPlugin_Request; + +typedef struct { + PacketHeader header; + uint8_t chunk[32]; +} ATTRIBUTE_PACKED ReadBrickletPlugin_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetIdentity_Request; + +typedef struct { + PacketHeader header; + char uid[8]; + char connected_uid[8]; + char position; + uint8_t hardware_version[3]; + uint8_t firmware_version[3]; + uint16_t device_identifier; +} ATTRIBUTE_PACKED GetIdentity_Response; + +#if defined _MSC_VER || defined __BORLANDC__ + #pragma pack(pop) +#endif +#undef ATTRIBUTE_PACKED + +static void master_callback_wrapper_stack_current(DevicePrivate *device_p, Packet *packet) { + StackCurrent_CallbackFunction callback_function; + void *user_data; + StackCurrent_Callback *callback; + + if (packet->header.length != sizeof(StackCurrent_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (StackCurrent_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_STACK_CURRENT]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_STACK_CURRENT]; + callback = (StackCurrent_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->current = leconvert_uint16_from(callback->current); + + callback_function(callback->current, user_data); +} + +static void master_callback_wrapper_stack_voltage(DevicePrivate *device_p, Packet *packet) { + StackVoltage_CallbackFunction callback_function; + void *user_data; + StackVoltage_Callback *callback; + + if (packet->header.length != sizeof(StackVoltage_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (StackVoltage_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_STACK_VOLTAGE]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_STACK_VOLTAGE]; + callback = (StackVoltage_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->voltage = leconvert_uint16_from(callback->voltage); + + callback_function(callback->voltage, user_data); +} + +static void master_callback_wrapper_usb_voltage(DevicePrivate *device_p, Packet *packet) { + USBVoltage_CallbackFunction callback_function; + void *user_data; + USBVoltage_Callback *callback; + + if (packet->header.length != sizeof(USBVoltage_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (USBVoltage_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_USB_VOLTAGE]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_USB_VOLTAGE]; + callback = (USBVoltage_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->voltage = leconvert_uint16_from(callback->voltage); + + callback_function(callback->voltage, user_data); +} + +static void master_callback_wrapper_stack_current_reached(DevicePrivate *device_p, Packet *packet) { + StackCurrentReached_CallbackFunction callback_function; + void *user_data; + StackCurrentReached_Callback *callback; + + if (packet->header.length != sizeof(StackCurrentReached_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (StackCurrentReached_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_STACK_CURRENT_REACHED]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_STACK_CURRENT_REACHED]; + callback = (StackCurrentReached_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->current = leconvert_uint16_from(callback->current); + + callback_function(callback->current, user_data); +} + +static void master_callback_wrapper_stack_voltage_reached(DevicePrivate *device_p, Packet *packet) { + StackVoltageReached_CallbackFunction callback_function; + void *user_data; + StackVoltageReached_Callback *callback; + + if (packet->header.length != sizeof(StackVoltageReached_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (StackVoltageReached_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_STACK_VOLTAGE_REACHED]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_STACK_VOLTAGE_REACHED]; + callback = (StackVoltageReached_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->voltage = leconvert_uint16_from(callback->voltage); + + callback_function(callback->voltage, user_data); +} + +static void master_callback_wrapper_usb_voltage_reached(DevicePrivate *device_p, Packet *packet) { + USBVoltageReached_CallbackFunction callback_function; + void *user_data; + USBVoltageReached_Callback *callback; + + if (packet->header.length != sizeof(USBVoltageReached_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (USBVoltageReached_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_USB_VOLTAGE_REACHED]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + MASTER_CALLBACK_USB_VOLTAGE_REACHED]; + callback = (USBVoltageReached_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->voltage = leconvert_uint16_from(callback->voltage); + + callback_function(callback->voltage, user_data); +} + +void master_create(Master *master, const char *uid, IPConnection *ipcon) { + IPConnectionPrivate *ipcon_p = ipcon->p; + DevicePrivate *device_p; + + device_create(master, uid, ipcon_p, 2, 0, 10, MASTER_DEVICE_IDENTIFIER); + + device_p = master->p; + + device_p->response_expected[MASTER_FUNCTION_GET_STACK_VOLTAGE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_STACK_CURRENT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_EXTENSION_TYPE] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_EXTENSION_TYPE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_IS_CHIBI_PRESENT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_CHIBI_ADDRESS] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_CHIBI_ADDRESS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_CHIBI_MASTER_ADDRESS] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_CHIBI_MASTER_ADDRESS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_CHIBI_SLAVE_ADDRESS] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_CHIBI_SLAVE_ADDRESS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_CHIBI_SIGNAL_STRENGTH] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_CHIBI_ERROR_LOG] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_CHIBI_FREQUENCY] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_CHIBI_FREQUENCY] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_CHIBI_CHANNEL] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_CHIBI_CHANNEL] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_IS_RS485_PRESENT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_RS485_ADDRESS] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_RS485_ADDRESS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_RS485_SLAVE_ADDRESS] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_RS485_SLAVE_ADDRESS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_RS485_ERROR_LOG] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_RS485_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_RS485_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_IS_WIFI_PRESENT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI_ENCRYPTION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI_ENCRYPTION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI_STATUS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_REFRESH_WIFI_STATUS] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI_CERTIFICATE] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI_CERTIFICATE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI_POWER_MODE] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI_POWER_MODE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI_BUFFER_INFO] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI_REGULATORY_DOMAIN] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI_REGULATORY_DOMAIN] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_USB_VOLTAGE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_LONG_WIFI_KEY] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_LONG_WIFI_KEY] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI_HOSTNAME] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI_HOSTNAME] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_STACK_CURRENT_CALLBACK_PERIOD] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_STACK_CURRENT_CALLBACK_PERIOD] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_STACK_VOLTAGE_CALLBACK_PERIOD] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_STACK_VOLTAGE_CALLBACK_PERIOD] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_USB_VOLTAGE_CALLBACK_PERIOD] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_USB_VOLTAGE_CALLBACK_PERIOD] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_STACK_CURRENT_CALLBACK_THRESHOLD] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_STACK_CURRENT_CALLBACK_THRESHOLD] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_STACK_VOLTAGE_CALLBACK_THRESHOLD] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_STACK_VOLTAGE_CALLBACK_THRESHOLD] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_USB_VOLTAGE_CALLBACK_THRESHOLD] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_USB_VOLTAGE_CALLBACK_THRESHOLD] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_DEBOUNCE_PERIOD] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_DEBOUNCE_PERIOD] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_IS_ETHERNET_PRESENT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_ETHERNET_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_ETHERNET_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_ETHERNET_STATUS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_ETHERNET_HOSTNAME] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_SET_ETHERNET_MAC_ADDRESS] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_SET_ETHERNET_WEBSOCKET_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_ETHERNET_WEBSOCKET_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_ETHERNET_AUTHENTICATION_SECRET] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_ETHERNET_AUTHENTICATION_SECRET] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI_AUTHENTICATION_SECRET] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI_AUTHENTICATION_SECRET] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_CONNECTION_TYPE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_IS_WIFI2_PRESENT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_START_WIFI2_BOOTLOADER] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_WRITE_WIFI2_SERIAL_PORT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_READ_WIFI2_SERIAL_PORT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI2_AUTHENTICATION_SECRET] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_AUTHENTICATION_SECRET] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI2_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_STATUS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI2_CLIENT_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_CLIENT_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI2_CLIENT_HOSTNAME] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_CLIENT_HOSTNAME] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI2_CLIENT_PASSWORD] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_CLIENT_PASSWORD] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI2_AP_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_AP_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI2_AP_PASSWORD] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_AP_PASSWORD] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SAVE_WIFI2_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_FIRMWARE_VERSION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_ENABLE_WIFI2_STATUS_LED] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_DISABLE_WIFI2_STATUS_LED] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_IS_WIFI2_STATUS_LED_ENABLED] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI2_MESH_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_MESH_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI2_MESH_ROUTER_SSID] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_MESH_ROUTER_SSID] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_WIFI2_MESH_ROUTER_PASSWORD] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_MESH_ROUTER_PASSWORD] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_MESH_COMMON_STATUS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_MESH_CLIENT_STATUS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_WIFI2_MESH_AP_STATUS] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_BRICKLET_XMC_FLASH_CONFIG] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_BRICKLET_XMC_FLASH_DATA] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_BRICKLETS_ENABLED] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_BRICKLETS_ENABLED] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_SPITFP_BAUDRATE_CONFIG] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_SPITFP_BAUDRATE_CONFIG] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_SEND_TIMEOUT_COUNT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_SET_SPITFP_BAUDRATE] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_GET_SPITFP_BAUDRATE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_SPITFP_ERROR_COUNT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_ENABLE_STATUS_LED] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_DISABLE_STATUS_LED] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_IS_STATUS_LED_ENABLED] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_PROTOCOL1_BRICKLET_NAME] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_CHIP_TEMPERATURE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_RESET] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_WRITE_BRICKLET_PLUGIN] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[MASTER_FUNCTION_READ_BRICKLET_PLUGIN] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[MASTER_FUNCTION_GET_IDENTITY] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + + device_p->callback_wrappers[MASTER_CALLBACK_STACK_CURRENT] = master_callback_wrapper_stack_current; + device_p->callback_wrappers[MASTER_CALLBACK_STACK_VOLTAGE] = master_callback_wrapper_stack_voltage; + device_p->callback_wrappers[MASTER_CALLBACK_USB_VOLTAGE] = master_callback_wrapper_usb_voltage; + device_p->callback_wrappers[MASTER_CALLBACK_STACK_CURRENT_REACHED] = master_callback_wrapper_stack_current_reached; + device_p->callback_wrappers[MASTER_CALLBACK_STACK_VOLTAGE_REACHED] = master_callback_wrapper_stack_voltage_reached; + device_p->callback_wrappers[MASTER_CALLBACK_USB_VOLTAGE_REACHED] = master_callback_wrapper_usb_voltage_reached; + + ipcon_add_device(ipcon_p, device_p); +} + +void master_destroy(Master *master) { + device_release(master->p); +} + +int master_get_response_expected(Master *master, uint8_t function_id, bool *ret_response_expected) { + return device_get_response_expected(master->p, function_id, ret_response_expected); +} + +int master_set_response_expected(Master *master, uint8_t function_id, bool response_expected) { + return device_set_response_expected(master->p, function_id, response_expected); +} + +int master_set_response_expected_all(Master *master, bool response_expected) { + return device_set_response_expected_all(master->p, response_expected); +} + +void master_register_callback(Master *master, int16_t callback_id, void (*function)(void), void *user_data) { + device_register_callback(master->p, callback_id, function, user_data); +} + +int master_get_api_version(Master *master, uint8_t ret_api_version[3]) { + return device_get_api_version(master->p, ret_api_version); +} + +int master_get_stack_voltage(Master *master, uint16_t *ret_voltage) { + DevicePrivate *device_p = master->p; + GetStackVoltage_Request request; + GetStackVoltage_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_STACK_VOLTAGE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_voltage = leconvert_uint16_from(response.voltage); + + return ret; +} + +int master_get_stack_current(Master *master, uint16_t *ret_current) { + DevicePrivate *device_p = master->p; + GetStackCurrent_Request request; + GetStackCurrent_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_STACK_CURRENT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_current = leconvert_uint16_from(response.current); + + return ret; +} + +int master_set_extension_type(Master *master, uint8_t extension, uint32_t exttype) { + DevicePrivate *device_p = master->p; + SetExtensionType_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_EXTENSION_TYPE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.extension = extension; + request.exttype = leconvert_uint32_to(exttype); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_extension_type(Master *master, uint8_t extension, uint32_t *ret_exttype) { + DevicePrivate *device_p = master->p; + GetExtensionType_Request request; + GetExtensionType_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_EXTENSION_TYPE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.extension = extension; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_exttype = leconvert_uint32_from(response.exttype); + + return ret; +} + +int master_is_chibi_present(Master *master, bool *ret_present) { + DevicePrivate *device_p = master->p; + IsChibiPresent_Request request; + IsChibiPresent_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_IS_CHIBI_PRESENT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_present = response.present != 0; + + return ret; +} + +int master_set_chibi_address(Master *master, uint8_t address) { + DevicePrivate *device_p = master->p; + SetChibiAddress_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_CHIBI_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.address = address; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_chibi_address(Master *master, uint8_t *ret_address) { + DevicePrivate *device_p = master->p; + GetChibiAddress_Request request; + GetChibiAddress_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_CHIBI_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_address = response.address; + + return ret; +} + +int master_set_chibi_master_address(Master *master, uint8_t address) { + DevicePrivate *device_p = master->p; + SetChibiMasterAddress_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_CHIBI_MASTER_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.address = address; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_chibi_master_address(Master *master, uint8_t *ret_address) { + DevicePrivate *device_p = master->p; + GetChibiMasterAddress_Request request; + GetChibiMasterAddress_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_CHIBI_MASTER_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_address = response.address; + + return ret; +} + +int master_set_chibi_slave_address(Master *master, uint8_t num, uint8_t address) { + DevicePrivate *device_p = master->p; + SetChibiSlaveAddress_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_CHIBI_SLAVE_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.num = num; + request.address = address; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_chibi_slave_address(Master *master, uint8_t num, uint8_t *ret_address) { + DevicePrivate *device_p = master->p; + GetChibiSlaveAddress_Request request; + GetChibiSlaveAddress_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_CHIBI_SLAVE_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.num = num; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_address = response.address; + + return ret; +} + +int master_get_chibi_signal_strength(Master *master, uint8_t *ret_signal_strength) { + DevicePrivate *device_p = master->p; + GetChibiSignalStrength_Request request; + GetChibiSignalStrength_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_CHIBI_SIGNAL_STRENGTH, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_signal_strength = response.signal_strength; + + return ret; +} + +int master_get_chibi_error_log(Master *master, uint16_t *ret_underrun, uint16_t *ret_crc_error, uint16_t *ret_no_ack, uint16_t *ret_overflow) { + DevicePrivate *device_p = master->p; + GetChibiErrorLog_Request request; + GetChibiErrorLog_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_CHIBI_ERROR_LOG, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_underrun = leconvert_uint16_from(response.underrun); + *ret_crc_error = leconvert_uint16_from(response.crc_error); + *ret_no_ack = leconvert_uint16_from(response.no_ack); + *ret_overflow = leconvert_uint16_from(response.overflow); + + return ret; +} + +int master_set_chibi_frequency(Master *master, uint8_t frequency) { + DevicePrivate *device_p = master->p; + SetChibiFrequency_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_CHIBI_FREQUENCY, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.frequency = frequency; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_chibi_frequency(Master *master, uint8_t *ret_frequency) { + DevicePrivate *device_p = master->p; + GetChibiFrequency_Request request; + GetChibiFrequency_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_CHIBI_FREQUENCY, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_frequency = response.frequency; + + return ret; +} + +int master_set_chibi_channel(Master *master, uint8_t channel) { + DevicePrivate *device_p = master->p; + SetChibiChannel_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_CHIBI_CHANNEL, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.channel = channel; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_chibi_channel(Master *master, uint8_t *ret_channel) { + DevicePrivate *device_p = master->p; + GetChibiChannel_Request request; + GetChibiChannel_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_CHIBI_CHANNEL, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_channel = response.channel; + + return ret; +} + +int master_is_rs485_present(Master *master, bool *ret_present) { + DevicePrivate *device_p = master->p; + IsRS485Present_Request request; + IsRS485Present_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_IS_RS485_PRESENT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_present = response.present != 0; + + return ret; +} + +int master_set_rs485_address(Master *master, uint8_t address) { + DevicePrivate *device_p = master->p; + SetRS485Address_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_RS485_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.address = address; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_rs485_address(Master *master, uint8_t *ret_address) { + DevicePrivate *device_p = master->p; + GetRS485Address_Request request; + GetRS485Address_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_RS485_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_address = response.address; + + return ret; +} + +int master_set_rs485_slave_address(Master *master, uint8_t num, uint8_t address) { + DevicePrivate *device_p = master->p; + SetRS485SlaveAddress_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_RS485_SLAVE_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.num = num; + request.address = address; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_rs485_slave_address(Master *master, uint8_t num, uint8_t *ret_address) { + DevicePrivate *device_p = master->p; + GetRS485SlaveAddress_Request request; + GetRS485SlaveAddress_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_RS485_SLAVE_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.num = num; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_address = response.address; + + return ret; +} + +int master_get_rs485_error_log(Master *master, uint16_t *ret_crc_error) { + DevicePrivate *device_p = master->p; + GetRS485ErrorLog_Request request; + GetRS485ErrorLog_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_RS485_ERROR_LOG, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_crc_error = leconvert_uint16_from(response.crc_error); + + return ret; +} + +int master_set_rs485_configuration(Master *master, uint32_t speed, char parity, uint8_t stopbits) { + DevicePrivate *device_p = master->p; + SetRS485Configuration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_RS485_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.speed = leconvert_uint32_to(speed); + request.parity = parity; + request.stopbits = stopbits; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_rs485_configuration(Master *master, uint32_t *ret_speed, char *ret_parity, uint8_t *ret_stopbits) { + DevicePrivate *device_p = master->p; + GetRS485Configuration_Request request; + GetRS485Configuration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_RS485_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_speed = leconvert_uint32_from(response.speed); + *ret_parity = response.parity; + *ret_stopbits = response.stopbits; + + return ret; +} + +int master_is_wifi_present(Master *master, bool *ret_present) { + DevicePrivate *device_p = master->p; + IsWifiPresent_Request request; + IsWifiPresent_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_IS_WIFI_PRESENT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_present = response.present != 0; + + return ret; +} + +int master_set_wifi_configuration(Master *master, const char ssid[32], uint8_t connection, uint8_t ip[4], uint8_t subnet_mask[4], uint8_t gateway[4], uint16_t port) { + DevicePrivate *device_p = master->p; + SetWifiConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.ssid, ssid, 32); + + request.connection = connection; + memcpy(request.ip, ip, 4 * sizeof(uint8_t)); + memcpy(request.subnet_mask, subnet_mask, 4 * sizeof(uint8_t)); + memcpy(request.gateway, gateway, 4 * sizeof(uint8_t)); + request.port = leconvert_uint16_to(port); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi_configuration(Master *master, char ret_ssid[32], uint8_t *ret_connection, uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint16_t *ret_port) { + DevicePrivate *device_p = master->p; + GetWifiConfiguration_Request request; + GetWifiConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_ssid, response.ssid, 32); + *ret_connection = response.connection; + memcpy(ret_ip, response.ip, 4 * sizeof(uint8_t)); + memcpy(ret_subnet_mask, response.subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_gateway, response.gateway, 4 * sizeof(uint8_t)); + *ret_port = leconvert_uint16_from(response.port); + + return ret; +} + +int master_set_wifi_encryption(Master *master, uint8_t encryption, const char key[50], uint8_t key_index, uint8_t eap_options, uint16_t ca_certificate_length, uint16_t client_certificate_length, uint16_t private_key_length) { + DevicePrivate *device_p = master->p; + SetWifiEncryption_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI_ENCRYPTION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.encryption = encryption; + memcpy(request.key, key, 50); + + request.key_index = key_index; + request.eap_options = eap_options; + request.ca_certificate_length = leconvert_uint16_to(ca_certificate_length); + request.client_certificate_length = leconvert_uint16_to(client_certificate_length); + request.private_key_length = leconvert_uint16_to(private_key_length); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi_encryption(Master *master, uint8_t *ret_encryption, char ret_key[50], uint8_t *ret_key_index, uint8_t *ret_eap_options, uint16_t *ret_ca_certificate_length, uint16_t *ret_client_certificate_length, uint16_t *ret_private_key_length) { + DevicePrivate *device_p = master->p; + GetWifiEncryption_Request request; + GetWifiEncryption_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI_ENCRYPTION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_encryption = response.encryption; + memcpy(ret_key, response.key, 50); + *ret_key_index = response.key_index; + *ret_eap_options = response.eap_options; + *ret_ca_certificate_length = leconvert_uint16_from(response.ca_certificate_length); + *ret_client_certificate_length = leconvert_uint16_from(response.client_certificate_length); + *ret_private_key_length = leconvert_uint16_from(response.private_key_length); + + return ret; +} + +int master_get_wifi_status(Master *master, uint8_t ret_mac_address[6], uint8_t ret_bssid[6], uint8_t *ret_channel, int16_t *ret_rssi, uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint32_t *ret_rx_count, uint32_t *ret_tx_count, uint8_t *ret_state) { + DevicePrivate *device_p = master->p; + GetWifiStatus_Request request; + GetWifiStatus_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI_STATUS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_mac_address, response.mac_address, 6 * sizeof(uint8_t)); + memcpy(ret_bssid, response.bssid, 6 * sizeof(uint8_t)); + *ret_channel = response.channel; + *ret_rssi = leconvert_int16_from(response.rssi); + memcpy(ret_ip, response.ip, 4 * sizeof(uint8_t)); + memcpy(ret_subnet_mask, response.subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_gateway, response.gateway, 4 * sizeof(uint8_t)); + *ret_rx_count = leconvert_uint32_from(response.rx_count); + *ret_tx_count = leconvert_uint32_from(response.tx_count); + *ret_state = response.state; + + return ret; +} + +int master_refresh_wifi_status(Master *master) { + DevicePrivate *device_p = master->p; + RefreshWifiStatus_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_REFRESH_WIFI_STATUS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_set_wifi_certificate(Master *master, uint16_t index, uint8_t data[32], uint8_t data_length) { + DevicePrivate *device_p = master->p; + SetWifiCertificate_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI_CERTIFICATE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.index = leconvert_uint16_to(index); + memcpy(request.data, data, 32 * sizeof(uint8_t)); + request.data_length = data_length; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi_certificate(Master *master, uint16_t index, uint8_t ret_data[32], uint8_t *ret_data_length) { + DevicePrivate *device_p = master->p; + GetWifiCertificate_Request request; + GetWifiCertificate_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI_CERTIFICATE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.index = leconvert_uint16_to(index); + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_data, response.data, 32 * sizeof(uint8_t)); + *ret_data_length = response.data_length; + + return ret; +} + +int master_set_wifi_power_mode(Master *master, uint8_t mode) { + DevicePrivate *device_p = master->p; + SetWifiPowerMode_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI_POWER_MODE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.mode = mode; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi_power_mode(Master *master, uint8_t *ret_mode) { + DevicePrivate *device_p = master->p; + GetWifiPowerMode_Request request; + GetWifiPowerMode_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI_POWER_MODE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_mode = response.mode; + + return ret; +} + +int master_get_wifi_buffer_info(Master *master, uint32_t *ret_overflow, uint16_t *ret_low_watermark, uint16_t *ret_used) { + DevicePrivate *device_p = master->p; + GetWifiBufferInfo_Request request; + GetWifiBufferInfo_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI_BUFFER_INFO, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_overflow = leconvert_uint32_from(response.overflow); + *ret_low_watermark = leconvert_uint16_from(response.low_watermark); + *ret_used = leconvert_uint16_from(response.used); + + return ret; +} + +int master_set_wifi_regulatory_domain(Master *master, uint8_t domain) { + DevicePrivate *device_p = master->p; + SetWifiRegulatoryDomain_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI_REGULATORY_DOMAIN, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.domain = domain; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi_regulatory_domain(Master *master, uint8_t *ret_domain) { + DevicePrivate *device_p = master->p; + GetWifiRegulatoryDomain_Request request; + GetWifiRegulatoryDomain_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI_REGULATORY_DOMAIN, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_domain = response.domain; + + return ret; +} + +int master_get_usb_voltage(Master *master, uint16_t *ret_voltage) { + DevicePrivate *device_p = master->p; + GetUSBVoltage_Request request; + GetUSBVoltage_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_USB_VOLTAGE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_voltage = leconvert_uint16_from(response.voltage); + + return ret; +} + +int master_set_long_wifi_key(Master *master, const char key[64]) { + DevicePrivate *device_p = master->p; + SetLongWifiKey_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_LONG_WIFI_KEY, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.key, key, 64); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_long_wifi_key(Master *master, char ret_key[64]) { + DevicePrivate *device_p = master->p; + GetLongWifiKey_Request request; + GetLongWifiKey_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_LONG_WIFI_KEY, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_key, response.key, 64); + + return ret; +} + +int master_set_wifi_hostname(Master *master, const char hostname[16]) { + DevicePrivate *device_p = master->p; + SetWifiHostname_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI_HOSTNAME, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.hostname, hostname, 16); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi_hostname(Master *master, char ret_hostname[16]) { + DevicePrivate *device_p = master->p; + GetWifiHostname_Request request; + GetWifiHostname_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI_HOSTNAME, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_hostname, response.hostname, 16); + + return ret; +} + +int master_set_stack_current_callback_period(Master *master, uint32_t period) { + DevicePrivate *device_p = master->p; + SetStackCurrentCallbackPeriod_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_STACK_CURRENT_CALLBACK_PERIOD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.period = leconvert_uint32_to(period); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_stack_current_callback_period(Master *master, uint32_t *ret_period) { + DevicePrivate *device_p = master->p; + GetStackCurrentCallbackPeriod_Request request; + GetStackCurrentCallbackPeriod_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_STACK_CURRENT_CALLBACK_PERIOD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_period = leconvert_uint32_from(response.period); + + return ret; +} + +int master_set_stack_voltage_callback_period(Master *master, uint32_t period) { + DevicePrivate *device_p = master->p; + SetStackVoltageCallbackPeriod_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_STACK_VOLTAGE_CALLBACK_PERIOD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.period = leconvert_uint32_to(period); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_stack_voltage_callback_period(Master *master, uint32_t *ret_period) { + DevicePrivate *device_p = master->p; + GetStackVoltageCallbackPeriod_Request request; + GetStackVoltageCallbackPeriod_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_STACK_VOLTAGE_CALLBACK_PERIOD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_period = leconvert_uint32_from(response.period); + + return ret; +} + +int master_set_usb_voltage_callback_period(Master *master, uint32_t period) { + DevicePrivate *device_p = master->p; + SetUSBVoltageCallbackPeriod_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_USB_VOLTAGE_CALLBACK_PERIOD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.period = leconvert_uint32_to(period); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_usb_voltage_callback_period(Master *master, uint32_t *ret_period) { + DevicePrivate *device_p = master->p; + GetUSBVoltageCallbackPeriod_Request request; + GetUSBVoltageCallbackPeriod_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_USB_VOLTAGE_CALLBACK_PERIOD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_period = leconvert_uint32_from(response.period); + + return ret; +} + +int master_set_stack_current_callback_threshold(Master *master, char option, uint16_t min, uint16_t max) { + DevicePrivate *device_p = master->p; + SetStackCurrentCallbackThreshold_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_STACK_CURRENT_CALLBACK_THRESHOLD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.option = option; + request.min = leconvert_uint16_to(min); + request.max = leconvert_uint16_to(max); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_stack_current_callback_threshold(Master *master, char *ret_option, uint16_t *ret_min, uint16_t *ret_max) { + DevicePrivate *device_p = master->p; + GetStackCurrentCallbackThreshold_Request request; + GetStackCurrentCallbackThreshold_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_STACK_CURRENT_CALLBACK_THRESHOLD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_option = response.option; + *ret_min = leconvert_uint16_from(response.min); + *ret_max = leconvert_uint16_from(response.max); + + return ret; +} + +int master_set_stack_voltage_callback_threshold(Master *master, char option, uint16_t min, uint16_t max) { + DevicePrivate *device_p = master->p; + SetStackVoltageCallbackThreshold_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_STACK_VOLTAGE_CALLBACK_THRESHOLD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.option = option; + request.min = leconvert_uint16_to(min); + request.max = leconvert_uint16_to(max); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_stack_voltage_callback_threshold(Master *master, char *ret_option, uint16_t *ret_min, uint16_t *ret_max) { + DevicePrivate *device_p = master->p; + GetStackVoltageCallbackThreshold_Request request; + GetStackVoltageCallbackThreshold_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_STACK_VOLTAGE_CALLBACK_THRESHOLD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_option = response.option; + *ret_min = leconvert_uint16_from(response.min); + *ret_max = leconvert_uint16_from(response.max); + + return ret; +} + +int master_set_usb_voltage_callback_threshold(Master *master, char option, uint16_t min, uint16_t max) { + DevicePrivate *device_p = master->p; + SetUSBVoltageCallbackThreshold_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_USB_VOLTAGE_CALLBACK_THRESHOLD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.option = option; + request.min = leconvert_uint16_to(min); + request.max = leconvert_uint16_to(max); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_usb_voltage_callback_threshold(Master *master, char *ret_option, uint16_t *ret_min, uint16_t *ret_max) { + DevicePrivate *device_p = master->p; + GetUSBVoltageCallbackThreshold_Request request; + GetUSBVoltageCallbackThreshold_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_USB_VOLTAGE_CALLBACK_THRESHOLD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_option = response.option; + *ret_min = leconvert_uint16_from(response.min); + *ret_max = leconvert_uint16_from(response.max); + + return ret; +} + +int master_set_debounce_period(Master *master, uint32_t debounce) { + DevicePrivate *device_p = master->p; + SetDebouncePeriod_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_DEBOUNCE_PERIOD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.debounce = leconvert_uint32_to(debounce); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_debounce_period(Master *master, uint32_t *ret_debounce) { + DevicePrivate *device_p = master->p; + GetDebouncePeriod_Request request; + GetDebouncePeriod_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_DEBOUNCE_PERIOD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_debounce = leconvert_uint32_from(response.debounce); + + return ret; +} + +int master_is_ethernet_present(Master *master, bool *ret_present) { + DevicePrivate *device_p = master->p; + IsEthernetPresent_Request request; + IsEthernetPresent_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_IS_ETHERNET_PRESENT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_present = response.present != 0; + + return ret; +} + +int master_set_ethernet_configuration(Master *master, uint8_t connection, uint8_t ip[4], uint8_t subnet_mask[4], uint8_t gateway[4], uint16_t port) { + DevicePrivate *device_p = master->p; + SetEthernetConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_ETHERNET_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.connection = connection; + memcpy(request.ip, ip, 4 * sizeof(uint8_t)); + memcpy(request.subnet_mask, subnet_mask, 4 * sizeof(uint8_t)); + memcpy(request.gateway, gateway, 4 * sizeof(uint8_t)); + request.port = leconvert_uint16_to(port); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_ethernet_configuration(Master *master, uint8_t *ret_connection, uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint16_t *ret_port) { + DevicePrivate *device_p = master->p; + GetEthernetConfiguration_Request request; + GetEthernetConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_ETHERNET_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_connection = response.connection; + memcpy(ret_ip, response.ip, 4 * sizeof(uint8_t)); + memcpy(ret_subnet_mask, response.subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_gateway, response.gateway, 4 * sizeof(uint8_t)); + *ret_port = leconvert_uint16_from(response.port); + + return ret; +} + +int master_get_ethernet_status(Master *master, uint8_t ret_mac_address[6], uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint32_t *ret_rx_count, uint32_t *ret_tx_count, char ret_hostname[32]) { + DevicePrivate *device_p = master->p; + GetEthernetStatus_Request request; + GetEthernetStatus_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_ETHERNET_STATUS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_mac_address, response.mac_address, 6 * sizeof(uint8_t)); + memcpy(ret_ip, response.ip, 4 * sizeof(uint8_t)); + memcpy(ret_subnet_mask, response.subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_gateway, response.gateway, 4 * sizeof(uint8_t)); + *ret_rx_count = leconvert_uint32_from(response.rx_count); + *ret_tx_count = leconvert_uint32_from(response.tx_count); + memcpy(ret_hostname, response.hostname, 32); + + return ret; +} + +int master_set_ethernet_hostname(Master *master, const char hostname[32]) { + DevicePrivate *device_p = master->p; + SetEthernetHostname_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_ETHERNET_HOSTNAME, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.hostname, hostname, 32); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_set_ethernet_mac_address(Master *master, uint8_t mac_address[6]) { + DevicePrivate *device_p = master->p; + SetEthernetMACAddress_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_ETHERNET_MAC_ADDRESS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.mac_address, mac_address, 6 * sizeof(uint8_t)); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_set_ethernet_websocket_configuration(Master *master, uint8_t sockets, uint16_t port) { + DevicePrivate *device_p = master->p; + SetEthernetWebsocketConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_ETHERNET_WEBSOCKET_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.sockets = sockets; + request.port = leconvert_uint16_to(port); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_ethernet_websocket_configuration(Master *master, uint8_t *ret_sockets, uint16_t *ret_port) { + DevicePrivate *device_p = master->p; + GetEthernetWebsocketConfiguration_Request request; + GetEthernetWebsocketConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_ETHERNET_WEBSOCKET_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_sockets = response.sockets; + *ret_port = leconvert_uint16_from(response.port); + + return ret; +} + +int master_set_ethernet_authentication_secret(Master *master, const char secret[64]) { + DevicePrivate *device_p = master->p; + SetEthernetAuthenticationSecret_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_ETHERNET_AUTHENTICATION_SECRET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.secret, secret, 64); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_ethernet_authentication_secret(Master *master, char ret_secret[64]) { + DevicePrivate *device_p = master->p; + GetEthernetAuthenticationSecret_Request request; + GetEthernetAuthenticationSecret_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_ETHERNET_AUTHENTICATION_SECRET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_secret, response.secret, 64); + + return ret; +} + +int master_set_wifi_authentication_secret(Master *master, const char secret[64]) { + DevicePrivate *device_p = master->p; + SetWifiAuthenticationSecret_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI_AUTHENTICATION_SECRET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.secret, secret, 64); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi_authentication_secret(Master *master, char ret_secret[64]) { + DevicePrivate *device_p = master->p; + GetWifiAuthenticationSecret_Request request; + GetWifiAuthenticationSecret_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI_AUTHENTICATION_SECRET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_secret, response.secret, 64); + + return ret; +} + +int master_get_connection_type(Master *master, uint8_t *ret_connection_type) { + DevicePrivate *device_p = master->p; + GetConnectionType_Request request; + GetConnectionType_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_CONNECTION_TYPE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_connection_type = response.connection_type; + + return ret; +} + +int master_is_wifi2_present(Master *master, bool *ret_present) { + DevicePrivate *device_p = master->p; + IsWifi2Present_Request request; + IsWifi2Present_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_IS_WIFI2_PRESENT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_present = response.present != 0; + + return ret; +} + +int master_start_wifi2_bootloader(Master *master, int8_t *ret_result) { + DevicePrivate *device_p = master->p; + StartWifi2Bootloader_Request request; + StartWifi2Bootloader_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_START_WIFI2_BOOTLOADER, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_result = response.result; + + return ret; +} + +int master_write_wifi2_serial_port(Master *master, uint8_t data[60], uint8_t length, int8_t *ret_result) { + DevicePrivate *device_p = master->p; + WriteWifi2SerialPort_Request request; + WriteWifi2SerialPort_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_WRITE_WIFI2_SERIAL_PORT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.data, data, 60 * sizeof(uint8_t)); + request.length = length; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_result = response.result; + + return ret; +} + +int master_read_wifi2_serial_port(Master *master, uint8_t length, uint8_t ret_data[60], uint8_t *ret_result) { + DevicePrivate *device_p = master->p; + ReadWifi2SerialPort_Request request; + ReadWifi2SerialPort_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_READ_WIFI2_SERIAL_PORT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.length = length; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_data, response.data, 60 * sizeof(uint8_t)); + *ret_result = response.result; + + return ret; +} + +int master_set_wifi2_authentication_secret(Master *master, const char secret[64]) { + DevicePrivate *device_p = master->p; + SetWifi2AuthenticationSecret_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI2_AUTHENTICATION_SECRET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.secret, secret, 64); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi2_authentication_secret(Master *master, char ret_secret[64]) { + DevicePrivate *device_p = master->p; + GetWifi2AuthenticationSecret_Request request; + GetWifi2AuthenticationSecret_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_AUTHENTICATION_SECRET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_secret, response.secret, 64); + + return ret; +} + +int master_set_wifi2_configuration(Master *master, uint16_t port, uint16_t websocket_port, uint16_t website_port, uint8_t phy_mode, uint8_t sleep_mode, uint8_t website) { + DevicePrivate *device_p = master->p; + SetWifi2Configuration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI2_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.port = leconvert_uint16_to(port); + request.websocket_port = leconvert_uint16_to(websocket_port); + request.website_port = leconvert_uint16_to(website_port); + request.phy_mode = phy_mode; + request.sleep_mode = sleep_mode; + request.website = website; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi2_configuration(Master *master, uint16_t *ret_port, uint16_t *ret_websocket_port, uint16_t *ret_website_port, uint8_t *ret_phy_mode, uint8_t *ret_sleep_mode, uint8_t *ret_website) { + DevicePrivate *device_p = master->p; + GetWifi2Configuration_Request request; + GetWifi2Configuration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_port = leconvert_uint16_from(response.port); + *ret_websocket_port = leconvert_uint16_from(response.websocket_port); + *ret_website_port = leconvert_uint16_from(response.website_port); + *ret_phy_mode = response.phy_mode; + *ret_sleep_mode = response.sleep_mode; + *ret_website = response.website; + + return ret; +} + +int master_get_wifi2_status(Master *master, bool *ret_client_enabled, uint8_t *ret_client_status, uint8_t ret_client_ip[4], uint8_t ret_client_subnet_mask[4], uint8_t ret_client_gateway[4], uint8_t ret_client_mac_address[6], uint32_t *ret_client_rx_count, uint32_t *ret_client_tx_count, int8_t *ret_client_rssi, bool *ret_ap_enabled, uint8_t ret_ap_ip[4], uint8_t ret_ap_subnet_mask[4], uint8_t ret_ap_gateway[4], uint8_t ret_ap_mac_address[6], uint32_t *ret_ap_rx_count, uint32_t *ret_ap_tx_count, uint8_t *ret_ap_connected_count) { + DevicePrivate *device_p = master->p; + GetWifi2Status_Request request; + GetWifi2Status_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_STATUS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_client_enabled = response.client_enabled != 0; + *ret_client_status = response.client_status; + memcpy(ret_client_ip, response.client_ip, 4 * sizeof(uint8_t)); + memcpy(ret_client_subnet_mask, response.client_subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_client_gateway, response.client_gateway, 4 * sizeof(uint8_t)); + memcpy(ret_client_mac_address, response.client_mac_address, 6 * sizeof(uint8_t)); + *ret_client_rx_count = leconvert_uint32_from(response.client_rx_count); + *ret_client_tx_count = leconvert_uint32_from(response.client_tx_count); + *ret_client_rssi = response.client_rssi; + *ret_ap_enabled = response.ap_enabled != 0; + memcpy(ret_ap_ip, response.ap_ip, 4 * sizeof(uint8_t)); + memcpy(ret_ap_subnet_mask, response.ap_subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_ap_gateway, response.ap_gateway, 4 * sizeof(uint8_t)); + memcpy(ret_ap_mac_address, response.ap_mac_address, 6 * sizeof(uint8_t)); + *ret_ap_rx_count = leconvert_uint32_from(response.ap_rx_count); + *ret_ap_tx_count = leconvert_uint32_from(response.ap_tx_count); + *ret_ap_connected_count = response.ap_connected_count; + + return ret; +} + +int master_set_wifi2_client_configuration(Master *master, bool enable, const char ssid[32], uint8_t ip[4], uint8_t subnet_mask[4], uint8_t gateway[4], uint8_t mac_address[6], uint8_t bssid[6]) { + DevicePrivate *device_p = master->p; + SetWifi2ClientConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI2_CLIENT_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.enable = enable ? 1 : 0; + memcpy(request.ssid, ssid, 32); + + memcpy(request.ip, ip, 4 * sizeof(uint8_t)); + memcpy(request.subnet_mask, subnet_mask, 4 * sizeof(uint8_t)); + memcpy(request.gateway, gateway, 4 * sizeof(uint8_t)); + memcpy(request.mac_address, mac_address, 6 * sizeof(uint8_t)); + memcpy(request.bssid, bssid, 6 * sizeof(uint8_t)); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi2_client_configuration(Master *master, bool *ret_enable, char ret_ssid[32], uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint8_t ret_mac_address[6], uint8_t ret_bssid[6]) { + DevicePrivate *device_p = master->p; + GetWifi2ClientConfiguration_Request request; + GetWifi2ClientConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_CLIENT_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_enable = response.enable != 0; + memcpy(ret_ssid, response.ssid, 32); + memcpy(ret_ip, response.ip, 4 * sizeof(uint8_t)); + memcpy(ret_subnet_mask, response.subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_gateway, response.gateway, 4 * sizeof(uint8_t)); + memcpy(ret_mac_address, response.mac_address, 6 * sizeof(uint8_t)); + memcpy(ret_bssid, response.bssid, 6 * sizeof(uint8_t)); + + return ret; +} + +int master_set_wifi2_client_hostname(Master *master, const char hostname[32]) { + DevicePrivate *device_p = master->p; + SetWifi2ClientHostname_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI2_CLIENT_HOSTNAME, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.hostname, hostname, 32); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi2_client_hostname(Master *master, char ret_hostname[32]) { + DevicePrivate *device_p = master->p; + GetWifi2ClientHostname_Request request; + GetWifi2ClientHostname_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_CLIENT_HOSTNAME, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_hostname, response.hostname, 32); + + return ret; +} + +int master_set_wifi2_client_password(Master *master, const char password[64]) { + DevicePrivate *device_p = master->p; + SetWifi2ClientPassword_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI2_CLIENT_PASSWORD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.password, password, 64); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi2_client_password(Master *master, char ret_password[64]) { + DevicePrivate *device_p = master->p; + GetWifi2ClientPassword_Request request; + GetWifi2ClientPassword_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_CLIENT_PASSWORD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_password, response.password, 64); + + return ret; +} + +int master_set_wifi2_ap_configuration(Master *master, bool enable, const char ssid[32], uint8_t ip[4], uint8_t subnet_mask[4], uint8_t gateway[4], uint8_t encryption, bool hidden, uint8_t channel, uint8_t mac_address[6]) { + DevicePrivate *device_p = master->p; + SetWifi2APConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI2_AP_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.enable = enable ? 1 : 0; + memcpy(request.ssid, ssid, 32); + + memcpy(request.ip, ip, 4 * sizeof(uint8_t)); + memcpy(request.subnet_mask, subnet_mask, 4 * sizeof(uint8_t)); + memcpy(request.gateway, gateway, 4 * sizeof(uint8_t)); + request.encryption = encryption; + request.hidden = hidden ? 1 : 0; + request.channel = channel; + memcpy(request.mac_address, mac_address, 6 * sizeof(uint8_t)); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi2_ap_configuration(Master *master, bool *ret_enable, char ret_ssid[32], uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint8_t *ret_encryption, bool *ret_hidden, uint8_t *ret_channel, uint8_t ret_mac_address[6]) { + DevicePrivate *device_p = master->p; + GetWifi2APConfiguration_Request request; + GetWifi2APConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_AP_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_enable = response.enable != 0; + memcpy(ret_ssid, response.ssid, 32); + memcpy(ret_ip, response.ip, 4 * sizeof(uint8_t)); + memcpy(ret_subnet_mask, response.subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_gateway, response.gateway, 4 * sizeof(uint8_t)); + *ret_encryption = response.encryption; + *ret_hidden = response.hidden != 0; + *ret_channel = response.channel; + memcpy(ret_mac_address, response.mac_address, 6 * sizeof(uint8_t)); + + return ret; +} + +int master_set_wifi2_ap_password(Master *master, const char password[64]) { + DevicePrivate *device_p = master->p; + SetWifi2APPassword_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI2_AP_PASSWORD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.password, password, 64); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi2_ap_password(Master *master, char ret_password[64]) { + DevicePrivate *device_p = master->p; + GetWifi2APPassword_Request request; + GetWifi2APPassword_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_AP_PASSWORD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_password, response.password, 64); + + return ret; +} + +int master_save_wifi2_configuration(Master *master, uint8_t *ret_result) { + DevicePrivate *device_p = master->p; + SaveWifi2Configuration_Request request; + SaveWifi2Configuration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SAVE_WIFI2_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_result = response.result; + + return ret; +} + +int master_get_wifi2_firmware_version(Master *master, uint8_t ret_firmware_version[3]) { + DevicePrivate *device_p = master->p; + GetWifi2FirmwareVersion_Request request; + GetWifi2FirmwareVersion_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_FIRMWARE_VERSION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_firmware_version, response.firmware_version, 3 * sizeof(uint8_t)); + + return ret; +} + +int master_enable_wifi2_status_led(Master *master) { + DevicePrivate *device_p = master->p; + EnableWifi2StatusLED_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_ENABLE_WIFI2_STATUS_LED, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_disable_wifi2_status_led(Master *master) { + DevicePrivate *device_p = master->p; + DisableWifi2StatusLED_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_DISABLE_WIFI2_STATUS_LED, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_is_wifi2_status_led_enabled(Master *master, bool *ret_enabled) { + DevicePrivate *device_p = master->p; + IsWifi2StatusLEDEnabled_Request request; + IsWifi2StatusLEDEnabled_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_IS_WIFI2_STATUS_LED_ENABLED, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_enabled = response.enabled != 0; + + return ret; +} + +int master_set_wifi2_mesh_configuration(Master *master, bool enable, uint8_t root_ip[4], uint8_t root_subnet_mask[4], uint8_t root_gateway[4], uint8_t router_bssid[6], uint8_t group_id[6], const char group_ssid_prefix[16], uint8_t gateway_ip[4], uint16_t gateway_port) { + DevicePrivate *device_p = master->p; + SetWifi2MeshConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI2_MESH_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.enable = enable ? 1 : 0; + memcpy(request.root_ip, root_ip, 4 * sizeof(uint8_t)); + memcpy(request.root_subnet_mask, root_subnet_mask, 4 * sizeof(uint8_t)); + memcpy(request.root_gateway, root_gateway, 4 * sizeof(uint8_t)); + memcpy(request.router_bssid, router_bssid, 6 * sizeof(uint8_t)); + memcpy(request.group_id, group_id, 6 * sizeof(uint8_t)); + memcpy(request.group_ssid_prefix, group_ssid_prefix, 16); + + memcpy(request.gateway_ip, gateway_ip, 4 * sizeof(uint8_t)); + request.gateway_port = leconvert_uint16_to(gateway_port); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi2_mesh_configuration(Master *master, bool *ret_enable, uint8_t ret_root_ip[4], uint8_t ret_root_subnet_mask[4], uint8_t ret_root_gateway[4], uint8_t ret_router_bssid[6], uint8_t ret_group_id[6], char ret_group_ssid_prefix[16], uint8_t ret_gateway_ip[4], uint16_t *ret_gateway_port) { + DevicePrivate *device_p = master->p; + GetWifi2MeshConfiguration_Request request; + GetWifi2MeshConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_MESH_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_enable = response.enable != 0; + memcpy(ret_root_ip, response.root_ip, 4 * sizeof(uint8_t)); + memcpy(ret_root_subnet_mask, response.root_subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_root_gateway, response.root_gateway, 4 * sizeof(uint8_t)); + memcpy(ret_router_bssid, response.router_bssid, 6 * sizeof(uint8_t)); + memcpy(ret_group_id, response.group_id, 6 * sizeof(uint8_t)); + memcpy(ret_group_ssid_prefix, response.group_ssid_prefix, 16); + memcpy(ret_gateway_ip, response.gateway_ip, 4 * sizeof(uint8_t)); + *ret_gateway_port = leconvert_uint16_from(response.gateway_port); + + return ret; +} + +int master_set_wifi2_mesh_router_ssid(Master *master, const char ssid[32]) { + DevicePrivate *device_p = master->p; + SetWifi2MeshRouterSSID_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI2_MESH_ROUTER_SSID, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.ssid, ssid, 32); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi2_mesh_router_ssid(Master *master, char ret_ssid[32]) { + DevicePrivate *device_p = master->p; + GetWifi2MeshRouterSSID_Request request; + GetWifi2MeshRouterSSID_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_MESH_ROUTER_SSID, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_ssid, response.ssid, 32); + + return ret; +} + +int master_set_wifi2_mesh_router_password(Master *master, const char password[64]) { + DevicePrivate *device_p = master->p; + SetWifi2MeshRouterPassword_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_WIFI2_MESH_ROUTER_PASSWORD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.password, password, 64); + + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_wifi2_mesh_router_password(Master *master, char ret_password[64]) { + DevicePrivate *device_p = master->p; + GetWifi2MeshRouterPassword_Request request; + GetWifi2MeshRouterPassword_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_MESH_ROUTER_PASSWORD, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_password, response.password, 64); + + return ret; +} + +int master_get_wifi2_mesh_common_status(Master *master, uint8_t *ret_status, bool *ret_root_node, bool *ret_root_candidate, uint16_t *ret_connected_nodes, uint32_t *ret_rx_count, uint32_t *ret_tx_count) { + DevicePrivate *device_p = master->p; + GetWifi2MeshCommonStatus_Request request; + GetWifi2MeshCommonStatus_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_MESH_COMMON_STATUS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_status = response.status; + *ret_root_node = response.root_node != 0; + *ret_root_candidate = response.root_candidate != 0; + *ret_connected_nodes = leconvert_uint16_from(response.connected_nodes); + *ret_rx_count = leconvert_uint32_from(response.rx_count); + *ret_tx_count = leconvert_uint32_from(response.tx_count); + + return ret; +} + +int master_get_wifi2_mesh_client_status(Master *master, char ret_hostname[32], uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint8_t ret_mac_address[6]) { + DevicePrivate *device_p = master->p; + GetWifi2MeshClientStatus_Request request; + GetWifi2MeshClientStatus_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_MESH_CLIENT_STATUS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_hostname, response.hostname, 32); + memcpy(ret_ip, response.ip, 4 * sizeof(uint8_t)); + memcpy(ret_subnet_mask, response.subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_gateway, response.gateway, 4 * sizeof(uint8_t)); + memcpy(ret_mac_address, response.mac_address, 6 * sizeof(uint8_t)); + + return ret; +} + +int master_get_wifi2_mesh_ap_status(Master *master, char ret_ssid[32], uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint8_t ret_mac_address[6]) { + DevicePrivate *device_p = master->p; + GetWifi2MeshAPStatus_Request request; + GetWifi2MeshAPStatus_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_WIFI2_MESH_AP_STATUS, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_ssid, response.ssid, 32); + memcpy(ret_ip, response.ip, 4 * sizeof(uint8_t)); + memcpy(ret_subnet_mask, response.subnet_mask, 4 * sizeof(uint8_t)); + memcpy(ret_gateway, response.gateway, 4 * sizeof(uint8_t)); + memcpy(ret_mac_address, response.mac_address, 6 * sizeof(uint8_t)); + + return ret; +} + +int master_set_bricklet_xmc_flash_config(Master *master, uint32_t config, uint32_t parameter1, uint32_t parameter2, uint8_t data[52], uint32_t *ret_return_value, uint8_t ret_return_data[60]) { + DevicePrivate *device_p = master->p; + SetBrickletXMCFlashConfig_Request request; + SetBrickletXMCFlashConfig_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_BRICKLET_XMC_FLASH_CONFIG, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.config = leconvert_uint32_to(config); + request.parameter1 = leconvert_uint32_to(parameter1); + request.parameter2 = leconvert_uint32_to(parameter2); + memcpy(request.data, data, 52 * sizeof(uint8_t)); + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_return_value = leconvert_uint32_from(response.return_value); + memcpy(ret_return_data, response.return_data, 60 * sizeof(uint8_t)); + + return ret; +} + +int master_set_bricklet_xmc_flash_data(Master *master, uint8_t data[64], uint32_t *ret_return_data) { + DevicePrivate *device_p = master->p; + SetBrickletXMCFlashData_Request request; + SetBrickletXMCFlashData_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_BRICKLET_XMC_FLASH_DATA, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.data, data, 64 * sizeof(uint8_t)); + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_return_data = leconvert_uint32_from(response.return_data); + + return ret; +} + +int master_set_bricklets_enabled(Master *master, bool bricklets_enabled) { + DevicePrivate *device_p = master->p; + SetBrickletsEnabled_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_BRICKLETS_ENABLED, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.bricklets_enabled = bricklets_enabled ? 1 : 0; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_bricklets_enabled(Master *master, bool *ret_bricklets_enabled) { + DevicePrivate *device_p = master->p; + GetBrickletsEnabled_Request request; + GetBrickletsEnabled_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_BRICKLETS_ENABLED, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_bricklets_enabled = response.bricklets_enabled != 0; + + return ret; +} + +int master_set_spitfp_baudrate_config(Master *master, bool enable_dynamic_baudrate, uint32_t minimum_dynamic_baudrate) { + DevicePrivate *device_p = master->p; + SetSPITFPBaudrateConfig_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_SPITFP_BAUDRATE_CONFIG, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.enable_dynamic_baudrate = enable_dynamic_baudrate ? 1 : 0; + request.minimum_dynamic_baudrate = leconvert_uint32_to(minimum_dynamic_baudrate); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_spitfp_baudrate_config(Master *master, bool *ret_enable_dynamic_baudrate, uint32_t *ret_minimum_dynamic_baudrate) { + DevicePrivate *device_p = master->p; + GetSPITFPBaudrateConfig_Request request; + GetSPITFPBaudrateConfig_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_SPITFP_BAUDRATE_CONFIG, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_enable_dynamic_baudrate = response.enable_dynamic_baudrate != 0; + *ret_minimum_dynamic_baudrate = leconvert_uint32_from(response.minimum_dynamic_baudrate); + + return ret; +} + +int master_get_send_timeout_count(Master *master, uint8_t communication_method, uint32_t *ret_timeout_count) { + DevicePrivate *device_p = master->p; + GetSendTimeoutCount_Request request; + GetSendTimeoutCount_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_SEND_TIMEOUT_COUNT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.communication_method = communication_method; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_timeout_count = leconvert_uint32_from(response.timeout_count); + + return ret; +} + +int master_set_spitfp_baudrate(Master *master, char bricklet_port, uint32_t baudrate) { + DevicePrivate *device_p = master->p; + SetSPITFPBaudrate_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_SET_SPITFP_BAUDRATE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.bricklet_port = bricklet_port; + request.baudrate = leconvert_uint32_to(baudrate); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_get_spitfp_baudrate(Master *master, char bricklet_port, uint32_t *ret_baudrate) { + DevicePrivate *device_p = master->p; + GetSPITFPBaudrate_Request request; + GetSPITFPBaudrate_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_SPITFP_BAUDRATE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.bricklet_port = bricklet_port; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_baudrate = leconvert_uint32_from(response.baudrate); + + return ret; +} + +int master_get_spitfp_error_count(Master *master, char bricklet_port, uint32_t *ret_error_count_ack_checksum, uint32_t *ret_error_count_message_checksum, uint32_t *ret_error_count_frame, uint32_t *ret_error_count_overflow) { + DevicePrivate *device_p = master->p; + GetSPITFPErrorCount_Request request; + GetSPITFPErrorCount_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_SPITFP_ERROR_COUNT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.bricklet_port = bricklet_port; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_error_count_ack_checksum = leconvert_uint32_from(response.error_count_ack_checksum); + *ret_error_count_message_checksum = leconvert_uint32_from(response.error_count_message_checksum); + *ret_error_count_frame = leconvert_uint32_from(response.error_count_frame); + *ret_error_count_overflow = leconvert_uint32_from(response.error_count_overflow); + + return ret; +} + +int master_enable_status_led(Master *master) { + DevicePrivate *device_p = master->p; + EnableStatusLED_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_ENABLE_STATUS_LED, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_disable_status_led(Master *master) { + DevicePrivate *device_p = master->p; + DisableStatusLED_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_DISABLE_STATUS_LED, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_is_status_led_enabled(Master *master, bool *ret_enabled) { + DevicePrivate *device_p = master->p; + IsStatusLEDEnabled_Request request; + IsStatusLEDEnabled_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_IS_STATUS_LED_ENABLED, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_enabled = response.enabled != 0; + + return ret; +} + +int master_get_protocol1_bricklet_name(Master *master, char port, uint8_t *ret_protocol_version, uint8_t ret_firmware_version[3], char ret_name[40]) { + DevicePrivate *device_p = master->p; + GetProtocol1BrickletName_Request request; + GetProtocol1BrickletName_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_PROTOCOL1_BRICKLET_NAME, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.port = port; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_protocol_version = response.protocol_version; + memcpy(ret_firmware_version, response.firmware_version, 3 * sizeof(uint8_t)); + memcpy(ret_name, response.name, 40); + + return ret; +} + +int master_get_chip_temperature(Master *master, int16_t *ret_temperature) { + DevicePrivate *device_p = master->p; + GetChipTemperature_Request request; + GetChipTemperature_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_CHIP_TEMPERATURE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_temperature = leconvert_int16_from(response.temperature); + + return ret; +} + +int master_reset(Master *master) { + DevicePrivate *device_p = master->p; + Reset_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_RESET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_write_bricklet_plugin(Master *master, char port, uint8_t offset, uint8_t chunk[32]) { + DevicePrivate *device_p = master->p; + WriteBrickletPlugin_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_WRITE_BRICKLET_PLUGIN, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.port = port; + request.offset = offset; + memcpy(request.chunk, chunk, 32 * sizeof(uint8_t)); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int master_read_bricklet_plugin(Master *master, char port, uint8_t offset, uint8_t ret_chunk[32]) { + DevicePrivate *device_p = master->p; + ReadBrickletPlugin_Request request; + ReadBrickletPlugin_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_READ_BRICKLET_PLUGIN, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.port = port; + request.offset = offset; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_chunk, response.chunk, 32 * sizeof(uint8_t)); + + return ret; +} + +int master_get_identity(Master *master, char ret_uid[8], char ret_connected_uid[8], char *ret_position, uint8_t ret_hardware_version[3], uint8_t ret_firmware_version[3], uint16_t *ret_device_identifier) { + DevicePrivate *device_p = master->p; + GetIdentity_Request request; + GetIdentity_Response response; + int ret; + + ret = packet_header_create(&request.header, sizeof(request), MASTER_FUNCTION_GET_IDENTITY, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_uid, response.uid, 8); + memcpy(ret_connected_uid, response.connected_uid, 8); + *ret_position = response.position; + memcpy(ret_hardware_version, response.hardware_version, 3 * sizeof(uint8_t)); + memcpy(ret_firmware_version, response.firmware_version, 3 * sizeof(uint8_t)); + *ret_device_identifier = leconvert_uint16_from(response.device_identifier); + + return ret; +} + +#ifdef __cplusplus +} +#endif diff --git a/tinkerforge/brick_master.h b/tinkerforge/brick_master.h new file mode 100644 index 0000000..8130175 --- /dev/null +++ b/tinkerforge/brick_master.h @@ -0,0 +1,3019 @@ +/* *********************************************************** + * This file was automatically generated on 2021-01-15. * + * * + * C/C++ Bindings Version 2.1.31 * + * * + * If you have a bugfix for this file and want to commit it, * + * please fix the bug in the generator. You can find a link * + * to the generators git repository on tinkerforge.com * + *************************************************************/ + +#ifndef BRICK_MASTER_H +#define BRICK_MASTER_H + +#include "ip_connection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup BrickMaster Master Brick + */ + +/** + * \ingroup BrickMaster + * + * Basis to build stacks and has 4 Bricklet ports + */ +typedef Device Master; + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_STACK_VOLTAGE 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_STACK_CURRENT 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_EXTENSION_TYPE 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_EXTENSION_TYPE 4 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_IS_CHIBI_PRESENT 5 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_CHIBI_ADDRESS 6 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_CHIBI_ADDRESS 7 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_CHIBI_MASTER_ADDRESS 8 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_CHIBI_MASTER_ADDRESS 9 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_CHIBI_SLAVE_ADDRESS 10 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_CHIBI_SLAVE_ADDRESS 11 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_CHIBI_SIGNAL_STRENGTH 12 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_CHIBI_ERROR_LOG 13 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_CHIBI_FREQUENCY 14 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_CHIBI_FREQUENCY 15 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_CHIBI_CHANNEL 16 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_CHIBI_CHANNEL 17 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_IS_RS485_PRESENT 18 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_RS485_ADDRESS 19 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_RS485_ADDRESS 20 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_RS485_SLAVE_ADDRESS 21 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_RS485_SLAVE_ADDRESS 22 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_RS485_ERROR_LOG 23 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_RS485_CONFIGURATION 24 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_RS485_CONFIGURATION 25 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_IS_WIFI_PRESENT 26 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI_CONFIGURATION 27 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI_CONFIGURATION 28 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI_ENCRYPTION 29 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI_ENCRYPTION 30 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI_STATUS 31 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_REFRESH_WIFI_STATUS 32 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI_CERTIFICATE 33 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI_CERTIFICATE 34 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI_POWER_MODE 35 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI_POWER_MODE 36 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI_BUFFER_INFO 37 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI_REGULATORY_DOMAIN 38 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI_REGULATORY_DOMAIN 39 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_USB_VOLTAGE 40 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_LONG_WIFI_KEY 41 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_LONG_WIFI_KEY 42 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI_HOSTNAME 43 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI_HOSTNAME 44 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_STACK_CURRENT_CALLBACK_PERIOD 45 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_STACK_CURRENT_CALLBACK_PERIOD 46 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_STACK_VOLTAGE_CALLBACK_PERIOD 47 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_STACK_VOLTAGE_CALLBACK_PERIOD 48 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_USB_VOLTAGE_CALLBACK_PERIOD 49 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_USB_VOLTAGE_CALLBACK_PERIOD 50 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_STACK_CURRENT_CALLBACK_THRESHOLD 51 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_STACK_CURRENT_CALLBACK_THRESHOLD 52 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_STACK_VOLTAGE_CALLBACK_THRESHOLD 53 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_STACK_VOLTAGE_CALLBACK_THRESHOLD 54 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_USB_VOLTAGE_CALLBACK_THRESHOLD 55 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_USB_VOLTAGE_CALLBACK_THRESHOLD 56 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_DEBOUNCE_PERIOD 57 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_DEBOUNCE_PERIOD 58 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_IS_ETHERNET_PRESENT 65 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_ETHERNET_CONFIGURATION 66 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_ETHERNET_CONFIGURATION 67 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_ETHERNET_STATUS 68 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_ETHERNET_HOSTNAME 69 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_ETHERNET_MAC_ADDRESS 70 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_ETHERNET_WEBSOCKET_CONFIGURATION 71 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_ETHERNET_WEBSOCKET_CONFIGURATION 72 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_ETHERNET_AUTHENTICATION_SECRET 73 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_ETHERNET_AUTHENTICATION_SECRET 74 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI_AUTHENTICATION_SECRET 75 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI_AUTHENTICATION_SECRET 76 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_CONNECTION_TYPE 77 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_IS_WIFI2_PRESENT 78 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_START_WIFI2_BOOTLOADER 79 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_WRITE_WIFI2_SERIAL_PORT 80 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_READ_WIFI2_SERIAL_PORT 81 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI2_AUTHENTICATION_SECRET 82 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_AUTHENTICATION_SECRET 83 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI2_CONFIGURATION 84 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_CONFIGURATION 85 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_STATUS 86 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI2_CLIENT_CONFIGURATION 87 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_CLIENT_CONFIGURATION 88 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI2_CLIENT_HOSTNAME 89 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_CLIENT_HOSTNAME 90 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI2_CLIENT_PASSWORD 91 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_CLIENT_PASSWORD 92 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI2_AP_CONFIGURATION 93 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_AP_CONFIGURATION 94 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI2_AP_PASSWORD 95 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_AP_PASSWORD 96 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SAVE_WIFI2_CONFIGURATION 97 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_FIRMWARE_VERSION 98 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_ENABLE_WIFI2_STATUS_LED 99 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_DISABLE_WIFI2_STATUS_LED 100 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_IS_WIFI2_STATUS_LED_ENABLED 101 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI2_MESH_CONFIGURATION 102 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_MESH_CONFIGURATION 103 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI2_MESH_ROUTER_SSID 104 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_MESH_ROUTER_SSID 105 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_WIFI2_MESH_ROUTER_PASSWORD 106 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_MESH_ROUTER_PASSWORD 107 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_MESH_COMMON_STATUS 108 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_MESH_CLIENT_STATUS 109 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_WIFI2_MESH_AP_STATUS 110 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_BRICKLET_XMC_FLASH_CONFIG 111 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_BRICKLET_XMC_FLASH_DATA 112 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_BRICKLETS_ENABLED 113 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_BRICKLETS_ENABLED 114 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_SPITFP_BAUDRATE_CONFIG 231 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_SPITFP_BAUDRATE_CONFIG 232 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_SEND_TIMEOUT_COUNT 233 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_SET_SPITFP_BAUDRATE 234 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_SPITFP_BAUDRATE 235 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_SPITFP_ERROR_COUNT 237 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_ENABLE_STATUS_LED 238 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_DISABLE_STATUS_LED 239 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_IS_STATUS_LED_ENABLED 240 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_PROTOCOL1_BRICKLET_NAME 241 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_CHIP_TEMPERATURE 242 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_RESET 243 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_WRITE_BRICKLET_PLUGIN 246 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_READ_BRICKLET_PLUGIN 247 + +/** + * \ingroup BrickMaster + */ +#define MASTER_FUNCTION_GET_IDENTITY 255 + +/** + * \ingroup BrickMaster + * + * Signature: \code void callback(uint16_t current, void *user_data) \endcode + * + * This callback is triggered periodically with the period that is set by + * {@link master_set_stack_current_callback_period}. The parameter is the current + * of the sensor. + * + * The {@link MASTER_CALLBACK_STACK_CURRENT} callback is only triggered if the current has changed + * since the last triggering. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +#define MASTER_CALLBACK_STACK_CURRENT 59 + +/** + * \ingroup BrickMaster + * + * Signature: \code void callback(uint16_t voltage, void *user_data) \endcode + * + * This callback is triggered periodically with the period that is set by + * {@link master_set_stack_voltage_callback_period}. The parameter is the voltage + * of the sensor. + * + * The {@link MASTER_CALLBACK_STACK_VOLTAGE} callback is only triggered if the voltage has changed + * since the last triggering. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +#define MASTER_CALLBACK_STACK_VOLTAGE 60 + +/** + * \ingroup BrickMaster + * + * Signature: \code void callback(uint16_t voltage, void *user_data) \endcode + * + * This callback is triggered periodically with the period that is set by + * {@link master_set_usb_voltage_callback_period}. The parameter is the USB + * voltage. + * + * The {@link MASTER_CALLBACK_USB_VOLTAGE} callback is only triggered if the USB voltage has changed + * since the last triggering. + * + * Does not work with hardware version 2.1. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +#define MASTER_CALLBACK_USB_VOLTAGE 61 + +/** + * \ingroup BrickMaster + * + * Signature: \code void callback(uint16_t current, void *user_data) \endcode + * + * This callback is triggered when the threshold as set by + * {@link master_set_stack_current_callback_threshold} is reached. + * The parameter is the stack current. + * + * If the threshold keeps being reached, the callback is triggered periodically + * with the period as set by {@link master_set_debounce_period}. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +#define MASTER_CALLBACK_STACK_CURRENT_REACHED 62 + +/** + * \ingroup BrickMaster + * + * Signature: \code void callback(uint16_t voltage, void *user_data) \endcode + * + * This callback is triggered when the threshold as set by + * {@link master_set_stack_voltage_callback_threshold} is reached. + * The parameter is the stack voltage. + * + * If the threshold keeps being reached, the callback is triggered periodically + * with the period as set by {@link master_set_debounce_period}. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +#define MASTER_CALLBACK_STACK_VOLTAGE_REACHED 63 + +/** + * \ingroup BrickMaster + * + * Signature: \code void callback(uint16_t voltage, void *user_data) \endcode + * + * This callback is triggered when the threshold as set by + * {@link master_set_usb_voltage_callback_threshold} is reached. + * The parameter is the voltage of the sensor. + * + * If the threshold keeps being reached, the callback is triggered periodically + * with the period as set by {@link master_set_debounce_period}. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +#define MASTER_CALLBACK_USB_VOLTAGE_REACHED 64 + + +/** + * \ingroup BrickMaster + */ +#define MASTER_EXTENSION_TYPE_CHIBI 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_EXTENSION_TYPE_RS485 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_EXTENSION_TYPE_WIFI 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_EXTENSION_TYPE_ETHERNET 4 + +/** + * \ingroup BrickMaster + */ +#define MASTER_EXTENSION_TYPE_WIFI2 5 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CHIBI_FREQUENCY_OQPSK_868_MHZ 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CHIBI_FREQUENCY_OQPSK_915_MHZ 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CHIBI_FREQUENCY_OQPSK_780_MHZ 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CHIBI_FREQUENCY_BPSK40_915_MHZ 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_RS485_PARITY_NONE 'n' + +/** + * \ingroup BrickMaster + */ +#define MASTER_RS485_PARITY_EVEN 'e' + +/** + * \ingroup BrickMaster + */ +#define MASTER_RS485_PARITY_ODD 'o' + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_CONNECTION_DHCP 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_CONNECTION_STATIC_IP 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_CONNECTION_ACCESS_POINT_DHCP 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_CONNECTION_ACCESS_POINT_STATIC_IP 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_CONNECTION_AD_HOC_DHCP 4 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_CONNECTION_AD_HOC_STATIC_IP 5 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_ENCRYPTION_WPA_WPA2 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_ENCRYPTION_WPA_ENTERPRISE 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_ENCRYPTION_WEP 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_ENCRYPTION_NO_ENCRYPTION 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_EAP_OPTION_OUTER_AUTH_EAP_FAST 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_EAP_OPTION_OUTER_AUTH_EAP_TLS 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_EAP_OPTION_OUTER_AUTH_EAP_TTLS 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_EAP_OPTION_OUTER_AUTH_EAP_PEAP 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_EAP_OPTION_INNER_AUTH_EAP_MSCHAP 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_EAP_OPTION_INNER_AUTH_EAP_GTC 4 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_EAP_OPTION_CERT_TYPE_CA_CERT 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_EAP_OPTION_CERT_TYPE_CLIENT_CERT 8 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_EAP_OPTION_CERT_TYPE_PRIVATE_KEY 16 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_STATE_DISASSOCIATED 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_STATE_ASSOCIATED 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_STATE_ASSOCIATING 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_STATE_ERROR 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_STATE_NOT_INITIALIZED_YET 255 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_POWER_MODE_FULL_SPEED 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_POWER_MODE_LOW_POWER 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_DOMAIN_CHANNEL_1TO11 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_DOMAIN_CHANNEL_1TO13 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI_DOMAIN_CHANNEL_1TO14 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_THRESHOLD_OPTION_OFF 'x' + +/** + * \ingroup BrickMaster + */ +#define MASTER_THRESHOLD_OPTION_OUTSIDE 'o' + +/** + * \ingroup BrickMaster + */ +#define MASTER_THRESHOLD_OPTION_INSIDE 'i' + +/** + * \ingroup BrickMaster + */ +#define MASTER_THRESHOLD_OPTION_SMALLER '<' + +/** + * \ingroup BrickMaster + */ +#define MASTER_THRESHOLD_OPTION_GREATER '>' + +/** + * \ingroup BrickMaster + */ +#define MASTER_ETHERNET_CONNECTION_DHCP 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_ETHERNET_CONNECTION_STATIC_IP 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CONNECTION_TYPE_NONE 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CONNECTION_TYPE_USB 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CONNECTION_TYPE_SPI_STACK 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CONNECTION_TYPE_CHIBI 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CONNECTION_TYPE_RS485 4 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CONNECTION_TYPE_WIFI 5 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CONNECTION_TYPE_ETHERNET 6 + +/** + * \ingroup BrickMaster + */ +#define MASTER_CONNECTION_TYPE_WIFI2 7 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_PHY_MODE_B 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_PHY_MODE_G 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_PHY_MODE_N 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_CLIENT_STATUS_IDLE 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_CLIENT_STATUS_CONNECTING 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_CLIENT_STATUS_WRONG_PASSWORD 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_CLIENT_STATUS_NO_AP_FOUND 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_CLIENT_STATUS_CONNECT_FAILED 4 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_CLIENT_STATUS_GOT_IP 5 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_CLIENT_STATUS_UNKNOWN 255 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_AP_ENCRYPTION_OPEN 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_AP_ENCRYPTION_WEP 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_AP_ENCRYPTION_WPA_PSK 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_AP_ENCRYPTION_WPA2_PSK 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_AP_ENCRYPTION_WPA_WPA2_PSK 4 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_MESH_STATUS_DISABLED 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_MESH_STATUS_WIFI_CONNECTING 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_MESH_STATUS_GOT_IP 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_MESH_STATUS_MESH_LOCAL 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_MESH_STATUS_MESH_ONLINE 4 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_MESH_STATUS_AP_AVAILABLE 5 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_MESH_STATUS_AP_SETUP 6 + +/** + * \ingroup BrickMaster + */ +#define MASTER_WIFI2_MESH_STATUS_LEAF_AVAILABLE 7 + +/** + * \ingroup BrickMaster + */ +#define MASTER_COMMUNICATION_METHOD_NONE 0 + +/** + * \ingroup BrickMaster + */ +#define MASTER_COMMUNICATION_METHOD_USB 1 + +/** + * \ingroup BrickMaster + */ +#define MASTER_COMMUNICATION_METHOD_SPI_STACK 2 + +/** + * \ingroup BrickMaster + */ +#define MASTER_COMMUNICATION_METHOD_CHIBI 3 + +/** + * \ingroup BrickMaster + */ +#define MASTER_COMMUNICATION_METHOD_RS485 4 + +/** + * \ingroup BrickMaster + */ +#define MASTER_COMMUNICATION_METHOD_WIFI 5 + +/** + * \ingroup BrickMaster + */ +#define MASTER_COMMUNICATION_METHOD_ETHERNET 6 + +/** + * \ingroup BrickMaster + */ +#define MASTER_COMMUNICATION_METHOD_WIFI_V2 7 + +/** + * \ingroup BrickMaster + * + * This constant is used to identify a Master Brick. + * + * The {@link master_get_identity} function and the + * {@link IPCON_CALLBACK_ENUMERATE} callback of the IP Connection have a + * \c device_identifier parameter to specify the Brick's or Bricklet's type. + */ +#define MASTER_DEVICE_IDENTIFIER 13 + +/** + * \ingroup BrickMaster + * + * This constant represents the display name of a Master Brick. + */ +#define MASTER_DEVICE_DISPLAY_NAME "Master Brick" + +/** + * \ingroup BrickMaster + * + * Creates the device object \c master with the unique device ID \c uid and adds + * it to the IPConnection \c ipcon. + */ +void master_create(Master *master, const char *uid, IPConnection *ipcon); + +/** + * \ingroup BrickMaster + * + * Removes the device object \c master from its IPConnection and destroys it. + * The device object cannot be used anymore afterwards. + */ +void master_destroy(Master *master); + +/** + * \ingroup BrickMaster + * + * Returns the response expected flag for the function specified by the + * \c function_id parameter. It is *true* if the function is expected to + * send a response, *false* otherwise. + * + * For getter functions this is enabled by default and cannot be disabled, + * because those functions will always send a response. For callback + * configuration functions it is enabled by default too, but can be disabled + * via the master_set_response_expected function. For setter functions it is + * disabled by default and can be enabled. + * + * Enabling the response expected flag for a setter function allows to + * detect timeouts and other error conditions calls of this setter as well. + * The device will then send a response for this purpose. If this flag is + * disabled for a setter function then no response is sent and errors are + * silently ignored, because they cannot be detected. + */ +int master_get_response_expected(Master *master, uint8_t function_id, bool *ret_response_expected); + +/** + * \ingroup BrickMaster + * + * Changes the response expected flag of the function specified by the + * \c function_id parameter. This flag can only be changed for setter + * (default value: *false*) and callback configuration functions + * (default value: *true*). For getter functions it is always enabled. + * + * Enabling the response expected flag for a setter function allows to detect + * timeouts and other error conditions calls of this setter as well. The device + * will then send a response for this purpose. If this flag is disabled for a + * setter function then no response is sent and errors are silently ignored, + * because they cannot be detected. + */ +int master_set_response_expected(Master *master, uint8_t function_id, bool response_expected); + +/** + * \ingroup BrickMaster + * + * Changes the response expected flag for all setter and callback configuration + * functions of this device at once. + */ +int master_set_response_expected_all(Master *master, bool response_expected); + +/** + * \ingroup BrickMaster + * + * Registers the given \c function with the given \c callback_id. The + * \c user_data will be passed as the last parameter to the \c function. + */ +void master_register_callback(Master *master, int16_t callback_id, void (*function)(void), void *user_data); + +/** + * \ingroup BrickMaster + * + * Returns the API version (major, minor, release) of the bindings for this + * device. + */ +int master_get_api_version(Master *master, uint8_t ret_api_version[3]); + +/** + * \ingroup BrickMaster + * + * Returns the stack voltage. The stack voltage is the + * voltage that is supplied via the stack, i.e. it is given by a + * Step-Down or Step-Up Power Supply. + * + * \note + * It is not possible to measure voltages supplied per PoE or USB with this function. + */ +int master_get_stack_voltage(Master *master, uint16_t *ret_voltage); + +/** + * \ingroup BrickMaster + * + * Returns the stack current. The stack current is the + * current that is drawn via the stack, i.e. it is given by a + * Step-Down or Step-Up Power Supply. + * + * \note + * It is not possible to measure the current drawn via PoE or USB with this function. + */ +int master_get_stack_current(Master *master, uint16_t *ret_current); + +/** + * \ingroup BrickMaster + * + * Writes the extension type to the EEPROM of a specified extension. + * The extension is either 0 or 1 (0 is the lower one, 1 is the upper one, + * if only one extension is present use 0). + * + * Possible extension types: + * + * \verbatim + * "Type", "Description" + * + * "1", "Chibi" + * "2", "RS485" + * "3", "WIFI" + * "4", "Ethernet" + * "5", "WIFI 2.0" + * \endverbatim + * + * The extension type is already set when bought and it can be set with the + * Brick Viewer, it is unlikely that you need this function. + */ +int master_set_extension_type(Master *master, uint8_t extension, uint32_t exttype); + +/** + * \ingroup BrickMaster + * + * Returns the type for a given extension as set by {@link master_set_extension_type}. + */ +int master_get_extension_type(Master *master, uint8_t extension, uint32_t *ret_exttype); + +/** + * \ingroup BrickMaster + * + * Returns *true* if the Master Brick is at position 0 in the stack and a Chibi + * Extension is available. + */ +int master_is_chibi_present(Master *master, bool *ret_present); + +/** + * \ingroup BrickMaster + * + * Sets the address belonging to the Chibi Extension. + * + * It is possible to set the address with the Brick Viewer and it will be + * saved in the EEPROM of the Chibi Extension, it does not + * have to be set on every startup. + */ +int master_set_chibi_address(Master *master, uint8_t address); + +/** + * \ingroup BrickMaster + * + * Returns the address as set by {@link master_set_chibi_address}. + */ +int master_get_chibi_address(Master *master, uint8_t *ret_address); + +/** + * \ingroup BrickMaster + * + * Sets the address of the Chibi Master. This address is used if the + * Chibi Extension is used as slave (i.e. it does not have a USB connection). + * + * It is possible to set the address with the Brick Viewer and it will be + * saved in the EEPROM of the Chibi Extension, it does not + * have to be set on every startup. + */ +int master_set_chibi_master_address(Master *master, uint8_t address); + +/** + * \ingroup BrickMaster + * + * Returns the address as set by {@link master_set_chibi_master_address}. + */ +int master_get_chibi_master_address(Master *master, uint8_t *ret_address); + +/** + * \ingroup BrickMaster + * + * Sets up to 254 slave addresses. 0 has a + * special meaning, it is used as list terminator and not allowed as normal slave + * address. The address numeration (via \c num parameter) has to be used + * ascending from 0. For example: If you use the Chibi Extension in Master mode + * (i.e. the stack has an USB connection) and you want to talk to three other + * Chibi stacks with the slave addresses 17, 23, and 42, you should call with + * ``(0, 17)``, ``(1, 23)``, ``(2, 42)`` and ``(3, 0)``. The last call with + * ``(3, 0)`` is a list terminator and indicates that the Chibi slave address + * list contains 3 addresses in this case. + * + * It is possible to set the addresses with the Brick Viewer, that will take care + * of correct address numeration and list termination. + * + * The slave addresses will be saved in the EEPROM of the Chibi Extension, they + * don't have to be set on every startup. + */ +int master_set_chibi_slave_address(Master *master, uint8_t num, uint8_t address); + +/** + * \ingroup BrickMaster + * + * Returns the slave address for a given \c num as set by + * {@link master_set_chibi_slave_address}. + */ +int master_get_chibi_slave_address(Master *master, uint8_t num, uint8_t *ret_address); + +/** + * \ingroup BrickMaster + * + * Returns the signal strength in dBm. The signal strength updates every time a + * packet is received. + */ +int master_get_chibi_signal_strength(Master *master, uint8_t *ret_signal_strength); + +/** + * \ingroup BrickMaster + * + * Returns underrun, CRC error, no ACK and overflow error counts of the Chibi + * communication. If these errors start rising, it is likely that either the + * distance between two Chibi stacks is becoming too big or there are + * interferences. + */ +int master_get_chibi_error_log(Master *master, uint16_t *ret_underrun, uint16_t *ret_crc_error, uint16_t *ret_no_ack, uint16_t *ret_overflow); + +/** + * \ingroup BrickMaster + * + * Sets the Chibi frequency range for the Chibi Extension. Possible values are: + * + * \verbatim + * "Type", "Description" + * + * "0", "OQPSK 868MHz (Europe)" + * "1", "OQPSK 915MHz (US)" + * "2", "OQPSK 780MHz (China)" + * "3", "BPSK40 915MHz" + * \endverbatim + * + * It is possible to set the frequency with the Brick Viewer and it will be + * saved in the EEPROM of the Chibi Extension, it does not + * have to be set on every startup. + */ +int master_set_chibi_frequency(Master *master, uint8_t frequency); + +/** + * \ingroup BrickMaster + * + * Returns the frequency value as set by {@link master_set_chibi_frequency}. + */ +int master_get_chibi_frequency(Master *master, uint8_t *ret_frequency); + +/** + * \ingroup BrickMaster + * + * Sets the channel used by the Chibi Extension. Possible channels are + * different for different frequencies: + * + * \verbatim + * "Frequency", "Possible Channels" + * + * "OQPSK 868MHz (Europe)", "0" + * "OQPSK 915MHz (US)", "1, 2, 3, 4, 5, 6, 7, 8, 9, 10" + * "OQPSK 780MHz (China)", "0, 1, 2, 3" + * "BPSK40 915MHz", "1, 2, 3, 4, 5, 6, 7, 8, 9, 10" + * \endverbatim + * + * It is possible to set the channel with the Brick Viewer and it will be + * saved in the EEPROM of the Chibi Extension, it does not + * have to be set on every startup. + */ +int master_set_chibi_channel(Master *master, uint8_t channel); + +/** + * \ingroup BrickMaster + * + * Returns the channel as set by {@link master_set_chibi_channel}. + */ +int master_get_chibi_channel(Master *master, uint8_t *ret_channel); + +/** + * \ingroup BrickMaster + * + * Returns *true* if the Master Brick is at position 0 in the stack and a RS485 + * Extension is available. + */ +int master_is_rs485_present(Master *master, bool *ret_present); + +/** + * \ingroup BrickMaster + * + * Sets the address (0-255) belonging to the RS485 Extension. + * + * Set to 0 if the RS485 Extension should be the RS485 Master (i.e. + * connected to a PC via USB). + * + * It is possible to set the address with the Brick Viewer and it will be + * saved in the EEPROM of the RS485 Extension, it does not + * have to be set on every startup. + */ +int master_set_rs485_address(Master *master, uint8_t address); + +/** + * \ingroup BrickMaster + * + * Returns the address as set by {@link master_set_rs485_address}. + */ +int master_get_rs485_address(Master *master, uint8_t *ret_address); + +/** + * \ingroup BrickMaster + * + * Sets up to 255 slave addresses. Valid addresses are in range 1-255. 0 has a + * special meaning, it is used as list terminator and not allowed as normal slave + * address. The address numeration (via ``num`` parameter) has to be used + * ascending from 0. For example: If you use the RS485 Extension in Master mode + * (i.e. the stack has an USB connection) and you want to talk to three other + * RS485 stacks with the addresses 17, 23, and 42, you should call with + * ``(0, 17)``, ``(1, 23)``, ``(2, 42)`` and ``(3, 0)``. The last call with + * ``(3, 0)`` is a list terminator and indicates that the RS485 slave address list + * contains 3 addresses in this case. + * + * It is possible to set the addresses with the Brick Viewer, that will take care + * of correct address numeration and list termination. + * + * The slave addresses will be saved in the EEPROM of the Chibi Extension, they + * don't have to be set on every startup. + */ +int master_set_rs485_slave_address(Master *master, uint8_t num, uint8_t address); + +/** + * \ingroup BrickMaster + * + * Returns the slave address for a given ``num`` as set by + * {@link master_set_rs485_slave_address}. + */ +int master_get_rs485_slave_address(Master *master, uint8_t num, uint8_t *ret_address); + +/** + * \ingroup BrickMaster + * + * Returns CRC error counts of the RS485 communication. + * If this counter starts rising, it is likely that the distance + * between the RS485 nodes is too big or there is some kind of + * interference. + */ +int master_get_rs485_error_log(Master *master, uint16_t *ret_crc_error); + +/** + * \ingroup BrickMaster + * + * Sets the configuration of the RS485 Extension. The + * Master Brick will try to match the given baud rate as exactly as possible. + * The maximum recommended baud rate is 2000000 (2MBd). + * Possible values for parity are 'n' (none), 'e' (even) and 'o' (odd). + * + * If your RS485 is unstable (lost messages etc.), the first thing you should + * try is to decrease the speed. On very large bus (e.g. 1km), you probably + * should use a value in the range of 100000 (100kBd). + * + * The values are stored in the EEPROM and only applied on startup. That means + * you have to restart the Master Brick after configuration. + */ +int master_set_rs485_configuration(Master *master, uint32_t speed, char parity, uint8_t stopbits); + +/** + * \ingroup BrickMaster + * + * Returns the configuration as set by {@link master_set_rs485_configuration}. + */ +int master_get_rs485_configuration(Master *master, uint32_t *ret_speed, char *ret_parity, uint8_t *ret_stopbits); + +/** + * \ingroup BrickMaster + * + * Returns *true* if the Master Brick is at position 0 in the stack and a WIFI + * Extension is available. + */ +int master_is_wifi_present(Master *master, bool *ret_present); + +/** + * \ingroup BrickMaster + * + * Sets the configuration of the WIFI Extension. The ``ssid`` can have a max length + * of 32 characters. Possible values for ``connection`` are: + * + * \verbatim + * "Value", "Description" + * + * "0", "DHCP" + * "1", "Static IP" + * "2", "Access Point: DHCP" + * "3", "Access Point: Static IP" + * "4", "Ad Hoc: DHCP" + * "5", "Ad Hoc: Static IP" + * \endverbatim + * + * If you set ``connection`` to one of the static IP options then you have to + * supply ``ip``, ``subnet_mask`` and ``gateway`` as an array of size 4 (first + * element of the array is the least significant byte of the address). If + * ``connection`` is set to one of the DHCP options then ``ip``, ``subnet_mask`` + * and ``gateway`` are ignored, you can set them to 0. + * + * The last parameter is the port that your program will connect to. + * + * The values are stored in the EEPROM and only applied on startup. That means + * you have to restart the Master Brick after configuration. + * + * It is recommended to use the Brick Viewer to set the WIFI configuration. + */ +int master_set_wifi_configuration(Master *master, const char ssid[32], uint8_t connection, uint8_t ip[4], uint8_t subnet_mask[4], uint8_t gateway[4], uint16_t port); + +/** + * \ingroup BrickMaster + * + * Returns the configuration as set by {@link master_set_wifi_configuration}. + */ +int master_get_wifi_configuration(Master *master, char ret_ssid[32], uint8_t *ret_connection, uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint16_t *ret_port); + +/** + * \ingroup BrickMaster + * + * Sets the encryption of the WIFI Extension. The first parameter is the + * type of the encryption. Possible values are: + * + * \verbatim + * "Value", "Description" + * + * "0", "WPA/WPA2" + * "1", "WPA Enterprise (EAP-FAST, EAP-TLS, EAP-TTLS, PEAP)" + * "2", "WEP" + * "3", "No Encryption" + * \endverbatim + * + * The ``key`` has a max length of 50 characters and is used if ``encryption`` + * is set to 0 or 2 (WPA/WPA2 or WEP). Otherwise the value is ignored. + * + * For WPA/WPA2 the key has to be at least 8 characters long. If you want to set + * a key with more than 50 characters, see {@link master_set_long_wifi_key}. + * + * For WEP the key has to be either 10 or 26 hexadecimal digits long. It is + * possible to set the WEP ``key_index`` (1-4). If you don't know your + * ``key_index``, it is likely 1. + * + * If you choose WPA Enterprise as encryption, you have to set ``eap_options`` and + * the length of the certificates (for other encryption types these parameters + * are ignored). The certificates + * themselves can be set with {@link master_set_wifi_certificate}. ``eap_options`` consist + * of the outer authentication (bits 1-2), inner authentication (bit 3) and + * certificate type (bits 4-5): + * + * \verbatim + * "Option", "Bits", "Description" + * + * "outer authentication", "1-2", "0=EAP-FAST, 1=EAP-TLS, 2=EAP-TTLS, 3=EAP-PEAP" + * "inner authentication", "3", "0=EAP-MSCHAP, 1=EAP-GTC" + * "certificate type", "4-5", "0=CA Certificate, 1=Client Certificate, 2=Private Key" + * \endverbatim + * + * Example for EAP-TTLS + EAP-GTC + Private Key: ``option = 2 | (1 << 2) | (2 << 3)``. + * + * The values are stored in the EEPROM and only applied on startup. That means + * you have to restart the Master Brick after configuration. + * + * It is recommended to use the Brick Viewer to set the Wi-Fi encryption. + */ +int master_set_wifi_encryption(Master *master, uint8_t encryption, const char key[50], uint8_t key_index, uint8_t eap_options, uint16_t ca_certificate_length, uint16_t client_certificate_length, uint16_t private_key_length); + +/** + * \ingroup BrickMaster + * + * Returns the encryption as set by {@link master_set_wifi_encryption}. + * + * \note + * Since Master Brick Firmware version 2.4.4 the key is not returned anymore. + */ +int master_get_wifi_encryption(Master *master, uint8_t *ret_encryption, char ret_key[50], uint8_t *ret_key_index, uint8_t *ret_eap_options, uint16_t *ret_ca_certificate_length, uint16_t *ret_client_certificate_length, uint16_t *ret_private_key_length); + +/** + * \ingroup BrickMaster + * + * Returns the status of the WIFI Extension. The ``state`` is updated automatically, + * all of the other parameters are updated on startup and every time + * {@link master_refresh_wifi_status} is called. + * + * Possible states are: + * + * \verbatim + * "State", "Description" + * + * "0", "Disassociated" + * "1", "Associated" + * "2", "Associating" + * "3", "Error" + * "255", "Not initialized yet" + * \endverbatim + */ +int master_get_wifi_status(Master *master, uint8_t ret_mac_address[6], uint8_t ret_bssid[6], uint8_t *ret_channel, int16_t *ret_rssi, uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint32_t *ret_rx_count, uint32_t *ret_tx_count, uint8_t *ret_state); + +/** + * \ingroup BrickMaster + * + * Refreshes the Wi-Fi status (see {@link master_get_wifi_status}). To read the status + * of the Wi-Fi module, the Master Brick has to change from data mode to + * command mode and back. This transaction and the readout itself is + * unfortunately time consuming. This means, that it might take some ms + * until the stack with attached WIFI Extension reacts again after this + * function is called. + */ +int master_refresh_wifi_status(Master *master); + +/** + * \ingroup BrickMaster + * + * This function is used to set the certificate as well as password and username + * for WPA Enterprise. To set the username use index 0xFFFF, + * to set the password use index 0xFFFE. The max length of username and + * password is 32. + * + * The certificate is written in chunks of size 32 and the index is used as + * the index of the chunk. ``data_length`` should nearly always be 32. Only + * the last chunk can have a length that is not equal to 32. + * + * The starting index of the CA Certificate is 0, of the Client Certificate + * 10000 and for the Private Key 20000. Maximum sizes are 1312, 1312 and + * 4320 byte respectively. + * + * The values are stored in the EEPROM and only applied on startup. That means + * you have to restart the Master Brick after uploading the certificate. + * + * It is recommended to use the Brick Viewer to set the certificate, username + * and password. + */ +int master_set_wifi_certificate(Master *master, uint16_t index, uint8_t data[32], uint8_t data_length); + +/** + * \ingroup BrickMaster + * + * Returns the certificate for a given index as set by {@link master_set_wifi_certificate}. + */ +int master_get_wifi_certificate(Master *master, uint16_t index, uint8_t ret_data[32], uint8_t *ret_data_length); + +/** + * \ingroup BrickMaster + * + * Sets the power mode of the WIFI Extension. Possible modes are: + * + * \verbatim + * "Mode", "Description" + * + * "0", "Full Speed (high power consumption, high throughput)" + * "1", "Low Power (low power consumption, low throughput)" + * \endverbatim + */ +int master_set_wifi_power_mode(Master *master, uint8_t mode); + +/** + * \ingroup BrickMaster + * + * Returns the power mode as set by {@link master_set_wifi_power_mode}. + */ +int master_get_wifi_power_mode(Master *master, uint8_t *ret_mode); + +/** + * \ingroup BrickMaster + * + * Returns informations about the Wi-Fi receive buffer. The Wi-Fi + * receive buffer has a max size of 1500 byte and if data is transfered + * too fast, it might overflow. + * + * The return values are the number of overflows, the low watermark + * (i.e. the smallest number of bytes that were free in the buffer) and + * the bytes that are currently used. + * + * You should always try to keep the buffer empty, otherwise you will + * have a permanent latency. A good rule of thumb is, that you can transfer + * 1000 messages per second without problems. + * + * Try to not send more then 50 messages at a time without any kind of + * break between them. + */ +int master_get_wifi_buffer_info(Master *master, uint32_t *ret_overflow, uint16_t *ret_low_watermark, uint16_t *ret_used); + +/** + * \ingroup BrickMaster + * + * Sets the regulatory domain of the WIFI Extension. Possible domains are: + * + * \verbatim + * "Domain", "Description" + * + * "0", "FCC: Channel 1-11 (N/S America, Australia, New Zealand)" + * "1", "ETSI: Channel 1-13 (Europe, Middle East, Africa)" + * "2", "TELEC: Channel 1-14 (Japan)" + * \endverbatim + */ +int master_set_wifi_regulatory_domain(Master *master, uint8_t domain); + +/** + * \ingroup BrickMaster + * + * Returns the regulatory domain as set by {@link master_set_wifi_regulatory_domain}. + */ +int master_get_wifi_regulatory_domain(Master *master, uint8_t *ret_domain); + +/** + * \ingroup BrickMaster + * + * Returns the USB voltage. Does not work with hardware version 2.1. + */ +int master_get_usb_voltage(Master *master, uint16_t *ret_voltage); + +/** + * \ingroup BrickMaster + * + * Sets a long Wi-Fi key (up to 63 chars, at least 8 chars) for WPA encryption. + * This key will be used + * if the key in {@link master_set_wifi_encryption} is set to "-". In the old protocol, + * a payload of size 63 was not possible, so the maximum key length was 50 chars. + * + * With the new protocol this is possible, since we didn't want to break API, + * this function was added additionally. + * + * .. versionadded:: 2.0.2$nbsp;(Firmware) + */ +int master_set_long_wifi_key(Master *master, const char key[64]); + +/** + * \ingroup BrickMaster + * + * Returns the encryption key as set by {@link master_set_long_wifi_key}. + * + * \note + * Since Master Brick firmware version 2.4.4 the key is not returned anymore. + * + * .. versionadded:: 2.0.2$nbsp;(Firmware) + */ +int master_get_long_wifi_key(Master *master, char ret_key[64]); + +/** + * \ingroup BrickMaster + * + * Sets the hostname of the WIFI Extension. The hostname will be displayed + * by access points as the hostname in the DHCP clients table. + * + * Setting an empty String will restore the default hostname. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_set_wifi_hostname(Master *master, const char hostname[16]); + +/** + * \ingroup BrickMaster + * + * Returns the hostname as set by {@link master_set_wifi_hostname}. + * + * An empty String means, that the default hostname is used. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_get_wifi_hostname(Master *master, char ret_hostname[16]); + +/** + * \ingroup BrickMaster + * + * Sets the period with which the {@link MASTER_CALLBACK_STACK_CURRENT} callback is triggered + * periodically. A value of 0 turns the callback off. + * + * The {@link MASTER_CALLBACK_STACK_CURRENT} callback is only triggered if the current has changed + * since the last triggering. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_set_stack_current_callback_period(Master *master, uint32_t period); + +/** + * \ingroup BrickMaster + * + * Returns the period as set by {@link master_set_stack_current_callback_period}. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_get_stack_current_callback_period(Master *master, uint32_t *ret_period); + +/** + * \ingroup BrickMaster + * + * Sets the period with which the {@link MASTER_CALLBACK_STACK_VOLTAGE} callback is triggered + * periodically. A value of 0 turns the callback off. + * + * The {@link MASTER_CALLBACK_STACK_VOLTAGE} callback is only triggered if the voltage has changed + * since the last triggering. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_set_stack_voltage_callback_period(Master *master, uint32_t period); + +/** + * \ingroup BrickMaster + * + * Returns the period as set by {@link master_set_stack_voltage_callback_period}. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_get_stack_voltage_callback_period(Master *master, uint32_t *ret_period); + +/** + * \ingroup BrickMaster + * + * Sets the period with which the {@link MASTER_CALLBACK_USB_VOLTAGE} callback is triggered + * periodically. A value of 0 turns the callback off. + * + * The {@link MASTER_CALLBACK_USB_VOLTAGE} callback is only triggered if the voltage has changed + * since the last triggering. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_set_usb_voltage_callback_period(Master *master, uint32_t period); + +/** + * \ingroup BrickMaster + * + * Returns the period as set by {@link master_set_usb_voltage_callback_period}. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_get_usb_voltage_callback_period(Master *master, uint32_t *ret_period); + +/** + * \ingroup BrickMaster + * + * Sets the thresholds for the {@link MASTER_CALLBACK_STACK_CURRENT_REACHED} callback. + * + * The following options are possible: + * + * \verbatim + * "Option", "Description" + * + * "'x'", "Callback is turned off" + * "'o'", "Callback is triggered when the current is *outside* the min and max values" + * "'i'", "Callback is triggered when the current is *inside* the min and max values" + * "'<'", "Callback is triggered when the current is smaller than the min value (max is ignored)" + * "'>'", "Callback is triggered when the current is greater than the min value (max is ignored)" + * \endverbatim + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_set_stack_current_callback_threshold(Master *master, char option, uint16_t min, uint16_t max); + +/** + * \ingroup BrickMaster + * + * Returns the threshold as set by {@link master_set_stack_current_callback_threshold}. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_get_stack_current_callback_threshold(Master *master, char *ret_option, uint16_t *ret_min, uint16_t *ret_max); + +/** + * \ingroup BrickMaster + * + * Sets the thresholds for the {@link MASTER_CALLBACK_STACK_VOLTAGE_REACHED} callback. + * + * The following options are possible: + * + * \verbatim + * "Option", "Description" + * + * "'x'", "Callback is turned off" + * "'o'", "Callback is triggered when the voltage is *outside* the min and max values" + * "'i'", "Callback is triggered when the voltage is *inside* the min and max values" + * "'<'", "Callback is triggered when the voltage is smaller than the min value (max is ignored)" + * "'>'", "Callback is triggered when the voltage is greater than the min value (max is ignored)" + * \endverbatim + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_set_stack_voltage_callback_threshold(Master *master, char option, uint16_t min, uint16_t max); + +/** + * \ingroup BrickMaster + * + * Returns the threshold as set by {@link master_set_stack_voltage_callback_threshold}. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_get_stack_voltage_callback_threshold(Master *master, char *ret_option, uint16_t *ret_min, uint16_t *ret_max); + +/** + * \ingroup BrickMaster + * + * Sets the thresholds for the {@link MASTER_CALLBACK_USB_VOLTAGE_REACHED} callback. + * + * The following options are possible: + * + * \verbatim + * "Option", "Description" + * + * "'x'", "Callback is turned off" + * "'o'", "Callback is triggered when the voltage is *outside* the min and max values" + * "'i'", "Callback is triggered when the voltage is *inside* the min and max values" + * "'<'", "Callback is triggered when the voltage is smaller than the min value (max is ignored)" + * "'>'", "Callback is triggered when the voltage is greater than the min value (max is ignored)" + * \endverbatim + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_set_usb_voltage_callback_threshold(Master *master, char option, uint16_t min, uint16_t max); + +/** + * \ingroup BrickMaster + * + * Returns the threshold as set by {@link master_set_usb_voltage_callback_threshold}. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_get_usb_voltage_callback_threshold(Master *master, char *ret_option, uint16_t *ret_min, uint16_t *ret_max); + +/** + * \ingroup BrickMaster + * + * Sets the period with which the threshold callbacks + * + * * {@link MASTER_CALLBACK_STACK_CURRENT_REACHED}, + * * {@link MASTER_CALLBACK_STACK_VOLTAGE_REACHED}, + * * {@link MASTER_CALLBACK_USB_VOLTAGE_REACHED} + * + * are triggered, if the thresholds + * + * * {@link master_set_stack_current_callback_threshold}, + * * {@link master_set_stack_voltage_callback_threshold}, + * * {@link master_set_usb_voltage_callback_threshold} + * + * keep being reached. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_set_debounce_period(Master *master, uint32_t debounce); + +/** + * \ingroup BrickMaster + * + * Returns the debounce period as set by {@link master_set_debounce_period}. + * + * .. versionadded:: 2.0.5$nbsp;(Firmware) + */ +int master_get_debounce_period(Master *master, uint32_t *ret_debounce); + +/** + * \ingroup BrickMaster + * + * Returns *true* if the Master Brick is at position 0 in the stack and an Ethernet + * Extension is available. + * + * .. versionadded:: 2.1.0$nbsp;(Firmware) + */ +int master_is_ethernet_present(Master *master, bool *ret_present); + +/** + * \ingroup BrickMaster + * + * Sets the configuration of the Ethernet Extension. Possible values for + * ``connection`` are: + * + * \verbatim + * "Value", "Description" + * + * "0", "DHCP" + * "1", "Static IP" + * \endverbatim + * + * If you set ``connection`` to static IP options then you have to supply ``ip``, + * ``subnet_mask`` and ``gateway`` as an array of size 4 (first element of the + * array is the least significant byte of the address). If ``connection`` is set + * to the DHCP options then ``ip``, ``subnet_mask`` and ``gateway`` are ignored, + * you can set them to 0. + * + * The last parameter is the port that your program will connect to. + * + * The values are stored in the EEPROM and only applied on startup. That means + * you have to restart the Master Brick after configuration. + * + * It is recommended to use the Brick Viewer to set the Ethernet configuration. + * + * .. versionadded:: 2.1.0$nbsp;(Firmware) + */ +int master_set_ethernet_configuration(Master *master, uint8_t connection, uint8_t ip[4], uint8_t subnet_mask[4], uint8_t gateway[4], uint16_t port); + +/** + * \ingroup BrickMaster + * + * Returns the configuration as set by {@link master_set_ethernet_configuration}. + * + * .. versionadded:: 2.1.0$nbsp;(Firmware) + */ +int master_get_ethernet_configuration(Master *master, uint8_t *ret_connection, uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint16_t *ret_port); + +/** + * \ingroup BrickMaster + * + * Returns the status of the Ethernet Extension. + * + * ``mac_address``, ``ip``, ``subnet_mask`` and ``gateway`` are given as an array. + * The first element of the array is the least significant byte of the address. + * + * ``rx_count`` and ``tx_count`` are the number of bytes that have been + * received/send since last restart. + * + * ``hostname`` is the currently used hostname. + * + * .. versionadded:: 2.1.0$nbsp;(Firmware) + */ +int master_get_ethernet_status(Master *master, uint8_t ret_mac_address[6], uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint32_t *ret_rx_count, uint32_t *ret_tx_count, char ret_hostname[32]); + +/** + * \ingroup BrickMaster + * + * Sets the hostname of the Ethernet Extension. The hostname will be displayed + * by access points as the hostname in the DHCP clients table. + * + * Setting an empty String will restore the default hostname. + * + * The current hostname can be discovered with {@link master_get_ethernet_status}. + * + * .. versionadded:: 2.1.0$nbsp;(Firmware) + */ +int master_set_ethernet_hostname(Master *master, const char hostname[32]); + +/** + * \ingroup BrickMaster + * + * Sets the MAC address of the Ethernet Extension. The Ethernet Extension should + * come configured with a valid MAC address, that is also written on a + * sticker of the extension itself. + * + * The MAC address can be read out again with {@link master_get_ethernet_status}. + * + * .. versionadded:: 2.1.0$nbsp;(Firmware) + */ +int master_set_ethernet_mac_address(Master *master, uint8_t mac_address[6]); + +/** + * \ingroup BrickMaster + * + * Sets the Ethernet WebSocket configuration. The first parameter sets the number of socket + * connections that are reserved for WebSockets. The range is 0-7. The connections + * are shared with the plain sockets. Example: If you set the connections to 3, + * there will be 3 WebSocket and 4 plain socket connections available. + * + * The second parameter is the port for the WebSocket connections. The port can + * not be the same as the port for the plain socket connections. + * + * The values are stored in the EEPROM and only applied on startup. That means + * you have to restart the Master Brick after configuration. + * + * It is recommended to use the Brick Viewer to set the Ethernet configuration. + * + * .. versionadded:: 2.2.0$nbsp;(Firmware) + */ +int master_set_ethernet_websocket_configuration(Master *master, uint8_t sockets, uint16_t port); + +/** + * \ingroup BrickMaster + * + * Returns the configuration as set by {@link master_set_ethernet_configuration}. + * + * .. versionadded:: 2.2.0$nbsp;(Firmware) + */ +int master_get_ethernet_websocket_configuration(Master *master, uint8_t *ret_sockets, uint16_t *ret_port); + +/** + * \ingroup BrickMaster + * + * Sets the Ethernet authentication secret. The secret can be a string of up to 64 + * characters. An empty string disables the authentication. + * + * See the :ref:`authentication tutorial ` for more + * information. + * + * The secret is stored in the EEPROM and only applied on startup. That means + * you have to restart the Master Brick after configuration. + * + * It is recommended to use the Brick Viewer to set the Ethernet authentication secret. + * + * The default value is an empty string (authentication disabled). + * + * .. versionadded:: 2.2.0$nbsp;(Firmware) + */ +int master_set_ethernet_authentication_secret(Master *master, const char secret[64]); + +/** + * \ingroup BrickMaster + * + * Returns the authentication secret as set by + * {@link master_set_ethernet_authentication_secret}. + * + * .. versionadded:: 2.2.0$nbsp;(Firmware) + */ +int master_get_ethernet_authentication_secret(Master *master, char ret_secret[64]); + +/** + * \ingroup BrickMaster + * + * Sets the WIFI authentication secret. The secret can be a string of up to 64 + * characters. An empty string disables the authentication. + * + * See the :ref:`authentication tutorial ` for more + * information. + * + * The secret is stored in the EEPROM and only applied on startup. That means + * you have to restart the Master Brick after configuration. + * + * It is recommended to use the Brick Viewer to set the WIFI authentication secret. + * + * The default value is an empty string (authentication disabled). + * + * .. versionadded:: 2.2.0$nbsp;(Firmware) + */ +int master_set_wifi_authentication_secret(Master *master, const char secret[64]); + +/** + * \ingroup BrickMaster + * + * Returns the authentication secret as set by + * {@link master_set_wifi_authentication_secret}. + * + * .. versionadded:: 2.2.0$nbsp;(Firmware) + */ +int master_get_wifi_authentication_secret(Master *master, char ret_secret[64]); + +/** + * \ingroup BrickMaster + * + * Returns the type of the connection over which this function was called. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_get_connection_type(Master *master, uint8_t *ret_connection_type); + +/** + * \ingroup BrickMaster + * + * Returns *true* if the Master Brick is at position 0 in the stack and a WIFI + * Extension 2.0 is available. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_is_wifi2_present(Master *master, bool *ret_present); + +/** + * \ingroup BrickMaster + * + * Starts the bootloader of the WIFI Extension 2.0. Returns 0 on success. + * Afterwards the {@link master_write_wifi2_serial_port} and {@link master_read_wifi2_serial_port} + * functions can be used to communicate with the bootloader to flash a new + * firmware. + * + * The bootloader should only be started over a USB connection. It cannot be + * started over a WIFI2 connection, see the {@link master_get_connection_type} function. + * + * It is recommended to use the Brick Viewer to update the firmware of the WIFI + * Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_start_wifi2_bootloader(Master *master, int8_t *ret_result); + +/** + * \ingroup BrickMaster + * + * Writes up to 60 bytes (number of bytes to be written specified by ``length``) + * to the serial port of the bootloader of the WIFI Extension 2.0. Returns 0 on + * success. + * + * Before this function can be used the bootloader has to be started using the + * {@link master_start_wifi2_bootloader} function. + * + * It is recommended to use the Brick Viewer to update the firmware of the WIFI + * Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_write_wifi2_serial_port(Master *master, uint8_t data[60], uint8_t length, int8_t *ret_result); + +/** + * \ingroup BrickMaster + * + * Reads up to 60 bytes (number of bytes to be read specified by ``length``) + * from the serial port of the bootloader of the WIFI Extension 2.0. + * Returns the number of actually read bytes. + * + * Before this function can be used the bootloader has to be started using the + * {@link master_start_wifi2_bootloader} function. + * + * It is recommended to use the Brick Viewer to update the firmware of the WIFI + * Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_read_wifi2_serial_port(Master *master, uint8_t length, uint8_t ret_data[60], uint8_t *ret_result); + +/** + * \ingroup BrickMaster + * + * Sets the WIFI authentication secret. The secret can be a string of up to 64 + * characters. An empty string disables the authentication. The default value is + * an empty string (authentication disabled). + * + * See the :ref:`authentication tutorial ` for more + * information. + * + * To apply configuration changes to the WIFI Extension 2.0 the + * {@link master_save_wifi2_configuration} function has to be called and the Master Brick + * has to be restarted afterwards. + * + * It is recommended to use the Brick Viewer to configure the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_set_wifi2_authentication_secret(Master *master, const char secret[64]); + +/** + * \ingroup BrickMaster + * + * Returns the WIFI authentication secret as set by + * {@link master_set_wifi2_authentication_secret}. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_get_wifi2_authentication_secret(Master *master, char ret_secret[64]); + +/** + * \ingroup BrickMaster + * + * Sets the general configuration of the WIFI Extension 2.0. + * + * The ``port`` parameter sets the port number that your programm will connect + * to. + * + * The ``websocket_port`` parameter sets the WebSocket port number that your + * JavaScript programm will connect to. + * + * The ``website_port`` parameter sets the port number for the website of the + * WIFI Extension 2.0. + * + * The ``phy_mode`` parameter sets the specific wireless network mode to be used. + * Possible values are B, G and N. + * + * The ``sleep_mode`` parameter is currently unused. + * + * The ``website`` parameter is used to enable or disable the web interface of + * the WIFI Extension 2.0, which is available from firmware version 2.0.1. Note + * that, for firmware version 2.0.3 and older, to disable the the web interface + * the ``website_port`` parameter must be set to 1 and greater than 1 to enable + * the web interface. For firmware version 2.0.4 and later, setting this parameter + * to 1 will enable the web interface and setting it to 0 will disable the web + * interface. + * + * To apply configuration changes to the WIFI Extension 2.0 the + * {@link master_save_wifi2_configuration} function has to be called and the Master Brick + * has to be restarted afterwards. + * + * It is recommended to use the Brick Viewer to configure the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_set_wifi2_configuration(Master *master, uint16_t port, uint16_t websocket_port, uint16_t website_port, uint8_t phy_mode, uint8_t sleep_mode, uint8_t website); + +/** + * \ingroup BrickMaster + * + * Returns the general configuration as set by {@link master_set_wifi2_configuration}. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_get_wifi2_configuration(Master *master, uint16_t *ret_port, uint16_t *ret_websocket_port, uint16_t *ret_website_port, uint8_t *ret_phy_mode, uint8_t *ret_sleep_mode, uint8_t *ret_website); + +/** + * \ingroup BrickMaster + * + * Returns the client and access point status of the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_get_wifi2_status(Master *master, bool *ret_client_enabled, uint8_t *ret_client_status, uint8_t ret_client_ip[4], uint8_t ret_client_subnet_mask[4], uint8_t ret_client_gateway[4], uint8_t ret_client_mac_address[6], uint32_t *ret_client_rx_count, uint32_t *ret_client_tx_count, int8_t *ret_client_rssi, bool *ret_ap_enabled, uint8_t ret_ap_ip[4], uint8_t ret_ap_subnet_mask[4], uint8_t ret_ap_gateway[4], uint8_t ret_ap_mac_address[6], uint32_t *ret_ap_rx_count, uint32_t *ret_ap_tx_count, uint8_t *ret_ap_connected_count); + +/** + * \ingroup BrickMaster + * + * Sets the client specific configuration of the WIFI Extension 2.0. + * + * The ``enable`` parameter enables or disables the client part of the + * WIFI Extension 2.0. + * + * The ``ssid`` parameter sets the SSID (up to 32 characters) of the access point + * to connect to. + * + * If the ``ip`` parameter is set to all zero then ``subnet_mask`` and ``gateway`` + * parameters are also set to all zero and DHCP is used for IP address configuration. + * Otherwise those three parameters can be used to configure a static IP address. + * The default configuration is DHCP. + * + * If the ``mac_address`` parameter is set to all zero then the factory MAC + * address is used. Otherwise this parameter can be used to set a custom MAC + * address. + * + * If the ``bssid`` parameter is set to all zero then WIFI Extension 2.0 will + * connect to any access point that matches the configured SSID. Otherwise this + * parameter can be used to make the WIFI Extension 2.0 only connect to an + * access point if SSID and BSSID match. + * + * To apply configuration changes to the WIFI Extension 2.0 the + * {@link master_save_wifi2_configuration} function has to be called and the Master Brick + * has to be restarted afterwards. + * + * It is recommended to use the Brick Viewer to configure the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_set_wifi2_client_configuration(Master *master, bool enable, const char ssid[32], uint8_t ip[4], uint8_t subnet_mask[4], uint8_t gateway[4], uint8_t mac_address[6], uint8_t bssid[6]); + +/** + * \ingroup BrickMaster + * + * Returns the client configuration as set by {@link master_set_wifi2_client_configuration}. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_get_wifi2_client_configuration(Master *master, bool *ret_enable, char ret_ssid[32], uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint8_t ret_mac_address[6], uint8_t ret_bssid[6]); + +/** + * \ingroup BrickMaster + * + * Sets the client hostname (up to 32 characters) of the WIFI Extension 2.0. The + * hostname will be displayed by access points as the hostname in the DHCP clients + * table. + * + * To apply configuration changes to the WIFI Extension 2.0 the + * {@link master_save_wifi2_configuration} function has to be called and the Master Brick + * has to be restarted afterwards. + * + * It is recommended to use the Brick Viewer to configure the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_set_wifi2_client_hostname(Master *master, const char hostname[32]); + +/** + * \ingroup BrickMaster + * + * Returns the client hostname as set by {@link master_set_wifi2_client_hostname}. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_get_wifi2_client_hostname(Master *master, char ret_hostname[32]); + +/** + * \ingroup BrickMaster + * + * Sets the client password (up to 63 chars) for WPA/WPA2 encryption. + * + * To apply configuration changes to the WIFI Extension 2.0 the + * {@link master_save_wifi2_configuration} function has to be called and the Master Brick + * has to be restarted afterwards. + * + * It is recommended to use the Brick Viewer to configure the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_set_wifi2_client_password(Master *master, const char password[64]); + +/** + * \ingroup BrickMaster + * + * Returns the client password as set by {@link master_set_wifi2_client_password}. + * + * \note + * Since WIFI Extension 2.0 firmware version 2.1.3 the password is not + * returned anymore. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_get_wifi2_client_password(Master *master, char ret_password[64]); + +/** + * \ingroup BrickMaster + * + * Sets the access point specific configuration of the WIFI Extension 2.0. + * + * The ``enable`` parameter enables or disables the access point part of the + * WIFI Extension 2.0. + * + * The ``ssid`` parameter sets the SSID (up to 32 characters) of the access point. + * + * If the ``ip`` parameter is set to all zero then ``subnet_mask`` and ``gateway`` + * parameters are also set to all zero and DHCP is used for IP address configuration. + * Otherwise those three parameters can be used to configure a static IP address. + * The default configuration is DHCP. + * + * The ``encryption`` parameter sets the encryption mode to be used. Possible + * values are Open (no encryption), WEP or WPA/WPA2 PSK. + * Use the {@link master_set_wifi2_ap_password} function to set the encryption + * password. + * + * The ``hidden`` parameter makes the access point hide or show its SSID. + * + * The ``channel`` parameter sets the channel (1 to 13) of the access point. + * + * If the ``mac_address`` parameter is set to all zero then the factory MAC + * address is used. Otherwise this parameter can be used to set a custom MAC + * address. + * + * To apply configuration changes to the WIFI Extension 2.0 the + * {@link master_save_wifi2_configuration} function has to be called and the Master Brick + * has to be restarted afterwards. + * + * It is recommended to use the Brick Viewer to configure the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_set_wifi2_ap_configuration(Master *master, bool enable, const char ssid[32], uint8_t ip[4], uint8_t subnet_mask[4], uint8_t gateway[4], uint8_t encryption, bool hidden, uint8_t channel, uint8_t mac_address[6]); + +/** + * \ingroup BrickMaster + * + * Returns the access point configuration as set by {@link master_set_wifi2_ap_configuration}. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_get_wifi2_ap_configuration(Master *master, bool *ret_enable, char ret_ssid[32], uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint8_t *ret_encryption, bool *ret_hidden, uint8_t *ret_channel, uint8_t ret_mac_address[6]); + +/** + * \ingroup BrickMaster + * + * Sets the access point password (at least 8 and up to 63 chars) for the configured encryption + * mode, see {@link master_set_wifi2_ap_configuration}. + * + * To apply configuration changes to the WIFI Extension 2.0 the + * {@link master_save_wifi2_configuration} function has to be called and the Master Brick + * has to be restarted afterwards. + * + * It is recommended to use the Brick Viewer to configure the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_set_wifi2_ap_password(Master *master, const char password[64]); + +/** + * \ingroup BrickMaster + * + * Returns the access point password as set by {@link master_set_wifi2_ap_password}. + * + * \note + * Since WIFI Extension 2.0 firmware version 2.1.3 the password is not + * returned anymore. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_get_wifi2_ap_password(Master *master, char ret_password[64]); + +/** + * \ingroup BrickMaster + * + * All configuration functions for the WIFI Extension 2.0 do not change the + * values permanently. After configuration this function has to be called to + * permanently store the values. + * + * The values are stored in the EEPROM and only applied on startup. That means + * you have to restart the Master Brick after configuration. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_save_wifi2_configuration(Master *master, uint8_t *ret_result); + +/** + * \ingroup BrickMaster + * + * Returns the current version of the WIFI Extension 2.0 firmware. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_get_wifi2_firmware_version(Master *master, uint8_t ret_firmware_version[3]); + +/** + * \ingroup BrickMaster + * + * Turns the green status LED of the WIFI Extension 2.0 on. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_enable_wifi2_status_led(Master *master); + +/** + * \ingroup BrickMaster + * + * Turns the green status LED of the WIFI Extension 2.0 off. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_disable_wifi2_status_led(Master *master); + +/** + * \ingroup BrickMaster + * + * Returns *true* if the green status LED of the WIFI Extension 2.0 is turned on. + * + * .. versionadded:: 2.4.0$nbsp;(Firmware) + */ +int master_is_wifi2_status_led_enabled(Master *master, bool *ret_enabled); + +/** + * \ingroup BrickMaster + * + * Requires WIFI Extension 2.0 firmware 2.1.0. + * + * Sets the mesh specific configuration of the WIFI Extension 2.0. + * + * The ``enable`` parameter enables or disables the mesh part of the + * WIFI Extension 2.0. The mesh part cannot be + * enabled together with the client and access-point part. + * + * If the ``root_ip`` parameter is set to all zero then ``root_subnet_mask`` + * and ``root_gateway`` parameters are also set to all zero and DHCP is used for + * IP address configuration. Otherwise those three parameters can be used to + * configure a static IP address. The default configuration is DHCP. + * + * If the ``router_bssid`` parameter is set to all zero then the information is + * taken from Wi-Fi scan when connecting the SSID as set by + * {@link master_set_wifi2_mesh_router_ssid}. This only works if the the SSID is not hidden. + * In case the router has hidden SSID this parameter must be specified, otherwise + * the node will not be able to reach the mesh router. + * + * The ``group_id`` and the ``group_ssid_prefix`` parameters identifies a + * particular mesh network and nodes configured with same ``group_id`` and the + * ``group_ssid_prefix`` are considered to be in the same mesh network. + * + * The ``gateway_ip`` and the ``gateway_port`` parameters specifies the location + * of the brickd that supports mesh feature. + * + * To apply configuration changes to the WIFI Extension 2.0 the + * {@link master_save_wifi2_configuration} function has to be called and the Master Brick + * has to be restarted afterwards. + * + * It is recommended to use the Brick Viewer to configure the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.2$nbsp;(Firmware) + */ +int master_set_wifi2_mesh_configuration(Master *master, bool enable, uint8_t root_ip[4], uint8_t root_subnet_mask[4], uint8_t root_gateway[4], uint8_t router_bssid[6], uint8_t group_id[6], const char group_ssid_prefix[16], uint8_t gateway_ip[4], uint16_t gateway_port); + +/** + * \ingroup BrickMaster + * + * Requires WIFI Extension 2.0 firmware 2.1.0. + * + * Returns the mesh configuration as set by {@link master_set_wifi2_mesh_configuration}. + * + * .. versionadded:: 2.4.2$nbsp;(Firmware) + */ +int master_get_wifi2_mesh_configuration(Master *master, bool *ret_enable, uint8_t ret_root_ip[4], uint8_t ret_root_subnet_mask[4], uint8_t ret_root_gateway[4], uint8_t ret_router_bssid[6], uint8_t ret_group_id[6], char ret_group_ssid_prefix[16], uint8_t ret_gateway_ip[4], uint16_t *ret_gateway_port); + +/** + * \ingroup BrickMaster + * + * Requires WIFI Extension 2.0 firmware 2.1.0. + * + * Sets the mesh router SSID of the WIFI Extension 2.0. + * It is used to specify the mesh router to connect to. + * + * Note that even though in the argument of this function a 32 characters long SSID + * is allowed, in practice valid SSID should have a maximum of 31 characters. This + * is due to a bug in the mesh library that we use in the firmware of the extension. + * + * To apply configuration changes to the WIFI Extension 2.0 the + * {@link master_save_wifi2_configuration} function has to be called and the Master Brick + * has to be restarted afterwards. + * + * It is recommended to use the Brick Viewer to configure the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.2$nbsp;(Firmware) + */ +int master_set_wifi2_mesh_router_ssid(Master *master, const char ssid[32]); + +/** + * \ingroup BrickMaster + * + * Requires WIFI Extension 2.0 firmware 2.1.0. + * + * Returns the mesh router SSID as set by {@link master_set_wifi2_mesh_router_ssid}. + * + * .. versionadded:: 2.4.2$nbsp;(Firmware) + */ +int master_get_wifi2_mesh_router_ssid(Master *master, char ret_ssid[32]); + +/** + * \ingroup BrickMaster + * + * Requires WIFI Extension 2.0 firmware 2.1.0. + * + * Sets the mesh router password (up to 64 characters) for WPA/WPA2 encryption. + * The password will be used to connect to the mesh router. + * + * To apply configuration changes to the WIFI Extension 2.0 the + * {@link master_save_wifi2_configuration} function has to be called and the Master Brick + * has to be restarted afterwards. + * + * It is recommended to use the Brick Viewer to configure the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.2$nbsp;(Firmware) + */ +int master_set_wifi2_mesh_router_password(Master *master, const char password[64]); + +/** + * \ingroup BrickMaster + * + * Requires WIFI Extension 2.0 firmware 2.1.0. + * + * Returns the mesh router password as set by {@link master_set_wifi2_mesh_router_password}. + * + * .. versionadded:: 2.4.2$nbsp;(Firmware) + */ +int master_get_wifi2_mesh_router_password(Master *master, char ret_password[64]); + +/** + * \ingroup BrickMaster + * + * Requires WIFI Extension 2.0 firmware 2.1.0. + * + * Returns the common mesh status of the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.2$nbsp;(Firmware) + */ +int master_get_wifi2_mesh_common_status(Master *master, uint8_t *ret_status, bool *ret_root_node, bool *ret_root_candidate, uint16_t *ret_connected_nodes, uint32_t *ret_rx_count, uint32_t *ret_tx_count); + +/** + * \ingroup BrickMaster + * + * Requires WIFI Extension 2.0 firmware 2.1.0. + * + * Returns the mesh client status of the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.2$nbsp;(Firmware) + */ +int master_get_wifi2_mesh_client_status(Master *master, char ret_hostname[32], uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint8_t ret_mac_address[6]); + +/** + * \ingroup BrickMaster + * + * Requires WIFI Extension 2.0 firmware 2.1.0. + * + * Returns the mesh AP status of the WIFI Extension 2.0. + * + * .. versionadded:: 2.4.2$nbsp;(Firmware) + */ +int master_get_wifi2_mesh_ap_status(Master *master, char ret_ssid[32], uint8_t ret_ip[4], uint8_t ret_subnet_mask[4], uint8_t ret_gateway[4], uint8_t ret_mac_address[6]); + +/** + * \ingroup BrickMaster + * + * This function is for internal use to flash the initial + * bootstrapper and bootloader to the Bricklets. + * + * If you need to flash a boostrapper/bootloader (for exmaple + * because you made your own Bricklet from scratch) please + * take a look at our open source flash and test tool at + * `https://github.com/Tinkerforge/flash-test `__ + * + * Don't use this function directly. + * + * .. versionadded:: 2.5.0$nbsp;(Firmware) + */ +int master_set_bricklet_xmc_flash_config(Master *master, uint32_t config, uint32_t parameter1, uint32_t parameter2, uint8_t data[52], uint32_t *ret_return_value, uint8_t ret_return_data[60]); + +/** + * \ingroup BrickMaster + * + * This function is for internal use to flash the initial + * bootstrapper and bootloader to the Bricklets. + * + * If you need to flash a boostrapper/bootloader (for exmaple + * because you made your own Bricklet from scratch) please + * take a look at our open source flash and test tool at + * `https://github.com/Tinkerforge/flash-test `__ + * + * Don't use this function directly. + * + * .. versionadded:: 2.5.0$nbsp;(Firmware) + */ +int master_set_bricklet_xmc_flash_data(Master *master, uint8_t data[64], uint32_t *ret_return_data); + +/** + * \ingroup BrickMaster + * + * This function is only available in Master Brick hardware version >= 3.0. + * + * Enables/disables all four Bricklets if set to true/false. + * + * If you disable the Bricklets the power supply to the Bricklets will be disconnected. + * The Bricklets will lose all configurations if disabled. + * + * .. versionadded:: 2.5.0$nbsp;(Firmware) + */ +int master_set_bricklets_enabled(Master *master, bool bricklets_enabled); + +/** + * \ingroup BrickMaster + * + * Returns *true* if the Bricklets are enabled, *false* otherwise. + * + * .. versionadded:: 2.5.0$nbsp;(Firmware) + */ +int master_get_bricklets_enabled(Master *master, bool *ret_bricklets_enabled); + +/** + * \ingroup BrickMaster + * + * The SPITF protocol can be used with a dynamic baudrate. If the dynamic baudrate is + * enabled, the Brick will try to adapt the baudrate for the communication + * between Bricks and Bricklets according to the amount of data that is transferred. + * + * The baudrate will be increased exponentially if lots of data is sent/received and + * decreased linearly if little data is sent/received. + * + * This lowers the baudrate in applications where little data is transferred (e.g. + * a weather station) and increases the robustness. If there is lots of data to transfer + * (e.g. Thermal Imaging Bricklet) it automatically increases the baudrate as needed. + * + * In cases where some data has to transferred as fast as possible every few seconds + * (e.g. RS485 Bricklet with a high baudrate but small payload) you may want to turn + * the dynamic baudrate off to get the highest possible performance. + * + * The maximum value of the baudrate can be set per port with the function + * {@link master_set_spitfp_baudrate}. If the dynamic baudrate is disabled, the baudrate + * as set by {@link master_set_spitfp_baudrate} will be used statically. + * + * .. versionadded:: 2.4.6$nbsp;(Firmware) + */ +int master_set_spitfp_baudrate_config(Master *master, bool enable_dynamic_baudrate, uint32_t minimum_dynamic_baudrate); + +/** + * \ingroup BrickMaster + * + * Returns the baudrate config, see {@link master_set_spitfp_baudrate_config}. + * + * .. versionadded:: 2.4.6$nbsp;(Firmware) + */ +int master_get_spitfp_baudrate_config(Master *master, bool *ret_enable_dynamic_baudrate, uint32_t *ret_minimum_dynamic_baudrate); + +/** + * \ingroup BrickMaster + * + * Returns the timeout count for the different communication methods. + * + * The methods 0-2 are available for all Bricks, 3-7 only for Master Bricks. + * + * This function is mostly used for debugging during development, in normal operation + * the counters should nearly always stay at 0. + * + * .. versionadded:: 2.4.3$nbsp;(Firmware) + */ +int master_get_send_timeout_count(Master *master, uint8_t communication_method, uint32_t *ret_timeout_count); + +/** + * \ingroup BrickMaster + * + * Sets the baudrate for a specific Bricklet port. + * + * If you want to increase the throughput of Bricklets you can increase + * the baudrate. If you get a high error count because of high + * interference (see {@link master_get_spitfp_error_count}) you can decrease the + * baudrate. + * + * If the dynamic baudrate feature is enabled, the baudrate set by this + * function corresponds to the maximum baudrate (see {@link master_set_spitfp_baudrate_config}). + * + * Regulatory testing is done with the default baudrate. If CE compatibility + * or similar is necessary in your applications we recommend to not change + * the baudrate. + * + * .. versionadded:: 2.4.3$nbsp;(Firmware) + */ +int master_set_spitfp_baudrate(Master *master, char bricklet_port, uint32_t baudrate); + +/** + * \ingroup BrickMaster + * + * Returns the baudrate for a given Bricklet port, see {@link master_set_spitfp_baudrate}. + * + * .. versionadded:: 2.4.3$nbsp;(Firmware) + */ +int master_get_spitfp_baudrate(Master *master, char bricklet_port, uint32_t *ret_baudrate); + +/** + * \ingroup BrickMaster + * + * Returns the error count for the communication between Brick and Bricklet. + * + * The errors are divided into + * + * * ACK checksum errors, + * * message checksum errors, + * * framing errors and + * * overflow errors. + * + * The errors counts are for errors that occur on the Brick side. All + * Bricklets have a similar function that returns the errors on the Bricklet side. + * + * .. versionadded:: 2.4.3$nbsp;(Firmware) + */ +int master_get_spitfp_error_count(Master *master, char bricklet_port, uint32_t *ret_error_count_ack_checksum, uint32_t *ret_error_count_message_checksum, uint32_t *ret_error_count_frame, uint32_t *ret_error_count_overflow); + +/** + * \ingroup BrickMaster + * + * Enables the status LED. + * + * The status LED is the blue LED next to the USB connector. If enabled is is + * on and it flickers if data is transfered. If disabled it is always off. + * + * The default state is enabled. + * + * .. versionadded:: 2.3.2$nbsp;(Firmware) + */ +int master_enable_status_led(Master *master); + +/** + * \ingroup BrickMaster + * + * Disables the status LED. + * + * The status LED is the blue LED next to the USB connector. If enabled is is + * on and it flickers if data is transfered. If disabled it is always off. + * + * The default state is enabled. + * + * .. versionadded:: 2.3.2$nbsp;(Firmware) + */ +int master_disable_status_led(Master *master); + +/** + * \ingroup BrickMaster + * + * Returns *true* if the status LED is enabled, *false* otherwise. + * + * .. versionadded:: 2.3.2$nbsp;(Firmware) + */ +int master_is_status_led_enabled(Master *master, bool *ret_enabled); + +/** + * \ingroup BrickMaster + * + * Returns the firmware and protocol version and the name of the Bricklet for a + * given port. + * + * This functions sole purpose is to allow automatic flashing of v1.x.y Bricklet + * plugins. + */ +int master_get_protocol1_bricklet_name(Master *master, char port, uint8_t *ret_protocol_version, uint8_t ret_firmware_version[3], char ret_name[40]); + +/** + * \ingroup BrickMaster + * + * Returns the temperature as measured inside the microcontroller. The + * value returned is not the ambient temperature! + * + * The temperature is only proportional to the real temperature and it has an + * accuracy of ±15%. Practically it is only useful as an indicator for + * temperature changes. + */ +int master_get_chip_temperature(Master *master, int16_t *ret_temperature); + +/** + * \ingroup BrickMaster + * + * Calling this function will reset the Brick. Calling this function + * on a Brick inside of a stack will reset the whole stack. + * + * After a reset you have to create new device objects, + * calling functions on the existing ones will result in + * undefined behavior! + */ +int master_reset(Master *master); + +/** + * \ingroup BrickMaster + * + * Writes 32 bytes of firmware to the bricklet attached at the given port. + * The bytes are written to the position offset * 32. + * + * This function is used by Brick Viewer during flashing. It should not be + * necessary to call it in a normal user program. + */ +int master_write_bricklet_plugin(Master *master, char port, uint8_t offset, uint8_t chunk[32]); + +/** + * \ingroup BrickMaster + * + * Reads 32 bytes of firmware from the bricklet attached at the given port. + * The bytes are read starting at the position offset * 32. + * + * This function is used by Brick Viewer during flashing. It should not be + * necessary to call it in a normal user program. + */ +int master_read_bricklet_plugin(Master *master, char port, uint8_t offset, uint8_t ret_chunk[32]); + +/** + * \ingroup BrickMaster + * + * Returns the UID, the UID where the Brick is connected to, + * the position, the hardware and firmware version as well as the + * device identifier. + * + * The position is the position in the stack from '0' (bottom) to '8' (top). + * + * The device identifier numbers can be found :ref:`here `. + * |device_identifier_constant| + */ +int master_get_identity(Master *master, char ret_uid[8], char ret_connected_uid[8], char *ret_position, uint8_t ret_hardware_version[3], uint8_t ret_firmware_version[3], uint16_t *ret_device_identifier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tinkerforge/bricklet_air_quality.c b/tinkerforge/bricklet_air_quality.c new file mode 100644 index 0000000..e452a95 --- /dev/null +++ b/tinkerforge/bricklet_air_quality.c @@ -0,0 +1,1463 @@ +/* *********************************************************** + * This file was automatically generated on 2021-01-15. * + * * + * C/C++ Bindings Version 2.1.31 * + * * + * If you have a bugfix for this file and want to commit it, * + * please fix the bug in the generator. You can find a link * + * to the generators git repository on tinkerforge.com * + *************************************************************/ + + +#define IPCON_EXPOSE_INTERNALS + +#include "bricklet_air_quality.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +typedef void (*AllValues_CallbackFunction)(int32_t iaq_index, uint8_t iaq_index_accuracy, int32_t temperature, int32_t humidity, int32_t air_pressure, void *user_data); + +typedef void (*IAQIndex_CallbackFunction)(int32_t iaq_index, uint8_t iaq_index_accuracy, void *user_data); + +typedef void (*Temperature_CallbackFunction)(int32_t temperature, void *user_data); + +typedef void (*Humidity_CallbackFunction)(int32_t humidity, void *user_data); + +typedef void (*AirPressure_CallbackFunction)(int32_t air_pressure, void *user_data); + +#if defined _MSC_VER || defined __BORLANDC__ + #pragma pack(push) + #pragma pack(1) + #define ATTRIBUTE_PACKED +#elif defined __GNUC__ + #ifdef _WIN32 + // workaround struct packing bug in GCC 4.7 on Windows + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 + #define ATTRIBUTE_PACKED __attribute__((gcc_struct, packed)) + #else + #define ATTRIBUTE_PACKED __attribute__((packed)) + #endif +#else + #error unknown compiler, do not know how to enable struct packing +#endif + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetAllValues_Request; + +typedef struct { + PacketHeader header; + int32_t iaq_index; + uint8_t iaq_index_accuracy; + int32_t temperature; + int32_t humidity; + int32_t air_pressure; +} ATTRIBUTE_PACKED GetAllValues_Response; + +typedef struct { + PacketHeader header; + int32_t offset; +} ATTRIBUTE_PACKED SetTemperatureOffset_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetTemperatureOffset_Request; + +typedef struct { + PacketHeader header; + int32_t offset; +} ATTRIBUTE_PACKED GetTemperatureOffset_Response; + +typedef struct { + PacketHeader header; + uint32_t period; + uint8_t value_has_to_change; +} ATTRIBUTE_PACKED SetAllValuesCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetAllValuesCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; + uint32_t period; + uint8_t value_has_to_change; +} ATTRIBUTE_PACKED GetAllValuesCallbackConfiguration_Response; + +typedef struct { + PacketHeader header; + int32_t iaq_index; + uint8_t iaq_index_accuracy; + int32_t temperature; + int32_t humidity; + int32_t air_pressure; +} ATTRIBUTE_PACKED AllValues_Callback; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetIAQIndex_Request; + +typedef struct { + PacketHeader header; + int32_t iaq_index; + uint8_t iaq_index_accuracy; +} ATTRIBUTE_PACKED GetIAQIndex_Response; + +typedef struct { + PacketHeader header; + uint32_t period; + uint8_t value_has_to_change; +} ATTRIBUTE_PACKED SetIAQIndexCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetIAQIndexCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; + uint32_t period; + uint8_t value_has_to_change; +} ATTRIBUTE_PACKED GetIAQIndexCallbackConfiguration_Response; + +typedef struct { + PacketHeader header; + int32_t iaq_index; + uint8_t iaq_index_accuracy; +} ATTRIBUTE_PACKED IAQIndex_Callback; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetTemperature_Request; + +typedef struct { + PacketHeader header; + int32_t temperature; +} ATTRIBUTE_PACKED GetTemperature_Response; + +typedef struct { + PacketHeader header; + uint32_t period; + uint8_t value_has_to_change; + char option; + int32_t min; + int32_t max; +} ATTRIBUTE_PACKED SetTemperatureCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetTemperatureCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; + uint32_t period; + uint8_t value_has_to_change; + char option; + int32_t min; + int32_t max; +} ATTRIBUTE_PACKED GetTemperatureCallbackConfiguration_Response; + +typedef struct { + PacketHeader header; + int32_t temperature; +} ATTRIBUTE_PACKED Temperature_Callback; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetHumidity_Request; + +typedef struct { + PacketHeader header; + int32_t humidity; +} ATTRIBUTE_PACKED GetHumidity_Response; + +typedef struct { + PacketHeader header; + uint32_t period; + uint8_t value_has_to_change; + char option; + int32_t min; + int32_t max; +} ATTRIBUTE_PACKED SetHumidityCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetHumidityCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; + uint32_t period; + uint8_t value_has_to_change; + char option; + int32_t min; + int32_t max; +} ATTRIBUTE_PACKED GetHumidityCallbackConfiguration_Response; + +typedef struct { + PacketHeader header; + int32_t humidity; +} ATTRIBUTE_PACKED Humidity_Callback; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetAirPressure_Request; + +typedef struct { + PacketHeader header; + int32_t air_pressure; +} ATTRIBUTE_PACKED GetAirPressure_Response; + +typedef struct { + PacketHeader header; + uint32_t period; + uint8_t value_has_to_change; + char option; + int32_t min; + int32_t max; +} ATTRIBUTE_PACKED SetAirPressureCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetAirPressureCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; + uint32_t period; + uint8_t value_has_to_change; + char option; + int32_t min; + int32_t max; +} ATTRIBUTE_PACKED GetAirPressureCallbackConfiguration_Response; + +typedef struct { + PacketHeader header; + int32_t air_pressure; +} ATTRIBUTE_PACKED AirPressure_Callback; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED RemoveCalibration_Request; + +typedef struct { + PacketHeader header; + uint8_t duration; +} ATTRIBUTE_PACKED SetBackgroundCalibrationDuration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetBackgroundCalibrationDuration_Request; + +typedef struct { + PacketHeader header; + uint8_t duration; +} ATTRIBUTE_PACKED GetBackgroundCalibrationDuration_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetSPITFPErrorCount_Request; + +typedef struct { + PacketHeader header; + uint32_t error_count_ack_checksum; + uint32_t error_count_message_checksum; + uint32_t error_count_frame; + uint32_t error_count_overflow; +} ATTRIBUTE_PACKED GetSPITFPErrorCount_Response; + +typedef struct { + PacketHeader header; + uint8_t mode; +} ATTRIBUTE_PACKED SetBootloaderMode_Request; + +typedef struct { + PacketHeader header; + uint8_t status; +} ATTRIBUTE_PACKED SetBootloaderMode_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetBootloaderMode_Request; + +typedef struct { + PacketHeader header; + uint8_t mode; +} ATTRIBUTE_PACKED GetBootloaderMode_Response; + +typedef struct { + PacketHeader header; + uint32_t pointer; +} ATTRIBUTE_PACKED SetWriteFirmwarePointer_Request; + +typedef struct { + PacketHeader header; + uint8_t data[64]; +} ATTRIBUTE_PACKED WriteFirmware_Request; + +typedef struct { + PacketHeader header; + uint8_t status; +} ATTRIBUTE_PACKED WriteFirmware_Response; + +typedef struct { + PacketHeader header; + uint8_t config; +} ATTRIBUTE_PACKED SetStatusLEDConfig_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetStatusLEDConfig_Request; + +typedef struct { + PacketHeader header; + uint8_t config; +} ATTRIBUTE_PACKED GetStatusLEDConfig_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetChipTemperature_Request; + +typedef struct { + PacketHeader header; + int16_t temperature; +} ATTRIBUTE_PACKED GetChipTemperature_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED Reset_Request; + +typedef struct { + PacketHeader header; + uint32_t uid; +} ATTRIBUTE_PACKED WriteUID_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED ReadUID_Request; + +typedef struct { + PacketHeader header; + uint32_t uid; +} ATTRIBUTE_PACKED ReadUID_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetIdentity_Request; + +typedef struct { + PacketHeader header; + char uid[8]; + char connected_uid[8]; + char position; + uint8_t hardware_version[3]; + uint8_t firmware_version[3]; + uint16_t device_identifier; +} ATTRIBUTE_PACKED GetIdentity_Response; + +#if defined _MSC_VER || defined __BORLANDC__ + #pragma pack(pop) +#endif +#undef ATTRIBUTE_PACKED + +static void air_quality_callback_wrapper_all_values(DevicePrivate *device_p, Packet *packet) { + AllValues_CallbackFunction callback_function; + void *user_data; + AllValues_Callback *callback; + + if (packet->header.length != sizeof(AllValues_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (AllValues_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + AIR_QUALITY_CALLBACK_ALL_VALUES]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + AIR_QUALITY_CALLBACK_ALL_VALUES]; + callback = (AllValues_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->iaq_index = leconvert_int32_from(callback->iaq_index); + callback->temperature = leconvert_int32_from(callback->temperature); + callback->humidity = leconvert_int32_from(callback->humidity); + callback->air_pressure = leconvert_int32_from(callback->air_pressure); + + callback_function(callback->iaq_index, callback->iaq_index_accuracy, callback->temperature, callback->humidity, callback->air_pressure, user_data); +} + +static void air_quality_callback_wrapper_iaq_index(DevicePrivate *device_p, Packet *packet) { + IAQIndex_CallbackFunction callback_function; + void *user_data; + IAQIndex_Callback *callback; + + if (packet->header.length != sizeof(IAQIndex_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (IAQIndex_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + AIR_QUALITY_CALLBACK_IAQ_INDEX]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + AIR_QUALITY_CALLBACK_IAQ_INDEX]; + callback = (IAQIndex_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->iaq_index = leconvert_int32_from(callback->iaq_index); + + callback_function(callback->iaq_index, callback->iaq_index_accuracy, user_data); +} + +static void air_quality_callback_wrapper_temperature(DevicePrivate *device_p, Packet *packet) { + Temperature_CallbackFunction callback_function; + void *user_data; + Temperature_Callback *callback; + + if (packet->header.length != sizeof(Temperature_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (Temperature_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + AIR_QUALITY_CALLBACK_TEMPERATURE]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + AIR_QUALITY_CALLBACK_TEMPERATURE]; + callback = (Temperature_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->temperature = leconvert_int32_from(callback->temperature); + + callback_function(callback->temperature, user_data); +} + +static void air_quality_callback_wrapper_humidity(DevicePrivate *device_p, Packet *packet) { + Humidity_CallbackFunction callback_function; + void *user_data; + Humidity_Callback *callback; + + if (packet->header.length != sizeof(Humidity_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (Humidity_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + AIR_QUALITY_CALLBACK_HUMIDITY]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + AIR_QUALITY_CALLBACK_HUMIDITY]; + callback = (Humidity_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->humidity = leconvert_int32_from(callback->humidity); + + callback_function(callback->humidity, user_data); +} + +static void air_quality_callback_wrapper_air_pressure(DevicePrivate *device_p, Packet *packet) { + AirPressure_CallbackFunction callback_function; + void *user_data; + AirPressure_Callback *callback; + + if (packet->header.length != sizeof(AirPressure_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (AirPressure_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + AIR_QUALITY_CALLBACK_AIR_PRESSURE]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + AIR_QUALITY_CALLBACK_AIR_PRESSURE]; + callback = (AirPressure_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->air_pressure = leconvert_int32_from(callback->air_pressure); + + callback_function(callback->air_pressure, user_data); +} + +void air_quality_create(AirQuality *air_quality, const char *uid, IPConnection *ipcon) { + IPConnectionPrivate *ipcon_p = ipcon->p; + DevicePrivate *device_p; + + device_create(air_quality, uid, ipcon_p, 2, 0, 1, AIR_QUALITY_DEVICE_IDENTIFIER); + + device_p = air_quality->p; + + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_ALL_VALUES] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_SET_TEMPERATURE_OFFSET] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_TEMPERATURE_OFFSET] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_SET_ALL_VALUES_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_ALL_VALUES_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_IAQ_INDEX] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_SET_IAQ_INDEX_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_IAQ_INDEX_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_TEMPERATURE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_SET_TEMPERATURE_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_TEMPERATURE_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_HUMIDITY] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_SET_HUMIDITY_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_HUMIDITY_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_AIR_PRESSURE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_SET_AIR_PRESSURE_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_AIR_PRESSURE_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_REMOVE_CALIBRATION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[AIR_QUALITY_FUNCTION_SET_BACKGROUND_CALIBRATION_DURATION] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_BACKGROUND_CALIBRATION_DURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_SPITFP_ERROR_COUNT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_SET_BOOTLOADER_MODE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_BOOTLOADER_MODE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_SET_WRITE_FIRMWARE_POINTER] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[AIR_QUALITY_FUNCTION_WRITE_FIRMWARE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_SET_STATUS_LED_CONFIG] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_STATUS_LED_CONFIG] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_CHIP_TEMPERATURE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_RESET] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[AIR_QUALITY_FUNCTION_WRITE_UID] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[AIR_QUALITY_FUNCTION_READ_UID] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[AIR_QUALITY_FUNCTION_GET_IDENTITY] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + + device_p->callback_wrappers[AIR_QUALITY_CALLBACK_ALL_VALUES] = air_quality_callback_wrapper_all_values; + device_p->callback_wrappers[AIR_QUALITY_CALLBACK_IAQ_INDEX] = air_quality_callback_wrapper_iaq_index; + device_p->callback_wrappers[AIR_QUALITY_CALLBACK_TEMPERATURE] = air_quality_callback_wrapper_temperature; + device_p->callback_wrappers[AIR_QUALITY_CALLBACK_HUMIDITY] = air_quality_callback_wrapper_humidity; + device_p->callback_wrappers[AIR_QUALITY_CALLBACK_AIR_PRESSURE] = air_quality_callback_wrapper_air_pressure; + + ipcon_add_device(ipcon_p, device_p); +} + +void air_quality_destroy(AirQuality *air_quality) { + device_release(air_quality->p); +} + +int air_quality_get_response_expected(AirQuality *air_quality, uint8_t function_id, bool *ret_response_expected) { + return device_get_response_expected(air_quality->p, function_id, ret_response_expected); +} + +int air_quality_set_response_expected(AirQuality *air_quality, uint8_t function_id, bool response_expected) { + return device_set_response_expected(air_quality->p, function_id, response_expected); +} + +int air_quality_set_response_expected_all(AirQuality *air_quality, bool response_expected) { + return device_set_response_expected_all(air_quality->p, response_expected); +} + +void air_quality_register_callback(AirQuality *air_quality, int16_t callback_id, void (*function)(void), void *user_data) { + device_register_callback(air_quality->p, callback_id, function, user_data); +} + +int air_quality_get_api_version(AirQuality *air_quality, uint8_t ret_api_version[3]) { + return device_get_api_version(air_quality->p, ret_api_version); +} + +int air_quality_get_all_values(AirQuality *air_quality, int32_t *ret_iaq_index, uint8_t *ret_iaq_index_accuracy, int32_t *ret_temperature, int32_t *ret_humidity, int32_t *ret_air_pressure) { + DevicePrivate *device_p = air_quality->p; + GetAllValues_Request request; + GetAllValues_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_ALL_VALUES, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_iaq_index = leconvert_int32_from(response.iaq_index); + *ret_iaq_index_accuracy = response.iaq_index_accuracy; + *ret_temperature = leconvert_int32_from(response.temperature); + *ret_humidity = leconvert_int32_from(response.humidity); + *ret_air_pressure = leconvert_int32_from(response.air_pressure); + + return ret; +} + +int air_quality_set_temperature_offset(AirQuality *air_quality, int32_t offset) { + DevicePrivate *device_p = air_quality->p; + SetTemperatureOffset_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_SET_TEMPERATURE_OFFSET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.offset = leconvert_int32_to(offset); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_get_temperature_offset(AirQuality *air_quality, int32_t *ret_offset) { + DevicePrivate *device_p = air_quality->p; + GetTemperatureOffset_Request request; + GetTemperatureOffset_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_TEMPERATURE_OFFSET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_offset = leconvert_int32_from(response.offset); + + return ret; +} + +int air_quality_set_all_values_callback_configuration(AirQuality *air_quality, uint32_t period, bool value_has_to_change) { + DevicePrivate *device_p = air_quality->p; + SetAllValuesCallbackConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_SET_ALL_VALUES_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.period = leconvert_uint32_to(period); + request.value_has_to_change = value_has_to_change ? 1 : 0; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_get_all_values_callback_configuration(AirQuality *air_quality, uint32_t *ret_period, bool *ret_value_has_to_change) { + DevicePrivate *device_p = air_quality->p; + GetAllValuesCallbackConfiguration_Request request; + GetAllValuesCallbackConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_ALL_VALUES_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_period = leconvert_uint32_from(response.period); + *ret_value_has_to_change = response.value_has_to_change != 0; + + return ret; +} + +int air_quality_get_iaq_index(AirQuality *air_quality, int32_t *ret_iaq_index, uint8_t *ret_iaq_index_accuracy) { + DevicePrivate *device_p = air_quality->p; + GetIAQIndex_Request request; + GetIAQIndex_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_IAQ_INDEX, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_iaq_index = leconvert_int32_from(response.iaq_index); + *ret_iaq_index_accuracy = response.iaq_index_accuracy; + + return ret; +} + +int air_quality_set_iaq_index_callback_configuration(AirQuality *air_quality, uint32_t period, bool value_has_to_change) { + DevicePrivate *device_p = air_quality->p; + SetIAQIndexCallbackConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_SET_IAQ_INDEX_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.period = leconvert_uint32_to(period); + request.value_has_to_change = value_has_to_change ? 1 : 0; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_get_iaq_index_callback_configuration(AirQuality *air_quality, uint32_t *ret_period, bool *ret_value_has_to_change) { + DevicePrivate *device_p = air_quality->p; + GetIAQIndexCallbackConfiguration_Request request; + GetIAQIndexCallbackConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_IAQ_INDEX_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_period = leconvert_uint32_from(response.period); + *ret_value_has_to_change = response.value_has_to_change != 0; + + return ret; +} + +int air_quality_get_temperature(AirQuality *air_quality, int32_t *ret_temperature) { + DevicePrivate *device_p = air_quality->p; + GetTemperature_Request request; + GetTemperature_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_TEMPERATURE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_temperature = leconvert_int32_from(response.temperature); + + return ret; +} + +int air_quality_set_temperature_callback_configuration(AirQuality *air_quality, uint32_t period, bool value_has_to_change, char option, int32_t min, int32_t max) { + DevicePrivate *device_p = air_quality->p; + SetTemperatureCallbackConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_SET_TEMPERATURE_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.period = leconvert_uint32_to(period); + request.value_has_to_change = value_has_to_change ? 1 : 0; + request.option = option; + request.min = leconvert_int32_to(min); + request.max = leconvert_int32_to(max); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_get_temperature_callback_configuration(AirQuality *air_quality, uint32_t *ret_period, bool *ret_value_has_to_change, char *ret_option, int32_t *ret_min, int32_t *ret_max) { + DevicePrivate *device_p = air_quality->p; + GetTemperatureCallbackConfiguration_Request request; + GetTemperatureCallbackConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_TEMPERATURE_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_period = leconvert_uint32_from(response.period); + *ret_value_has_to_change = response.value_has_to_change != 0; + *ret_option = response.option; + *ret_min = leconvert_int32_from(response.min); + *ret_max = leconvert_int32_from(response.max); + + return ret; +} + +int air_quality_get_humidity(AirQuality *air_quality, int32_t *ret_humidity) { + DevicePrivate *device_p = air_quality->p; + GetHumidity_Request request; + GetHumidity_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_HUMIDITY, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_humidity = leconvert_int32_from(response.humidity); + + return ret; +} + +int air_quality_set_humidity_callback_configuration(AirQuality *air_quality, uint32_t period, bool value_has_to_change, char option, int32_t min, int32_t max) { + DevicePrivate *device_p = air_quality->p; + SetHumidityCallbackConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_SET_HUMIDITY_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.period = leconvert_uint32_to(period); + request.value_has_to_change = value_has_to_change ? 1 : 0; + request.option = option; + request.min = leconvert_int32_to(min); + request.max = leconvert_int32_to(max); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_get_humidity_callback_configuration(AirQuality *air_quality, uint32_t *ret_period, bool *ret_value_has_to_change, char *ret_option, int32_t *ret_min, int32_t *ret_max) { + DevicePrivate *device_p = air_quality->p; + GetHumidityCallbackConfiguration_Request request; + GetHumidityCallbackConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_HUMIDITY_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_period = leconvert_uint32_from(response.period); + *ret_value_has_to_change = response.value_has_to_change != 0; + *ret_option = response.option; + *ret_min = leconvert_int32_from(response.min); + *ret_max = leconvert_int32_from(response.max); + + return ret; +} + +int air_quality_get_air_pressure(AirQuality *air_quality, int32_t *ret_air_pressure) { + DevicePrivate *device_p = air_quality->p; + GetAirPressure_Request request; + GetAirPressure_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_AIR_PRESSURE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_air_pressure = leconvert_int32_from(response.air_pressure); + + return ret; +} + +int air_quality_set_air_pressure_callback_configuration(AirQuality *air_quality, uint32_t period, bool value_has_to_change, char option, int32_t min, int32_t max) { + DevicePrivate *device_p = air_quality->p; + SetAirPressureCallbackConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_SET_AIR_PRESSURE_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.period = leconvert_uint32_to(period); + request.value_has_to_change = value_has_to_change ? 1 : 0; + request.option = option; + request.min = leconvert_int32_to(min); + request.max = leconvert_int32_to(max); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_get_air_pressure_callback_configuration(AirQuality *air_quality, uint32_t *ret_period, bool *ret_value_has_to_change, char *ret_option, int32_t *ret_min, int32_t *ret_max) { + DevicePrivate *device_p = air_quality->p; + GetAirPressureCallbackConfiguration_Request request; + GetAirPressureCallbackConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_AIR_PRESSURE_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_period = leconvert_uint32_from(response.period); + *ret_value_has_to_change = response.value_has_to_change != 0; + *ret_option = response.option; + *ret_min = leconvert_int32_from(response.min); + *ret_max = leconvert_int32_from(response.max); + + return ret; +} + +int air_quality_remove_calibration(AirQuality *air_quality) { + DevicePrivate *device_p = air_quality->p; + RemoveCalibration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_REMOVE_CALIBRATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_set_background_calibration_duration(AirQuality *air_quality, uint8_t duration) { + DevicePrivate *device_p = air_quality->p; + SetBackgroundCalibrationDuration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_SET_BACKGROUND_CALIBRATION_DURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.duration = duration; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_get_background_calibration_duration(AirQuality *air_quality, uint8_t *ret_duration) { + DevicePrivate *device_p = air_quality->p; + GetBackgroundCalibrationDuration_Request request; + GetBackgroundCalibrationDuration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_BACKGROUND_CALIBRATION_DURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_duration = response.duration; + + return ret; +} + +int air_quality_get_spitfp_error_count(AirQuality *air_quality, uint32_t *ret_error_count_ack_checksum, uint32_t *ret_error_count_message_checksum, uint32_t *ret_error_count_frame, uint32_t *ret_error_count_overflow) { + DevicePrivate *device_p = air_quality->p; + GetSPITFPErrorCount_Request request; + GetSPITFPErrorCount_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_SPITFP_ERROR_COUNT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_error_count_ack_checksum = leconvert_uint32_from(response.error_count_ack_checksum); + *ret_error_count_message_checksum = leconvert_uint32_from(response.error_count_message_checksum); + *ret_error_count_frame = leconvert_uint32_from(response.error_count_frame); + *ret_error_count_overflow = leconvert_uint32_from(response.error_count_overflow); + + return ret; +} + +int air_quality_set_bootloader_mode(AirQuality *air_quality, uint8_t mode, uint8_t *ret_status) { + DevicePrivate *device_p = air_quality->p; + SetBootloaderMode_Request request; + SetBootloaderMode_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_SET_BOOTLOADER_MODE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.mode = mode; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_status = response.status; + + return ret; +} + +int air_quality_get_bootloader_mode(AirQuality *air_quality, uint8_t *ret_mode) { + DevicePrivate *device_p = air_quality->p; + GetBootloaderMode_Request request; + GetBootloaderMode_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_BOOTLOADER_MODE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_mode = response.mode; + + return ret; +} + +int air_quality_set_write_firmware_pointer(AirQuality *air_quality, uint32_t pointer) { + DevicePrivate *device_p = air_quality->p; + SetWriteFirmwarePointer_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_SET_WRITE_FIRMWARE_POINTER, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.pointer = leconvert_uint32_to(pointer); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_write_firmware(AirQuality *air_quality, uint8_t data[64], uint8_t *ret_status) { + DevicePrivate *device_p = air_quality->p; + WriteFirmware_Request request; + WriteFirmware_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_WRITE_FIRMWARE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.data, data, 64 * sizeof(uint8_t)); + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_status = response.status; + + return ret; +} + +int air_quality_set_status_led_config(AirQuality *air_quality, uint8_t config) { + DevicePrivate *device_p = air_quality->p; + SetStatusLEDConfig_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_SET_STATUS_LED_CONFIG, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.config = config; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_get_status_led_config(AirQuality *air_quality, uint8_t *ret_config) { + DevicePrivate *device_p = air_quality->p; + GetStatusLEDConfig_Request request; + GetStatusLEDConfig_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_STATUS_LED_CONFIG, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_config = response.config; + + return ret; +} + +int air_quality_get_chip_temperature(AirQuality *air_quality, int16_t *ret_temperature) { + DevicePrivate *device_p = air_quality->p; + GetChipTemperature_Request request; + GetChipTemperature_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_CHIP_TEMPERATURE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_temperature = leconvert_int16_from(response.temperature); + + return ret; +} + +int air_quality_reset(AirQuality *air_quality) { + DevicePrivate *device_p = air_quality->p; + Reset_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_RESET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_write_uid(AirQuality *air_quality, uint32_t uid) { + DevicePrivate *device_p = air_quality->p; + WriteUID_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_WRITE_UID, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.uid = leconvert_uint32_to(uid); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int air_quality_read_uid(AirQuality *air_quality, uint32_t *ret_uid) { + DevicePrivate *device_p = air_quality->p; + ReadUID_Request request; + ReadUID_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_READ_UID, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_uid = leconvert_uint32_from(response.uid); + + return ret; +} + +int air_quality_get_identity(AirQuality *air_quality, char ret_uid[8], char ret_connected_uid[8], char *ret_position, uint8_t ret_hardware_version[3], uint8_t ret_firmware_version[3], uint16_t *ret_device_identifier) { + DevicePrivate *device_p = air_quality->p; + GetIdentity_Request request; + GetIdentity_Response response; + int ret; + + ret = packet_header_create(&request.header, sizeof(request), AIR_QUALITY_FUNCTION_GET_IDENTITY, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_uid, response.uid, 8); + memcpy(ret_connected_uid, response.connected_uid, 8); + *ret_position = response.position; + memcpy(ret_hardware_version, response.hardware_version, 3 * sizeof(uint8_t)); + memcpy(ret_firmware_version, response.firmware_version, 3 * sizeof(uint8_t)); + *ret_device_identifier = leconvert_uint16_from(response.device_identifier); + + return ret; +} + +#ifdef __cplusplus +} +#endif diff --git a/tinkerforge/bricklet_air_quality.h b/tinkerforge/bricklet_air_quality.h new file mode 100644 index 0000000..a73a706 --- /dev/null +++ b/tinkerforge/bricklet_air_quality.h @@ -0,0 +1,941 @@ +/* *********************************************************** + * This file was automatically generated on 2021-01-15. * + * * + * C/C++ Bindings Version 2.1.31 * + * * + * If you have a bugfix for this file and want to commit it, * + * please fix the bug in the generator. You can find a link * + * to the generators git repository on tinkerforge.com * + *************************************************************/ + +#ifndef BRICKLET_AIR_QUALITY_H +#define BRICKLET_AIR_QUALITY_H + +#include "ip_connection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup BrickletAirQuality Air Quality Bricklet + */ + +/** + * \ingroup BrickletAirQuality + * + * Measures IAQ index, temperature, humidity and air pressure + */ +typedef Device AirQuality; + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_ALL_VALUES 1 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_SET_TEMPERATURE_OFFSET 2 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_TEMPERATURE_OFFSET 3 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_SET_ALL_VALUES_CALLBACK_CONFIGURATION 4 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_ALL_VALUES_CALLBACK_CONFIGURATION 5 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_IAQ_INDEX 7 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_SET_IAQ_INDEX_CALLBACK_CONFIGURATION 8 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_IAQ_INDEX_CALLBACK_CONFIGURATION 9 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_TEMPERATURE 11 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_SET_TEMPERATURE_CALLBACK_CONFIGURATION 12 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_TEMPERATURE_CALLBACK_CONFIGURATION 13 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_HUMIDITY 15 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_SET_HUMIDITY_CALLBACK_CONFIGURATION 16 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_HUMIDITY_CALLBACK_CONFIGURATION 17 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_AIR_PRESSURE 19 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_SET_AIR_PRESSURE_CALLBACK_CONFIGURATION 20 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_AIR_PRESSURE_CALLBACK_CONFIGURATION 21 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_REMOVE_CALIBRATION 23 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_SET_BACKGROUND_CALIBRATION_DURATION 24 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_BACKGROUND_CALIBRATION_DURATION 25 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_SPITFP_ERROR_COUNT 234 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_SET_BOOTLOADER_MODE 235 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_BOOTLOADER_MODE 236 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_SET_WRITE_FIRMWARE_POINTER 237 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_WRITE_FIRMWARE 238 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_SET_STATUS_LED_CONFIG 239 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_STATUS_LED_CONFIG 240 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_CHIP_TEMPERATURE 242 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_RESET 243 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_WRITE_UID 248 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_READ_UID 249 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_FUNCTION_GET_IDENTITY 255 + +/** + * \ingroup BrickletAirQuality + * + * Signature: \code void callback(int32_t iaq_index, uint8_t iaq_index_accuracy, int32_t temperature, int32_t humidity, int32_t air_pressure, void *user_data) \endcode + * + * This callback is triggered periodically according to the configuration set by + * {@link air_quality_set_all_values_callback_configuration}. + * + * The parameters are the same as {@link air_quality_get_all_values}. + */ +#define AIR_QUALITY_CALLBACK_ALL_VALUES 6 + +/** + * \ingroup BrickletAirQuality + * + * Signature: \code void callback(int32_t iaq_index, uint8_t iaq_index_accuracy, void *user_data) \endcode + * + * This callback is triggered periodically according to the configuration set by + * {@link air_quality_set_iaq_index_callback_configuration}. + * + * The parameters are the same as {@link air_quality_get_iaq_index}. + */ +#define AIR_QUALITY_CALLBACK_IAQ_INDEX 10 + +/** + * \ingroup BrickletAirQuality + * + * Signature: \code void callback(int32_t temperature, void *user_data) \endcode + * + * This callback is triggered periodically according to the configuration set by + * {@link air_quality_set_temperature_callback_configuration}. + * + * The parameter is the same as {@link air_quality_get_temperature}. + */ +#define AIR_QUALITY_CALLBACK_TEMPERATURE 14 + +/** + * \ingroup BrickletAirQuality + * + * Signature: \code void callback(int32_t humidity, void *user_data) \endcode + * + * This callback is triggered periodically according to the configuration set by + * {@link air_quality_set_humidity_callback_configuration}. + * + * The parameter is the same as {@link air_quality_get_humidity}. + */ +#define AIR_QUALITY_CALLBACK_HUMIDITY 18 + +/** + * \ingroup BrickletAirQuality + * + * Signature: \code void callback(int32_t air_pressure, void *user_data) \endcode + * + * This callback is triggered periodically according to the configuration set by + * {@link air_quality_set_air_pressure_callback_configuration}. + * + * The parameter is the same as {@link air_quality_get_air_pressure}. + */ +#define AIR_QUALITY_CALLBACK_AIR_PRESSURE 22 + + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_ACCURACY_UNRELIABLE 0 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_ACCURACY_LOW 1 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_ACCURACY_MEDIUM 2 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_ACCURACY_HIGH 3 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_THRESHOLD_OPTION_OFF 'x' + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_THRESHOLD_OPTION_OUTSIDE 'o' + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_THRESHOLD_OPTION_INSIDE 'i' + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_THRESHOLD_OPTION_SMALLER '<' + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_THRESHOLD_OPTION_GREATER '>' + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_DURATION_4_DAYS 0 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_DURATION_28_DAYS 1 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_MODE_BOOTLOADER 0 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_MODE_FIRMWARE 1 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_MODE_BOOTLOADER_WAIT_FOR_REBOOT 2 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_MODE_FIRMWARE_WAIT_FOR_REBOOT 3 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_MODE_FIRMWARE_WAIT_FOR_ERASE_AND_REBOOT 4 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_STATUS_OK 0 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_STATUS_INVALID_MODE 1 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_STATUS_NO_CHANGE 2 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_STATUS_ENTRY_FUNCTION_NOT_PRESENT 3 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_STATUS_DEVICE_IDENTIFIER_INCORRECT 4 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_BOOTLOADER_STATUS_CRC_MISMATCH 5 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_STATUS_LED_CONFIG_OFF 0 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_STATUS_LED_CONFIG_ON 1 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_STATUS_LED_CONFIG_SHOW_HEARTBEAT 2 + +/** + * \ingroup BrickletAirQuality + */ +#define AIR_QUALITY_STATUS_LED_CONFIG_SHOW_STATUS 3 + +/** + * \ingroup BrickletAirQuality + * + * This constant is used to identify a Air Quality Bricklet. + * + * The {@link air_quality_get_identity} function and the + * {@link IPCON_CALLBACK_ENUMERATE} callback of the IP Connection have a + * \c device_identifier parameter to specify the Brick's or Bricklet's type. + */ +#define AIR_QUALITY_DEVICE_IDENTIFIER 297 + +/** + * \ingroup BrickletAirQuality + * + * This constant represents the display name of a Air Quality Bricklet. + */ +#define AIR_QUALITY_DEVICE_DISPLAY_NAME "Air Quality Bricklet" + +/** + * \ingroup BrickletAirQuality + * + * Creates the device object \c air_quality with the unique device ID \c uid and adds + * it to the IPConnection \c ipcon. + */ +void air_quality_create(AirQuality *air_quality, const char *uid, IPConnection *ipcon); + +/** + * \ingroup BrickletAirQuality + * + * Removes the device object \c air_quality from its IPConnection and destroys it. + * The device object cannot be used anymore afterwards. + */ +void air_quality_destroy(AirQuality *air_quality); + +/** + * \ingroup BrickletAirQuality + * + * Returns the response expected flag for the function specified by the + * \c function_id parameter. It is *true* if the function is expected to + * send a response, *false* otherwise. + * + * For getter functions this is enabled by default and cannot be disabled, + * because those functions will always send a response. For callback + * configuration functions it is enabled by default too, but can be disabled + * via the air_quality_set_response_expected function. For setter functions it is + * disabled by default and can be enabled. + * + * Enabling the response expected flag for a setter function allows to + * detect timeouts and other error conditions calls of this setter as well. + * The device will then send a response for this purpose. If this flag is + * disabled for a setter function then no response is sent and errors are + * silently ignored, because they cannot be detected. + */ +int air_quality_get_response_expected(AirQuality *air_quality, uint8_t function_id, bool *ret_response_expected); + +/** + * \ingroup BrickletAirQuality + * + * Changes the response expected flag of the function specified by the + * \c function_id parameter. This flag can only be changed for setter + * (default value: *false*) and callback configuration functions + * (default value: *true*). For getter functions it is always enabled. + * + * Enabling the response expected flag for a setter function allows to detect + * timeouts and other error conditions calls of this setter as well. The device + * will then send a response for this purpose. If this flag is disabled for a + * setter function then no response is sent and errors are silently ignored, + * because they cannot be detected. + */ +int air_quality_set_response_expected(AirQuality *air_quality, uint8_t function_id, bool response_expected); + +/** + * \ingroup BrickletAirQuality + * + * Changes the response expected flag for all setter and callback configuration + * functions of this device at once. + */ +int air_quality_set_response_expected_all(AirQuality *air_quality, bool response_expected); + +/** + * \ingroup BrickletAirQuality + * + * Registers the given \c function with the given \c callback_id. The + * \c user_data will be passed as the last parameter to the \c function. + */ +void air_quality_register_callback(AirQuality *air_quality, int16_t callback_id, void (*function)(void), void *user_data); + +/** + * \ingroup BrickletAirQuality + * + * Returns the API version (major, minor, release) of the bindings for this + * device. + */ +int air_quality_get_api_version(AirQuality *air_quality, uint8_t ret_api_version[3]); + +/** + * \ingroup BrickletAirQuality + * + * Returns all values measured by the Air Quality Bricklet. The values are + * IAQ (Indoor Air Quality) Index (higher value means greater level of air pollution), IAQ Index Accuracy, Temperature, Humidity and + * Air Pressure. + * + * .. image:: /Images/Misc/bricklet_air_quality_iaq_index.png + * :scale: 100 % + * :alt: Air Quality Index description + * :align: center + * :target: ../../_images/Misc/bricklet_air_quality_iaq_index.png + */ +int air_quality_get_all_values(AirQuality *air_quality, int32_t *ret_iaq_index, uint8_t *ret_iaq_index_accuracy, int32_t *ret_temperature, int32_t *ret_humidity, int32_t *ret_air_pressure); + +/** + * \ingroup BrickletAirQuality + * + * Sets a temperature offset. A offset of 10 will decrease the measured temperature by 0.1 °C. + * + * If you install this Bricklet into an enclosure and you want to measure the ambient + * temperature, you may have to decrease the measured temperature by some value to + * compensate for the error because of the heating inside of the enclosure. + * + * We recommend that you leave the parts in the enclosure running for at least + * 24 hours such that a temperature equilibrium can be reached. After that you can measure + * the temperature directly outside of enclosure and set the difference as offset. + * + * This temperature offset is used to calculate the relative humidity and + * IAQ index measurements. In case the Bricklet is installed in an enclosure, we + * recommend to measure and set the temperature offset to improve the accuracy of + * the measurements. + */ +int air_quality_set_temperature_offset(AirQuality *air_quality, int32_t offset); + +/** + * \ingroup BrickletAirQuality + * + * Returns the temperature offset as set by + * {@link air_quality_set_temperature_offset}. + */ +int air_quality_get_temperature_offset(AirQuality *air_quality, int32_t *ret_offset); + +/** + * \ingroup BrickletAirQuality + * + * The period is the period with which the {@link AIR_QUALITY_CALLBACK_ALL_VALUES} + * callback is triggered periodically. A value of 0 turns the callback off. + * + * If the `value has to change`-parameter is set to true, the callback is only + * triggered after at least one of the values has changed. If the values didn't + * change within the period, the callback is triggered immediately on change. + * + * If it is set to false, the callback is continuously triggered with the period, + * independent of the value. + */ +int air_quality_set_all_values_callback_configuration(AirQuality *air_quality, uint32_t period, bool value_has_to_change); + +/** + * \ingroup BrickletAirQuality + * + * Returns the callback configuration as set by + * {@link air_quality_set_all_values_callback_configuration}. + */ +int air_quality_get_all_values_callback_configuration(AirQuality *air_quality, uint32_t *ret_period, bool *ret_value_has_to_change); + +/** + * \ingroup BrickletAirQuality + * + * Returns the IAQ index and accuracy. The higher the IAQ index, the greater the level of air pollution. + * + * .. image:: /Images/Misc/bricklet_air_quality_iaq_index.png + * :scale: 100 % + * :alt: IAQ index description + * :align: center + * :target: ../../_images/Misc/bricklet_air_quality_iaq_index.png + * + * If you want to get the value periodically, it is recommended to use the + * {@link AIR_QUALITY_CALLBACK_IAQ_INDEX} callback. You can set the callback configuration + * with {@link air_quality_set_iaq_index_callback_configuration}. + */ +int air_quality_get_iaq_index(AirQuality *air_quality, int32_t *ret_iaq_index, uint8_t *ret_iaq_index_accuracy); + +/** + * \ingroup BrickletAirQuality + * + * The period is the period with which the {@link AIR_QUALITY_CALLBACK_IAQ_INDEX} + * callback is triggered periodically. A value of 0 turns the callback off. + * + * If the `value has to change`-parameter is set to true, the callback is only + * triggered after at least one of the values has changed. If the values didn't + * change within the period, the callback is triggered immediately on change. + * + * If it is set to false, the callback is continuously triggered with the period, + * independent of the value. + */ +int air_quality_set_iaq_index_callback_configuration(AirQuality *air_quality, uint32_t period, bool value_has_to_change); + +/** + * \ingroup BrickletAirQuality + * + * Returns the callback configuration as set by + * {@link air_quality_set_iaq_index_callback_configuration}. + */ +int air_quality_get_iaq_index_callback_configuration(AirQuality *air_quality, uint32_t *ret_period, bool *ret_value_has_to_change); + +/** + * \ingroup BrickletAirQuality + * + * Returns temperature. + * + * + * If you want to get the value periodically, it is recommended to use the + * {@link AIR_QUALITY_CALLBACK_TEMPERATURE} callback. You can set the callback configuration + * with {@link air_quality_set_temperature_callback_configuration}. + */ +int air_quality_get_temperature(AirQuality *air_quality, int32_t *ret_temperature); + +/** + * \ingroup BrickletAirQuality + * + * The period is the period with which the {@link AIR_QUALITY_CALLBACK_TEMPERATURE} callback is triggered + * periodically. A value of 0 turns the callback off. + * + * If the `value has to change`-parameter is set to true, the callback is only + * triggered after the value has changed. If the value didn't change + * within the period, the callback is triggered immediately on change. + * + * If it is set to false, the callback is continuously triggered with the period, + * independent of the value. + * + * It is furthermore possible to constrain the callback with thresholds. + * + * The `option`-parameter together with min/max sets a threshold for the {@link AIR_QUALITY_CALLBACK_TEMPERATURE} callback. + * + * The following options are possible: + * + * \verbatim + * "Option", "Description" + * + * "'x'", "Threshold is turned off" + * "'o'", "Threshold is triggered when the value is *outside* the min and max values" + * "'i'", "Threshold is triggered when the value is *inside* or equal to the min and max values" + * "'<'", "Threshold is triggered when the value is smaller than the min value (max is ignored)" + * "'>'", "Threshold is triggered when the value is greater than the min value (max is ignored)" + * \endverbatim + * + * If the option is set to 'x' (threshold turned off) the callback is triggered with the fixed period. + */ +int air_quality_set_temperature_callback_configuration(AirQuality *air_quality, uint32_t period, bool value_has_to_change, char option, int32_t min, int32_t max); + +/** + * \ingroup BrickletAirQuality + * + * Returns the callback configuration as set by {@link air_quality_set_temperature_callback_configuration}. + */ +int air_quality_get_temperature_callback_configuration(AirQuality *air_quality, uint32_t *ret_period, bool *ret_value_has_to_change, char *ret_option, int32_t *ret_min, int32_t *ret_max); + +/** + * \ingroup BrickletAirQuality + * + * Returns relative humidity. + * + * + * If you want to get the value periodically, it is recommended to use the + * {@link AIR_QUALITY_CALLBACK_HUMIDITY} callback. You can set the callback configuration + * with {@link air_quality_set_humidity_callback_configuration}. + */ +int air_quality_get_humidity(AirQuality *air_quality, int32_t *ret_humidity); + +/** + * \ingroup BrickletAirQuality + * + * The period is the period with which the {@link AIR_QUALITY_CALLBACK_HUMIDITY} callback is triggered + * periodically. A value of 0 turns the callback off. + * + * If the `value has to change`-parameter is set to true, the callback is only + * triggered after the value has changed. If the value didn't change + * within the period, the callback is triggered immediately on change. + * + * If it is set to false, the callback is continuously triggered with the period, + * independent of the value. + * + * It is furthermore possible to constrain the callback with thresholds. + * + * The `option`-parameter together with min/max sets a threshold for the {@link AIR_QUALITY_CALLBACK_HUMIDITY} callback. + * + * The following options are possible: + * + * \verbatim + * "Option", "Description" + * + * "'x'", "Threshold is turned off" + * "'o'", "Threshold is triggered when the value is *outside* the min and max values" + * "'i'", "Threshold is triggered when the value is *inside* or equal to the min and max values" + * "'<'", "Threshold is triggered when the value is smaller than the min value (max is ignored)" + * "'>'", "Threshold is triggered when the value is greater than the min value (max is ignored)" + * \endverbatim + * + * If the option is set to 'x' (threshold turned off) the callback is triggered with the fixed period. + */ +int air_quality_set_humidity_callback_configuration(AirQuality *air_quality, uint32_t period, bool value_has_to_change, char option, int32_t min, int32_t max); + +/** + * \ingroup BrickletAirQuality + * + * Returns the callback configuration as set by {@link air_quality_set_humidity_callback_configuration}. + */ +int air_quality_get_humidity_callback_configuration(AirQuality *air_quality, uint32_t *ret_period, bool *ret_value_has_to_change, char *ret_option, int32_t *ret_min, int32_t *ret_max); + +/** + * \ingroup BrickletAirQuality + * + * Returns air pressure. + * + * + * If you want to get the value periodically, it is recommended to use the + * {@link AIR_QUALITY_CALLBACK_AIR_PRESSURE} callback. You can set the callback configuration + * with {@link air_quality_set_air_pressure_callback_configuration}. + */ +int air_quality_get_air_pressure(AirQuality *air_quality, int32_t *ret_air_pressure); + +/** + * \ingroup BrickletAirQuality + * + * The period is the period with which the {@link AIR_QUALITY_CALLBACK_AIR_PRESSURE} callback is triggered + * periodically. A value of 0 turns the callback off. + * + * If the `value has to change`-parameter is set to true, the callback is only + * triggered after the value has changed. If the value didn't change + * within the period, the callback is triggered immediately on change. + * + * If it is set to false, the callback is continuously triggered with the period, + * independent of the value. + * + * It is furthermore possible to constrain the callback with thresholds. + * + * The `option`-parameter together with min/max sets a threshold for the {@link AIR_QUALITY_CALLBACK_AIR_PRESSURE} callback. + * + * The following options are possible: + * + * \verbatim + * "Option", "Description" + * + * "'x'", "Threshold is turned off" + * "'o'", "Threshold is triggered when the value is *outside* the min and max values" + * "'i'", "Threshold is triggered when the value is *inside* or equal to the min and max values" + * "'<'", "Threshold is triggered when the value is smaller than the min value (max is ignored)" + * "'>'", "Threshold is triggered when the value is greater than the min value (max is ignored)" + * \endverbatim + * + * If the option is set to 'x' (threshold turned off) the callback is triggered with the fixed period. + */ +int air_quality_set_air_pressure_callback_configuration(AirQuality *air_quality, uint32_t period, bool value_has_to_change, char option, int32_t min, int32_t max); + +/** + * \ingroup BrickletAirQuality + * + * Returns the callback configuration as set by {@link air_quality_set_air_pressure_callback_configuration}. + */ +int air_quality_get_air_pressure_callback_configuration(AirQuality *air_quality, uint32_t *ret_period, bool *ret_value_has_to_change, char *ret_option, int32_t *ret_min, int32_t *ret_max); + +/** + * \ingroup BrickletAirQuality + * + * Deletes the calibration from flash. After you call this function, + * you need to power cycle the Air Quality Bricklet. + * + * On the next power up the Bricklet will start a new calibration, as + * if it was started for the very first time. + * + * The calibration is based on the data of the last four days, so it takes + * four days until a full calibration is re-established. + * + * .. versionadded:: 2.0.3$nbsp;(Plugin) + */ +int air_quality_remove_calibration(AirQuality *air_quality); + +/** + * \ingroup BrickletAirQuality + * + * The Air Quality Bricklet uses an automatic background calibration mechanism to + * calculate the IAQ Index. This calibration mechanism considers a history of + * measured data. The duration of this history can be configured to either be + * 4 days or 28 days. + * + * If you keep the Bricklet mostly at one place and it does not get moved around + * to different environments, we recommend that you use a duration of 28 days. + * + * If you change the duration, the current calibration will be discarded and + * the calibration will start from beginning again. The configuration of the + * duration is saved in flash, so you should only have to call this function + * once in the lifetime of the Bricklet. + * + * The Bricklet has to be power cycled after this function is called + * for a duration change to take effect. + * + * Before firmware version 2.0.3 this was not configurable and the duration was + * 4 days. + * + * The default value (since firmware version 2.0.3) is 28 days. + * + * .. versionadded:: 2.0.3$nbsp;(Plugin) + */ +int air_quality_set_background_calibration_duration(AirQuality *air_quality, uint8_t duration); + +/** + * \ingroup BrickletAirQuality + * + * Returns the background calibration duration as set by + * {@link air_quality_set_background_calibration_duration}. + * + * .. versionadded:: 2.0.3$nbsp;(Plugin) + */ +int air_quality_get_background_calibration_duration(AirQuality *air_quality, uint8_t *ret_duration); + +/** + * \ingroup BrickletAirQuality + * + * Returns the error count for the communication between Brick and Bricklet. + * + * The errors are divided into + * + * * ACK checksum errors, + * * message checksum errors, + * * framing errors and + * * overflow errors. + * + * The errors counts are for errors that occur on the Bricklet side. All + * Bricks have a similar function that returns the errors on the Brick side. + */ +int air_quality_get_spitfp_error_count(AirQuality *air_quality, uint32_t *ret_error_count_ack_checksum, uint32_t *ret_error_count_message_checksum, uint32_t *ret_error_count_frame, uint32_t *ret_error_count_overflow); + +/** + * \ingroup BrickletAirQuality + * + * Sets the bootloader mode and returns the status after the requested + * mode change was instigated. + * + * You can change from bootloader mode to firmware mode and vice versa. A change + * from bootloader mode to firmware mode will only take place if the entry function, + * device identifier and CRC are present and correct. + * + * This function is used by Brick Viewer during flashing. It should not be + * necessary to call it in a normal user program. + */ +int air_quality_set_bootloader_mode(AirQuality *air_quality, uint8_t mode, uint8_t *ret_status); + +/** + * \ingroup BrickletAirQuality + * + * Returns the current bootloader mode, see {@link air_quality_set_bootloader_mode}. + */ +int air_quality_get_bootloader_mode(AirQuality *air_quality, uint8_t *ret_mode); + +/** + * \ingroup BrickletAirQuality + * + * Sets the firmware pointer for {@link air_quality_write_firmware}. The pointer has + * to be increased by chunks of size 64. The data is written to flash + * every 4 chunks (which equals to one page of size 256). + * + * This function is used by Brick Viewer during flashing. It should not be + * necessary to call it in a normal user program. + */ +int air_quality_set_write_firmware_pointer(AirQuality *air_quality, uint32_t pointer); + +/** + * \ingroup BrickletAirQuality + * + * Writes 64 Bytes of firmware at the position as written by + * {@link air_quality_set_write_firmware_pointer} before. The firmware is written + * to flash every 4 chunks. + * + * You can only write firmware in bootloader mode. + * + * This function is used by Brick Viewer during flashing. It should not be + * necessary to call it in a normal user program. + */ +int air_quality_write_firmware(AirQuality *air_quality, uint8_t data[64], uint8_t *ret_status); + +/** + * \ingroup BrickletAirQuality + * + * Sets the status LED configuration. By default the LED shows + * communication traffic between Brick and Bricklet, it flickers once + * for every 10 received data packets. + * + * You can also turn the LED permanently on/off or show a heartbeat. + * + * If the Bricklet is in bootloader mode, the LED is will show heartbeat by default. + */ +int air_quality_set_status_led_config(AirQuality *air_quality, uint8_t config); + +/** + * \ingroup BrickletAirQuality + * + * Returns the configuration as set by {@link air_quality_set_status_led_config} + */ +int air_quality_get_status_led_config(AirQuality *air_quality, uint8_t *ret_config); + +/** + * \ingroup BrickletAirQuality + * + * Returns the temperature as measured inside the microcontroller. The + * value returned is not the ambient temperature! + * + * The temperature is only proportional to the real temperature and it has bad + * accuracy. Practically it is only useful as an indicator for + * temperature changes. + */ +int air_quality_get_chip_temperature(AirQuality *air_quality, int16_t *ret_temperature); + +/** + * \ingroup BrickletAirQuality + * + * Calling this function will reset the Bricklet. All configurations + * will be lost. + * + * After a reset you have to create new device objects, + * calling functions on the existing ones will result in + * undefined behavior! + */ +int air_quality_reset(AirQuality *air_quality); + +/** + * \ingroup BrickletAirQuality + * + * Writes a new UID into flash. If you want to set a new UID + * you have to decode the Base58 encoded UID string into an + * integer first. + * + * We recommend that you use Brick Viewer to change the UID. + */ +int air_quality_write_uid(AirQuality *air_quality, uint32_t uid); + +/** + * \ingroup BrickletAirQuality + * + * Returns the current UID as an integer. Encode as + * Base58 to get the usual string version. + */ +int air_quality_read_uid(AirQuality *air_quality, uint32_t *ret_uid); + +/** + * \ingroup BrickletAirQuality + * + * Returns the UID, the UID where the Bricklet is connected to, + * the position, the hardware and firmware version as well as the + * device identifier. + * + * The position can be 'a', 'b', 'c', 'd', 'e', 'f', 'g' or 'h' (Bricklet Port). + * A Bricklet connected to an :ref:`Isolator Bricklet ` is always at + * position 'z'. + * + * The device identifier numbers can be found :ref:`here `. + * |device_identifier_constant| + */ +int air_quality_get_identity(AirQuality *air_quality, char ret_uid[8], char ret_connected_uid[8], char *ret_position, uint8_t ret_hardware_version[3], uint8_t ret_firmware_version[3], uint16_t *ret_device_identifier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tinkerforge/bricklet_outdoor_weather.c b/tinkerforge/bricklet_outdoor_weather.c new file mode 100644 index 0000000..ee91ed2 --- /dev/null +++ b/tinkerforge/bricklet_outdoor_weather.c @@ -0,0 +1,1083 @@ +/* *********************************************************** + * This file was automatically generated on 2021-01-15. * + * * + * C/C++ Bindings Version 2.1.31 * + * * + * If you have a bugfix for this file and want to commit it, * + * please fix the bug in the generator. You can find a link * + * to the generators git repository on tinkerforge.com * + *************************************************************/ + + +#define IPCON_EXPOSE_INTERNALS + +#include "bricklet_outdoor_weather.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +typedef void (*StationData_CallbackFunction)(uint8_t identifier, int16_t temperature, uint8_t humidity, uint32_t wind_speed, uint32_t gust_speed, uint32_t rain, uint8_t wind_direction, bool battery_low, void *user_data); + +typedef void (*SensorData_CallbackFunction)(uint8_t identifier, int16_t temperature, uint8_t humidity, void *user_data); + +#if defined _MSC_VER || defined __BORLANDC__ + #pragma pack(push) + #pragma pack(1) + #define ATTRIBUTE_PACKED +#elif defined __GNUC__ + #ifdef _WIN32 + // workaround struct packing bug in GCC 4.7 on Windows + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 + #define ATTRIBUTE_PACKED __attribute__((gcc_struct, packed)) + #else + #define ATTRIBUTE_PACKED __attribute__((packed)) + #endif +#else + #error unknown compiler, do not know how to enable struct packing +#endif + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetStationIdentifiersLowLevel_Request; + +typedef struct { + PacketHeader header; + uint16_t identifiers_length; + uint16_t identifiers_chunk_offset; + uint8_t identifiers_chunk_data[60]; +} ATTRIBUTE_PACKED GetStationIdentifiersLowLevel_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetSensorIdentifiersLowLevel_Request; + +typedef struct { + PacketHeader header; + uint16_t identifiers_length; + uint16_t identifiers_chunk_offset; + uint8_t identifiers_chunk_data[60]; +} ATTRIBUTE_PACKED GetSensorIdentifiersLowLevel_Response; + +typedef struct { + PacketHeader header; + uint8_t identifier; +} ATTRIBUTE_PACKED GetStationData_Request; + +typedef struct { + PacketHeader header; + int16_t temperature; + uint8_t humidity; + uint32_t wind_speed; + uint32_t gust_speed; + uint32_t rain; + uint8_t wind_direction; + uint8_t battery_low; + uint16_t last_change; +} ATTRIBUTE_PACKED GetStationData_Response; + +typedef struct { + PacketHeader header; + uint8_t identifier; +} ATTRIBUTE_PACKED GetSensorData_Request; + +typedef struct { + PacketHeader header; + int16_t temperature; + uint8_t humidity; + uint16_t last_change; +} ATTRIBUTE_PACKED GetSensorData_Response; + +typedef struct { + PacketHeader header; + uint8_t enable_callback; +} ATTRIBUTE_PACKED SetStationCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetStationCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; + uint8_t enable_callback; +} ATTRIBUTE_PACKED GetStationCallbackConfiguration_Response; + +typedef struct { + PacketHeader header; + uint8_t enable_callback; +} ATTRIBUTE_PACKED SetSensorCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetSensorCallbackConfiguration_Request; + +typedef struct { + PacketHeader header; + uint8_t enable_callback; +} ATTRIBUTE_PACKED GetSensorCallbackConfiguration_Response; + +typedef struct { + PacketHeader header; + uint8_t identifier; + int16_t temperature; + uint8_t humidity; + uint32_t wind_speed; + uint32_t gust_speed; + uint32_t rain; + uint8_t wind_direction; + uint8_t battery_low; +} ATTRIBUTE_PACKED StationData_Callback; + +typedef struct { + PacketHeader header; + uint8_t identifier; + int16_t temperature; + uint8_t humidity; +} ATTRIBUTE_PACKED SensorData_Callback; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetSPITFPErrorCount_Request; + +typedef struct { + PacketHeader header; + uint32_t error_count_ack_checksum; + uint32_t error_count_message_checksum; + uint32_t error_count_frame; + uint32_t error_count_overflow; +} ATTRIBUTE_PACKED GetSPITFPErrorCount_Response; + +typedef struct { + PacketHeader header; + uint8_t mode; +} ATTRIBUTE_PACKED SetBootloaderMode_Request; + +typedef struct { + PacketHeader header; + uint8_t status; +} ATTRIBUTE_PACKED SetBootloaderMode_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetBootloaderMode_Request; + +typedef struct { + PacketHeader header; + uint8_t mode; +} ATTRIBUTE_PACKED GetBootloaderMode_Response; + +typedef struct { + PacketHeader header; + uint32_t pointer; +} ATTRIBUTE_PACKED SetWriteFirmwarePointer_Request; + +typedef struct { + PacketHeader header; + uint8_t data[64]; +} ATTRIBUTE_PACKED WriteFirmware_Request; + +typedef struct { + PacketHeader header; + uint8_t status; +} ATTRIBUTE_PACKED WriteFirmware_Response; + +typedef struct { + PacketHeader header; + uint8_t config; +} ATTRIBUTE_PACKED SetStatusLEDConfig_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetStatusLEDConfig_Request; + +typedef struct { + PacketHeader header; + uint8_t config; +} ATTRIBUTE_PACKED GetStatusLEDConfig_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetChipTemperature_Request; + +typedef struct { + PacketHeader header; + int16_t temperature; +} ATTRIBUTE_PACKED GetChipTemperature_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED Reset_Request; + +typedef struct { + PacketHeader header; + uint32_t uid; +} ATTRIBUTE_PACKED WriteUID_Request; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED ReadUID_Request; + +typedef struct { + PacketHeader header; + uint32_t uid; +} ATTRIBUTE_PACKED ReadUID_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED GetIdentity_Request; + +typedef struct { + PacketHeader header; + char uid[8]; + char connected_uid[8]; + char position; + uint8_t hardware_version[3]; + uint8_t firmware_version[3]; + uint16_t device_identifier; +} ATTRIBUTE_PACKED GetIdentity_Response; + +#if defined _MSC_VER || defined __BORLANDC__ + #pragma pack(pop) +#endif +#undef ATTRIBUTE_PACKED + +static void outdoor_weather_callback_wrapper_station_data(DevicePrivate *device_p, Packet *packet) { + StationData_CallbackFunction callback_function; + void *user_data; + StationData_Callback *callback; + bool unpacked_battery_low; + + if (packet->header.length != sizeof(StationData_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (StationData_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + OUTDOOR_WEATHER_CALLBACK_STATION_DATA]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + OUTDOOR_WEATHER_CALLBACK_STATION_DATA]; + callback = (StationData_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->temperature = leconvert_int16_from(callback->temperature); + callback->wind_speed = leconvert_uint32_from(callback->wind_speed); + callback->gust_speed = leconvert_uint32_from(callback->gust_speed); + callback->rain = leconvert_uint32_from(callback->rain); + unpacked_battery_low = callback->battery_low != 0; + + callback_function(callback->identifier, callback->temperature, callback->humidity, callback->wind_speed, callback->gust_speed, callback->rain, callback->wind_direction, unpacked_battery_low, user_data); +} + +static void outdoor_weather_callback_wrapper_sensor_data(DevicePrivate *device_p, Packet *packet) { + SensorData_CallbackFunction callback_function; + void *user_data; + SensorData_Callback *callback; + + if (packet->header.length != sizeof(SensorData_Callback)) { + return; // silently ignoring callback with wrong length + } + + callback_function = (SensorData_CallbackFunction)device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + OUTDOOR_WEATHER_CALLBACK_SENSOR_DATA]; + user_data = device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + OUTDOOR_WEATHER_CALLBACK_SENSOR_DATA]; + callback = (SensorData_Callback *)packet; + (void)callback; // avoid unused variable warning + + if (callback_function == NULL) { + return; + } + + callback->temperature = leconvert_int16_from(callback->temperature); + + callback_function(callback->identifier, callback->temperature, callback->humidity, user_data); +} + +void outdoor_weather_create(OutdoorWeather *outdoor_weather, const char *uid, IPConnection *ipcon) { + IPConnectionPrivate *ipcon_p = ipcon->p; + DevicePrivate *device_p; + + device_create(outdoor_weather, uid, ipcon_p, 2, 0, 0, OUTDOOR_WEATHER_DEVICE_IDENTIFIER); + + device_p = outdoor_weather->p; + + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_STATION_IDENTIFIERS_LOW_LEVEL] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_SENSOR_IDENTIFIERS_LOW_LEVEL] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_STATION_DATA] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_SENSOR_DATA] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_SET_STATION_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_STATION_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_SET_SENSOR_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_SENSOR_CALLBACK_CONFIGURATION] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_SPITFP_ERROR_COUNT] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_SET_BOOTLOADER_MODE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_BOOTLOADER_MODE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_SET_WRITE_FIRMWARE_POINTER] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_WRITE_FIRMWARE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_SET_STATUS_LED_CONFIG] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_STATUS_LED_CONFIG] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_CHIP_TEMPERATURE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_RESET] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_WRITE_UID] = DEVICE_RESPONSE_EXPECTED_FALSE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_READ_UID] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[OUTDOOR_WEATHER_FUNCTION_GET_IDENTITY] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + + device_p->callback_wrappers[OUTDOOR_WEATHER_CALLBACK_STATION_DATA] = outdoor_weather_callback_wrapper_station_data; + device_p->callback_wrappers[OUTDOOR_WEATHER_CALLBACK_SENSOR_DATA] = outdoor_weather_callback_wrapper_sensor_data; + + ipcon_add_device(ipcon_p, device_p); +} + +void outdoor_weather_destroy(OutdoorWeather *outdoor_weather) { + device_release(outdoor_weather->p); +} + +int outdoor_weather_get_response_expected(OutdoorWeather *outdoor_weather, uint8_t function_id, bool *ret_response_expected) { + return device_get_response_expected(outdoor_weather->p, function_id, ret_response_expected); +} + +int outdoor_weather_set_response_expected(OutdoorWeather *outdoor_weather, uint8_t function_id, bool response_expected) { + return device_set_response_expected(outdoor_weather->p, function_id, response_expected); +} + +int outdoor_weather_set_response_expected_all(OutdoorWeather *outdoor_weather, bool response_expected) { + return device_set_response_expected_all(outdoor_weather->p, response_expected); +} + +void outdoor_weather_register_callback(OutdoorWeather *outdoor_weather, int16_t callback_id, void (*function)(void), void *user_data) { + device_register_callback(outdoor_weather->p, callback_id, function, user_data); +} + +int outdoor_weather_get_api_version(OutdoorWeather *outdoor_weather, uint8_t ret_api_version[3]) { + return device_get_api_version(outdoor_weather->p, ret_api_version); +} + +int outdoor_weather_get_station_identifiers_low_level(OutdoorWeather *outdoor_weather, uint16_t *ret_identifiers_length, uint16_t *ret_identifiers_chunk_offset, uint8_t ret_identifiers_chunk_data[60]) { + DevicePrivate *device_p = outdoor_weather->p; + GetStationIdentifiersLowLevel_Request request; + GetStationIdentifiersLowLevel_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_STATION_IDENTIFIERS_LOW_LEVEL, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_identifiers_length = leconvert_uint16_from(response.identifiers_length); + *ret_identifiers_chunk_offset = leconvert_uint16_from(response.identifiers_chunk_offset); + memcpy(ret_identifiers_chunk_data, response.identifiers_chunk_data, 60 * sizeof(uint8_t)); + + return ret; +} + +int outdoor_weather_get_sensor_identifiers_low_level(OutdoorWeather *outdoor_weather, uint16_t *ret_identifiers_length, uint16_t *ret_identifiers_chunk_offset, uint8_t ret_identifiers_chunk_data[60]) { + DevicePrivate *device_p = outdoor_weather->p; + GetSensorIdentifiersLowLevel_Request request; + GetSensorIdentifiersLowLevel_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_SENSOR_IDENTIFIERS_LOW_LEVEL, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_identifiers_length = leconvert_uint16_from(response.identifiers_length); + *ret_identifiers_chunk_offset = leconvert_uint16_from(response.identifiers_chunk_offset); + memcpy(ret_identifiers_chunk_data, response.identifiers_chunk_data, 60 * sizeof(uint8_t)); + + return ret; +} + +int outdoor_weather_get_station_data(OutdoorWeather *outdoor_weather, uint8_t identifier, int16_t *ret_temperature, uint8_t *ret_humidity, uint32_t *ret_wind_speed, uint32_t *ret_gust_speed, uint32_t *ret_rain, uint8_t *ret_wind_direction, bool *ret_battery_low, uint16_t *ret_last_change) { + DevicePrivate *device_p = outdoor_weather->p; + GetStationData_Request request; + GetStationData_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_STATION_DATA, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.identifier = identifier; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_temperature = leconvert_int16_from(response.temperature); + *ret_humidity = response.humidity; + *ret_wind_speed = leconvert_uint32_from(response.wind_speed); + *ret_gust_speed = leconvert_uint32_from(response.gust_speed); + *ret_rain = leconvert_uint32_from(response.rain); + *ret_wind_direction = response.wind_direction; + *ret_battery_low = response.battery_low != 0; + *ret_last_change = leconvert_uint16_from(response.last_change); + + return ret; +} + +int outdoor_weather_get_sensor_data(OutdoorWeather *outdoor_weather, uint8_t identifier, int16_t *ret_temperature, uint8_t *ret_humidity, uint16_t *ret_last_change) { + DevicePrivate *device_p = outdoor_weather->p; + GetSensorData_Request request; + GetSensorData_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_SENSOR_DATA, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.identifier = identifier; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_temperature = leconvert_int16_from(response.temperature); + *ret_humidity = response.humidity; + *ret_last_change = leconvert_uint16_from(response.last_change); + + return ret; +} + +int outdoor_weather_set_station_callback_configuration(OutdoorWeather *outdoor_weather, bool enable_callback) { + DevicePrivate *device_p = outdoor_weather->p; + SetStationCallbackConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_SET_STATION_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.enable_callback = enable_callback ? 1 : 0; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int outdoor_weather_get_station_callback_configuration(OutdoorWeather *outdoor_weather, bool *ret_enable_callback) { + DevicePrivate *device_p = outdoor_weather->p; + GetStationCallbackConfiguration_Request request; + GetStationCallbackConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_STATION_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_enable_callback = response.enable_callback != 0; + + return ret; +} + +int outdoor_weather_set_sensor_callback_configuration(OutdoorWeather *outdoor_weather, bool enable_callback) { + DevicePrivate *device_p = outdoor_weather->p; + SetSensorCallbackConfiguration_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_SET_SENSOR_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.enable_callback = enable_callback ? 1 : 0; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int outdoor_weather_get_sensor_callback_configuration(OutdoorWeather *outdoor_weather, bool *ret_enable_callback) { + DevicePrivate *device_p = outdoor_weather->p; + GetSensorCallbackConfiguration_Request request; + GetSensorCallbackConfiguration_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_SENSOR_CALLBACK_CONFIGURATION, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_enable_callback = response.enable_callback != 0; + + return ret; +} + +int outdoor_weather_get_spitfp_error_count(OutdoorWeather *outdoor_weather, uint32_t *ret_error_count_ack_checksum, uint32_t *ret_error_count_message_checksum, uint32_t *ret_error_count_frame, uint32_t *ret_error_count_overflow) { + DevicePrivate *device_p = outdoor_weather->p; + GetSPITFPErrorCount_Request request; + GetSPITFPErrorCount_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_SPITFP_ERROR_COUNT, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_error_count_ack_checksum = leconvert_uint32_from(response.error_count_ack_checksum); + *ret_error_count_message_checksum = leconvert_uint32_from(response.error_count_message_checksum); + *ret_error_count_frame = leconvert_uint32_from(response.error_count_frame); + *ret_error_count_overflow = leconvert_uint32_from(response.error_count_overflow); + + return ret; +} + +int outdoor_weather_set_bootloader_mode(OutdoorWeather *outdoor_weather, uint8_t mode, uint8_t *ret_status) { + DevicePrivate *device_p = outdoor_weather->p; + SetBootloaderMode_Request request; + SetBootloaderMode_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_SET_BOOTLOADER_MODE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.mode = mode; + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_status = response.status; + + return ret; +} + +int outdoor_weather_get_bootloader_mode(OutdoorWeather *outdoor_weather, uint8_t *ret_mode) { + DevicePrivate *device_p = outdoor_weather->p; + GetBootloaderMode_Request request; + GetBootloaderMode_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_BOOTLOADER_MODE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_mode = response.mode; + + return ret; +} + +int outdoor_weather_set_write_firmware_pointer(OutdoorWeather *outdoor_weather, uint32_t pointer) { + DevicePrivate *device_p = outdoor_weather->p; + SetWriteFirmwarePointer_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_SET_WRITE_FIRMWARE_POINTER, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.pointer = leconvert_uint32_to(pointer); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int outdoor_weather_write_firmware(OutdoorWeather *outdoor_weather, uint8_t data[64], uint8_t *ret_status) { + DevicePrivate *device_p = outdoor_weather->p; + WriteFirmware_Request request; + WriteFirmware_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_WRITE_FIRMWARE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.data, data, 64 * sizeof(uint8_t)); + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_status = response.status; + + return ret; +} + +int outdoor_weather_set_status_led_config(OutdoorWeather *outdoor_weather, uint8_t config) { + DevicePrivate *device_p = outdoor_weather->p; + SetStatusLEDConfig_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_SET_STATUS_LED_CONFIG, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.config = config; + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int outdoor_weather_get_status_led_config(OutdoorWeather *outdoor_weather, uint8_t *ret_config) { + DevicePrivate *device_p = outdoor_weather->p; + GetStatusLEDConfig_Request request; + GetStatusLEDConfig_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_STATUS_LED_CONFIG, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_config = response.config; + + return ret; +} + +int outdoor_weather_get_chip_temperature(OutdoorWeather *outdoor_weather, int16_t *ret_temperature) { + DevicePrivate *device_p = outdoor_weather->p; + GetChipTemperature_Request request; + GetChipTemperature_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_CHIP_TEMPERATURE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_temperature = leconvert_int16_from(response.temperature); + + return ret; +} + +int outdoor_weather_reset(OutdoorWeather *outdoor_weather) { + DevicePrivate *device_p = outdoor_weather->p; + Reset_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_RESET, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int outdoor_weather_write_uid(OutdoorWeather *outdoor_weather, uint32_t uid) { + DevicePrivate *device_p = outdoor_weather->p; + WriteUID_Request request; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_WRITE_UID, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + request.uid = leconvert_uint32_to(uid); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +int outdoor_weather_read_uid(OutdoorWeather *outdoor_weather, uint32_t *ret_uid) { + DevicePrivate *device_p = outdoor_weather->p; + ReadUID_Request request; + ReadUID_Response response; + int ret; + + ret = device_check_validity(device_p); + + if (ret < 0) { + return ret; + } + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_READ_UID, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + *ret_uid = leconvert_uint32_from(response.uid); + + return ret; +} + +int outdoor_weather_get_identity(OutdoorWeather *outdoor_weather, char ret_uid[8], char ret_connected_uid[8], char *ret_position, uint8_t ret_hardware_version[3], uint8_t ret_firmware_version[3], uint16_t *ret_device_identifier) { + DevicePrivate *device_p = outdoor_weather->p; + GetIdentity_Request request; + GetIdentity_Response response; + int ret; + + ret = packet_header_create(&request.header, sizeof(request), OUTDOOR_WEATHER_FUNCTION_GET_IDENTITY, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_uid, response.uid, 8); + memcpy(ret_connected_uid, response.connected_uid, 8); + *ret_position = response.position; + memcpy(ret_hardware_version, response.hardware_version, 3 * sizeof(uint8_t)); + memcpy(ret_firmware_version, response.firmware_version, 3 * sizeof(uint8_t)); + *ret_device_identifier = leconvert_uint16_from(response.device_identifier); + + return ret; +} + +int outdoor_weather_get_station_identifiers(OutdoorWeather *outdoor_weather, uint8_t *ret_identifiers, uint16_t *ret_identifiers_length) { + DevicePrivate *device_p = outdoor_weather->p; + int ret = 0; + uint16_t identifiers_length = 0; + uint16_t identifiers_chunk_offset; + uint8_t identifiers_chunk_data[60]; + bool identifiers_out_of_sync; + uint16_t identifiers_chunk_length; + + *ret_identifiers_length = 0; + + mutex_lock(&device_p->stream_mutex); + + ret = outdoor_weather_get_station_identifiers_low_level(outdoor_weather, &identifiers_length, &identifiers_chunk_offset, identifiers_chunk_data); + + if (ret < 0) { + goto unlock; + } + + identifiers_out_of_sync = identifiers_chunk_offset != 0; + + if (!identifiers_out_of_sync) { + identifiers_chunk_length = identifiers_length - identifiers_chunk_offset; + + if (identifiers_chunk_length > 60) { + identifiers_chunk_length = 60; + } + + memcpy(ret_identifiers, identifiers_chunk_data, sizeof(uint8_t) * identifiers_chunk_length); + *ret_identifiers_length = identifiers_chunk_length; + + while (*ret_identifiers_length < identifiers_length) { + ret = outdoor_weather_get_station_identifiers_low_level(outdoor_weather, &identifiers_length, &identifiers_chunk_offset, identifiers_chunk_data); + + if (ret < 0) { + goto unlock; + } + + identifiers_out_of_sync = identifiers_chunk_offset != *ret_identifiers_length; + + if (identifiers_out_of_sync) { + break; + } + + identifiers_chunk_length = identifiers_length - identifiers_chunk_offset; + + if (identifiers_chunk_length > 60) { + identifiers_chunk_length = 60; + } + + memcpy(&ret_identifiers[*ret_identifiers_length], identifiers_chunk_data, sizeof(uint8_t) * identifiers_chunk_length); + *ret_identifiers_length += identifiers_chunk_length; + } + } + + if (identifiers_out_of_sync) { + *ret_identifiers_length = 0; // return empty array + + // discard remaining stream to bring it back in-sync + while (identifiers_chunk_offset + 60 < identifiers_length) { + ret = outdoor_weather_get_station_identifiers_low_level(outdoor_weather, &identifiers_length, &identifiers_chunk_offset, identifiers_chunk_data); + + if (ret < 0) { + goto unlock; + } + } + + ret = E_STREAM_OUT_OF_SYNC; + } + +unlock: + mutex_unlock(&device_p->stream_mutex); + + return ret; +} + +int outdoor_weather_get_sensor_identifiers(OutdoorWeather *outdoor_weather, uint8_t *ret_identifiers, uint16_t *ret_identifiers_length) { + DevicePrivate *device_p = outdoor_weather->p; + int ret = 0; + uint16_t identifiers_length = 0; + uint16_t identifiers_chunk_offset; + uint8_t identifiers_chunk_data[60]; + bool identifiers_out_of_sync; + uint16_t identifiers_chunk_length; + + *ret_identifiers_length = 0; + + mutex_lock(&device_p->stream_mutex); + + ret = outdoor_weather_get_sensor_identifiers_low_level(outdoor_weather, &identifiers_length, &identifiers_chunk_offset, identifiers_chunk_data); + + if (ret < 0) { + goto unlock; + } + + identifiers_out_of_sync = identifiers_chunk_offset != 0; + + if (!identifiers_out_of_sync) { + identifiers_chunk_length = identifiers_length - identifiers_chunk_offset; + + if (identifiers_chunk_length > 60) { + identifiers_chunk_length = 60; + } + + memcpy(ret_identifiers, identifiers_chunk_data, sizeof(uint8_t) * identifiers_chunk_length); + *ret_identifiers_length = identifiers_chunk_length; + + while (*ret_identifiers_length < identifiers_length) { + ret = outdoor_weather_get_sensor_identifiers_low_level(outdoor_weather, &identifiers_length, &identifiers_chunk_offset, identifiers_chunk_data); + + if (ret < 0) { + goto unlock; + } + + identifiers_out_of_sync = identifiers_chunk_offset != *ret_identifiers_length; + + if (identifiers_out_of_sync) { + break; + } + + identifiers_chunk_length = identifiers_length - identifiers_chunk_offset; + + if (identifiers_chunk_length > 60) { + identifiers_chunk_length = 60; + } + + memcpy(&ret_identifiers[*ret_identifiers_length], identifiers_chunk_data, sizeof(uint8_t) * identifiers_chunk_length); + *ret_identifiers_length += identifiers_chunk_length; + } + } + + if (identifiers_out_of_sync) { + *ret_identifiers_length = 0; // return empty array + + // discard remaining stream to bring it back in-sync + while (identifiers_chunk_offset + 60 < identifiers_length) { + ret = outdoor_weather_get_sensor_identifiers_low_level(outdoor_weather, &identifiers_length, &identifiers_chunk_offset, identifiers_chunk_data); + + if (ret < 0) { + goto unlock; + } + } + + ret = E_STREAM_OUT_OF_SYNC; + } + +unlock: + mutex_unlock(&device_p->stream_mutex); + + return ret; +} + +#ifdef __cplusplus +} +#endif diff --git a/tinkerforge/bricklet_outdoor_weather.h b/tinkerforge/bricklet_outdoor_weather.h new file mode 100644 index 0000000..cedc892 --- /dev/null +++ b/tinkerforge/bricklet_outdoor_weather.h @@ -0,0 +1,682 @@ +/* *********************************************************** + * This file was automatically generated on 2021-01-15. * + * * + * C/C++ Bindings Version 2.1.31 * + * * + * If you have a bugfix for this file and want to commit it, * + * please fix the bug in the generator. You can find a link * + * to the generators git repository on tinkerforge.com * + *************************************************************/ + +#ifndef BRICKLET_OUTDOOR_WEATHER_H +#define BRICKLET_OUTDOOR_WEATHER_H + +#include "ip_connection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup BrickletOutdoorWeather Outdoor Weather Bricklet + */ + +/** + * \ingroup BrickletOutdoorWeather + * + * 433MHz receiver for outdoor weather station + */ +typedef Device OutdoorWeather; + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_STATION_IDENTIFIERS_LOW_LEVEL 1 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_SENSOR_IDENTIFIERS_LOW_LEVEL 2 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_STATION_DATA 3 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_SENSOR_DATA 4 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_SET_STATION_CALLBACK_CONFIGURATION 5 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_STATION_CALLBACK_CONFIGURATION 6 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_SET_SENSOR_CALLBACK_CONFIGURATION 7 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_SENSOR_CALLBACK_CONFIGURATION 8 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_SPITFP_ERROR_COUNT 234 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_SET_BOOTLOADER_MODE 235 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_BOOTLOADER_MODE 236 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_SET_WRITE_FIRMWARE_POINTER 237 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_WRITE_FIRMWARE 238 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_SET_STATUS_LED_CONFIG 239 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_STATUS_LED_CONFIG 240 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_CHIP_TEMPERATURE 242 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_RESET 243 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_WRITE_UID 248 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_READ_UID 249 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_FUNCTION_GET_IDENTITY 255 + +/** + * \ingroup BrickletOutdoorWeather + * + * Signature: \code void callback(uint8_t identifier, int16_t temperature, uint8_t humidity, uint32_t wind_speed, uint32_t gust_speed, uint32_t rain, uint8_t wind_direction, bool battery_low, void *user_data) \endcode + * + * Reports the station data every time a new data packet is received. + * See {@link outdoor_weather_get_station_data} for information about the data. + * + * For each station the callback will be triggered about every 45 seconds. + * + * Turn the callback on/off with {@link outdoor_weather_set_station_callback_configuration} + * (by default it is turned off). + */ +#define OUTDOOR_WEATHER_CALLBACK_STATION_DATA 9 + +/** + * \ingroup BrickletOutdoorWeather + * + * Signature: \code void callback(uint8_t identifier, int16_t temperature, uint8_t humidity, void *user_data) \endcode + * + * Reports the sensor data every time a new data packet is received. + * See {@link outdoor_weather_get_sensor_data} for information about the data. + * + * For each sensor the callback will be called about every 45 seconds. + * + * Turn the callback on/off with {@link outdoor_weather_set_sensor_callback_configuration} + * (by default it is turned off). + */ +#define OUTDOOR_WEATHER_CALLBACK_SENSOR_DATA 10 + + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_N 0 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_NNE 1 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_NE 2 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_ENE 3 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_E 4 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_ESE 5 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_SE 6 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_SSE 7 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_S 8 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_SSW 9 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_SW 10 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_WSW 11 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_W 12 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_WNW 13 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_NW 14 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_NNW 15 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_WIND_DIRECTION_ERROR 255 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_MODE_BOOTLOADER 0 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_MODE_FIRMWARE 1 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_MODE_BOOTLOADER_WAIT_FOR_REBOOT 2 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_MODE_FIRMWARE_WAIT_FOR_REBOOT 3 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_MODE_FIRMWARE_WAIT_FOR_ERASE_AND_REBOOT 4 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_STATUS_OK 0 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_STATUS_INVALID_MODE 1 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_STATUS_NO_CHANGE 2 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_STATUS_ENTRY_FUNCTION_NOT_PRESENT 3 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_STATUS_DEVICE_IDENTIFIER_INCORRECT 4 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_BOOTLOADER_STATUS_CRC_MISMATCH 5 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_STATUS_LED_CONFIG_OFF 0 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_STATUS_LED_CONFIG_ON 1 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_STATUS_LED_CONFIG_SHOW_HEARTBEAT 2 + +/** + * \ingroup BrickletOutdoorWeather + */ +#define OUTDOOR_WEATHER_STATUS_LED_CONFIG_SHOW_STATUS 3 + +/** + * \ingroup BrickletOutdoorWeather + * + * This constant is used to identify a Outdoor Weather Bricklet. + * + * The {@link outdoor_weather_get_identity} function and the + * {@link IPCON_CALLBACK_ENUMERATE} callback of the IP Connection have a + * \c device_identifier parameter to specify the Brick's or Bricklet's type. + */ +#define OUTDOOR_WEATHER_DEVICE_IDENTIFIER 288 + +/** + * \ingroup BrickletOutdoorWeather + * + * This constant represents the display name of a Outdoor Weather Bricklet. + */ +#define OUTDOOR_WEATHER_DEVICE_DISPLAY_NAME "Outdoor Weather Bricklet" + +/** + * \ingroup BrickletOutdoorWeather + * + * Creates the device object \c outdoor_weather with the unique device ID \c uid and adds + * it to the IPConnection \c ipcon. + */ +void outdoor_weather_create(OutdoorWeather *outdoor_weather, const char *uid, IPConnection *ipcon); + +/** + * \ingroup BrickletOutdoorWeather + * + * Removes the device object \c outdoor_weather from its IPConnection and destroys it. + * The device object cannot be used anymore afterwards. + */ +void outdoor_weather_destroy(OutdoorWeather *outdoor_weather); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the response expected flag for the function specified by the + * \c function_id parameter. It is *true* if the function is expected to + * send a response, *false* otherwise. + * + * For getter functions this is enabled by default and cannot be disabled, + * because those functions will always send a response. For callback + * configuration functions it is enabled by default too, but can be disabled + * via the outdoor_weather_set_response_expected function. For setter functions it is + * disabled by default and can be enabled. + * + * Enabling the response expected flag for a setter function allows to + * detect timeouts and other error conditions calls of this setter as well. + * The device will then send a response for this purpose. If this flag is + * disabled for a setter function then no response is sent and errors are + * silently ignored, because they cannot be detected. + */ +int outdoor_weather_get_response_expected(OutdoorWeather *outdoor_weather, uint8_t function_id, bool *ret_response_expected); + +/** + * \ingroup BrickletOutdoorWeather + * + * Changes the response expected flag of the function specified by the + * \c function_id parameter. This flag can only be changed for setter + * (default value: *false*) and callback configuration functions + * (default value: *true*). For getter functions it is always enabled. + * + * Enabling the response expected flag for a setter function allows to detect + * timeouts and other error conditions calls of this setter as well. The device + * will then send a response for this purpose. If this flag is disabled for a + * setter function then no response is sent and errors are silently ignored, + * because they cannot be detected. + */ +int outdoor_weather_set_response_expected(OutdoorWeather *outdoor_weather, uint8_t function_id, bool response_expected); + +/** + * \ingroup BrickletOutdoorWeather + * + * Changes the response expected flag for all setter and callback configuration + * functions of this device at once. + */ +int outdoor_weather_set_response_expected_all(OutdoorWeather *outdoor_weather, bool response_expected); + +/** + * \ingroup BrickletOutdoorWeather + * + * Registers the given \c function with the given \c callback_id. The + * \c user_data will be passed as the last parameter to the \c function. + */ +void outdoor_weather_register_callback(OutdoorWeather *outdoor_weather, int16_t callback_id, void (*function)(void), void *user_data); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the API version (major, minor, release) of the bindings for this + * device. + */ +int outdoor_weather_get_api_version(OutdoorWeather *outdoor_weather, uint8_t ret_api_version[3]); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the identifiers (number between 0 and 255) of all `stations + * `__ + * that have been seen since the startup of the Bricklet. + * + * Each station gives itself a random identifier on first startup. + * + * Since firmware version 2.0.2 a station is removed from the list if no data was received for + * 12 hours. + */ +int outdoor_weather_get_station_identifiers_low_level(OutdoorWeather *outdoor_weather, uint16_t *ret_identifiers_length, uint16_t *ret_identifiers_chunk_offset, uint8_t ret_identifiers_chunk_data[60]); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the identifiers (number between 0 and 255) of all `sensors + * `__ + * that have been seen since the startup of the Bricklet. + * + * Each sensor gives itself a random identifier on first startup. + * + * Since firmware version 2.0.2 a sensor is removed from the list if no data was received for + * 12 hours. + */ +int outdoor_weather_get_sensor_identifiers_low_level(OutdoorWeather *outdoor_weather, uint16_t *ret_identifiers_length, uint16_t *ret_identifiers_chunk_offset, uint8_t ret_identifiers_chunk_data[60]); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the last received data for a station with the given identifier. + * Call {@link outdoor_weather_get_station_identifiers} for a list of all available identifiers. + * + * The return values are: + * + * * Temperature, + * * Humidity, + * * Wind Speed, + * * Gust Speed, + * * Rain Fall (accumulated since station power-up), + * * Wind Direction, + * * Battery Low (true if battery is low) and + * * Last Change (seconds since the reception of this data). + */ +int outdoor_weather_get_station_data(OutdoorWeather *outdoor_weather, uint8_t identifier, int16_t *ret_temperature, uint8_t *ret_humidity, uint32_t *ret_wind_speed, uint32_t *ret_gust_speed, uint32_t *ret_rain, uint8_t *ret_wind_direction, bool *ret_battery_low, uint16_t *ret_last_change); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the last measured data for a sensor with the given identifier. + * Call {@link outdoor_weather_get_sensor_identifiers} for a list of all available identifiers. + * + * The return values are: + * + * * Temperature, + * * Humidity and + * * Last Change (seconds since the last reception of data). + */ +int outdoor_weather_get_sensor_data(OutdoorWeather *outdoor_weather, uint8_t identifier, int16_t *ret_temperature, uint8_t *ret_humidity, uint16_t *ret_last_change); + +/** + * \ingroup BrickletOutdoorWeather + * + * Turns callback for station data on or off. + */ +int outdoor_weather_set_station_callback_configuration(OutdoorWeather *outdoor_weather, bool enable_callback); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the configuration as set by {@link outdoor_weather_set_station_callback_configuration}. + */ +int outdoor_weather_get_station_callback_configuration(OutdoorWeather *outdoor_weather, bool *ret_enable_callback); + +/** + * \ingroup BrickletOutdoorWeather + * + * Turns callback for sensor data on or off. + */ +int outdoor_weather_set_sensor_callback_configuration(OutdoorWeather *outdoor_weather, bool enable_callback); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the configuration as set by {@link outdoor_weather_set_sensor_callback_configuration}. + */ +int outdoor_weather_get_sensor_callback_configuration(OutdoorWeather *outdoor_weather, bool *ret_enable_callback); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the error count for the communication between Brick and Bricklet. + * + * The errors are divided into + * + * * ACK checksum errors, + * * message checksum errors, + * * framing errors and + * * overflow errors. + * + * The errors counts are for errors that occur on the Bricklet side. All + * Bricks have a similar function that returns the errors on the Brick side. + */ +int outdoor_weather_get_spitfp_error_count(OutdoorWeather *outdoor_weather, uint32_t *ret_error_count_ack_checksum, uint32_t *ret_error_count_message_checksum, uint32_t *ret_error_count_frame, uint32_t *ret_error_count_overflow); + +/** + * \ingroup BrickletOutdoorWeather + * + * Sets the bootloader mode and returns the status after the requested + * mode change was instigated. + * + * You can change from bootloader mode to firmware mode and vice versa. A change + * from bootloader mode to firmware mode will only take place if the entry function, + * device identifier and CRC are present and correct. + * + * This function is used by Brick Viewer during flashing. It should not be + * necessary to call it in a normal user program. + */ +int outdoor_weather_set_bootloader_mode(OutdoorWeather *outdoor_weather, uint8_t mode, uint8_t *ret_status); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the current bootloader mode, see {@link outdoor_weather_set_bootloader_mode}. + */ +int outdoor_weather_get_bootloader_mode(OutdoorWeather *outdoor_weather, uint8_t *ret_mode); + +/** + * \ingroup BrickletOutdoorWeather + * + * Sets the firmware pointer for {@link outdoor_weather_write_firmware}. The pointer has + * to be increased by chunks of size 64. The data is written to flash + * every 4 chunks (which equals to one page of size 256). + * + * This function is used by Brick Viewer during flashing. It should not be + * necessary to call it in a normal user program. + */ +int outdoor_weather_set_write_firmware_pointer(OutdoorWeather *outdoor_weather, uint32_t pointer); + +/** + * \ingroup BrickletOutdoorWeather + * + * Writes 64 Bytes of firmware at the position as written by + * {@link outdoor_weather_set_write_firmware_pointer} before. The firmware is written + * to flash every 4 chunks. + * + * You can only write firmware in bootloader mode. + * + * This function is used by Brick Viewer during flashing. It should not be + * necessary to call it in a normal user program. + */ +int outdoor_weather_write_firmware(OutdoorWeather *outdoor_weather, uint8_t data[64], uint8_t *ret_status); + +/** + * \ingroup BrickletOutdoorWeather + * + * Sets the status LED configuration. By default the LED shows + * communication traffic between Brick and Bricklet, it flickers once + * for every 10 received data packets. + * + * You can also turn the LED permanently on/off or show a heartbeat. + * + * If the Bricklet is in bootloader mode, the LED is will show heartbeat by default. + */ +int outdoor_weather_set_status_led_config(OutdoorWeather *outdoor_weather, uint8_t config); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the configuration as set by {@link outdoor_weather_set_status_led_config} + */ +int outdoor_weather_get_status_led_config(OutdoorWeather *outdoor_weather, uint8_t *ret_config); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the temperature as measured inside the microcontroller. The + * value returned is not the ambient temperature! + * + * The temperature is only proportional to the real temperature and it has bad + * accuracy. Practically it is only useful as an indicator for + * temperature changes. + */ +int outdoor_weather_get_chip_temperature(OutdoorWeather *outdoor_weather, int16_t *ret_temperature); + +/** + * \ingroup BrickletOutdoorWeather + * + * Calling this function will reset the Bricklet. All configurations + * will be lost. + * + * After a reset you have to create new device objects, + * calling functions on the existing ones will result in + * undefined behavior! + */ +int outdoor_weather_reset(OutdoorWeather *outdoor_weather); + +/** + * \ingroup BrickletOutdoorWeather + * + * Writes a new UID into flash. If you want to set a new UID + * you have to decode the Base58 encoded UID string into an + * integer first. + * + * We recommend that you use Brick Viewer to change the UID. + */ +int outdoor_weather_write_uid(OutdoorWeather *outdoor_weather, uint32_t uid); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the current UID as an integer. Encode as + * Base58 to get the usual string version. + */ +int outdoor_weather_read_uid(OutdoorWeather *outdoor_weather, uint32_t *ret_uid); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the UID, the UID where the Bricklet is connected to, + * the position, the hardware and firmware version as well as the + * device identifier. + * + * The position can be 'a', 'b', 'c', 'd', 'e', 'f', 'g' or 'h' (Bricklet Port). + * A Bricklet connected to an :ref:`Isolator Bricklet ` is always at + * position 'z'. + * + * The device identifier numbers can be found :ref:`here `. + * |device_identifier_constant| + */ +int outdoor_weather_get_identity(OutdoorWeather *outdoor_weather, char ret_uid[8], char ret_connected_uid[8], char *ret_position, uint8_t ret_hardware_version[3], uint8_t ret_firmware_version[3], uint16_t *ret_device_identifier); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the identifiers (number between 0 and 255) of all `stations + * `__ + * that have been seen since the startup of the Bricklet. + * + * Each station gives itself a random identifier on first startup. + * + * Since firmware version 2.0.2 a station is removed from the list if no data was received for + * 12 hours. + */ +int outdoor_weather_get_station_identifiers(OutdoorWeather *outdoor_weather, uint8_t *ret_identifiers, uint16_t *ret_identifiers_length); + +/** + * \ingroup BrickletOutdoorWeather + * + * Returns the identifiers (number between 0 and 255) of all `sensors + * `__ + * that have been seen since the startup of the Bricklet. + * + * Each sensor gives itself a random identifier on first startup. + * + * Since firmware version 2.0.2 a sensor is removed from the list if no data was received for + * 12 hours. + */ +int outdoor_weather_get_sensor_identifiers(OutdoorWeather *outdoor_weather, uint8_t *ret_identifiers, uint16_t *ret_identifiers_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tinkerforge/ip_connection.c b/tinkerforge/ip_connection.c new file mode 100644 index 0000000..0667cd0 --- /dev/null +++ b/tinkerforge/ip_connection.c @@ -0,0 +1,2695 @@ +/* + * Copyright (C) 2012-2016, 2019-2020 Matthias Bolte + * Copyright (C) 2011 Olaf Lüke + * + * Redistribution and use in source and binary forms of this file, + * with or without modification, are permitted. See the Creative + * Commons Zero (CC0 1.0) License for more details. + */ + +#ifndef _WIN32 + #ifndef _BSD_SOURCE + #define _BSD_SOURCE // for usleep from unistd.h + #endif + #ifndef _GNU_SOURCE + #define _GNU_SOURCE + #endif + #ifndef _DEFAULT_SOURCE + #define _DEFAULT_SOURCE + #endif +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + #include + #include + #include + #include +#else + #include + #include + #include + #include // connect + #include + #include + #include // TCP_NO_DELAY + #include // gethostbyname + #include // struct sockaddr_in +#endif + +#ifdef _MSC_VER + // replace getpid with GetCurrentProcessId + #define getpid GetCurrentProcessId + + // avoid warning from MSVC about deprecated POSIX name + #define strdup _strdup +#else + #include // gettimeofday +#endif + +#define IPCON_EXPOSE_INTERNALS +#define IPCON_EXPOSE_MILLISLEEP + +#include "ip_connection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined _MSC_VER || defined __BORLANDC__ + #pragma pack(push) + #pragma pack(1) + #define ATTRIBUTE_PACKED +#elif defined __GNUC__ + #ifdef _WIN32 + // workaround struct packing bug in GCC 4.7 on Windows + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 + #define ATTRIBUTE_PACKED __attribute__((gcc_struct, packed)) + #else + #define ATTRIBUTE_PACKED __attribute__((packed)) + #endif +#else + #error unknown compiler, do not know how to enable struct packing +#endif + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED DeviceEnumerate_Broadcast; + +typedef struct { + PacketHeader header; + char uid[8]; + char connected_uid[8]; + char position; + uint8_t hardware_version[3]; + uint8_t firmware_version[3]; + uint16_t device_identifier; + uint8_t enumeration_type; +} ATTRIBUTE_PACKED DeviceEnumerate_Callback; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED DeviceGetIdentity_Request; + +typedef struct { + PacketHeader header; + char uid[8]; + char connected_uid[8]; + char position; + uint8_t hardware_version[3]; + uint8_t firmware_version[3]; + uint16_t device_identifier; +} ATTRIBUTE_PACKED DeviceGetIdentity_Response; + +typedef struct { + PacketHeader header; +} ATTRIBUTE_PACKED BrickDaemonGetAuthenticationNonce_Request; + +typedef struct { + PacketHeader header; + uint8_t server_nonce[4]; +} ATTRIBUTE_PACKED BrickDaemonGetAuthenticationNonce_Response; + +typedef struct { + PacketHeader header; + uint8_t client_nonce[4]; + uint8_t digest[20]; +} ATTRIBUTE_PACKED BrickDaemonAuthenticate_Request; + +#if defined _MSC_VER || defined __BORLANDC__ + #pragma pack(pop) +#endif +#undef ATTRIBUTE_PACKED + +#ifndef __cplusplus + #ifdef __GNUC__ + #ifndef __GNUC_PREREQ + #define __GNUC_PREREQ(major, minor) \ + ((((__GNUC__) << 16) + (__GNUC_MINOR__)) >= (((major) << 16) + (minor))) + #endif + #if __GNUC_PREREQ(4, 6) + #define STATIC_ASSERT(condition, message) \ + _Static_assert(condition, message); + #else + #define STATIC_ASSERT(condition, message) // FIXME + #endif + #else + #define STATIC_ASSERT(condition, message) // FIXME + #endif + + STATIC_ASSERT(sizeof(PacketHeader) == 8, "PacketHeader has invalid size") + STATIC_ASSERT(sizeof(Packet) == 80, "Packet has invalid size") + STATIC_ASSERT(sizeof(DeviceEnumerate_Broadcast) == 8, "DeviceEnumerate_Broadcast has invalid size") + STATIC_ASSERT(sizeof(DeviceEnumerate_Callback) == 34, "DeviceEnumerate_Callback has invalid size") + STATIC_ASSERT(sizeof(DeviceGetIdentity_Request) == 8, "DeviceGetIdentity_Request has invalid size") + STATIC_ASSERT(sizeof(DeviceGetIdentity_Response) == 33, "DeviceGetIdentity_Response has invalid size") + STATIC_ASSERT(sizeof(BrickDaemonGetAuthenticationNonce_Request) == 8, "BrickDaemonGetAuthenticationNonce_Request has invalid size") + STATIC_ASSERT(sizeof(BrickDaemonGetAuthenticationNonce_Response) == 12, "BrickDaemonGetAuthenticationNonce_Response has invalid size") + STATIC_ASSERT(sizeof(BrickDaemonAuthenticate_Request) == 32, "BrickDaemonAuthenticate_Request has invalid size") +#endif + +void millisleep(uint32_t msec) { +#ifdef _WIN32 + Sleep(msec); +#else + if (msec >= 1000) { + sleep(msec / 1000); + + msec %= 1000; + } + + usleep(msec * 1000); +#endif +} + +/***************************************************************************** + * + * SHA1 + * + *****************************************************************************/ + +/* + * Based on the SHA-1 C implementation by Steve Reid + * 100% Public Domain + * + * Test Vectors (from FIPS PUB 180-1) + * "abc" + * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + * A million repetitions of "a" + * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F + */ + +#define SHA1_BLOCK_LENGTH 64 +#define SHA1_DIGEST_LENGTH 20 + +typedef struct { + uint32_t state[5]; + uint64_t count; + uint8_t buffer[SHA1_BLOCK_LENGTH]; +} SHA1; + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +// blk0() and blk() perform the initial expand. blk0() deals with host endianess +#define blk0(i) (block[i] = htonl(block[i])) +#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15]^block[(i+2)&15]^block[i&15],1)) + +// (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30) +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30) +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30) +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30) +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30) + +// hash a single 512-bit block. this is the core of the algorithm +static uint32_t sha1_transform(SHA1 *sha1, const uint8_t buffer[SHA1_BLOCK_LENGTH]) { + uint32_t a, b, c, d, e; + uint32_t block[SHA1_BLOCK_LENGTH / 4]; + + memcpy(&block, buffer, SHA1_BLOCK_LENGTH); + + // copy sha1->state[] to working variables + a = sha1->state[0]; + b = sha1->state[1]; + c = sha1->state[2]; + d = sha1->state[3]; + e = sha1->state[4]; + + // 4 rounds of 20 operations each (loop unrolled) + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + // add the working variables back into sha1->state[] + sha1->state[0] += a; + sha1->state[1] += b; + sha1->state[2] += c; + sha1->state[3] += d; + sha1->state[4] += e; + + // wipe variables + a = b = c = d = e = 0; + + return a + b + c + d + e; // return to avoid dead-store warning from clang static analyzer +} + +static void sha1_init(SHA1 *sha1) { + sha1->state[0] = 0x67452301; + sha1->state[1] = 0xEFCDAB89; + sha1->state[2] = 0x98BADCFE; + sha1->state[3] = 0x10325476; + sha1->state[4] = 0xC3D2E1F0; + sha1->count = 0; +} + +static void sha1_update(SHA1 *sha1, const uint8_t *data, size_t length) { + size_t i, j; + + j = (size_t)((sha1->count >> 3) & 63); + sha1->count += (uint64_t)length << 3; + + if ((j + length) > 63) { + i = 64 - j; + + memcpy(&sha1->buffer[j], data, i); + sha1_transform(sha1, sha1->buffer); + + for (; i + 63 < length; i += 64) { + sha1_transform(sha1, &data[i]); + } + + j = 0; + } else { + i = 0; + } + + memcpy(&sha1->buffer[j], &data[i], length - i); +} + +static void sha1_final(SHA1 *sha1, uint8_t digest[SHA1_DIGEST_LENGTH]) { + uint32_t i; + uint8_t count[8]; + + for (i = 0; i < 8; i++) { + // this is endian independent + count[i] = (uint8_t)((sha1->count >> ((7 - (i & 7)) * 8)) & 255); + } + + sha1_update(sha1, (uint8_t *)"\200", 1); + + while ((sha1->count & 504) != 448) { + sha1_update(sha1, (uint8_t *)"\0", 1); + } + + sha1_update(sha1, count, 8); + + for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { + digest[i] = (uint8_t)((sha1->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + + memset(sha1, 0, sizeof(*sha1)); +} + +#undef rol +#undef blk0 +#undef blk +#undef R0 +#undef R1 +#undef R2 +#undef R3 +#undef R4 + +/***************************************************************************** + * + * Utils + * + *****************************************************************************/ + +static int string_length(const char *s, int max_length) { + const char *p = s; + int n = 0; + + while (*p != '\0' && n < max_length) { + ++p; + ++n; + } + + return n; +} + +#ifdef _MSC_VER + +// difference between Unix epoch and January 1, 1601 in 100-nanoseconds +#define DELTA_EPOCH 116444736000000000ULL + +typedef void (WINAPI *GETSYSTEMTIMEPRECISEASFILETIME)(LPFILETIME); + +// implement gettimeofday based on GetSystemTime(Precise)AsFileTime +static int gettimeofday(struct timeval *tv, struct timezone *tz) { + GETSYSTEMTIMEPRECISEASFILETIME ptr_GetSystemTimePreciseAsFileTime = NULL; + FILETIME ft; + uint64_t t; + + (void)tz; + + if (tv != NULL) { +#pragma warning(push) +#pragma warning(disable: 4191) // stop MSVC from warning about casting FARPROC + ptr_GetSystemTimePreciseAsFileTime = + (GETSYSTEMTIMEPRECISEASFILETIME)GetProcAddress(GetModuleHandleA("kernel32"), + "GetSystemTimePreciseAsFileTime"); +#pragma warning(pop) + + if (ptr_GetSystemTimePreciseAsFileTime != NULL) { + ptr_GetSystemTimePreciseAsFileTime(&ft); + } else { + GetSystemTimeAsFileTime(&ft); + } + + t = ((uint64_t)ft.dwHighDateTime << 32) | (uint64_t)ft.dwLowDateTime; + t = (t - DELTA_EPOCH) / 10; // 100-nanoseconds to microseconds + + tv->tv_sec = (long)(t / 1000000UL); + tv->tv_usec = (long)(t % 1000000UL); + } + + return 0; +} + +#endif + +#ifndef _WIN32 + +static int read_uint32_non_blocking(const char *filename, uint32_t *value) { + int fd = open(filename, O_NONBLOCK); + int rc; + + if (fd < 0) { + return -1; + } + + rc = (int)read(fd, value, sizeof(uint32_t)); + + close(fd); + + return rc != sizeof(uint32_t) ? -1 : 0; +} + +#endif + +// this function is not meant to be called often, +// this function is meant to provide a good random seed value +static uint32_t get_random_uint32(void) { + uint32_t r = 0; + struct timeval tv; + uint32_t seconds; + uint32_t microseconds; +#ifdef _WIN32 + HCRYPTPROV hprovider; + + if (!CryptAcquireContext(&hprovider, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + goto fallback; + } + + if (!CryptGenRandom(hprovider, sizeof(r), (BYTE *)&r)) { + CryptReleaseContext(hprovider, 0); + + goto fallback; + } + + CryptReleaseContext(hprovider, 0); +#else + // try /dev/urandom first, if not available or a read would + // block then fall back to /dev/random + if (read_uint32_non_blocking("/dev/urandom", &r) < 0) { + if (read_uint32_non_blocking("/dev/random", &r) < 0) { + goto fallback; + } + } +#endif + + return r; + +fallback: + // if no other random source is available fall back to the current time + if (gettimeofday(&tv, NULL) < 0) { + seconds = (uint32_t)time(NULL); + microseconds = 0; + } else { + seconds = (uint32_t)tv.tv_sec; + microseconds = tv.tv_usec; + } + + return (seconds << 26 | seconds >> 6) + microseconds + getpid(); // overflow is intended +} + +static void hmac_sha1(uint8_t *secret, int secret_length, + uint8_t *data, int data_length, + uint8_t digest[SHA1_DIGEST_LENGTH]) { + SHA1 sha1; + uint8_t secret_digest[SHA1_DIGEST_LENGTH]; + uint8_t inner_digest[SHA1_DIGEST_LENGTH]; + uint8_t ipad[SHA1_BLOCK_LENGTH]; + uint8_t opad[SHA1_BLOCK_LENGTH]; + int i; + + if (secret_length > SHA1_BLOCK_LENGTH) { + sha1_init(&sha1); + sha1_update(&sha1, secret, secret_length); + sha1_final(&sha1, secret_digest); + + secret = secret_digest; + secret_length = SHA1_DIGEST_LENGTH; + } + + // inner digest + for (i = 0; i < secret_length; ++i) { + ipad[i] = secret[i] ^ 0x36; + } + + for (i = secret_length; i < SHA1_BLOCK_LENGTH; ++i) { + ipad[i] = 0x36; + } + + sha1_init(&sha1); + sha1_update(&sha1, ipad, SHA1_BLOCK_LENGTH); + sha1_update(&sha1, data, data_length); + sha1_final(&sha1, inner_digest); + + // outer digest + for (i = 0; i < secret_length; ++i) { + opad[i] = secret[i] ^ 0x5C; + } + + for (i = secret_length; i < SHA1_BLOCK_LENGTH; ++i) { + opad[i] = 0x5C; + } + + sha1_init(&sha1); + sha1_update(&sha1, opad, SHA1_BLOCK_LENGTH); + sha1_update(&sha1, inner_digest, SHA1_DIGEST_LENGTH); + sha1_final(&sha1, digest); +} + +/***************************************************************************** + * + * BASE58 + * + *****************************************************************************/ + +static const char BASE58_ALPHABET[] = \ + "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; + +#if 0 + +#define BASE58_MAX_STR_SIZE 13 + +static void base58_encode(uint64_t value, char *str) { + uint32_t mod; + char reverse_str[BASE58_MAX_STR_SIZE] = {'\0'}; + int i = 0; + int k = 0; + + while (value >= 58) { + mod = value % 58; + reverse_str[i] = BASE58_ALPHABET[mod]; + value = value / 58; + ++i; + } + + reverse_str[i] = BASE58_ALPHABET[value]; + + for (k = 0; k <= i; k++) { + str[k] = reverse_str[i - k]; + } + + for (; k < BASE58_MAX_STR_SIZE; k++) { + str[k] = '\0'; + } +} + +#endif + +// https://www.fefe.de/intof.html +static bool uint64_add(uint64_t a, uint64_t b, uint64_t *c) { + if (UINT64_MAX - a < b) { + return false; + } + + *c = a + b; + + return true; +} + +static bool uint64_multiply(uint64_t a, uint64_t b, uint64_t *c) { + uint64_t a0 = a & UINT32_MAX; + uint64_t a1 = a >> 32; + uint64_t b0 = b & UINT32_MAX; + uint64_t b1 = b >> 32; + uint64_t c0; + uint64_t c1; + + if (a1 > 0 && b1 > 0) { + return false; + } + + c1 = a1 * b0 + a0 * b1; + + if (c1 > UINT32_MAX) { + return false; + } + + c0 = a0 * b0; + c1 <<= 32; + + return uint64_add(c1, c0, c); +} + +static bool base58_decode(const char *str, uint64_t *ret_value) { + int i = strlen(str) - 1; + int k; + uint64_t next; + uint64_t value = 0; + uint64_t base = 1; + + *ret_value = 0; + + for (; i >= 0; --i) { + for (k = 0; k < 58; ++k) { + if (BASE58_ALPHABET[k] == str[i]) { + break; + } + } + + if (k == 58) { + return false; // invalid char + } + + if (!uint64_multiply(k, base, &next)) { + return false; // overflow + } + + if (!uint64_add(value, next, &value)) { + return false; // overflow + } + + if (i > 0 && !uint64_multiply(base, 58, &base)) { + return false; // overflow + } + } + + *ret_value = value; + + return true; +} + +/***************************************************************************** + * + * Socket + * + *****************************************************************************/ + +struct _Socket { +#ifdef _WIN32 + SOCKET handle; +#else + int handle; +#endif + Mutex send_mutex; // used to serialize socket_send calls +}; + +#ifdef _WIN32 + +static int socket_create(Socket *socket_, int domain, int type, int protocol) { + BOOL flag = 1; + + socket_->handle = socket(domain, type, protocol); + + if (socket_->handle == INVALID_SOCKET) { + return -1; + } + + if (setsockopt(socket_->handle, IPPROTO_TCP, TCP_NODELAY, + (const char *)&flag, sizeof(flag)) == SOCKET_ERROR) { + closesocket(socket_->handle); + + return -1; + } + + mutex_create(&socket_->send_mutex); + + return 0; +} + +static void socket_destroy(Socket *socket) { + mutex_destroy(&socket->send_mutex); + + closesocket(socket->handle); +} + +static int socket_connect(Socket *socket, struct sockaddr *address, int length) { + return connect(socket->handle, address, length) == SOCKET_ERROR ? -1 : 0; +} + +static void socket_shutdown(Socket *socket) { + shutdown(socket->handle, SD_BOTH); +} + +static int socket_receive(Socket *socket, void *buffer, int length) { + length = recv(socket->handle, (char *)buffer, length, 0); + + if (length == SOCKET_ERROR) { + length = -1; + + if (WSAGetLastError() == WSAEINTR) { + errno = EINTR; + } else { + errno = EFAULT; + } + } + + return length; +} + +static int socket_send(Socket *socket, const void *buffer, int length) { + mutex_lock(&socket->send_mutex); + + length = send(socket->handle, (const char *)buffer, length, 0); + + mutex_unlock(&socket->send_mutex); + + if (length == SOCKET_ERROR) { + length = -1; + } + + return length; +} + +#else + +static int socket_create(Socket *socket_, int domain, int type, int protocol) { + int flag = 1; + + socket_->handle = socket(domain, type, protocol); + + if (socket_->handle < 0) { + return -1; + } + + if (setsockopt(socket_->handle, IPPROTO_TCP, TCP_NODELAY, (void *)&flag, + sizeof(flag)) < 0) { + close(socket_->handle); + + return -1; + } + + mutex_create(&socket_->send_mutex); + + return 0; +} + +static void socket_destroy(Socket *socket) { + mutex_destroy(&socket->send_mutex); + + close(socket->handle); +} + +static int socket_connect(Socket *socket, struct sockaddr *address, int length) { + return connect(socket->handle, address, length); +} + +static void socket_shutdown(Socket *socket) { + shutdown(socket->handle, SHUT_RDWR); +} + +static int socket_receive(Socket *socket, void *buffer, int length) { + return (int)recv(socket->handle, buffer, length, 0); +} + +static int socket_send(Socket *socket, const void *buffer, int length) { + int rc; + + mutex_lock(&socket->send_mutex); + + rc = (int)send(socket->handle, buffer, length, 0); + + mutex_unlock(&socket->send_mutex); + + return rc; +} + +#endif + +/***************************************************************************** + * + * Mutex + * + *****************************************************************************/ + +#ifdef _WIN32 + +void mutex_create(Mutex *mutex) { + InitializeCriticalSection(&mutex->handle); +} + +void mutex_destroy(Mutex *mutex) { + DeleteCriticalSection(&mutex->handle); +} + +void mutex_lock(Mutex *mutex) { + EnterCriticalSection(&mutex->handle); +} + +void mutex_unlock(Mutex *mutex) { + LeaveCriticalSection(&mutex->handle); +} + +#else + +void mutex_create(Mutex *mutex) { + pthread_mutex_init(&mutex->handle, NULL); +} + +void mutex_destroy(Mutex *mutex) { + pthread_mutex_destroy(&mutex->handle); +} + +void mutex_lock(Mutex *mutex) { + pthread_mutex_lock(&mutex->handle); +} + +void mutex_unlock(Mutex *mutex) { + pthread_mutex_unlock(&mutex->handle); +} +#endif + +/***************************************************************************** + * + * Event + * + *****************************************************************************/ + +#ifdef _WIN32 + +static void event_create(Event *event) { + event->handle = CreateEvent(NULL, TRUE, FALSE, NULL); +} + +static void event_destroy(Event *event) { + CloseHandle(event->handle); +} + +static void event_set(Event *event) { + SetEvent(event->handle); +} + +static void event_reset(Event *event) { + ResetEvent(event->handle); +} + +static int event_wait(Event *event, uint32_t timeout) { // in msec + return WaitForSingleObject(event->handle, timeout) == WAIT_OBJECT_0 ? 0 : -1; +} + +#else + +static void event_create(Event *event) { + pthread_mutex_init(&event->mutex, NULL); + pthread_cond_init(&event->condition, NULL); + + event->flag = false; +} + +static void event_destroy(Event *event) { + pthread_mutex_destroy(&event->mutex); + pthread_cond_destroy(&event->condition); +} + +static void event_set(Event *event) { + pthread_mutex_lock(&event->mutex); + + event->flag = true; + + pthread_cond_broadcast(&event->condition); + pthread_mutex_unlock(&event->mutex); +} + +static void event_reset(Event *event) { + pthread_mutex_lock(&event->mutex); + + event->flag = false; + + pthread_mutex_unlock(&event->mutex); +} + +static int event_wait(Event *event, uint32_t timeout) { // in msec + struct timeval tp; + struct timespec ts; + int ret = E_OK; + + gettimeofday(&tp, NULL); + + ts.tv_sec = tp.tv_sec + timeout / 1000; + ts.tv_nsec = (tp.tv_usec + (timeout % 1000) * 1000) * 1000; + + while (ts.tv_nsec >= 1000000000L) { + ts.tv_sec += 1; + ts.tv_nsec -= 1000000000L; + } + + pthread_mutex_lock(&event->mutex); + + while (!event->flag) { + ret = pthread_cond_timedwait(&event->condition, &event->mutex, &ts); + + if (ret != 0) { + ret = E_TIMEOUT; + break; + } + } + + pthread_mutex_unlock(&event->mutex); + + return ret; +} + +#endif + +/***************************************************************************** + * + * Semaphore + * + *****************************************************************************/ + +#ifdef _WIN32 + +static void semaphore_create(Semaphore *semaphore) { + semaphore->handle = CreateSemaphore(NULL, 0, INT32_MAX, NULL); +} + +static void semaphore_destroy(Semaphore *semaphore) { + CloseHandle(semaphore->handle); +} + +static int semaphore_acquire(Semaphore *semaphore) { + return WaitForSingleObject(semaphore->handle, INFINITE) != WAIT_OBJECT_0 ? -1 : 0; +} + +static void semaphore_release(Semaphore *semaphore) { + ReleaseSemaphore(semaphore->handle, 1, NULL); +} + +#else + +static void semaphore_create(Semaphore *semaphore) { +#ifdef __APPLE__ + // Mac OS X does not support unnamed semaphores, so we fake them. Unlink + // first to ensure that there is no existing semaphore with that name. + // Then open the semaphore to create a new one. Finally unlink it again to + // avoid leaking the name. The semaphore will work fine without a name. + char name[100]; + + snprintf(name, sizeof(name), "tf-ipcon-%p", semaphore); + + sem_unlink(name); + semaphore->pointer = sem_open(name, O_CREAT | O_EXCL, S_IRWXU, 0); + sem_unlink(name); +#else + semaphore->pointer = &semaphore->object; + + sem_init(semaphore->pointer, 0, 0); +#endif +} + +static void semaphore_destroy(Semaphore *semaphore) { +#ifdef __APPLE__ + sem_close(semaphore->pointer); +#else + sem_destroy(semaphore->pointer); +#endif +} + +static int semaphore_acquire(Semaphore *semaphore) { + return sem_wait(semaphore->pointer) < 0 ? -1 : 0; +} + +static void semaphore_release(Semaphore *semaphore) { + sem_post(semaphore->pointer); +} + +#endif + +/***************************************************************************** + * + * Thread + * + *****************************************************************************/ + +#ifdef _WIN32 + +static DWORD WINAPI thread_wrapper(void *opaque) { + Thread *thread = (Thread *)opaque; + + thread->function(thread->opaque); + + return 0; +} + +static int thread_create(Thread *thread, ThreadFunction function, void *opaque) { + thread->function = function; + thread->opaque = opaque; + + thread->handle = CreateThread(NULL, 0, thread_wrapper, thread, 0, &thread->id); + + return thread->handle == NULL ? -1 : 0; +} + +static void thread_destroy(Thread *thread) { + CloseHandle(thread->handle); +} + +static bool thread_is_current(Thread *thread) { + return thread->id == GetCurrentThreadId(); +} + +static void thread_join(Thread *thread) { + WaitForSingleObject(thread->handle, INFINITE); +} + +#else + +static void *thread_wrapper(void *opaque) { + Thread *thread = (Thread *)opaque; + + thread->function(thread->opaque); + + return NULL; +} + +static int thread_create(Thread *thread, ThreadFunction function, void *opaque) { + thread->function = function; + thread->opaque = opaque; + + return pthread_create(&thread->handle, NULL, thread_wrapper, thread); +} + +static void thread_destroy(Thread *thread) { + (void)thread; +} + +static bool thread_is_current(Thread *thread) { + return pthread_equal(thread->handle, pthread_self()) ? true : false; +} + +static void thread_join(Thread *thread) { + pthread_join(thread->handle, NULL); +} + +#endif + +/***************************************************************************** + * + * Table + * + *****************************************************************************/ + +static void table_create(Table *table) { + mutex_create(&table->mutex); + + table->used = 0; + table->allocated = 16; + table->keys = (uint32_t *)malloc(sizeof(uint32_t) * table->allocated); + table->values = (void **)malloc(sizeof(void *) * table->allocated); +} + +static void table_destroy(Table *table) { + free(table->keys); + free(table->values); + + mutex_destroy(&table->mutex); +} + +static void *table_insert(Table *table, uint32_t key, void *value) { + int i; + void *replaced_value; + + mutex_lock(&table->mutex); + + for (i = 0; i < table->used; ++i) { + if (table->keys[i] == key) { + replaced_value = table->values[i]; + table->values[i] = value; + + mutex_unlock(&table->mutex); + + return replaced_value; + } + } + + if (table->allocated <= table->used) { + table->allocated += 16; + table->keys = (uint32_t *)realloc(table->keys, sizeof(uint32_t) * table->allocated); + table->values = (void **)realloc(table->values, sizeof(void *) * table->allocated); + } + + table->keys[table->used] = key; + table->values[table->used] = value; + + ++table->used; + + mutex_unlock(&table->mutex); + + return NULL; +} + +static void table_remove(Table *table, uint32_t key) { + int i; + int tail; + + mutex_lock(&table->mutex); + + for (i = 0; i < table->used; ++i) { + if (table->keys[i] == key) { + tail = table->used - i - 1; + + if (tail > 0) { + memmove(table->keys + i, table->keys + i + 1, sizeof(uint32_t) * tail); + memmove(table->values + i, table->values + i + 1, sizeof(void *) * tail); + } + + --table->used; + + break; + } + } + + mutex_unlock(&table->mutex); +} + +static void *table_get(Table *table, uint32_t key) { + int i; + void *value = NULL; + + mutex_lock(&table->mutex); + + for (i = 0; i < table->used; ++i) { + if (table->keys[i] == key) { + value = table->values[i]; + + break; + } + } + + mutex_unlock(&table->mutex); + + return value; +} + +/***************************************************************************** + * + * Queue + * + *****************************************************************************/ + +enum { + QUEUE_KIND_EXIT = 0, + QUEUE_KIND_DESTROY_AND_EXIT, + QUEUE_KIND_META, + QUEUE_KIND_PACKET +}; + +typedef struct { + uint8_t function_id; + uint8_t parameter; + uint64_t socket_id; +} Meta; + +static void queue_create(Queue *queue) { + queue->head = NULL; + queue->tail = NULL; + + mutex_create(&queue->mutex); + semaphore_create(&queue->semaphore); +} + +static void queue_destroy(Queue *queue) { + QueueItem *item = queue->head; + QueueItem *next; + + while (item != NULL) { + next = item->next; + + free(item->data); + free(item); + + item = next; + } + + mutex_destroy(&queue->mutex); + semaphore_destroy(&queue->semaphore); +} + +static void queue_put(Queue *queue, int kind, void *data) { + QueueItem *item = (QueueItem *)malloc(sizeof(QueueItem)); + + item->next = NULL; + item->kind = kind; + item->data = data; + + mutex_lock(&queue->mutex); + + if (queue->tail == NULL) { + queue->head = item; + queue->tail = item; + } else { + queue->tail->next = item; + queue->tail = item; + } + + mutex_unlock(&queue->mutex); + semaphore_release(&queue->semaphore); +} + +static int queue_get(Queue *queue, int *kind, void **data) { + QueueItem *item; + + if (semaphore_acquire(&queue->semaphore) < 0) { + return -1; + } + + mutex_lock(&queue->mutex); + + if (queue->head == NULL) { + mutex_unlock(&queue->mutex); + + return -1; + } + + item = queue->head; + queue->head = item->next; + item->next = NULL; + + if (queue->tail == item) { + queue->head = NULL; + queue->tail = NULL; + } + + mutex_unlock(&queue->mutex); + + *kind = item->kind; + *data = item->data; + + free(item); + + return 0; +} + +/***************************************************************************** + * + * Device + * + *****************************************************************************/ + +enum { + DEVICE_FUNCTION_ENUMERATE = 254, + DEVICE_FUNCTION_GET_IDENTITY = 255 +}; + +static int ipcon_send_request(IPConnectionPrivate *ipcon_p, Packet *request); + +// NOTE: assumes device_p->ref_count == 0 +static void device_destroy(DevicePrivate *device_p) { + int i; + + if (!device_p->replaced && device_p->uid_valid) { + table_remove(&device_p->ipcon_p->devices, device_p->uid); + } + + for (i = 0; i < DEVICE_NUM_FUNCTION_IDS; i++) { + free(device_p->high_level_callbacks[i].data); + } + + mutex_destroy(&device_p->stream_mutex); + + event_destroy(&device_p->response_event); + + mutex_destroy(&device_p->response_mutex); + + mutex_destroy(&device_p->request_mutex); + + mutex_destroy(&device_p->device_identifier_mutex); + + free(device_p); +} + +void device_create(Device *device, const char *uid_str, + IPConnectionPrivate *ipcon_p, uint8_t api_version_major, + uint8_t api_version_minor, uint8_t api_version_release, + uint16_t device_identifier) { + DevicePrivate *device_p; + uint64_t uid; + uint32_t value1; + uint32_t value2; + int i; + + device_p = (DevicePrivate *)malloc(sizeof(DevicePrivate)); + device->p = device_p; + + device_p->replaced = false; + + device_p->uid_valid = base58_decode(uid_str, &uid); + + if (device_p->uid_valid && uid > 0xFFFFFFFF) { + // convert from 64bit to 32bit + value1 = uid & 0xFFFFFFFF; + value2 = (uid >> 32) & 0xFFFFFFFF; + + uid = (value1 & 0x00000FFF); + uid |= (value1 & 0x0F000000) >> 12; + uid |= (value2 & 0x0000003F) << 16; + uid |= (value2 & 0x000F0000) << 6; + uid |= (value2 & 0x3F000000) << 2; + } + + if (uid == 0) { + device_p->uid_valid = false; // broadcast UID is forbidden + } + + device_p->ref_count = 1; + + device_p->uid = (uint32_t)uid; + + device_p->ipcon_p = ipcon_p; + + device_p->api_version[0] = api_version_major; + device_p->api_version[1] = api_version_minor; + device_p->api_version[2] = api_version_release; + + // device identifier + device_p->device_identifier = device_identifier; + + mutex_create(&device_p->device_identifier_mutex); + + device_p->device_identifier_check = DEVICE_IDENTIFIER_CHECK_PENDING; + + // request + mutex_create(&device_p->request_mutex); + + // response + device_p->expected_response_function_id = 0; + device_p->expected_response_sequence_number = 0; + + mutex_create(&device_p->response_mutex); + + memset(&device_p->response_packet, 0, sizeof(Packet)); + + event_create(&device_p->response_event); + + for (i = 0; i < DEVICE_NUM_FUNCTION_IDS; i++) { + device_p->response_expected[i] = DEVICE_RESPONSE_EXPECTED_INVALID_FUNCTION_ID; + } + + // stream + mutex_create(&device_p->stream_mutex); + + // callbacks + for (i = 0; i < DEVICE_NUM_FUNCTION_IDS * 2; i++) { + device_p->registered_callbacks[i] = NULL; + device_p->registered_callback_user_data[i] = NULL; + } + + for (i = 0; i < DEVICE_NUM_FUNCTION_IDS; i++) { + device_p->callback_wrappers[i] = NULL; + device_p->high_level_callbacks[i].exists = false; + device_p->high_level_callbacks[i].data = NULL; + device_p->high_level_callbacks[i].length = 0; + } +} + +void device_release(DevicePrivate *device_p) { + IPConnectionPrivate *ipcon_p = device_p->ipcon_p; + + mutex_lock(&ipcon_p->devices_ref_mutex); + + --device_p->ref_count; + + if (device_p->ref_count == 0) { + device_destroy(device_p); + } + + mutex_unlock(&ipcon_p->devices_ref_mutex); +} + +int device_get_response_expected(DevicePrivate *device_p, uint8_t function_id, + bool *ret_response_expected) { + int flag = device_p->response_expected[function_id]; + + if (flag == DEVICE_RESPONSE_EXPECTED_INVALID_FUNCTION_ID) { + return E_INVALID_PARAMETER; + } + + if (flag == DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE || + flag == DEVICE_RESPONSE_EXPECTED_TRUE) { + *ret_response_expected = true; + } else { + *ret_response_expected = false; + } + + return E_OK; +} + +int device_set_response_expected(DevicePrivate *device_p, uint8_t function_id, + bool response_expected) { + int current_flag = device_p->response_expected[function_id]; + + if (current_flag != DEVICE_RESPONSE_EXPECTED_TRUE && + current_flag != DEVICE_RESPONSE_EXPECTED_FALSE) { + return E_INVALID_PARAMETER; + } + + device_p->response_expected[function_id] = + response_expected ? DEVICE_RESPONSE_EXPECTED_TRUE + : DEVICE_RESPONSE_EXPECTED_FALSE; + + return E_OK; +} + +int device_set_response_expected_all(DevicePrivate *device_p, bool response_expected) { + int flag = response_expected ? DEVICE_RESPONSE_EXPECTED_TRUE + : DEVICE_RESPONSE_EXPECTED_FALSE; + int i; + + for (i = 0; i < DEVICE_NUM_FUNCTION_IDS; ++i) { + if (device_p->response_expected[i] == DEVICE_RESPONSE_EXPECTED_TRUE || + device_p->response_expected[i] == DEVICE_RESPONSE_EXPECTED_FALSE) { + device_p->response_expected[i] = flag; + } + } + + return E_OK; +} + +void device_register_callback(DevicePrivate *device_p, int16_t callback_id, + void (*function)(void), void *user_data) { + if (callback_id <= -DEVICE_NUM_FUNCTION_IDS || callback_id >= DEVICE_NUM_FUNCTION_IDS) { + return; + } + + device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + callback_id] = function; + device_p->registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS + callback_id] = user_data; +} + +int device_get_api_version(DevicePrivate *device_p, uint8_t ret_api_version[3]) { + ret_api_version[0] = device_p->api_version[0]; + ret_api_version[1] = device_p->api_version[1]; + ret_api_version[2] = device_p->api_version[2]; + + return E_OK; +} + +// NOTE: assumes that device_check_validity was successful +int device_send_request(DevicePrivate *device_p, Packet *request, Packet *response, + int expected_response_length) { + int ret = E_OK; + uint8_t sequence_number = packet_header_get_sequence_number(&request->header); + uint8_t response_expected = packet_header_get_response_expected(&request->header); + uint8_t error_code; + + if (response_expected) { + mutex_lock(&device_p->request_mutex); + + event_reset(&device_p->response_event); + + device_p->expected_response_function_id = request->header.function_id; + device_p->expected_response_sequence_number = sequence_number; + } + + ret = ipcon_send_request(device_p->ipcon_p, request); + + if (ret != E_OK) { + if (response_expected) { + mutex_unlock(&device_p->request_mutex); + } + + return ret; + } + + if (response_expected) { + if (event_wait(&device_p->response_event, device_p->ipcon_p->timeout) < 0) { + ret = E_TIMEOUT; + } + + device_p->expected_response_function_id = 0; + device_p->expected_response_sequence_number = 0; + + event_reset(&device_p->response_event); + + if (ret == E_OK) { + mutex_lock(&device_p->response_mutex); + + error_code = packet_header_get_error_code(&device_p->response_packet.header); + + if (device_p->response_packet.header.function_id != request->header.function_id || + packet_header_get_sequence_number(&device_p->response_packet.header) != sequence_number) { + ret = E_TIMEOUT; + } else if (error_code == 0) { + if (expected_response_length == 0) { + // setter with response-expected enabled + expected_response_length = sizeof(PacketHeader); + } + + if (device_p->response_packet.header.length != expected_response_length) { + ret = E_WRONG_RESPONSE_LENGTH; + } else if (response != NULL) { + memcpy(response, &device_p->response_packet, + device_p->response_packet.header.length); + } + } else if (error_code == 1) { + ret = E_INVALID_PARAMETER; + } else if (error_code == 2) { + ret = E_NOT_SUPPORTED; + } else { + ret = E_UNKNOWN_ERROR_CODE; + } + + mutex_unlock(&device_p->response_mutex); + } + + mutex_unlock(&device_p->request_mutex); + } + + return ret; +} + +int device_check_validity(DevicePrivate *device_p) { + DeviceGetIdentity_Request request; + DeviceGetIdentity_Response response; + uint16_t device_identifier; + int ret; + + if (device_p->replaced) { + return E_DEVICE_REPLACED; + } + + if (!device_p->uid_valid) { + return E_INVALID_UID; + } + + if (device_p->device_identifier_check == DEVICE_IDENTIFIER_CHECK_PENDING) { + mutex_lock(&device_p->device_identifier_mutex); + + if (device_p->device_identifier_check == DEVICE_IDENTIFIER_CHECK_PENDING) { + ret = packet_header_create(&request.header, sizeof(request), DEVICE_FUNCTION_GET_IDENTITY, device_p->ipcon_p, device_p); + + if (ret < 0) { + mutex_unlock(&device_p->device_identifier_mutex); + + return ret; + } + + // initialize to 0 to stop the clang static analyzer from warning about accessing + // uninitialized memory when accessing the device_identifier member later on + memset(&response, 0, sizeof(response)); + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + mutex_unlock(&device_p->device_identifier_mutex); + + return ret; + } + + device_identifier = leconvert_uint16_from(response.device_identifier); + + if (device_identifier == device_p->device_identifier) { + device_p->device_identifier_check = DEVICE_IDENTIFIER_CHECK_MATCH; + } else { + device_p->device_identifier_check = DEVICE_IDENTIFIER_CHECK_MISMATCH; + } + } + + mutex_unlock(&device_p->device_identifier_mutex); + } + + if (device_p->device_identifier_check == DEVICE_IDENTIFIER_CHECK_MISMATCH) { + return E_WRONG_DEVICE_TYPE; + } + + return E_OK; // DEVICE_IDENTIFIER_CHECK_MATCH +} + +/***************************************************************************** + * + * Brick Daemon + * + *****************************************************************************/ + +enum { + BRICK_DAEMON_FUNCTION_GET_AUTHENTICATION_NONCE = 1, + BRICK_DAEMON_FUNCTION_AUTHENTICATE = 2 +}; + +static void brickd_create(BrickDaemon *brickd, const char *uid, IPConnection *ipcon) { + IPConnectionPrivate *ipcon_p = ipcon->p; + DevicePrivate *device_p; + + device_create(brickd, uid, ipcon_p, 2, 0, 0, 0); + + device_p = brickd->p; + + device_p->response_expected[BRICK_DAEMON_FUNCTION_GET_AUTHENTICATION_NONCE] = DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE; + device_p->response_expected[BRICK_DAEMON_FUNCTION_AUTHENTICATE] = DEVICE_RESPONSE_EXPECTED_TRUE; + + ipcon_add_device(ipcon_p, device_p); +} + +static void brickd_destroy(BrickDaemon *brickd) { + device_release(brickd->p); +} + +static int brickd_get_authentication_nonce(BrickDaemon *brickd, uint8_t ret_server_nonce[4]) { + DevicePrivate *device_p = brickd->p; + BrickDaemonGetAuthenticationNonce_Request request; + BrickDaemonGetAuthenticationNonce_Response response; + int ret; + + ret = packet_header_create(&request.header, sizeof(request), BRICK_DAEMON_FUNCTION_GET_AUTHENTICATION_NONCE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + ret = device_send_request(device_p, (Packet *)&request, (Packet *)&response, sizeof(response)); + + if (ret < 0) { + return ret; + } + + memcpy(ret_server_nonce, response.server_nonce, 4 * sizeof(uint8_t)); + + return ret; +} + +static int brickd_authenticate(BrickDaemon *brickd, uint8_t client_nonce[4], uint8_t digest[20]) { + DevicePrivate *device_p = brickd->p; + BrickDaemonAuthenticate_Request request; + int ret; + + ret = packet_header_create(&request.header, sizeof(request), BRICK_DAEMON_FUNCTION_AUTHENTICATE, device_p->ipcon_p, device_p); + + if (ret < 0) { + return ret; + } + + memcpy(request.client_nonce, client_nonce, 4 * sizeof(uint8_t)); + memcpy(request.digest, digest, 20 * sizeof(uint8_t)); + + ret = device_send_request(device_p, (Packet *)&request, NULL, 0); + + return ret; +} + +/***************************************************************************** + * + * IPConnection + * + *****************************************************************************/ + +struct _CallbackContext { + IPConnectionPrivate *ipcon_p; + Queue queue; + Mutex mutex; + Thread thread; + bool packet_dispatch_allowed; +}; + +static int ipcon_connect_unlocked(IPConnectionPrivate *ipcon_p, bool is_auto_reconnect); +static void ipcon_disconnect_unlocked(IPConnectionPrivate *ipcon_p); + +static DevicePrivate *ipcon_acquire_device(IPConnectionPrivate *ipcon_p, uint32_t uid) { + DevicePrivate *device_p; + + if (uid == 0) { + return NULL; + } + + mutex_lock(&ipcon_p->devices_ref_mutex); + + device_p = (DevicePrivate *)table_get(&ipcon_p->devices, uid); + + if (device_p != NULL) { + ++device_p->ref_count; + } + + mutex_unlock(&ipcon_p->devices_ref_mutex); + + return device_p; +} + +static void ipcon_dispatch_meta(IPConnectionPrivate *ipcon_p, Meta *meta) { + ConnectedCallbackFunction connected_callback_function; + DisconnectedCallbackFunction disconnected_callback_function; + void *user_data; + bool retry; + + if (meta->function_id == IPCON_CALLBACK_CONNECTED) { + if (ipcon_p->registered_callbacks[IPCON_CALLBACK_CONNECTED] != NULL) { + connected_callback_function = (ConnectedCallbackFunction)ipcon_p->registered_callbacks[IPCON_CALLBACK_CONNECTED]; + user_data = ipcon_p->registered_callback_user_data[IPCON_CALLBACK_CONNECTED]; + + connected_callback_function(meta->parameter, user_data); + } + } else if (meta->function_id == IPCON_CALLBACK_DISCONNECTED) { + // need to do this here, the receive loop is not allowed to + // hold the socket mutex because this could cause a deadlock + // with a concurrent call to the (dis-)connect function + if (meta->parameter != IPCON_DISCONNECT_REASON_REQUEST) { + mutex_lock(&ipcon_p->socket_mutex); + + // don't close the socket if it got disconnected or + // reconnected in the meantime + if (ipcon_p->socket != NULL && ipcon_p->socket_id == meta->socket_id) { + // destroy disconnect probe thread + event_set(&ipcon_p->disconnect_probe_event); + thread_join(&ipcon_p->disconnect_probe_thread); + thread_destroy(&ipcon_p->disconnect_probe_thread); + + // destroy socket + socket_destroy(ipcon_p->socket); + free(ipcon_p->socket); + ipcon_p->socket = NULL; + } + + mutex_unlock(&ipcon_p->socket_mutex); + } + + // FIXME: wait a moment here, otherwise the next connect + // attempt will succeed, even if there is no open server + // socket. the first receive will then fail directly + millisleep(100); + + if (ipcon_p->registered_callbacks[IPCON_CALLBACK_DISCONNECTED] != NULL) { + disconnected_callback_function = (DisconnectedCallbackFunction)ipcon_p->registered_callbacks[IPCON_CALLBACK_DISCONNECTED]; + user_data = ipcon_p->registered_callback_user_data[IPCON_CALLBACK_DISCONNECTED]; + + disconnected_callback_function(meta->parameter, user_data); + } + + if (meta->parameter != IPCON_DISCONNECT_REASON_REQUEST && + ipcon_p->auto_reconnect && ipcon_p->auto_reconnect_allowed) { + ipcon_p->auto_reconnect_pending = true; + retry = true; + + // block here until reconnect. this is okay, there is no + // callback to deliver when there is no connection + while (retry) { + retry = false; + + mutex_lock(&ipcon_p->socket_mutex); + + if (ipcon_p->auto_reconnect_allowed && ipcon_p->socket == NULL) { + if (ipcon_connect_unlocked(ipcon_p, true) < 0) { + retry = true; + } + } else { + ipcon_p->auto_reconnect_pending = false; + } + + mutex_unlock(&ipcon_p->socket_mutex); + + if (retry) { + // wait a moment to give another thread a chance to + // interrupt the auto-reconnect + millisleep(100); + } + } + } + } +} + +static void ipcon_dispatch_packet(IPConnectionPrivate *ipcon_p, Packet *packet) { + EnumerateCallbackFunction enumerate_callback_function; + void *user_data; + DeviceEnumerate_Callback *enumerate_callback; + DevicePrivate *device_p; + CallbackWrapperFunction callback_wrapper_function; + + if (packet->header.function_id == IPCON_CALLBACK_ENUMERATE) { + if (ipcon_p->registered_callbacks[IPCON_CALLBACK_ENUMERATE] != NULL) { + if (packet->header.length != sizeof(DeviceEnumerate_Callback)) { + return; // silently ignoring callback with wrong length + } + + enumerate_callback_function = (EnumerateCallbackFunction)ipcon_p->registered_callbacks[IPCON_CALLBACK_ENUMERATE]; + user_data = ipcon_p->registered_callback_user_data[IPCON_CALLBACK_ENUMERATE]; + enumerate_callback = (DeviceEnumerate_Callback *)packet; + + enumerate_callback_function(enumerate_callback->uid, + enumerate_callback->connected_uid, + enumerate_callback->position, + enumerate_callback->hardware_version, + enumerate_callback->firmware_version, + leconvert_uint16_from(enumerate_callback->device_identifier), + enumerate_callback->enumeration_type, + user_data); + } + } else { + device_p = ipcon_acquire_device(ipcon_p, packet->header.uid); + + if (device_p == NULL) { + return; + } + + callback_wrapper_function = device_p->callback_wrappers[packet->header.function_id]; + + if (callback_wrapper_function == NULL) { + device_release(device_p); + + return; + } + + if (device_check_validity(device_p) < 0) { + device_release(device_p); + + return; // silently ignoring callback for invalid device + } + + callback_wrapper_function(device_p, packet); + + device_release(device_p); + } +} + +static void ipcon_destroy_callback_context(CallbackContext *callback) { + thread_destroy(&callback->thread); + mutex_destroy(&callback->mutex); + queue_destroy(&callback->queue); + + free(callback); +} + +static void ipcon_exit_callback_thread(CallbackContext *callback) { + if (!thread_is_current(&callback->thread)) { + queue_put(&callback->queue, QUEUE_KIND_EXIT, NULL); + + thread_join(&callback->thread); + + ipcon_destroy_callback_context(callback); + } else { + queue_put(&callback->queue, QUEUE_KIND_DESTROY_AND_EXIT, NULL); + } +} + +static void ipcon_callback_loop(void *opaque) { + CallbackContext *callback = (CallbackContext *)opaque; + int kind; + void *data; + + while (true) { + if (queue_get(&callback->queue, &kind, &data) < 0) { + // FIXME: what to do here? try again? exit? + break; + } + + if (kind == QUEUE_KIND_EXIT) { + break; + } else if (kind == QUEUE_KIND_DESTROY_AND_EXIT) { + ipcon_destroy_callback_context(callback); + break; + } + + // FIXME: cannot lock callback mutex here because this can + // deadlock due to an ordering problem with the socket mutex + //mutex_lock(&callback->mutex); + + if (kind == QUEUE_KIND_META) { + ipcon_dispatch_meta(callback->ipcon_p, (Meta *)data); + } else if (kind == QUEUE_KIND_PACKET) { + // don't dispatch callbacks when the receive thread isn't running + if (callback->packet_dispatch_allowed) { + ipcon_dispatch_packet(callback->ipcon_p, (Packet *)data); + } + } + + //mutex_unlock(&callback->mutex); + + free(data); + } +} + +// NOTE: assumes that socket_mutex is locked if disconnect_immediately is true +static void ipcon_handle_disconnect_by_peer(IPConnectionPrivate *ipcon_p, + uint8_t disconnect_reason, + uint64_t socket_id, + bool disconnect_immediately) { + Meta *meta; + + ipcon_p->auto_reconnect_allowed = true; + + if (disconnect_immediately) { + ipcon_disconnect_unlocked(ipcon_p); + } + + meta = (Meta *)malloc(sizeof(Meta)); + meta->function_id = IPCON_CALLBACK_DISCONNECTED; + meta->parameter = disconnect_reason; + meta->socket_id = socket_id; + + queue_put(&ipcon_p->callback->queue, QUEUE_KIND_META, meta); +} + +enum { + IPCON_DISCONNECT_PROBE_INTERVAL = 5000 +}; + +enum { + IPCON_FUNCTION_DISCONNECT_PROBE = 128 +}; + +// NOTE: the disconnect probe loop is not allowed to hold the socket_mutex at any +// time because it is created and joined while the socket_mutex is locked +static void ipcon_disconnect_probe_loop(void *opaque) { + IPConnectionPrivate *ipcon_p = (IPConnectionPrivate *)opaque; + PacketHeader disconnect_probe; + + packet_header_create(&disconnect_probe, sizeof(PacketHeader), + IPCON_FUNCTION_DISCONNECT_PROBE, ipcon_p, NULL); + + while (event_wait(&ipcon_p->disconnect_probe_event, + IPCON_DISCONNECT_PROBE_INTERVAL) < 0) { + if (ipcon_p->disconnect_probe_flag) { + // FIXME: this might block + if (socket_send(ipcon_p->socket, &disconnect_probe, + disconnect_probe.length) < 0) { + ipcon_handle_disconnect_by_peer(ipcon_p, IPCON_DISCONNECT_REASON_ERROR, + ipcon_p->socket_id, false); + break; + } + } else { + ipcon_p->disconnect_probe_flag = true; + } + } +} + +static void ipcon_handle_response(IPConnectionPrivate *ipcon_p, Packet *response) { + DevicePrivate *device_p; + uint8_t sequence_number = packet_header_get_sequence_number(&response->header); + Packet *callback; + + ipcon_p->disconnect_probe_flag = false; + + response->header.uid = leconvert_uint32_from(response->header.uid); + + if (sequence_number == 0 && + response->header.function_id == IPCON_CALLBACK_ENUMERATE) { + if (ipcon_p->registered_callbacks[IPCON_CALLBACK_ENUMERATE] != NULL) { + callback = (Packet *)malloc(response->header.length); + + memcpy(callback, response, response->header.length); + queue_put(&ipcon_p->callback->queue, QUEUE_KIND_PACKET, callback); + } + + return; + } + + device_p = ipcon_acquire_device(ipcon_p, response->header.uid); + + if (device_p == NULL) { + // ignoring response for an unknown device + return; + } + + if (sequence_number == 0) { + if (device_p->registered_callbacks[DEVICE_NUM_FUNCTION_IDS + response->header.function_id] != NULL || + device_p->high_level_callbacks[response->header.function_id].exists) { + callback = (Packet *)malloc(response->header.length); + + memcpy(callback, response, response->header.length); + queue_put(&ipcon_p->callback->queue, QUEUE_KIND_PACKET, callback); + } + + device_release(device_p); + + return; + } + + if (device_p->expected_response_function_id == response->header.function_id && + device_p->expected_response_sequence_number == sequence_number) { + mutex_lock(&device_p->response_mutex); + memcpy(&device_p->response_packet, response, response->header.length); + mutex_unlock(&device_p->response_mutex); + + event_set(&device_p->response_event); + + device_release(device_p); + + return; + } + + device_release(device_p); + + // response seems to be OK, but can't be handled +} + +// NOTE: the receive loop is now allowed to hold the socket_mutex at any time +// because it is created and joined while the socket_mutex is locked +static void ipcon_receive_loop(void *opaque) { + IPConnectionPrivate *ipcon_p = (IPConnectionPrivate *)opaque; + uint64_t socket_id = ipcon_p->socket_id; + Packet pending_data[10]; + int pending_length = 0; + int length; + uint8_t disconnect_reason; + + while (ipcon_p->receive_flag) { + length = socket_receive(ipcon_p->socket, (uint8_t *)pending_data + pending_length, + sizeof(pending_data) - pending_length); + + if (!ipcon_p->receive_flag) { + return; + } + + if (length <= 0) { + if (length < 0 && errno == EINTR) { + continue; + } + + if (length == 0) { + disconnect_reason = IPCON_DISCONNECT_REASON_SHUTDOWN; + } else { + disconnect_reason = IPCON_DISCONNECT_REASON_ERROR; + } + + ipcon_handle_disconnect_by_peer(ipcon_p, disconnect_reason, socket_id, false); + return; + } + + pending_length += length; + + while (ipcon_p->receive_flag) { + if (pending_length < (int)sizeof(PacketHeader)) { + // wait for complete header + break; + } + + length = pending_data[0].header.length; + + if (pending_length < length) { + // wait for complete packet + break; + } + + ipcon_handle_response(ipcon_p, pending_data); + + memmove(pending_data, (uint8_t *)pending_data + length, + pending_length - length); + pending_length -= length; + } + } +} + +// NOTE: assumes that socket is NULL and socket_mutex is locked +static int ipcon_connect_unlocked(IPConnectionPrivate *ipcon_p, bool is_auto_reconnect) { + char service[32]; + struct addrinfo hints; + struct addrinfo *resolved = NULL; + Socket *tmp; + uint8_t connect_reason; + Meta *meta; + + // create callback queue and thread + if (ipcon_p->callback == NULL) { + ipcon_p->callback = (CallbackContext *)malloc(sizeof(CallbackContext)); + + ipcon_p->callback->ipcon_p = ipcon_p; + ipcon_p->callback->packet_dispatch_allowed = false; + + queue_create(&ipcon_p->callback->queue); + mutex_create(&ipcon_p->callback->mutex); + + if (thread_create(&ipcon_p->callback->thread, ipcon_callback_loop, + ipcon_p->callback) < 0) { + mutex_destroy(&ipcon_p->callback->mutex); + queue_destroy(&ipcon_p->callback->queue); + + free(ipcon_p->callback); + ipcon_p->callback = NULL; + + return E_NO_THREAD; + } + } + + // create and connect socket + snprintf(service, sizeof(service), "%u", ipcon_p->port); + + memset(&hints, 0, sizeof(hints)); + + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(ipcon_p->host, service, &hints, &resolved) != 0) { + // destroy callback thread + if (!is_auto_reconnect) { + ipcon_exit_callback_thread(ipcon_p->callback); + ipcon_p->callback = NULL; + } + + return E_HOSTNAME_INVALID; + } + + tmp = (Socket *)malloc(sizeof(Socket)); + + if (socket_create(tmp, resolved->ai_family, resolved->ai_socktype, + resolved->ai_protocol) < 0) { + // destroy callback thread + if (!is_auto_reconnect) { + ipcon_exit_callback_thread(ipcon_p->callback); + ipcon_p->callback = NULL; + } + + // destroy socket + free(tmp); + freeaddrinfo(resolved); + + return E_NO_STREAM_SOCKET; + } + + if (socket_connect(tmp, resolved->ai_addr, resolved->ai_addrlen) < 0) { + // destroy callback thread + if (!is_auto_reconnect) { + ipcon_exit_callback_thread(ipcon_p->callback); + ipcon_p->callback = NULL; + } + + // destroy socket + socket_destroy(tmp); + free(tmp); + freeaddrinfo(resolved); + + return E_NO_CONNECT; + } + + freeaddrinfo(resolved); + + ipcon_p->socket = tmp; + ++ipcon_p->socket_id; + + // create disconnect probe thread + ipcon_p->disconnect_probe_flag = true; + + event_reset(&ipcon_p->disconnect_probe_event); + + if (thread_create(&ipcon_p->disconnect_probe_thread, + ipcon_disconnect_probe_loop, ipcon_p) < 0) { + // destroy callback thread + if (!is_auto_reconnect) { + ipcon_exit_callback_thread(ipcon_p->callback); + ipcon_p->callback = NULL; + } + + // destroy socket + socket_destroy(ipcon_p->socket); + free(ipcon_p->socket); + ipcon_p->socket = NULL; + + return E_NO_THREAD; + } + + // create receive thread + ipcon_p->receive_flag = true; + ipcon_p->callback->packet_dispatch_allowed = true; + + if (thread_create(&ipcon_p->receive_thread, ipcon_receive_loop, ipcon_p) < 0) { + ipcon_p->receive_flag = false; + + // destroy socket + ipcon_disconnect_unlocked(ipcon_p); + + // destroy callback thread + if (!is_auto_reconnect) { + ipcon_exit_callback_thread(ipcon_p->callback); + ipcon_p->callback = NULL; + } + + return E_NO_THREAD; + } + + ipcon_p->auto_reconnect_allowed = false; + ipcon_p->auto_reconnect_pending = false; + + // trigger connected callback + if (is_auto_reconnect) { + connect_reason = IPCON_CONNECT_REASON_AUTO_RECONNECT; + } else { + connect_reason = IPCON_CONNECT_REASON_REQUEST; + } + + meta = (Meta *)malloc(sizeof(Meta)); + meta->function_id = IPCON_CALLBACK_CONNECTED; + meta->parameter = connect_reason; + meta->socket_id = 0; + + queue_put(&ipcon_p->callback->queue, QUEUE_KIND_META, meta); + + return E_OK; +} + +// NOTE: assumes that socket is not NULL and socket_mutex is locked +static void ipcon_disconnect_unlocked(IPConnectionPrivate *ipcon_p) { + // destroy disconnect probe thread + event_set(&ipcon_p->disconnect_probe_event); + thread_join(&ipcon_p->disconnect_probe_thread); + thread_destroy(&ipcon_p->disconnect_probe_thread); + + // stop dispatching packet callbacks before ending the receive + // thread to avoid timeout exceptions due to callback functions + // trying to call getters + if (!thread_is_current(&ipcon_p->callback->thread)) { + // FIXME: cannot lock callback mutex here because this can + // deadlock due to an ordering problem with the socket mutex + //mutex_lock(&ipcon->callback->mutex); + + ipcon_p->callback->packet_dispatch_allowed = false; + + //mutex_unlock(&ipcon->callback->mutex); + } else { + ipcon_p->callback->packet_dispatch_allowed = false; + } + + // destroy receive thread + if (ipcon_p->receive_flag) { + ipcon_p->receive_flag = false; + + socket_shutdown(ipcon_p->socket); + + thread_join(&ipcon_p->receive_thread); + thread_destroy(&ipcon_p->receive_thread); + } + + // destroy socket + socket_destroy(ipcon_p->socket); + free(ipcon_p->socket); + ipcon_p->socket = NULL; +} + +static int ipcon_send_request(IPConnectionPrivate *ipcon_p, Packet *request) { + int ret = E_OK; + + mutex_lock(&ipcon_p->socket_mutex); + + if (ipcon_p->socket == NULL) { + ret = E_NOT_CONNECTED; + } + + if (ret == E_OK) { + if (socket_send(ipcon_p->socket, request, request->header.length) < 0) { + ipcon_handle_disconnect_by_peer(ipcon_p, IPCON_DISCONNECT_REASON_ERROR, 0, true); + + ret = E_NOT_CONNECTED; + } else { + ipcon_p->disconnect_probe_flag = false; + } + } + + mutex_unlock(&ipcon_p->socket_mutex); + + return ret; +} + +void ipcon_create(IPConnection *ipcon) { + IPConnectionPrivate *ipcon_p; + int i; + + ipcon_p = (IPConnectionPrivate *)malloc(sizeof(IPConnectionPrivate)); + ipcon->p = ipcon_p; + +#ifdef _WIN32 + ipcon_p->wsa_startup_done = false; +#endif + + ipcon_p->host = NULL; + ipcon_p->port = 0; + + ipcon_p->timeout = 2500; + + ipcon_p->auto_reconnect = true; + ipcon_p->auto_reconnect_allowed = false; + ipcon_p->auto_reconnect_pending = false; + + mutex_create(&ipcon_p->sequence_number_mutex); + ipcon_p->next_sequence_number = 0; + + mutex_create(&ipcon_p->authentication_mutex); + ipcon_p->next_authentication_nonce = 0; + + mutex_create(&ipcon_p->devices_ref_mutex); + table_create(&ipcon_p->devices); + + for (i = 0; i < IPCON_NUM_CALLBACK_IDS; ++i) { + ipcon_p->registered_callbacks[i] = NULL; + ipcon_p->registered_callback_user_data[i] = NULL; + } + + mutex_create(&ipcon_p->socket_mutex); + ipcon_p->socket = NULL; + ipcon_p->socket_id = 0; + + ipcon_p->receive_flag = false; + + ipcon_p->callback = NULL; + + ipcon_p->disconnect_probe_flag = false; + event_create(&ipcon_p->disconnect_probe_event); + + semaphore_create(&ipcon_p->wait); + + brickd_create(&ipcon_p->brickd, "2", ipcon); +} + +void ipcon_destroy(IPConnection *ipcon) { + IPConnectionPrivate *ipcon_p = ipcon->p; + + ipcon_disconnect(ipcon); // FIXME: disable disconnected callback before? + + brickd_destroy(&ipcon_p->brickd); + + mutex_destroy(&ipcon_p->authentication_mutex); + + mutex_destroy(&ipcon_p->sequence_number_mutex); + + table_destroy(&ipcon_p->devices); // FIXME: destroy all devices? + mutex_destroy(&ipcon_p->devices_ref_mutex); + + mutex_destroy(&ipcon_p->socket_mutex); + + event_destroy(&ipcon_p->disconnect_probe_event); + + semaphore_destroy(&ipcon_p->wait); + + free(ipcon_p->host); + + free(ipcon_p); +} + +int ipcon_connect(IPConnection *ipcon, const char *host, uint16_t port) { + IPConnectionPrivate *ipcon_p = ipcon->p; + int ret; +#ifdef _WIN32 + WSADATA wsa_data; +#endif + + mutex_lock(&ipcon_p->socket_mutex); + +#ifdef _WIN32 + if (!ipcon_p->wsa_startup_done) { + if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) { + mutex_unlock(&ipcon_p->socket_mutex); + + return E_NO_STREAM_SOCKET; + } + + ipcon_p->wsa_startup_done = true; + } +#endif + + if (ipcon_p->socket != NULL) { + mutex_unlock(&ipcon_p->socket_mutex); + + return E_ALREADY_CONNECTED; + } + + free(ipcon_p->host); + + ipcon_p->host = strdup(host); + ipcon_p->port = port; + + ret = ipcon_connect_unlocked(ipcon_p, false); + + mutex_unlock(&ipcon_p->socket_mutex); + + return ret; +} + +int ipcon_disconnect(IPConnection *ipcon) { + IPConnectionPrivate *ipcon_p = ipcon->p; + CallbackContext *callback; + Meta *meta; + + mutex_lock(&ipcon_p->socket_mutex); + + ipcon_p->auto_reconnect_allowed = false; + + if (ipcon_p->auto_reconnect_pending) { + // abort pending auto-reconnect + ipcon_p->auto_reconnect_pending = false; + } else { + if (ipcon_p->socket == NULL) { + mutex_unlock(&ipcon_p->socket_mutex); + + return E_NOT_CONNECTED; + } + + ipcon_disconnect_unlocked(ipcon_p); + } + + // destroy callback thread + callback = ipcon_p->callback; + ipcon_p->callback = NULL; + + mutex_unlock(&ipcon_p->socket_mutex); + + // do this outside of socket_mutex to allow calling (dis-)connect from + // the callbacks while blocking on the join call here + meta = (Meta *)malloc(sizeof(Meta)); + meta->function_id = IPCON_CALLBACK_DISCONNECTED; + meta->parameter = IPCON_DISCONNECT_REASON_REQUEST; + meta->socket_id = 0; + + queue_put(&callback->queue, QUEUE_KIND_META, meta); + + ipcon_exit_callback_thread(callback); + + return E_OK; +} + +int ipcon_authenticate(IPConnection *ipcon, const char secret[64]) { + IPConnectionPrivate *ipcon_p = ipcon->p; + int ret; + uint32_t nonces[2]; // server, client + uint8_t digest[SHA1_DIGEST_LENGTH]; + int i; + int secret_length; + + secret_length = string_length(secret, IPCON_MAX_SECRET_LENGTH); + + for (i = 0; i < secret_length; ++i) { + if ((secret[i] & 0x80) != 0) { + return E_NON_ASCII_CHAR_IN_SECRET; + } + } + + mutex_lock(&ipcon_p->authentication_mutex); + + if (ipcon_p->next_authentication_nonce == 0) { + ipcon_p->next_authentication_nonce = get_random_uint32(); + } + + ret = brickd_get_authentication_nonce(&ipcon_p->brickd, (uint8_t *)nonces); + + if (ret < 0) { + mutex_unlock(&ipcon_p->authentication_mutex); + + return ret; + } + + nonces[1] = ipcon_p->next_authentication_nonce++; + + hmac_sha1((uint8_t *)secret, secret_length, + (uint8_t *)nonces, sizeof(nonces), digest); + + ret = brickd_authenticate(&ipcon_p->brickd, (uint8_t *)&nonces[1], digest); + + if (ret < 0) { + mutex_unlock(&ipcon_p->authentication_mutex); + + return ret; + } + + mutex_unlock(&ipcon_p->authentication_mutex); + + return E_OK; +} + +int ipcon_get_connection_state(IPConnection *ipcon) { + IPConnectionPrivate *ipcon_p = ipcon->p; + + if (ipcon_p->socket != NULL) { + return IPCON_CONNECTION_STATE_CONNECTED; + } else if (ipcon_p->auto_reconnect_pending) { + return IPCON_CONNECTION_STATE_PENDING; + } else { + return IPCON_CONNECTION_STATE_DISCONNECTED; + } +} + +void ipcon_set_auto_reconnect(IPConnection *ipcon, bool auto_reconnect) { + IPConnectionPrivate *ipcon_p = ipcon->p; + + ipcon_p->auto_reconnect = auto_reconnect; + + if (!ipcon_p->auto_reconnect) { + // abort potentially pending auto reconnect + ipcon_p->auto_reconnect_allowed = false; + } +} + +bool ipcon_get_auto_reconnect(IPConnection *ipcon) { + return ipcon->p->auto_reconnect; +} + +void ipcon_set_timeout(IPConnection *ipcon, uint32_t timeout) { // in msec + ipcon->p->timeout = timeout; +} + +uint32_t ipcon_get_timeout(IPConnection *ipcon) { // in msec + return ipcon->p->timeout; +} + +int ipcon_enumerate(IPConnection *ipcon) { + IPConnectionPrivate *ipcon_p = ipcon->p; + DeviceEnumerate_Broadcast enumerate; + int ret; + + ret = packet_header_create(&enumerate.header, sizeof(DeviceEnumerate_Broadcast), + DEVICE_FUNCTION_ENUMERATE, ipcon_p, NULL); + + if (ret < 0) { + return ret; + } + + return ipcon_send_request(ipcon_p, (Packet *)&enumerate); +} + +void ipcon_wait(IPConnection *ipcon) { + semaphore_acquire(&ipcon->p->wait); +} + +void ipcon_unwait(IPConnection *ipcon) { + semaphore_release(&ipcon->p->wait); +} + +void ipcon_register_callback(IPConnection *ipcon, int16_t callback_id, + void (*function)(void), void *user_data) { + IPConnectionPrivate *ipcon_p = ipcon->p; + + if (callback_id <= -1 || callback_id >= IPCON_NUM_CALLBACK_IDS) { + return; + } + + ipcon_p->registered_callbacks[callback_id] = function; + ipcon_p->registered_callback_user_data[callback_id] = user_data; +} + +void ipcon_add_device(IPConnectionPrivate *ipcon_p, DevicePrivate *device_p) { + DevicePrivate *replaced_device_p; + + if (device_p->uid_valid) { + replaced_device_p = (DevicePrivate *)table_insert(&ipcon_p->devices, device_p->uid, device_p); + + if (replaced_device_p != NULL) { + replaced_device_p->replaced = true; + } + } +} + +int packet_header_create(PacketHeader *header, uint8_t length, + uint8_t function_id, IPConnectionPrivate *ipcon_p, + DevicePrivate *device_p) { + uint8_t sequence_number; + bool response_expected = false; + int ret = E_OK; + + mutex_lock(&ipcon_p->sequence_number_mutex); + + sequence_number = ipcon_p->next_sequence_number + 1; + ipcon_p->next_sequence_number = sequence_number % 15; + + mutex_unlock(&ipcon_p->sequence_number_mutex); + + memset(header, 0, sizeof(PacketHeader)); + + if (device_p != NULL) { + header->uid = leconvert_uint32_to(device_p->uid); + } + + header->length = length; + header->function_id = function_id; + packet_header_set_sequence_number(header, sequence_number); + + if (device_p != NULL) { + ret = device_get_response_expected(device_p, function_id, &response_expected); + packet_header_set_response_expected(header, response_expected); + } + + return ret; +} + +uint8_t packet_header_get_sequence_number(PacketHeader *header) { + return (header->sequence_number_and_options >> 4) & 0x0F; +} + +void packet_header_set_sequence_number(PacketHeader *header, uint8_t sequence_number) { + header->sequence_number_and_options &= ~0xF0; + header->sequence_number_and_options |= (sequence_number << 4) & 0xF0; +} + +uint8_t packet_header_get_response_expected(PacketHeader *header) { + return (header->sequence_number_and_options >> 3) & 0x01; +} + +void packet_header_set_response_expected(PacketHeader *header, bool response_expected) { + if (response_expected) { + header->sequence_number_and_options |= 0x01 << 3; + } else { + header->sequence_number_and_options &= ~(0x01 << 3); + } +} + +uint8_t packet_header_get_error_code(PacketHeader *header) { + return (header->error_code_and_future_use >> 6) & 0x03; +} + +int16_t leconvert_int16_to(int16_t native) { + return leconvert_uint16_to(native); +} + +uint16_t leconvert_uint16_to(uint16_t native) { + union { + uint8_t bytes[2]; + uint16_t little; + } c; + + c.bytes[0] = (native >> 0) & 0xFF; + c.bytes[1] = (native >> 8) & 0xFF; + + return c.little; +} + +int32_t leconvert_int32_to(int32_t native) { + return leconvert_uint32_to(native); +} + +uint32_t leconvert_uint32_to(uint32_t native) { + union { + uint8_t bytes[4]; + uint32_t little; + } c; + + c.bytes[0] = (native >> 0) & 0xFF; + c.bytes[1] = (native >> 8) & 0xFF; + c.bytes[2] = (native >> 16) & 0xFF; + c.bytes[3] = (native >> 24) & 0xFF; + + return c.little; +} + +int64_t leconvert_int64_to(int64_t native) { + return leconvert_uint64_to(native); +} + +uint64_t leconvert_uint64_to(uint64_t native) { + union { + uint8_t bytes[8]; + uint64_t little; + } c; + + c.bytes[0] = (native >> 0) & 0xFF; + c.bytes[1] = (native >> 8) & 0xFF; + c.bytes[2] = (native >> 16) & 0xFF; + c.bytes[3] = (native >> 24) & 0xFF; + c.bytes[4] = (native >> 32) & 0xFF; + c.bytes[5] = (native >> 40) & 0xFF; + c.bytes[6] = (native >> 48) & 0xFF; + c.bytes[7] = (native >> 56) & 0xFF; + + return c.little; +} + +float leconvert_float_to(float native) { + union { + uint32_t u; + float f; + } c; + + c.f = native; + c.u = leconvert_uint32_to(c.u); + + return c.f; +} + +int16_t leconvert_int16_from(int16_t little) { + return leconvert_uint16_from(little); +} + +uint16_t leconvert_uint16_from(uint16_t little) { + uint8_t *bytes = (uint8_t *)&little; + + return ((uint16_t)bytes[1] << 8) | + (uint16_t)bytes[0]; +} + +int32_t leconvert_int32_from(int32_t little) { + return leconvert_uint32_from(little); +} + +uint32_t leconvert_uint32_from(uint32_t little) { + uint8_t *bytes = (uint8_t *)&little; + + return ((uint32_t)bytes[3] << 24) | + ((uint32_t)bytes[2] << 16) | + ((uint32_t)bytes[1] << 8) | + (uint32_t)bytes[0]; +} + +int64_t leconvert_int64_from(int64_t little) { + return leconvert_uint64_from(little); +} + +uint64_t leconvert_uint64_from(uint64_t little) { + uint8_t *bytes = (uint8_t *)&little; + + return ((uint64_t)bytes[7] << 56) | + ((uint64_t)bytes[6] << 48) | + ((uint64_t)bytes[5] << 40) | + ((uint64_t)bytes[4] << 32) | + ((uint64_t)bytes[3] << 24) | + ((uint64_t)bytes[2] << 16) | + ((uint64_t)bytes[1] << 8) | + (uint64_t)bytes[0]; +} + +float leconvert_float_from(float little) { + union { + uint32_t u; + float f; + } c; + + c.f = little; + c.u = leconvert_uint32_from(c.u); + + return c.f; +} + +#ifdef __cplusplus +} +#endif diff --git a/tinkerforge/ip_connection.h b/tinkerforge/ip_connection.h new file mode 100644 index 0000000..5c21197 --- /dev/null +++ b/tinkerforge/ip_connection.h @@ -0,0 +1,716 @@ +/* + * Copyright (C) 2012-2014, 2019-2020 Matthias Bolte + * Copyright (C) 2011 Olaf Lüke + * + * Redistribution and use in source and binary forms of this file, + * with or without modification, are permitted. See the Creative + * Commons Zero (CC0 1.0) License for more details. + */ + +#ifndef IP_CONNECTION_H +#define IP_CONNECTION_H + +/** + * \defgroup IPConnection IP Connection + */ + +#ifndef __STDC_LIMIT_MACROS + #define __STDC_LIMIT_MACROS +#endif +#include +#include +#include + +#if (!defined __cplusplus && defined __GNUC__) || (defined _MSC_VER && _MSC_VER >= 1600) + #include +#endif + +#ifdef _WIN32 + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #include +#else + #include + #include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + E_OK = 0, + E_TIMEOUT = -1, + E_NO_STREAM_SOCKET = -2, + E_HOSTNAME_INVALID = -3, + E_NO_CONNECT = -4, + E_NO_THREAD = -5, + E_NOT_ADDED = -6, // unused since v2.0 + E_ALREADY_CONNECTED = -7, + E_NOT_CONNECTED = -8, + E_INVALID_PARAMETER = -9, // error response from device + E_NOT_SUPPORTED = -10, // error response from device + E_UNKNOWN_ERROR_CODE = -11, // error response from device + E_STREAM_OUT_OF_SYNC = -12, + E_INVALID_UID = -13, + E_NON_ASCII_CHAR_IN_SECRET = -14, + E_WRONG_DEVICE_TYPE = -15, + E_DEVICE_REPLACED = -16, + E_WRONG_RESPONSE_LENGTH = -17 +}; + +#ifdef IPCON_EXPOSE_MILLISLEEP + +void millisleep(uint32_t msec); + +#endif // IPCON_EXPOSE_MILLISLEEP + +#ifdef IPCON_EXPOSE_INTERNALS + +typedef struct _Socket Socket; + +typedef struct { +#ifdef _WIN32 + CRITICAL_SECTION handle; +#else + pthread_mutex_t handle; +#endif +} Mutex; + +void mutex_create(Mutex *mutex); + +void mutex_destroy(Mutex *mutex); + +void mutex_lock(Mutex *mutex); + +void mutex_unlock(Mutex *mutex); + +typedef struct { +#ifdef _WIN32 + HANDLE handle; +#else + pthread_cond_t condition; + pthread_mutex_t mutex; + bool flag; +#endif +} Event; + +typedef struct { +#ifdef _WIN32 + HANDLE handle; +#else + sem_t object; + sem_t *pointer; +#endif +} Semaphore; + +typedef void (*ThreadFunction)(void *opaque); + +typedef struct { +#ifdef _WIN32 + HANDLE handle; + DWORD id; +#else + pthread_t handle; +#endif + ThreadFunction function; + void *opaque; +} Thread; + +typedef struct { + Mutex mutex; + int used; + int allocated; + uint32_t *keys; + void **values; +} Table; + +typedef struct _QueueItem { + struct _QueueItem *next; + int kind; + void *data; +} QueueItem; + +typedef struct { + Mutex mutex; + Semaphore semaphore; + QueueItem *head; + QueueItem *tail; +} Queue; + +#if defined _MSC_VER || defined __BORLANDC__ + #pragma pack(push) + #pragma pack(1) + #define ATTRIBUTE_PACKED +#elif defined __GNUC__ + #ifdef _WIN32 + // workaround struct packing bug in GCC 4.7 on Windows + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 + #define ATTRIBUTE_PACKED __attribute__((gcc_struct, packed)) + #else + #define ATTRIBUTE_PACKED __attribute__((packed)) + #endif +#else + #error unknown compiler, do not know how to enable struct packing +#endif + +typedef struct { + uint32_t uid; // always little endian + uint8_t length; + uint8_t function_id; + uint8_t sequence_number_and_options; + uint8_t error_code_and_future_use; +} ATTRIBUTE_PACKED PacketHeader; + +typedef struct { + PacketHeader header; + uint8_t payload[64]; + uint8_t optional_data[8]; +} ATTRIBUTE_PACKED Packet; + +#if defined _MSC_VER || defined __BORLANDC__ + #pragma pack(pop) +#endif +#undef ATTRIBUTE_PACKED + +#endif // IPCON_EXPOSE_INTERNALS + +typedef struct _IPConnection IPConnection; +typedef struct _IPConnectionPrivate IPConnectionPrivate; +typedef struct _Device Device; +typedef struct _DevicePrivate DevicePrivate; + +#ifdef IPCON_EXPOSE_INTERNALS + +typedef struct _CallbackContext CallbackContext; +typedef struct _HighLevelCallback HighLevelCallback; + +/** + * \internal + */ +struct _HighLevelCallback { + bool exists; + void *data; + size_t length; +}; + +#endif + +typedef void (*EnumerateCallbackFunction)(const char *uid, + const char *connected_uid, + char position, + uint8_t hardware_version[3], + uint8_t firmware_version[3], + uint16_t device_identifier, + uint8_t enumeration_type, + void *user_data); +typedef void (*ConnectedCallbackFunction)(uint8_t connect_reason, + void *user_data); +typedef void (*DisconnectedCallbackFunction)(uint8_t disconnect_reason, + void *user_data); + +#ifdef IPCON_EXPOSE_INTERNALS + +typedef void (*CallbackFunction)(void); +typedef void (*CallbackWrapperFunction)(DevicePrivate *device_p, Packet *packet); + +#endif + +/** + * \internal + */ +struct _Device { + DevicePrivate *p; +}; + +#ifdef IPCON_EXPOSE_INTERNALS + +#define DEVICE_NUM_FUNCTION_IDS 256 + +typedef enum { + DEVICE_IDENTIFIER_CHECK_PENDING = 0, + DEVICE_IDENTIFIER_CHECK_MATCH = 1, + DEVICE_IDENTIFIER_CHECK_MISMATCH = 2 +} DeviceIdentifierCheck; + +/** + * \internal + */ +struct _DevicePrivate { + int ref_count; + + bool replaced; + + uint32_t uid; // always host endian + bool uid_valid; + + IPConnectionPrivate *ipcon_p; + + uint8_t api_version[3]; + + uint16_t device_identifier; + Mutex device_identifier_mutex; + DeviceIdentifierCheck device_identifier_check; // protected by device_identifier_mutex + + Mutex request_mutex; + + uint8_t expected_response_function_id; // protected by request_mutex + uint8_t expected_response_sequence_number; // protected by request_mutex + Mutex response_mutex; + Packet response_packet; // protected by response_mutex + Event response_event; + int response_expected[DEVICE_NUM_FUNCTION_IDS]; + + Mutex stream_mutex; + + CallbackFunction registered_callbacks[DEVICE_NUM_FUNCTION_IDS * 2]; + void *registered_callback_user_data[DEVICE_NUM_FUNCTION_IDS * 2]; + CallbackWrapperFunction callback_wrappers[DEVICE_NUM_FUNCTION_IDS]; + HighLevelCallback high_level_callbacks[DEVICE_NUM_FUNCTION_IDS]; +}; + +/** + * \internal + */ +enum { + DEVICE_RESPONSE_EXPECTED_INVALID_FUNCTION_ID = 0, + DEVICE_RESPONSE_EXPECTED_ALWAYS_TRUE, // getter + DEVICE_RESPONSE_EXPECTED_TRUE, // setter + DEVICE_RESPONSE_EXPECTED_FALSE // setter, default +}; + +/** + * \internal + */ +void device_create(Device *device, const char *uid, + IPConnectionPrivate *ipcon_p, uint8_t api_version_major, + uint8_t api_version_minor, uint8_t api_version_release, + uint16_t device_identifier); + +/** + * \internal + */ +void device_release(DevicePrivate *device_p); + +/** + * \internal + */ +int device_get_response_expected(DevicePrivate *device_p, uint8_t function_id, + bool *ret_response_expected); + +/** + * \internal + */ +int device_set_response_expected(DevicePrivate *device_p, uint8_t function_id, + bool response_expected); + +/** + * \internal + */ +int device_set_response_expected_all(DevicePrivate *device_p, bool response_expected); + +/** + * \internal + */ +void device_register_callback(DevicePrivate *device_p, int16_t callback_id, + void (*function)(void), void *user_data); + +/** + * \internal + */ +int device_get_api_version(DevicePrivate *device_p, uint8_t ret_api_version[3]); + +/** + * \internal + */ +int device_send_request(DevicePrivate *device_p, Packet *request, Packet *response, + int expected_response_length); + +/** + * \internal + */ +int device_check_validity(DevicePrivate *device_p); + +#endif // IPCON_EXPOSE_INTERNALS + +/** + * \ingroup IPConnection + * + * Possible IDs for ipcon_register_callback. + */ +enum { + IPCON_CALLBACK_ENUMERATE = 253, + IPCON_CALLBACK_CONNECTED = 0, + IPCON_CALLBACK_DISCONNECTED = 1 +}; + +/** + * \ingroup IPConnection + * + * Possible values for enumeration_type parameter of EnumerateCallback. + */ +enum { + IPCON_ENUMERATION_TYPE_AVAILABLE = 0, + IPCON_ENUMERATION_TYPE_CONNECTED = 1, + IPCON_ENUMERATION_TYPE_DISCONNECTED = 2 +}; + +/** + * \ingroup IPConnection + * + * Possible values for connect_reason parameter of ConnectedCallback. + */ +enum { + IPCON_CONNECT_REASON_REQUEST = 0, + IPCON_CONNECT_REASON_AUTO_RECONNECT = 1 +}; + +/** + * \ingroup IPConnection + * + * Possible values for disconnect_reason parameter of DisconnectedCallback. + */ +enum { + IPCON_DISCONNECT_REASON_REQUEST = 0, + IPCON_DISCONNECT_REASON_ERROR = 1, + IPCON_DISCONNECT_REASON_SHUTDOWN = 2 +}; + +/** + * \ingroup IPConnection + * + * Possible return values of ipcon_get_connection_state. + */ +enum { + IPCON_CONNECTION_STATE_DISCONNECTED = 0, + IPCON_CONNECTION_STATE_CONNECTED = 1, + IPCON_CONNECTION_STATE_PENDING = 2 // auto-reconnect in progress +}; + +/** + * \internal + */ +struct _IPConnection { + IPConnectionPrivate *p; +}; + +#ifdef IPCON_EXPOSE_INTERNALS + +#define IPCON_NUM_CALLBACK_IDS 256 +#define IPCON_MAX_SECRET_LENGTH 64 + +/** + * \internal + */ +typedef Device BrickDaemon; + +/** + * \internal + */ +struct _IPConnectionPrivate { +#ifdef _WIN32 + bool wsa_startup_done; // protected by socket_mutex +#endif + + char *host; + uint16_t port; + + uint32_t timeout; // in msec + + bool auto_reconnect; + bool auto_reconnect_allowed; + bool auto_reconnect_pending; + + Mutex sequence_number_mutex; + uint8_t next_sequence_number; // protected by sequence_number_mutex + + Mutex authentication_mutex; // protects authentication handshake + uint32_t next_authentication_nonce; // protected by authentication_mutex + + Mutex devices_ref_mutex; // protects DevicePrivate.ref_count + Table devices; + + CallbackFunction registered_callbacks[IPCON_NUM_CALLBACK_IDS]; + void *registered_callback_user_data[IPCON_NUM_CALLBACK_IDS]; + + Mutex socket_mutex; + Socket *socket; // protected by socket_mutex + uint64_t socket_id; // protected by socket_mutex + + bool receive_flag; + Thread receive_thread; // protected by socket_mutex + + CallbackContext *callback; + + bool disconnect_probe_flag; + Thread disconnect_probe_thread; // protected by socket_mutex + Event disconnect_probe_event; + + Semaphore wait; + + BrickDaemon brickd; +}; + +#endif // IPCON_EXPOSE_INTERNALS + +/** + * \ingroup IPConnection + * + * Creates an IP Connection object that can be used to enumerate the available + * devices. It is also required for the constructor of Bricks and Bricklets. + */ +void ipcon_create(IPConnection *ipcon); + +/** + * \ingroup IPConnection + * + * Destroys the IP Connection object. Calls ipcon_disconnect internally. + * The connection to the Brick Daemon gets closed and the threads of the + * IP Connection are terminated. + */ +void ipcon_destroy(IPConnection *ipcon); + +/** + * \ingroup IPConnection + * + * Creates a TCP/IP connection to the given \c host and c\ port. The host and + * port can point to a Brick Daemon or to a WIFI/Ethernet Extension. + * + * Devices can only be controlled when the connection was established + * successfully. + * + * Blocks until the connection is established and returns an error code if + * there is no Brick Daemon or WIFI/Ethernet Extension listening at the given + * host and port. + */ +int ipcon_connect(IPConnection *ipcon, const char *host, uint16_t port); + +/** + * \ingroup IPConnection + * + * Disconnects the TCP/IP connection from the Brick Daemon or the WIFI/Ethernet + * Extension. + */ +int ipcon_disconnect(IPConnection *ipcon); + +/** + * \ingroup IPConnection + * + * Performs an authentication handshake with the connected Brick Daemon or + * WIFI/Ethernet Extension. If the handshake succeeds the connection switches + * from non-authenticated to authenticated state and communication can + * continue as normal. If the handshake fails then the connection gets closed. + * Authentication can fail if the wrong secret was used or if authentication + * is not enabled at all on the Brick Daemon or the WIFI/Ethernet Extension. + * + * For more information about authentication see + * https://www.tinkerforge.com/en/doc/Tutorials/Tutorial_Authentication/Tutorial.html + */ +int ipcon_authenticate(IPConnection *ipcon, const char secret[64]); + +/** + * \ingroup IPConnection + * + * Can return the following states: + * + * - IPCON_CONNECTION_STATE_DISCONNECTED: No connection is established. + * - IPCON_CONNECTION_STATE_CONNECTED: A connection to the Brick Daemon or + * the WIFI/Ethernet Extension is established. + * - IPCON_CONNECTION_STATE_PENDING: IP Connection is currently trying to + * connect. + */ +int ipcon_get_connection_state(IPConnection *ipcon); + +/** + * \ingroup IPConnection + * + * Enables or disables auto-reconnect. If auto-reconnect is enabled, + * the IP Connection will try to reconnect to the previously given + * host and port, if the connection is lost. + * + * Default value is *true*. + */ +void ipcon_set_auto_reconnect(IPConnection *ipcon, bool auto_reconnect); + +/** + * \ingroup IPConnection + * + * Returns *true* if auto-reconnect is enabled, *false* otherwise. + */ +bool ipcon_get_auto_reconnect(IPConnection *ipcon); + +/** + * \ingroup IPConnection + * + * Sets the timeout in milliseconds for getters and for setters for which the + * response expected flag is activated. + * + * Default timeout is 2500. + */ +void ipcon_set_timeout(IPConnection *ipcon, uint32_t timeout); + +/** + * \ingroup IPConnection + * + * Returns the timeout as set by ipcon_set_timeout. + */ +uint32_t ipcon_get_timeout(IPConnection *ipcon); + +/** + * \ingroup IPConnection + * + * Broadcasts an enumerate request. All devices will respond with an enumerate + * callback. + */ +int ipcon_enumerate(IPConnection *ipcon); + +/** + * \ingroup IPConnection + * + * Stops the current thread until ipcon_unwait is called. + * + * This is useful if you rely solely on callbacks for events, if you want + * to wait for a specific callback or if the IP Connection was created in + * a thread. + * + * ipcon_wait and ipcon_unwait act in the same way as "acquire" and "release" + * of a semaphore. + */ +void ipcon_wait(IPConnection *ipcon); + +/** + * \ingroup IPConnection + * + * Unwaits the thread previously stopped by ipcon_wait. + * + * ipcon_wait and ipcon_unwait act in the same way as "acquire" and "release" + * of a semaphore. + */ +void ipcon_unwait(IPConnection *ipcon); + +/** + * \ingroup IPConnection + * + * Registers the given \c function with the given \c callback_id. The + * \c user_data will be passed as the last parameter to the \c function. + */ +void ipcon_register_callback(IPConnection *ipcon, int16_t callback_id, + void (*function)(void), void *user_data); + +#ifdef IPCON_EXPOSE_INTERNALS + +/** + * \internal + */ +void ipcon_add_device(IPConnectionPrivate *ipcon_p, DevicePrivate *device_p); + +/** + * \internal + */ +int packet_header_create(PacketHeader *header, uint8_t length, + uint8_t function_id, IPConnectionPrivate *ipcon_p, + DevicePrivate *device_p); + +/** + * \internal + */ +uint8_t packet_header_get_sequence_number(PacketHeader *header); + +/** + * \internal + */ +void packet_header_set_sequence_number(PacketHeader *header, uint8_t sequence_number); + +/** + * \internal + */ +uint8_t packet_header_get_response_expected(PacketHeader *header); + +/** + * \internal + */ +void packet_header_set_response_expected(PacketHeader *header, bool response_expected); + +/** + * \internal + */ +uint8_t packet_header_get_error_code(PacketHeader *header); + +/** + * \internal + */ +int16_t leconvert_int16_to(int16_t native); + +/** + * \internal + */ +uint16_t leconvert_uint16_to(uint16_t native); + +/** + * \internal + */ +int32_t leconvert_int32_to(int32_t native); + +/** + * \internal + */ +uint32_t leconvert_uint32_to(uint32_t native); + +/** + * \internal + */ +int64_t leconvert_int64_to(int64_t native); + +/** + * \internal + */ +uint64_t leconvert_uint64_to(uint64_t native); + +/** + * \internal + */ +float leconvert_float_to(float native); + +/** + * \internal + */ +int16_t leconvert_int16_from(int16_t little); + +/** + * \internal + */ +uint16_t leconvert_uint16_from(uint16_t little); + +/** + * \internal + */ +int32_t leconvert_int32_from(int32_t little); + +/** + * \internal + */ +uint32_t leconvert_uint32_from(uint32_t little); + +/** + * \internal + */ +int64_t leconvert_int64_from(int64_t little); + +/** + * \internal + */ +uint64_t leconvert_uint64_from(uint64_t little); + +/** + * \internal + */ +float leconvert_float_from(float little); + +#endif // IPCON_EXPOSE_INTERNALS + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/weatherStation.pro b/weatherStation.pro new file mode 100644 index 0000000..bdd8f43 --- /dev/null +++ b/weatherStation.pro @@ -0,0 +1,39 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + cairquality.cpp \ + ctinkerforge.cpp \ + main.cpp \ + cmainwindow.cpp \ + tinkerforge/brick_master.c \ + tinkerforge/bricklet_air_quality.c \ + tinkerforge/bricklet_outdoor_weather.c \ + tinkerforge/ip_connection.c + +HEADERS += \ + cairquality.h \ + cmainwindow.h \ + ctinkerforge.h \ + tinkerforge/brick_master.h \ + tinkerforge/bricklet_air_quality.h \ + tinkerforge/bricklet_outdoor_weather.h \ + tinkerforge/ip_connection.h + +FORMS += \ + cmainwindow.ui + +win32:LIBS += -lws2_32 -ladvapi32 +unix:QMAKE_CXXFLAGS += -pthread + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target