New memory address for i2c dev loaded apps (#2817)

* New memory address for i2c dev loaded apps

* better download handling on error

* new hackrf version (added PortapackRf support)

* lock i2cdev while loading apps
This commit is contained in:
Totoo 2025-10-14 09:45:52 +02:00 committed by GitHub
parent 54d99945f2
commit 2f4d222403
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 52 additions and 10 deletions

View file

@ -132,20 +132,36 @@ namespace ui {
gridItem.on_select = [&nav, appInfo, i]() { gridItem.on_select = [&nav, appInfo, i]() {
auto dev2 = (i2cdev::I2cDev_PPmod*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDECMDL_PPMOD); auto dev2 = (i2cdev::I2cDev_PPmod*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDECMDL_PPMOD);
dev2->lockDevice();
if (dev2) { if (dev2) {
auto app_image = reinterpret_cast<uint8_t*>(portapack::memory::map::m4_code.end() - appInfo->binary_size); // auto app_image = reinterpret_cast<uint8_t*>(portapack::memory::map::m4_code.end() - appInfo->binary_size);
auto app_image = reinterpret_cast<uint8_t*>(portapack::memory::map::local_sram_0.base());
uint8_t errorcnt = 0;
for (size_t j = 0; j < appInfo->binary_size; j += 128) { for (size_t j = 0; j < appInfo->binary_size; j += 128) {
auto segment = dev2->downloadStandaloneApp(i, j); errorcnt = 0;
if (segment.size() != 128) { do {
continue; auto segment = dev2->downloadStandaloneApp(i, j);
if (segment.size() != 128) {
errorcnt++;
if (errorcnt > 5) {
break;
}
} else {
std::copy(segment.begin(), segment.end(), app_image + j);
break;
}
} while (1); // when ok, break. when errorcnt > 5, break
if (errorcnt > 5) {
nav.display_modal("Error", "Unable to download app.");
dev2->unlockDevice();
return;
} }
std::copy(segment.begin(), segment.end(), app_image + j);
} }
if (!run_module_app(nav, app_image, appInfo->binary_size)) { if (!run_module_app(nav, app_image, appInfo->binary_size)) {
nav.display_modal("Error", "Unable to run downloaded app."); nav.display_modal("Error", "Unable to run downloaded app.");
} }
dev2->unlockDevice();
} else } else
nav.display_modal("Error", "Unable to download app."); nav.display_modal("Error", "Unable to download app.");
}; };
@ -346,7 +362,6 @@ namespace ui {
if (openError) if (openError)
return false; return false;
// TODO: move this to m4 memory space
auto app_image = reinterpret_cast<uint8_t*>(portapack::memory::map::local_sram_0.base()); auto app_image = reinterpret_cast<uint8_t*>(portapack::memory::map::local_sram_0.base());
// read file in 512 byte chunks // read file in 512 byte chunks

View file

@ -46,6 +46,7 @@ bool I2cDev_PPmod::init(uint8_t addr_) {
} }
void I2cDev_PPmod::update() { void I2cDev_PPmod::update() {
if (isLocked()) return; // device is busy
// mask = get_features_mask(); //saved on init. replug device if something changed. //needs to revise when modules come out. // mask = get_features_mask(); //saved on init. replug device if something changed. //needs to revise when modules come out.
if (mask & (uint64_t)SupportedFeatures::FEAT_GPS && self_timer % SENSORUPDATETIME == 0) { if (mask & (uint64_t)SupportedFeatures::FEAT_GPS && self_timer % SENSORUPDATETIME == 0) {
auto data = get_gps_data(); auto data = get_gps_data();
@ -101,11 +102,13 @@ void I2cDev_PPmod::update() {
} }
bool I2cDev_PPmod::get_shell_get_buffer_data(uint8_t* buff, size_t len) { bool I2cDev_PPmod::get_shell_get_buffer_data(uint8_t* buff, size_t len) {
if (isLocked()) return false; // device is busy
Command cmd = Command::COMMAND_SHELL_MODTOPP_DATA; Command cmd = Command::COMMAND_SHELL_MODTOPP_DATA;
return i2c_read((uint8_t*)&cmd, 2, buff, len); return i2c_read((uint8_t*)&cmd, 2, buff, len);
} }
std::optional<orientation_t> I2cDev_PPmod::get_orientation_data() { std::optional<orientation_t> I2cDev_PPmod::get_orientation_data() {
if (isLocked()) return std::nullopt; // device is busy
Command cmd = Command::COMMAND_GETFEAT_DATA_ORIENTATION; Command cmd = Command::COMMAND_GETFEAT_DATA_ORIENTATION;
orientation_t data; orientation_t data;
bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(orientation_t)); bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(orientation_t));
@ -116,6 +119,7 @@ std::optional<orientation_t> I2cDev_PPmod::get_orientation_data() {
} }
std::optional<gpssmall_t> I2cDev_PPmod::get_gps_data() { std::optional<gpssmall_t> I2cDev_PPmod::get_gps_data() {
if (isLocked()) return std::nullopt; // device is busy
Command cmd = Command::COMMAND_GETFEAT_DATA_GPS; Command cmd = Command::COMMAND_GETFEAT_DATA_GPS;
gpssmall_t data; gpssmall_t data;
bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(gpssmall_t)); bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(gpssmall_t));
@ -126,6 +130,7 @@ std::optional<gpssmall_t> I2cDev_PPmod::get_gps_data() {
} }
std::optional<environment_t> I2cDev_PPmod::get_environment_data() { std::optional<environment_t> I2cDev_PPmod::get_environment_data() {
if (isLocked()) return std::nullopt; // device is busy
Command cmd = Command::COMMAND_GETFEAT_DATA_ENVIRONMENT; Command cmd = Command::COMMAND_GETFEAT_DATA_ENVIRONMENT;
environment_t data; environment_t data;
bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(environment_t)); bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(environment_t));
@ -136,6 +141,7 @@ std::optional<environment_t> I2cDev_PPmod::get_environment_data() {
} }
std::optional<uint16_t> I2cDev_PPmod::get_light_data() { std::optional<uint16_t> I2cDev_PPmod::get_light_data() {
if (isLocked()) return std::nullopt; // device is busy
Command cmd = Command::COMMAND_GETFEAT_DATA_LIGHT; Command cmd = Command::COMMAND_GETFEAT_DATA_LIGHT;
uint16_t data; uint16_t data;
bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(uint16_t)); bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(uint16_t));
@ -146,6 +152,7 @@ std::optional<uint16_t> I2cDev_PPmod::get_light_data() {
} }
uint16_t I2cDev_PPmod::get_shell_buffer_bytes() { uint16_t I2cDev_PPmod::get_shell_buffer_bytes() {
if (isLocked()) return 0; // device is busy
Command cmd = Command::COMMAND_SHELL_MODTOPP_DATA_SIZE; Command cmd = Command::COMMAND_SHELL_MODTOPP_DATA_SIZE;
uint16_t data; uint16_t data;
bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(uint16_t)); bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&data, sizeof(uint16_t));
@ -156,6 +163,7 @@ uint16_t I2cDev_PPmod::get_shell_buffer_bytes() {
} }
uint64_t I2cDev_PPmod::get_features_mask() { uint64_t I2cDev_PPmod::get_features_mask() {
if (isLocked()) return 0; // device is busy
uint64_t mask_ = 0; uint64_t mask_ = 0;
Command cmd = Command::COMMAND_GETFEATURE_MASK; Command cmd = Command::COMMAND_GETFEATURE_MASK;
bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&mask_, sizeof(mask_)); bool success = i2c_read((uint8_t*)&cmd, 2, (uint8_t*)&mask_, sizeof(mask_));
@ -170,6 +178,7 @@ uint64_t I2cDev_PPmod::get_features_mask() {
} }
std::optional<I2cDev_PPmod::device_info> I2cDev_PPmod::readDeviceInfo() { std::optional<I2cDev_PPmod::device_info> I2cDev_PPmod::readDeviceInfo() {
if (isLocked()) return std::nullopt; // device is busy
Command cmd = Command::COMMAND_INFO; Command cmd = Command::COMMAND_INFO;
I2cDev_PPmod::device_info info; I2cDev_PPmod::device_info info;

View file

@ -108,6 +108,19 @@ FROM HERE YOU SHOULDN'T WRITE ANYTHING IF YOU JUST IMPLEMENT A NEW DRIVER
*/ */
void I2cDev::unlockDevice() {
mtx = 0;
}
// when device is locked, all not important queries will return 0 or nullopt, so no communication broken.
bool I2cDev::lockDevice() {
if (mtx == 0) {
mtx = 1;
return true;
}
return false;
}
void I2cDev::set_update_interval(uint8_t interval) { void I2cDev::set_update_interval(uint8_t interval) {
query_interval = interval; query_interval = interval;
} }

View file

@ -41,8 +41,8 @@ namespace i2cdev {
class I2cDev { class I2cDev {
public: public:
virtual ~I2cDev(){}; virtual ~I2cDev(){};
virtual bool init(uint8_t addr); // returns true if it is that that device we are looking for. virtual bool init(uint8_t addr) = 0; // returns true if it is that that device we are looking for.
virtual void update() = 0; // override this, and you'll be able to query your device and broadcast the result to the system virtual void update() = 0; // override this, and you'll be able to query your device and broadcast the result to the system
void set_update_interval(uint8_t interval); // sets the device's update interval in sec. if you change it, don't forget to change back to it's original value after you finished! void set_update_interval(uint8_t interval); // sets the device's update interval in sec. if you change it, don't forget to change back to it's original value after you finished!
uint8_t get_update_interval(); // gets the device's update interval in sec uint8_t get_update_interval(); // gets the device's update interval in sec
@ -59,6 +59,10 @@ class I2cDev {
int16_t readS16_LE_1(uint8_t reg); int16_t readS16_LE_1(uint8_t reg);
uint32_t read24_1(uint8_t reg); uint32_t read24_1(uint8_t reg);
bool lockDevice(); // locks the device's "mutex". returns true on success. guard important communication with this
void unlockDevice(); // unlocks the device's "mutex"
inline bool isLocked() { return mtx != 0; }
bool need_del = false; // device can self destruct, and re-init when new scan discovers it bool need_del = false; // device can self destruct, and re-init when new scan discovers it
I2C_DEVMDL model = I2CDEVMDL_NOTSET; // overwrite it in the init()!!! I2C_DEVMDL model = I2CDEVMDL_NOTSET; // overwrite it in the init()!!!
uint8_t query_interval = 5; // in seconds. can be overriden in init() if necessary uint8_t query_interval = 5; // in seconds. can be overriden in init() if necessary
@ -68,6 +72,7 @@ class I2cDev {
uint8_t addr = 0; // some devices can have different addresses, so we store what was it wound with uint8_t addr = 0; // some devices can have different addresses, so we store what was it wound with
uint8_t errcnt = 0; // error count during communication. if it reaches a threshold set need_del to remove itself from the device list uint8_t errcnt = 0; // error count during communication. if it reaches a threshold set need_del to remove itself from the device list
uint8_t mtx = 0; // internal lock, so important client code can be skipped when lock is on. check PPMod for an example
}; };
// store for the devices. may not have a driver if not supported // store for the devices. may not have a driver if not supported

2
hackrf

@ -1 +1 @@
Subproject commit 651d0a7f232e12016b3b12fb6a9b3fea08eb52fd Subproject commit 03e4732a5308a3d0de5b0341004d7a2fcc825806