diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index a6696b484..c98a0f2fc 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -149,6 +149,7 @@ const NavigationView::AppList NavigationView::appList = { {"search", "Search", RX, Color::yellow(), &bitmap_icon_search, new ViewFactory()}, {"subghzd", "SubGhzD", RX, Color::yellow(), &bitmap_icon_remote, new ViewFactory()}, {"weather", "Weather", RX, Color::green(), &bitmap_icon_thermometer, new ViewFactory()}, + //{"fskrx", "FSK RX", RX, Color::yellow(), &bitmap_icon_remote, new ViewFactory()}, //for JT //{"dmr", "DMR", RX, Color::dark_grey(), &bitmap_icon_dmr, new ViewFactory()}, //{"sigfox", "SIGFOX", RX, Color::dark_grey(), &bitmap_icon_fox, new ViewFactory()}, //{"lora", "LoRa", RX, Color::dark_grey(), &bitmap_icon_lora, new ViewFactory()}, diff --git a/firmware/common/i2cdev_ppmod.cpp b/firmware/common/i2cdev_ppmod.cpp index 68b53d75b..85000ef70 100644 --- a/firmware/common/i2cdev_ppmod.cpp +++ b/firmware/common/i2cdev_ppmod.cpp @@ -21,7 +21,6 @@ #include "i2cdev_ppmod.hpp" #include "portapack.hpp" - #include namespace i2cdev { @@ -30,11 +29,95 @@ bool I2cDev_PPmod::init(uint8_t addr_) { if (addr_ != I2CDEV_PPMOD_ADDR_1) return false; addr = addr_; model = I2CDECMDL_PPMOD; + query_interval = 10; return true; } void I2cDev_PPmod::update() { + auto mask = get_features_mask(); + if (mask & (uint64_t)SupportedFeatures::FEAT_GPS) { + auto data = get_gps_data(); + if (data.has_value()) { + GPSPosDataMessage msg{data.value().latitude, data.value().longitude, (int32_t)data.value().altitude, (int32_t)data.value().speed, data.value().sats_in_use}; + EventDispatcher::send_message(msg); + } + } + if (mask & (uint64_t)SupportedFeatures::FEAT_ORIENTATION) { + auto data = get_orientation_data(); + if (data.has_value()) { + OrientationDataMessage msg{(uint16_t)data.value().angle, (int16_t)data.value().tilt}; + EventDispatcher::send_message(msg); + } + } + if (mask & (uint64_t)SupportedFeatures::FEAT_ENVIRONMENT) { + auto data = get_environment_data(); + if (data.has_value()) { + EnvironmentDataMessage msg{data.value().temperature, data.value().humidity, data.value().pressure}; + EventDispatcher::send_message(msg); + } + } + if (mask & (uint64_t)SupportedFeatures::FEAT_LIGHT) { + auto data = get_light_data(); + if (data.has_value()) { + LightDataMessage msg{data.value()}; + EventDispatcher::send_message(msg); + } + } +} + +std::optional I2cDev_PPmod::get_orientation_data() { + Command cmd = Command::COMMAND_GETFEAT_DATA_ORIENTATION; + orientation_t data; + bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(orientation_t)); + if (success == false) { + return std::nullopt; + } + return data; +} + +std::optional I2cDev_PPmod::get_gps_data() { + Command cmd = Command::COMMAND_GETFEAT_DATA_GPS; + gpssmall_t data; + bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(gpssmall_t)); + if (success == false) { + return std::nullopt; + } + return data; +} + +std::optional I2cDev_PPmod::get_environment_data() { + Command cmd = Command::COMMAND_GETFEAT_DATA_ENVIRONMENT; + environment_t data; + bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(environment_t)); + if (success == false) { + return std::nullopt; + } + return data; +} + +std::optional I2cDev_PPmod::get_light_data() { + Command cmd = Command::COMMAND_GETFEAT_DATA_LIGHT; + uint16_t data; + bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(uint16_t)); + if (success == false) { + return std::nullopt; + } + return data; +} + +uint64_t I2cDev_PPmod::get_features_mask() { + uint64_t mask = 0; + Command cmd = Command::COMMAND_GETFEATURE_MASK; + bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&mask, sizeof(mask)); + if (success == false) { + return 0; + } + // sanity check + if (mask == UINT64_MAX) { + return 0; + } + return mask; } std::optional I2cDev_PPmod::readDeviceInfo() { @@ -45,7 +128,10 @@ std::optional I2cDev_PPmod::readDeviceInfo() { if (success == false) { return std::nullopt; } - + // sanity check + if (info.application_count > 1000) { + return std::nullopt; + } return info; } @@ -58,6 +144,10 @@ std::optional I2cDev_PPmod::getStandaloneAppI if (success == false) { return std::nullopt; } + // sanity check + if (info.binary_size == UINT32_MAX) { + return std::nullopt; + } return info; } diff --git a/firmware/common/i2cdev_ppmod.hpp b/firmware/common/i2cdev_ppmod.hpp index 56dc5713b..4341ff6f1 100644 --- a/firmware/common/i2cdev_ppmod.hpp +++ b/firmware/common/i2cdev_ppmod.hpp @@ -30,6 +30,8 @@ #include "standalone_app.hpp" #include "i2cdevmanager.hpp" +#include "i2cdev_ppmod_helper.hpp" + namespace i2cdev { class I2cDev_PPmod : public I2cDev { @@ -38,13 +40,22 @@ class I2cDev_PPmod : public I2cDev { COMMAND_NONE = 0, // will respond with device_info - COMMAND_INFO = 0x18F0, + COMMAND_INFO = 1, // will respond with info of application - COMMAND_APP_INFO = 0xA90B, + COMMAND_APP_INFO, // will respond with application data - COMMAND_APP_TRANSFER = 0x4183, + COMMAND_APP_TRANSFER, + + // Feature specific commands + COMMAND_GETFEATURE_MASK, + // Feature data getter commands + COMMAND_GETFEAT_DATA_GPS, + COMMAND_GETFEAT_DATA_ORIENTATION, + COMMAND_GETFEAT_DATA_ENVIRONMENT, + COMMAND_GETFEAT_DATA_LIGHT, + }; typedef struct { @@ -66,9 +77,14 @@ class I2cDev_PPmod : public I2cDev { bool init(uint8_t addr_) override; void update() override; - std::optional readDeviceInfo(); std::optional getStandaloneAppInfo(uint32_t index); std::vector downloadStandaloneApp(uint32_t index, size_t offset); + uint64_t get_features_mask(); + std::optional readDeviceInfo(); + std::optional get_gps_data(); + std::optional get_orientation_data(); + std::optional get_environment_data(); + std::optional get_light_data(); }; } /* namespace i2cdev */ diff --git a/firmware/common/i2cdev_ppmod_helper.hpp b/firmware/common/i2cdev_ppmod_helper.hpp new file mode 100644 index 000000000..6a2dc0799 --- /dev/null +++ b/firmware/common/i2cdev_ppmod_helper.hpp @@ -0,0 +1,59 @@ +#ifndef I2CDEV_PPMOD_HELPER_H +#define I2CDEV_PPMOD_HELPER_H + +#include + +enum class SupportedFeatures : uint64_t { + FEAT_NONE = 0, + FEAT_EXT_APP = 1 << 0, + FEAT_UART = 1 << 1, + FEAT_GPS = 1 << 2, + FEAT_ORIENTATION = 1 << 3, + FEAT_ENVIRONMENT = 1 << 4, + FEAT_LIGHT = 1 << 5, + FEAT_DISPLAY = 1 << 6 +}; + +typedef struct +{ + uint8_t hour; /*!< Hour */ + uint8_t minute; /*!< Minute */ + uint8_t second; /*!< Second */ + uint16_t thousand; /*!< Thousand */ +} gps_time_t; + +typedef struct +{ + uint8_t day; /*!< Day (start from 1) */ + uint8_t month; /*!< Month (start from 1) */ + uint16_t year; /*!< Year (start from 2000) */ +} gps_date_t; + +typedef struct +{ + float latitude; /*!< Latitude (degrees) */ + float longitude; /*!< Longitude (degrees) */ + float altitude; /*!< Altitude (meters) */ + uint8_t sats_in_use; /*!< Number of satellites in use */ + uint8_t sats_in_view; /*!< Number of satellites in view */ + float speed; /*!< Ground speed, unit: m/s */ + gps_date_t date; /*!< Fix date */ + gps_time_t tim; /*!< time in UTC */ +} gpssmall_t; + +typedef struct +{ + float angle; + float tilt; +} orientation_t; + +typedef struct +{ + float temperature; + float humidity; + float pressure; +} environment_t; + +// light is uint16_t + +#endif \ No newline at end of file diff --git a/firmware/common/i2cdevmanager.cpp b/firmware/common/i2cdevmanager.cpp index 3a83e14f3..c04a9c98d 100644 --- a/firmware/common/i2cdevmanager.cpp +++ b/firmware/common/i2cdevmanager.cpp @@ -131,8 +131,13 @@ void I2cDev::got_success() { bool I2cDev::i2c_read(uint8_t* reg, uint8_t reg_size, uint8_t* data, uint8_t bytes) { if (bytes == 0) return false; - if (reg_size > 0 && reg) i2cbus.transmit(addr, reg, reg_size); - bool ret = i2cbus.receive(addr, data, bytes); + bool ret = true; + if (reg_size > 0 && reg) ret = i2cbus.transmit(addr, reg, reg_size, 150); + if (!ret) { + got_error(); + return false; + } + ret = i2cbus.receive(addr, data, bytes, 150); if (!ret) got_error(); else @@ -153,7 +158,7 @@ bool I2cDev::i2c_write(uint8_t* reg, uint8_t reg_size, uint8_t* data, uint8_t by // Copy the data into the buffer after the register data memcpy(buffer + reg_size, data, bytes); // Transmit the combined data - bool result = i2cbus.transmit(addr, buffer, total_size); + bool result = i2cbus.transmit(addr, buffer, total_size, 150); // Clean up the dynamically allocated buffer delete[] buffer; if (!result) @@ -304,7 +309,7 @@ msg_t I2CDevManager::timer_fn(void* arg) { force_scan = false; } for (size_t i = 0; i < devlist.size(); i++) { - if (devlist[i].addr != 0 && devlist[i].dev) { + if (devlist[i].addr != 0 && devlist[i].dev && devlist[i].dev->query_interval != 0) { if ((curr_timer % devlist[i].dev->query_interval) == 0) { // only if it is device's interval devlist[i].dev->update(); // updates it's data, and broadcasts it. if there is any error it will handle in it, and later we can remove it }