mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-01-09 23:43:39 +00:00
I2C device manager (#2282)
* message on dev list change * dc detect * added sht3x sensor. * separete environment data from light * max17055 moved to i2c dev * sht fix, goterror detection fix * fix ext sensor app display for a lot of devices. * added bh1750 driver * autoscan on main view * added devlist mutex * better timing * fix h2 sw8 on poweron by usb
This commit is contained in:
parent
d4edb5f5f9
commit
83b65ba6ce
@ -125,6 +125,9 @@ set(CSRC
|
|||||||
${CHIBIOS}/os/various/chprintf.c
|
${CHIBIOS}/os/various/chprintf.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#look for all i2cdev_ files
|
||||||
|
file(GLOB I2CDEV_SOURCES ${COMMON}/i2cdev_*.cpp)
|
||||||
|
|
||||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
# setting.
|
# setting.
|
||||||
set(CPPSRC
|
set(CPPSRC
|
||||||
@ -176,8 +179,8 @@ set(CPPSRC
|
|||||||
${COMMON}/ui_language.cpp
|
${COMMON}/ui_language.cpp
|
||||||
${COMMON}/utility.cpp
|
${COMMON}/utility.cpp
|
||||||
${COMMON}/wm8731.cpp
|
${COMMON}/wm8731.cpp
|
||||||
${COMMON}/ads1110.cpp
|
${COMMON}/i2cdevmanager.cpp
|
||||||
${COMMON}/max17055.cpp
|
${I2CDEV_SOURCES}
|
||||||
${COMMON}/battery.cpp
|
${COMMON}/battery.cpp
|
||||||
${COMMON}/performance_counter.cpp
|
${COMMON}/performance_counter.cpp
|
||||||
${COMMON}/bmpfile.cpp
|
${COMMON}/bmpfile.cpp
|
||||||
@ -292,7 +295,7 @@ set(CPPSRC
|
|||||||
apps/ui_btle_rx.cpp
|
apps/ui_btle_rx.cpp
|
||||||
# apps/ui_coasterp.cpp
|
# apps/ui_coasterp.cpp
|
||||||
apps/ui_debug.cpp
|
apps/ui_debug.cpp
|
||||||
apps/ui_debug_battery.cpp
|
apps/ui_debug_max17055.cpp
|
||||||
apps/ui_dfu_menu.cpp
|
apps/ui_dfu_menu.cpp
|
||||||
apps/ui_encoders.cpp
|
apps/ui_encoders.cpp
|
||||||
apps/ui_fileman.cpp
|
apps/ui_fileman.cpp
|
||||||
|
@ -43,87 +43,86 @@ void BattinfoView::on_timer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattinfoView::update_result() {
|
void BattinfoView::update_results_ads1110(i2cdev::I2cDev_ADS1110* dev) {
|
||||||
if (!battery::BatteryManagement::isDetected()) {
|
|
||||||
text_percent.set("UNKNOWN");
|
|
||||||
text_voltage.set("UNKNOWN");
|
|
||||||
text_current.set("-");
|
|
||||||
text_charge.set("-");
|
|
||||||
text_cycles.set("-");
|
|
||||||
text_ttef.set("-");
|
|
||||||
text_method.set("-");
|
|
||||||
text_warn.set("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bool uichg = false;
|
bool uichg = false;
|
||||||
uint8_t valid_mask = 0;
|
auto voltage = dev->readVoltage();
|
||||||
battery::BatteryManagement::getBatteryInfo(valid_mask, percent, voltage, current);
|
auto percent = battery::BatteryManagement::calc_percent_voltage(voltage);
|
||||||
// update text fields
|
if (percent <= 100)
|
||||||
if (percent <= 100 && (valid_mask & battery::BatteryManagement::BATT_VALID_VOLTAGE) == battery::BatteryManagement::BATT_VALID_VOLTAGE)
|
|
||||||
text_percent.set(to_string_dec_uint(percent) + " %");
|
text_percent.set(to_string_dec_uint(percent) + " %");
|
||||||
else
|
else
|
||||||
text_percent.set("UNKNOWN");
|
text_percent.set("UNKNOWN");
|
||||||
if (voltage > 1 && (valid_mask & battery::BatteryManagement::BATT_VALID_VOLTAGE) == battery::BatteryManagement::BATT_VALID_VOLTAGE) {
|
if (voltage > 1) {
|
||||||
text_voltage.set(to_string_decimal(voltage / 1000.0, 3) + " V");
|
text_voltage.set(to_string_decimal(voltage / 1000.0, 3) + " V");
|
||||||
} else {
|
} else {
|
||||||
text_voltage.set("UNKNOWN");
|
text_voltage.set("UNKNOWN");
|
||||||
}
|
}
|
||||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_CURRENT) == battery::BatteryManagement::BATT_VALID_CURRENT) {
|
|
||||||
if (labels_opt.hidden()) uichg = true;
|
|
||||||
labels_opt.hidden(false);
|
|
||||||
text_current.hidden(false);
|
|
||||||
text_charge.hidden(false);
|
|
||||||
text_current.set(to_string_dec_int(current) + " mA");
|
|
||||||
text_charge.set(current >= 0 ? "Charging" : "Discharging");
|
|
||||||
labels_opt.hidden(false);
|
|
||||||
|
|
||||||
text_ttef.hidden(false);
|
// ui hide:
|
||||||
|
if (!labels_opt.hidden()) uichg = true;
|
||||||
|
labels_opt.hidden(true);
|
||||||
|
text_current.hidden(true);
|
||||||
|
text_charge.hidden(true);
|
||||||
|
labels_opt.hidden(true);
|
||||||
|
text_ttef.hidden(true);
|
||||||
|
text_cycles.hidden(true);
|
||||||
|
text_warn.set("");
|
||||||
|
text_ttef.hidden(true);
|
||||||
|
text_method.set("Voltage");
|
||||||
|
button_mode.set_text("Voltage");
|
||||||
|
if (uichg) set_dirty();
|
||||||
|
BatteryStateMessage msg{1, percent, false, voltage};
|
||||||
|
EventDispatcher::send_message(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BattinfoView::update_results_max17055(i2cdev::I2cDev_MAX17055* dev) {
|
||||||
|
bool uichg = false;
|
||||||
|
uint8_t valid_mask = 0;
|
||||||
|
dev->getBatteryInfo(valid_mask, percent, voltage, current);
|
||||||
|
// update text fields
|
||||||
|
if (percent <= 100)
|
||||||
|
text_percent.set(to_string_dec_uint(percent) + " %");
|
||||||
|
else
|
||||||
|
text_percent.set("UNKNOWN");
|
||||||
|
if (voltage > 1) {
|
||||||
|
text_voltage.set(to_string_decimal(voltage / 1000.0, 3) + " V");
|
||||||
} else {
|
} else {
|
||||||
if (!labels_opt.hidden()) uichg = true;
|
text_voltage.set("UNKNOWN");
|
||||||
labels_opt.hidden(true);
|
}
|
||||||
text_current.hidden(true);
|
if (labels_opt.hidden()) uichg = true;
|
||||||
text_charge.hidden(true);
|
labels_opt.hidden(false);
|
||||||
text_cycles.hidden(true);
|
text_current.hidden(false);
|
||||||
text_ttef.hidden(true);
|
text_charge.hidden(false);
|
||||||
|
text_current.set(to_string_dec_int(current) + " mA");
|
||||||
|
text_charge.set(current >= 0 ? "Charging" : "Discharging");
|
||||||
|
labels_opt.hidden(false);
|
||||||
|
text_ttef.hidden(false);
|
||||||
|
// cycles
|
||||||
|
text_cycles.hidden(false);
|
||||||
|
uint16_t cycles = (uint16_t)dev->getValue("Cycles");
|
||||||
|
if (cycles < 2)
|
||||||
|
text_warn.set("SoC improves after 2 cycles");
|
||||||
|
else
|
||||||
text_warn.set("");
|
text_warn.set("");
|
||||||
}
|
text_cycles.set(to_string_dec_uint(cycles));
|
||||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_CYCLES) == battery::BatteryManagement::BATT_VALID_CYCLES) {
|
// ttef
|
||||||
text_cycles.hidden(false);
|
text_ttef.hidden(false);
|
||||||
uint16_t cycles = battery::BatteryManagement::get_cycles();
|
float ttef = 0;
|
||||||
if (cycles < 2)
|
if (current <= 0) {
|
||||||
text_warn.set("SoC improves after 2 cycles");
|
ttef = dev->getValue("TTE");
|
||||||
else
|
|
||||||
text_warn.set("");
|
|
||||||
text_cycles.set(to_string_dec_uint(cycles));
|
|
||||||
} else {
|
} else {
|
||||||
text_cycles.hidden(true);
|
ttef = dev->getValue("TTF");
|
||||||
text_warn.set("");
|
|
||||||
}
|
}
|
||||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_TTEF) == battery::BatteryManagement::BATT_VALID_TTEF) {
|
// Convert ttef to hours and minutes
|
||||||
text_ttef.hidden(false);
|
uint8_t hours = static_cast<uint8_t>(ttef);
|
||||||
float ttef = 0;
|
uint8_t minutes = static_cast<uint8_t>((ttef - hours) * 60 + 0.5); // +0.5 for rounding
|
||||||
if (current <= 0) {
|
// Create the formatted string
|
||||||
ttef = battery::BatteryManagement::get_tte();
|
std::string formatted_time;
|
||||||
} else {
|
if (hours > 0) {
|
||||||
ttef = battery::BatteryManagement::get_ttf();
|
formatted_time += to_string_dec_uint(hours) + "h ";
|
||||||
}
|
|
||||||
|
|
||||||
// Convert ttef to hours and minutes
|
|
||||||
uint8_t hours = static_cast<uint8_t>(ttef);
|
|
||||||
uint8_t minutes = static_cast<uint8_t>((ttef - hours) * 60 + 0.5); // +0.5 for rounding
|
|
||||||
|
|
||||||
// Create the formatted string
|
|
||||||
std::string formatted_time;
|
|
||||||
if (hours > 0) {
|
|
||||||
formatted_time += to_string_dec_uint(hours) + "h ";
|
|
||||||
}
|
|
||||||
formatted_time += to_string_dec_uint(minutes) + "m";
|
|
||||||
|
|
||||||
text_ttef.set(formatted_time);
|
|
||||||
} else {
|
|
||||||
text_ttef.hidden(true);
|
|
||||||
}
|
}
|
||||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_PERCENT) == battery::BatteryManagement::BATT_VALID_PERCENT) {
|
formatted_time += to_string_dec_uint(minutes) + "m";
|
||||||
|
text_ttef.set(formatted_time);
|
||||||
|
if (!battery::BatteryManagement::calcOverride) {
|
||||||
text_method.set("IC");
|
text_method.set("IC");
|
||||||
button_mode.set_text("Volt");
|
button_mode.set_text("Volt");
|
||||||
} else {
|
} else {
|
||||||
@ -136,6 +135,30 @@ void BattinfoView::update_result() {
|
|||||||
EventDispatcher::send_message(msg);
|
EventDispatcher::send_message(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BattinfoView::update_result() {
|
||||||
|
auto dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_MAX17055);
|
||||||
|
if (dev) {
|
||||||
|
update_results_max17055((i2cdev::I2cDev_MAX17055*)dev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_ADS1110);
|
||||||
|
if (dev) {
|
||||||
|
update_results_ads1110((i2cdev::I2cDev_ADS1110*)dev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no dev found
|
||||||
|
text_percent.set("UNKNOWN");
|
||||||
|
text_voltage.set("UNKNOWN");
|
||||||
|
text_current.set("-");
|
||||||
|
text_charge.set("-");
|
||||||
|
text_cycles.set("-");
|
||||||
|
text_ttef.set("-");
|
||||||
|
text_method.set("-");
|
||||||
|
text_warn.set("");
|
||||||
|
}
|
||||||
|
|
||||||
BattinfoView::BattinfoView(NavigationView& nav)
|
BattinfoView::BattinfoView(NavigationView& nav)
|
||||||
: nav_{nav} {
|
: nav_{nav} {
|
||||||
add_children({&labels,
|
add_children({&labels,
|
||||||
|
@ -27,6 +27,9 @@
|
|||||||
#include "ui_widget.hpp"
|
#include "ui_widget.hpp"
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
|
#include "i2cdevmanager.hpp"
|
||||||
|
#include "i2cdev_max17055.hpp"
|
||||||
|
#include "i2cdev_ads1110.hpp"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
class BattinfoView : public View {
|
class BattinfoView : public View {
|
||||||
@ -43,6 +46,8 @@ class BattinfoView : public View {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void update_result();
|
void update_result();
|
||||||
|
void update_results_max17055(i2cdev::I2cDev_MAX17055* dev);
|
||||||
|
void update_results_ads1110(i2cdev::I2cDev_ADS1110* dev);
|
||||||
void on_timer();
|
void on_timer();
|
||||||
NavigationView& nav_;
|
NavigationView& nav_;
|
||||||
uint16_t timer_period = 60;
|
uint16_t timer_period = 60;
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
#include "ui_font_fixed_8x16.hpp"
|
#include "ui_font_fixed_8x16.hpp"
|
||||||
#include "ui_painter.hpp"
|
#include "ui_painter.hpp"
|
||||||
#include "ui_external_items_menu_loader.hpp"
|
#include "ui_external_items_menu_loader.hpp"
|
||||||
#include "ui_debug_battery.hpp"
|
#include "ui_debug_max17055.hpp"
|
||||||
|
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
#include "portapack_persistent_memory.hpp"
|
#include "portapack_persistent_memory.hpp"
|
||||||
@ -226,8 +226,10 @@ uint32_t RegistersWidget::reg_read(const uint32_t register_number) {
|
|||||||
return radio::debug::second_if::register_read(register_number);
|
return radio::debug::second_if::register_read(register_number);
|
||||||
case CT_SI5351:
|
case CT_SI5351:
|
||||||
return portapack::clock_generator.read_register(register_number);
|
return portapack::clock_generator.read_register(register_number);
|
||||||
case CT_BATTERY:
|
case CT_MAX17055: {
|
||||||
return battery::BatteryManagement::read_register(register_number);
|
i2cdev::I2cDev_MAX17055* dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055);
|
||||||
|
return dev->read_register(register_number);
|
||||||
|
}
|
||||||
case CT_AUDIO:
|
case CT_AUDIO:
|
||||||
return audio::debug::reg_read(register_number);
|
return audio::debug::reg_read(register_number);
|
||||||
}
|
}
|
||||||
@ -249,9 +251,11 @@ void RegistersWidget::reg_write(const uint32_t register_number, const uint32_t v
|
|||||||
case CT_SI5351:
|
case CT_SI5351:
|
||||||
portapack::clock_generator.write_register(register_number, value);
|
portapack::clock_generator.write_register(register_number, value);
|
||||||
break;
|
break;
|
||||||
case CT_BATTERY:
|
case CT_MAX17055: {
|
||||||
battery::BatteryManagement::write_register(register_number, value);
|
i2cdev::I2cDev_MAX17055* dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055);
|
||||||
|
dev->write_register(register_number, value);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case CT_AUDIO:
|
case CT_AUDIO:
|
||||||
audio::debug::reg_write(register_number, value);
|
audio::debug::reg_write(register_number, value);
|
||||||
break;
|
break;
|
||||||
@ -465,9 +469,9 @@ void DebugPeripheralsMenuView::on_populate() {
|
|||||||
{si5351x, Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this, si5351x]() { nav_.push<RegistersView>(si5351x, RegistersWidgetConfig{CT_SI5351, 188, 96, 8}); }},
|
{si5351x, Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this, si5351x]() { nav_.push<RegistersView>(si5351x, RegistersWidgetConfig{CT_SI5351, 188, 96, 8}); }},
|
||||||
{audio::debug::codec_name(), Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>(audio::debug::codec_name(), RegistersWidgetConfig{CT_AUDIO, audio::debug::reg_count(), audio::debug::reg_count(), audio::debug::reg_bits()}); }},
|
{audio::debug::codec_name(), Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>(audio::debug::codec_name(), RegistersWidgetConfig{CT_AUDIO, audio::debug::reg_count(), audio::debug::reg_count(), audio::debug::reg_bits()}); }},
|
||||||
});
|
});
|
||||||
if (battery::BatteryManagement::detectedModule() == battery::BatteryManagement::BatteryModules::BATT_MAX17055) {
|
if (i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055)) {
|
||||||
add_item(
|
add_item(
|
||||||
{"MAX17055", Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>("MAX17055", RegistersWidgetConfig{CT_BATTERY, 256, 16, 16}); }});
|
{"MAX17055", Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>("MAX17055", RegistersWidgetConfig{CT_MAX17055, 256, 16, 16}); }});
|
||||||
}
|
}
|
||||||
set_max_rows(2); // allow wider buttons
|
set_max_rows(2); // allow wider buttons
|
||||||
}
|
}
|
||||||
@ -512,7 +516,7 @@ void DebugMenuView::on_populate() {
|
|||||||
{"Reboot", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_setup, [this]() { nav_.push<DebugReboot>(); }},
|
{"Reboot", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_setup, [this]() { nav_.push<DebugReboot>(); }},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (battery::BatteryManagement::detectedModule() == battery::BatteryManagement::BatteryModules::BATT_MAX17055) {
|
if (i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055)) {
|
||||||
add_item(
|
add_item(
|
||||||
{"Battery", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_batt_icon, [this]() { nav_.push<BatteryCapacityView>(); }});
|
{"Battery", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_batt_icon, [this]() { nav_.push<BatteryCapacityView>(); }});
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ typedef enum {
|
|||||||
CT_MAX283X,
|
CT_MAX283X,
|
||||||
CT_SI5351,
|
CT_SI5351,
|
||||||
CT_AUDIO,
|
CT_AUDIO,
|
||||||
CT_BATTERY,
|
CT_MAX17055,
|
||||||
} chip_type_t;
|
} chip_type_t;
|
||||||
|
|
||||||
struct RegistersWidgetConfig {
|
struct RegistersWidgetConfig {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#include "ui_debug_battery.hpp"
|
#include "ui_debug_max17055.hpp"
|
||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
BatteryCapacityView::RegisterEntry BatteryCapacityView::get_entry(size_t index) {
|
BatteryCapacityView::RegisterEntry BatteryCapacityView::get_entry(size_t index) {
|
||||||
if (index < battery::max17055::MAX17055::entries_count) {
|
if (index < i2cdev::I2cDev_MAX17055::entries_count) {
|
||||||
return battery::max17055::MAX17055::entries[index];
|
return i2cdev::I2cDev_MAX17055::entries[index];
|
||||||
}
|
}
|
||||||
return {"", 0, "", 0, false, "", false, 0, false, false, false, 0, false};
|
return {"", 0, "", 0, false, "", false, 0, false, false, false, 0, false};
|
||||||
}
|
}
|
||||||
@ -27,6 +27,12 @@ BatteryCapacityView::BatteryCapacityView(NavigationView& nav) {
|
|||||||
|
|
||||||
button_done.on_select = [&nav](Button&) { nav.pop(); };
|
button_done.on_select = [&nav](Button&) { nav.pop(); };
|
||||||
|
|
||||||
|
auto dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055);
|
||||||
|
if (!dev) { // dev not found
|
||||||
|
nav.pop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
populate_page(0);
|
populate_page(0);
|
||||||
update_page_text();
|
update_page_text();
|
||||||
}
|
}
|
||||||
@ -37,7 +43,7 @@ void BatteryCapacityView::focus() {
|
|||||||
|
|
||||||
bool BatteryCapacityView::on_encoder(const EncoderEvent delta) {
|
bool BatteryCapacityView::on_encoder(const EncoderEvent delta) {
|
||||||
int32_t new_page = current_page + delta;
|
int32_t new_page = current_page + delta;
|
||||||
if (new_page >= 0 && new_page < ((int32_t)battery::max17055::MAX17055::entries_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE) {
|
if (new_page >= 0 && new_page < ((int32_t)i2cdev::I2cDev_MAX17055::entries_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE) {
|
||||||
current_page = new_page;
|
current_page = new_page;
|
||||||
populate_page(current_page * ENTRIES_PER_PAGE);
|
populate_page(current_page * ENTRIES_PER_PAGE);
|
||||||
update_page_text();
|
update_page_text();
|
||||||
@ -46,11 +52,12 @@ bool BatteryCapacityView::on_encoder(const EncoderEvent delta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BatteryCapacityView::update_values() {
|
void BatteryCapacityView::update_values() {
|
||||||
|
i2cdev::I2cDev_MAX17055* dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055);
|
||||||
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
||||||
size_t entry_index = current_page * ENTRIES_PER_PAGE + i;
|
size_t entry_index = current_page * ENTRIES_PER_PAGE + i;
|
||||||
if (entry_index < battery::max17055::MAX17055::entries_count) {
|
if (entry_index < i2cdev::I2cDev_MAX17055::entries_count) {
|
||||||
const auto entry = get_entry(entry_index);
|
const auto entry = get_entry(entry_index);
|
||||||
uint16_t raw_value = battery::BatteryManagement::read_register(entry.address);
|
uint16_t raw_value = dev->read_register(entry.address);
|
||||||
|
|
||||||
hex_texts[i].set("0x" + to_string_hex(raw_value, 4));
|
hex_texts[i].set("0x" + to_string_hex(raw_value, 4));
|
||||||
|
|
||||||
@ -78,7 +85,7 @@ void BatteryCapacityView::update_values() {
|
|||||||
void BatteryCapacityView::populate_page(int start_index) {
|
void BatteryCapacityView::populate_page(int start_index) {
|
||||||
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
||||||
size_t entry_index = start_index + i;
|
size_t entry_index = start_index + i;
|
||||||
if (entry_index < battery::max17055::MAX17055::entries_count) {
|
if (entry_index < i2cdev::I2cDev_MAX17055::entries_count) {
|
||||||
const auto entry = get_entry(entry_index);
|
const auto entry = get_entry(entry_index);
|
||||||
name_texts[i].set(entry.name);
|
name_texts[i].set(entry.name);
|
||||||
addr_texts[i].set("0x" + to_string_hex(entry.address, 2));
|
addr_texts[i].set("0x" + to_string_hex(entry.address, 2));
|
||||||
@ -97,7 +104,7 @@ void BatteryCapacityView::populate_page(int start_index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BatteryCapacityView::update_page_text() {
|
void BatteryCapacityView::update_page_text() {
|
||||||
int total_pages = (battery::max17055::MAX17055::entries_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
|
int total_pages = (i2cdev::I2cDev_MAX17055::entries_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
|
||||||
page_text.set("Page " + to_string_dec_uint(current_page + 1) + "/" + to_string_dec_uint(total_pages));
|
page_text.set("Page " + to_string_dec_uint(current_page + 1) + "/" + to_string_dec_uint(total_pages));
|
||||||
}
|
}
|
||||||
|
|
@ -5,7 +5,8 @@
|
|||||||
#include "ui_widget.hpp"
|
#include "ui_widget.hpp"
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
#include "battery.hpp"
|
#include "battery.hpp"
|
||||||
#include "max17055.hpp"
|
#include "i2cdevmanager.hpp"
|
||||||
|
#include "i2cdev_max17055.hpp"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
@ -13,11 +14,11 @@ class BatteryCapacityView : public View {
|
|||||||
public:
|
public:
|
||||||
BatteryCapacityView(NavigationView& nav);
|
BatteryCapacityView(NavigationView& nav);
|
||||||
void focus() override;
|
void focus() override;
|
||||||
std::string title() const override { return "Battery Registers"; }
|
std::string title() const override { return "MAX17055 Registers"; }
|
||||||
|
|
||||||
bool on_encoder(const EncoderEvent delta) override;
|
bool on_encoder(const EncoderEvent delta) override;
|
||||||
|
|
||||||
using RegisterEntry = battery::max17055::RegisterEntry;
|
using RegisterEntry = i2cdev::I2cDev_MAX17055::RegisterEntry;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static RegisterEntry get_entry(size_t index);
|
static RegisterEntry get_entry(size_t index);
|
@ -41,11 +41,6 @@ DfuMenu::DfuMenu(NavigationView& nav)
|
|||||||
&text_info_line_8,
|
&text_info_line_8,
|
||||||
&text_info_line_9,
|
&text_info_line_9,
|
||||||
&text_info_line_10});
|
&text_info_line_10});
|
||||||
|
|
||||||
if (battery::BatteryManagement::isDetected()) {
|
|
||||||
add_child(&voltage_label);
|
|
||||||
add_child(&text_info_line_11);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DfuMenu::paint(Painter& painter) {
|
void DfuMenu::paint(Painter& painter) {
|
||||||
@ -53,7 +48,7 @@ void DfuMenu::paint(Painter& painter) {
|
|||||||
size_t m0_fragmented_free_space = 0;
|
size_t m0_fragmented_free_space = 0;
|
||||||
const auto m0_fragments = chHeapStatus(NULL, &m0_fragmented_free_space);
|
const auto m0_fragments = chHeapStatus(NULL, &m0_fragmented_free_space);
|
||||||
|
|
||||||
auto lines = (battery::BatteryManagement::isDetected() ? 11 : 10) + 2;
|
auto lines = 10 + 2;
|
||||||
|
|
||||||
text_info_line_1.set(to_string_dec_uint(chCoreStatus(), 6));
|
text_info_line_1.set(to_string_dec_uint(chCoreStatus(), 6));
|
||||||
text_info_line_2.set(to_string_dec_uint(m0_fragmented_free_space, 6));
|
text_info_line_2.set(to_string_dec_uint(m0_fragmented_free_space, 6));
|
||||||
@ -65,9 +60,6 @@ void DfuMenu::paint(Painter& painter) {
|
|||||||
text_info_line_8.set(to_string_dec_uint(shared_memory.m4_performance_counter, 6));
|
text_info_line_8.set(to_string_dec_uint(shared_memory.m4_performance_counter, 6));
|
||||||
text_info_line_9.set(to_string_dec_uint(shared_memory.m4_buffer_missed, 6));
|
text_info_line_9.set(to_string_dec_uint(shared_memory.m4_buffer_missed, 6));
|
||||||
text_info_line_10.set(to_string_dec_uint(chTimeNow() / 1000, 6));
|
text_info_line_10.set(to_string_dec_uint(chTimeNow() / 1000, 6));
|
||||||
if (battery::BatteryManagement::isDetected()) {
|
|
||||||
text_info_line_11.set(to_string_decimal_padding((float)battery::BatteryManagement::getVoltage() / 1000.0, 3, 6));
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr auto margin = 5;
|
constexpr auto margin = 5;
|
||||||
|
|
||||||
|
@ -60,8 +60,6 @@ class DfuMenu : public View {
|
|||||||
{{6 * CHARACTER_WIDTH, 13 * LINE_HEIGHT}, "M4 miss:", Theme::getInstance()->fg_darkcyan->foreground},
|
{{6 * CHARACTER_WIDTH, 13 * LINE_HEIGHT}, "M4 miss:", Theme::getInstance()->fg_darkcyan->foreground},
|
||||||
{{6 * CHARACTER_WIDTH, 14 * LINE_HEIGHT}, "Uptime:", Theme::getInstance()->fg_darkcyan->foreground}};
|
{{6 * CHARACTER_WIDTH, 14 * LINE_HEIGHT}, "Uptime:", Theme::getInstance()->fg_darkcyan->foreground}};
|
||||||
|
|
||||||
Labels voltage_label{{{6 * CHARACTER_WIDTH, 15 * LINE_HEIGHT}, "Voltage:", Theme::getInstance()->fg_darkcyan->foreground}};
|
|
||||||
|
|
||||||
Text text_info_line_1{{15 * CHARACTER_WIDTH, 5 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
Text text_info_line_1{{15 * CHARACTER_WIDTH, 5 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||||
Text text_info_line_2{{15 * CHARACTER_WIDTH, 6 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
Text text_info_line_2{{15 * CHARACTER_WIDTH, 6 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||||
Text text_info_line_3{{15 * CHARACTER_WIDTH, 7 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
Text text_info_line_3{{15 * CHARACTER_WIDTH, 7 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||||
@ -72,7 +70,6 @@ class DfuMenu : public View {
|
|||||||
Text text_info_line_8{{15 * CHARACTER_WIDTH, 12 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
Text text_info_line_8{{15 * CHARACTER_WIDTH, 12 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||||
Text text_info_line_9{{15 * CHARACTER_WIDTH, 13 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
Text text_info_line_9{{15 * CHARACTER_WIDTH, 13 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||||
Text text_info_line_10{{15 * CHARACTER_WIDTH, 14 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
Text text_info_line_10{{15 * CHARACTER_WIDTH, 14 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||||
Text text_info_line_11{{15 * CHARACTER_WIDTH, 15 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DfuMenu2 : public View {
|
class DfuMenu2 : public View {
|
||||||
|
@ -50,6 +50,8 @@ namespace fs = std::filesystem;
|
|||||||
#include "ui_font_fixed_8x16.hpp"
|
#include "ui_font_fixed_8x16.hpp"
|
||||||
#include "cpld_update.hpp"
|
#include "cpld_update.hpp"
|
||||||
#include "config_mode.hpp"
|
#include "config_mode.hpp"
|
||||||
|
#include "i2cdevmanager.hpp"
|
||||||
|
#include "i2cdev_max17055.hpp"
|
||||||
|
|
||||||
extern ui::SystemView* system_view_ptr;
|
extern ui::SystemView* system_view_ptr;
|
||||||
|
|
||||||
@ -977,7 +979,7 @@ SetBatteryView::SetBatteryView(NavigationView& nav) {
|
|||||||
&button_cancel,
|
&button_cancel,
|
||||||
&checkbox_overridebatt});
|
&checkbox_overridebatt});
|
||||||
|
|
||||||
if (battery::BatteryManagement::detectedModule() == battery::BatteryManagement::BATT_MAX17055) add_children({&button_reset, &labels2});
|
if (i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055)) add_children({&button_reset, &labels2});
|
||||||
|
|
||||||
button_save.on_select = [&nav, this](Button&) {
|
button_save.on_select = [&nav, this](Button&) {
|
||||||
pmem::set_ui_override_batt_calc(checkbox_overridebatt.value());
|
pmem::set_ui_override_batt_calc(checkbox_overridebatt.value());
|
||||||
@ -987,7 +989,8 @@ SetBatteryView::SetBatteryView(NavigationView& nav) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
button_reset.on_select = [&nav, this](Button&) {
|
button_reset.on_select = [&nav, this](Button&) {
|
||||||
if (battery::BatteryManagement::reset_learned())
|
auto dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055);
|
||||||
|
if (dev->reset_learned())
|
||||||
nav.display_modal("Reset", "Battery parameters reset");
|
nav.display_modal("Reset", "Battery parameters reset");
|
||||||
else
|
else
|
||||||
nav.display_modal("Error", "Error parameter reset");
|
nav.display_modal("Error", "Error parameter reset");
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "rtc_time.hpp"
|
#include "rtc_time.hpp"
|
||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
#include "portapack_persistent_memory.hpp"
|
#include "portapack_persistent_memory.hpp"
|
||||||
|
#include "i2cdevmanager.hpp"
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
using namespace ui;
|
using namespace ui;
|
||||||
@ -29,7 +30,7 @@ using namespace ui;
|
|||||||
namespace ui::external_app::extsensors {
|
namespace ui::external_app::extsensors {
|
||||||
|
|
||||||
void ExtSensorsView::focus() {
|
void ExtSensorsView::focus() {
|
||||||
text_info.focus();
|
console.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtSensorsView::ExtSensorsView(NavigationView& nav)
|
ExtSensorsView::ExtSensorsView(NavigationView& nav)
|
||||||
@ -39,10 +40,33 @@ ExtSensorsView::ExtSensorsView(NavigationView& nav)
|
|||||||
&text_gps,
|
&text_gps,
|
||||||
&text_orientation,
|
&text_orientation,
|
||||||
&text_envl1,
|
&text_envl1,
|
||||||
&text_envl2});
|
&text_envl2,
|
||||||
|
&text_envl3,
|
||||||
|
&console});
|
||||||
|
|
||||||
|
prev_scan_int = i2cdev::I2CDevManager::get_autoscan_interval();
|
||||||
|
refreshi2c();
|
||||||
|
i2cdev::I2CDevManager::set_autoscan_interval(3); // scan each 3 sec for new i2c devices
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtSensorsView::on_new_dev() {
|
||||||
|
refreshi2c();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtSensorsView::refreshi2c() {
|
||||||
|
console.clear(true);
|
||||||
|
console.writeln("Found I2C devices:");
|
||||||
|
auto addrlist = i2cdev::I2CDevManager::get_gev_list_by_addr();
|
||||||
|
for (size_t i = 0; i < addrlist.size(); ++i) {
|
||||||
|
console.write("0x");
|
||||||
|
console.write(to_string_hex(addrlist[i]));
|
||||||
|
console.write(", ");
|
||||||
|
}
|
||||||
|
if (addrlist.size() == 0) console.writeln("No I2C devs found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtSensorsView::~ExtSensorsView() {
|
ExtSensorsView::~ExtSensorsView() {
|
||||||
|
i2cdev::I2CDevManager::set_autoscan_interval(prev_scan_int);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtSensorsView::on_any() {
|
void ExtSensorsView::on_any() {
|
||||||
@ -78,9 +102,14 @@ void ExtSensorsView::on_environment(const EnvironmentDataMessage* msg) {
|
|||||||
tmp += "C";
|
tmp += "C";
|
||||||
tmp += "; H: " + to_string_decimal(msg->humidity, 1) + "%"; // humidity
|
tmp += "; H: " + to_string_decimal(msg->humidity, 1) + "%"; // humidity
|
||||||
text_envl1.set(tmp);
|
text_envl1.set(tmp);
|
||||||
tmp = "P: " + to_string_decimal(msg->pressure, 1) + " hPa; L:"; // pressure
|
tmp = "P: " + to_string_decimal(msg->pressure, 1) + " hPa"; // pressure
|
||||||
tmp += to_string_dec_int(msg->light) + " LUX"; // light
|
|
||||||
text_envl2.set(tmp);
|
text_envl2.set(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExtSensorsView::on_light(const LightDataMessage* msg) {
|
||||||
|
on_any();
|
||||||
|
std::string tmp = "L: " + to_string_dec_int(msg->light) + " LUX";
|
||||||
|
text_envl3.set(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ui::external_app::extsensors
|
} // namespace ui::external_app::extsensors
|
@ -53,6 +53,7 @@ class ExtSensorsView : public View {
|
|||||||
NavigationView& nav_;
|
NavigationView& nav_;
|
||||||
|
|
||||||
bool has_data = false;
|
bool has_data = false;
|
||||||
|
uint16_t prev_scan_int = 0;
|
||||||
|
|
||||||
Labels labels{
|
Labels labels{
|
||||||
{{0 * 8, 3 * 16}, "GPS:", Theme::getInstance()->fg_light->foreground},
|
{{0 * 8, 3 * 16}, "GPS:", Theme::getInstance()->fg_light->foreground},
|
||||||
@ -64,9 +65,15 @@ class ExtSensorsView : public View {
|
|||||||
Text text_orientation{{5 * 8, 5 * 16, 24 * 8, 16}, "-"};
|
Text text_orientation{{5 * 8, 5 * 16, 24 * 8, 16}, "-"};
|
||||||
Text text_envl1{{5 * 8, 7 * 16, 24 * 8, 16}, "-"};
|
Text text_envl1{{5 * 8, 7 * 16, 24 * 8, 16}, "-"};
|
||||||
Text text_envl2{{1 * 8, 9 * 16, 24 * 8, 16}, "-"};
|
Text text_envl2{{1 * 8, 9 * 16, 24 * 8, 16}, "-"};
|
||||||
|
Text text_envl3{{1 * 8, 11 * 16, 24 * 8, 16}, "-"};
|
||||||
|
Console console{
|
||||||
|
{1, 13 * 16, screen_width - 1, screen_height - 13 * 16}};
|
||||||
|
|
||||||
|
void refreshi2c();
|
||||||
|
void on_new_dev();
|
||||||
void on_any();
|
void on_any();
|
||||||
|
|
||||||
|
void on_light(const LightDataMessage* msg);
|
||||||
void on_gps(const GPSPosDataMessage* msg);
|
void on_gps(const GPSPosDataMessage* msg);
|
||||||
void on_orientation(const OrientationDataMessage* msg);
|
void on_orientation(const OrientationDataMessage* msg);
|
||||||
void on_environment(const EnvironmentDataMessage* msg);
|
void on_environment(const EnvironmentDataMessage* msg);
|
||||||
@ -90,6 +97,20 @@ class ExtSensorsView : public View {
|
|||||||
const auto message = static_cast<const EnvironmentDataMessage*>(p);
|
const auto message = static_cast<const EnvironmentDataMessage*>(p);
|
||||||
this->on_environment(message);
|
this->on_environment(message);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_light{
|
||||||
|
Message::ID::LightData,
|
||||||
|
[this](Message* const p) {
|
||||||
|
const auto message = static_cast<const LightDataMessage*>(p);
|
||||||
|
this->on_light(message);
|
||||||
|
}};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_dev{
|
||||||
|
Message::ID::I2CDevListChanged,
|
||||||
|
[this](Message* const p) {
|
||||||
|
(void)p; // make compiler happy
|
||||||
|
this->on_new_dev();
|
||||||
|
}};
|
||||||
};
|
};
|
||||||
}; // namespace ui::external_app::extsensors
|
}; // namespace ui::external_app::extsensors
|
||||||
|
|
||||||
|
@ -53,6 +53,8 @@ using asahi_kasei::ak4951::AK4951;
|
|||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
#include "bitmap.hpp"
|
#include "bitmap.hpp"
|
||||||
#include "ui_widget.hpp"
|
#include "ui_widget.hpp"
|
||||||
|
#include "i2cdevmanager.hpp"
|
||||||
|
#include "battery.hpp"
|
||||||
|
|
||||||
namespace portapack {
|
namespace portapack {
|
||||||
|
|
||||||
@ -588,7 +590,8 @@ init_status_t init() {
|
|||||||
chThdSleepMilliseconds(10);
|
chThdSleepMilliseconds(10);
|
||||||
|
|
||||||
audio::init(portapack_audio_codec());
|
audio::init(portapack_audio_codec());
|
||||||
battery::BatteryManagement::init(persistent_memory::ui_override_batt_calc());
|
battery::BatteryManagement::set_calc_override(persistent_memory::ui_override_batt_calc());
|
||||||
|
i2cdev::I2CDevManager::init();
|
||||||
|
|
||||||
if (lcd_fast_setup)
|
if (lcd_fast_setup)
|
||||||
draw_splash_screen_icon(4, ui::bitmap_icon_speaker);
|
draw_splash_screen_icon(4, ui::bitmap_icon_speaker);
|
||||||
|
@ -33,13 +33,9 @@
|
|||||||
#include "backlight.hpp"
|
#include "backlight.hpp"
|
||||||
#include "usb_serial.hpp"
|
#include "usb_serial.hpp"
|
||||||
|
|
||||||
#include "ads1110.hpp"
|
|
||||||
#include "max17055.hpp"
|
|
||||||
|
|
||||||
#include "radio.hpp"
|
#include "radio.hpp"
|
||||||
#include "clock_manager.hpp"
|
#include "clock_manager.hpp"
|
||||||
#include "temperature_logger.hpp"
|
#include "temperature_logger.hpp"
|
||||||
#include "battery.hpp"
|
|
||||||
#include "theme.hpp"
|
#include "theme.hpp"
|
||||||
|
|
||||||
/* TODO: This would be better as a class to add
|
/* TODO: This would be better as a class to add
|
||||||
|
@ -388,7 +388,6 @@ void SystemStatusView::on_battery_data(const BatteryStateMessage* msg) {
|
|||||||
if (!batt_was_inited) {
|
if (!batt_was_inited) {
|
||||||
batt_was_inited = true;
|
batt_was_inited = true;
|
||||||
refresh();
|
refresh();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (!pmem::ui_hide_numeric_battery()) {
|
if (!pmem::ui_hide_numeric_battery()) {
|
||||||
battery_text.set_battery(msg->valid_mask, msg->percent, msg->on_charger);
|
battery_text.set_battery(msg->valid_mask, msg->percent, msg->on_charger);
|
||||||
@ -416,14 +415,11 @@ void SystemStatusView::refresh() {
|
|||||||
if (!pmem::ui_hide_fake_brightness() && !pmem::config_lcd_inverted_mode()) status_icons.add(&button_fake_brightness);
|
if (!pmem::ui_hide_fake_brightness() && !pmem::config_lcd_inverted_mode()) status_icons.add(&button_fake_brightness);
|
||||||
if (battery::BatteryManagement::isDetected()) {
|
if (battery::BatteryManagement::isDetected()) {
|
||||||
batt_was_inited = true;
|
batt_was_inited = true;
|
||||||
uint8_t percent = battery::BatteryManagement::getPercent();
|
|
||||||
if (!pmem::ui_hide_battery_icon()) {
|
if (!pmem::ui_hide_battery_icon()) {
|
||||||
status_icons.add(&battery_icon);
|
status_icons.add(&battery_icon);
|
||||||
battery_text.set_battery(percent <= 100 ? 1 : 0, percent, false); // got an on select, that may pop up the details of the battery.
|
|
||||||
};
|
};
|
||||||
if (!pmem::ui_hide_numeric_battery()) {
|
if (!pmem::ui_hide_numeric_battery()) {
|
||||||
status_icons.add(&battery_text);
|
status_icons.add(&battery_text);
|
||||||
battery_text.set_battery(percent <= 100 ? 1 : 0, percent, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,12 +654,10 @@ bool NavigationView::is_valid() const {
|
|||||||
|
|
||||||
View* NavigationView::push_view(std::unique_ptr<View> new_view) {
|
View* NavigationView::push_view(std::unique_ptr<View> new_view) {
|
||||||
free_view();
|
free_view();
|
||||||
|
|
||||||
const auto p = new_view.get();
|
const auto p = new_view.get();
|
||||||
view_stack.emplace_back(ViewState{std::move(new_view), {}});
|
view_stack.emplace_back(ViewState{std::move(new_view), {}});
|
||||||
|
|
||||||
update_view();
|
update_view();
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -791,7 +785,9 @@ static void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc)
|
|||||||
for (auto& app : NavigationView::appList) {
|
for (auto& app : NavigationView::appList) {
|
||||||
if (app.menuLocation == loc) {
|
if (app.menuLocation == loc) {
|
||||||
grid.add_item({app.displayName, app.iconColor, app.icon,
|
grid.add_item({app.displayName, app.iconColor, app.icon,
|
||||||
[&nav, &app]() { nav.push_view(std::unique_ptr<View>(app.viewFactory->produce(nav))); }});
|
[&nav, &app]() {
|
||||||
|
i2cdev::I2CDevManager::set_autoscan_interval(0); //if i navigate away from any menu, turn off autoscan
|
||||||
|
nav.push_view(std::unique_ptr<View>(app.viewFactory->produce(nav))); }});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -888,7 +884,6 @@ SystemMenuView::SystemMenuView(NavigationView& nav)
|
|||||||
|
|
||||||
void SystemMenuView::on_populate() {
|
void SystemMenuView::on_populate() {
|
||||||
add_apps(nav_, *this, HOME);
|
add_apps(nav_, *this, HOME);
|
||||||
|
|
||||||
add_item({"HackRF", Theme::getInstance()->fg_cyan->foreground, &bitmap_icon_hackrf, [this]() { hackrf_mode(nav_); }});
|
add_item({"HackRF", Theme::getInstance()->fg_cyan->foreground, &bitmap_icon_hackrf, [this]() { hackrf_mode(nav_); }});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -928,6 +923,7 @@ SystemView::SystemView(
|
|||||||
} else {
|
} else {
|
||||||
add_child(&info_view);
|
add_child(&info_view);
|
||||||
info_view.refresh();
|
info_view.refresh();
|
||||||
|
i2cdev::I2CDevManager::set_autoscan_interval(3); // turn on autoscan in sysmainv
|
||||||
}
|
}
|
||||||
|
|
||||||
this->status_view.set_back_enabled(!this->navigation_view.is_top());
|
this->status_view.set_back_enabled(!this->navigation_view.is_top());
|
||||||
|
@ -939,7 +939,7 @@ static void cmd_gotorientation(BaseSequentialStream* chp, int argc, char* argv[]
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void cmd_gotenv(BaseSequentialStream* chp, int argc, char* argv[]) {
|
static void cmd_gotenv(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||||
const char* usage = "usage: gotenv <temperature> [humidity] [pressure] [light]\r\n";
|
const char* usage = "usage: gotenv <temperature> [humidity] [pressure] [light]\r\n"; // keeping light here too for compatibility
|
||||||
if (argc < 1 || argc > 4) {
|
if (argc < 1 || argc > 4) {
|
||||||
chprintf(chp, usage);
|
chprintf(chp, usage);
|
||||||
return;
|
return;
|
||||||
@ -950,8 +950,25 @@ static void cmd_gotenv(BaseSequentialStream* chp, int argc, char* argv[]) {
|
|||||||
uint16_t light = 0;
|
uint16_t light = 0;
|
||||||
if (argc > 1) humi = atof(argv[1]);
|
if (argc > 1) humi = atof(argv[1]);
|
||||||
if (argc > 2) pressure = atof(argv[2]);
|
if (argc > 2) pressure = atof(argv[2]);
|
||||||
if (argc > 3) light = strtol(argv[3], NULL, 10);
|
if (argc > 3) light = strtol(argv[0], NULL, 10);
|
||||||
EnvironmentDataMessage msg{temp, humi, pressure, light};
|
EnvironmentDataMessage msg{temp, humi, pressure};
|
||||||
|
EventDispatcher::send_message(msg);
|
||||||
|
// compatibility:
|
||||||
|
if (argc > 3) {
|
||||||
|
LightDataMessage msg{light};
|
||||||
|
EventDispatcher::send_message(msg);
|
||||||
|
}
|
||||||
|
chprintf(chp, "ok\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_gotlight(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||||
|
const char* usage = "usage: gotlight <light_lux>\r\n";
|
||||||
|
if (argc != 1) {
|
||||||
|
chprintf(chp, usage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint16_t light = strtol(argv[0], NULL, 10);
|
||||||
|
LightDataMessage msg{light};
|
||||||
EventDispatcher::send_message(msg);
|
EventDispatcher::send_message(msg);
|
||||||
chprintf(chp, "ok\r\n");
|
chprintf(chp, "ok\r\n");
|
||||||
}
|
}
|
||||||
@ -1191,6 +1208,7 @@ static const ShellCommand commands[] = {
|
|||||||
{"gotgps", cmd_gotgps},
|
{"gotgps", cmd_gotgps},
|
||||||
{"gotorientation", cmd_gotorientation},
|
{"gotorientation", cmd_gotorientation},
|
||||||
{"gotenv", cmd_gotenv},
|
{"gotenv", cmd_gotenv},
|
||||||
|
{"gotlight", cmd_gotlight},
|
||||||
{"sysinfo", cmd_sysinfo},
|
{"sysinfo", cmd_sysinfo},
|
||||||
{"radioinfo", cmd_radioinfo},
|
{"radioinfo", cmd_radioinfo},
|
||||||
{"pmemreset", cmd_pmemreset},
|
{"pmemreset", cmd_pmemreset},
|
||||||
|
@ -1,151 +1,24 @@
|
|||||||
#include "battery.hpp"
|
#include "battery.hpp"
|
||||||
#include "event_m0.hpp"
|
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
#include "ads1110.hpp"
|
#include "i2cdevmanager.hpp"
|
||||||
#include "max17055.hpp"
|
|
||||||
|
|
||||||
// uncomment if you want to emulate batt management system
|
|
||||||
// #define USE_BATT_EMULATOR
|
|
||||||
|
|
||||||
extern I2C portapack::i2c0;
|
|
||||||
|
|
||||||
namespace battery {
|
namespace battery {
|
||||||
|
|
||||||
constexpr uint32_t BATTERY_UPDATE_INTERVAL = 20000;
|
|
||||||
BatteryManagement::BatteryModules BatteryManagement::detected_ = BatteryManagement::BATT_NONE;
|
|
||||||
|
|
||||||
ads1110::ADS1110 battery_ads1110{portapack::i2c0, 0x48};
|
|
||||||
max17055::MAX17055 battery_max17055{portapack::i2c0, 0x36};
|
|
||||||
|
|
||||||
Thread* BatteryManagement::thread = nullptr;
|
|
||||||
bool BatteryManagement::calcOverride = false;
|
bool BatteryManagement::calcOverride = false;
|
||||||
|
|
||||||
void BatteryManagement::detect() {
|
|
||||||
// try to detect supported modules
|
|
||||||
detected_ = BATT_NONE;
|
|
||||||
if (battery_max17055.detect()) {
|
|
||||||
battery_max17055.init();
|
|
||||||
detected_ = BATT_MAX17055;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (battery_ads1110.detect()) {
|
|
||||||
battery_ads1110.init();
|
|
||||||
detected_ = BATT_ADS1110;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add new supported module detect + init here
|
|
||||||
|
|
||||||
#ifdef USE_BATT_EMULATOR
|
|
||||||
if (detected_ == BATT_NONE) {
|
|
||||||
detected_ = BATT_EMULATOR;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void BatteryManagement::init(bool override) {
|
|
||||||
calcOverride = override;
|
|
||||||
detect();
|
|
||||||
// sets timer to query and broadcats this info
|
|
||||||
create_thread();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BatteryManagement::reset_learned() {
|
|
||||||
if (detected_ == BATT_MAX17055) {
|
|
||||||
return battery_max17055.reset_learned();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set if the default percentage calculation should be overrided by voltage based one
|
// set if the default percentage calculation should be overrided by voltage based one
|
||||||
void BatteryManagement::set_calc_override(bool override) {
|
void BatteryManagement::set_calc_override(bool override) {
|
||||||
calcOverride = override;
|
calcOverride = override;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets the values, it the currend module supports it.
|
// Helper function to checkif there is ANY battery management ic present.
|
||||||
void BatteryManagement::getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current) {
|
bool BatteryManagement::isDetected() {
|
||||||
if (detected_ == BATT_NONE) {
|
auto dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_MAX17055);
|
||||||
valid_mask = BATT_VALID_NONE;
|
if (dev) return true;
|
||||||
return;
|
dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_ADS1110);
|
||||||
} else if (detected_ == BATT_ADS1110) {
|
if (dev) return true;
|
||||||
battery_ads1110.getBatteryInfo(valid_mask, voltage);
|
|
||||||
batteryPercentage = calc_percent_voltage(voltage);
|
|
||||||
return;
|
|
||||||
} else if (detected_ == BATT_MAX17055) {
|
|
||||||
battery_max17055.getBatteryInfo(valid_mask, batteryPercentage, voltage, current);
|
|
||||||
if (calcOverride) {
|
|
||||||
valid_mask &= ~BATT_VALID_PERCENT; // indicate it is voltage based
|
|
||||||
batteryPercentage = calc_percent_voltage(voltage);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// add new module query here
|
|
||||||
|
|
||||||
#ifdef USE_BATT_EMULATOR
|
|
||||||
if (detected_ == BATT_EMULATOR) {
|
|
||||||
batteryPercentage += 5; // %
|
|
||||||
if (batteryPercentage > 100) batteryPercentage = 0;
|
|
||||||
voltage = rand() % 1000 + 3000; // mV
|
|
||||||
current = rand() % 150; // mA
|
|
||||||
isCharging = rand() % 2;
|
|
||||||
valid_mask = 7;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
(void)current;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t BatteryManagement::get_cycles() {
|
|
||||||
if (detected_ == BATT_MAX17055) {
|
|
||||||
return (uint16_t)battery_max17055.getValue("Cycles");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float BatteryManagement::get_tte() {
|
|
||||||
if (detected_ == BATT_MAX17055) {
|
|
||||||
return battery_max17055.getValue("TTE");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
float BatteryManagement::get_ttf() {
|
|
||||||
if (detected_ == BATT_MAX17055) {
|
|
||||||
return battery_max17055.getValue("TTF");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t BatteryManagement::read_register(const uint8_t reg) {
|
|
||||||
if (detected_ == BATT_MAX17055) {
|
|
||||||
return battery_max17055.read_register(reg);
|
|
||||||
}
|
|
||||||
return 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BatteryManagement::write_register(const uint8_t reg, const uint16_t value) {
|
|
||||||
if (detected_ == BATT_MAX17055) {
|
|
||||||
return battery_max17055.write_register(reg, value);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t BatteryManagement::getPercent() {
|
|
||||||
if (detected_ == BATT_NONE) return 102;
|
|
||||||
uint8_t validity = 0;
|
|
||||||
uint8_t batteryPercentage = 0;
|
|
||||||
uint16_t voltage = 0;
|
|
||||||
int32_t current = 0;
|
|
||||||
getBatteryInfo(validity, batteryPercentage, voltage, current);
|
|
||||||
if ((validity & BATT_VALID_VOLTAGE) != BATT_VALID_VOLTAGE) return 102;
|
|
||||||
if (calcOverride || ((validity & BATT_VALID_PERCENT) != BATT_VALID_PERCENT)) {
|
|
||||||
validity &= ~BATT_VALID_PERCENT; // indicate it is voltage based
|
|
||||||
batteryPercentage = calc_percent_voltage(voltage);
|
|
||||||
}
|
|
||||||
return batteryPercentage;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t BatteryManagement::calc_percent_voltage(uint16_t voltage) {
|
uint8_t BatteryManagement::calc_percent_voltage(uint16_t voltage) {
|
||||||
// Calculate the remaining battery percentage
|
// Calculate the remaining battery percentage
|
||||||
uint8_t batteryPercentage = (float)(voltage - BATTERY_MIN_VOLTAGE) / (float)(BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE) * 100.0;
|
uint8_t batteryPercentage = (float)(voltage - BATTERY_MIN_VOLTAGE) / (float)(BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE) * 100.0;
|
||||||
@ -154,42 +27,4 @@ uint8_t BatteryManagement::calc_percent_voltage(uint16_t voltage) {
|
|||||||
return batteryPercentage;
|
return batteryPercentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t BatteryManagement::getVoltage() {
|
|
||||||
if (detected_ == BATT_NONE) return 0;
|
|
||||||
uint8_t validity = 0;
|
|
||||||
uint8_t batteryPercentage = 0;
|
|
||||||
uint16_t voltage = 0;
|
|
||||||
int32_t current = 0;
|
|
||||||
getBatteryInfo(validity, batteryPercentage, voltage, current);
|
|
||||||
if ((validity & BATT_VALID_VOLTAGE) != BATT_VALID_VOLTAGE) return 0;
|
|
||||||
return voltage;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_t BatteryManagement::timer_fn(void* arg) {
|
|
||||||
(void)arg;
|
|
||||||
uint8_t validity = 0;
|
|
||||||
uint8_t batteryPercentage = 102;
|
|
||||||
uint16_t voltage = 0;
|
|
||||||
int32_t current = 0;
|
|
||||||
chThdSleepMilliseconds(1000); // wait ui for fully load
|
|
||||||
while (1) {
|
|
||||||
if (!detected_) {
|
|
||||||
detect(); // try to detect it again, it maybe disconnected while pp was powered up
|
|
||||||
chThdSleepMilliseconds(500);
|
|
||||||
}
|
|
||||||
if (detected_) {
|
|
||||||
BatteryManagement::getBatteryInfo(validity, batteryPercentage, voltage, current);
|
|
||||||
// send local message
|
|
||||||
BatteryStateMessage msg{validity, batteryPercentage, current >= 0, voltage};
|
|
||||||
EventDispatcher::send_message(msg);
|
|
||||||
}
|
|
||||||
chThdSleepMilliseconds(BATTERY_UPDATE_INTERVAL);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BatteryManagement::create_thread() {
|
|
||||||
thread = chThdCreateFromHeap(NULL, 512, NORMALPRIO, BatteryManagement::timer_fn, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace battery
|
} // namespace battery
|
@ -23,7 +23,6 @@
|
|||||||
#define __BATTERY_H__
|
#define __BATTERY_H__
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "ch.h"
|
|
||||||
|
|
||||||
namespace battery {
|
namespace battery {
|
||||||
|
|
||||||
@ -31,14 +30,9 @@ namespace battery {
|
|||||||
#define BATTERY_MAX_VOLTAGE 4170.0
|
#define BATTERY_MAX_VOLTAGE 4170.0
|
||||||
#define BATTERY_DESIGN_CAP 2500
|
#define BATTERY_DESIGN_CAP 2500
|
||||||
|
|
||||||
|
// this will just hold the config and a calculation. also some defines above for the battery management. could be movet to the classes, but it is a bit more readeable i think.
|
||||||
class BatteryManagement {
|
class BatteryManagement {
|
||||||
public:
|
public:
|
||||||
enum BatteryModules {
|
|
||||||
BATT_NONE = 0,
|
|
||||||
BATT_ADS1110 = 1,
|
|
||||||
BATT_MAX17055 = 2,
|
|
||||||
BATT_EMULATOR = 254
|
|
||||||
};
|
|
||||||
enum BatteryValidMask {
|
enum BatteryValidMask {
|
||||||
BATT_VALID_NONE = 0,
|
BATT_VALID_NONE = 0,
|
||||||
BATT_VALID_VOLTAGE = 1,
|
BATT_VALID_VOLTAGE = 1,
|
||||||
@ -47,28 +41,11 @@ class BatteryManagement {
|
|||||||
BATT_VALID_CYCLES = 8,
|
BATT_VALID_CYCLES = 8,
|
||||||
BATT_VALID_TTEF = 16,
|
BATT_VALID_TTEF = 16,
|
||||||
};
|
};
|
||||||
static void init(bool override = false);
|
static bool isDetected();
|
||||||
static void detect();
|
|
||||||
static bool isDetected() { return detected_ != BATT_NONE; }
|
|
||||||
static BatteryModules detectedModule() { return detected_; }
|
|
||||||
static void getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current);
|
|
||||||
static uint16_t getVoltage();
|
|
||||||
static uint8_t getPercent();
|
|
||||||
static uint16_t read_register(const uint8_t reg);
|
|
||||||
static bool write_register(const uint8_t reg, const uint16_t value);
|
|
||||||
static void set_calc_override(bool override);
|
static void set_calc_override(bool override);
|
||||||
static uint8_t calc_percent_voltage(uint16_t); // calculates battery percentage from the voltage
|
static uint8_t calc_percent_voltage(uint16_t); // calculates battery percentage from the voltage
|
||||||
static bool reset_learned(); // resets the ic's learned parameters
|
static bool calcOverride; // if set to true, it'll override the battery percent calculation based on current voltage.
|
||||||
static uint16_t get_cycles();
|
|
||||||
static float get_tte();
|
|
||||||
static float get_ttf();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void create_thread();
|
|
||||||
static msg_t timer_fn(void* arg);
|
|
||||||
static Thread* thread;
|
|
||||||
static BatteryModules detected_; // if there is any batt management system
|
|
||||||
static bool calcOverride; // if set to true, it'll override the battery percent calculation based on current voltage.
|
|
||||||
};
|
};
|
||||||
}; // namespace battery
|
}; // namespace battery
|
||||||
#endif
|
#endif
|
@ -29,6 +29,21 @@ void I2C::stop() {
|
|||||||
i2cStop(_driver);
|
i2cStop(_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool I2C::probe(i2caddr_t addr, systime_t timeout) {
|
||||||
|
i2cAcquireBus(_driver);
|
||||||
|
chSysLock();
|
||||||
|
_driver->errors = I2CD_NO_ERROR;
|
||||||
|
_driver->state = I2C_ACTIVE_TX;
|
||||||
|
msg_t rdymsg = i2c_lld_master_transmit_timeout(_driver, addr, nullptr, 0, nullptr, 0, timeout);
|
||||||
|
if (rdymsg == RDY_TIMEOUT)
|
||||||
|
_driver->state = I2C_LOCKED;
|
||||||
|
else
|
||||||
|
_driver->state = I2C_READY;
|
||||||
|
chSysUnlock();
|
||||||
|
i2cReleaseBus(_driver);
|
||||||
|
return (rdymsg == RDY_OK);
|
||||||
|
}
|
||||||
|
|
||||||
bool I2C::transfer(
|
bool I2C::transfer(
|
||||||
const address_t slave_address,
|
const address_t slave_address,
|
||||||
const uint8_t* const data_tx,
|
const uint8_t* const data_tx,
|
||||||
|
@ -59,7 +59,7 @@ class I2C {
|
|||||||
|
|
||||||
void start(const I2CConfig& config);
|
void start(const I2CConfig& config);
|
||||||
void stop();
|
void stop();
|
||||||
|
bool probe(i2caddr_t addr, systime_t timeout = TIME_INFINITE);
|
||||||
bool receive(
|
bool receive(
|
||||||
const address_t slave_address,
|
const address_t slave_address,
|
||||||
uint8_t* const data,
|
uint8_t* const data,
|
||||||
|
@ -19,53 +19,60 @@
|
|||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ads1110.hpp"
|
#include "i2cdev_ads1110.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace battery {
|
namespace i2cdev {
|
||||||
namespace ads1110 {
|
|
||||||
|
|
||||||
void ADS1110::init() {
|
bool I2cDev_ADS1110::init(uint8_t addr_) {
|
||||||
if (!detected_) {
|
if (addr_ != I2CDEV_ADS1110_ADDR_1) return false;
|
||||||
detected_ = detect();
|
addr = addr_;
|
||||||
}
|
model = I2CDEVMDL_ADS1110;
|
||||||
if (detected_) {
|
query_interval = BATTERY_WIDGET_REFRESH_INTERVAL;
|
||||||
|
|
||||||
|
if (detect()) {
|
||||||
// Set the configuration register
|
// Set the configuration register
|
||||||
write(0x8C);
|
write(0x8C);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ADS1110::detect() {
|
bool I2cDev_ADS1110::detect() {
|
||||||
uint8_t data[3];
|
uint8_t data[3];
|
||||||
if (bus.receive(bus_address, data, 3)) {
|
if (i2cbus.receive(addr, data, 3)) {
|
||||||
// Check if the received data is valid
|
// Check if the received data is valid
|
||||||
uint8_t configRegister = data[2];
|
uint8_t configRegister = data[2];
|
||||||
if ((configRegister & 0x0F) == 0x0C) {
|
if ((configRegister & 0x0F) == 0x0C) {
|
||||||
// The configuration register value matches the expected value (0x8C)
|
// The configuration register value matches the expected value (0x8C)
|
||||||
detected_ = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
detected_ = false;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ADS1110::write(const uint8_t value) {
|
void I2cDev_ADS1110::update() {
|
||||||
return bus.transmit(bus_address, &value, 1);
|
uint16_t voltage = readVoltage();
|
||||||
|
uint8_t batteryPercentage = battery::BatteryManagement::calc_percent_voltage(voltage);
|
||||||
|
// send local message
|
||||||
|
BatteryStateMessage msg{1, batteryPercentage, false, voltage};
|
||||||
|
EventDispatcher::send_message(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I2cDev_ADS1110::write(const uint8_t value) {
|
||||||
|
return i2cbus.transmit(addr, &value, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the batt voltage in mV
|
// returns the batt voltage in mV
|
||||||
uint16_t ADS1110::readVoltage() {
|
uint16_t I2cDev_ADS1110::readVoltage() {
|
||||||
// Read the conversion result
|
// Read the conversion result
|
||||||
uint8_t data[3];
|
uint8_t data[3];
|
||||||
if (!bus.receive(bus_address, data, 3)) {
|
if (!i2cbus.receive(addr, data, 3)) {
|
||||||
return 0.0f; // Return 0 if the read fails
|
return 0.0f; // Return 0 if the read fails
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t raw = (static_cast<uint16_t>(data[0]) << 8) | data[1];
|
uint16_t raw = (static_cast<uint16_t>(data[0]) << 8) | data[1];
|
||||||
|
|
||||||
// Calculate the voltage based on the output code
|
// Calculate the voltage based on the output code
|
||||||
int16_t voltage = 0;
|
int16_t voltage = 0;
|
||||||
float minCode = 0;
|
float minCode = 0;
|
||||||
@ -115,10 +122,4 @@ uint16_t ADS1110::readVoltage() {
|
|||||||
return (uint16_t)voltage;
|
return (uint16_t)voltage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ADS1110::getBatteryInfo(uint8_t& valid_mask, uint16_t& voltage) {
|
} /* namespace i2cdev */
|
||||||
voltage = readVoltage();
|
|
||||||
valid_mask = 1; // BATT_VALID_VOLTAGE
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace ads1110 */
|
|
||||||
} // namespace battery
|
|
@ -19,39 +19,29 @@
|
|||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ADS1110_H__
|
#ifndef __I2CDEV_ADS1110_H__
|
||||||
#define __ADS1110_H__
|
#define __I2CDEV_ADS1110_H__
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "battery.hpp"
|
||||||
|
#include "i2cdevmanager.hpp"
|
||||||
|
|
||||||
#include "i2c_pp.hpp"
|
namespace i2cdev {
|
||||||
namespace battery {
|
|
||||||
namespace ads1110 {
|
|
||||||
|
|
||||||
using address_t = uint8_t;
|
using address_t = uint8_t;
|
||||||
|
|
||||||
class ADS1110 {
|
class I2cDev_ADS1110 : public I2cDev {
|
||||||
public:
|
public:
|
||||||
constexpr ADS1110(I2C& bus, const I2C::address_t bus_address)
|
bool init(uint8_t addr_) override;
|
||||||
: bus(bus), bus_address(bus_address), detected_(false) {}
|
void update() override;
|
||||||
|
|
||||||
void init();
|
|
||||||
bool detect();
|
|
||||||
bool isDetected() const { return detected_; }
|
|
||||||
|
|
||||||
uint16_t readVoltage();
|
uint16_t readVoltage();
|
||||||
void getBatteryInfo(uint8_t& valid_mask, uint16_t& voltage);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
I2C& bus;
|
|
||||||
const I2C::address_t bus_address;
|
|
||||||
bool detected_;
|
|
||||||
|
|
||||||
bool write(const uint8_t value);
|
bool write(const uint8_t value);
|
||||||
|
bool detect();
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace ads1110 */
|
} /* namespace i2cdev */
|
||||||
} // namespace battery
|
#endif /* __I2CDEV_ADS1110_H__ */
|
||||||
#endif /* __ADS1110_H__ */
|
|
97
firmware/common/i2cdev_bh1750.cpp
Normal file
97
firmware/common/i2cdev_bh1750.cpp
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 HTotoo.
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "i2cdev_bh1750.hpp"
|
||||||
|
#include "utility.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace i2cdev {
|
||||||
|
|
||||||
|
#define BH1750_CONV_FACTOR 1.2
|
||||||
|
#define BH1750_MODE 0x13
|
||||||
|
|
||||||
|
bool I2cDev_BH1750::init(uint8_t addr_) {
|
||||||
|
if (addr_ != I2CDEV_BH1750_ADDR_1) return false;
|
||||||
|
addr = addr_;
|
||||||
|
model = I2CDECMDL_BH1750;
|
||||||
|
query_interval = 3;
|
||||||
|
|
||||||
|
// power up
|
||||||
|
uint8_t tmp = 0x01;
|
||||||
|
if (!i2c_write(nullptr, 0, &tmp, 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
chThdSleepMilliseconds(10);
|
||||||
|
// set mode
|
||||||
|
tmp = BH1750_MODE;
|
||||||
|
if (!i2c_write(nullptr, 0, &tmp, 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
chThdSleepMilliseconds(10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// unused, since default
|
||||||
|
// mtreg
|
||||||
|
tmp = (0b01000 << 3) | (69 >> 5);
|
||||||
|
if (!i2c_write(nullptr, 0, &tmp, 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
chThdSleepMilliseconds(10);
|
||||||
|
tmp = (0b011 << 5) | (69 & 0b11111);
|
||||||
|
if (!i2c_write(nullptr, 0, &tmp, 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
chThdSleepMilliseconds(10);
|
||||||
|
// mode
|
||||||
|
tmp = BH1750_MODE;
|
||||||
|
if (!i2c_write(nullptr, 0, &tmp, 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
chThdSleepMilliseconds(10);
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2cDev_BH1750::update() {
|
||||||
|
uint16_t light = readLight();
|
||||||
|
LightDataMessage msg{light};
|
||||||
|
EventDispatcher::send_message(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t I2cDev_BH1750::readLight() {
|
||||||
|
float level = -1.0;
|
||||||
|
uint8_t tmp[2];
|
||||||
|
// Read two bytes from the sensor, which are low and high parts of the sensor value
|
||||||
|
if (i2c_read(nullptr, 0, tmp, 2)) {
|
||||||
|
uint16_t t = (tmp[0] << 8) | tmp[1];
|
||||||
|
level = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level != -1.0) {
|
||||||
|
// Convert raw value to lux
|
||||||
|
level /= BH1750_CONV_FACTOR;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace i2cdev */
|
43
firmware/common/i2cdev_bh1750.hpp
Normal file
43
firmware/common/i2cdev_bh1750.hpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 HTotoo.
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __I2CDEV_BH1750_H__
|
||||||
|
#define __I2CDEV_BH1750_H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
#include "battery.hpp"
|
||||||
|
#include "i2cdevmanager.hpp"
|
||||||
|
|
||||||
|
namespace i2cdev {
|
||||||
|
|
||||||
|
using address_t = uint8_t;
|
||||||
|
|
||||||
|
class I2cDev_BH1750 : public I2cDev {
|
||||||
|
public:
|
||||||
|
bool init(uint8_t addr_) override;
|
||||||
|
void update() override;
|
||||||
|
uint16_t readLight();
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace i2cdev */
|
||||||
|
#endif /* __I2CDEV_BH1750_H__ */
|
188
firmware/common/i2cdev_bmx280.cpp
Normal file
188
firmware/common/i2cdev_bmx280.cpp
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 HTotoo.
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "i2cdev_bmx280.hpp"
|
||||||
|
|
||||||
|
namespace i2cdev {
|
||||||
|
|
||||||
|
bool I2cDev_BMX280::init(uint8_t addr_) {
|
||||||
|
if (addr_ != I2CDEV_BMX280_ADDR_1 && addr_ != I2CDEV_BMX280_ADDR_2) return false;
|
||||||
|
addr = addr_; // store the addr so i2c write / read will use this.
|
||||||
|
model = I2C_DEVMDL::I2CDEVMDL_BMP280; // set the device model!!!!!!!!!!!!!!!!!!
|
||||||
|
query_interval = 5; // set update interval in sec
|
||||||
|
|
||||||
|
uint8_t reg = BME280_REG_CHIPID; // register
|
||||||
|
uint8_t tmp = 0; // value. will save fw space, but harder to read code. so read comments
|
||||||
|
i2c_read(®, 1, &tmp, 1); // read chip id to tmp
|
||||||
|
if (tmp != CHIP_ID_BMP280 && tmp != CHIP_ID_BME280) return false; // this is not BME280 or BMP280, so skip
|
||||||
|
if (tmp == CHIP_ID_BME280) model = I2C_DEVMDL::I2CDEVMDL_BME280; // update dev model, since this driver can handle 2 type of models
|
||||||
|
|
||||||
|
// here we can be "sure" this is a bmp280, so init it
|
||||||
|
|
||||||
|
// soft reset the ic
|
||||||
|
reg = BME280_REG_RESET;
|
||||||
|
tmp = RESET_KEY;
|
||||||
|
i2c_write(®, 1, &tmp, 1);
|
||||||
|
chThdSleepMilliseconds(10); // wait to get awake
|
||||||
|
uint8_t timeout = 0; // wait for calibration data load
|
||||||
|
while (is_reading_calib()) {
|
||||||
|
timeout++;
|
||||||
|
if (timeout > 200) return false; // timeout, bad device
|
||||||
|
chThdSleepMilliseconds(10);
|
||||||
|
}
|
||||||
|
read_coeff();
|
||||||
|
set_sampling();
|
||||||
|
chThdSleepMilliseconds(50);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2cDev_BMX280::update() {
|
||||||
|
float temp = read_temperature(); // internal data gathering from the device.
|
||||||
|
float pressure = read_pressure();
|
||||||
|
float hum = read_humidity();
|
||||||
|
EnvironmentDataMessage msg{temp, hum, pressure}; // create the system message
|
||||||
|
EventDispatcher::send_message(msg); // and send it
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
INTERNAL FUNCTIONS
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool I2cDev_BMX280::is_reading_calib() {
|
||||||
|
uint8_t const rStatus = read8_1(BMX280_REG_STATUS);
|
||||||
|
return (rStatus & (1 << 0)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2cDev_BMX280::read_coeff() {
|
||||||
|
_dig_T1 = read16_LE_1(BMX280_REG_DIG_T1);
|
||||||
|
_dig_T2 = readS16_LE_1(BMX280_REG_DIG_T2);
|
||||||
|
_dig_T3 = readS16_LE_1(BMX280_REG_DIG_T3);
|
||||||
|
|
||||||
|
_dig_P1 = read16_LE_1(BMX280_REG_DIG_P1);
|
||||||
|
_dig_P2 = readS16_LE_1(BMX280_REG_DIG_P2);
|
||||||
|
_dig_P3 = readS16_LE_1(BMX280_REG_DIG_P3);
|
||||||
|
_dig_P4 = readS16_LE_1(BMX280_REG_DIG_P4);
|
||||||
|
_dig_P5 = readS16_LE_1(BMX280_REG_DIG_P5);
|
||||||
|
_dig_P6 = readS16_LE_1(BMX280_REG_DIG_P6);
|
||||||
|
_dig_P7 = readS16_LE_1(BMX280_REG_DIG_P7);
|
||||||
|
_dig_P8 = readS16_LE_1(BMX280_REG_DIG_P8);
|
||||||
|
_dig_P9 = readS16_LE_1(BMX280_REG_DIG_P9);
|
||||||
|
|
||||||
|
if (model == I2C_DEVMDL::I2CDEVMDL_BME280) {
|
||||||
|
_dig_H1 = read8_1(BME280_REG_DIG_H1);
|
||||||
|
_dig_H2 = readS16_LE_1(BME280_REG_DIG_H2);
|
||||||
|
_dig_H3 = read8_1(BME280_REG_DIG_H3);
|
||||||
|
_dig_H4 = ((int8_t)read8_1(BME280_REG_DIG_H4) << 4) | (read8_1(BME280_REG_DIG_H4 + 1) & 0xF);
|
||||||
|
_dig_H5 = ((int8_t)read8_1(BME280_REG_DIG_H5 + 1) << 4) | (read8_1(BME280_REG_DIG_H5) >> 4);
|
||||||
|
_dig_H6 = (int8_t)read8_1(BME280_REG_DIG_H6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2cDev_BMX280::set_sampling() {
|
||||||
|
//
|
||||||
|
write8_1(BMX280_REG_CTRL_MEAS, BMX280_MODE_SLEEP);
|
||||||
|
write8_1(BMX280_REG_CONFIG, (uint8_t)((BMX280_STANDBY_MS_0_5 << 5) | (BMX280_FILTER_OFF << 2)));
|
||||||
|
if (model == I2C_DEVMDL::I2CDEVMDL_BME280) write8_1(BME280_REG_CTRL_HUM, BMX280_SAMPLING_X16);
|
||||||
|
write8_1(BMX280_REG_CTRL_MEAS, (uint8_t)((BMX280_SAMPLING_X16 << 5) | (BMX280_SAMPLING_X16 << 2) | BMX280_MODE_NORMAL));
|
||||||
|
}
|
||||||
|
|
||||||
|
float I2cDev_BMX280::read_temperature() {
|
||||||
|
int32_t var1, var2;
|
||||||
|
|
||||||
|
int32_t adc_T = read24_1(BMX280_REG_TEMP);
|
||||||
|
if (adc_T == 0x800000) // value in case temp measurement was disabled
|
||||||
|
return 0;
|
||||||
|
adc_T >>= 4;
|
||||||
|
|
||||||
|
var1 = (int32_t)((adc_T / 8) - ((int32_t)_dig_T1 * 2));
|
||||||
|
var1 = (var1 * ((int32_t)_dig_T2)) / 2048;
|
||||||
|
var2 = (int32_t)((adc_T / 16) - ((int32_t)_dig_T1));
|
||||||
|
var2 = (((var2 * var2) / 4096) * ((int32_t)_dig_T3)) / 16384;
|
||||||
|
|
||||||
|
_t_fine = var1 + var2; // + t_fine_adjust;
|
||||||
|
|
||||||
|
int32_t T = (_t_fine * 5 + 128) / 256;
|
||||||
|
return (float)T / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
float I2cDev_BMX280::read_pressure() {
|
||||||
|
int64_t var1, var2, var3, var4;
|
||||||
|
|
||||||
|
// readTemperature(); // must be done first to get t_fine
|
||||||
|
|
||||||
|
int32_t adc_P = read24_1(BMX280_REG_PRESS);
|
||||||
|
if (adc_P == 0x800000) // value in case pressure measurement was disabled
|
||||||
|
return 0;
|
||||||
|
adc_P >>= 4;
|
||||||
|
|
||||||
|
var1 = ((int64_t)_t_fine) - 128000;
|
||||||
|
var2 = var1 * var1 * (int64_t)_dig_P6;
|
||||||
|
var2 = var2 + ((var1 * (int64_t)_dig_P5) * 131072);
|
||||||
|
var2 = var2 + (((int64_t)_dig_P4) * 34359738368);
|
||||||
|
var1 = ((var1 * var1 * (int64_t)_dig_P3) / 256) +
|
||||||
|
((var1 * ((int64_t)_dig_P2) * 4096));
|
||||||
|
var3 = ((int64_t)1) * 140737488355328;
|
||||||
|
var1 = (var3 + var1) * ((int64_t)_dig_P1) / 8589934592;
|
||||||
|
|
||||||
|
if (var1 == 0) {
|
||||||
|
return 0; // avoid exception caused by division by zero
|
||||||
|
}
|
||||||
|
|
||||||
|
var4 = 1048576 - adc_P;
|
||||||
|
var4 = (((var4 * 2147483648) - var2) * 3125) / var1;
|
||||||
|
var1 = (((int64_t)_dig_P9) * (var4 / 8192) * (var4 / 8192)) /
|
||||||
|
33554432;
|
||||||
|
var2 = (((int64_t)_dig_P8) * var4) / 524288;
|
||||||
|
var4 = ((var4 + var1 + var2) / 256) + (((int64_t)_dig_P7) * 16);
|
||||||
|
|
||||||
|
float P = var4 / 256.0;
|
||||||
|
return P / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
float I2cDev_BMX280::read_humidity() {
|
||||||
|
if (model != I2C_DEVMDL::I2CDEVMDL_BME280) return 0;
|
||||||
|
int32_t var1, var2, var3, var4, var5;
|
||||||
|
// readTemperature(); // must be done first to get t_fine
|
||||||
|
int32_t adc_H = read16_1(BME280_REG_HUM);
|
||||||
|
if (adc_H == 0x8000) // value in case humidity measurement was disabled
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var1 = _t_fine - ((int32_t)76800);
|
||||||
|
var2 = (int32_t)(adc_H * 16384);
|
||||||
|
var3 = (int32_t)(((int32_t)_dig_H4) * 1048576);
|
||||||
|
var4 = ((int32_t)_dig_H5) * var1;
|
||||||
|
var5 = (((var2 - var3) - var4) + (int32_t)16384) / 32768;
|
||||||
|
var2 = (var1 * ((int32_t)_dig_H6)) / 1024;
|
||||||
|
var3 = (var1 * ((int32_t)_dig_H3)) / 2048;
|
||||||
|
var4 = ((var2 * (var3 + (int32_t)32768)) / 1024) + (int32_t)2097152;
|
||||||
|
var2 = ((var4 * ((int32_t)_dig_H2)) + 8192) / 16384;
|
||||||
|
var3 = var5 * var2;
|
||||||
|
var4 = ((var3 / 32768) * (var3 / 32768)) / 128;
|
||||||
|
var5 = var3 - ((var4 * ((int32_t)_dig_H1)) / 16);
|
||||||
|
var5 = (var5 < 0 ? 0 : var5);
|
||||||
|
var5 = (var5 > 419430400 ? 419430400 : var5);
|
||||||
|
uint32_t H = (uint32_t)(var5 / 4096);
|
||||||
|
return (float)H / 1024.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace i2cdev
|
133
firmware/common/i2cdev_bmx280.hpp
Normal file
133
firmware/common/i2cdev_bmx280.hpp
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 HTotoo.
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
DEAR DEVS THIS IS AN EXAMPLE FILE FOR i2C COMMUNICATION
|
||||||
|
YOU have to derive your class from I2cDev and override the init(), and the update()
|
||||||
|
The update() query the device, and send the corresponding Message to the system with the data.
|
||||||
|
The init() must check the device if it is really that this driver meant to handle, and fully set the device up. If all ok, set the device's model to the corresponting enum value from "i2cdevlist.hpp" and return true. Othervise false, so next driver can check it. (since multiple different devices manufactured with the same addr)
|
||||||
|
|
||||||
|
You can create custom functions, that can be called from any app that identifies the device and casts the I2cDev to your class.
|
||||||
|
This can be checked by query the 'model' variable.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
- Add this new module name in the i2cdevlist.hpp's enum (to the end)
|
||||||
|
- Create a hpp and cpp. (in the init SET THE MODULE to the prev enum value you created). If the filename is i2cdev_*.cpp it'll be added to cmake automatically.
|
||||||
|
- Add this header to i2cdevmanager.cpp, and add an if statement and the init code to the I2CDevManager::found() function. (see examples)
|
||||||
|
- Compile and test.
|
||||||
|
- Create a PR.
|
||||||
|
|
||||||
|
Notes: try to create a minimal code, to save FW space.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __I2CDEV_BMP280_H__
|
||||||
|
#define __I2CDEV_BMP280_H__
|
||||||
|
|
||||||
|
#include "i2cdevmanager.hpp"
|
||||||
|
|
||||||
|
namespace i2cdev {
|
||||||
|
|
||||||
|
// Register defines
|
||||||
|
#define BMX280_REG_DIG_T1 0x88 //!< Temperature coefficient register
|
||||||
|
#define BMX280_REG_DIG_T2 0x8A //!< Temperature coefficient register
|
||||||
|
#define BMX280_REG_DIG_T3 0x8C //!< Temperature coefficient register
|
||||||
|
|
||||||
|
#define BMX280_REG_DIG_P1 0x8E //!< Pressure coefficient register
|
||||||
|
#define BMX280_REG_DIG_P2 0x90 //!< Pressure coefficient register
|
||||||
|
#define BMX280_REG_DIG_P3 0x92 //!< Pressure coefficient register
|
||||||
|
#define BMX280_REG_DIG_P4 0x94 //!< Pressure coefficient register
|
||||||
|
#define BMX280_REG_DIG_P5 0x96 //!< Pressure coefficient register
|
||||||
|
#define BMX280_REG_DIG_P6 0x98 //!< Pressure coefficient register
|
||||||
|
#define BMX280_REG_DIG_P7 0x9A //!< Pressure coefficient register
|
||||||
|
#define BMX280_REG_DIG_P8 0x9C //!< Pressure coefficient register
|
||||||
|
#define BMX280_REG_DIG_P9 0x9E //!< Pressure coefficient register
|
||||||
|
|
||||||
|
#define BME280_REG_DIG_H1 0xA1 //!< Humidity coefficient register
|
||||||
|
#define BME280_REG_DIG_H2 0xE1 //!< Humidity coefficient register
|
||||||
|
#define BME280_REG_DIG_H3 0xE3 //!< Humidity coefficient register
|
||||||
|
#define BME280_REG_DIG_H4 0xE4 //!< Humidity coefficient register
|
||||||
|
#define BME280_REG_DIG_H5 0xE5 //!< Humidity coefficient register
|
||||||
|
#define BME280_REG_DIG_H6 0xE7 //!< Humidity coefficient register
|
||||||
|
|
||||||
|
#define BME280_REG_CHIPID 0xD0 //!< Chip ID register
|
||||||
|
#define BME280_REG_RESET 0xE0 //!< Reset register
|
||||||
|
|
||||||
|
#define BME280_REG_CTRL_HUM 0xF2 //!< BME280: Control humidity register
|
||||||
|
#define BMX280_REG_STATUS 0XF3 //!< Status register
|
||||||
|
#define BMX280_REG_CTRL_MEAS 0xF4 //!< Control measure register
|
||||||
|
#define BMX280_REG_CONFIG 0xF5 //!< Config register
|
||||||
|
#define BMX280_REG_PRESS 0xF7 //!< Pressure data register
|
||||||
|
#define BMX280_REG_TEMP 0xFA //!< Temperature data register
|
||||||
|
#define BME280_REG_HUM 0xFD //!< Humidity data register
|
||||||
|
|
||||||
|
// Bit defines
|
||||||
|
#define CHIP_ID_BMP280 0x58 //!< BMP280 chip ID
|
||||||
|
#define CHIP_ID_BME280 0x60 //!< BME280 chip ID
|
||||||
|
#define RESET_KEY 0xB6 //!< Reset value for reset register
|
||||||
|
#define STATUS_IM_UPDATE 0 //!< im_update bit in status register
|
||||||
|
|
||||||
|
#define BMX280_SAMPLING_X4 0b011
|
||||||
|
#define BMX280_SAMPLING_X16 0b101
|
||||||
|
#define BMX280_FILTER_OFF 0
|
||||||
|
#define BMX280_STANDBY_MS_0_5 0
|
||||||
|
#define BMX280_MODE_NORMAL 0b11
|
||||||
|
#define BMX280_MODE_SLEEP 0b00
|
||||||
|
|
||||||
|
class I2cDev_BMX280 : public I2cDev {
|
||||||
|
public:
|
||||||
|
bool init(uint8_t addr_) override; // sets the addr to our local variable, set the model, try to init the module, and only return true if it is really that module, and inited ok
|
||||||
|
void update() override; // query the module for recent data, and send it to the system via the corresponding Message
|
||||||
|
|
||||||
|
private:
|
||||||
|
// driver specific stuff
|
||||||
|
void read_coeff();
|
||||||
|
void set_sampling();
|
||||||
|
float read_temperature();
|
||||||
|
float read_pressure();
|
||||||
|
float read_humidity();
|
||||||
|
bool is_reading_calib();
|
||||||
|
uint16_t _dig_T1 = 0;
|
||||||
|
int16_t _dig_T2 = 0;
|
||||||
|
int16_t _dig_T3 = 0;
|
||||||
|
|
||||||
|
uint16_t _dig_P1 = 0;
|
||||||
|
int16_t _dig_P2 = 0;
|
||||||
|
int16_t _dig_P3 = 0;
|
||||||
|
int16_t _dig_P4 = 0;
|
||||||
|
int16_t _dig_P5 = 0;
|
||||||
|
int16_t _dig_P6 = 0;
|
||||||
|
int16_t _dig_P7 = 0;
|
||||||
|
int16_t _dig_P8 = 0;
|
||||||
|
int16_t _dig_P9 = 0;
|
||||||
|
|
||||||
|
uint8_t _dig_H1 = 0;
|
||||||
|
int16_t _dig_H2 = 0;
|
||||||
|
uint8_t _dig_H3 = 0;
|
||||||
|
int16_t _dig_H4 = 0;
|
||||||
|
int16_t _dig_H5 = 0;
|
||||||
|
int8_t _dig_H6 = 0;
|
||||||
|
|
||||||
|
int32_t _t_fine = 0;
|
||||||
|
};
|
||||||
|
} // namespace i2cdev
|
||||||
|
|
||||||
|
#endif
|
@ -19,17 +19,17 @@ along with this program; see the file COPYING. If not, write to
|
|||||||
the Free Software Foundation, Inc., 51 Franklin Street,
|
the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
Boston, MA 02110-1301, USA.
|
Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
#include "max17055.hpp"
|
#include "i2cdev_max17055.hpp"
|
||||||
|
#include "battery.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
#include "portapack_persistent_memory.hpp"
|
#include "portapack_persistent_memory.hpp"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace battery {
|
namespace i2cdev {
|
||||||
namespace max17055 {
|
|
||||||
|
|
||||||
const RegisterEntry MAX17055::entries[] = {
|
const I2cDev_MAX17055::RegisterEntry I2cDev_MAX17055::entries[] = {
|
||||||
{"Status", 0x00, "", 1, false, "", false, 0, true, false, false, 0, false},
|
{"Status", 0x00, "", 1, false, "", false, 0, true, false, false, 0, false},
|
||||||
{"VAlrtTh", 0x01, "", 1, false, "", false, 0, true, false, false, 0, false},
|
{"VAlrtTh", 0x01, "", 1, false, "", false, 0, true, false, false, 0, false},
|
||||||
{"TAlrtTh", 0x02, "", 1, false, "", false, 0, true, false, false, 0, false},
|
{"TAlrtTh", 0x02, "", 1, false, "", false, 0, true, false, false, 0, false},
|
||||||
@ -184,11 +184,24 @@ const RegisterEntry MAX17055::entries[] = {
|
|||||||
{"Reserved", 0xFF, "", 0.00390625, false, "%", true, 6, true, false, false, 0, true},
|
{"Reserved", 0xFF, "", 0.00390625, false, "%", true, 6, true, false, false, 0, true},
|
||||||
};
|
};
|
||||||
|
|
||||||
void MAX17055::init() {
|
void I2cDev_MAX17055::update() {
|
||||||
if (!detected_) {
|
uint8_t validity = 0;
|
||||||
detected_ = detect();
|
uint8_t batteryPercentage = 102;
|
||||||
}
|
uint16_t voltage = 0;
|
||||||
if (detected_) {
|
int32_t current = 0;
|
||||||
|
getBatteryInfo(validity, batteryPercentage, voltage, current);
|
||||||
|
|
||||||
|
// send local message
|
||||||
|
BatteryStateMessage msg{validity, batteryPercentage, current >= 0, voltage};
|
||||||
|
EventDispatcher::send_message(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I2cDev_MAX17055::init(uint8_t addr_) {
|
||||||
|
if (addr_ != I2CDEV_MAX17055_ADDR_1) return false;
|
||||||
|
addr = addr_;
|
||||||
|
model = I2CDEVMDL_MAX17055;
|
||||||
|
query_interval = BATTERY_WIDGET_REFRESH_INTERVAL;
|
||||||
|
if (detect()) {
|
||||||
if (needsInitialization()) {
|
if (needsInitialization()) {
|
||||||
// First-time or POR initialization
|
// First-time or POR initialization
|
||||||
full_reset_and_init();
|
full_reset_and_init();
|
||||||
@ -198,10 +211,12 @@ void MAX17055::init() {
|
|||||||
}
|
}
|
||||||
partialInit();
|
partialInit();
|
||||||
// statusClear(); I am not sure if this should be here or not
|
// statusClear(); I am not sure if this should be here or not
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::full_reset_and_init() {
|
bool I2cDev_MAX17055::full_reset_and_init() {
|
||||||
if (!soft_reset()) {
|
if (!soft_reset()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -221,11 +236,11 @@ bool MAX17055::full_reset_and_init() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::soft_reset() {
|
bool I2cDev_MAX17055::soft_reset() {
|
||||||
return write_register(0x0BB, 0x0000);
|
return write_register(0x0BB, 0x0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::initialize_custom_parameters() {
|
bool I2cDev_MAX17055::initialize_custom_parameters() {
|
||||||
if (!write_register(0xD0, 0x03E8)) return false; // Unknown register, possibly related to battery profile
|
if (!write_register(0xD0, 0x03E8)) return false; // Unknown register, possibly related to battery profile
|
||||||
if (!write_register(0xDB, 0x0000)) return false; // ModelCfg
|
if (!write_register(0xDB, 0x0000)) return false; // ModelCfg
|
||||||
if (!write_register(0x05, 0x0000)) return false; // RepCap
|
if (!write_register(0x05, 0x0000)) return false; // RepCap
|
||||||
@ -241,7 +256,7 @@ bool MAX17055::initialize_custom_parameters() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::load_custom_parameters() {
|
bool I2cDev_MAX17055::load_custom_parameters() {
|
||||||
uint16_t hib_cfg = read_register(0xBA);
|
uint16_t hib_cfg = read_register(0xBA);
|
||||||
if (!write_register(0xBA, 0x0000)) return false; // Disable hibernate mode
|
if (!write_register(0xBA, 0x0000)) return false; // Disable hibernate mode
|
||||||
if (!write_register(0x60, 0x0000)) return false; // Unknown register
|
if (!write_register(0x60, 0x0000)) return false; // Unknown register
|
||||||
@ -259,13 +274,13 @@ bool MAX17055::load_custom_parameters() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::clear_por() {
|
bool I2cDev_MAX17055::clear_por() {
|
||||||
uint16_t status = read_register(0x00);
|
uint16_t status = read_register(0x00);
|
||||||
status &= ~(1 << 1);
|
status &= ~(1 << 1);
|
||||||
return write_register(0x00, status);
|
return write_register(0x00, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::needsInitialization() {
|
bool I2cDev_MAX17055::needsInitialization() {
|
||||||
uint16_t UserMem1 = read_register(0x40);
|
uint16_t UserMem1 = read_register(0x40);
|
||||||
|
|
||||||
if (UserMem1 == 0) {
|
if (UserMem1 == 0) {
|
||||||
@ -274,41 +289,38 @@ bool MAX17055::needsInitialization() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MAX17055::partialInit() {
|
void I2cDev_MAX17055::partialInit() {
|
||||||
// Only update necessary volatile settings
|
// Only update necessary volatile settings
|
||||||
setHibCFG(0x0000); // If you always want hibernation disabled
|
setHibCFG(0x0000); // If you always want hibernation disabled
|
||||||
// Add any other volatile settings that need updating
|
// Add any other volatile settings that need updating
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::reset_learned() {
|
bool I2cDev_MAX17055::reset_learned() {
|
||||||
// this if for reset all the learned parameters by ic
|
// this if for reset all the learned parameters by ic
|
||||||
// the full inis should do this
|
// the full inis should do this
|
||||||
full_reset_and_init();
|
full_reset_and_init();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::detect() {
|
bool I2cDev_MAX17055::detect() {
|
||||||
// Read the DevName register (0x21)
|
// Read the DevName register (0x21)
|
||||||
uint16_t dev_name = read_register(0x21);
|
uint16_t dev_name = read_register(0x21);
|
||||||
|
|
||||||
// The DevName register should return 0x4010 for MAX17055
|
// The DevName register should return 0x4010 for MAX17055
|
||||||
if (dev_name == 0x4010) {
|
if (dev_name == 0x4010) {
|
||||||
detected_ = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If DevName doesn't match, try reading Status register as a fallback
|
// If DevName doesn't match, try reading Status register as a fallback
|
||||||
uint16_t status = read_register(0x00);
|
uint16_t status = read_register(0x00);
|
||||||
if (status != 0xFFFF && status != 0x0000) {
|
if (status != 0xFFFF && status != 0x0000) {
|
||||||
detected_ = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
detected_ = false;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RegisterEntry* MAX17055::findEntry(const char* name) const {
|
const I2cDev_MAX17055::RegisterEntry* I2cDev_MAX17055::findEntry(const char* name) const {
|
||||||
for (const auto& entry : entries) {
|
for (const auto& entry : entries) {
|
||||||
if (std::strcmp(entry.name, name) == 0) {
|
if (std::strcmp(entry.name, name) == 0) {
|
||||||
return &entry;
|
return &entry;
|
||||||
@ -317,48 +329,47 @@ const RegisterEntry* MAX17055::findEntry(const char* name) const {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t MAX17055::read_register(const uint8_t reg) {
|
uint16_t I2cDev_MAX17055::read_register(const uint8_t reg) {
|
||||||
const std::array<uint8_t, 1> tx{reg};
|
const std::array<uint8_t, 1> tx{reg};
|
||||||
std::array<uint8_t, 2> rx{0x00, 0x00};
|
std::array<uint8_t, 2> rx{0x00, 0x00};
|
||||||
|
|
||||||
bus.transmit(bus_address, tx.data(), tx.size());
|
i2cbus.transmit(addr, tx.data(), tx.size());
|
||||||
bus.receive(bus_address, rx.data(), rx.size());
|
i2cbus.receive(addr, rx.data(), rx.size());
|
||||||
|
|
||||||
// Combine the two bytes into a 16-bit value
|
// Combine the two bytes into a 16-bit value
|
||||||
// little-endian format (LSB first)
|
// little-endian format (LSB first)
|
||||||
return static_cast<uint16_t>((rx[1] << 8) | rx[0]);
|
return static_cast<uint16_t>((rx[1] << 8) | rx[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::write_register(const uint8_t reg, const uint16_t value) {
|
bool I2cDev_MAX17055::write_register(const uint8_t reg, const uint16_t value) {
|
||||||
std::array<uint8_t, 3> tx;
|
std::array<uint8_t, 3> tx;
|
||||||
tx[0] = reg;
|
tx[0] = reg;
|
||||||
tx[1] = value & 0xFF; // Low byte
|
tx[1] = value & 0xFF; // Low byte
|
||||||
tx[2] = (value >> 8) & 0xFF; // High byte
|
tx[2] = (value >> 8) & 0xFF; // High byte
|
||||||
|
|
||||||
bool success = bus.transmit(bus_address, tx.data(), tx.size());
|
bool success = i2cbus.transmit(addr, tx.data(), tx.size());
|
||||||
chThdSleepMilliseconds(1);
|
chThdSleepMilliseconds(1);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MAX17055::getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current) {
|
void I2cDev_MAX17055::getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current) {
|
||||||
if (detected_) {
|
// Read Status Register
|
||||||
// Read Status Register
|
uint16_t status = read_register(0x00);
|
||||||
uint16_t status = read_register(0x00);
|
voltage = averageMVoltage();
|
||||||
voltage = averageMVoltage();
|
if ((status == 0 && voltage == 0) || (status == 0x0002 && voltage == 3600) || (status == 0x0002 && voltage == 0)) {
|
||||||
if ((status == 0 && voltage == 0) || (status == 0x0002 && voltage == 3600) || (status == 0x0002 && voltage == 0)) {
|
|
||||||
valid_mask = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
batteryPercentage = stateOfCharge();
|
|
||||||
current = instantCurrent();
|
|
||||||
valid_mask = 31; // BATT_VALID_VOLTAGE + CURRENT + PERCENT + BATT_VALID_CYCLES + BATT_VALID_TTEF
|
|
||||||
} else {
|
|
||||||
// let's indicate the data is wrong. ui will handle this by display UNK values.
|
|
||||||
valid_mask = 0;
|
valid_mask = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
batteryPercentage = stateOfCharge();
|
||||||
|
current = instantCurrent();
|
||||||
|
valid_mask = 31; // BATT_VALID_VOLTAGE + CURRENT + PERCENT + BATT_VALID_CYCLES + BATT_VALID_TTEF
|
||||||
|
if (battery::BatteryManagement::calcOverride) {
|
||||||
|
valid_mask &= ~battery::BatteryManagement::BATT_VALID_PERCENT; // indicate it is voltage based
|
||||||
|
batteryPercentage = battery::BatteryManagement::calc_percent_voltage(voltage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float MAX17055::getValue(const char* entityName) {
|
float I2cDev_MAX17055::getValue(const char* entityName) {
|
||||||
const RegisterEntry* entry = findEntry(entityName);
|
const RegisterEntry* entry = findEntry(entityName);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
uint16_t raw_value = read_register(entry->address);
|
uint16_t raw_value = read_register(entry->address);
|
||||||
@ -376,11 +387,11 @@ float MAX17055::getValue(const char* entityName) {
|
|||||||
return 0; // Return 0 if entry not found
|
return 0; // Return 0 if entry not found
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t MAX17055::averageMVoltage(void) {
|
uint16_t I2cDev_MAX17055::averageMVoltage(void) {
|
||||||
return static_cast<uint16_t>(getValue("AvgVCell") * 1000.0f); // Convert to millivolts
|
return static_cast<uint16_t>(getValue("AvgVCell") * 1000.0f); // Convert to millivolts
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t MAX17055::instantCurrent(void) {
|
int32_t I2cDev_MAX17055::instantCurrent(void) {
|
||||||
return getValue("Current");
|
return getValue("Current");
|
||||||
|
|
||||||
// Get Data from IC
|
// Get Data from IC
|
||||||
@ -395,11 +406,11 @@ int32_t MAX17055::instantCurrent(void) {
|
|||||||
return _Value;
|
return _Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t MAX17055::stateOfCharge(void) {
|
uint16_t I2cDev_MAX17055::stateOfCharge(void) {
|
||||||
return getValue("RepSOC");
|
return getValue("RepSOC");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setEmptyVoltage(uint16_t _Empty_Voltage) {
|
bool I2cDev_MAX17055::setEmptyVoltage(uint16_t _Empty_Voltage) {
|
||||||
// Calculate the new VE_Empty value (upper 9 bits)
|
// Calculate the new VE_Empty value (upper 9 bits)
|
||||||
uint16_t ve_empty = ((_Empty_Voltage * 100) / 10) & 0xFF80;
|
uint16_t ve_empty = ((_Empty_Voltage * 100) / 10) & 0xFF80;
|
||||||
|
|
||||||
@ -413,7 +424,7 @@ bool MAX17055::setEmptyVoltage(uint16_t _Empty_Voltage) {
|
|||||||
return write_register(0x3A, new_value);
|
return write_register(0x3A, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setRecoveryVoltage(uint16_t _Recovery_Voltage) {
|
bool I2cDev_MAX17055::setRecoveryVoltage(uint16_t _Recovery_Voltage) {
|
||||||
// Calculate the new VR_Empty value (lower 7 bits)
|
// Calculate the new VR_Empty value (lower 7 bits)
|
||||||
uint16_t vr_empty = (_Recovery_Voltage * 25) & 0x007F; // 40mV per bit, 25 = 1000/40
|
uint16_t vr_empty = (_Recovery_Voltage * 25) & 0x007F; // 40mV per bit, 25 = 1000/40
|
||||||
|
|
||||||
@ -427,7 +438,7 @@ bool MAX17055::setRecoveryVoltage(uint16_t _Recovery_Voltage) {
|
|||||||
return write_register(0x3A, new_value);
|
return write_register(0x3A, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setMinVoltage(uint16_t _Minimum_Voltage) {
|
bool I2cDev_MAX17055::setMinVoltage(uint16_t _Minimum_Voltage) {
|
||||||
uint16_t current_value = read_register(0x01);
|
uint16_t current_value = read_register(0x01);
|
||||||
|
|
||||||
uint16_t min_voltage_raw = (_Minimum_Voltage * 50) & 0x00FF; // 20mV per bit, 50 = 1000/20
|
uint16_t min_voltage_raw = (_Minimum_Voltage * 50) & 0x00FF; // 20mV per bit, 50 = 1000/20
|
||||||
@ -436,7 +447,7 @@ bool MAX17055::setMinVoltage(uint16_t _Minimum_Voltage) {
|
|||||||
return write_register(0x01, new_value);
|
return write_register(0x01, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setMaxVoltage(uint16_t _Maximum_Voltage) {
|
bool I2cDev_MAX17055::setMaxVoltage(uint16_t _Maximum_Voltage) {
|
||||||
uint16_t current_value = read_register(0x01);
|
uint16_t current_value = read_register(0x01);
|
||||||
|
|
||||||
uint16_t max_voltage_raw = ((_Maximum_Voltage * 50) & 0x00FF) << 8; // 20mV per bit, 50 = 1000/20
|
uint16_t max_voltage_raw = ((_Maximum_Voltage * 50) & 0x00FF) << 8; // 20mV per bit, 50 = 1000/20
|
||||||
@ -445,7 +456,7 @@ bool MAX17055::setMaxVoltage(uint16_t _Maximum_Voltage) {
|
|||||||
return write_register(0x01, new_value);
|
return write_register(0x01, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setMaxCurrent(uint16_t _Maximum_Current) {
|
bool I2cDev_MAX17055::setMaxCurrent(uint16_t _Maximum_Current) {
|
||||||
uint16_t current_value = read_register(0xB4);
|
uint16_t current_value = read_register(0xB4);
|
||||||
|
|
||||||
uint16_t max_current_raw = ((_Maximum_Current * 25) & 0x00FF) << 8; // 40mV per bit, 25 = 1000/40
|
uint16_t max_current_raw = ((_Maximum_Current * 25) & 0x00FF) << 8; // 40mV per bit, 25 = 1000/40
|
||||||
@ -454,34 +465,34 @@ bool MAX17055::setMaxCurrent(uint16_t _Maximum_Current) {
|
|||||||
return write_register(0xB4, new_value);
|
return write_register(0xB4, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setChargeTerminationCurrent(uint16_t _Charge_Termination_Current) {
|
bool I2cDev_MAX17055::setChargeTerminationCurrent(uint16_t _Charge_Termination_Current) {
|
||||||
float lsb_mA = 1.5625 / (__MAX17055_Resistor__ * 1000); // Convert to mA
|
float lsb_mA = 1.5625 / (__MAX17055_Resistor__ * 1000); // Convert to mA
|
||||||
uint16_t ichgterm_value = static_cast<uint16_t>(round(_Charge_Termination_Current / lsb_mA));
|
uint16_t ichgterm_value = static_cast<uint16_t>(round(_Charge_Termination_Current / lsb_mA));
|
||||||
|
|
||||||
return write_register(0x1E, ichgterm_value);
|
return write_register(0x1E, ichgterm_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setDesignCapacity(const uint16_t _Capacity) {
|
bool I2cDev_MAX17055::setDesignCapacity(const uint16_t _Capacity) {
|
||||||
uint16_t raw_cap = (uint16_t)_Capacity * 2;
|
uint16_t raw_cap = (uint16_t)_Capacity * 2;
|
||||||
return write_register(0x18, raw_cap);
|
return write_register(0x18, raw_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setFullCapRep(const uint16_t _Capacity) {
|
bool I2cDev_MAX17055::setFullCapRep(const uint16_t _Capacity) {
|
||||||
uint16_t raw_cap = _Capacity * 2; // 0.5mAh per LSB
|
uint16_t raw_cap = _Capacity * 2; // 0.5mAh per LSB
|
||||||
return write_register(0x10, raw_cap);
|
return write_register(0x10, raw_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setFullCapNom(const uint16_t _Capacity) {
|
bool I2cDev_MAX17055::setFullCapNom(const uint16_t _Capacity) {
|
||||||
uint16_t raw_cap = _Capacity * 2; // 0.5mAh per LSB
|
uint16_t raw_cap = _Capacity * 2; // 0.5mAh per LSB
|
||||||
return write_register(0x23, raw_cap);
|
return write_register(0x23, raw_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setRepCap(const uint16_t _Capacity) {
|
bool I2cDev_MAX17055::setRepCap(const uint16_t _Capacity) {
|
||||||
uint16_t raw_cap = _Capacity * 2; // 0.5mAh per LSB
|
uint16_t raw_cap = _Capacity * 2; // 0.5mAh per LSB
|
||||||
return write_register(0x05, raw_cap);
|
return write_register(0x05, raw_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setMinSOC(uint8_t _Minimum_SOC) {
|
bool I2cDev_MAX17055::setMinSOC(uint8_t _Minimum_SOC) {
|
||||||
uint16_t current_value = read_register(0x03);
|
uint16_t current_value = read_register(0x03);
|
||||||
|
|
||||||
uint16_t min_soc_raw = ((_Minimum_SOC * 256) / 100) & 0x00FF;
|
uint16_t min_soc_raw = ((_Minimum_SOC * 256) / 100) & 0x00FF;
|
||||||
@ -490,7 +501,7 @@ bool MAX17055::setMinSOC(uint8_t _Minimum_SOC) {
|
|||||||
return write_register(0x03, new_value);
|
return write_register(0x03, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setMaxSOC(uint8_t _Maximum_SOC) {
|
bool I2cDev_MAX17055::setMaxSOC(uint8_t _Maximum_SOC) {
|
||||||
uint16_t current_value = read_register(0x03);
|
uint16_t current_value = read_register(0x03);
|
||||||
|
|
||||||
uint16_t max_soc_raw = (((_Maximum_SOC * 256) / 100) & 0x00FF) << 8;
|
uint16_t max_soc_raw = (((_Maximum_SOC * 256) / 100) & 0x00FF) << 8;
|
||||||
@ -499,7 +510,7 @@ bool MAX17055::setMaxSOC(uint8_t _Maximum_SOC) {
|
|||||||
return write_register(0x03, new_value);
|
return write_register(0x03, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setMinTemperature(uint8_t _Minimum_Temperature) {
|
bool I2cDev_MAX17055::setMinTemperature(uint8_t _Minimum_Temperature) {
|
||||||
uint16_t current_value = read_register(0x02);
|
uint16_t current_value = read_register(0x02);
|
||||||
|
|
||||||
uint16_t min_temp_raw = (uint8_t)_Minimum_Temperature;
|
uint16_t min_temp_raw = (uint8_t)_Minimum_Temperature;
|
||||||
@ -508,7 +519,7 @@ bool MAX17055::setMinTemperature(uint8_t _Minimum_Temperature) {
|
|||||||
return write_register(0x02, new_value);
|
return write_register(0x02, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setMaxTemperature(uint8_t _Maximum_Temperature) {
|
bool I2cDev_MAX17055::setMaxTemperature(uint8_t _Maximum_Temperature) {
|
||||||
uint16_t current_value = read_register(0x02);
|
uint16_t current_value = read_register(0x02);
|
||||||
|
|
||||||
uint16_t max_temp_raw = ((uint8_t)_Maximum_Temperature) << 8;
|
uint16_t max_temp_raw = ((uint8_t)_Maximum_Temperature) << 8;
|
||||||
@ -517,7 +528,7 @@ bool MAX17055::setMaxTemperature(uint8_t _Maximum_Temperature) {
|
|||||||
return write_register(0x02, new_value);
|
return write_register(0x02, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setModelCfg(const uint8_t _Model_ID) {
|
bool I2cDev_MAX17055::setModelCfg(const uint8_t _Model_ID) {
|
||||||
uint16_t model_cfg = 0x0400; // Set Charge Voltage (bit 10)
|
uint16_t model_cfg = 0x0400; // Set Charge Voltage (bit 10)
|
||||||
|
|
||||||
// Set Battery Model
|
// Set Battery Model
|
||||||
@ -537,11 +548,11 @@ bool MAX17055::setModelCfg(const uint8_t _Model_ID) {
|
|||||||
return write_register(0xDB, model_cfg);
|
return write_register(0xDB, model_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::setHibCFG(const uint16_t _Config) {
|
bool I2cDev_MAX17055::setHibCFG(const uint16_t _Config) {
|
||||||
return write_register(0xBA, _Config);
|
return write_register(0xBA, _Config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MAX17055::config(void) {
|
void I2cDev_MAX17055::config(void) {
|
||||||
uint16_t config1 = 0x0000;
|
uint16_t config1 = 0x0000;
|
||||||
uint16_t config2 = 0x0618; // Default value: 0b00011000 00000110
|
uint16_t config2 = 0x0618; // Default value: 0b00011000 00000110
|
||||||
|
|
||||||
@ -575,7 +586,7 @@ void MAX17055::config(void) {
|
|||||||
write_register(0xBB, config2);
|
write_register(0xBB, config2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::statusClear() {
|
bool I2cDev_MAX17055::statusClear() {
|
||||||
// Clear all bits in the Status register (0x00)
|
// Clear all bits in the Status register (0x00)
|
||||||
return write_register(0x00, 0x0000);
|
return write_register(0x00, 0x0000);
|
||||||
}
|
}
|
||||||
@ -584,7 +595,7 @@ bool bitRead(uint8_t value, uint8_t bit) {
|
|||||||
return (value >> bit) & 0x01;
|
return (value >> bit) & 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MAX17055::statusControl(const uint8_t _Status) {
|
bool I2cDev_MAX17055::statusControl(const uint8_t _Status) {
|
||||||
// Read Status Register (0x00)
|
// Read Status Register (0x00)
|
||||||
uint16_t status_register = read_register(0x00);
|
uint16_t status_register = read_register(0x00);
|
||||||
|
|
||||||
@ -621,5 +632,4 @@ bool MAX17055::statusControl(const uint8_t _Status) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace max17055 */
|
} /* namespace i2cdev */
|
||||||
} // namespace battery
|
|
@ -25,9 +25,9 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "battery.hpp"
|
#include "battery.hpp"
|
||||||
#include "i2c_pp.hpp"
|
|
||||||
|
#include "i2cdevmanager.hpp"
|
||||||
|
|
||||||
#define MAX17055_POR 0
|
#define MAX17055_POR 0
|
||||||
#define MAX17055_IMin 1
|
#define MAX17055_IMin 1
|
||||||
@ -248,41 +248,36 @@
|
|||||||
#define MAX17055_AtRateEn 0
|
#define MAX17055_AtRateEn 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace battery {
|
namespace i2cdev {
|
||||||
namespace max17055 {
|
|
||||||
|
|
||||||
using address_t = uint8_t;
|
using address_t = uint8_t;
|
||||||
|
|
||||||
struct RegisterEntry {
|
class I2cDev_MAX17055 : public I2cDev {
|
||||||
const char* name;
|
|
||||||
uint8_t address;
|
|
||||||
const char* type;
|
|
||||||
float scalar;
|
|
||||||
bool is_signed;
|
|
||||||
const char* unit;
|
|
||||||
bool abbr_units;
|
|
||||||
int resolution;
|
|
||||||
bool is_user;
|
|
||||||
bool is_save_restore;
|
|
||||||
bool is_nv;
|
|
||||||
uint16_t por_data;
|
|
||||||
bool is_read_only;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MAX17055 {
|
|
||||||
public:
|
public:
|
||||||
constexpr MAX17055(I2C& bus, const I2C::address_t bus_address)
|
struct RegisterEntry {
|
||||||
: bus(bus), bus_address(bus_address), detected_(false) {}
|
const char* name;
|
||||||
|
uint8_t address;
|
||||||
|
const char* type;
|
||||||
|
float scalar;
|
||||||
|
bool is_signed;
|
||||||
|
const char* unit;
|
||||||
|
bool abbr_units;
|
||||||
|
int resolution;
|
||||||
|
bool is_user;
|
||||||
|
bool is_save_restore;
|
||||||
|
bool is_nv;
|
||||||
|
uint16_t por_data;
|
||||||
|
bool is_read_only;
|
||||||
|
};
|
||||||
static const RegisterEntry entries[];
|
static const RegisterEntry entries[];
|
||||||
static constexpr size_t entries_count = 144;
|
static constexpr size_t entries_count = 144;
|
||||||
|
|
||||||
uint16_t read_register(const uint8_t reg);
|
uint16_t read_register(const uint8_t reg);
|
||||||
bool write_register(const uint8_t reg, const uint16_t value);
|
bool write_register(const uint8_t reg, const uint16_t value);
|
||||||
|
|
||||||
void init();
|
bool init(uint8_t addr_) override;
|
||||||
|
void update() override;
|
||||||
bool detect();
|
bool detect();
|
||||||
bool isDetected() const { return detected_; }
|
|
||||||
|
|
||||||
void getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current);
|
void getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current);
|
||||||
bool reset_learned();
|
bool reset_learned();
|
||||||
@ -293,10 +288,6 @@ class MAX17055 {
|
|||||||
uint16_t stateOfCharge(void);
|
uint16_t stateOfCharge(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
I2C& bus;
|
|
||||||
const I2C::address_t bus_address;
|
|
||||||
bool detected_ = false;
|
|
||||||
|
|
||||||
const RegisterEntry* findEntry(const char* name) const;
|
const RegisterEntry* findEntry(const char* name) const;
|
||||||
|
|
||||||
bool needsInitialization();
|
bool needsInitialization();
|
||||||
@ -330,6 +321,5 @@ class MAX17055 {
|
|||||||
void config(void);
|
void config(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace max17055 */
|
} /* namespace i2cdev */
|
||||||
} // namespace battery
|
|
||||||
#endif /* __MAX17055_H__ */
|
#endif /* __MAX17055_H__ */
|
62
firmware/common/i2cdev_sht3x.cpp
Normal file
62
firmware/common/i2cdev_sht3x.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 HTotoo.
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "i2cdev_sht3x.hpp"
|
||||||
|
|
||||||
|
namespace i2cdev {
|
||||||
|
|
||||||
|
bool I2cDev_SHT3x::init(uint8_t addr_) {
|
||||||
|
if (addr_ != I2CDEV_SHT3X_ADDR_1 && addr_ != I2CDEV_SHT3X_ADDR_2) return false;
|
||||||
|
addr = addr_; // store the addr
|
||||||
|
model = I2C_DEVMDL::I2CDEVMDL_SHT3X; // set the device model!!!!!!!!!!!!!!!!!!
|
||||||
|
query_interval = 5; // set update interval in sec
|
||||||
|
chThdSleepMilliseconds(50);
|
||||||
|
uint8_t tmp[2]; // command buffer
|
||||||
|
tmp[0] = 0x30;
|
||||||
|
tmp[1] = 0x66;
|
||||||
|
if (!i2c_write(nullptr, 0, tmp, 2)) return false; // heater off
|
||||||
|
chThdSleepMilliseconds(50);
|
||||||
|
tmp[0] = 0x22;
|
||||||
|
tmp[1] = 0x36;
|
||||||
|
if (!i2c_write(nullptr, 0, tmp, 2)) return false; // conti, 2mps
|
||||||
|
|
||||||
|
chThdSleepMilliseconds(50);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2cDev_SHT3x::update() {
|
||||||
|
float temp = 0;
|
||||||
|
float hum = 0;
|
||||||
|
uint8_t cmd[2];
|
||||||
|
cmd[0] = 0xe0;
|
||||||
|
cmd[1] = 0;
|
||||||
|
uint8_t res[6];
|
||||||
|
i2c_read(cmd, 2, res, 6);
|
||||||
|
uint16_t temptick = res[0] << 8 | res[1];
|
||||||
|
uint16_t humtick = res[3] << 8 | res[4];
|
||||||
|
|
||||||
|
temp = -45 + (((float)temptick * 175.0) / 65535.0);
|
||||||
|
hum = (100.0 * (float)humtick) / 65535.0;
|
||||||
|
EnvironmentDataMessage msg{temp, hum}; // create the system message
|
||||||
|
EventDispatcher::send_message(msg); // and send it
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace i2cdev
|
40
firmware/common/i2cdev_sht3x.hpp
Normal file
40
firmware/common/i2cdev_sht3x.hpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 HTotoo.
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __I2CDEV_SHT3X_H__
|
||||||
|
#define __I2CDEV_SHT3X_H__
|
||||||
|
|
||||||
|
#include "i2cdevmanager.hpp"
|
||||||
|
|
||||||
|
namespace i2cdev {
|
||||||
|
|
||||||
|
class I2cDev_SHT3x : public I2cDev {
|
||||||
|
public:
|
||||||
|
bool init(uint8_t addr_) override; // sets the addr to our local variable, set the model, try to init the module, and only return true if it is really that module, and inited ok
|
||||||
|
void update() override; // query the module for recent data, and send it to the system via the corresponding Message
|
||||||
|
|
||||||
|
private:
|
||||||
|
float read_temperature();
|
||||||
|
float read_humidity();
|
||||||
|
};
|
||||||
|
} // namespace i2cdev
|
||||||
|
|
||||||
|
#endif
|
53
firmware/common/i2cdevlist.hpp
Normal file
53
firmware/common/i2cdevlist.hpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 HTotoo.
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __I2CDEVLIST_H__
|
||||||
|
#define __I2CDEVLIST_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
DEAR DEVS: Put your new driver to this enum's end. Also consider using define to store it's address.
|
||||||
|
If the same driver can handle multiple devices, with different data, should use different names. Like BMP280 + BME280. If the data is the same across multiple devices, can use the same name. Like SHT3x (sht30, sht31, ..)
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum I2C_DEVMDL {
|
||||||
|
I2CDEVMDL_NOTSET, // i2c dev present, but no driver for it
|
||||||
|
I2CDEVMDL_MAX17055,
|
||||||
|
I2CDEVMDL_ADS1110,
|
||||||
|
I2CDEVMDL_SHT3X,
|
||||||
|
I2CDEVMDL_BMP280,
|
||||||
|
I2CDEVMDL_BME280,
|
||||||
|
I2CDECMDL_BH1750,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define I2CDEV_BMX280_ADDR_1 0x76
|
||||||
|
#define I2CDEV_BMX280_ADDR_2 0x77
|
||||||
|
#define I2CDEV_SHT3X_ADDR_1 0x44
|
||||||
|
#define I2CDEV_SHT3X_ADDR_2 0x45
|
||||||
|
|
||||||
|
#define I2CDEV_MAX17055_ADDR_1 0x36
|
||||||
|
#define I2CDEV_ADS1110_ADDR_1 0x48
|
||||||
|
|
||||||
|
#define I2CDEV_BH1750_ADDR_1 0x23
|
||||||
|
|
||||||
|
// this will be the update interval for battery management ic's:
|
||||||
|
#define BATTERY_WIDGET_REFRESH_INTERVAL 10
|
||||||
|
|
||||||
|
#endif
|
334
firmware/common/i2cdevmanager.cpp
Normal file
334
firmware/common/i2cdevmanager.cpp
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 HTotoo.
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include <algorithm>
|
||||||
|
#include "i2cdevmanager.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
DEAR DEVS.
|
||||||
|
Include your devices headers here:
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "i2cdev_bmx280.hpp"
|
||||||
|
#include "i2cdev_sht3x.hpp"
|
||||||
|
#include "i2cdev_max17055.hpp"
|
||||||
|
#include "i2cdev_ads1110.hpp"
|
||||||
|
#include "i2cdev_bh1750.hpp"
|
||||||
|
|
||||||
|
namespace i2cdev {
|
||||||
|
|
||||||
|
// statics
|
||||||
|
uint16_t I2CDevManager::scan_interval = 0;
|
||||||
|
bool I2CDevManager::force_scan = false;
|
||||||
|
Thread* I2CDevManager::thread;
|
||||||
|
std::vector<I2DevListElement> I2CDevManager::devlist;
|
||||||
|
Mutex I2CDevManager::mutex_list{};
|
||||||
|
|
||||||
|
/*
|
||||||
|
DEAR DEVELOPERS!
|
||||||
|
IF YOU WANT TO ADD NEW DERIVERS, PUT IT'S I2C ADDRESS AND INIT PART HERE.
|
||||||
|
THE INIT MUST RETURN FALSE, WHEN THE DEVICE NOT MATCH OR NOT WORKING.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool I2CDevManager::found(uint8_t addr) {
|
||||||
|
// check if present already
|
||||||
|
for (size_t i = 0; i < devlist.size(); i++) {
|
||||||
|
if (devlist[i].addr == addr) return false;
|
||||||
|
}
|
||||||
|
// try to find a suitable driver
|
||||||
|
I2DevListElement item;
|
||||||
|
item.addr = addr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
DEAR DEVS
|
||||||
|
Put your driver's init code here. ALLWAYS check the !item.dev, if any other driver already took it. Also check the addr if it suits your module. (also need additional checks in the init() code)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!item.dev && (addr == I2CDEV_BMX280_ADDR_1 || addr == I2CDEV_BMX280_ADDR_2)) { // check if device is already taken, and i can handle the address
|
||||||
|
item.dev = std::make_unique<I2cDev_BMX280>();
|
||||||
|
if (!item.dev->init(addr)) item.dev = nullptr; // if not inited, reset it's instance, and let other handlers try
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.dev && (addr == I2CDEV_SHT3X_ADDR_1 || addr == I2CDEV_SHT3X_ADDR_2)) {
|
||||||
|
item.dev = std::make_unique<I2cDev_SHT3x>();
|
||||||
|
if (!item.dev->init(addr)) item.dev = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.dev && (addr == I2CDEV_MAX17055_ADDR_1)) {
|
||||||
|
item.dev = std::make_unique<I2cDev_MAX17055>();
|
||||||
|
if (!item.dev->init(addr)) item.dev = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.dev && (addr == I2CDEV_ADS1110_ADDR_1)) {
|
||||||
|
item.dev = std::make_unique<I2cDev_ADS1110>();
|
||||||
|
if (!item.dev->init(addr)) item.dev = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.dev && (addr == I2CDEV_BH1750_ADDR_1)) {
|
||||||
|
item.dev = std::make_unique<I2cDev_BH1750>();
|
||||||
|
if (!item.dev->init(addr)) item.dev = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if can't find any driver, add it too with empty, so we won't try to init it again and again
|
||||||
|
devlist.push_back(std::move(item));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
FROM HERE YOU SHOULDN'T WRITE ANYTHING IF YOU JUST IMPLEMENT A NEW DRIVER
|
||||||
|
(maybe maximum i2c_rewd / write helpers)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
void I2cDev::set_update_interval(uint8_t interval) {
|
||||||
|
query_interval = interval;
|
||||||
|
}
|
||||||
|
uint8_t I2cDev::get_update_interval() {
|
||||||
|
return query_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2cDev::got_error() {
|
||||||
|
errcnt++;
|
||||||
|
if (errcnt >= 5) need_del = true; // too many errors. remove dev from list. may be re-discovered and re inited
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2cDev::got_success() {
|
||||||
|
errcnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
I2C read / write functions and helpers.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (!ret)
|
||||||
|
got_error();
|
||||||
|
else
|
||||||
|
got_success();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I2cDev::i2c_write(uint8_t* reg, uint8_t reg_size, uint8_t* data, uint8_t bytes) {
|
||||||
|
// Check if there's any data to write
|
||||||
|
if (bytes == 0) return false;
|
||||||
|
// Create a new buffer to hold both reg and data
|
||||||
|
uint8_t total_size = reg_size + bytes;
|
||||||
|
uint8_t* buffer = new uint8_t[total_size];
|
||||||
|
// Copy the register data into the buffer
|
||||||
|
if (reg_size > 0 && reg) {
|
||||||
|
memcpy(buffer, reg, reg_size);
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
// Clean up the dynamically allocated buffer
|
||||||
|
delete[] buffer;
|
||||||
|
if (!result)
|
||||||
|
got_error();
|
||||||
|
else
|
||||||
|
got_success();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I2cDev::write8_1(uint8_t reg, uint8_t data) {
|
||||||
|
return i2c_write(®, 1, &data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t I2cDev::read8_1(uint8_t reg) {
|
||||||
|
uint8_t res = 0;
|
||||||
|
i2c_read(®, 1, &res, 1);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t I2cDev::read16_1(uint8_t reg) {
|
||||||
|
uint8_t buffer[2];
|
||||||
|
i2c_read(®, 1, buffer, 2);
|
||||||
|
return uint16_t(buffer[0]) << 8 | uint16_t(buffer[1]);
|
||||||
|
}
|
||||||
|
uint32_t I2cDev::read24_1(uint8_t reg) {
|
||||||
|
uint8_t buffer[3];
|
||||||
|
i2c_read(®, 1, buffer, 2);
|
||||||
|
return uint32_t(buffer[0]) << 16 | uint32_t(buffer[1]) << 8 | uint32_t(buffer[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t I2cDev::readS16_1(uint8_t reg) {
|
||||||
|
return (int16_t)read16_1(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t I2cDev::read16_LE_1(uint8_t reg) {
|
||||||
|
uint16_t res = read16_1(reg);
|
||||||
|
res = (res >> 8) | (res << 8);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t I2cDev::readS16_LE_1(uint8_t reg) {
|
||||||
|
return (int16_t)read16_LE_1(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// END OF i2C communication + helpers
|
||||||
|
|
||||||
|
void I2CDevManager::init() {
|
||||||
|
force_scan = true;
|
||||||
|
create_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CDevManager::manual_scan() {
|
||||||
|
force_scan = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CDevManager::set_autoscan_interval(uint16_t interval) {
|
||||||
|
scan_interval = interval;
|
||||||
|
}
|
||||||
|
uint16_t I2CDevManager::get_autoscan_interval() {
|
||||||
|
return scan_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
I2cDev* I2CDevManager::get_dev_by_addr(uint8_t addr) {
|
||||||
|
chMtxLock(&mutex_list);
|
||||||
|
for (size_t i = 0; i < devlist.size(); i++) {
|
||||||
|
if (devlist[i].addr == addr) {
|
||||||
|
chMtxUnlock();
|
||||||
|
return devlist[i].dev.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chMtxUnlock();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
I2cDev* I2CDevManager::get_dev_by_model(I2C_DEVMDL model) {
|
||||||
|
chMtxLock(&mutex_list);
|
||||||
|
for (size_t i = 0; i < devlist.size(); i++) {
|
||||||
|
if (devlist[i].dev && devlist[i].dev->model == model) {
|
||||||
|
chMtxUnlock();
|
||||||
|
return devlist[i].dev.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chMtxUnlock();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<I2C_DEVMDL> I2CDevManager::get_dev_list_by_model() {
|
||||||
|
std::vector<I2C_DEVMDL> ret;
|
||||||
|
chMtxLock(&mutex_list);
|
||||||
|
for (size_t i = 0; i < devlist.size(); i++) {
|
||||||
|
if (devlist[i].dev) {
|
||||||
|
ret.push_back(devlist[i].dev->model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chMtxUnlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> I2CDevManager::get_gev_list_by_addr() {
|
||||||
|
std::vector<uint8_t> ret;
|
||||||
|
chMtxLock(&mutex_list);
|
||||||
|
for (size_t i = 0; i < devlist.size(); i++) {
|
||||||
|
if (devlist[i].addr) {
|
||||||
|
ret.push_back(devlist[i].addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chMtxUnlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I2CDevManager::scan() {
|
||||||
|
bool changed = false;
|
||||||
|
std::vector<uint8_t> currList;
|
||||||
|
for (uint8_t i = 1; i < 128; ++i) {
|
||||||
|
if (i2cbus.probe(i, 50)) {
|
||||||
|
chMtxLock(&mutex_list);
|
||||||
|
changed = changed | found(i);
|
||||||
|
chMtxUnlock();
|
||||||
|
currList.push_back(i);
|
||||||
|
}
|
||||||
|
chThdSleepMilliseconds(1);
|
||||||
|
}
|
||||||
|
// remove those not present
|
||||||
|
for (size_t i = 0; i < devlist.size(); ++i) {
|
||||||
|
if (std::find(currList.begin(), currList.end(), devlist[i].addr) == currList.end()) {
|
||||||
|
// found on our list, but now not discovered, so remove it
|
||||||
|
devlist[i].addr = 0; // mark to delete
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CDevManager::create_thread() {
|
||||||
|
chMtxInit(&mutex_list);
|
||||||
|
thread = chThdCreateFromHeap(NULL, 2048, NORMALPRIO, I2CDevManager::timer_fn, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_t I2CDevManager::timer_fn(void* arg) {
|
||||||
|
(void)arg;
|
||||||
|
uint16_t curr_timer = 0; // seconds since thread start
|
||||||
|
while (1) {
|
||||||
|
systime_t start_time = chTimeNow();
|
||||||
|
bool changed = false;
|
||||||
|
// check if i2c scan needed
|
||||||
|
if (force_scan || (scan_interval != 0 && curr_timer % scan_interval == 0)) {
|
||||||
|
changed = changed | scan();
|
||||||
|
force_scan = false;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < devlist.size(); i++) {
|
||||||
|
if (devlist[i].addr != 0 && devlist[i].dev) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove all unneeded items
|
||||||
|
chMtxLock(&mutex_list);
|
||||||
|
size_t cnt = devlist.size();
|
||||||
|
devlist.erase(std::remove_if(devlist.begin(), devlist.end(), [](const I2DevListElement& x) {
|
||||||
|
if (x.addr == 0) return true;
|
||||||
|
if (x.dev && x.dev->need_del == true) return true; // self destruct on too many errors
|
||||||
|
return false; // won't remove the unidentified ones, so we can list them, and not trying all the time with them
|
||||||
|
}),
|
||||||
|
devlist.end());
|
||||||
|
chMtxUnlock();
|
||||||
|
if (cnt != devlist.size()) changed = true;
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
I2CDevListChangedMessage msg{};
|
||||||
|
EventDispatcher::send_message(msg);
|
||||||
|
}
|
||||||
|
systime_t end_time = chTimeNow();
|
||||||
|
systime_t delta = (end_time > start_time) ? end_time - start_time : 100; // wont calculate overflow, just guess.
|
||||||
|
if (delta > 950) delta = 950; // ensure minimum 50 milli sleep
|
||||||
|
|
||||||
|
chThdSleepMilliseconds(1000 - delta); // 1sec timer
|
||||||
|
++curr_timer;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace i2cdev
|
104
firmware/common/i2cdevmanager.hpp
Normal file
104
firmware/common/i2cdevmanager.hpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 HTotoo.
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __I2CDEVMANAGER_H__
|
||||||
|
#define __I2CDEVMANAGER_H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include "ch.h"
|
||||||
|
#include "portapack.hpp"
|
||||||
|
#include "i2c_pp.hpp"
|
||||||
|
#include "i2cdevlist.hpp"
|
||||||
|
#include "event_m0.hpp"
|
||||||
|
|
||||||
|
#define i2cbus portapack::i2c0
|
||||||
|
|
||||||
|
extern I2C portapack::i2c0;
|
||||||
|
|
||||||
|
namespace i2cdev {
|
||||||
|
|
||||||
|
// The device class. You'll derive your from this. Override init() and update();
|
||||||
|
class I2cDev {
|
||||||
|
public:
|
||||||
|
virtual ~I2cDev(){};
|
||||||
|
virtual bool init(uint8_t addr); // 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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
bool i2c_read(uint8_t* reg, uint8_t reg_size, uint8_t* data, uint8_t bytes); // if want to read without register addr, just set reg_size to 0. this way can read 8, or 16 or 32 bit registers too. reg_size in bytes! returns true on succes. handles the errcnt automatically!
|
||||||
|
bool i2c_write(uint8_t* reg, uint8_t reg_size, uint8_t* data, uint8_t bytes); // if want to write without register addr, just set reg_size to 0. this way can read 8, or 16 or 32 bit registers too. reg_size in bytes! returns true on succes. handles the errcnt automatically!
|
||||||
|
|
||||||
|
// helpers for easier i2c communication
|
||||||
|
uint8_t read8_1(uint8_t reg);
|
||||||
|
bool write8_1(uint8_t reg, uint8_t data);
|
||||||
|
uint16_t read16_1(uint8_t reg);
|
||||||
|
int16_t readS16_1(uint8_t reg);
|
||||||
|
uint16_t read16_LE_1(uint8_t reg);
|
||||||
|
int16_t readS16_LE_1(uint8_t reg);
|
||||||
|
uint32_t read24_1(uint8_t reg);
|
||||||
|
|
||||||
|
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()!!!
|
||||||
|
uint8_t query_interval = 5; // in seconds. can be overriden in init() if necessary
|
||||||
|
protected:
|
||||||
|
void got_error(); // i2c communication will call this when communication was not ok. you can call it from any part of your code too.
|
||||||
|
void got_success(); // i2c communication will call this when the communication was ok. you can call it from any part of your code too.
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
// store for the devices. may not have a driver if not supported
|
||||||
|
class I2DevListElement {
|
||||||
|
public:
|
||||||
|
uint8_t addr = 0; // i2c addr of the device
|
||||||
|
std::unique_ptr<I2cDev> dev = nullptr; // device driver if any
|
||||||
|
};
|
||||||
|
|
||||||
|
class I2CDevManager {
|
||||||
|
public:
|
||||||
|
static void init(); // creates the thread, and sets an one time full scan
|
||||||
|
static void manual_scan(); // it'll init a forced device scan in the thread's next cycle. (1sec max)
|
||||||
|
static void set_autoscan_interval(uint16_t interval); // 0 no auto scan, other values: seconds
|
||||||
|
static uint16_t get_autoscan_interval();
|
||||||
|
static I2cDev* get_dev_by_addr(uint8_t addr); // caller function needs to cast to the specific device!
|
||||||
|
static I2cDev* get_dev_by_model(I2C_DEVMDL model); // caller function needs to cast to the specific device!
|
||||||
|
static std::vector<I2C_DEVMDL> get_dev_list_by_model(); // returns the currently discovered
|
||||||
|
static std::vector<uint8_t> get_gev_list_by_addr(); // returns the currently discovered
|
||||||
|
|
||||||
|
private:
|
||||||
|
static uint16_t scan_interval;
|
||||||
|
static bool force_scan; // if set to true, on hte next run it'll do an i2c scan, ONCE
|
||||||
|
static std::vector<I2DevListElement> devlist;
|
||||||
|
|
||||||
|
static bool found(uint8_t addr); // returns true on any new device. also initializes the driver if there is a suitable one
|
||||||
|
static bool scan(); // return true on any change (delete or found new)
|
||||||
|
static void create_thread();
|
||||||
|
static msg_t timer_fn(void* arg);
|
||||||
|
static Thread* thread;
|
||||||
|
static Mutex mutex_list;
|
||||||
|
};
|
||||||
|
}; // namespace i2cdev
|
||||||
|
#endif
|
@ -126,6 +126,8 @@ class Message {
|
|||||||
BatteryStateData = 68,
|
BatteryStateData = 68,
|
||||||
ProtoViewData = 69,
|
ProtoViewData = 69,
|
||||||
FreqChangeCommand = 70,
|
FreqChangeCommand = 70,
|
||||||
|
I2CDevListChanged = 71,
|
||||||
|
LightData = 72,
|
||||||
MAX
|
MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1330,18 +1332,26 @@ class EnvironmentDataMessage : public Message {
|
|||||||
constexpr EnvironmentDataMessage(
|
constexpr EnvironmentDataMessage(
|
||||||
float temperature = 0,
|
float temperature = 0,
|
||||||
float humidity = 0,
|
float humidity = 0,
|
||||||
float pressure = 0,
|
float pressure = 0)
|
||||||
uint16_t light = 0)
|
|
||||||
: Message{ID::EnvironmentData},
|
: Message{ID::EnvironmentData},
|
||||||
temperature{temperature},
|
temperature{temperature},
|
||||||
humidity{humidity},
|
humidity{humidity},
|
||||||
pressure{pressure},
|
pressure{pressure} {
|
||||||
light{light} {
|
|
||||||
}
|
}
|
||||||
float temperature = 0; // celsius
|
float temperature = 0; // celsius
|
||||||
float humidity = 0; // percent (rh)
|
float humidity = 0; // percent (rh)
|
||||||
float pressure = 0; // hpa
|
float pressure = 0; // hpa
|
||||||
uint16_t light = 0; // lux
|
};
|
||||||
|
|
||||||
|
class LightDataMessage : public Message {
|
||||||
|
public:
|
||||||
|
constexpr LightDataMessage(
|
||||||
|
|
||||||
|
uint16_t light = 0)
|
||||||
|
: Message{ID::LightData},
|
||||||
|
light{light} {
|
||||||
|
}
|
||||||
|
uint16_t light = 0; // lux
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioBeepMessage : public Message {
|
class AudioBeepMessage : public Message {
|
||||||
@ -1423,4 +1433,10 @@ class FreqChangeCommandMessage : public Message {
|
|||||||
int64_t freq = 0;
|
int64_t freq = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class I2CDevListChangedMessage : public Message {
|
||||||
|
public:
|
||||||
|
constexpr I2CDevListChangedMessage()
|
||||||
|
: Message{ID::I2CDevListChanged} {}
|
||||||
|
};
|
||||||
|
|
||||||
#endif /*__MESSAGE_H__*/
|
#endif /*__MESSAGE_H__*/
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
#include "usb_serial_device_to_host.h"
|
#include "usb_serial_device_to_host.h"
|
||||||
#include "rtc_time.hpp"
|
#include "rtc_time.hpp"
|
||||||
|
#include "battery.hpp"
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
using namespace rtc_time;
|
using namespace rtc_time;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user