From 0f99b1634535f2e343decbe59427391ba7943938 Mon Sep 17 00:00:00 2001
From: Paolo Patruno
Date: Tue, 15 Jun 2021 17:48:01 +0200
Subject: [PATCH] added i2c-wind to platformio
---
.../stima_v3/i2c-wind/include/debug_config.h | 188 ++++
.../i2c-wind/include/i2c-wind-config.h | 290 ++++++
.../stima_v3/i2c-wind/include/i2c-wind.h | 537 ++++++++++
.../stima_v3/i2c-wind/include/i2c_config.h | 44 +
.../stima_v3/i2c-wind/include/json_config.h | 32 +
.../stima_v3/i2c-wind/include/mqtt_config.h | 156 +++
.../stima_v3/i2c-wind/include/sdcard_config.h | 32 +
.../i2c-wind/include/sensors_config.h | 337 +++++++
platformio/stima_v3/i2c-wind/platformio.ini | 35 +
platformio/stima_v3/i2c-wind/src/i2c-wind.ino | 932 ++++++++++++++++++
10 files changed, 2583 insertions(+)
create mode 100644 platformio/stima_v3/i2c-wind/include/debug_config.h
create mode 100644 platformio/stima_v3/i2c-wind/include/i2c-wind-config.h
create mode 100644 platformio/stima_v3/i2c-wind/include/i2c-wind.h
create mode 100644 platformio/stima_v3/i2c-wind/include/i2c_config.h
create mode 100644 platformio/stima_v3/i2c-wind/include/json_config.h
create mode 100644 platformio/stima_v3/i2c-wind/include/mqtt_config.h
create mode 100644 platformio/stima_v3/i2c-wind/include/sdcard_config.h
create mode 100644 platformio/stima_v3/i2c-wind/include/sensors_config.h
create mode 100644 platformio/stima_v3/i2c-wind/platformio.ini
create mode 100644 platformio/stima_v3/i2c-wind/src/i2c-wind.ino
diff --git a/platformio/stima_v3/i2c-wind/include/debug_config.h b/platformio/stima_v3/i2c-wind/include/debug_config.h
new file mode 100644
index 000000000..69760d9c8
--- /dev/null
+++ b/platformio/stima_v3/i2c-wind/include/debug_config.h
@@ -0,0 +1,188 @@
+/**@file debug_config.h */
+
+/*********************************************************************
+Copyright (C) 2017 Marco Baldinetti
+authors:
+Paolo Patruno
+Marco Baldinetti
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+**********************************************************************/
+
+#ifndef _DEBUG_CONFIG_H
+#define _DEBUG_CONFIG_H
+
+/*!
+\def SERIAL_TRACE_LEVEL_OFF
+\brief Debug level for disable debug on serial interface.
+*/
+#define SERIAL_TRACE_LEVEL_OFF (0)
+
+/*!
+\def SERIAL_TRACE_LEVEL_ERROR
+\brief Debug level for print error message on serial interface.
+*/
+#define SERIAL_TRACE_LEVEL_ERROR (1)
+
+/*!
+\def SERIAL_TRACE_LEVEL_WARNING
+\brief Debug level for print warning message on serial interface.
+*/
+#define SERIAL_TRACE_LEVEL_WARNING (2)
+
+/*!
+\def SERIAL_TRACE_LEVEL_INFO
+\brief Debug level for print informations message on serial interface.
+*/
+#define SERIAL_TRACE_LEVEL_INFO (3)
+
+/*!
+\def SERIAL_TRACE_LEVEL_DEBUG
+\brief Debug level for print verbose informations message on serial interface.
+*/
+#define SERIAL_TRACE_LEVEL_DEBUG (4)
+
+/*!
+\def SERIAL_TRACE_LEVEL_TRACE
+\brief Debug level for print detailed informations message on serial interface.
+*/
+#define SERIAL_TRACE_LEVEL_TRACE (5)
+
+/*!
+\def LCD_TRACE_LEVEL_OFF
+\brief Debug level for print error message on lcd interface.
+*/
+#define LCD_TRACE_LEVEL_OFF (0)
+
+/*!
+\def LCD_TRACE_LEVEL_ERROR
+\brief Debug level for print error message on lcd.
+*/
+#define LCD_TRACE_LEVEL_ERROR (1)
+
+/*!
+\def LCD_TRACE_LEVEL_WARNING
+\brief Debug level for print detailed informations message on serial interface.
+*/
+#define LCD_TRACE_LEVEL_WARNING (2)
+
+/*!
+\def LCD_TRACE_LEVEL_INFO
+\brief Debug level for print informations message on lcd.
+*/
+#define LCD_TRACE_LEVEL_INFO (3)
+
+/*!
+\def LCD_TRACE_LEVEL_DEBUG
+\brief Debug level for print verbose informations message on lcd.
+*/
+#define LCD_TRACE_LEVEL_DEBUG (4)
+
+/*!
+\def OK_STRING
+\brief "OK" string message.
+*/
+#define OK_STRING ("OK")
+
+/*!
+\def ERROR_STRING
+\brief "ERROR" string message.
+*/
+#define ERROR_STRING ("ERROR")
+
+/*!
+\def FAIL_STRING
+\brief "FAIL" string message.
+*/
+#define FAIL_STRING ("FAIL")
+
+/*!
+\def YES_STRING
+\brief "YES" string message.
+*/
+#define YES_STRING ("YES")
+
+/*!
+\def NO_STRING
+\brief "NO" string message.
+*/
+#define NO_STRING ("NO")
+
+/*!
+\def ON_STRING
+\brief "ON" string message.
+*/
+#define ON_STRING ("ON")
+
+/*!
+\def OFF_STRING
+\brief "OFF" string message.
+*/
+#define OFF_STRING ("OFF")
+
+/*!
+\def SAVE_STRING
+\brief "SAVE" string message.
+*/
+#define SAVE_STRING ("SAVE")
+
+/*!
+\def SENSOR_DRIVER_SERIAL_TRACE_LEVEL
+\brief Serial trace level debug for SensorDriver library.
+*/
+#define SENSOR_DRIVER_SERIAL_TRACE_LEVEL (SERIAL_TRACE_LEVEL_OFF)
+
+/*!
+\def SIM800_SERIAL_TRACE_LEVEL
+\brief Serial trace level debug for Sim800 library.
+*/
+#define SIM800_SERIAL_TRACE_LEVEL (SERIAL_TRACE_LEVEL_INFO)
+
+/*!
+\def OPC_SERIAL_TRACE_LEVEL
+\brief Serial trace level debug for Opcxx library.
+*/
+#define OPC_SERIAL_TRACE_LEVEL (SERIAL_TRACE_LEVEL_INFO)
+
+/*!
+\def I2C_TH_SERIAL_TRACE_LEVEL
+\brief Serial trace level debug for i2c-th sketch.
+*/
+#define I2C_TH_SERIAL_TRACE_LEVEL (SERIAL_TRACE_LEVEL_INFO)
+
+/*!
+\def I2C_RAIN_SERIAL_TRACE_LEVEL
+\brief Serial trace level debug for i2c-rain sketch.
+*/
+#define I2C_RAIN_SERIAL_TRACE_LEVEL (SERIAL_TRACE_LEVEL_INFO)
+
+/*!
+\def I2C_OPC_SERIAL_TRACE_LEVEL
+\brief Serial trace level debug for i2c-opc sketch.
+*/
+#define I2C_OPC_SERIAL_TRACE_LEVEL (SERIAL_TRACE_LEVEL_DEBUG)
+
+/*!
+\def STIMA_SERIAL_TRACE_LEVEL
+\brief Serial trace level debug for stima sketch.
+*/
+#define STIMA_SERIAL_TRACE_LEVEL (SERIAL_TRACE_LEVEL_INFO)
+
+/*!
+\def STIMA_LCD_TRACE_LEVEL
+\brief Lcd trace level debug for stima sketch.
+*/
+#define STIMA_LCD_TRACE_LEVEL (LCD_TRACE_LEVEL_INFO)
+
+#endif
diff --git a/platformio/stima_v3/i2c-wind/include/i2c-wind-config.h b/platformio/stima_v3/i2c-wind/include/i2c-wind-config.h
new file mode 100644
index 000000000..0b964a46a
--- /dev/null
+++ b/platformio/stima_v3/i2c-wind/include/i2c-wind-config.h
@@ -0,0 +1,290 @@
+/**@file i2c-wind-config.h */
+
+/*********************************************************************
+Copyright (C) 2017 Marco Baldinetti
+authors:
+Paolo patruno
+Marco Baldinetti
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+**********************************************************************/
+
+#ifndef _I2C_WIND_CONFIG_H
+#define _I2C_WIND_CONFIG_H
+
+#include
+
+/*********************************************************************
+* MODULE
+*********************************************************************/
+/*!
+\def MODULE_VERSION
+\brief Module version.
+*/
+#define MODULE_VERSION (3)
+
+/*!
+\def MODULE_TYPE
+\brief Type of module. It is defined in registers.h.
+*/
+#define MODULE_TYPE (STIMA_MODULE_TYPE_WIND)
+
+/*********************************************************************
+* CONFIGURATION
+*********************************************************************/
+/*!
+\def CONFIGURATION_DEFAULT_IS_ONESHOT
+\brief Oneshot mode for default.
+*/
+#define CONFIGURATION_DEFAULT_IS_ONESHOT (false)
+
+/*!
+\def CONFIGURATION_DEFAULT_IS_CONTINUOUS
+\brief Continuous mode for default.
+*/
+#define CONFIGURATION_DEFAULT_IS_CONTINUOUS (true)
+
+/*!
+\def CONFIGURATION_DEFAULT_I2C_ADDRESS
+\brief Default i2c address.
+*/
+#define CONFIGURATION_DEFAULT_I2C_ADDRESS (I2C_WIND_DEFAULT_ADDRESS)
+
+/*!
+\def CONFIGURATION_RESET_PIN
+\brief Input pin for reset configuration at startup.
+*/
+#define CONFIGURATION_RESET_PIN (8)
+
+#if (USE_SENSOR_GWS)
+#define WIND_POWER_PIN (4)
+
+#define WIND_DIRECTION_MAX (360.0)
+#define WIND_DIRECTION_MIN (0.0)
+
+#define WIND_SPEED_MAX (60.0)
+#define WIND_SPEED_MIN (0.0)
+
+#define GWS_SERIAL_BAUD (9600)
+#define GWS_SERIAL_TIMEOUT_MS (8)
+#define GWS_ACQUISITION_COUNT_FOR_POWER_RESET (100)
+
+#define GWS_STX_INDEX (0)
+#define GWS_ETX_INDEX (19)
+
+#define GWS_DIRECTION_INDEX (3)
+#define GWS_DIRECTION_LENGTH (3)
+#define GWS_SPEED_INDEX (7)
+#define GWS_SPEED_LENGTH (6)
+#define GWS_CRC_INDEX (20)
+#define GWS_CRC_LENGTH (2)
+#define STX_VALUE (2)
+#define ETX_VALUE (3)
+#define CR_VALUE (13)
+#define LF_VALUE (10)
+
+#define UART_RX_BUFFER_LENGTH (40)
+#endif
+
+/*********************************************************************
+* POWER DOWN
+*********************************************************************/
+/*!
+\def USE_POWER_DOWN
+\brief Enable or disable power down.
+*/
+#define USE_POWER_DOWN (true)
+
+/*!
+\def DEBOUNCING_POWER_DOWN_TIME_MS
+\brief Debounce power down ms.
+*/
+#define DEBOUNCING_POWER_DOWN_TIME_MS (10)
+
+/*!
+\def USE_TIMER_1
+\brief Enable or disable timer1.
+*/
+#define USE_TIMER_1 (true)
+
+/*********************************************************************
+* WATCHDOG
+*********************************************************************/
+/*!
+\def WDT_TIMER
+\brief Watchdog timer for periodically check microprocessor block states.
+
+Possible value for WDT_TIMER are:
+WDTO_15MS, WDTO_30MS, WDTO_60MS, WDTO_120MS, WDTO_250MS, WDTO_500MS,
+WDTO_1S, WDTO_2S, WDTO_4S, WDTO_8S
+*/
+#define WDT_TIMER (WDTO_8S)
+
+/*********************************************************************
+* WIND SENSORS
+*********************************************************************/
+// observations with processing every 1-10 minutes (minutes for processing sampling)
+// report every 5-60 minutes (> OBSERVATIONS_MINUTES)
+#define OBSERVATIONS_MINUTES 1
+#define SENSORS_SAMPLE_TIME_MS 5000
+
+/*!
+\def OBSERVATION_SAMPLES_COUNT_MIN
+\brief Sample count minimum in OBSERVATIONS_MINUTES minutes.
+*/
+#define OBSERVATION_SAMPLES_COUNT_MIN ((uint8_t)(OBSERVATIONS_MINUTES * 60 / ((uint8_t)(SENSORS_SAMPLE_TIME_MS / 1000))))
+
+#if ((OBSERVATIONS_MINUTES * 60) % (SENSORS_SAMPLE_TIME_MS / 1000) == 0)
+/*!
+\def OBSERVATION_SAMPLES_COUNT_MAX
+\brief Sample count maximum in OBSERVATIONS_MINUTES minutes.
+*/
+#define OBSERVATION_SAMPLES_COUNT_MAX (OBSERVATION_SAMPLES_COUNT_MIN)
+#else
+/*!
+\def OBSERVATION_SAMPLES_COUNT_MAX
+\brief Sample count maximum in OBSERVATIONS_MINUTES minutes.
+*/
+#define OBSERVATION_SAMPLES_COUNT_MAX (OBSERVATION_SAMPLES_COUNT_MIN + 1)
+#endif
+
+#define RMAP_REPORT_SAMPLE_VALID (true)
+
+#define RMAP_REPORT_SAMPLES_COUNT (STATISTICAL_DATA_COUNT * OBSERVATIONS_MINUTES * OBSERVATION_SAMPLES_COUNT_MAX)
+#define WMO_REPORT_SAMPLES_COUNT (10 * OBSERVATION_SAMPLES_COUNT_MAX)
+
+/*!
+\def OBSERVATION_SAMPLE_ERROR_MAX
+\brief Maximum invalid sample count for generate a valid observations.
+*/
+#define OBSERVATION_SAMPLE_ERROR_MAX ((uint16_t)(round(OBSERVATION_SAMPLES_COUNT_MAX / 2)))
+#define OBSERVATION_SAMPLE_VALID_MIN ((uint16_t)(OBSERVATION_SAMPLES_COUNT_MAX - OBSERVATION_SAMPLE_ERROR_MAX))
+
+#define RMAP_REPORT_SAMPLE_ERROR_MAX ((uint16_t)(STATISTICAL_DATA_COUNT * OBSERVATION_SAMPLE_ERROR_MAX))
+#define WMO_REPORT_SAMPLE_ERROR_MAX ((uint16_t)(10 * OBSERVATION_SAMPLE_ERROR_MAX))
+
+#if (RMAP_REPORT_SAMPLE_VALID)
+#define RMAP_REPORT_SAMPLE_VALID_MIN (OBSERVATION_SAMPLE_VALID_MIN)
+#define WMO_REPORT_SAMPLE_VALID_MIN (OBSERVATION_SAMPLE_VALID_MIN)
+#else
+#define RMAP_REPORT_SAMPLE_VALID_MIN ((uint16_t)(STATISTICAL_DATA_COUNT * OBSERVATION_SAMPLE_VALID_MIN))
+#define WMO_REPORT_SAMPLE_VALID_MIN ((uint16_t)(10 * OBSERVATION_SAMPLE_VALID_MIN))
+#endif
+
+#define RMAP_REPORT_ERROR_MAX ((uint16_t)(STATISTICAL_DATA_COUNT - 1))
+#define RMAP_REPORT_VALID_MIN ((uint16_t)(STATISTICAL_DATA_COUNT - RMAP_REPORT_ERROR_MAX))
+
+#define SAMPLES_COUNT ((60000 / SENSORS_SAMPLE_TIME_MS * STATISTICAL_DATA_COUNT) + 10)
+
+#define WIND_CLASS_1_MAX (1.0)
+#define WIND_CLASS_2_MAX (2.0)
+#define WIND_CLASS_3_MAX (4.0)
+#define WIND_CLASS_4_MAX (7.0)
+#define WIND_CLASS_5_MAX (10.0)
+
+#if (USE_SENSOR_GWS)
+#define CALM_WIND_MAX_MS (0.1)
+#endif
+
+/*!
+\def USE_SENSORS_COUNT
+\brief Sensors count.
+*/
+/*********************************************************************
+* SENSORS
+*********************************************************************/
+/*!
+\def USE_SENSORS_COUNT
+\brief Sensors count.
+*/
+#define USE_SENSORS_COUNT (USE_SENSOR_GWS)
+
+#if (USE_SENSORS_COUNT == 0)
+#error No sensor used. Are you sure? If not, enable it in RmapConfig/sensors_config.h
+#endif
+
+/*********************************************************************
+* TIMER1
+*********************************************************************/
+/*!
+\def TIMER1_INTERRUPT_TIME_MS
+\brief Value in milliseconds for generating timer1 interrupt: 100 - 8000 [ms].
+*/
+#if (USE_SENSOR_GWS)
+#define TIMER1_INTERRUPT_TIME_MS (SENSORS_SAMPLE_TIME_MS)
+#endif
+
+/*!
+\def TIMER1_OVERFLOW_TIME_MS
+\brief Timer1 timer overflow with 1024 prescaler at 8 or 16 MHz.
+*/
+#if (F_CPU == 8000000L)
+#define TIMER1_OVERFLOW_TIME_MS (8388)
+#elif (F_CPU == 16000000L)
+#define TIMER1_OVERFLOW_TIME_MS (4194)
+#endif
+
+/*!
+\def TIMER1_TCNT1_VALUE
+\brief Timer1 timer overflow with 1024 prescaler at 16 MHz.
+*/
+#define TIMER1_TCNT1_VALUE ((uint16_t)(0xFFFF - (float)(1.0 * 0xFFFF * TIMER1_INTERRUPT_TIME_MS / TIMER1_OVERFLOW_TIME_MS)))
+
+/*!
+\def TIMER_COUNTER_VALUE_MAX_MS
+\brief Maximum timer1 counter value for timed tasks.
+*/
+#define TIMER_COUNTER_VALUE_MAX_MS (SENSORS_SAMPLE_TIME_MS)
+#define TIMER_COUNTER_VALUE_MAX_S (60)
+
+/*********************************************************************
+* TASKS
+*********************************************************************/
+/*!
+\def WIND_SETUP_DELAY_MS
+\brief Reading delay.
+*/
+#define WIND_SETUP_DELAY_MS (100)
+
+/*!
+\def WIND_POWER_STARTUP_DELAY_MS
+\brief power on delay.
+*/
+#define WIND_POWER_ON_DELAY_MS (5000)
+
+/*!
+\def WIND_READ_DELAY_MS
+\brief Reading delay.
+*/
+#define WIND_READ_DELAY_MS (2)
+
+/*!
+\def WIND_READ_DELAY_MS
+\brief Reading delay.
+*/
+#define WIND_RETRY_DELAY_MS (2)
+
+/*!
+\def WIND_READ_COUNT
+\brief number of read.
+*/
+#define WIND_READ_COUNT (10)
+
+/*!
+\def WIND_READ_COUNT
+\brief number of read.
+*/
+#define WIND_RETRY_MAX (600)
+
+#endif
diff --git a/platformio/stima_v3/i2c-wind/include/i2c-wind.h b/platformio/stima_v3/i2c-wind/include/i2c-wind.h
new file mode 100644
index 000000000..fa950bc0d
--- /dev/null
+++ b/platformio/stima_v3/i2c-wind/include/i2c-wind.h
@@ -0,0 +1,537 @@
+/**@file i2c-wind.h */
+
+/*********************************************************************
+Copyright (C) 2017 Marco Baldinetti
+authors:
+Paolo patruno
+Marco Baldinetti
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+**********************************************************************/
+
+#ifndef _I2C_WIND_H
+#define _I2C_WIND_H
+
+#include "i2c-wind-config.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#if (USE_JSON)
+#include
+#endif
+#include
+#include
+#include
+#include
+#include
+
+/*********************************************************************
+* TYPEDEF
+*********************************************************************/
+/*!
+\struct configuration_t
+\brief EEPROM saved configuration.
+*/
+typedef struct {
+ uint8_t module_version; //!< module version
+ uint8_t module_type; //!< module type
+ uint8_t i2c_address; //!< i2c address
+ bool is_oneshot; //!< enable or disable oneshot mode
+ bool is_continuous; //!< enable or disable continuous mode
+ float adc_voltage_offset_1;
+ float adc_voltage_offset_2;
+ float adc_voltage_min;
+ float adc_voltage_max;
+} configuration_t;
+
+/*!
+\struct sample_t
+\brief samples data
+*/
+typedef struct {
+ float value[SAMPLES_COUNT]; //!< samples buffer
+ uint16_t count; //!< samples counter
+ float *read_ptr; //!< reader pointer
+ float *write_ptr; //!< writer pointer
+} sample_t;
+
+/*!
+\struct report_t
+\brief report data.
+*/
+typedef struct {
+ // DWA
+ float vavg10_speed; // B11002 254,0,0
+ float vavg10_direction; // B11001 254,0,0
+
+ // DWB
+ float vavg_speed; // B11002 200,0,900
+ float vavg_direction; // B11001 200,0,900
+
+ // DWC
+ float peak_gust_speed; // B11041 2,0,900
+ float long_gust_speed; // B11209 2,0,900
+
+ // DWD
+ float avg_speed; // B11002 0,0,900
+
+ // DWE
+ float class_1; // B11211 9,0,900
+ float class_2; // B11212 9,0,900
+ float class_3; // B11213 9,0,900
+ float class_4; // B11214 9,0,900
+ float class_5; // B11215 9,0,900
+ float class_6; // B11216 9,0,900
+ // dtable={"51":["B11211","B11212","B11213","B11214","B11215","B11216"]}
+
+ // DWF
+ float peak_gust_direction; // B11043 205,0,900
+ float long_gust_direction; // B11210 205,0,900
+
+} report_t;
+
+/*!
+\struct readable_data_t
+\brief Readable data through i2c bus.
+*/
+typedef struct {
+ uint8_t module_type; //!< module version
+ uint8_t module_version; //!< module type
+ report_t wind;
+} readable_data_t;
+
+/*!
+\struct writable_data_t
+\brief Writable data through i2c bus.
+*/
+typedef struct {
+ uint8_t i2c_address; //!< i2c address
+ bool is_oneshot; //!< enable or disable oneshot mode
+ bool is_continuous; //!< enable or disable continuous mode
+} writable_data_t;
+
+/*********************************************************************
+* TYPEDEF for Finite State Machine
+*********************************************************************/
+/*!
+\enum state_t
+\brief Main loop finite state machine.
+*/
+typedef enum {
+ INIT, //!< init tasks and sensors
+ #if (USE_POWER_DOWN)
+ ENTER_POWER_DOWN, //!< if no task is running, activate power down
+ #endif
+ TASKS_EXECUTION, //!< execute active tasks
+ END //!< go to ENTER_POWER_DOWN or TASKS_EXECUTION
+} state_t;
+
+/*!
+\enum wind_state_t
+\brief WIND setup and reading task finite state machine.
+*/
+typedef enum {
+ WIND_INIT,
+ WIND_READING,
+ WIND_ELABORATE,
+ WIND_END, //!< performs end operations and deactivate task
+ WIND_WAIT_STATE //!< non-blocking waiting time
+} wind_state_t;
+
+/*********************************************************************
+* GLOBAL VARIABLE
+*********************************************************************/
+/*!
+\var configuration
+\brief Configuration data.
+*/
+configuration_t configuration;
+
+/*!
+\var readable_data_1
+\brief First readable i2c register.
+*/
+volatile readable_data_t readable_data_1;
+
+/*!
+\var readable_data_2
+\brief Second readable i2c register.
+*/
+volatile readable_data_t readable_data_2;
+
+/*!
+\var readable_data_read_ptr
+\brief Pointer for read data in i2c readable register.
+*/
+volatile readable_data_t *readable_data_read_ptr;
+
+/*!
+\var readable_data_write_ptr
+\brief Pointer for write data in i2c readable register.
+*/
+volatile readable_data_t *readable_data_write_ptr;
+
+/*!
+\var readable_data_temp_ptr
+\brief Temporary pointer for exchange read and write pointer for i2c readable register.
+*/
+volatile readable_data_t *readable_data_temp_ptr;
+
+/*!
+\var writable_data
+\brief Writable i2c register.
+*/
+writable_data_t writable_data;
+
+/*!
+\var writable_data_ptr
+\brief Pointer for read and write data in i2c writable register.
+*/
+writable_data_t *writable_data_ptr;
+
+/*!
+\var readable_data_address
+\brief Address of readable i2c register.
+*/
+volatile uint8_t readable_data_address;
+
+/*!
+\var readable_data_length
+\brief Number of bytes to read at readable_data_address.
+*/
+volatile uint8_t readable_data_length;
+
+/*!
+\var i2c_rx_data
+\brief Buffer for i2c received data.
+*/
+volatile uint8_t i2c_rx_data[I2C_MAX_DATA_LENGTH];
+
+/*!
+\var i2c_error
+\brief Number of i2c error.
+*/
+volatile uint8_t i2c_error;
+
+/*!
+\var ready_tasks_count
+\brief Number of tasks ready to execute.
+*/
+volatile uint8_t ready_tasks_count;
+
+/*!
+\var awakened_event_occurred_time_ms
+\brief System time (in millisecond) when the system has awakened from power down.
+*/
+uint32_t awakened_event_occurred_time_ms;
+
+/*!
+\var is_start
+\brief Execute start command.
+*/
+bool is_start;
+
+/*!
+\var is_stop
+\brief Execute stop command.
+*/
+bool is_stop;
+
+/*!
+\var is_oneshot
+\brief Received command is in oneshot mode.
+*/
+bool is_oneshot;
+
+/*!
+\var is_continuous
+\brief Received command is in continuous mode.
+*/
+bool is_continuous;
+
+/*!
+\var is_test
+\brief Received command is in test mode.
+*/
+bool is_test;
+
+#if (USE_SENSOR_GWS)
+sample_t wind_speed_samples;
+sample_t wind_direction_samples;
+#endif
+
+/*!
+\var samples_count
+\brief Number of samples to be acquired for make one observation.
+*/
+// uint8_t samples_count;
+
+/*!
+\var timer_counter_ms
+\brief Timer counter variable for execute timed task with time multiple of base Timer1 time.
+*/
+volatile uint16_t timer_counter_ms;
+volatile uint16_t timer_counter_s;
+
+#if (USE_SENSOR_GWS)
+volatile bool is_wind_on;
+uint8_t wind_acquisition_count;
+#endif
+
+/*!
+\var state
+\brief Current main loop state.
+*/
+state_t state;
+
+/*!
+\var wind_state
+\brief Current sensors reading task state.
+*/
+wind_state_t wind_state;
+
+/*********************************************************************
+* FUNCTIONS
+*********************************************************************/
+/*!
+\fn void init_power_down(uint32_t *time_ms, uint32_t debouncing_ms)
+\brief Enter power down mode.
+\param time_ms pointer to a variable to save the last instant you entered power down.
+\param debouncing_ms delay to power down.
+\return void.
+*/
+void init_power_down(uint32_t *time_ms, uint32_t debouncing_ms);
+
+/*!
+\fn void init_wdt(uint8_t wdt_timer)
+\brief Init watchdog.
+\param wdt_timer a time value for init watchdog (WDTO_xxxx).
+\return void.
+*/
+void init_wdt(uint8_t wdt_timer);
+
+/*!
+\fn void init_system(void)
+\brief Init system.
+\return void.
+*/
+void init_system(void);
+
+/*!
+\fn void init_buffers(void)
+\brief Init buffers.
+\return void.
+*/
+void init_buffers(void);
+
+/*!
+\fn void init_tasks(void)
+\brief Init tasks variable and state.
+\return void.
+*/
+void init_tasks(void);
+
+/*!
+\fn void init_pins(void)
+\brief Init hardware pins.
+\return void.
+*/
+void init_pins(void);
+
+/*!
+\fn void init_wire(void)
+\brief Init wire (i2c) library and performs checks on the bus.
+\return void.
+*/
+void init_wire(void);
+
+/*!
+\fn void init_spi(void)
+\brief Init SPI library.
+\return void.
+*/
+void init_spi(void);
+
+/*!
+\fn void init_rtc(void)
+\brief Init RTC module.
+\return void.
+*/
+void init_rtc(void);
+
+#if (USE_TIMER_1)
+/*!
+\fn void init_timer1(void)
+\brief Init Timer1 module.
+\return void.
+*/
+void init_timer1(void);
+
+/*!
+\fn void start_timer(void)
+\brief Start Timer1 module.
+\return void.
+*/
+void start_timer(void);
+
+/*!
+\fn void stop_timer(void)
+\brief Stop Timer1 module.
+\return void.
+*/
+void stop_timer(void);
+#endif
+
+/*!
+\fn void init_sensors(void)
+\brief Create and setup sensors.
+\return void.
+*/
+void init_sensors(void);
+
+/*!
+\fn void print_configuration(void)
+\brief Print current configuration.
+\return void.
+*/
+void print_configuration(void);
+
+/*!
+\fn void load_configuration(void)
+\brief Load configuration from EEPROM.
+\return void.
+*/
+void load_configuration(void);
+
+/*!
+\fn void save_configuration(bool is_default)
+\brief Save configuration to EEPROM.
+\param is_default: if true save default configuration; if false save current configuration.
+\return void.
+*/
+void save_configuration(bool);
+
+/*!
+\fn void commands(void)
+\brief Performs specific operations based on the received command.
+\return void.
+*/
+void commands(void);
+
+/*!
+\fn void tests(void)
+\brief Performs specific operations based on the received command.
+\return void.
+*/
+void tests(void);
+
+/*!
+\fn void reset_samples_buffer(void)
+\brief Reset samples buffers to default value.
+\return void.
+*/
+void reset_samples_buffer(void);
+
+/*!
+\fn void reset_observations_buffer(void)
+\brief Reset observations buffers to default value.
+\return void.
+*/
+// void reset_observations_buffer(void);
+
+void reset_report_buffer(void);
+
+/*!
+\fn void exchange_buffers(void)
+\brief Exchange reader and writer pointer to buffer.
+\return void.
+*/
+void exchange_buffers(void);
+
+template value_v bufferRead(buffer_g *buffer, length_v length);
+template value_v bufferReadBack(buffer_g *buffer, length_v length);
+template void bufferWrite(buffer_g *buffer, value_v value);
+template void bufferPtrReset(buffer_g *buffer);
+template void bufferPtrResetBack(buffer_g *buffer, length_v length);
+template void incrementBuffer(buffer_g *buffer, length_v length);
+template void bufferReset(buffer_g *buffer, length_v length);
+template void addValue(buffer_g *buffer, length_v length, value_v value);
+
+/*!
+\fn void samples_processing()
+\brief Main routine for processing the samples to calculate an observation.
+\return void.
+*/
+void samples_processing();
+void make_report();
+void getSDFromUV (float, float, float *, float *);
+
+bool windsonic_interpreter (float *speed, float *direction);
+
+uint16_t uart_rx_buffer_length;
+uint8_t uart_rx_buffer[UART_RX_BUFFER_LENGTH];
+
+/*********************************************************************
+* TASKS
+*********************************************************************/
+/*!
+\var is_event_wind_task
+\brief Enable or disable the WIND task.
+*/
+volatile bool is_event_wind_task;
+
+/*!
+\fn void wind_task(void)
+\brief Wind setup and reading Task.
+Read data from WIND.
+\return void.
+*/
+void wind_task(void);
+
+/*!
+\var is_event_command_task
+\brief Enable or disable the Command task.
+*/
+volatile bool is_event_command_task;
+
+/*!
+\fn void command_task(void)
+\brief Command Task.
+Execute the command received on i2c bus by reading i2c received data buffer.
+\return void.
+*/
+void command_task(void);
+
+/*********************************************************************
+* INTERRUPTS HANDLER
+*********************************************************************/
+/*!
+\fn void i2c_request_interrupt_handler(void)
+\brief I2C request interrupt handler.
+\return void.
+*/
+void i2c_request_interrupt_handler(void);
+
+/*!
+\fn void i2c_receive_interrupt_handler(void)
+\brief I2C receive interrupt handler.
+\return void.
+*/
+void i2c_receive_interrupt_handler(void);
+
+#endif
diff --git a/platformio/stima_v3/i2c-wind/include/i2c_config.h b/platformio/stima_v3/i2c-wind/include/i2c_config.h
new file mode 100644
index 000000000..83e67e607
--- /dev/null
+++ b/platformio/stima_v3/i2c-wind/include/i2c_config.h
@@ -0,0 +1,44 @@
+/**@file i2c_config.h */
+
+/*********************************************************************
+Copyright (C) 2017 Marco Baldinetti
+authors:
+Paolo Patruno
+Marco Baldinetti
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+**********************************************************************/
+
+#ifndef _HARDWARE_CONFIG_H
+#define _HARDWARE_CONFIG_H
+
+/*!
+\def I2C_BUS_CLOCK
+\brief I2C bus clock in Hertz.
+*/
+#define I2C_BUS_CLOCK (50000L)
+
+/*!
+\def I2C_MAX_DATA_LENGTH
+\brief Max length in bytes for i2c bus data buffer.
+*/
+#define I2C_MAX_DATA_LENGTH (32)
+
+/*!
+\def I2C_MAX_ERROR_COUNT
+\brief Max i2c error for bus restart.
+*/
+#define I2C_MAX_ERROR_COUNT (5)
+
+#endif
diff --git a/platformio/stima_v3/i2c-wind/include/json_config.h b/platformio/stima_v3/i2c-wind/include/json_config.h
new file mode 100644
index 000000000..50dbbd401
--- /dev/null
+++ b/platformio/stima_v3/i2c-wind/include/json_config.h
@@ -0,0 +1,32 @@
+/**@file json_config.h */
+
+/*********************************************************************
+Copyright (C) 2017 Marco Baldinetti
+authors:
+Paolo Patruno
+Marco Baldinetti
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+**********************************************************************/
+
+#ifndef _JSON_CONFIG_H
+#define _JSON_CONFIG_H
+
+/*!
+\def JSON_BUFFER_LENGTH
+\brief Length in bytes for JSON data buffer.
+*/
+#define JSON_BUFFER_LENGTH (140)
+
+#endif
diff --git a/platformio/stima_v3/i2c-wind/include/mqtt_config.h b/platformio/stima_v3/i2c-wind/include/mqtt_config.h
new file mode 100644
index 000000000..690d32113
--- /dev/null
+++ b/platformio/stima_v3/i2c-wind/include/mqtt_config.h
@@ -0,0 +1,156 @@
+/**@file mqtt_config.h */
+
+/*********************************************************************
+Copyright (C) 2017 Marco Baldinetti
+authors:
+Paolo Patruno
+Marco Baldinetti
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+**********************************************************************/
+
+#ifndef _MQTT_CONFIG_H
+#define _MQTT_CONFIG_H
+
+/*!
+\def MQTT_ROOT_TOPIC_LENGTH
+\brief Length in bytes for mqtt root topic.
+*/
+#define MQTT_ROOT_TOPIC_LENGTH (50)
+
+/*!
+\def MQTT_MAINT_TOPIC_LENGTH
+\brief Length in bytes for mqtt maint topic.
+*/
+#define MQTT_MAINT_TOPIC_LENGTH (MQTT_ROOT_TOPIC_LENGTH)
+
+/*!
+\def MQTT_SUBSCRIBE_TOPIC_LENGTH
+\brief Length in bytes for mqtt subscibe topic.
+*/
+#define MQTT_SUBSCRIBE_TOPIC_LENGTH (50)
+
+/*!
+\def MQTT_SENSOR_TOPIC_LENGTH
+\brief Length in bytes for mqtt sensor topic.
+*/
+#define MQTT_SENSOR_TOPIC_LENGTH (30)
+
+/*!
+\def MQTT_CLIENT_ID_LENGTH
+\brief Length in bytes for mqtt client id.
+*/
+#define MQTT_CLIENT_ID_LENGTH (MQTT_ROOT_TOPIC_LENGTH)
+
+/*!
+\def MQTT_MESSAGE_LENGTH
+\brief Length in bytes for mqtt message.
+*/
+#define MQTT_MESSAGE_LENGTH (200)
+
+/*!
+\def MQTT_SERVER_LENGTH
+\brief Length in bytes for mqtt server.
+*/
+#define MQTT_SERVER_LENGTH (30)
+
+/*!
+\def MQTT_USERNAME_LENGTH
+\brief Length in bytes for mqtt username.
+*/
+#define MQTT_USERNAME_LENGTH (30)
+
+/*!
+\def MQTT_PASSWORD_LENGTH
+\brief Length in bytes for mqtt password.
+*/
+#define MQTT_PASSWORD_LENGTH (30)
+
+/*!
+\def MQTT_TIMEOUT_MS
+\brief Timeout in milliseconds for mqtt stack.
+*/
+#define MQTT_TIMEOUT_MS (6000)
+
+/*!
+\def MQTT_DEFAULT_SERVER
+\brief Default MQTT server.
+*/
+#define MQTT_DEFAULT_SERVER ("rmap.cc")
+
+/*!
+\def MQTT_DEFAULT_PORT
+\brief Default MQTT server port.
+*/
+#define MQTT_DEFAULT_PORT (1883)
+
+/*!
+\def MQTT_DEFAULT_ROOT_TOPIC
+\brief Default MQTT root topic.
+*/
+#define MQTT_DEFAULT_ROOT_TOPIC ("")
+
+/*!
+\def MQTT_DEFAULT_MAINT_TOPIC
+\brief Default MQTT maint topic.
+*/
+#define MQTT_DEFAULT_MAINT_TOPIC ("")
+
+/*!
+\def MQTT_DEFAULT_SUBSCRIBE_TOPIC
+\brief Default MQTT subscibe topic.
+*/
+#define MQTT_DEFAULT_SUBSCRIBE_TOPIC ("")
+
+/*!
+\def MQTT_DEFAULT_USERNAME
+\brief Default MQTT username.
+*/
+#define MQTT_DEFAULT_USERNAME ("")
+
+/*!
+\def MQTT_DEFAULT_PASSWORD
+\brief Default MQTT password.
+*/
+#define MQTT_DEFAULT_PASSWORD ("")
+
+/*!
+\def MQTT_STATUS_TOPIC
+\brief Default MQTT status topic for printing on connect/disconnect message.
+*/
+#define MQTT_STATUS_TOPIC ("254,0,0/265,0,-,-/B01213")
+
+/*!
+\def MQTT_ON_CONNECT_MESSAGE
+\brief MQTT on connect message.
+*/
+#define MQTT_ON_CONNECT_MESSAGE ("{\"v\":\"conn\"}")
+
+/*!
+\def MQTT_ON_DISCONNECT_MESSAGE
+\brief MQTT on disconnect message.
+*/
+#define MQTT_ON_DISCONNECT_MESSAGE ("{\"v\":\"disconn\"}")
+
+/*!
+\def MQTT_ON_ERROR_MESSAGE
+\brief MQTT on error message.
+*/
+#define MQTT_ON_ERROR_MESSAGE ("{\"v\":\"error01\"}")
+
+#if (MQTT_ROOT_TOPIC_LENGTH + MQTT_SENSOR_TOPIC_LENGTH > 100)
+#error MQTT root/sensor topic is too big!
+#endif
+
+#endif
diff --git a/platformio/stima_v3/i2c-wind/include/sdcard_config.h b/platformio/stima_v3/i2c-wind/include/sdcard_config.h
new file mode 100644
index 000000000..9243f4b11
--- /dev/null
+++ b/platformio/stima_v3/i2c-wind/include/sdcard_config.h
@@ -0,0 +1,32 @@
+/**@file sdcard_config.h */
+
+/*********************************************************************
+Copyright (C) 2017 Marco Baldinetti
+authors:
+Paolo Patruno
+Marco Baldinetti
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+**********************************************************************/
+
+#ifndef _SDCARD_CONFIG_H
+#define _SDCARD_CONFIG_H
+
+/*!
+\def SDCARD_FILES_NAME_MAX_LENGTH
+\brief Length in bytes for sdcard file name data buffer.
+*/
+#define SDCARD_FILES_NAME_MAX_LENGTH (20)
+
+#endif
diff --git a/platformio/stima_v3/i2c-wind/include/sensors_config.h b/platformio/stima_v3/i2c-wind/include/sensors_config.h
new file mode 100644
index 000000000..e1bfec947
--- /dev/null
+++ b/platformio/stima_v3/i2c-wind/include/sensors_config.h
@@ -0,0 +1,337 @@
+/**@file sensors_config.h */
+
+/*********************************************************************
+Copyright (C) 2017 Marco Baldinetti
+authors:
+Paolo Patruno
+Marco Baldinetti
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+**********************************************************************/
+
+#ifndef SENSOR_CONFIG_H
+#define SENSOR_CONFIG_H
+
+/*!
+\def USE_JSON
+\brief Enable if you want use json library for json response (getJson function in SensorDriver).
+*/
+#define USE_JSON (true)
+
+/*!
+\def USE_SENSOR_ADT
+\brief Enable if you want use ADT7420 sensor.
+*/
+#define USE_SENSOR_ADT (false)
+
+/*!
+\def USE_SENSOR_HIH
+\brief Enable if you want use HIH6100 sensor.
+*/
+#define USE_SENSOR_HIH (false)
+
+/*!
+\def USE_SENSOR_HYT
+\brief Enable if you want use HYT271 or HYT221 sensor.
+*/
+#define USE_SENSOR_HYT (false)
+
+/*!
+\def USE_SENSOR_DEP
+\brief Enable if you want use DigitEco Power sensor.
+*/
+#define USE_SENSOR_DEP (false)
+
+/*!
+\def USE_SENSOR_DES
+\brief Enable if you want use DigitEco Wind Speed sensor.
+*/
+#define USE_SENSOR_DES (false)
+
+/*!
+\def USE_SENSOR_DED
+\brief Enable if you want use DigitEco Wind Direction sensor.
+*/
+#define USE_SENSOR_DED (false)
+
+/*!
+\def USE_SENSOR_DSR
+\brief Enable if you want use DigitEco Global Solar Radiation sensor.
+*/
+#define USE_SENSOR_DSR (false)
+
+/*!
+\def USE_SENSOR_VSR
+\brief Enable if you want use 0-5V High Resolution Global Solar Radiation sensor.
+*/
+#define USE_SENSOR_VSR (false)
+
+/*!
+\def USE_SENSOR_DSA
+\brief Enable if you want average Global Solar Radiation sensor.
+*/
+#define USE_SENSOR_DSA (false)
+
+/*!
+\def USE_SENSOR_DWA
+\brief Enable if you want vectorial average Wind Speed and Direction over 10'.
+*/
+#define USE_SENSOR_DWA (false)
+
+/*!
+\def USE_SENSOR_DWB
+\brief Enable if you want vectorial average Wind Speed and Direction over report time.
+*/
+#define USE_SENSOR_DWB (false)
+
+/*!
+\def USE_SENSOR_DWC
+\brief Enable if you want gust Wind Speed and Direction over report time.
+*/
+#define USE_SENSOR_DWC (false)
+
+/*!
+\def USE_SENSOR_DWD
+\brief Enable if you want average Wind Speed over report time.
+*/
+#define USE_SENSOR_DWD (false)
+
+/*!
+\def USE_SENSOR_DWE
+\brief Enable if you want class Wind Speed over report time.
+*/
+#define USE_SENSOR_DWE (false)
+
+/*!
+\def USE_SENSOR_OA2
+\brief Enable if you want use OPC PM1, PM2.5, PM10 continuous average value.
+*/
+#define USE_SENSOR_OA2 (false)
+#define USE_SENSOR_OA3 (false)
+
+/*!
+\def USE_SENSOR_OB2
+\brief Enable if you want use OPC PM1, PM2.5, PM10 continuous standard deviation value.
+*/
+#define USE_SENSOR_OB2 (false)
+#define USE_SENSOR_OB3 (false)
+
+/*!
+\def USE_SENSOR_OC2
+\brief Enable if you want use OPC BINS continuous average value.
+*/
+#define USE_SENSOR_OC2 (false)
+#define USE_SENSOR_OC3 (false)
+
+/*!
+\def USE_SENSOR_OD2
+\brief Enable if you want use OPC BINS continuous standard deviation value.
+*/
+#define USE_SENSOR_OD2 (false)
+#define USE_SENSOR_OD3 (false)
+
+/*!
+\def USE_SENSOR_OD2
+\brief Enable if you want use OPC BINS continuous standard deviation value.
+*/
+#define USE_SENSOR_OE3 (false)
+
+/*!
+\def USE_SENSOR_LWT
+\brief Enable if you want use leaf wetness time continuous value.
+*/
+#define USE_SENSOR_LWT (false)
+
+/*!
+\def USE_SENSOR_HI7
+\brief Enable if you want use SI7021 sensor.
+*/
+#define USE_SENSOR_HI7 (false)
+
+/*!
+\def USE_SENSOR_BMP
+\brief Enable if you want use Bmp085 sensor.
+*/
+#define USE_SENSOR_BMP (false)
+
+/*!
+\def USE_SENSOR_DW1
+\brief Enable if you want use DW1 sensor.
+*/
+#define USE_SENSOR_DW1 (false)
+
+/*!
+\def USE_SENSOR_TBS
+\brief Enable if you want use Tipping bucket rain gauge sensor.
+*/
+#define USE_SENSOR_TBS (false)
+
+/*!
+\def USE_SENSOR_TBR
+\brief Enable if you want use Tipping bucket rain gauge sensor.
+*/
+#define USE_SENSOR_TBR (false)
+
+/*!
+\def USE_SENSOR_STH
+\brief Enable if you want use Temperature and humidity oneshot sensor.
+*/
+#define USE_SENSOR_STH (false)
+
+/*!
+\def USE_SENSOR_ITH
+\brief Enable if you want use Temperature and humidity continuous istantaneous sensor.
+*/
+#define USE_SENSOR_ITH (false)
+
+/*!
+\def USE_SENSOR_NTH
+\brief Enable if you want use Temperature and humidity continuous minium sensor.
+*/
+#define USE_SENSOR_NTH (false)
+
+/*!
+\def USE_SENSOR_MTH
+\brief Enable if you want use Temperature and humidity continuous average sensor.
+*/
+#define USE_SENSOR_MTH (false)
+
+/*!
+\def USE_SENSOR_XTH
+\brief Enable if you want use Temperature and humidity continuous maximum sensor.
+*/
+#define USE_SENSOR_XTH (false)
+
+/*!
+\def USE_SENSOR_SSD
+\brief Enable if you want use SSD011 oneshot sensor.
+*/
+#define USE_SENSOR_SSD (false)
+
+/*!
+\def USE_SENSOR_ISD
+\brief Enable if you want use SSD011 report istantaneous sensor.
+*/
+#define USE_SENSOR_ISD (false)
+
+/*!
+\def USE_SENSOR_NSD
+\brief Enable if you want use SSD011 report minium sensor.
+*/
+#define USE_SENSOR_NSD (false)
+
+/*!
+\def USE_SENSOR_MSD
+\brief Enable if you want use SSD011 report average sensor.
+*/
+#define USE_SENSOR_MSD (false)
+
+/*!
+\def USE_SENSOR_XSD
+\brief Enable if you want use SSD011 report maximum sensor.
+*/
+#define USE_SENSOR_XSD (false)
+
+/*!
+\def USE_SENSOR_SMI
+\brief Enable if you want use MICS4514 oneshot sensor.
+*/
+#define USE_SENSOR_SMI (false)
+
+/*!
+\def USE_SENSOR_IMI
+\brief Enable if you want use MICS4514 report istantaneous sensor.
+*/
+#define USE_SENSOR_IMI (false)
+
+/*!
+\def USE_SENSOR_NMI
+\brief Enable if you want use MICS4514 report minium sensor.
+*/
+#define USE_SENSOR_NMI (false)
+
+/*!
+\def USE_SENSOR_MMI
+\brief Enable if you want use MICS4514 report average sensor.
+*/
+#define USE_SENSOR_MMI (false)
+
+/*!
+\def USE_SENSOR_GWS
+\brief Enable if you want use Gill Windsonic sensor.
+*/
+#define USE_SENSOR_GWS (true)
+
+/*!
+\def USE_SENSOR_XMI
+\brief Enable if you want use MICS4514 report maximum sensor.
+*/
+#define USE_SENSOR_XMI (false)
+
+/*!
+\def USE_SENSOR_RF24
+\brief Enable if you want use Radio RF24 sensor.
+*/
+#define USE_SENSOR_RF24 (false)
+
+/*!
+\def RAIN_FOR_TIP
+\brief How much mm of rain for one tip of tipping bucket rain gauge.
+*/
+#define RAIN_FOR_TIP (1)
+
+/*!
+\def VALUES_TO_READ_FROM_SENSOR_COUNT
+Maximum number of values to be read by the sensors.
+*/
+#define VALUES_TO_READ_FROM_SENSOR_COUNT (3)
+#define JSONS_TO_READ_FROM_SENSOR_COUNT (3)
+
+// sampling every 3-15 seconds --> watchdog timer (SENSORS_SAMPLE_TIME_S in relative modules)
+// observations with processing every 1-10 minutes (minutes for processing sampling)
+// report every 5-60 minutes (> OBSERVATIONS_MINUTES)
+// reported data is calulate by moving average on STATISTICAL_DATA_MINUTES window
+
+// observations every 1-10 minutes (minutes for processing samples)
+// report every 5-60 minutes (minutes for report. > n * OBSERVATIONS_MINUTES)
+
+/*!
+\def OBSERVATIONS_MINUTES
+\brief How much minutes for calculate an observations by processing sampling. Tipically 1-10 minutes.
+*/
+#define OBSERVATIONS_MINUTES (1)
+
+/*!
+\def STATISTICAL_DATA_COUNT
+\brief How much observations are needed for generating a report.
+*/
+#define STATISTICAL_DATA_COUNT (15)
+
+/*!
+\def OBSERVATION_COUNT
+\brief Observations buffer length.
+*/
+#define OBSERVATION_COUNT (STATISTICAL_DATA_COUNT * 2)
+
+/*!
+\def OBSERVATION_COUNT_TOLLERANCE
+\brief Tolerance of observations for generating a valid report.
+*/
+#define OBSERVATION_COUNT_TOLLERANCE (1)
+
+#if (OBSERVATION_COUNT < STATISTICAL_DATA_COUNT)
+#error OBSERVATION_COUNT must be major of STATISTICAL_DATA_COUNT !!!
+#endif
+
+#endif
diff --git a/platformio/stima_v3/i2c-wind/platformio.ini b/platformio/stima_v3/i2c-wind/platformio.ini
new file mode 100644
index 000000000..3e255168b
--- /dev/null
+++ b/platformio/stima_v3/i2c-wind/platformio.ini
@@ -0,0 +1,35 @@
+; PlatformIO Project Configuration File
+;
+; Build options: build flags, source filter
+; Upload options: custom upload port, speed and extra flags
+; Library options: dependencies, extra library storages
+; Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env]
+framework = arduino
+lib_extra_dirs = ../../../arduino/sketchbook/libraries/
+monitor_speed = 115200
+lib_ldf_mode = deep+
+
+
+[env:1284p16m]
+platform = atmelavr
+platform_packages =
+ toolchain-atmelavr@1.70300.191015
+ ;toolchain-atmelavr @ https://github.com/r-map/platformio-toolchain-atmelavr-uselocal.git
+ ;toolchain-atmelavr@1.50400.190710
+ framework-arduino-avr @ https://github.com/r-map/ArduinoCore-avr.git
+board = 1284p16m
+lib_ignore =
+ STM32duino FreeRTOS
+ EspSoftwareSerial
+ SD
+ RmapConfig
+build_flags = -I include -DSERIAL_TX_BUFFER_SIZE=192 -DSERIAL_RX_BUFFER_SIZE=192
+; with -Og do not compile (SensorDriver)
+;debug_build_flags = -I include -Og -g2 -ggdb2
+debug_build_flags = -I include -Os
+
diff --git a/platformio/stima_v3/i2c-wind/src/i2c-wind.ino b/platformio/stima_v3/i2c-wind/src/i2c-wind.ino
new file mode 100644
index 000000000..8823f9795
--- /dev/null
+++ b/platformio/stima_v3/i2c-wind/src/i2c-wind.ino
@@ -0,0 +1,932 @@
+/**@file i2c-wind.ino */
+
+/*********************************************************************
+Copyright (C) 2017 Marco Baldinetti
+authors:
+Paolo patruno
+Marco Baldinetti
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+**********************************************************************/
+
+#include
+
+/*!
+\def SERIAL_TRACE_LEVEL
+\brief Serial debug level for this sketch.
+*/
+#define SERIAL_TRACE_LEVEL I2C_WIND_SERIAL_TRACE_LEVEL
+
+#include "i2c-wind.h"
+
+/*!
+\fn void setup()
+\brief Arduino setup function.
+* Init watchdog, hardware, debug, buffer and load configuration stored in EEPROM.
+\return void.
+*/
+void setup() {
+ init_wdt(WDT_TIMER);
+ SERIAL_BEGIN(115200);
+ init_pins();
+ load_configuration();
+ init_buffers();
+ init_wire();
+ init_spi();
+ init_rtc();
+ #if (USE_TIMER_1)
+ init_timer1();
+ #endif
+ init_system();
+ wdt_reset();
+
+ #if (USE_SENSOR_GWS)
+ Serial1.begin(GWS_SERIAL_BAUD);
+ #endif
+}
+
+/*!
+\fn void loop()
+\brief Arduino loop function.
+* First, initialize tasks and sensors, then execute the tasks and activates the power down if no task is running.
+\return void.
+*/
+void loop() {
+ switch (state) {
+ case INIT:
+ init_tasks();
+ init_sensors();
+ wdt_reset();
+ state = TASKS_EXECUTION;
+ break;
+
+ #if (USE_POWER_DOWN)
+ case ENTER_POWER_DOWN:
+ //! enter in power down mode only if DEBOUNCING_POWER_DOWN_TIME_MS milliseconds have passed since last time (awakened_event_occurred_time_ms)
+ init_power_down(&awakened_event_occurred_time_ms, DEBOUNCING_POWER_DOWN_TIME_MS);
+ state = TASKS_EXECUTION;
+ break;
+ #endif
+
+ case TASKS_EXECUTION:
+ // I2C Bus Check
+ if (i2c_error >= I2C_MAX_ERROR_COUNT) {
+ SERIAL_DEBUG(F("Restart I2C BUS\r\n"));
+ init_wire();
+ wdt_reset();
+ }
+
+ #if (USE_SENSOR_GWS)
+ if (is_event_wind_task) {
+ wind_task();
+ wdt_reset();
+ }
+ #endif
+
+ if (is_event_command_task) {
+ command_task();
+ wdt_reset();
+ }
+
+ if (ready_tasks_count == 0) {
+ wdt_reset();
+ state = END;
+ }
+ break;
+
+ case END:
+ #if (USE_POWER_DOWN)
+ state = ENTER_POWER_DOWN;
+ #else
+ state = TASKS_EXECUTION;
+ #endif
+ break;
+ }
+}
+
+void init_power_down(uint32_t *time_ms, uint32_t debouncing_ms) {
+ if (millis() - *time_ms > debouncing_ms) {
+ *time_ms = millis();
+
+ power_adc_disable();
+ power_spi_disable();
+ power_timer0_disable();
+ #if (USE_TIMER_1 == false)
+ power_timer1_disable();
+ #endif
+ power_timer2_disable();
+
+ noInterrupts ();
+ sleep_enable();
+
+ //! turn off brown-out
+ // MCUCR = bit (BODS) | bit (BODSE);
+ // MCUCR = bit (BODS);
+ interrupts ();
+
+ sleep_cpu();
+ sleep_disable();
+
+ power_adc_enable();
+ power_spi_enable();
+ power_timer0_enable();
+ #if (USE_TIMER_1 == false)
+ power_timer1_enable();
+ #endif
+ power_timer2_enable();
+ }
+}
+
+void init_wdt(uint8_t wdt_timer) {
+ wdt_disable();
+ wdt_reset();
+ wdt_enable(wdt_timer);
+}
+
+void init_buffers() {
+ readable_data_read_ptr = &readable_data_1;
+ readable_data_write_ptr = &readable_data_2;
+ writable_data_ptr = &writable_data;
+
+ readable_data_write_ptr->module_type = MODULE_TYPE;
+ readable_data_write_ptr->module_version = MODULE_VERSION;
+
+ reset_samples_buffer();
+ reset_report_buffer();
+
+ //! copy readable_data_2 in readable_data_1
+ memcpy((void *) readable_data_read_ptr, (const void*) readable_data_write_ptr, sizeof(readable_data_t));
+}
+
+void init_tasks() {
+ noInterrupts();
+
+ //! no tasks ready
+ ready_tasks_count = 0;
+
+ is_event_command_task = false;
+ is_event_wind_task = false;
+
+ wind_acquisition_count = 0;
+
+ wind_state = WIND_INIT;
+
+ is_oneshot = false;
+ is_continuous = false;
+ is_start = false;
+ is_stop = false;
+ is_test = false;
+
+ interrupts();
+}
+
+void init_pins() {
+ pinMode(CONFIGURATION_RESET_PIN, INPUT_PULLUP);
+
+}
+
+void init_wire() {
+ if (i2c_error > 0) {
+ i2c_error = 0;
+ }
+
+ Wire.end();
+ Wire.begin(configuration.i2c_address);
+ Wire.setClock(I2C_BUS_CLOCK);
+ Wire.onRequest(i2c_request_interrupt_handler);
+ Wire.onReceive(i2c_receive_interrupt_handler);
+}
+
+void init_spi() {
+}
+
+void init_rtc() {
+}
+
+#if (USE_TIMER_1)
+void init_timer1() {
+ timer_counter_ms = 0;
+ start_timer();
+}
+
+void start_timer() {
+ TCCR1A = 0x00; //!< Normal timer operation
+ TCCR1B = 0x05; //!< 1:1024 prescaler
+ TCNT1 = TIMER1_TCNT1_VALUE; //!< Pre-load timer counter register
+ TIFR1 |= (1 << TOV1); //!< Clear interrupt overflow flag register
+ TIMSK1 |= (1 << TOIE1); //!< Enable overflow interrupt
+}
+
+void stop_timer() {
+ TCCR1B = 0x00; //!< Stop
+ TIMSK1 &= ~(1 << TOIE1); //!< Disable overflow interrupt
+ TIFR1 |= (1 << TOV1); //!< Clear interrupt overflow flag register
+ TCNT1 = TIMER1_TCNT1_VALUE; //!< Pre-load timer counter register
+}
+#endif
+
+void init_system() {
+ #if (USE_POWER_DOWN)
+ set_sleep_mode(SLEEP_MODE_IDLE);
+ awakened_event_occurred_time_ms = millis();
+ #endif
+
+ //! main loop state
+ state = INIT;
+ i2c_error = 0;
+}
+
+void print_configuration() {
+ char stima_name[20];
+ getStimaNameByType(stima_name, configuration.module_type);
+ SERIAL_INFO(F("--> type: %s\r\n"), stima_name);
+ SERIAL_INFO(F("--> version: %d\r\n"), configuration.module_version);
+ SERIAL_INFO(F("--> i2c address: 0x%X (%d)\r\n"), configuration.i2c_address, configuration.i2c_address);
+ SERIAL_INFO(F("--> oneshot: %s\r\n"), configuration.is_oneshot ? ON_STRING : OFF_STRING);
+ SERIAL_INFO(F("--> continuous: %s\r\n"), configuration.is_continuous ? ON_STRING : OFF_STRING);
+}
+
+void save_configuration(bool is_default) {
+ if (is_default) {
+ SERIAL_INFO(F("Save default configuration... [ %s ]\r\n"), OK_STRING);
+ configuration.module_type = MODULE_TYPE;
+ configuration.module_version = MODULE_VERSION;
+ configuration.i2c_address = CONFIGURATION_DEFAULT_I2C_ADDRESS;
+ configuration.is_oneshot = CONFIGURATION_DEFAULT_IS_ONESHOT;
+ configuration.is_continuous = CONFIGURATION_DEFAULT_IS_CONTINUOUS;
+ }
+ else {
+ SERIAL_INFO(F("Save configuration... [ %s ]\r\n"), OK_STRING);
+ configuration.i2c_address = writable_data.i2c_address;
+ configuration.is_oneshot = writable_data.is_oneshot;
+ configuration.is_continuous = writable_data.is_continuous;
+ }
+
+ //! write configuration to eeprom
+ ee_write(&configuration, CONFIGURATION_EEPROM_ADDRESS, sizeof(configuration));
+
+ print_configuration();
+}
+
+void load_configuration() {
+ //! read configuration from eeprom
+ ee_read(&configuration, CONFIGURATION_EEPROM_ADDRESS, sizeof(configuration));
+
+ if (configuration.module_type != MODULE_TYPE || configuration.module_version != MODULE_VERSION || digitalRead(CONFIGURATION_RESET_PIN) == LOW) {
+ save_configuration(CONFIGURATION_DEFAULT);
+ }
+ else {
+ SERIAL_INFO(F("Load configuration... [ %s ]\r\n"), OK_STRING);
+ print_configuration();
+ }
+
+ writable_data.i2c_address = configuration.i2c_address;
+ writable_data.is_oneshot = configuration.is_oneshot;
+ writable_data.is_continuous = configuration.is_continuous;
+}
+
+void init_sensors () {
+ if (configuration.is_continuous) {
+ SERIAL_INFO(F("\r\n"));
+ SERIAL_INFO(F("--> acquiring %u~%u samples in %u minutes\r\n"), OBSERVATION_SAMPLES_COUNT_MIN, OBSERVATION_SAMPLES_COUNT_MAX, OBSERVATIONS_MINUTES);
+ SERIAL_INFO(F("--> max %u samples error in %u minutes (observation)\r\n"), OBSERVATION_SAMPLE_ERROR_MAX, OBSERVATIONS_MINUTES);
+ SERIAL_INFO(F("--> max %u samples error in 10 minutes\r\n"), WMO_REPORT_SAMPLE_ERROR_MAX);
+ SERIAL_INFO(F("--> max %u samples error in %u minutes (report)\r\n\r\n"), RMAP_REPORT_SAMPLE_ERROR_MAX, STATISTICAL_DATA_COUNT * OBSERVATIONS_MINUTES);
+
+ #if (USE_SENSOR_GWS)
+ SERIAL_INFO(F("sc: speed sample count\r\n"));
+ SERIAL_INFO(F("dc: direction sample count\r\n"));
+ SERIAL_INFO(F("speed: sensor speed\r\n"));
+ SERIAL_INFO(F("dir: sensor direction\r\n"));
+ SERIAL_DEBUG(F("ua: average u component over 10'\r\n"));
+ SERIAL_DEBUG(F("va: average v component over 10'\r\n"));
+ SERIAL_INFO(F("vs10: vectorial average speed over 10'\r\n"));
+ SERIAL_INFO(F("vd10: vectorial average speed over 10'\r\n"));
+ SERIAL_DEBUG(F("ub: average u component over %u'\r\n"), STATISTICAL_DATA_COUNT * OBSERVATIONS_MINUTES);
+ SERIAL_DEBUG(F("vb: average v component over %u'\r\n"), STATISTICAL_DATA_COUNT * OBSERVATIONS_MINUTES);
+ SERIAL_INFO(F("vsr: vectorial average speed over %u'\r\n"), STATISTICAL_DATA_COUNT * OBSERVATIONS_MINUTES);
+ SERIAL_INFO(F("vdr: vectorial average speed over %u'\r\n"), STATISTICAL_DATA_COUNT * OBSERVATIONS_MINUTES);
+ SERIAL_INFO(F("ss: scalar average speed over %u'\r\n"), STATISTICAL_DATA_COUNT * OBSERVATIONS_MINUTES);
+ SERIAL_INFO(F("pgs: peak gust speed\r\n"));
+ SERIAL_INFO(F("pgd: peak gust direction\r\n"));
+ SERIAL_INFO(F("lgs: long gust speed'\r\n"));
+ SERIAL_INFO(F("lgd: long gust direction'\r\n"));
+ SERIAL_INFO(F("C1: %% of sample <= 1.0 m/s \r\n"));
+ SERIAL_INFO(F("C2: %% of sample <= 2.0 m/s \r\n"));
+ SERIAL_INFO(F("C4: %% of sample <= 4.0 m/s \r\n"));
+ SERIAL_INFO(F("C7: %% of sample <= 7.0 m/s \r\n"));
+ SERIAL_INFO(F("C10: %% of sample <= 10.0 m/s \r\n"));
+ SERIAL_INFO(F("CXX: %% of sample > 10.0 m/s \r\n\r\n"));
+
+ #if (SERIAL_TRACE_LEVEL < SERIAL_TRACE_LEVEL_DEBUG)
+ SERIAL_INFO(F("sc\tdc\tspeed\tdir\tvs10\tvd10\tvsr\tvdr\tss\tpgs\tpgd\tlgs\tlgd\tC1\tC2\tC4\tC7\tC10\tCXX\r\n\r\n"));
+ #else
+ SERIAL_DEBUG(F("sc\tdc\tspeed\tdir\tua\tva\tvs10\tvd10\tub\tvb\tvsr\tvdr\tss\tpgs\tpgd\tlgs\tlgd\tC1\tC2\tC4\tC7\tC10\tCXX\r\n\r\n"));
+ #endif
+ #endif
+ }
+}
+
+/*!
+\fn ISR(TIMER1_OVF_vect)
+\brief Timer1 overflow interrupts routine.
+\return void.
+*/
+ISR(TIMER1_OVF_vect) {
+ //! Pre-load timer counter register
+ TCNT1 = TIMER1_TCNT1_VALUE;
+
+ //! increment timer_counter_ms by TIMER1_INTERRUPT_TIME_MS
+ timer_counter_ms += TIMER1_INTERRUPT_TIME_MS;
+ timer_counter_s += (uint16_t)(TIMER1_INTERRUPT_TIME_MS/1000);
+
+ #if (USE_SENSOR_GWS)
+ if (executeTimerTaskEach(timer_counter_ms, SENSORS_SAMPLE_TIME_MS, TIMER1_INTERRUPT_TIME_MS) && configuration.is_continuous) {
+ if (!is_event_wind_task) {
+ noInterrupts();
+ is_event_wind_task = true;
+ ready_tasks_count++;
+ interrupts();
+ }
+ }
+ #endif
+
+ //! reset timer_counter_ms if it has become larger than TIMER_COUNTER_VALUE_MAX_MS
+ if (timer_counter_ms >= TIMER_COUNTER_VALUE_MAX_MS) {
+ timer_counter_ms = 0;
+ }
+
+ if (timer_counter_s >= TIMER_COUNTER_VALUE_MAX_S) {
+ timer_counter_s = 0;
+ }
+}
+
+void i2c_request_interrupt_handler() {
+ if (readable_data_length) {
+ //! write readable_data_length bytes of data stored in readable_data_read_ptr (base) + readable_data_address (offset) on i2c bus
+ Wire.write((uint8_t *)readable_data_read_ptr+readable_data_address, readable_data_length);
+ //! write crc8
+ Wire.write(crc8((uint8_t *)readable_data_read_ptr+readable_data_address, readable_data_length));
+ } else {
+ Wire.write(UINT16_MAX);
+ }
+}
+
+void i2c_receive_interrupt_handler(int rx_data_length) {
+ bool is_i2c_data_ok = false;
+
+ readable_data_length = 0;
+
+ // read rx_data_length bytes of data from i2c bus
+ for (uint8_t i = 0; i < rx_data_length; i++) {
+ i2c_rx_data[i] = Wire.read();
+ }
+
+ //! check crc: ok
+ if (i2c_rx_data[rx_data_length - 1] == crc8((uint8_t *)i2c_rx_data, rx_data_length - 1)) {
+ rx_data_length--;
+
+ // it is a registers read?
+ if (rx_data_length == 2 && is_readable_register(i2c_rx_data[0])) {
+ // offset in readable_data_read_ptr buffer
+ readable_data_address = i2c_rx_data[0];
+
+ // length (in bytes) of data to be read in readable_data_read_ptr
+ readable_data_length = i2c_rx_data[1];
+ }
+ // it is a command?
+ else if (rx_data_length == 2 && is_command(i2c_rx_data[0])) {
+ noInterrupts();
+ // enable Command task
+ if (!is_event_command_task) {
+ is_event_command_task = true;
+ ready_tasks_count++;
+ }
+ interrupts();
+ }
+ // it is a registers write?
+ else if (is_writable_register(i2c_rx_data[0])) {
+ rx_data_length -= 2;
+
+ if (i2c_rx_data[0] == I2C_WIND_ADDRESS_ADDRESS && rx_data_length == I2C_WIND_ADDRESS_LENGTH) {
+ is_i2c_data_ok = true;
+ }
+ else if (i2c_rx_data[0] == I2C_WIND_ONESHOT_ADDRESS && rx_data_length == I2C_WIND_ONESHOT_LENGTH) {
+ is_i2c_data_ok = true;
+ }
+ else if (i2c_rx_data[0] == I2C_WIND_CONTINUOUS_ADDRESS && rx_data_length == I2C_WIND_CONTINUOUS_LENGTH) {
+ is_i2c_data_ok = true;
+ }
+
+ if (is_i2c_data_ok) {
+ for (uint8_t i = 0; i < rx_data_length; i++) {
+ // write rx_data_length bytes in writable_data_ptr (base) at (i2c_rx_data[i] - I2C_WRITE_REGISTER_START_ADDRESS) (position in buffer)
+ ((uint8_t *)writable_data_ptr)[i2c_rx_data[0] - I2C_WRITE_REGISTER_START_ADDRESS + i] = i2c_rx_data[i + 2];
+ }
+ }
+ }
+ } else {
+ readable_data_length = 0;
+ i2c_error++;
+ }
+}
+
+template value_v bufferRead(buffer_g *buffer, length_v length) {
+ value_v value = *buffer->read_ptr;
+
+ if (buffer->read_ptr == buffer->value+length-1) {
+ buffer->read_ptr = buffer->value;
+ }
+ else buffer->read_ptr++;
+
+ return value;
+}
+
+template value_v bufferReadBack(buffer_g *buffer, length_v length) {
+ value_v value = *buffer->read_ptr;
+
+ if (buffer->read_ptr == buffer->value) {
+ buffer->read_ptr = buffer->value+length-1;
+ }
+ else buffer->read_ptr--;
+
+ return value;
+}
+
+template void bufferWrite(buffer_g *buffer, value_v value) {
+ *buffer->write_ptr = value;
+}
+
+template void bufferPtrReset(buffer_g *buffer) {
+ buffer->read_ptr = buffer->value;
+}
+
+template void bufferPtrResetBack(buffer_g *buffer, length_v length) {
+ if (buffer->write_ptr == buffer->value) {
+ buffer->read_ptr = buffer->value+length-1;
+ }
+ else buffer->read_ptr = buffer->write_ptr-1;
+}
+
+template void incrementBuffer(buffer_g *buffer, length_v length) {
+ if (buffer->count < length) {
+ buffer->count++;
+ }
+
+ if (buffer->write_ptr+1 < buffer->value + length) {
+ buffer->write_ptr++;
+ } else buffer->write_ptr = buffer->value;
+}
+
+template void bufferReset(buffer_g *buffer, length_v length) {
+ memset(buffer->value, UINT8_MAX, length * sizeof(value_v));
+ buffer->count = 0;
+ buffer->read_ptr = buffer->value;
+ buffer->write_ptr = buffer->value;
+}
+
+template void addValue(buffer_g *buffer, length_v length, value_v value) {
+ *buffer->write_ptr = (value_v) value;
+ incrementBuffer(buffer, length);
+}
+
+void getSDFromUV (float u, float v, float *speed, float *direction) {
+ *speed = sqrt(u*u + v*v);
+ *direction = RAD_TO_DEG * atan2(u, v);
+}
+
+void make_report () {
+ uint16_t valid_count_a = 0;
+ uint16_t error_count_a = 0;
+
+ uint16_t valid_count_b = 0;
+ uint16_t error_count_b = 0;
+
+ uint16_t valid_count_speed = 0;
+ uint16_t error_count_speed = 0;
+
+ uint16_t valid_count_o = 0;
+ uint16_t error_count_o = 0;
+
+ uint16_t valid_count_c = 0;
+ uint16_t error_count_c = 0;
+
+ float ua = 0;
+ float va = 0;
+
+ float ub = 0;
+ float vb = 0;
+
+ float uc = 0;
+ float vc = 0;
+
+ float vavg10_speed = 0;
+ float vavg10_direction = 0;
+
+ float vavg_speed = 0;
+ float vavg_direction = 0;
+
+ float peak_gust_speed = -1.0;
+ float peak_gust_direction = 0;
+
+ float vavg_speed_o = -1.0;
+ float vavg_direction_o = 0;
+
+ float long_gust_speed = -1.0;
+ float long_gust_direction = 0;
+
+ float avg_speed = 0;
+
+ #if (USE_SENSOR_GWS)
+ bufferPtrResetBack(&wind_speed_samples, SAMPLES_COUNT);
+ #endif
+
+ #if (USE_SENSOR_GWS)
+ bufferPtrResetBack(&wind_direction_samples, SAMPLES_COUNT);
+ #endif
+
+ uint16_t sample_count = RMAP_REPORT_SAMPLES_COUNT;
+
+ #if (USE_SENSOR_GWS)
+ if (wind_speed_samples.count < sample_count) {
+ sample_count = wind_speed_samples.count;
+ }
+ #endif
+
+ #if (USE_SENSOR_GWS)
+ if (wind_direction_samples.count < sample_count) {
+ sample_count = wind_direction_samples.count;
+ }
+ #endif
+
+ #if (USE_SENSORS_COUNT == 0)
+ sample_count = 0;
+ #endif
+
+ for (uint16_t i = 0; i < sample_count; i++) {
+ bool is_new_observation = (((i+1) % OBSERVATION_SAMPLES_COUNT_MAX) == 0);
+
+ #if (USE_SENSOR_GWS)
+ float speed = bufferReadBack(&wind_speed_samples, SAMPLES_COUNT);
+ #endif
+
+ #if (USE_SENSOR_GWS)
+ float direction = bufferReadBack(&wind_direction_samples, SAMPLES_COUNT);
+
+ #endif
+
+ if (i == 0) {
+ #if (USE_SENSOR_GWS)
+ SERIAL_INFO(F("%u\t%u\t%.2f\t%.0f\t"), wind_speed_samples.count, wind_direction_samples.count, speed, direction);
+ #endif
+ }
+
+ #if (USE_SENSOR_GWS)
+ if (i < WMO_REPORT_SAMPLES_COUNT) {
+ if (isValid(speed) && isValid(direction)) {
+ valid_count_a++;
+ ua += ((float) (-speed * sin(DEG_TO_RAD * direction)) - ua) / valid_count_a;
+ va += ((float) (-speed * cos(DEG_TO_RAD * direction)) - va) / valid_count_a;
+ }
+ else {
+ error_count_a++;
+ }
+ }
+
+ if (isValid(speed) && isValid(direction)) {
+ valid_count_b++;
+ valid_count_c++;
+
+ ub += ((float) (-speed * sin(DEG_TO_RAD * direction)) - ub) / valid_count_b;
+ vb += ((float) (-speed * cos(DEG_TO_RAD * direction)) - vb) / valid_count_b;
+
+ uc += ((float) (-speed * sin(DEG_TO_RAD * direction)) - uc) / valid_count_c;
+ vc += ((float) (-speed * cos(DEG_TO_RAD * direction)) - vc) / valid_count_c;
+
+ if (speed >= peak_gust_speed) {
+ peak_gust_speed = speed;
+ peak_gust_direction = direction;
+ }
+ }
+ else {
+ error_count_b++;
+ error_count_c++;
+ }
+ #endif
+
+ #if (USE_SENSOR_GWS)
+ if (is_new_observation) {
+ if (valid_count_c && (error_count_c <= OBSERVATION_SAMPLE_ERROR_MAX)) {
+ valid_count_o++;
+ getSDFromUV(uc, vc, &vavg_speed_o, &vavg_direction_o);
+
+ if (vavg_speed_o >= long_gust_speed) {
+ long_gust_speed = vavg_speed_o;
+ long_gust_direction = vavg_direction_o;
+ }
+ }
+ else {
+ error_count_o++;
+ }
+
+ uc = 0;
+ vc = 0;
+ vavg_speed_o = 0;
+ vavg_direction_o = 0;
+ valid_count_c = 0;
+ error_count_c = 0;
+ }
+ #endif
+ }
+
+ #if (USE_SENSOR_GWS)
+ getSDFromUV(ua, va, &vavg10_speed, &vavg10_direction);
+ getSDFromUV(ub, vb, &vavg_speed, &vavg_direction);
+ readable_data_write_ptr->wind.vavg10_speed = vavg10_speed;
+ readable_data_write_ptr->wind.vavg10_direction = vavg10_direction;
+ readable_data_write_ptr->wind.vavg_speed = vavg_speed;
+ readable_data_write_ptr->wind.vavg_direction = vavg_direction;
+ readable_data_write_ptr->wind.peak_gust_speed = peak_gust_speed;
+ readable_data_write_ptr->wind.peak_gust_direction = peak_gust_direction;
+ readable_data_write_ptr->wind.long_gust_speed = long_gust_speed;
+ readable_data_write_ptr->wind.long_gust_direction = long_gust_direction;
+ #endif
+}
+
+void samples_processing() {
+ reset_report_buffer();
+ make_report();
+}
+
+#if (USE_SENSOR_GWS)
+void wind_task () {
+ static uint16_t retry;
+ static bool is_error;
+ static wind_state_t state_after_wait;
+ static uint32_t delay_ms;
+ static uint32_t start_time_ms;
+ static uint8_t i = 0;
+ float speed;
+ float direction;
+
+ switch (wind_state) {
+ case WIND_INIT:
+ i = 0;
+ retry = 0;
+ is_error = false;
+ wind_acquisition_count++;
+
+ wind_state = WIND_READING;
+ SERIAL_TRACE(F("WIND_INIT --> WIND_READING\r\n"));
+ break;
+
+ case WIND_READING:
+ if (Serial1.available()) {
+ uart_rx_buffer_length = Serial1.readBytes(uart_rx_buffer, UART_RX_BUFFER_LENGTH);
+ wind_state = WIND_ELABORATE;
+ SERIAL_TRACE(F("WIND_READING --> WIND_ELABORATE\r\n"));
+ }
+ else {
+ is_error = true;
+ wind_state = WIND_ELABORATE;
+ SERIAL_TRACE(F("WIND_READING --> WIND_ELABORATE\r\n"));
+ }
+ break;
+
+ case WIND_ELABORATE:
+ if (is_error) {
+ speed = UINT16_MAX;
+ direction = UINT16_MAX;
+ }
+ else {
+ windsonic_interpreter(&speed, &direction);
+ }
+
+ addValue(&wind_speed_samples, SAMPLES_COUNT, speed);
+ addValue(&wind_direction_samples, SAMPLES_COUNT, direction);
+ samples_processing();
+
+ wind_state = WIND_END;
+ SERIAL_TRACE(F("WIND_ELABORATE --> WIND_END\r\n"));
+ break;
+
+ case WIND_END:
+ noInterrupts();
+ is_event_wind_task = false;
+ ready_tasks_count--;
+ interrupts();
+ wind_state = WIND_INIT;
+ SERIAL_TRACE(F("WIND_END --> WIND_INIT\r\n"));
+ break;
+
+ case WIND_WAIT_STATE:
+ if (millis() - start_time_ms > delay_ms) {
+ wind_state = state_after_wait;
+ }
+ break;
+ }
+}
+
+bool windsonic_interpreter (float *speed, float *direction) {
+ *speed = UINT16_MAX;
+ *direction = UINT16_MAX;
+
+ if ((uart_rx_buffer[GWS_STX_INDEX] == STX_VALUE) && (uart_rx_buffer[GWS_ETX_INDEX] != ETX_VALUE)) {
+ char tempstr[GWS_SPEED_LENGTH+1];
+
+ strncpy(tempstr, (const char *)(uart_rx_buffer+GWS_DIRECTION_INDEX), GWS_DIRECTION_LENGTH);
+ *direction = (float) atof(tempstr);
+ memset(tempstr, 0, GWS_SPEED_LENGTH+1);
+
+ strncpy(tempstr, (const char *)(uart_rx_buffer+GWS_SPEED_INDEX), GWS_SPEED_LENGTH);
+ *speed = (float) atof(tempstr);
+ memset(tempstr, 0, GWS_SPEED_LENGTH+1);
+ }
+
+ return true;
+}
+#endif
+
+void exchange_buffers() {
+ readable_data_temp_ptr = readable_data_write_ptr;
+ readable_data_write_ptr = readable_data_read_ptr;
+ readable_data_read_ptr = readable_data_temp_ptr;
+}
+
+void reset_samples_buffer() {
+ #if (USE_SENSOR_GWS)
+ bufferReset(&wind_speed_samples, SAMPLES_COUNT);
+ bufferReset(&wind_direction_samples, SAMPLES_COUNT);
+ #endif
+}
+
+void reset_report_buffer () {
+ readable_data_write_ptr->wind.vavg10_speed = (float) UINT16_MAX;
+ readable_data_write_ptr->wind.vavg10_direction = (float) UINT16_MAX;
+ readable_data_write_ptr->wind.vavg_speed = (float) UINT16_MAX;
+ readable_data_write_ptr->wind.vavg_direction = (float) UINT16_MAX;
+ readable_data_write_ptr->wind.avg_speed = (float) UINT16_MAX;
+ readable_data_write_ptr->wind.peak_gust_speed = (float) UINT16_MAX;
+ readable_data_write_ptr->wind.peak_gust_direction = (float) UINT16_MAX;
+ readable_data_write_ptr->wind.long_gust_speed = (float) UINT16_MAX;
+ readable_data_write_ptr->wind.long_gust_direction = (float) UINT16_MAX;
+}
+
+void command_task() {
+ #if (SERIAL_TRACE_LEVEL >= SERIAL_TRACE_LEVEL_TRACE)
+ char buffer[30];
+ #endif
+
+ switch(i2c_rx_data[1]) {
+ case I2C_WIND_COMMAND_ONESHOT_START:
+ #if (SERIAL_TRACE_LEVEL >= SERIAL_TRACE_LEVEL_TRACE)
+ strcpy(buffer, "ONESHOT START");
+ #endif
+ is_oneshot = true;
+ is_continuous = false;
+ is_start = true;
+ is_stop = false;
+ is_test = false;
+ commands();
+ break;
+
+ case I2C_WIND_COMMAND_ONESHOT_STOP:
+ #if (SERIAL_TRACE_LEVEL >= SERIAL_TRACE_LEVEL_TRACE)
+ strcpy(buffer, "ONESHOT STOP");
+ #endif
+ is_oneshot = true;
+ is_continuous = false;
+ is_start = false;
+ is_stop = true;
+ is_test = false;
+ commands();
+ break;
+
+ case I2C_WIND_COMMAND_ONESHOT_START_STOP:
+ #if (SERIAL_TRACE_LEVEL >= SERIAL_TRACE_LEVEL_TRACE)
+ strcpy(buffer, "ONESHOT START-STOP");
+ #endif
+ is_oneshot = true;
+ is_continuous = false;
+ is_start = true;
+ is_stop = true;
+ is_test = false;
+ commands();
+ break;
+
+ case I2C_WIND_COMMAND_CONTINUOUS_START:
+ #if (SERIAL_TRACE_LEVEL >= SERIAL_TRACE_LEVEL_TRACE)
+ strcpy(buffer, "CONTINUOUS START");
+ #endif
+ is_oneshot = false;
+ is_continuous = true;
+ is_start = true;
+ is_stop = false;
+ is_test = false;
+ commands();
+ break;
+
+ case I2C_WIND_COMMAND_CONTINUOUS_STOP:
+ #if (SERIAL_TRACE_LEVEL >= SERIAL_TRACE_LEVEL_TRACE)
+ strcpy(buffer, "CONTINUOUS STOP");
+ #endif
+ is_oneshot = false;
+ is_continuous = true;
+ is_start = false;
+ is_stop = true;
+ is_test = false;
+ commands();
+ break;
+
+ case I2C_WIND_COMMAND_CONTINUOUS_START_STOP:
+ #if (SERIAL_TRACE_LEVEL >= SERIAL_TRACE_LEVEL_TRACE)
+ strcpy(buffer, "CONTINUOUS START-STOP");
+ #endif
+ is_oneshot = false;
+ is_continuous = true;
+ is_start = true;
+ is_stop = true;
+ is_test = false;
+ commands();
+ break;
+
+ case I2C_WIND_COMMAND_TEST_READ:
+ #if (SERIAL_TRACE_LEVEL >= SERIAL_TRACE_LEVEL_TRACE)
+ strcpy(buffer, "TEST READ");
+ #endif
+ is_test = true;
+ tests();
+ break;
+
+ case I2C_WIND_COMMAND_SAVE:
+ SERIAL_TRACE(F("Execute command [ SAVE ]\r\n"));
+ save_configuration(CONFIGURATION_CURRENT);
+ init_wire();
+ break;
+ }
+
+ #if (SERIAL_TRACE_LEVEL >= SERIAL_TRACE_LEVEL_TRACE)
+ if (configuration.is_oneshot == is_oneshot || configuration.is_continuous == is_continuous) {
+ SERIAL_TRACE(F("Execute [ %s ]\r\n"), buffer);
+ }
+ else if (configuration.is_oneshot == is_continuous || configuration.is_continuous == is_oneshot) {
+ SERIAL_TRACE(F("Ignore [ %s ]\r\n"), buffer);
+ }
+ #endif
+
+ noInterrupts();
+ is_event_command_task = false;
+ ready_tasks_count--;
+ interrupts();
+}
+
+void commands() {
+ noInterrupts();
+
+ //! CONTINUOUS START
+ if (configuration.is_continuous && is_continuous && is_start && !is_stop) {
+ reset_samples_buffer();
+ reset_report_buffer();
+ }
+ //! CONTINUOUS STOP
+ else if (configuration.is_continuous && is_continuous && !is_start && is_stop) {
+ exchange_buffers();
+ }
+ //! CONTINUOUS START-STOP
+ else if (configuration.is_continuous && is_continuous && is_start && is_stop) {
+ exchange_buffers();
+ }
+ //! ONESHOT START
+ else if (configuration.is_oneshot && is_oneshot && is_start && !is_stop) {
+ }
+ //! ONESHOT STOP
+ else if (configuration.is_oneshot && is_oneshot && !is_start && is_stop) {
+ }
+ //! ONESHOT START-STOP
+ else if (configuration.is_oneshot && is_oneshot && is_start && is_stop) {
+ }
+
+ interrupts();
+}
+
+void tests() {
+ noInterrupts();
+
+ //! TEST
+ if (is_test) {
+ exchange_buffers();
+ }
+
+ interrupts();
+}