* WIP

* WIP

* WIP

* Corrected name

* WIP

* WIP

* WIP

* WIP

* Added new calc

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Added debug serial lines

* WIP

* Fixed issue

* Fixed calculation issue

* Added voltage to performance DFU menu

* Added padding function and added voltage to perf menu

* Clean up

* Refactor

* Fixed linting

* Hides voltage if PP does not conatin IC

* WIP showing battery %

* made the percentage a int

* Added % to header

* Removed test UI

* Removed comment

* Added fix for precision too large

* Added fix for precision too large

* Linting
This commit is contained in:
jLynx 2024-04-21 20:44:47 +12:00 committed by GitHub
parent 282e4da1cb
commit 67975d76a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 235 additions and 2 deletions

View File

@ -176,6 +176,7 @@ 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}/performance_counter.cpp ${COMMON}/performance_counter.cpp
app_settings.cpp app_settings.cpp
audio.cpp audio.cpp

View File

@ -41,6 +41,11 @@ 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 (portapack::battery_ads1110.isDetected()) {
add_child(&voltage_label);
add_child(&text_info_line_11);
}
} }
void DfuMenu::paint(Painter& painter) { void DfuMenu::paint(Painter& painter) {
@ -48,6 +53,8 @@ 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 = (portapack::battery_ads1110.isDetected() ? 11 : 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));
text_info_line_3.set(to_string_dec_uint(m0_fragments, 6)); text_info_line_3.set(to_string_dec_uint(m0_fragments, 6));
@ -58,9 +65,11 @@ 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 (portapack::battery_ads1110.isDetected()) {
text_info_line_11.set(to_string_decimal_padding(portapack::battery_ads1110.readVoltage(), 3, 6));
}
constexpr auto margin = 5; constexpr auto margin = 5;
constexpr auto lines = 10 + 2;
painter.fill_rectangle( painter.fill_rectangle(
{{6 * CHARACTER_WIDTH - margin, 3 * LINE_HEIGHT - margin}, {{6 * CHARACTER_WIDTH - margin, 3 * LINE_HEIGHT - margin},

View File

@ -58,7 +58,9 @@ class DfuMenu : public View {
{{6 * CHARACTER_WIDTH, 11 * LINE_HEIGHT}, "M4 stack:", Color::dark_cyan()}, {{6 * CHARACTER_WIDTH, 11 * LINE_HEIGHT}, "M4 stack:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 12 * LINE_HEIGHT}, "M4 cpu %:", Color::dark_cyan()}, {{6 * CHARACTER_WIDTH, 12 * LINE_HEIGHT}, "M4 cpu %:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 13 * LINE_HEIGHT}, "M4 miss:", Color::dark_cyan()}, {{6 * CHARACTER_WIDTH, 13 * LINE_HEIGHT}, "M4 miss:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 14 * LINE_HEIGHT}, "uptime:", Color::dark_cyan()}}; {{6 * CHARACTER_WIDTH, 14 * LINE_HEIGHT}, "Uptime:", Color::dark_cyan()}};
Labels voltage_label{{{6 * CHARACTER_WIDTH, 15 * LINE_HEIGHT}, "Voltage:", Color::dark_cyan()}};
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}, ""};
@ -70,6 +72,7 @@ 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 {

View File

@ -52,6 +52,7 @@ using asahi_kasei::ak4951::AK4951;
#include "sd_card.hpp" #include "sd_card.hpp"
#include "string_format.hpp" #include "string_format.hpp"
#include "bitmap.hpp" #include "bitmap.hpp"
#include "ui_widget.hpp"
namespace portapack { namespace portapack {
@ -84,6 +85,7 @@ ClockManager clock_manager{
WM8731 audio_codec_wm8731{i2c0, 0x1a}; WM8731 audio_codec_wm8731{i2c0, 0x1a};
AK4951 audio_codec_ak4951{i2c0, 0x12}; AK4951 audio_codec_ak4951{i2c0, 0x12};
ads1110::ADS1110 battery_ads1110{i2c0, 0x48};
ReceiverModel receiver_model; ReceiverModel receiver_model;
TransmitterModel transmitter_model; TransmitterModel transmitter_model;
@ -585,6 +587,7 @@ init_status_t init() {
chThdSleepMilliseconds(10); chThdSleepMilliseconds(10);
audio::init(portapack_audio_codec()); audio::init(portapack_audio_codec());
battery_ads1110.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);

View File

@ -33,6 +33,8 @@
#include "backlight.hpp" #include "backlight.hpp"
#include "usb_serial.hpp" #include "usb_serial.hpp"
#include "ads1110.hpp"
#include "radio.hpp" #include "radio.hpp"
#include "clock_manager.hpp" #include "clock_manager.hpp"
#include "temperature_logger.hpp" #include "temperature_logger.hpp"
@ -61,6 +63,7 @@ extern portapack::USBSerial usb_serial;
extern si5351::Si5351 clock_generator; extern si5351::Si5351 clock_generator;
extern ClockManager clock_manager; extern ClockManager clock_manager;
extern ads1110::ADS1110 battery_ads1110;
extern ReceiverModel receiver_model; extern ReceiverModel receiver_model;
extern TransmitterModel transmitter_model; extern TransmitterModel transmitter_model;

View File

@ -172,6 +172,31 @@ std::string to_string_decimal(float decimal, int8_t precision) {
return result; return result;
} }
std::string to_string_decimal_padding(float decimal, int8_t precision, const int32_t l) {
double integer_part;
double fractional_part;
std::string result;
if (precision > 9) precision = 9; // we will convert to uin32_t, and that is the max it can hold.
fractional_part = modf(decimal, &integer_part) * pow(10, precision);
if (fractional_part < 0) {
fractional_part = -fractional_part;
}
result = to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, precision, '0');
// Add padding with spaces to meet the length requirement
if (result.length() < l) {
int padding_length = l - result.length();
std::string padding(padding_length, ' ');
result = padding + result;
}
return result;
}
// right-justified frequency in Hz, always 10 characters // right-justified frequency in Hz, always 10 characters
std::string to_string_freq(const uint64_t f) { std::string to_string_freq(const uint64_t f) {
std::string final_str{""}; std::string final_str{""};

View File

@ -54,6 +54,7 @@ std::string to_string_bin(const uint32_t n, const uint8_t l = 0);
std::string to_string_dec_uint(const uint32_t n, const int32_t l, const char fill = ' '); std::string to_string_dec_uint(const uint32_t n, const int32_t l, const char fill = ' ');
std::string to_string_dec_int(const int32_t n, const int32_t l, const char fill = 0); std::string to_string_dec_int(const int32_t n, const int32_t l, const char fill = 0);
std::string to_string_decimal(float decimal, int8_t precision); std::string to_string_decimal(float decimal, int8_t precision);
std::string to_string_decimal_padding(float decimal, int8_t precision, const int32_t l);
std::string to_string_hex(uint64_t n, int32_t length); std::string to_string_hex(uint64_t n, int32_t length);
std::string to_string_hex_array(uint8_t* array, int32_t length); std::string to_string_hex_array(uint8_t* array, int32_t length);

130
firmware/common/ads1110.cpp Normal file
View File

@ -0,0 +1,130 @@
/*
* 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 "ads1110.hpp"
#include "utility.hpp"
#include <algorithm>
#include <cstdint>
namespace ads1110 {
constexpr float BATTERY_MIN_VOLTAGE = 3.0;
constexpr float BATTERY_MAX_VOLTAGE = 4.0;
void ADS1110::init() {
if (!detected_) {
detected_ = detect();
}
if (detected_) {
// Set the configuration register
write(0x8C);
}
}
bool ADS1110::detect() {
uint8_t data[3];
if (bus.receive(bus_address, data, 3)) {
// Check if the received data is valid
uint8_t configRegister = data[2];
if ((configRegister & 0x0F) == 0x0C) {
// The configuration register value matches the expected value (0x8C)
detected_ = true;
return true;
}
}
return false;
}
bool ADS1110::write(const uint8_t value) {
return bus.transmit(bus_address, &value, 1);
}
float ADS1110::readVoltage() {
// Read the conversion result
uint8_t data[3];
if (!bus.receive(bus_address, data, 3)) {
return 0.0f; // Return 0 if the read fails
}
uint16_t raw = (static_cast<uint16_t>(data[0]) << 8) | data[1];
// Calculate the voltage based on the output code
float voltage = 0.0f;
float minCode = 0;
float pga = 0.0f;
uint8_t pga_rate = data[2] & 0x03;
switch (pga_rate) {
case 0:
pga = 1.0f;
break;
case 1:
pga = 2.0f;
break;
case 2:
pga = 4.0f;
break;
case 3:
pga = 8.0f;
break;
default:
// Handle invalid data rate
break;
}
uint8_t data_rate = (data[2] >> 2) & 0x03;
switch (data_rate) {
case 0: // 240
minCode = -2048.0;
break;
case 1: // 60
minCode = -8192.0;
break;
case 2: // 30
minCode = -16384.0;
break;
case 3: // 15
minCode = -32768.0;
break;
default:
// Handle invalid data rate
break;
}
// 2.048 is the reference voltage & 2.0 is to make up for the voltage divider
voltage = raw / (-1.0 * minCode) * pga * 2.048 * 2.0;
return voltage;
}
void ADS1110::getBatteryInfo(float& batteryPercentage, float& voltage) {
voltage = readVoltage();
// Calculate the remaining battery percentage
batteryPercentage = (voltage - BATTERY_MIN_VOLTAGE) /
(BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE) * 100.0;
// Limit the values to the valid range
batteryPercentage = std::clamp(batteryPercentage, 0.0f, 100.0f);
// ToDo: if its > 4, then 100%, if < 3 then 0%
}
} /* namespace ads1110 */

View File

@ -0,0 +1,58 @@
/*
* 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 __ADS1110_H__
#define __ADS1110_H__
#include <cstdint>
#include <array>
#include <string>
#include "i2c_pp.hpp"
namespace ads1110 {
using address_t = uint8_t;
using reg_t = uint16_t;
class ADS1110 {
public:
constexpr ADS1110(I2C& bus, const I2C::address_t bus_address)
: bus(bus), bus_address(bus_address), detected_(false) {}
void init();
bool isDetected() const { return detected_; }
float readVoltage();
void getBatteryInfo(float& batteryPercentage, float& voltage);
private:
I2C& bus;
const I2C::address_t bus_address;
bool detected_;
bool write(const uint8_t value);
bool detect();
};
} /* namespace ads1110 */
#endif /* __ADS1110_H__ */