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