From bc858f622de9a56c4cdd15144c0465d18e411bfb Mon Sep 17 00:00:00 2001 From: Serhii Salamakha Date: Tue, 24 Oct 2023 18:04:03 +0300 Subject: [PATCH] [Telink] Add Mars board overlay and real measurment of sht3xd sensor --- config/telink/chip-module/Kconfig | 5 + .../telink/CMakeLists.txt | 24 +++- .../telink/include/AppTask.h | 4 +- .../telink/include/SensorManager.h | 44 +++++++ .../air-quality-sensor-app/telink/prj.conf | 2 +- .../telink/src/AppTask.cpp | 95 ++++++++++++-- .../telink/src/SensorManager.cpp | 120 ++++++++++++++++++ src/platform/telink/tlsr9518adk80d_mars.conf | 4 + .../telink/tlsr9518adk80d_mars.overlay | 62 +++++++++ 9 files changed, 345 insertions(+), 15 deletions(-) create mode 100644 examples/air-quality-sensor-app/telink/include/SensorManager.h create mode 100644 examples/air-quality-sensor-app/telink/src/SensorManager.cpp create mode 100644 src/platform/telink/tlsr9518adk80d_mars.conf create mode 100644 src/platform/telink/tlsr9518adk80d_mars.overlay diff --git a/config/telink/chip-module/Kconfig b/config/telink/chip-module/Kconfig index b1bd07660937bd..93ebc31a0f426e 100644 --- a/config/telink/chip-module/Kconfig +++ b/config/telink/chip-module/Kconfig @@ -202,3 +202,8 @@ config CHIP_ENABLE_POWER_ON_FACTORY_RESET Enable power on factory reset sequence. If device power triggered off during first 5 seconds after power on and this sequence repeated 5 times - factory reset will be involved. + +config CHIP_USE_MARS_SENSOR + bool "Use Mars board sensor" + depends on SOC_SERIES_RISCV_TELINK_B9X && (BOARD_TLSR9518ADK80D || BOARD_TLSR9518ADK80D_RETENTION) + default n diff --git a/examples/air-quality-sensor-app/telink/CMakeLists.txt b/examples/air-quality-sensor-app/telink/CMakeLists.txt index fd5a5b14256426..a6148fe2933e2d 100644 --- a/examples/air-quality-sensor-app/telink/CMakeLists.txt +++ b/examples/air-quality-sensor-app/telink/CMakeLists.txt @@ -19,6 +19,23 @@ get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/connect get_filename_component(TELINK_COMMON ${CHIP_ROOT}/examples/platform/telink REALPATH) get_filename_component(GEN_DIR ${CHIP_ROOT}/zzz_generated/ REALPATH) +set(ignoreMe "${TLNK_MARS_BOARD}") + +if(${TLNK_MARS_BOARD} MATCHES y) + if(EXISTS "${CHIP_ROOT}/src/platform/telink/${BOARD}_mars.overlay") + set(MARS_DTC_OVERLAY_FILE "${CHIP_ROOT}/src/platform/telink/${BOARD}_mars.overlay") + else() + unset(MARS_DTC_OVERLAY_FILE) + endif() + if(EXISTS "${CHIP_ROOT}/src/platform/telink/${BOARD}_mars.conf") + set(MARS_CONF_OVERLAY_FILE "${CHIP_ROOT}/src/platform/telink/${BOARD}_mars.conf") + else() + unset(MARS_CONF_OVERLAY_FILE) + endif() +else() + unset(MARS_CONF_OVERLAY_FILE) +endif() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD}.overlay") set(LOCAL_DTC_OVERLAY_FILE "${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD}.overlay") else() @@ -41,14 +58,14 @@ endif() if(DTC_OVERLAY_FILE) set(DTC_OVERLAY_FILE - "${DTC_OVERLAY_FILE} ${GLOBAL_DTC_OVERLAY_FILE} ${FLASH_DTC_OVERLAY_FILE} ${LOCAL_DTC_OVERLAY_FILE}" + "${DTC_OVERLAY_FILE} ${GLOBAL_DTC_OVERLAY_FILE} ${MARS_DTC_OVERLAY_FILE} ${FLASH_DTC_OVERLAY_FILE} ${LOCAL_DTC_OVERLAY_FILE}" CACHE STRING "" FORCE ) else() - set(DTC_OVERLAY_FILE ${GLOBAL_DTC_OVERLAY_FILE} ${FLASH_DTC_OVERLAY_FILE} ${LOCAL_DTC_OVERLAY_FILE}) + set(DTC_OVERLAY_FILE ${GLOBAL_DTC_OVERLAY_FILE} ${MARS_DTC_OVERLAY_FILE} ${FLASH_DTC_OVERLAY_FILE} ${LOCAL_DTC_OVERLAY_FILE}) endif() -set(CONF_FILE prj.conf) +set(CONF_FILE ${MARS_CONF_OVERLAY_FILE} prj.conf) # Load NCS/Zephyr build system list(APPEND ZEPHYR_EXTRA_MODULES ${CHIP_ROOT}/config/telink/chip-module) @@ -75,6 +92,7 @@ add_definitions( target_sources(app PRIVATE src/AppTask.cpp + src/SensorManager.cpp src/ZclCallbacks.cpp ${TELINK_COMMON}/common/src/mainCommon.cpp ${TELINK_COMMON}/common/src/AppTaskCommon.cpp diff --git a/examples/air-quality-sensor-app/telink/include/AppTask.h b/examples/air-quality-sensor-app/telink/include/AppTask.h index a1b55a9b83108f..e76897cdd81d99 100644 --- a/examples/air-quality-sensor-app/telink/include/AppTask.h +++ b/examples/air-quality-sensor-app/telink/include/AppTask.h @@ -31,7 +31,9 @@ class AppTask : public AppTaskCommon CHIP_ERROR Init(void); - static void AirQualityActionEventHandler(AppEvent * aEvent); + static void AirQualitySensorMeasurTimerTimeoutCallback(k_timer * timer); + static void AirQualitySensorBanForNextMeasurTimerTimeoutCallback(k_timer * timer); + static void AirQualitySensorMeasurActionEventHandler(AppEvent * aEvent); static AppTask sAppTask; }; diff --git a/examples/air-quality-sensor-app/telink/include/SensorManager.h b/examples/air-quality-sensor-app/telink/include/SensorManager.h new file mode 100644 index 00000000000000..f545120df238ab --- /dev/null +++ b/examples/air-quality-sensor-app/telink/include/SensorManager.h @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "AppEventCommon.h" + +#include +#include + +class SensorManager +{ +public: + CHIP_ERROR Init(); + CHIP_ERROR GetTempAndHumMeasurValue(int16_t *pTempMeasured, uint16_t *pHumMeasured); + +private: + friend SensorManager & SensorMgr(); + + static SensorManager sSensorManager; +}; + +inline SensorManager & SensorMgr() +{ + return SensorManager::sSensorManager; +} diff --git a/examples/air-quality-sensor-app/telink/prj.conf b/examples/air-quality-sensor-app/telink/prj.conf index 703e78efb7ed4a..7bfa11f4891ea8 100644 --- a/examples/air-quality-sensor-app/telink/prj.conf +++ b/examples/air-quality-sensor-app/telink/prj.conf @@ -54,4 +54,4 @@ CONFIG_CHIP_FACTORY_DATA_BUILD=n CONFIG_CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE=n # Enable Power Management -CONFIG_PM=y +CONFIG_PM=n diff --git a/examples/air-quality-sensor-app/telink/src/AppTask.cpp b/examples/air-quality-sensor-app/telink/src/AppTask.cpp index 94988ea8bbe5a0..5e841faa8d5623 100644 --- a/examples/air-quality-sensor-app/telink/src/AppTask.cpp +++ b/examples/air-quality-sensor-app/telink/src/AppTask.cpp @@ -17,50 +17,125 @@ */ #include "AppTask.h" +#include "SensorManager.h" #include LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); +using namespace chip; using namespace ::chip::app::Clusters; using namespace ::chip::app::Clusters::AirQuality; -AppTask AppTask::sAppTask; +namespace { +volatile bool mSensorBanForNextMeasur = false; +k_timer sSensorMeasurTimer; +k_timer sSensorBanForNextMeasurTimer; +constexpr uint16_t kSensorMeasurTimerPeriodMs = 10000; // 10s timer period +constexpr uint16_t kSensorBanForNextMeasurTimeoutMs = 1000; // 1s timeout +} // namespace -constexpr EndpointId kAirQualityEndpoint = 1; +AppTask AppTask::sAppTask; CHIP_ERROR AppTask::Init(void) { + CHIP_ERROR ret; + #if APP_USE_EXAMPLE_START_BUTTON - SetExampleButtonCallbacks(AirQualityActionEventHandler); + SetExampleButtonCallbacks(AirQualitySensorMeasurActionEventHandler); #endif InitCommonParts(); - AirQualitySensorManager::InitInstance(kAirQualityEndpoint); + ret = SensorMgr().Init(); + if (ret != CHIP_NO_ERROR) + { + LOG_ERR("Init of the Sensor Manager failed"); + return ret; + } + + // Initialize sensor measurement timer + k_timer_init(&sSensorMeasurTimer, &AppTask::AirQualitySensorMeasurTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&sSensorMeasurTimer, this); + k_timer_start(&sSensorMeasurTimer, K_MSEC(kSensorMeasurTimerPeriodMs), K_NO_WAIT); + + // Initialise the timer to ban sensor measurement + k_timer_init(&sSensorBanForNextMeasurTimer, &AppTask::AirQualitySensorBanForNextMeasurTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&sSensorBanForNextMeasurTimer, this); + + AirQualitySensorManager::InitInstance(kExampleEndpointId); return CHIP_NO_ERROR; } void AppTask::UpdateClusterState(void) { + CHIP_ERROR ret; AirQualitySensorManager * mInstance = AirQualitySensorManager::GetInstance(); + static int16_t temperature = 0; + static uint16_t humidity = 0; + + if (!mSensorBanForNextMeasur) + { + ret = SensorMgr().GetTempAndHumMeasurValue(&temperature, &humidity); + if (ret != CHIP_NO_ERROR) + { + LOG_ERR("Update of the Air Quality clusters failed"); + return; + } + + mSensorBanForNextMeasur = true; + + // Start next timer to measurement the air quality sensor + k_timer_start(&sSensorBanForNextMeasurTimer, K_MSEC(kSensorBanForNextMeasurTimeoutMs), K_NO_WAIT); + } // Update AirQuality value - mInstance->OnAirQualityChangeHandler(AirQualityEnum::kModerate); + mInstance->OnAirQualityChangeHandler(AirQualityEnum::kUnknown); // Update Carbon Dioxide - mInstance->OnCarbonDioxideMeasurementChangeHandler(400); + mInstance->OnCarbonDioxideMeasurementChangeHandler(0); // Update Temperature value - mInstance->OnTemperatureMeasurementChangeHandler(18); + mInstance->OnTemperatureMeasurementChangeHandler(temperature); // Update Humidity value - mInstance->OnHumidityMeasurementChangeHandler(60); + mInstance->OnHumidityMeasurementChangeHandler(humidity); + + LOG_INF("Update Air Quality: temperature is %d*0.01°C, humidity is %d", temperature, humidity); } -void AppTask::AirQualityActionEventHandler(AppEvent * aEvent) +void AppTask::AirQualitySensorMeasurTimerTimeoutCallback(k_timer * timer) { - if (aEvent->Type == AppEvent::kEventType_Button) + if (!timer) + { + return; + } + + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.Handler = AirQualitySensorMeasurActionEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::AirQualitySensorBanForNextMeasurTimerTimeoutCallback(k_timer * timer) +{ + if (!timer) + { + return; + } + + mSensorBanForNextMeasur = false; +} + +void AppTask::AirQualitySensorMeasurActionEventHandler(AppEvent * aEvent) +{ + if ((aEvent->Type == AppEvent::kEventType_Button) || (aEvent->Type == AppEvent::kEventType_Timer)) { sAppTask.UpdateClusterState(); } + + if (aEvent->Type == AppEvent::kEventType_Timer) + { + // Start next timer to measurement the air quality sensor + k_timer_start(&sSensorMeasurTimer, K_MSEC(kSensorMeasurTimerPeriodMs), K_NO_WAIT); + } } diff --git a/examples/air-quality-sensor-app/telink/src/SensorManager.cpp b/examples/air-quality-sensor-app/telink/src/SensorManager.cpp new file mode 100644 index 00000000000000..de580ed9ba00fb --- /dev/null +++ b/examples/air-quality-sensor-app/telink/src/SensorManager.cpp @@ -0,0 +1,120 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SensorManager.h" +#include "AppConfig.h" +#include "AppTask.h" +#include + +LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); + +using namespace chip; +using namespace ::chip::DeviceLayer; + +constexpr float kMinTempDelta = 0.5; // 0.5 degree Celsius + +#ifdef CONFIG_CHIP_USE_MARS_SENSOR +const struct device *const sht3xd_dev = DEVICE_DT_GET_ONE(sensirion_sht3xd); +#elif +constexpr float kSimulatedHum = 55.5; // percents +constexpr uint16_t kSimulatedReadingFrequency = 5; // change Simulated number +static float mSimulatedTemp[] = { 23.01, 24.02, 28.03, 25.50, 22.05, 21.25, 21.07, 26.08, 18.09, 27.11 }; +#endif // CONFIG_CHIP_USE_MARS_SENSOR + +SensorManager SensorManager::sSensorManager; + +CHIP_ERROR SensorManager::Init() +{ +#ifdef CONFIG_CHIP_USE_MARS_SENSOR + if (!device_is_ready(sht3xd_dev)) + { + LOG_ERR("Device %s is not ready", sht3xd_dev->name); + return CHIP_ERROR_INCORRECT_STATE; + } +#endif // CONFIG_CHIP_USE_MARS_SENSOR + + return CHIP_NO_ERROR; +} + +CHIP_ERROR SensorManager::GetTempAndHumMeasurValue(int16_t *pTempMeasured, uint16_t *pHumMeasured) +{ + static float lastTemp = 0.0; + float temp = 0.0; + float hum = 0.0; + +#ifdef CONFIG_CHIP_USE_MARS_SENSOR + struct sensor_value sensorTemp = {0}; + struct sensor_value sensorHum = {0}; + + int status = sensor_sample_fetch(sht3xd_dev); + if (!status) + { + status = sensor_channel_get(sht3xd_dev, SENSOR_CHAN_AMBIENT_TEMP, &sensorTemp); + } + + if (!status) + { + status = sensor_channel_get(sht3xd_dev, SENSOR_CHAN_HUMIDITY, &sensorHum); + } + + if (status) + { + LOG_ERR("Device %s is not ready for temperature and humidity measurement (status: %d)", sht3xd_dev->name, status); + return System::MapErrorZephyr(status); + } + + temp = (float)sensor_value_to_double(&sensorTemp); + hum = (float)sensor_value_to_double(&sensorHum); +#else + /* Temperature simulation is used */ + static uint8_t nbOfRepetition = 0; + static uint8_t simulatedIndex = 0; + if (simulatedIndex >= ArraySize(mSimulatedTemp)) + { + simulatedIndex = 0; + } + temp = mSimulatedTemp[simulatedIndex]; + + nbOfRepetition++; + + if (nbOfRepetition >= kSimulatedReadingFrequency) + { + simulatedIndex++; + nbOfRepetition = 0; + } + + /* Humidity simulation is used */ + hum = kSimulatedHum; + +#endif // CONFIG_CHIP_USE_MARS_SENSOR + + if ((temp >= (lastTemp + kMinTempDelta)) || temp <= (lastTemp - kMinTempDelta)) + { + lastTemp = temp; + } + else + { + temp = lastTemp; + } + + // Per spec Application Clusters 2.3.4.1. : MeasuredValue = 100 x temperature [°C] + *pTempMeasured = (int16_t) 100 * temp; + *pHumMeasured = (uint16_t) hum; + + return CHIP_NO_ERROR; +} diff --git a/src/platform/telink/tlsr9518adk80d_mars.conf b/src/platform/telink/tlsr9518adk80d_mars.conf new file mode 100644 index 00000000000000..1c076febc2f4bd --- /dev/null +++ b/src/platform/telink/tlsr9518adk80d_mars.conf @@ -0,0 +1,4 @@ +CONFIG_CHIP_USE_MARS_SENSOR=y +CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE=y +CONFIG_I2C=y +CONFIG_SENSOR=y \ No newline at end of file diff --git a/src/platform/telink/tlsr9518adk80d_mars.overlay b/src/platform/telink/tlsr9518adk80d_mars.overlay new file mode 100644 index 00000000000000..87a2f67ae50d56 --- /dev/null +++ b/src/platform/telink/tlsr9518adk80d_mars.overlay @@ -0,0 +1,62 @@ +/ { + leds { + led_red: led_3 { + gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>; + label = "LED Red"; + }; + }; + + keys { + /delete-node/ button_1; + /delete-node/ button_3; + compatible = "gpio-keys"; + key_1: button_1 { + gpios = <&gpiod 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + key_2: button_2 { + gpios = <&gpiod 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + key_3: button_3 { + gpios = <&gpioc 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + key_4: button_4 { + gpios = <&gpiod 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + }; +}; + +&gpioc { + interrupts = <38 1>; +}; + +&gpiod { + interrupts = <37 1>; + status = "okay"; +}; + +&pinctrl { + /* Define I2C pins: SCL(PE0), SDA(PC2) */ + i2c_scl_pe0_default: i2c_scl_pe0_default { + pinmux = ; + }; + i2c_sda_pc2_default: i2c_sda_pc2_default { + pinmux = ; + }; + + pwm_ch4_pe4_default: pwm_ch4_pe4_default { + pinmux = ; + }; +}; + +&i2c { + pinctrl-0 = <&i2c_scl_pe0_default &i2c_sda_pc2_default>; + + sht3xd@44 { + compatible = "sensirion,sht3xd"; + reg = <0x44>; + }; +}; + +&pwm0 { + pinctrl-0 = <&pwm_ch0_pb4_default &pwm_ch1_pb5_default &pwm_ch2_pe2_default &pwm_ch4_pe4_default>; +};