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(); +}