From 01b68e0e6ca147ac03b63b8c71d035563e3bf13b Mon Sep 17 00:00:00 2001 From: Mathias Buder Date: Mon, 5 Dec 2022 23:08:57 +0100 Subject: [PATCH] [ME007] Simplified state maschine within me007_measure() --- tasmota/tasmota_xsns_sensor/xsns_23_me007.ino | 285 +++++++++--------- 1 file changed, 149 insertions(+), 136 deletions(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_23_me007.ino b/tasmota/tasmota_xsns_sensor/xsns_23_me007.ino index d2d1ab99083e..8515c52a569f 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_23_me007.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_23_me007.ino @@ -17,7 +17,7 @@ along with this program. If not, see . */ -#define USE_ME007 +//#define USE_ME007 #ifdef USE_ME007 /*********************************************************************************************\ @@ -43,29 +43,25 @@ #define ME007_SENSOR_ERROR_CNT_CURRENT_TAG "ErrorCounterCurrent" #define ME007_SENSOR_ERROR_CNT_TOTAL_TAG "ErrorCounterTotal" - -#define ME007_MIN_SENSOR_DISTANCE 30U /* @unit cm */ +#define ME007_MIN_SENSOR_DISTANCE 30U /**< Minimum measurement distance @unit cm */ #ifndef ME007_MAX_SENSOR_DISTANCE -#define ME007_MAX_SENSOR_DISTANCE 800U /**< Maximum measurement distance: 8 m */ +#define ME007_MAX_SENSOR_DISTANCE 800U /**< Maximum measurement distance @unit cm */ #endif -#define ME007_WS_SCALE_SWITCH_THRESH 100U /* @unit cm */ -#define ME007_SERIAL_IF_BAUD_RATE 9600U -#define ME007_SERIAL_SOF 0xFF /**< Start of frame indicator (header) */ -#define ME007_SERIAL_FRAME_SIZE 6U /**< Total frame size: 6 byte */ -#define ME007_SERIAL_DATA_SIZE 5U /**< Header (1Byte) + distance (2 byte) + temperature (2 byte): 5 byte */ -#define ME007_SERIAL_MAX_WAIT_TIME 61U /**< Max. wait time for data after trigger signal @unit ms */ +#define ME007_WS_SCALE_SWITCH_THRESH 100U /**< @unit Distance threshold to switch between cm/m to be displayed on web-interface */ +#define ME007_SERIAL_IF_BAUD_RATE 9600U /**< Serial interface baud rate @unit Baud */ +#define ME007_SERIAL_SOF 0xFF /**< Start of frame indicator (header) */ +#define ME007_SERIAL_FRAME_SIZE 6U /**< Total frame size: Header (1Byte) + Distance (2 byte) + Temperature (2 byte) + Checksum (1 byte) = 6 byte */ +#define ME007_SERIAL_MAX_WAIT_TIME 120U /**< Max. wait time for data after trigger signal @unit ms */ #define ME007_SERIAL_MAX_DATA_RECEIVE_TIME 500U /**< Max. time to receive entire data frame @unit ms */ -#define ME007_TRIG_SIG_DURATION_MS 1U /**< Time duration of trigger low-pulse @unit ms */ -#define ME007_MEDIAN_FILTER_SIZE 5U /**< Median filter samples @unit sample */ -#define ME007_SENSOR_NUM_ERROR 10U /**< Number of tries to detect sensor */ - - +#define ME007_TRIG_SIG_DURATION_MS 1U /**< Time duration of trigger low-pulse @unit ms */ +#define ME007_HIST_FILTER_SIZE 5U /**< Median filter samples @unit sample */ +#define ME007_SENSOR_NUM_ERROR 10U /**< Number of tries to detect sensor */ /*********************************************************************************************/ /* Enums */ /*********************************************************************************************/ /** - * @details I2C error types + * @details Sensor readings type */ enum ME007_SHOW_TYPE { @@ -73,20 +69,46 @@ enum ME007_SHOW_TYPE ME007_SHOW_TYPE_WS }; +/** + * @details Sensor serial interface mode type + */ typedef enum ME007_SERIAL_RECEIVE_TYPE_TAG { - ME007_SERIAL_RECEIVE_TYPE_SOF = 0U, - ME007_SERIAL_RECEIVE_TYPE_DATA, - ME007_SERIAL_RECEIVE_TYPE_CHECKSUM + ME007_SERIAL_RECEIVE_TYPE_SOF = 0U, /**< @details Receive Start-Of-Frame character */ + ME007_SERIAL_RECEIVE_TYPE_DATA /**< @details Receive data (distance + temperature + checksum) */ } ME007_SERIAL_RECEIVE_TYPE; /** - * @details ME007 + * @details Sensor serial interface byte type + */ +enum ME007_SERIAL_BYTE_TYPE +{ + ME007_SERIAL_BYTE_TYPE_SOF = 0U, /**< @details Receive Start-Of-Frame character */ + ME007_SERIAL_BYTE_TYPE_DIST_H, + ME007_SERIAL_BYTE_TYPE_DIST_L, + ME007_SERIAL_BYTE_TYPE_TEMP_H, + ME007_SERIAL_BYTE_TYPE_TEMP_L, + ME007_SERIAL_BYTE_TYPE_CHECKSUM +}; + +/** + * @details Global sensor error type + */ +typedef enum ME007_ERROR_TYPE_TAG +{ + ME007_ERROR_TYPE_NONE = 0U, + ME007_ERROR_TYPE_TIMEOUT, + ME007_ERROR_TYPE_CRC +} ME007_ERROR_TYPE; + + +/** + * @details Global sensor state type */ typedef enum ME007_STATE_TYPE_TAG { - ME007_STATE_NOT_DETECTED = 0U, - ME007_STATE_DETECTED + ME007_STATE_NOT_DETECTED = 0U, /**< @details Sensor not detected */ + ME007_STATE_DETECTED /**< @details Sensor detected */ } ME007_STATE_TYPE; /*********************************************************************************************/ @@ -94,19 +116,18 @@ typedef enum ME007_STATE_TYPE_TAG /*********************************************************************************************/ /** - * @details I2C error types + * @details Global sensor data structure */ struct { - uint8_t pin_rx_u8; - uint8_t pin_trig_u8; - ME007_STATE_TYPE state_e; - bool sensorDetected_b; - float distance_cm_f32; - float temperature_deg_f32; - float buffer_distance_cm_vf32[ME007_MEDIAN_FILTER_SIZE]; - uint8_t error_cnt_current_u8; - uint16_t error_cnt_total_u16; + uint8_t pin_rx_u8; /**< @details Serial interface receive pin */ + uint8_t pin_trig_u8; /**< @details Sensor trigger pin */ + ME007_STATE_TYPE state_e; /**< @details Global sensor state */ + float distance_cm_f32; /**< @details Distance measurement @unit cm */ + float temperature_deg_f32; /**< @details Temperature measurement @unit °C */ + float buffer_distance_cm_vf32[ME007_HIST_FILTER_SIZE]; /**< @details Histogram filter buffer */ + uint8_t error_cnt_current_u8; /**< @details Measurement error counter (current) */ + uint16_t error_cnt_total_u16; /**< @details Measurement error counter (total) */ } me007_data_s; /*********************************************************************************************/ @@ -130,7 +151,7 @@ void me007_init( void ); * low-level interface is working correctly. * @param[in] uint8_t I2C error code */ -bool me007_measure( float* p_distance_cm_f32, float* p_temperature_f32 ); +ME007_ERROR_TYPE me007_measure( float* p_distance_cm_f32, float* p_temperature_f32 ); /** * @details This function performs a read/write test on the specified I2C device to make sure the @@ -155,9 +176,9 @@ void me007_init( void ) } /* Init global sensor state to ME007_STATE_NOT_DETECTED */ - me007_data_s.state_e = ME007_STATE_NOT_DETECTED; - me007_data_s.error_cnt_current_u8 = 0U; - me007_data_s.error_cnt_total_u16 = 0U; + me007_data_s.state_e = ME007_STATE_NOT_DETECTED; + me007_data_s.error_cnt_current_u8 = 0U; + me007_data_s.error_cnt_total_u16 = 0U; /* Store real pin number */ me007_data_s.pin_rx_u8 = Pin( GPIO_ME007_RX ); @@ -165,7 +186,7 @@ void me007_init( void ) DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "Using GPIOs: Trigger: %i / Rx: %i)" ), me007_data_s.pin_trig_u8, me007_data_s.pin_rx_u8 ); - /* Configure serial interface */ + /* Configure serial interface */ /* Only Rx pin is required as ME007 is controlled using its trigger pin. Therefore, passing value "-1" as transmit_pin argument */ p_SerialIf = new TasmotaSerial( me007_data_s.pin_rx_u8, -1, 1U ); @@ -182,11 +203,11 @@ void me007_init( void ) /* Detect sensor */ AddLog( LOG_LEVEL_INFO, PSTR( ME007_DEBUG_MSG_TAG "Detecting ..." ) ); - for( uint8_t idx_u8 = 0U; idx_u8 < ME007_SENSOR_NUM_ERROR; ++idx_u8 ) + for ( uint8_t idx_u8 = 0U; idx_u8 < ME007_SENSOR_NUM_ERROR; ++idx_u8 ) { - bool detected_b = me007_measure( &me007_data_s.distance_cm_f32, - &me007_data_s.temperature_deg_f32 ); - if( true == detected_b ) + ME007_ERROR_TYPE detected_e = me007_measure( &me007_data_s.distance_cm_f32, + &me007_data_s.temperature_deg_f32 ); + if ( ME007_ERROR_TYPE_NONE == detected_e ) { me007_data_s.state_e = ME007_STATE_DETECTED; break; @@ -196,7 +217,7 @@ void me007_init( void ) DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "Measurement error: %i" ), idx_u8 ); } } - AddLog( LOG_LEVEL_INFO, PSTR( ME007_DEBUG_MSG_TAG "%s" ),me007_data_s.state_e == ME007_STATE_DETECTED ? "Detected" : "Not detected, Sensor deactivated" ); + AddLog( LOG_LEVEL_INFO, PSTR( ME007_DEBUG_MSG_TAG "%s" ), me007_data_s.state_e == ME007_STATE_DETECTED ? "Detected" : "Not detected, Sensor deactivated" ); } else { @@ -204,15 +225,13 @@ void me007_init( void ) } } -bool me007_measure( float* p_distance_cm_f32, float* p_temperature_f32 ) +ME007_ERROR_TYPE me007_measure( float* p_distance_cm_f32, float* p_temperature_f32 ) { - bool status_b = false; /**< @details Status io sensor reading, false: faulty reading, true: valid reading */ - ME007_SERIAL_RECEIVE_TYPE state_e = ME007_SERIAL_RECEIVE_TYPE_SOF; - uint8_t buffer_vu8[ME007_SERIAL_DATA_SIZE] = {0U}; - uint8_t buffer_idx_u8 = 0U; - uint8_t data_byte_u8 = 0U; - uint32_t timestamp_ms_u32 = 0U; - uint16_t data_receive_time_ms_u8 = 0U; + ME007_SERIAL_RECEIVE_TYPE state_e = ME007_SERIAL_RECEIVE_TYPE_SOF; /**< @details Always start trying to receive SOF */ + uint8_t buffer_vu8[ME007_SERIAL_FRAME_SIZE] = {0U}; + uint8_t buffer_idx_u8 = 0U; + uint8_t data_byte_u8 = 0U; + uint32_t timestamp_ms_u32 = 0U; if ( ( nullptr != p_distance_cm_f32 ) && ( nullptr != p_temperature_f32 ) @@ -220,23 +239,17 @@ bool me007_measure( float* p_distance_cm_f32, float* p_temperature_f32 ) { /* Trigger new sensor measurement */ digitalWrite( me007_data_s.pin_trig_u8, LOW ); - delay( ME007_TRIG_SIG_DURATION_MS ); /**< @details Wait 1ms to give the oin time to go low */ - digitalWrite( me007_data_s.pin_trig_u8, HIGH ); - - /* Store trigger time */ - timestamp_ms_u32 = millis(); - + timestamp_ms_u32 = millis(); /**< @details Store trigger time */ DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "Sensor reading triggered" ) ); + delay( ME007_TRIG_SIG_DURATION_MS ); /**< @details Wait 1ms to give the oin time to go low */ + digitalWrite( me007_data_s.pin_trig_u8, HIGH ); /* Give sensor some time to take a measurement and send the result */ /* Max. wait time is T2max + T3max = 61 ms (see https://wiki.dfrobot.com/Water-proof%20Ultrasonic%20Sensor%20(ULS)%20%20SKU:%20SEN0300, section "Serial Output" for details) */ - while ( ( timestamp_ms_u32 + ME007_SERIAL_MAX_WAIT_TIME + data_receive_time_ms_u8 ) >= millis() ) + while ( ( timestamp_ms_u32 + ME007_SERIAL_MAX_WAIT_TIME ) >= millis() ) { if ( 0U < p_SerialIf->available() ) { - /* Extend time to receive entire data frame */ - data_receive_time_ms_u8 = ME007_SERIAL_MAX_DATA_RECEIVE_TIME; - /* Read 1 byte of data */ data_byte_u8 = p_SerialIf->read(); @@ -248,112 +261,113 @@ bool me007_measure( float* p_distance_cm_f32, float* p_temperature_f32 ) if ( ME007_SERIAL_SOF == data_byte_u8 ) { buffer_vu8[buffer_idx_u8++] = data_byte_u8; - state_e = ME007_SERIAL_RECEIVE_TYPE_DATA; + state_e = ME007_SERIAL_RECEIVE_TYPE_DATA; DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "(Idx: %i) Serial: SOF detected" ), buffer_idx_u8 ); } break; case ME007_SERIAL_RECEIVE_TYPE_DATA: - buffer_vu8[buffer_idx_u8++] = data_byte_u8; - DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "(Idx: %i) Receiving distance/temperature data" ), buffer_idx_u8 ); + buffer_vu8[buffer_idx_u8++] = data_byte_u8; + DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "(Idx: %i) Receiving data: 0x%x" ), buffer_idx_u8, data_byte_u8 ); - /* Move to next state if 4 data bytes have been received */ - if( ME007_SERIAL_DATA_SIZE <= buffer_idx_u8 ) + /* If all bytes have been received: calculate checksum and assembly date */ + if ( ME007_SERIAL_FRAME_SIZE <= buffer_idx_u8 ) { - state_e = ME007_SERIAL_RECEIVE_TYPE_CHECKSUM; - } - break; + /* Calculate expected checksum (Only the the lower 8 bit shall be used) */ + uint8_t checksum_u8 = ( buffer_vu8[ME007_SERIAL_BYTE_TYPE_SOF] + + buffer_vu8[ME007_SERIAL_BYTE_TYPE_DIST_H] + + buffer_vu8[ME007_SERIAL_BYTE_TYPE_DIST_L] + + buffer_vu8[ME007_SERIAL_BYTE_TYPE_TEMP_H] + + buffer_vu8[ME007_SERIAL_BYTE_TYPE_TEMP_L] ) & 0x00FF; - case ME007_SERIAL_RECEIVE_TYPE_CHECKSUM: - /* Calculate expected checksum */ - uint16_t sum_u16 = 0U; - for( uint8_t idx_u8 = 0U; idx_u8 < ME007_SERIAL_DATA_SIZE; ++idx_u8 ) - { - sum_u16 += buffer_vu8[idx_u8]; - DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "Sum[%i]: %i (value: %i)"), idx_u8, sum_u16, buffer_vu8[idx_u8] ); - } - - /* Only the the lower 8 bit shall be used */ - sum_u16 &= 0x00FF; - - DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "Comparing expected sum %i to checksum %i" ), sum_u16, data_byte_u8 ); + DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "Comparing expected sum %i to checksum %i" ), checksum_u8, buffer_vu8[ME007_SERIAL_BYTE_TYPE_CHECKSUM] ); - /* Compare expected and receive checksum */ - if( sum_u16 == data_byte_u8 ) - { - /* Assemble and scale distance to cm */ - *p_distance_cm_f32 = ( ( buffer_vu8[1U] << 8U ) + buffer_vu8[2U] ) / 10.0F; - - /* Apply physical sensor measurement limits */ - if( ME007_MIN_SENSOR_DISTANCE > *p_distance_cm_f32 ) + /* Compare expected and receive checksum */ + if ( checksum_u8 == buffer_vu8[ME007_SERIAL_BYTE_TYPE_CHECKSUM] ) { - *p_distance_cm_f32 = 0.0F; - } - else if( ME007_MAX_SENSOR_DISTANCE < *p_distance_cm_f32 ) - { - *p_distance_cm_f32 = ME007_MAX_SENSOR_DISTANCE; + /* Assemble and scale distance to cm */ + *p_distance_cm_f32 = ( ( buffer_vu8[ME007_SERIAL_BYTE_TYPE_DIST_H] << 8U ) + buffer_vu8[ME007_SERIAL_BYTE_TYPE_DIST_L] ) / 10.0F; + + /* Apply physical sensor measurement limits */ + if ( ME007_MIN_SENSOR_DISTANCE > *p_distance_cm_f32 ) + { + *p_distance_cm_f32 = 0.0F; + } + else if ( ME007_MAX_SENSOR_DISTANCE < *p_distance_cm_f32 ) + { + *p_distance_cm_f32 = ME007_MAX_SENSOR_DISTANCE; + } + else + { + /* Ok: Measurement is within the physical sensor measurement limits */ + } + + /* Assemble and scale temperature °C */ + /* Check sign-bit (MSB) */ + if ( 0x80 == ( buffer_vu8[ME007_SERIAL_BYTE_TYPE_TEMP_H] & 0x80 ) ) + { + buffer_vu8[2U] ^= 0x80; + } + + *p_temperature_f32 = ( ( buffer_vu8[ME007_SERIAL_BYTE_TYPE_TEMP_H] << 8U ) + buffer_vu8[ME007_SERIAL_BYTE_TYPE_TEMP_L] ) / 10.0F; + + DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "Distance [cm]: %s, Temperature [deg]: %s" ), + String( *p_distance_cm_f32, 1U ).c_str(), + String( *p_temperature_f32, 1U ).c_str() ); + + /* All ok: Measurement valid */ + return ME007_ERROR_TYPE_NONE; } else { - /* Ok: Measurement is within the physical sensor measurement limits */ - } - - /* Assemble and scale temperature °C */ - /* Check sign-bit (MSB) */ - if( 0x80 == ( buffer_vu8[2U] & 0x80 ) ) - { - buffer_vu8[2U] ^= 0x80; + /* Checksum nok: Measurement invalid */ + return ME007_ERROR_TYPE_CRC; } - - *p_temperature_f32 = ( ( buffer_vu8[3U] << 8U ) + buffer_vu8[4U] ) / 10.0F; - - DEBUG_SENSOR_LOG( PSTR( ME007_DEBUG_MSG_TAG "Distance [cm]: %s, Temperature [deg]: %s"), - String( *p_distance_cm_f32, 1U ).c_str(), - String( *p_temperature_f32, 1U ).c_str() ); - - /* Early-return in case measurement is valid */ - return true; - } - else - { - /* status_b is set to false already */ } break; + + default: /* Should never happen */ + break; } } } } - return status_b; + + /* This point will only be reached in case of timeout */ + return ME007_ERROR_TYPE_TIMEOUT; } void me007_read_value( void ) { /* Record some sensor measurements */ - for ( uint8_t idx_u8 = 0U; idx_u8 < ME007_MEDIAN_FILTER_SIZE; ++idx_u8 ) + for ( uint8_t idx_u8 = 0U; idx_u8 < ME007_HIST_FILTER_SIZE; ++idx_u8 ) { - bool status_b = me007_measure( &me007_data_s.buffer_distance_cm_vf32[idx_u8], - &me007_data_s.temperature_deg_f32 ); + ME007_ERROR_TYPE status_e = me007_measure( &me007_data_s.buffer_distance_cm_vf32[idx_u8], + &me007_data_s.temperature_deg_f32 ); - if ( true == status_b ) + switch (status_e) { + case ME007_ERROR_TYPE_NONE: /* Apply histogram filter */ me007_data_s.distance_cm_f32 = me007_data_s.buffer_distance_cm_vf32[0]; - + if ( 0U < me007_data_s.error_cnt_current_u8 ) { me007_data_s.error_cnt_current_u8--; } - } - else - { + break; + + case ME007_ERROR_TYPE_CRC: me007_data_s.error_cnt_current_u8++; + me007_data_s.error_cnt_total_u16++; /* Store total number of measurement errors */ + break; - /* Store total number of measurement errors */ - me007_data_s.error_cnt_total_u16++; + default: /* Should never happen */ + break; } /* Check error counter and deactivate sensor in case error is present for ME007_SENSOR_NUM_ERROR cycles */ - if( ME007_SENSOR_NUM_ERROR <= me007_data_s.error_cnt_current_u8 ) + if ( ME007_SENSOR_NUM_ERROR <= me007_data_s.error_cnt_current_u8 ) { AddLog( LOG_LEVEL_ERROR, PSTR( ME007_DEBUG_MSG_TAG "Error @ counter: %i, Sensor deactivated" ), me007_data_s.error_cnt_current_u8 ); me007_data_s.state_e = ME007_STATE_NOT_DETECTED; @@ -362,17 +376,16 @@ void me007_read_value( void ) } } - void me007_show( uint8_t type_u8 ) { switch ( type_u8 ) { case ME007_SHOW_TYPE_JS: ResponseAppend_P( PSTR( ",\"" ME007_WS_MQTT_MSG_TAG "\":{\"" D_JSON_DISTANCE "\":%1_f,\"" D_JSON_TEMPERATURE "\":%1_f,\"" ME007_SENSOR_ERROR_CNT_CURRENT_TAG "\":%i,\"" ME007_SENSOR_ERROR_CNT_TOTAL_TAG "\":%i}" ), - &me007_data_s.distance_cm_f32, - &me007_data_s.temperature_deg_f32, - me007_data_s.error_cnt_current_u8, - me007_data_s.error_cnt_total_u16 ); + &me007_data_s.distance_cm_f32, + &me007_data_s.temperature_deg_f32, + me007_data_s.error_cnt_current_u8, + me007_data_s.error_cnt_total_u16 ); #ifdef USE_DOMOTICZ if ( 0U == TasmotaGlobal.tele_period ) { @@ -383,7 +396,7 @@ void me007_show( uint8_t type_u8 ) break; #ifdef USE_WEBSERVER case ME007_SHOW_TYPE_WS: - if( ME007_WS_SCALE_SWITCH_THRESH > me007_data_s.distance_cm_f32 ) + if ( ME007_WS_SCALE_SWITCH_THRESH > me007_data_s.distance_cm_f32 ) { WSContentSend_PD( HTTP_SNS_F_DISTANCE_CM, ME007_WS_MQTT_MSG_TAG, @@ -425,7 +438,7 @@ bool Xsns23( uint32_t function ) break; case FUNC_EVERY_SECOND: - if( ME007_STATE_DETECTED == me007_data_s.state_e ) + if ( ME007_STATE_DETECTED == me007_data_s.state_e ) { me007_read_value(); result_b = true; @@ -433,7 +446,7 @@ bool Xsns23( uint32_t function ) break; case FUNC_JSON_APPEND: - if (ME007_STATE_DETECTED == me007_data_s.state_e ) + if ( ME007_STATE_DETECTED == me007_data_s.state_e ) { me007_show( ME007_SHOW_TYPE_JS ); } @@ -441,7 +454,7 @@ bool Xsns23( uint32_t function ) #ifdef USE_WEBSERVER case FUNC_WEB_SENSOR: - if (ME007_STATE_DETECTED == me007_data_s.state_e ) + if ( ME007_STATE_DETECTED == me007_data_s.state_e ) { me007_show( ME007_SHOW_TYPE_WS ); }