Skip to content

Commit

Permalink
I2cDev_PPmod periodic sensor query (#2315)
Browse files Browse the repository at this point in the history
* Add more data tx from esp

* command enum rework. +1 for JT

* filter 0 query interval

* i2c timeouts and sanity check on ppmod
  • Loading branch information
htotoo authored Oct 19, 2024
1 parent 7a38b04 commit c90f094
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 10 deletions.
1 change: 1 addition & 0 deletions firmware/application/ui_navigation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ const NavigationView::AppList NavigationView::appList = {
{"search", "Search", RX, Color::yellow(), &bitmap_icon_search, new ViewFactory<SearchView>()},
{"subghzd", "SubGhzD", RX, Color::yellow(), &bitmap_icon_remote, new ViewFactory<SubGhzDView>()},
{"weather", "Weather", RX, Color::green(), &bitmap_icon_thermometer, new ViewFactory<WeatherView>()},
//{"fskrx", "FSK RX", RX, Color::yellow(), &bitmap_icon_remote, new ViewFactory<FskxRxMainView>()}, //for JT
//{"dmr", "DMR", RX, Color::dark_grey(), &bitmap_icon_dmr, new ViewFactory<NotImplementedView>()},
//{"sigfox", "SIGFOX", RX, Color::dark_grey(), &bitmap_icon_fox, new ViewFactory<NotImplementedView>()},
//{"lora", "LoRa", RX, Color::dark_grey(), &bitmap_icon_lora, new ViewFactory<NotImplementedView>()},
Expand Down
94 changes: 92 additions & 2 deletions firmware/common/i2cdev_ppmod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

#include "i2cdev_ppmod.hpp"
#include "portapack.hpp"

#include <optional>

namespace i2cdev {
Expand All @@ -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<orientation_t> 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<gpssmall_t> 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<environment_t> 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<uint16_t> 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::device_info> I2cDev_PPmod::readDeviceInfo() {
Expand All @@ -45,7 +128,10 @@ std::optional<I2cDev_PPmod::device_info> I2cDev_PPmod::readDeviceInfo() {
if (success == false) {
return std::nullopt;
}

// sanity check
if (info.application_count > 1000) {
return std::nullopt;
}
return info;
}

Expand All @@ -58,6 +144,10 @@ std::optional<I2cDev_PPmod::standalone_app_info> I2cDev_PPmod::getStandaloneAppI
if (success == false) {
return std::nullopt;
}
// sanity check
if (info.binary_size == UINT32_MAX) {
return std::nullopt;
}

return info;
}
Expand Down
24 changes: 20 additions & 4 deletions firmware/common/i2cdev_ppmod.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include "standalone_app.hpp"
#include "i2cdevmanager.hpp"

#include "i2cdev_ppmod_helper.hpp"

namespace i2cdev {

class I2cDev_PPmod : public I2cDev {
Expand All @@ -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 {
Expand All @@ -66,9 +77,14 @@ class I2cDev_PPmod : public I2cDev {
bool init(uint8_t addr_) override;
void update() override;

std::optional<device_info> readDeviceInfo();
std::optional<standalone_app_info> getStandaloneAppInfo(uint32_t index);
std::vector<uint8_t> downloadStandaloneApp(uint32_t index, size_t offset);
uint64_t get_features_mask();
std::optional<device_info> readDeviceInfo();
std::optional<gpssmall_t> get_gps_data();
std::optional<orientation_t> get_orientation_data();
std::optional<environment_t> get_environment_data();
std::optional<uint16_t> get_light_data();
};

} /* namespace i2cdev */
Expand Down
59 changes: 59 additions & 0 deletions firmware/common/i2cdev_ppmod_helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#ifndef I2CDEV_PPMOD_HELPER_H
#define I2CDEV_PPMOD_HELPER_H

#include <cstdint>

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
13 changes: 9 additions & 4 deletions firmware/common/i2cdevmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down

0 comments on commit c90f094

Please sign in to comment.