mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-13 18:19:33 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f13756d4c7 | |||
| ae6724b359 | |||
| e11c28cf30 | |||
| b93fbad207 | |||
| 2bedb5f09f | |||
| 19eb6b44d5 | |||
| 048359fb0e | |||
| ae75540d35 | |||
| 9ef58b7763 |
@@ -54,7 +54,7 @@ jobs:
|
||||
run: docker run -e VERSION_STRING=${{ steps.version_date.outputs.date }} -i -v ${{ github.workspace }}:/havoc portapack-dev
|
||||
- name: Create Small SD Card ZIP - No World Map
|
||||
run: |
|
||||
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version_date.outputs.date }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cd sdcard && zip -r ../sdcard-no-map.zip . && cd ..
|
||||
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version_date.outputs.date }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard-no-map.zip . && cd ..
|
||||
- name: Download world map
|
||||
run: |
|
||||
wget https://github.com/portapack-mayhem/mayhem-firmware/releases/download/world_map/world_map.zip
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
zip -j firmware.zip build/firmware/portapack-h1_h2-mayhem.bin && cd flashing && zip -r ../firmware.zip *
|
||||
- name: Create SD Card ZIP
|
||||
run: |
|
||||
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version_date.outputs.date }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cd sdcard && zip -r ../sdcard.zip . && cd ..
|
||||
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version_date.outputs.date }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard.zip . && cd ..
|
||||
- name: Create changelog
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
run: docker run -e VERSION_STRING=${{ steps.version.outputs.version }} -i -v ${{ github.workspace }}:/havoc portapack-dev
|
||||
- name: Create Small SD Card ZIP - No World Map
|
||||
run: |
|
||||
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version.outputs.version }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cd sdcard && zip -r ../sdcard-no-map.zip . && cd ..
|
||||
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version.outputs.version }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard-no-map.zip . && cd ..
|
||||
- name: Download world map
|
||||
run: |
|
||||
wget https://github.com/portapack-mayhem/mayhem-firmware/releases/download/world_map/world_map.zip
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
zip -j firmware.zip build/firmware/portapack-h1_h2-mayhem.bin && cd flashing && zip -r ../firmware.zip *
|
||||
- name: Create SD Card ZIP
|
||||
run: |
|
||||
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version.outputs.version }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cd sdcard && zip -r ../sdcard.zip . && cd ..
|
||||
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version.outputs.version }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cp build/firmware/standalone/*/*.ppmp sdcard/APPS && cd sdcard && zip -r ../sdcard.zip . && cd ..
|
||||
- name: Create changelog
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -177,6 +177,7 @@ set(CPPSRC
|
||||
${COMMON}/utility.cpp
|
||||
${COMMON}/wm8731.cpp
|
||||
${COMMON}/ads1110.cpp
|
||||
${COMMON}/max17055.cpp
|
||||
${COMMON}/battery.cpp
|
||||
${COMMON}/performance_counter.cpp
|
||||
${COMMON}/bmpfile.cpp
|
||||
@@ -508,6 +509,7 @@ include_directories(. ${INCDIR})
|
||||
link_directories(${LLIBDIR})
|
||||
target_link_libraries(${PROJECT_NAME}.elf ${LIBS} "-L${CMAKE_CURRENT_LIST_DIR}/external")
|
||||
target_link_libraries(${PROJECT_NAME}.elf -Wl,-Map=${PROJECT_NAME}.map)
|
||||
target_link_libraries(${PROJECT_NAME}.elf -Wl,--print-memory-usage)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_NAME}.bin
|
||||
|
||||
@@ -24,14 +24,13 @@
|
||||
|
||||
#include "event_m0.hpp"
|
||||
#include "portapack.hpp"
|
||||
|
||||
#include "battery.hpp"
|
||||
#include <cstring>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
bool BattinfoView::needRun = true;
|
||||
void BattinfoView::focus() {
|
||||
button_exit.focus();
|
||||
}
|
||||
@@ -53,24 +52,25 @@ void BattinfoView::update_result() {
|
||||
return;
|
||||
}
|
||||
bool uichg = false;
|
||||
battery::BatteryManagement::getBatteryInfo(percent, voltage, current, isCharging);
|
||||
uint8_t valid_mask = 0;
|
||||
battery::BatteryManagement::getBatteryInfo(valid_mask, percent, voltage, current);
|
||||
// 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) + " %");
|
||||
else
|
||||
text_percent.set("UNKNOWN");
|
||||
if (voltage > 1) {
|
||||
if (voltage > 1 && (valid_mask & battery::BatteryManagement::BATT_VALID_VOLTAGE) == battery::BatteryManagement::BATT_VALID_VOLTAGE) {
|
||||
text_voltage.set(to_string_decimal(voltage / 1000.0, 3) + " V");
|
||||
} else {
|
||||
text_voltage.set("UNKNOWN");
|
||||
}
|
||||
if (current != 0) {
|
||||
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(isCharging ? "charge" : "discharge");
|
||||
text_charge.set(current >= 0 ? "Charging" : "Discharging");
|
||||
labels_opt.hidden(false);
|
||||
} else {
|
||||
if (!labels_opt.hidden()) uichg = true;
|
||||
@@ -80,7 +80,7 @@ void BattinfoView::update_result() {
|
||||
}
|
||||
if (uichg) set_dirty();
|
||||
// to update status bar too, send message in behalf of batt manager
|
||||
BatteryStateMessage msg{percent, isCharging, voltage};
|
||||
BatteryStateMessage msg{valid_mask, percent, current >= 0, voltage};
|
||||
EventDispatcher::send_message(msg);
|
||||
}
|
||||
|
||||
@@ -99,13 +99,12 @@ BattinfoView::BattinfoView(NavigationView& nav)
|
||||
};
|
||||
|
||||
update_result();
|
||||
needRun = true;
|
||||
thread = chThdCreateFromHeap(NULL, 512, NORMALPRIO + 10, BattinfoView::static_fn, this);
|
||||
if (thread == nullptr) thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, BattinfoView::static_fn, this);
|
||||
}
|
||||
|
||||
msg_t BattinfoView::static_fn(void* arg) {
|
||||
auto obj = static_cast<BattinfoView*>(arg);
|
||||
while (needRun) {
|
||||
while (!chThdShouldTerminate()) {
|
||||
chThdSleepMilliseconds(16);
|
||||
obj->on_timer();
|
||||
}
|
||||
@@ -113,7 +112,6 @@ msg_t BattinfoView::static_fn(void* arg) {
|
||||
}
|
||||
|
||||
BattinfoView::~BattinfoView() {
|
||||
needRun = false;
|
||||
if (thread) {
|
||||
chThdTerminate(thread);
|
||||
chThdWait(thread);
|
||||
|
||||
@@ -50,7 +50,6 @@ class BattinfoView : public View {
|
||||
uint8_t percent = 0;
|
||||
uint16_t voltage = 0;
|
||||
int32_t current = 0;
|
||||
bool isCharging = false;
|
||||
|
||||
Labels labels{
|
||||
{{2 * 8, 1 * 16}, "Percent:", Theme::getInstance()->fg_light->foreground},
|
||||
@@ -77,7 +76,6 @@ class BattinfoView : public View {
|
||||
{72, 17 * 16, 96, 32},
|
||||
"Back"};
|
||||
static msg_t static_fn(void* arg);
|
||||
static bool needRun;
|
||||
Thread* thread{nullptr};
|
||||
};
|
||||
|
||||
|
||||
@@ -225,6 +225,8 @@ uint32_t RegistersWidget::reg_read(const uint32_t register_number) {
|
||||
return radio::debug::second_if::register_read(register_number);
|
||||
case CT_SI5351:
|
||||
return portapack::clock_generator.read_register(register_number);
|
||||
case CT_BATTERY:
|
||||
return battery::BatteryManagement::read_register(register_number);
|
||||
case CT_AUDIO:
|
||||
return audio::debug::reg_read(register_number);
|
||||
}
|
||||
@@ -246,6 +248,9 @@ void RegistersWidget::reg_write(const uint32_t register_number, const uint32_t v
|
||||
case CT_SI5351:
|
||||
portapack::clock_generator.write_register(register_number, value);
|
||||
break;
|
||||
case CT_BATTERY:
|
||||
battery::BatteryManagement::write_register(register_number, value);
|
||||
break;
|
||||
case CT_AUDIO:
|
||||
audio::debug::reg_write(register_number, value);
|
||||
break;
|
||||
@@ -459,6 +464,10 @@ 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}); }},
|
||||
{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) {
|
||||
add_item(
|
||||
{"MAX17055", Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>("MAX17055", RegistersWidgetConfig{CT_BATTERY, 256, 16, 16}); }});
|
||||
}
|
||||
set_max_rows(2); // allow wider buttons
|
||||
}
|
||||
|
||||
@@ -496,10 +505,10 @@ void DebugMenuView::on_populate() {
|
||||
{"Peripherals", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals, [this]() { nav_.push<DebugPeripheralsMenuView>(); }},
|
||||
{"Pers. Memory", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_memory, [this]() { nav_.push<DebugPmemView>(); }},
|
||||
//{ "Radio State", ui::Theme::getInstance()->bg_darkest->foreground, nullptr, [this](){ nav_.push<NotImplementedView>(); } },
|
||||
{"Reboot", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_setup, [this]() { nav_.push<DebugReboot>(); }},
|
||||
{"SD Card", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_sdcard, [this]() { nav_.push<SDCardDebugView>(); }},
|
||||
{"Temperature", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_temperature, [this]() { nav_.push<TemperatureView>(); }},
|
||||
{"Touch Test", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_notepad, [this]() { nav_.push<DebugScreenTest>(); }},
|
||||
{"Reboot", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_setup, [this]() { nav_.push<DebugReboot>(); }},
|
||||
});
|
||||
|
||||
for (auto const& gridItem : ExternalItemsMenuLoader::load_external_items(app_location_t::DEBUG, nav_)) {
|
||||
|
||||
@@ -139,6 +139,7 @@ typedef enum {
|
||||
CT_MAX283X,
|
||||
CT_SI5351,
|
||||
CT_AUDIO,
|
||||
CT_BATTERY,
|
||||
} chip_type_t;
|
||||
|
||||
struct RegistersWidgetConfig {
|
||||
|
||||
@@ -285,7 +285,7 @@ void MicTXView::set_rxbw_defaults(bool use_app_settings) { // Initially in that
|
||||
field_rxbw.set_by_value(0);
|
||||
} else if ((mic_mod_index == MIC_MOD_USB) | (mic_mod_index == MIC_MOD_LSB)) {
|
||||
field_bw.set_value(3); // In SSB by default let's limit TX_BW to 3kHz.
|
||||
field_bw.set_range(2, 3); // User range to modify that TX_BW. (TODO pending to investigate 4khz).
|
||||
field_bw.set_range(2, 3); // User TXBW GUI range to modify that SSB TX_BW to limit SSB radiated spectrum.
|
||||
field_bw.set_step(1);
|
||||
}
|
||||
// field_bw is hidden in other modulation cases
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "usb_serial.hpp"
|
||||
|
||||
#include "ads1110.hpp"
|
||||
#include "max17055.hpp"
|
||||
|
||||
#include "radio.hpp"
|
||||
#include "clock_manager.hpp"
|
||||
|
||||
@@ -385,11 +385,16 @@ void SystemStatusView::on_battery_details() {
|
||||
}
|
||||
|
||||
void SystemStatusView::on_battery_data(const BatteryStateMessage* msg) {
|
||||
if (!batt_was_inited) {
|
||||
batt_was_inited = true;
|
||||
refresh();
|
||||
return;
|
||||
}
|
||||
if (!pmem::ui_hide_numeric_battery()) {
|
||||
battery_text.set_battery(msg->percent, msg->on_charger);
|
||||
battery_text.set_battery(msg->valid_mask, msg->percent, msg->on_charger);
|
||||
}
|
||||
if (!pmem::ui_hide_battery_icon()) {
|
||||
battery_icon.set_battery(msg->percent, msg->on_charger);
|
||||
battery_icon.set_battery(msg->valid_mask, msg->percent, msg->on_charger);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -410,14 +415,15 @@ void SystemStatusView::refresh() {
|
||||
|
||||
if (!pmem::ui_hide_fake_brightness()) status_icons.add(&button_fake_brightness);
|
||||
if (battery::BatteryManagement::isDetected()) {
|
||||
batt_was_inited = true;
|
||||
uint8_t percent = battery::BatteryManagement::getPercent();
|
||||
if (!pmem::ui_hide_battery_icon()) {
|
||||
status_icons.add(&battery_icon);
|
||||
battery_text.set_battery(percent, false); // got an on select, that may pop up the details of the battery.
|
||||
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()) {
|
||||
status_icons.add(&battery_text);
|
||||
battery_text.set_battery(percent, false);
|
||||
battery_text.set_battery(percent <= 100 ? 1 : 0, percent, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -194,7 +194,8 @@ class SystemStatusView : public View {
|
||||
|
||||
private:
|
||||
static constexpr auto default_title = "";
|
||||
bool batt_info_up = false; // to prevent show multiple batt info dialog
|
||||
bool batt_was_inited = false; // if the battery was off on tart, but later turned on.
|
||||
bool batt_info_up = false; // to prevent show multiple batt info dialog
|
||||
NavigationView& nav_;
|
||||
|
||||
Rectangle backdrop{
|
||||
|
||||
@@ -49,6 +49,7 @@ void USBSerial::on_channel_opened() {
|
||||
}
|
||||
|
||||
void USBSerial::on_channel_closed() {
|
||||
reset_transfer_queues();
|
||||
connected = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ CH_IRQ_HANDLER(USB0_IRQHandler) {
|
||||
chSysUnlockFromIsr();
|
||||
}
|
||||
|
||||
if (status & USB0_USBSTS_D_SLI) {
|
||||
on_channel_closed();
|
||||
}
|
||||
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
@@ -131,11 +135,7 @@ usb_request_status_t usb_get_line_coding_request(usb_endpoint_t* const endpoint,
|
||||
}
|
||||
usb_request_status_t usb_set_control_line_state_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
// if (endpoint->setup.value == 3) {
|
||||
on_channel_opened();
|
||||
//} else {
|
||||
// on_channel_closed();
|
||||
//}
|
||||
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,14 @@ void init_host_to_device() {
|
||||
thread_usb_event = chThdSelf();
|
||||
}
|
||||
|
||||
void reset_transfer_queues() {
|
||||
while (usb_bulk_buffer_queue.empty() == false)
|
||||
usb_bulk_buffer_queue.pop();
|
||||
|
||||
while (usb_bulk_buffer_spare.empty() == false)
|
||||
usb_bulk_buffer_spare.pop();
|
||||
}
|
||||
|
||||
void schedule_host_to_device_transfer() {
|
||||
if (usb_bulk_buffer_queue.size() >= 8)
|
||||
return;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#define USB_BULK_BUFFER_SIZE 64
|
||||
|
||||
void init_host_to_device();
|
||||
void reset_transfer_queues();
|
||||
void serial_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred);
|
||||
void schedule_host_to_device_transfer();
|
||||
void complete_host_to_device_transfer();
|
||||
|
||||
@@ -278,7 +278,9 @@ macro(DeclareTargets chunk_tag name)
|
||||
include_directories(. ${INCDIR} ${MODE_INCDIR})
|
||||
link_directories(${LLIBDIR})
|
||||
target_link_libraries(${PROJECT_NAME}.elf ${LIBS})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}.elf -Wl,-Map=${PROJECT_NAME}.map)
|
||||
target_link_libraries(${PROJECT_NAME}.elf -Wl,--print-memory-usage)
|
||||
|
||||
if(add_to_firmware)
|
||||
|
||||
|
||||
@@ -33,11 +33,11 @@ HilbertTransform::HilbertTransform() {
|
||||
}
|
||||
|
||||
void HilbertTransform::execute(float in, float& out_i, float& out_q) {
|
||||
// Synthesized Hilbert Transform, it is implemented based on 1/2 band LPF and later freq shift fs/4, achieving a H.T_BW of transmitted = fs/2 ;
|
||||
// Half_band LPF means a LP filter with f_cut_off = fs/4; Half band = Half max band = 1/2 * fs_max = 1/2 x f_Nyquist = 1/2 * fs/2 = fs/4
|
||||
float a = 0, b = 0;
|
||||
|
||||
float in_filtered = sos_input.execute(in) * 1.0f; // Anti-aliasing LPF at fs/4 mic audio filter front-end.
|
||||
// it is exactly matching with the usefull mic BW_cut_off =fs/4 of the following Hilbert Transf. implementation
|
||||
// Ex. to TX SSB 3khz BW (3KHZ =fs/4) ,we need to run Hiblert_Trf fs = 12khz . And our anti-aliasing filter is also fcut =fs/4 when we use a half_band_LPF .
|
||||
|
||||
switch (n) {
|
||||
case 0:
|
||||
|
||||
@@ -84,18 +84,13 @@ SSB::SSB()
|
||||
void SSB::set_fs_div_factor(float new_bw_ssb) {
|
||||
switch ((int)new_bw_ssb / 1000) {
|
||||
case 2:
|
||||
fs_div_factor = 192; // TXBW_ssb = 2khz = fs/4 ; fs of Hilbert Transform => 8khz fs Hilbert = 1536.000/8000= 192
|
||||
fs_div_factor = 192; // TXBW_ssb = 2khz = BW_cut_off LPF = fs/4 ; BW_HT fs Hilbert Transform (4khz=fs/2) ==> (8k=fs) Hilbert_fs = 1.536.000/8000= 192
|
||||
break;
|
||||
case 3:
|
||||
fs_div_factor = 128; // TXBW_ssb = 3khz = fs/4 ; fs of Hilbert Transform => 12khz fs Hilbert = 1536.000/12000= 128
|
||||
fs_div_factor = 128; // TXBW_ssb = 3khz = BW_cut_off LPF = fs/4 ; BW_HT fs Hilbert Transform (6khz=fs/2) ==> (12k=fs) Hilbert_fs = 1.536.000/12000= 128
|
||||
break;
|
||||
/* TODO pending to investigate 4khz, now is making aliasing folding with audio sweep .
|
||||
case 4:
|
||||
fs_div_factor = 96; // TXBW_ssb = 4khz = fs/4 ; fs of Hilbert Transform => 16khz fs Hilbert = 1536.000/16000= 96
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
fs_div_factor = 128; // TXBW_ssb = 3khz = fs/4 ; fs of Hilbert Transform => 12khz fs Hilbert = 1536.000/12000= 128
|
||||
fs_div_factor = 128; // TXBW_ssb = 3khz = BW_cut_off LPF = fs/4 ; BW_HT fs Hilbert Transform (6khz=fs/2) ==> (12k=fs) Hilbert_fs = 1.536.000/12000= 128
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ void MicTXProcessor::on_message(const Message* const msg) {
|
||||
modulator->set_mode(dsp::modulate::Mode::DSB);
|
||||
}
|
||||
|
||||
modulator->set_over(baseband_fs / 24000); // Keep no change.
|
||||
modulator->set_over(baseband_fs / 24000); // "over" is calculated based on relationship fs_transceiver / fs_audio_mic_capture, to be used in dsp_modulate.cpp
|
||||
|
||||
am_enabled = config_message.am_enabled;
|
||||
usb_enabled = config_message.usb_enabled;
|
||||
|
||||
@@ -22,13 +22,23 @@
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include <libopencm3/lpc43xx/usb.h>
|
||||
|
||||
extern "C" {
|
||||
void start_usb(void);
|
||||
void irq_usb(void);
|
||||
void usb_transfer(void);
|
||||
|
||||
extern volatile bool scsi_running;
|
||||
|
||||
CH_IRQ_HANDLER(Vector60) {
|
||||
const uint32_t status = USB0_USBSTS_D & USB0_USBINTR_D;
|
||||
if (status & USB0_USBSTS_D_SLI) {
|
||||
// USB reset received.
|
||||
if (scsi_running) {
|
||||
LPC_RGU->RESET_CTRL[0] = (1 << 0);
|
||||
}
|
||||
}
|
||||
irq_usb();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "sd_over_usb.h"
|
||||
#include "scsi.h"
|
||||
|
||||
bool scsi_running = false;
|
||||
volatile bool scsi_running = false;
|
||||
|
||||
usb_request_status_t report_max_lun(
|
||||
usb_endpoint_t* const endpoint,
|
||||
|
||||
@@ -118,7 +118,7 @@ uint16_t ADS1110::readVoltage() {
|
||||
return (uint16_t)voltage;
|
||||
}
|
||||
|
||||
void ADS1110::getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage) {
|
||||
void ADS1110::getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage) {
|
||||
voltage = readVoltage();
|
||||
|
||||
// Calculate the remaining battery percentage
|
||||
@@ -127,6 +127,7 @@ void ADS1110::getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage) {
|
||||
// Limit the values to the valid range
|
||||
batteryPercentage = (batteryPercentage > 100) ? 100 : batteryPercentage;
|
||||
// ToDo: if its > 4, then 100%, if < 3 then 0%
|
||||
valid_mask = 1; // BATT_VALID_VOLTAGE
|
||||
}
|
||||
|
||||
} /* namespace ads1110 */
|
||||
|
||||
@@ -42,7 +42,7 @@ class ADS1110 {
|
||||
bool isDetected() const { return detected_; }
|
||||
|
||||
uint16_t readVoltage();
|
||||
void getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage);
|
||||
void getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage);
|
||||
|
||||
private:
|
||||
I2C& bus;
|
||||
|
||||
+54
-21
@@ -2,6 +2,7 @@
|
||||
#include "event_m0.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "ads1110.hpp"
|
||||
#include "max17055.hpp"
|
||||
|
||||
// uncomment if you want to emulate batt management system
|
||||
// #define USE_BATT_EMULATOR
|
||||
@@ -10,19 +11,26 @@ extern I2C portapack::i2c0;
|
||||
|
||||
namespace battery {
|
||||
|
||||
constexpr uint32_t BATTERY_UPDATE_INTERVAL = 30000;
|
||||
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;
|
||||
|
||||
void BatteryManagement::init() {
|
||||
void BatteryManagement::detect() {
|
||||
// try to detect supported modules
|
||||
detected_ = BATT_NONE;
|
||||
if (battery_ads1110.detect()) {
|
||||
battery_ads1110.init();
|
||||
detected_ = BATT_ADS1110;
|
||||
return;
|
||||
}
|
||||
if (battery_max17055.detect()) {
|
||||
// battery_max17055.init(); //detect will call this on each "re detect"
|
||||
detected_ = BATT_MAX17055;
|
||||
return;
|
||||
}
|
||||
|
||||
// add new supported module detect + init here
|
||||
@@ -30,21 +38,28 @@ void BatteryManagement::init() {
|
||||
#ifdef USE_BATT_EMULATOR
|
||||
if (detected_ == BATT_NONE) {
|
||||
detected_ = BATT_EMULATOR;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (detected_ != BATT_NONE) {
|
||||
// sets timer to query and broadcats this info
|
||||
create_thread();
|
||||
}
|
||||
void BatteryManagement::init() {
|
||||
detect();
|
||||
// sets timer to query and broadcats this info
|
||||
create_thread();
|
||||
}
|
||||
|
||||
// sets the values, it the currend module supports it.
|
||||
bool BatteryManagement::getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current, bool& isCharging) {
|
||||
if (detected_ == BATT_NONE) return false;
|
||||
if (detected_ == BATT_ADS1110) {
|
||||
battery_ads1110.getBatteryInfo(batteryPercentage, voltage);
|
||||
return true;
|
||||
void BatteryManagement::getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current) {
|
||||
if (detected_ == BATT_NONE) {
|
||||
valid_mask = BATT_VALID_NONE;
|
||||
return;
|
||||
} else if (detected_ == BATT_ADS1110) {
|
||||
battery_ads1110.getBatteryInfo(valid_mask, batteryPercentage, voltage);
|
||||
return;
|
||||
} else if (detected_ == BATT_MAX17055) {
|
||||
battery_max17055.getBatteryInfo(valid_mask, batteryPercentage, voltage, current);
|
||||
return;
|
||||
}
|
||||
// add new module query here
|
||||
|
||||
@@ -55,48 +70,66 @@ bool BatteryManagement::getBatteryInfo(uint8_t& batteryPercentage, uint16_t& vol
|
||||
voltage = rand() % 1000 + 3000; // mV
|
||||
current = rand() % 150; // mA
|
||||
isCharging = rand() % 2;
|
||||
valid_mask = 3;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
(void)isCharging; // keep the compiler calm
|
||||
(void)current;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
uint8_t BatteryManagement::getPercent() {
|
||||
if (detected_ == BATT_NONE) return 102;
|
||||
uint8_t validity = 0;
|
||||
uint8_t batteryPercentage = 0;
|
||||
bool isCharging = false;
|
||||
uint16_t voltage = 0;
|
||||
int32_t current = 0;
|
||||
getBatteryInfo(batteryPercentage, voltage, current, isCharging);
|
||||
getBatteryInfo(validity, batteryPercentage, voltage, current);
|
||||
if ((validity & BATT_VALID_VOLTAGE) != BATT_VALID_VOLTAGE) return 102;
|
||||
return batteryPercentage;
|
||||
}
|
||||
|
||||
uint16_t BatteryManagement::getVoltage() {
|
||||
if (detected_ == BATT_NONE) return 0;
|
||||
if (detected_ == BATT_NONE) return 102;
|
||||
uint8_t validity = 0;
|
||||
uint8_t batteryPercentage = 0;
|
||||
bool isCharging = false;
|
||||
uint16_t voltage = 0;
|
||||
int32_t current = 0;
|
||||
getBatteryInfo(batteryPercentage, voltage, current, isCharging);
|
||||
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;
|
||||
if (!detected_) return 0;
|
||||
uint8_t validity = 0;
|
||||
uint8_t batteryPercentage = 102;
|
||||
bool isCharging = false;
|
||||
uint16_t voltage = 0;
|
||||
int32_t current = 0;
|
||||
chThdSleepMilliseconds(1000); // wait ui for fully load
|
||||
while (1) {
|
||||
if (BatteryManagement::getBatteryInfo(batteryPercentage, voltage, current, isCharging)) {
|
||||
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{batteryPercentage, isCharging, voltage};
|
||||
BatteryStateMessage msg{validity, batteryPercentage, current >= 0, voltage};
|
||||
EventDispatcher::send_message(msg);
|
||||
}
|
||||
chThdSleepMilliseconds(BATTERY_UPDATE_INTERVAL);
|
||||
|
||||
@@ -32,13 +32,23 @@ class BatteryManagement {
|
||||
enum BatteryModules {
|
||||
BATT_NONE = 0,
|
||||
BATT_ADS1110 = 1,
|
||||
BATT_MAX17055 = 2,
|
||||
BATT_EMULATOR = 254
|
||||
};
|
||||
enum BatteryValidMask {
|
||||
BATT_VALID_NONE = 0,
|
||||
BATT_VALID_VOLTAGE = 1,
|
||||
BATT_VALID_CURRENT = 2,
|
||||
};
|
||||
static void init();
|
||||
static void detect();
|
||||
static bool isDetected() { return detected_ != BATT_NONE; }
|
||||
static bool getBatteryInfo(uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current, bool& isCharging);
|
||||
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);
|
||||
|
||||
private:
|
||||
static void create_thread();
|
||||
|
||||
@@ -0,0 +1,821 @@
|
||||
/*
|
||||
|
||||
Copyright (C) 2024 jLynx.
|
||||
*
|
||||
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 "max17055.hpp"
|
||||
#include "utility.hpp"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace battery {
|
||||
namespace max17055 {
|
||||
|
||||
void MAX17055::init() {
|
||||
if (!detected_) {
|
||||
detected_ = detect();
|
||||
}
|
||||
if (detected_) { // check again if it is detected
|
||||
config();
|
||||
setHibCFG(0x0000);
|
||||
|
||||
// Design Capacity Register
|
||||
setDesignCapacity(__MAX17055_Design_Capacity__);
|
||||
|
||||
// ModelCfg Register
|
||||
setModelCfg(__MAX17055_Battery_Model__);
|
||||
|
||||
// IChgTerm Register
|
||||
setChargeTerminationCurrent(__MAX17055_Termination_Current__);
|
||||
|
||||
// VEmpty Register
|
||||
setEmptyVoltage(__MAX17055_Empty_Voltage__);
|
||||
|
||||
// VRecovery Register
|
||||
setRecoveryVoltage(__MAX17055_Recovery_Voltage__);
|
||||
|
||||
// Set Minimum Voltage
|
||||
setMinVoltage(__MAX17055_Min_Voltage__);
|
||||
|
||||
// Set Maximum Voltage
|
||||
setMaxVoltage(__MAX17055_Max_Voltage__);
|
||||
|
||||
// Set Maximum Current
|
||||
setMaxCurrent(__MAX17055_Max_Current__);
|
||||
|
||||
// Set Minimum SOC
|
||||
setMinSOC(__MAX17055_Min_SOC__);
|
||||
|
||||
// Set Maximum SOC
|
||||
setMaxSOC(__MAX17055_Max_SOC__);
|
||||
|
||||
// Set Minimum Temperature
|
||||
setMinTemperature(__MAX17055_Min_Temperature__);
|
||||
|
||||
// Set Maximum Temperature
|
||||
setMaxTemperature(__MAX17055_Max_Temperature__);
|
||||
|
||||
// Clear Bits
|
||||
statusClear();
|
||||
}
|
||||
}
|
||||
|
||||
bool MAX17055::detect() {
|
||||
uint8_t _MAX17055_Data[2];
|
||||
|
||||
// Get Data from IC
|
||||
if (readMultipleRegister(0x00, _MAX17055_Data, 2, false)) {
|
||||
detected_ = true;
|
||||
return true;
|
||||
}
|
||||
detected_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bitRead(uint8_t value, uint8_t bit) {
|
||||
return (value >> bit) & 0x01;
|
||||
}
|
||||
|
||||
void bitSet(uint16_t& value, uint8_t bit) {
|
||||
value |= (1 << bit);
|
||||
}
|
||||
|
||||
void bitSet(uint8_t& value, uint8_t bit) {
|
||||
value |= (1 << bit);
|
||||
}
|
||||
|
||||
void bitClear(uint16_t& value, uint8_t bit) {
|
||||
value &= ~(1 << bit);
|
||||
}
|
||||
|
||||
uint16_t MAX17055::read_register(const uint8_t reg) {
|
||||
const std::array<uint8_t, 1> tx{reg};
|
||||
std::array<uint8_t, 2> rx{0x00, 0x00};
|
||||
|
||||
bus.transmit(bus_address, tx.data(), tx.size());
|
||||
bus.receive(bus_address, rx.data(), rx.size());
|
||||
|
||||
// Combine the two bytes into a 16-bit value
|
||||
// little-endian format (LSB first)
|
||||
return static_cast<uint16_t>((rx[1] << 8) | rx[0]);
|
||||
}
|
||||
|
||||
bool MAX17055::write_register(const uint8_t reg, const uint16_t value) {
|
||||
std::array<uint8_t, 3> tx;
|
||||
tx[0] = reg;
|
||||
tx[1] = value & 0xFF; // Low byte
|
||||
tx[2] = (value >> 8) & 0xFF; // High byte
|
||||
|
||||
bool success = bus.transmit(bus_address, tx.data(), tx.size());
|
||||
return success;
|
||||
}
|
||||
|
||||
bool MAX17055::readMultipleRegister(uint8_t reg, uint8_t* data, uint8_t length, bool endTransmission) {
|
||||
if (bus.transmit(bus_address, ®, 1)) {
|
||||
if (bus.receive(bus_address, data, length)) {
|
||||
if (endTransmission) {
|
||||
// bus.stop(); // Testing if we need this line
|
||||
// Perform any necessary end transmission actions
|
||||
// For example, you can use bus.endTransmission()
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MAX17055::writeMultipleRegister(uint8_t reg, const uint8_t* data, uint8_t length) {
|
||||
uint8_t buffer[length + 1];
|
||||
buffer[0] = reg;
|
||||
memcpy(buffer + 1, data, length);
|
||||
|
||||
if (bus.transmit(bus_address, buffer, length + 1)) {
|
||||
// Perform any necessary end transmission actions
|
||||
// For example, you can use bus.endTransmission()
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MAX17055::getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current) {
|
||||
if (detected_) {
|
||||
uint16_t status = 0;
|
||||
// Read Status Register
|
||||
readMultipleRegister(0x00, (uint8_t*)&status, 2, false);
|
||||
voltage = averageVoltage();
|
||||
if ((status == 0 && voltage == 0) || (status == 0x0002 && voltage == 3600) || (status == 0x0002 && voltage == 0)) {
|
||||
valid_mask = 0;
|
||||
return;
|
||||
}
|
||||
batteryPercentage = stateOfCharge();
|
||||
current = instantCurrent();
|
||||
valid_mask = 3; // BATT_VALID_VOLTAGE + CURRENT
|
||||
} else {
|
||||
// let's indicate the data is wrong. ui will handle this by display UNK values.
|
||||
valid_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool MAX17055::setEmptyVoltage(uint16_t _Empty_Voltage) {
|
||||
// Set Voltage Value
|
||||
uint16_t _Raw_Voltage = ((uint16_t)((uint16_t)_Empty_Voltage * 100) << 7) & 0b1111111110000000;
|
||||
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_RAW_Data[2];
|
||||
|
||||
// Handle Data
|
||||
MAX17055_RAW_Data[1] = (uint8_t)(_Raw_Voltage >> 8);
|
||||
MAX17055_RAW_Data[0] = (uint8_t)(_Raw_Voltage & 0x00FF);
|
||||
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Current_Data[2];
|
||||
|
||||
// Read Current Register
|
||||
readMultipleRegister(0x3A, MAX17055_Current_Data, 2, true);
|
||||
|
||||
// Clear Current Value
|
||||
MAX17055_Current_Data[0] &= 0b01111111;
|
||||
MAX17055_Current_Data[1] &= 0b00000000;
|
||||
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Handle_Data[2];
|
||||
|
||||
// Handle Data
|
||||
MAX17055_Handle_Data[0] = MAX17055_Current_Data[0] | MAX17055_RAW_Data[0];
|
||||
MAX17055_Handle_Data[1] = MAX17055_Current_Data[1] | MAX17055_RAW_Data[1];
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x3A, MAX17055_Handle_Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setRecoveryVoltage(uint16_t _Recovery_Voltage) {
|
||||
// Handle Value
|
||||
_Recovery_Voltage = _Recovery_Voltage * 1000 / 40;
|
||||
|
||||
// Set Voltage Value
|
||||
uint16_t _Raw_Voltage = ((uint16_t)_Recovery_Voltage);
|
||||
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_RAW_Data[2];
|
||||
|
||||
// Handle Data
|
||||
MAX17055_RAW_Data[1] = (uint8_t)(_Raw_Voltage >> 8);
|
||||
MAX17055_RAW_Data[0] = (uint8_t)(_Raw_Voltage & 0x00FF);
|
||||
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Current_Data[2];
|
||||
|
||||
// Read Current Register
|
||||
readMultipleRegister(0x3A, MAX17055_Current_Data, 2, true);
|
||||
|
||||
// Clear Current Value
|
||||
MAX17055_Current_Data[0] &= 0b10000000;
|
||||
MAX17055_Current_Data[1] &= 0b11111111;
|
||||
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Handle_Data[2];
|
||||
|
||||
// Handle Data
|
||||
MAX17055_Handle_Data[0] = MAX17055_Current_Data[0] | MAX17055_RAW_Data[0];
|
||||
MAX17055_Handle_Data[1] = MAX17055_Current_Data[1] | MAX17055_RAW_Data[1];
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x3A, MAX17055_Handle_Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setMinVoltage(uint16_t _Minimum_Voltage) {
|
||||
// Set Voltage Value
|
||||
uint8_t _Raw_Voltage = (uint8_t)(_Minimum_Voltage * 1000 / 20);
|
||||
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Current_Data[2];
|
||||
|
||||
// Read Current Register
|
||||
readMultipleRegister(0x01, MAX17055_Current_Data, 2, true);
|
||||
|
||||
// Set Voltage Value
|
||||
MAX17055_Current_Data[0] = _Raw_Voltage;
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x01, MAX17055_Current_Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setMaxVoltage(uint16_t _Maximum_Voltage) {
|
||||
// Set Voltage Value
|
||||
uint8_t _Raw_Voltage = (uint8_t)(_Maximum_Voltage * 1000 / 20);
|
||||
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Current_Data[2];
|
||||
|
||||
// Read Current Register
|
||||
readMultipleRegister(0x01, MAX17055_Current_Data, 2, true);
|
||||
|
||||
// Set Voltage Value
|
||||
MAX17055_Current_Data[1] = _Raw_Voltage;
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x01, MAX17055_Current_Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setMaxCurrent(uint16_t _Maximum_Current) {
|
||||
// Set Current Value
|
||||
uint8_t _Raw_Current = (uint8_t)(_Maximum_Current * 1000 / 40);
|
||||
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Current_Data[2];
|
||||
|
||||
// Read Current Register
|
||||
readMultipleRegister(0xB4, MAX17055_Current_Data, 2, true);
|
||||
|
||||
// Set Current Value
|
||||
MAX17055_Current_Data[1] = _Raw_Current;
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0xB4, MAX17055_Current_Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setChargeTerminationCurrent(uint16_t _Charge_Termination_Current) {
|
||||
// Handle Raw Data
|
||||
uint16_t _RAW_Data = (uint16_t)(_Charge_Termination_Current * 1000000 * __MAX17055_Resistor__ / 1.5625);
|
||||
|
||||
// Declare Default Data Array
|
||||
uint8_t _Data[2];
|
||||
|
||||
// Set Data Low/High Byte
|
||||
_Data[0] = ((_RAW_Data & (uint16_t)0x00FF));
|
||||
_Data[1] = ((_RAW_Data & (uint16_t)0xFF00) >> 8);
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x1E, _Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setDesignCapacity(const uint16_t _Capacity) {
|
||||
// Set Raw
|
||||
uint16_t _Raw_Cap = (uint16_t)_Capacity * 2;
|
||||
|
||||
// Declare Default Data Array
|
||||
uint8_t _Data[2];
|
||||
|
||||
// Set Data Low/High Byte
|
||||
_Data[0] = ((_Raw_Cap & (uint16_t)0x00FF));
|
||||
_Data[1] = ((_Raw_Cap & (uint16_t)0xFF00) >> 8);
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x18, _Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setFullCapRep(const uint16_t _Capacity) {
|
||||
// Set Raw
|
||||
uint16_t _Raw_Cap = (uint16_t)_Capacity * 2;
|
||||
|
||||
// Declare Default Data Array
|
||||
uint8_t _Data[2];
|
||||
|
||||
// Set Data Low/High Byte
|
||||
_Data[0] = ((_Raw_Cap & (uint16_t)0x00FF));
|
||||
_Data[1] = ((_Raw_Cap & (uint16_t)0xFF00) >> 8);
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x10, _Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setFullCapNom(const uint16_t _Capacity) {
|
||||
// Set Raw
|
||||
uint16_t _Raw_Cap = (uint16_t)_Capacity * 2;
|
||||
|
||||
// Declare Default Data Array
|
||||
uint8_t _Data[2];
|
||||
|
||||
// Set Data Low/High Byte
|
||||
_Data[0] = ((_Raw_Cap & (uint16_t)0x00FF));
|
||||
_Data[1] = ((_Raw_Cap & (uint16_t)0xFF00) >> 8);
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x23, _Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setRepCap(const uint16_t _Capacity) {
|
||||
// Set Raw
|
||||
uint16_t _Raw_Cap = (uint16_t)_Capacity * 2;
|
||||
|
||||
// Declare Default Data Array
|
||||
uint8_t _Data[2];
|
||||
|
||||
// Set Data Low/High Byte
|
||||
_Data[0] = ((_Raw_Cap & (uint16_t)0x00FF));
|
||||
_Data[1] = ((_Raw_Cap & (uint16_t)0xFF00) >> 8);
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x05, _Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setMinSOC(uint8_t _Minimum_SOC) {
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Current_Data[2];
|
||||
|
||||
// Read Current Register
|
||||
readMultipleRegister(0x03, MAX17055_Current_Data, 2, true);
|
||||
|
||||
// Scale Value
|
||||
uint8_t _MinSOC = (_Minimum_SOC / 100) * 255;
|
||||
|
||||
// Set Voltage Value
|
||||
MAX17055_Current_Data[0] = _MinSOC;
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x03, MAX17055_Current_Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setMaxSOC(uint8_t _Maximum_SOC) {
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Current_Data[2];
|
||||
|
||||
// Read Current Register
|
||||
readMultipleRegister(0x03, MAX17055_Current_Data, 2, true);
|
||||
|
||||
// Scale Value
|
||||
uint8_t _MaxSOC = (_Maximum_SOC / 100) * 255;
|
||||
|
||||
// Set Voltage Value
|
||||
MAX17055_Current_Data[1] = _MaxSOC;
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x03, MAX17055_Current_Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setMinTemperature(uint8_t _Minimum_Temperature) {
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Current_Data[2];
|
||||
|
||||
// Read Current Register
|
||||
readMultipleRegister(0x02, MAX17055_Current_Data, 2, true);
|
||||
|
||||
// Set Voltage Value
|
||||
MAX17055_Current_Data[0] = _Minimum_Temperature;
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x02, MAX17055_Current_Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setMaxTemperature(uint8_t _Maximum_Temperature) {
|
||||
// Define Data Variable
|
||||
uint8_t MAX17055_Current_Data[2];
|
||||
|
||||
// Read Current Register
|
||||
readMultipleRegister(0x02, MAX17055_Current_Data, 2, true);
|
||||
|
||||
// Set Voltage Value
|
||||
MAX17055_Current_Data[1] = _Maximum_Temperature;
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0x02, MAX17055_Current_Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setModelCfg(const uint8_t _Model_ID) {
|
||||
// Declare Variable
|
||||
uint16_t _Data_Set = 0x00;
|
||||
|
||||
// Set Charge Voltage
|
||||
bitSet(_Data_Set, 10);
|
||||
|
||||
// Set Battery Model
|
||||
if (_Model_ID == 0) {
|
||||
bitClear(_Data_Set, 4);
|
||||
bitClear(_Data_Set, 5);
|
||||
bitClear(_Data_Set, 6);
|
||||
bitClear(_Data_Set, 7);
|
||||
}
|
||||
if (_Model_ID == 2) {
|
||||
bitClear(_Data_Set, 4);
|
||||
bitSet(_Data_Set, 5);
|
||||
bitClear(_Data_Set, 6);
|
||||
bitClear(_Data_Set, 7);
|
||||
}
|
||||
if (_Model_ID == 6) {
|
||||
bitClear(_Data_Set, 4);
|
||||
bitSet(_Data_Set, 5);
|
||||
bitSet(_Data_Set, 6);
|
||||
bitClear(_Data_Set, 7);
|
||||
}
|
||||
|
||||
// Declare Default Data Array
|
||||
uint8_t _Data[2];
|
||||
|
||||
// Set Data Low/High Byte
|
||||
_Data[0] = ((_Data_Set & (uint16_t)0x00FF));
|
||||
_Data[1] = ((_Data_Set & (uint16_t)0xFF00) >> 8);
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0xDB, _Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
bool MAX17055::setHibCFG(const uint16_t _Config) {
|
||||
// Declare Default Data Array
|
||||
uint8_t _Data[2];
|
||||
|
||||
// Set Data Low/High Byte
|
||||
_Data[0] = ((_Config & (uint16_t)0x00FF));
|
||||
_Data[1] = ((_Config & (uint16_t)0xFF00) >> 8);
|
||||
|
||||
// Set Register
|
||||
bool _Result = writeMultipleRegister(0xBA, _Data, 2);
|
||||
|
||||
// End Function
|
||||
return _Result;
|
||||
}
|
||||
|
||||
void MAX17055::config(void) {
|
||||
// Declare Default Data Array
|
||||
uint8_t _Config1[2];
|
||||
uint8_t _Config2[2];
|
||||
|
||||
// Set Default Data
|
||||
_Config1[0] = 0b00000000;
|
||||
_Config1[1] = 0b00000000;
|
||||
_Config2[0] = 0b00011000;
|
||||
_Config2[1] = 0b00000110;
|
||||
|
||||
// Set Configuration bits [Config1]
|
||||
if (MAX17055_Ber) bitSet(_Config1[0], 0);
|
||||
if (MAX17055_Bei) bitSet(_Config1[0], 1);
|
||||
if (MAX17055_Aen) bitSet(_Config1[0], 2);
|
||||
if (MAX17055_FTHRM) bitSet(_Config1[0], 3);
|
||||
if (MAX17055_ETHRM) bitSet(_Config1[0], 4);
|
||||
if (MAX17055_COMMSH) bitSet(_Config1[0], 6);
|
||||
if (MAX17055_SHDN) bitSet(_Config1[0], 7);
|
||||
if (MAX17055_Tex) bitSet(_Config1[1], 0);
|
||||
if (MAX17055_Ten) bitSet(_Config1[1], 1);
|
||||
if (MAX17055_AINSH) bitSet(_Config1[1], 2);
|
||||
if (MAX17055_IS) bitSet(_Config1[1], 3);
|
||||
if (MAX17055_VS) bitSet(_Config1[1], 4);
|
||||
if (MAX17055_TS) bitSet(_Config1[1], 5);
|
||||
if (MAX17055_SS) bitSet(_Config1[1], 6);
|
||||
if (MAX17055_TSel) bitSet(_Config1[1], 7);
|
||||
|
||||
// Set Configuration bits [Config2]
|
||||
if (MAX17055_CPMode) bitSet(_Config2[0], 1);
|
||||
if (MAX17055_LDMDL) bitSet(_Config2[0], 5);
|
||||
if (MAX17055_TAIrtEN) bitSet(_Config2[0], 6);
|
||||
if (MAX17055_dSOCen) bitSet(_Config2[0], 7);
|
||||
if (MAX17055_DPEn) bitSet(_Config2[1], 4);
|
||||
if (MAX17055_AtRateEn) bitSet(_Config2[1], 5);
|
||||
|
||||
// Config1 Setting
|
||||
writeMultipleRegister(0x1D, _Config1, 2);
|
||||
writeMultipleRegister(0xBB, _Config2, 2);
|
||||
}
|
||||
|
||||
uint16_t MAX17055::instantVoltage(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x09);
|
||||
|
||||
// Calculate Measurement
|
||||
uint16_t _Value = ((uint32_t)_Measurement_Raw * 1.25 / 16);
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::averageVoltage(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x19);
|
||||
|
||||
// Calculate Measurement
|
||||
uint16_t _Value = ((uint32_t)_Measurement_Raw * 1.25 / 16);
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::emptyVoltage(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x3A);
|
||||
_Measurement_Raw = ((_Measurement_Raw & 0xFF80) >> 7);
|
||||
|
||||
// Calculate Measurement
|
||||
uint16_t _Value = ((uint32_t)_Measurement_Raw * 10);
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::recoveryVoltage(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x3A);
|
||||
|
||||
_Measurement_Raw = (_Measurement_Raw & 0x7F);
|
||||
|
||||
// Calculate Measurement
|
||||
uint16_t _Value = ((uint32_t)_Measurement_Raw * 40);
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
int32_t MAX17055::instantCurrent(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x0A);
|
||||
|
||||
// Convert to signed int16_t (two's complement)
|
||||
int32_t _Signed_Raw = static_cast<int16_t>(_Measurement_Raw);
|
||||
|
||||
int32_t _Value = (_Signed_Raw * 15625) / (__MAX17055_Resistor__ * 100) / 100000;
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
int32_t MAX17055::averageCurrent(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x0B);
|
||||
|
||||
// Convert to signed int16_t (two's complement)
|
||||
int32_t _Signed_Raw = static_cast<int16_t>(_Measurement_Raw);
|
||||
|
||||
int32_t _Value = (_Signed_Raw * 15625) / (__MAX17055_Resistor__ * 100) / 100000;
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::stateOfCharge(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x06); // RepSOC
|
||||
|
||||
// Calculate Measurement
|
||||
uint8_t _Value = (_Measurement_Raw >> 8) & 0xFF;
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::averageStateOfCharge(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x0E);
|
||||
|
||||
// Calculate Measurement
|
||||
uint16_t _Value = ((uint32_t)_Measurement_Raw * 100 / 256);
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::instantCapacity(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x05);
|
||||
|
||||
// Calculate Data
|
||||
uint16_t _Value = _Measurement_Raw * 5 / 1000 / __MAX17055_Resistor__;
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::designCapacity(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x18);
|
||||
|
||||
// Calculate Data
|
||||
uint16_t _Value = _Measurement_Raw * 5 / 1000 / __MAX17055_Resistor__;
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::fullCapacity(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x35);
|
||||
|
||||
// Calculate Data
|
||||
uint16_t _Value = _Measurement_Raw * 5 / 1000 / __MAX17055_Resistor__;
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::icTemperature(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x08);
|
||||
|
||||
// Declare Variables
|
||||
bool _Signiture = false;
|
||||
|
||||
// Control for Negative Value
|
||||
if ((_Measurement_Raw >> 12) == 0xF) {
|
||||
// Calculate Data
|
||||
_Measurement_Raw = 0xFFFF - _Measurement_Raw;
|
||||
|
||||
// Assign Signiture
|
||||
_Signiture = true;
|
||||
}
|
||||
|
||||
// Calculate Data
|
||||
uint16_t _Value = ((uint32_t)_Measurement_Raw * 100 / 256);
|
||||
|
||||
// Assign Signiture
|
||||
if (_Signiture) _Value = -_Value;
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::timeToEmpty(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x11);
|
||||
|
||||
// Calculate Data
|
||||
uint16_t _Value = ((uint32_t)_Measurement_Raw * 5625 / 60 / 60 / 100);
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::timeToFull(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x20);
|
||||
|
||||
// Calculate Data
|
||||
uint16_t _Value = ((uint32_t)_Measurement_Raw * 5625 / 60 / 60 / 100);
|
||||
|
||||
// End Function
|
||||
return _Value;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::batteryAge(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x07);
|
||||
|
||||
// End Function
|
||||
return _Measurement_Raw;
|
||||
}
|
||||
|
||||
uint16_t MAX17055::chargeCycle(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x17);
|
||||
|
||||
// End Function
|
||||
return _Measurement_Raw;
|
||||
}
|
||||
|
||||
bool MAX17055::statusControl(const uint8_t _Status) {
|
||||
// Define Data Variable
|
||||
uint8_t _Status_Register[2] = {0x00, 0x00};
|
||||
|
||||
// Read Status Register
|
||||
readMultipleRegister(0x00, _Status_Register, 2, false);
|
||||
|
||||
// Control for Status
|
||||
if (_Status == MAX17055_POR)
|
||||
return bitRead(_Status_Register[0], 1);
|
||||
else if (_Status == MAX17055_IMin)
|
||||
return bitRead(_Status_Register[0], 2);
|
||||
else if (_Status == MAX17055_IMax)
|
||||
return bitRead(_Status_Register[0], 6);
|
||||
else if (_Status == MAX17055_VMin)
|
||||
return bitRead(_Status_Register[1], 0);
|
||||
else if (_Status == MAX17055_VMax)
|
||||
return bitRead(_Status_Register[1], 4);
|
||||
else if (_Status == MAX17055_TMin)
|
||||
return bitRead(_Status_Register[1], 1);
|
||||
else if (_Status == MAX17055_TMax)
|
||||
return bitRead(_Status_Register[1], 5);
|
||||
else if (_Status == MAX17055_SOC_Min)
|
||||
return bitRead(_Status_Register[1], 2);
|
||||
else if (_Status == MAX17055_SOC_Max)
|
||||
return bitRead(_Status_Register[1], 6);
|
||||
else if (_Status == MAX17055_SOC_Change)
|
||||
return bitRead(_Status_Register[0], 7);
|
||||
else if (_Status == MAX17055_Bat_Status)
|
||||
return bitRead(_Status_Register[0], 3);
|
||||
else if (_Status == MAX17055_Bat_Insert)
|
||||
return bitRead(_Status_Register[1], 3);
|
||||
else if (_Status == MAX17055_Bat_Remove)
|
||||
return bitRead(_Status_Register[1], 7);
|
||||
|
||||
// End Function
|
||||
return false;
|
||||
}
|
||||
|
||||
void MAX17055::statusClear(void) {
|
||||
// Define Data Variable
|
||||
const uint8_t _Status_Register[2] = {0x00, 0x00};
|
||||
|
||||
// Write Status Register
|
||||
writeMultipleRegister(0x00, _Status_Register, 2);
|
||||
}
|
||||
|
||||
uint16_t MAX17055::chargeTerminationCurrent(void) {
|
||||
// Get Data from IC
|
||||
uint16_t _Measurement_Raw = read_register(0x1E);
|
||||
|
||||
// Calculate Data
|
||||
uint16_t Value = (((uint32_t)_Measurement_Raw * 1.5625) / __MAX17055_Resistor__);
|
||||
|
||||
// End Function
|
||||
return Value;
|
||||
}
|
||||
|
||||
} /* namespace max17055 */
|
||||
} // namespace battery
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright (C) 2024 jLynx.
|
||||
*
|
||||
* 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 __MAX17055_H__
|
||||
#define __MAX17055_H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "i2c_pp.hpp"
|
||||
|
||||
#define MAX17055_POR 0
|
||||
#define MAX17055_IMin 1
|
||||
#define MAX17055_IMax 2
|
||||
#define MAX17055_VMin 3
|
||||
#define MAX17055_VMax 4
|
||||
#define MAX17055_TMin 5
|
||||
#define MAX17055_TMax 6
|
||||
#define MAX17055_SOC_Min 7
|
||||
#define MAX17055_SOC_Max 8
|
||||
#define MAX17055_SOC_Change 9
|
||||
#define MAX17055_Bat_Status 10
|
||||
#define MAX17055_Bat_Insert 11
|
||||
#define MAX17055_Bat_Remove 12
|
||||
|
||||
// Design Parameters
|
||||
//----------------------------------------------
|
||||
|
||||
// Define Battery Capacity
|
||||
#ifndef __MAX17055_Design_Capacity__
|
||||
#define __MAX17055_Design_Capacity__ 2500 // Battery Capacity
|
||||
#endif
|
||||
|
||||
// Define Gauge Resistor
|
||||
#ifndef __MAX17055_Resistor__
|
||||
#define __MAX17055_Resistor__ 0.01 // Shunt Resistor
|
||||
#endif
|
||||
|
||||
// Define Minimum Voltage
|
||||
#ifndef __MAX17055_Min_Voltage__
|
||||
#define __MAX17055_Min_Voltage__ 3.0 // Minimum Voltage
|
||||
#endif
|
||||
|
||||
// Define Maximum Voltage
|
||||
#ifndef __MAX17055_Max_Voltage__
|
||||
#define __MAX17055_Max_Voltage__ 4.17 // Maximum Voltage
|
||||
#endif
|
||||
|
||||
// Define Empty Voltage
|
||||
#ifndef __MAX17055_Empty_Voltage__
|
||||
#define __MAX17055_Empty_Voltage__ 3.0 // Empty Voltage
|
||||
#endif
|
||||
|
||||
// Define Recovery Voltage
|
||||
#ifndef __MAX17055_Recovery_Voltage__
|
||||
#define __MAX17055_Recovery_Voltage__ 3.1 // Recovery Voltage
|
||||
#endif
|
||||
|
||||
// Define Maximum Current
|
||||
#ifndef __MAX17055_Max_Current__
|
||||
#define __MAX17055_Max_Current__ 3.0 // Maximum Current
|
||||
#endif
|
||||
|
||||
// Define Termination Current
|
||||
#ifndef __MAX17055_Termination_Current__
|
||||
#define __MAX17055_Termination_Current__ 0.1 // Termination Current
|
||||
#endif
|
||||
|
||||
// Define Minimum Temperature
|
||||
#ifndef __MAX17055_Min_Temperature__
|
||||
#define __MAX17055_Min_Temperature__ -20 // Minimum Temperature
|
||||
#endif
|
||||
|
||||
// Define Maximum Temperature
|
||||
#ifndef __MAX17055_Max_Temperature__
|
||||
#define __MAX17055_Max_Temperature__ 60 // Maximum Temperature
|
||||
#endif
|
||||
|
||||
// Define Battery Model
|
||||
#ifndef __MAX17055_Battery_Model__
|
||||
#define __MAX17055_Battery_Model__ 0 // Battery Model
|
||||
#endif
|
||||
|
||||
// Define Limits
|
||||
//----------------------------------------------
|
||||
|
||||
// Define Minimum SOC
|
||||
#ifndef __MAX17055_Min_SOC__
|
||||
#define __MAX17055_Min_SOC__ 0 // Minimum SOC
|
||||
#endif
|
||||
|
||||
// Define Maximum SOC
|
||||
#ifndef __MAX17055_Max_SOC__
|
||||
#define __MAX17055_Max_SOC__ 100 // Maximum SOC
|
||||
#endif
|
||||
|
||||
// Config1 (0x1D) Configuration
|
||||
//----------------------------------------------
|
||||
|
||||
// Enable alert on battery removal when the IC is mounted host side.
|
||||
// When Ber = 1, a battery-removal condition, as detected by the AIN pin voltage, triggers an alert.
|
||||
#ifndef MAX17055_Ber
|
||||
#define MAX17055_Ber 0
|
||||
#endif
|
||||
|
||||
// Enable alert on battery insertion when the IC is mounted host side.
|
||||
// When Bei = 1, a battery-insertion condition, as detected by the AIN pin voltage, triggers an alert.
|
||||
#ifndef MAX17055_Bei
|
||||
#define MAX17055_Bei 0
|
||||
#endif
|
||||
|
||||
// When Aen = 1, violation of any of the alert threshold register values
|
||||
// by temperature, voltage, or SOC triggers an alert. This bit
|
||||
// affects the ALRT pin operation only. The Smx, Smn, Tmx,
|
||||
// Tmn, Vmx, Vmn, Imx, and Imn bits of the Status register
|
||||
// (00h) are not disabled.
|
||||
#ifndef MAX17055_Aen
|
||||
#define MAX17055_Aen 1
|
||||
#endif
|
||||
|
||||
// This allows the host to control the bias of the thermistor switch or
|
||||
// enable fast detection of battery removal. Set FTHRM = 1
|
||||
// to always enable the thermistor bias switch. With a standard 10kΩ thermistor,
|
||||
// this adds an additional ~200μA to the current drain of the circuit.
|
||||
#ifndef MAX17055_FTHRM
|
||||
#define MAX17055_FTHRM 0
|
||||
#endif
|
||||
|
||||
// Set to logic 1 to enable the automatic THRM output bias and AIN measurement.
|
||||
#ifndef MAX17055_ETHRM
|
||||
#define MAX17055_ETHRM 0
|
||||
#endif
|
||||
|
||||
// Set to logic 1 to force the device to enter shutdown mode if both
|
||||
// SDA and SCL are held low for more than timeout of the
|
||||
// ShdnTimer register.
|
||||
#ifndef MAX17055_COMMSH
|
||||
#define MAX17055_COMMSH 0
|
||||
#endif
|
||||
|
||||
// Write this bit to logic 1 to force a shutdown of the device after timeout of the ShdnTimer register (default 45s delay).
|
||||
#ifndef MAX17055_SHDN
|
||||
#define MAX17055_SHDN 0
|
||||
#endif
|
||||
|
||||
// When set to 1, the fuel gauge requires external temperature measurements to be
|
||||
// written from the host. When set to 0, the IC's own measurements as used as selected by Config.TSEL.
|
||||
#ifndef MAX17055_Tex
|
||||
#define MAX17055_Tex 0
|
||||
#endif
|
||||
|
||||
// Set to 1 and set ETHRM or FTHRM to 1 to enable temperature measurements selected by Config.TSel.
|
||||
#ifndef MAX17055_Ten
|
||||
#define MAX17055_Ten 1
|
||||
#endif
|
||||
|
||||
// Set to 1 to enable device shutdown when the IC is mounted host side and the battery is removed.
|
||||
#ifndef MAX17055_AINSH
|
||||
#define MAX17055_AINSH 0
|
||||
#endif
|
||||
|
||||
// When IS = 1, current alerts can only be cleared through software. When IS = 0,
|
||||
// current alerts are cleared automatically when the thresholdis no longer exceeded.
|
||||
#ifndef MAX17055_IS
|
||||
#define MAX17055_IS 0
|
||||
#endif
|
||||
|
||||
// When VS = 1, voltage alerts can only be cleared through software. When VS = 0,
|
||||
// voltage alerts are cleared automatically when the threshold is no longer exceeded.
|
||||
#ifndef MAX17055_VS
|
||||
#define MAX17055_VS 0
|
||||
#endif
|
||||
|
||||
// When TS = 1, temperature alerts can only be cleared through software. WhenTS = 0,
|
||||
// temperature alerts are cleared automatically whenthe threshold is no longer exceeded.
|
||||
#ifndef MAX17055_TS
|
||||
#define MAX17055_TS 0
|
||||
#endif
|
||||
|
||||
// When SS = 1, SOC alerts can only be cleared through software. When SS = 0,
|
||||
// SOC alerts are cleared automatically when the threshold is no longer exceeded.
|
||||
#ifndef MAX17055_SS
|
||||
#define MAX17055_SS 0
|
||||
#endif
|
||||
|
||||
// 0 to use internal die temperature. 1 to use temperature information from thermistor.
|
||||
// ETHRM bit should be set to 1 when TSel is 1.
|
||||
#ifndef MAX17055_TSel
|
||||
#define MAX17055_TSel 0
|
||||
#endif
|
||||
|
||||
// Config1 (0xBB) Configuration
|
||||
//----------------------------------------------
|
||||
|
||||
// Set to 1 to enable constant-power mode. If it is set to 0,
|
||||
// AtRate/AvgCurrent is used for (At)TTE/(At) QResidual/(At)AvSOC/(At)AvCap.
|
||||
#ifndef MAX17055_CPMode
|
||||
#define MAX17055_CPMode 0
|
||||
#endif
|
||||
|
||||
// Host sets this bit to 1 in order to initiate firmware to finish processing a newly loaded model.
|
||||
// Firmware clears this bit to zero to indicate that model loading is finished.
|
||||
#ifndef MAX17055_LDMDL
|
||||
#define MAX17055_LDMDL 0
|
||||
#endif
|
||||
|
||||
// Set this bit to 1 to enable temperature based alerts.
|
||||
// Write this bit to 0 to disable temperature alerts. This bit is set to 1 at power-up.
|
||||
#ifndef MAX17055_TAIrtEN
|
||||
#define MAX17055_TAIrtEN 1
|
||||
#endif
|
||||
|
||||
// Set this bit to 1 to enable alert output with the Status.dSOCi bit function.
|
||||
// Write this bit to 0 to disable alert output with the Status. dSOCi bit. This bit is set to 0 at power-up.
|
||||
#ifndef MAX17055_dSOCen
|
||||
#define MAX17055_dSOCen 0
|
||||
#endif
|
||||
|
||||
// When this bit is set to 0, Dynamic Power calculations are disabled and registers
|
||||
// MaxPeakPower/SusPeakPower/MPPCurrent/ SPPCurrent can be used as general purpose memory.
|
||||
#ifndef MAX17055_DPEn
|
||||
#define MAX17055_DPEn 0
|
||||
#endif
|
||||
|
||||
// When this bit is set to 0, AtRate calculations are disabled and registers
|
||||
// AtQResidual/AtTTE/AtAvSOC/AtAvCap can be used as general purpose memory.
|
||||
#ifndef MAX17055_AtRateEn
|
||||
#define MAX17055_AtRateEn 0
|
||||
#endif
|
||||
|
||||
namespace battery {
|
||||
namespace max17055 {
|
||||
|
||||
using address_t = uint8_t;
|
||||
|
||||
class MAX17055 {
|
||||
public:
|
||||
constexpr MAX17055(I2C& bus, const I2C::address_t bus_address)
|
||||
: bus(bus), bus_address(bus_address), detected_(false) {}
|
||||
|
||||
void init();
|
||||
bool detect();
|
||||
bool isDetected() const { return detected_; }
|
||||
|
||||
uint16_t readVoltage();
|
||||
uint8_t readPercentage();
|
||||
void getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current);
|
||||
|
||||
uint16_t instantVoltage(void);
|
||||
uint16_t averageVoltage(void);
|
||||
uint16_t emptyVoltage(void);
|
||||
uint16_t recoveryVoltage(void);
|
||||
int32_t instantCurrent(void);
|
||||
int32_t averageCurrent(void);
|
||||
uint16_t stateOfCharge(void);
|
||||
uint16_t averageStateOfCharge(void);
|
||||
uint16_t instantCapacity(void);
|
||||
uint16_t designCapacity(void);
|
||||
uint16_t fullCapacity(void);
|
||||
uint16_t icTemperature(void);
|
||||
uint16_t timeToEmpty(void);
|
||||
uint16_t timeToFull(void);
|
||||
uint16_t batteryAge(void);
|
||||
uint16_t chargeCycle(void);
|
||||
bool statusControl(const uint8_t _Status);
|
||||
void statusClear(void);
|
||||
uint16_t chargeTerminationCurrent(void);
|
||||
uint16_t read_register(const uint8_t reg);
|
||||
bool write_register(const uint8_t reg, const uint16_t value);
|
||||
|
||||
private:
|
||||
I2C& bus;
|
||||
const I2C::address_t bus_address;
|
||||
bool detected_ = false;
|
||||
|
||||
bool readRegister(uint8_t reg, uint16_t& value);
|
||||
bool readMultipleRegister(uint8_t reg, uint8_t* data, uint8_t length, bool endTransmission);
|
||||
bool writeMultipleRegister(uint8_t reg, const uint8_t* data, uint8_t length);
|
||||
|
||||
bool setEmptyVoltage(uint16_t _Empty_Voltage);
|
||||
bool setRecoveryVoltage(uint16_t _Recovery_Voltage);
|
||||
bool setMinVoltage(uint16_t _Minimum_Voltage);
|
||||
bool setMaxVoltage(uint16_t _Maximum_Voltage);
|
||||
bool setMaxCurrent(uint16_t _Maximum_Current);
|
||||
bool setChargeTerminationCurrent(uint16_t _Charge_Termination_Current);
|
||||
bool setDesignCapacity(const uint16_t _Capacity);
|
||||
bool setFullCapRep(const uint16_t _Capacity);
|
||||
bool setFullCapNom(const uint16_t _Capacity);
|
||||
bool setRepCap(const uint16_t _Capacity);
|
||||
bool setMinSOC(uint8_t _Minimum_SOC);
|
||||
bool setMaxSOC(uint8_t _Maximum_SOC);
|
||||
bool setMinTemperature(uint8_t _Minimum_Temperature);
|
||||
bool setMaxTemperature(uint8_t _Maximum_Temperature);
|
||||
bool setModelCfg(const uint8_t _Model_ID);
|
||||
bool setHibCFG(const uint16_t _Config);
|
||||
void config(void);
|
||||
};
|
||||
|
||||
} /* namespace max17055 */
|
||||
} // namespace battery
|
||||
#endif /* __MAX17055_H__ */
|
||||
@@ -1413,14 +1413,17 @@ class PocsagTosendMessage : public Message {
|
||||
class BatteryStateMessage : public Message {
|
||||
public:
|
||||
constexpr BatteryStateMessage(
|
||||
uint8_t valid_mask,
|
||||
uint8_t percent,
|
||||
bool on_charger,
|
||||
uint16_t voltage)
|
||||
: Message{ID::BatteryStateData},
|
||||
valid_mask{valid_mask},
|
||||
percent{percent},
|
||||
on_charger{on_charger},
|
||||
voltage{voltage} {
|
||||
}
|
||||
uint8_t valid_mask = 0;
|
||||
uint8_t percent = 0;
|
||||
bool on_charger = false;
|
||||
uint16_t voltage = 0; // mV
|
||||
|
||||
@@ -2048,7 +2048,7 @@ bool TextField::on_touch(TouchEvent event) {
|
||||
|
||||
BatteryIcon::BatteryIcon(Rect parent_rect, uint8_t percent)
|
||||
: Widget(parent_rect) {
|
||||
this->set_battery(percent, false);
|
||||
this->set_battery(percent <= 100 ? 1 : 0, percent, false);
|
||||
set_focusable(true);
|
||||
}
|
||||
|
||||
@@ -2059,10 +2059,12 @@ void BatteryIcon::getWidgetName(std::string& result) {
|
||||
result = "Battery percent";
|
||||
}
|
||||
|
||||
void BatteryIcon::set_battery(uint8_t percentage, bool charge) {
|
||||
if (charge == charge_ && percent_ == percentage) return;
|
||||
void BatteryIcon::set_battery(uint8_t valid_mask, uint8_t percentage, bool charge) {
|
||||
if (charge == charge_ && percent_ == percentage && valid_ == valid_mask) return;
|
||||
percent_ = percentage;
|
||||
charge_ = charge;
|
||||
valid_ = valid_mask;
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_VOLTAGE) != battery::BatteryManagement::BATT_VALID_VOLTAGE) percent_ = 102; // to indicate error
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
@@ -2121,7 +2123,7 @@ void BatteryIcon::paint(Painter& painter) {
|
||||
|
||||
BatteryTextField::BatteryTextField(Rect parent_rect, uint8_t percent)
|
||||
: Widget(parent_rect) {
|
||||
this->set_battery(percent, false);
|
||||
this->set_battery(percent <= 100 ? 1 : 0, percent, false);
|
||||
set_focusable(true);
|
||||
}
|
||||
|
||||
@@ -2146,10 +2148,12 @@ void BatteryTextField::getWidgetName(std::string& result) {
|
||||
result = "Battery percent";
|
||||
}
|
||||
|
||||
void BatteryTextField::set_battery(uint8_t percentage, bool charge) {
|
||||
if (charge == charge_ && percent_ == percentage) return;
|
||||
void BatteryTextField::set_battery(uint8_t valid_mask, uint8_t percentage, bool charge) {
|
||||
if (charge == charge_ && percent_ == percentage && valid_ == valid_mask) return;
|
||||
charge_ = charge;
|
||||
percent_ = percentage;
|
||||
valid_ = valid_mask;
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_VOLTAGE) != battery::BatteryManagement::BATT_VALID_VOLTAGE) percent_ = 102; // to indicate error
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
|
||||
@@ -790,7 +790,7 @@ class BatteryTextField : public Widget {
|
||||
BatteryTextField(Rect parent_rect, uint8_t percent);
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
void set_battery(uint8_t percentage, bool charge);
|
||||
void set_battery(uint8_t valid_mask, uint8_t percentage, bool charge);
|
||||
void set_text(std::string_view value);
|
||||
|
||||
bool on_key(KeyEvent key) override;
|
||||
@@ -801,6 +801,7 @@ class BatteryTextField : public Widget {
|
||||
|
||||
private:
|
||||
uint8_t percent_{102};
|
||||
uint8_t valid_{0};
|
||||
bool charge_{false};
|
||||
|
||||
Style style{
|
||||
@@ -816,7 +817,7 @@ class BatteryIcon : public Widget {
|
||||
|
||||
BatteryIcon(Rect parent_rect, uint8_t percent);
|
||||
void paint(Painter& painter) override;
|
||||
void set_battery(uint8_t percentage, bool charge);
|
||||
void set_battery(uint8_t valid_mask, uint8_t percentage, bool charge);
|
||||
|
||||
bool on_key(KeyEvent key) override;
|
||||
bool on_touch(TouchEvent event) override;
|
||||
@@ -826,6 +827,7 @@ class BatteryIcon : public Widget {
|
||||
|
||||
private:
|
||||
uint8_t percent_{102};
|
||||
uint8_t valid_{0};
|
||||
bool charge_{false};
|
||||
};
|
||||
|
||||
|
||||
@@ -220,6 +220,7 @@ target_link_libraries(${PROJECT_NAME}.elf -Wl,-Map=${PROJECT_NAME}.map)
|
||||
# redirect std lib memory allocations
|
||||
target_link_libraries(${PROJECT_NAME}.elf "-Wl,-wrap,_malloc_r")
|
||||
target_link_libraries(${PROJECT_NAME}.elf "-Wl,-wrap,_free_r")
|
||||
target_link_libraries(${PROJECT_NAME}.elf "-Wl,--print-memory-usage")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_NAME}.ppmp
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
f=400600000,d=poprad CH1
|
||||
f=403630000,d=zahorie CH2
|
||||
f=403810000,d=zahorie1 CH3
|
||||
f=403670000,d=zahorie2CH4
|
||||
f=403500000,d=vienna CH5
|
||||
f=402300000,d=szeged CH6
|
||||
f=403200000,d=budapest CH7
|
||||
f=404199000,d=praha CH8
|
||||
Reference in New Issue
Block a user