Skip to content

Commit 757a9c0

Browse files
ApehaengerClemensElfleinrovo89
authored
Feature/sabo wip (#35)
- [x] Persistent Sabo GPS settings, protecting against boot loop - [x] Improve emergency widget states for edge cases - [x] Merge/implement HighLevelService - [x] Add robot state to SaboScreenMain - [x] Add ADC driver for precise DCDC-in current Please take an extra look to changes in: - robots/include/robot.hpp - src/services/gps_service/gps_service.cpp --------- Co-authored-by: Clemens Elflein <clemens1@familie-elflein.de> Co-authored-by: Robert Vollmer <dev@robv.de>
1 parent aa9b5ff commit 757a9c0

25 files changed

+1241
-145
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ target_sources(${CMAKE_PROJECT_NAME} PRIVATE
7575
src/json_stream.cpp
7676
src/services.cpp
7777
src/status_led.c
78+
src/drivers/adc/adc1.cpp
79+
src/drivers/adc/adc3.cpp
7880
# LittleFS helpers
7981
src/filesystem/file.cpp
8082
src/filesystem/filesystem.cpp
@@ -85,6 +87,7 @@ target_sources(${CMAKE_PROJECT_NAME} PRIVATE
8587
src/services/mower_service/mower_service.cpp
8688
src/services/gps_service/gps_service.cpp
8789
src/services/input_service/input_service.cpp
90+
src/services/high_level_service/high_level_service.cpp
8891
# BQ2567 driver
8992
src/drivers/charger/bq_2576/bq_2576.cpp
9093
# BQ25679 driver
@@ -160,6 +163,7 @@ target_add_service(${CMAKE_PROJECT_NAME} DiffDriveService ${CMAKE_CURRENT_SOURCE
160163
target_add_service(${CMAKE_PROJECT_NAME} MowerService ${CMAKE_CURRENT_SOURCE_DIR}/services/mower_service.json)
161164
target_add_service(${CMAKE_PROJECT_NAME} GpsService ${CMAKE_CURRENT_SOURCE_DIR}/services/gps_service.json)
162165
target_add_service(${CMAKE_PROJECT_NAME} InputService ${CMAKE_CURRENT_SOURCE_DIR}/services/input_service.json)
166+
target_add_service(${CMAKE_PROJECT_NAME} HighLevelService ${CMAKE_CURRENT_SOURCE_DIR}/services/high_level_service.json)
163167

164168
set_target_properties(${CMAKE_PROJECT_NAME}
165169
PROPERTIES SUFFIX ".elf")

boards/XCORE/mcuconf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@
291291
#define STM32_I2C_I2C2_DMA_PRIORITY 3
292292
#define STM32_I2C_I2C3_DMA_PRIORITY 3
293293
#define STM32_I2C_I2C4_DMA_PRIORITY 3
294-
#define STM32_I2C_USE_DMA TRUE
294+
#define STM32_I2C_USE_DMA FALSE
295295
#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
296296

297297
/*

robots/include/robot.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
#include <hal.h>
77

88
#include <debug/debug_tcp_interface.hpp>
9+
#include <limits>
10+
11+
// Forward declare ProtocolType from GpsServiceBase.hpp
12+
enum class ProtocolType : uint8_t;
913

1014
class Robot {
1115
public:
@@ -41,6 +45,29 @@ class Robot {
4145
* Return the minimum voltage before shutting down as much as possible
4246
*/
4347
virtual float Power_GetAbsoluteMinVoltage() = 0;
48+
49+
/**
50+
* Set the max. allowed system current in Amps.
51+
* This is to limit e.g. the charger current for not overloading the power supply.
52+
* Only usefull for systems that do have some kind of system current sense.
53+
*/
54+
virtual void Power_SetSystemCurrent(float system_current) {
55+
(void)system_current;
56+
};
57+
58+
/**
59+
* Save GPS settings to persistent storage (optional).
60+
* Default implementation does nothing.
61+
* @param protocol GPS protocol (0=UBX, 1=NMEA as per ProtocolType enum)
62+
* @param uart UART index (0 = default robot port)
63+
* @param baudrate Baudrate
64+
*/
65+
virtual bool SaveGpsSettings(ProtocolType protocol, uint8_t uart, uint32_t baudrate) {
66+
(void)protocol;
67+
(void)uart;
68+
(void)baudrate;
69+
return true;
70+
}
4471
};
4572

4673
class MowerRobot : public Robot {

robots/include/sabo_common.hpp

Lines changed: 83 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@
2424
#include <globals.hpp>
2525

2626
#include "../../src/filesystem/versioned_struct.hpp"
27+
#include "GpsServiceBase.hpp"
2728

2829
namespace xbot::driver::sabo {
2930

3031
// Main types and enums
3132
namespace types {
3233
// Hardware versions are "as of" versions
33-
enum class HardwareVersion : uint8_t { V0_1 = 0, V0_2, V0_3 };
34+
enum class HardwareVersion : uint8_t { V0_1 = 0, V0_2_0, V0_2_1, V0_3 };
3435

3536
enum class SeriesType { Series1, Series2 };
3637

@@ -74,43 +75,49 @@ enum class TempCompensation : uint8_t {
7475
// Hardware configurations
7576
namespace config {
7677
struct Sensor {
77-
ioline_t line;
78-
bool invert = false;
78+
const ioline_t line;
79+
const bool invert = false;
7980
};
8081

8182
struct Spi {
8283
SPIDriver* instance;
8384
struct {
84-
ioline_t sck;
85-
ioline_t miso;
86-
ioline_t mosi;
87-
ioline_t cs = PAL_NOLINE;
85+
const ioline_t sck;
86+
const ioline_t miso;
87+
const ioline_t mosi;
88+
const ioline_t cs = PAL_NOLINE;
8889
} pins;
8990
};
9091

9192
struct CoverUi {
9293
Spi spi;
9394
struct {
94-
ioline_t latch_load;
95-
ioline_t oe = PAL_NOLINE;
96-
ioline_t btn_cs = PAL_NOLINE;
97-
ioline_t inp_cs = PAL_NOLINE;
95+
const ioline_t latch_load;
96+
const ioline_t oe = PAL_NOLINE;
97+
const ioline_t btn_cs = PAL_NOLINE;
98+
const ioline_t inp_cs = PAL_NOLINE;
9899
} pins;
99100
};
100101

101102
struct Lcd {
102-
Spi spi;
103+
const Spi spi;
103104
struct {
104-
ioline_t dc;
105-
ioline_t rst;
106-
ioline_t backlight;
105+
const ioline_t dc;
106+
const ioline_t rst;
107+
const ioline_t backlight;
107108
} pins;
108109
};
109110

110111
struct Bms {
111112
I2CDriver* i2c;
112113
};
113114

115+
struct Adc {
116+
const float charger_voltage_scale_factor;
117+
const float battery_voltage_scale_factor;
118+
const float dcdc_in_current_scale_factor;
119+
};
120+
114121
// Individual hardware configurations
115122
inline const Sensor SENSORS_V0_1[] = {
116123
{LINE_GPIO13}, // LIFT_FL
@@ -143,12 +150,17 @@ inline const Lcd LCD_V0_2 = {.spi = {&SPID1, {LINE_SPI1_SCK, LINE_SPI1_MISO, LIN
143150

144151
inline const Bms BMS_V0_2 = {.i2c = &I2CD2};
145152

153+
inline const Adc ADC_V0_2_1 = {.charger_voltage_scale_factor = 16.3846f, // (200k Rtop + 13k Rbot)/13k Rbot
154+
.battery_voltage_scale_factor = 16.3846f, // (200k Rtop + 13k Rbot)/13k Rbot
155+
.dcdc_in_current_scale_factor = 1.0f}; // 1/(20gain * Rshunt 0.05)
156+
146157
// Hardware configuration references
147158
struct HardwareConfig {
148159
etl::array_view<const Sensor> sensors;
149160
const CoverUi* cover_ui;
150161
const Lcd* lcd;
151162
const Bms* bms;
163+
const Adc* adc;
152164
};
153165

154166
// Hardware version to configuration array which need to be in sync with HardwareVersion enum
@@ -159,22 +171,26 @@ inline constexpr HardwareConfig HARDWARE_CONFIGS[] = {
159171
.cover_ui = &COVER_UI_V0_1,
160172
.lcd = nullptr, // No LCD for V0_1
161173
.bms = nullptr, // No BMS for V0_1
174+
.adc = nullptr // No ADC for V0_1
162175
},
163-
// V0_2
164-
{
165-
.sensors = etl::array_view<const Sensor>(SENSORS_V0_1),
166-
.cover_ui = &COVER_UI_V0_2,
167-
.lcd = &LCD_V0_2,
168-
.bms = &BMS_V0_2,
169-
},
176+
// V0_2_0
177+
{.sensors = etl::array_view<const Sensor>(SENSORS_V0_1),
178+
.cover_ui = &COVER_UI_V0_2,
179+
.lcd = &LCD_V0_2,
180+
.bms = &BMS_V0_2,
181+
.adc = nullptr},
182+
// V0_2_1
183+
{.sensors = etl::array_view<const Sensor>(SENSORS_V0_1),
184+
.cover_ui = &COVER_UI_V0_2,
185+
.lcd = &LCD_V0_2,
186+
.bms = &BMS_V0_2,
187+
.adc = &ADC_V0_2_1},
170188
// V0_3
171-
{
172-
.sensors = etl::array_view<const Sensor>(SENSORS_V0_3),
173-
.cover_ui = &COVER_UI_V0_2,
174-
.lcd = &LCD_V0_2,
175-
.bms = nullptr, // No BMS for V0_3 yet
176-
},
177-
};
189+
{.sensors = etl::array_view<const Sensor>(SENSORS_V0_3),
190+
.cover_ui = &COVER_UI_V0_2,
191+
.lcd = &LCD_V0_2,
192+
.bms = nullptr, // No BMS for V0_3 yet
193+
.adc = &ADC_V0_2_1}};
178194
} // namespace config
179195

180196
// Constants and definitions
@@ -190,6 +206,7 @@ inline constexpr size_t NUM_BUTTONS = sizeof(ALL_BUTTONS) / sizeof(ALL_BUTTONS[0
190206
inline constexpr uint16_t LCD_WIDTH = 240; // ATTENTION: LVGL I1 mode requires a multiple of 8 width
191207
inline constexpr uint16_t LCD_HEIGHT = 160;
192208
inline constexpr uint8_t BUFFER_FRACTION = 10; // 1/10 screen size for buffers
209+
193210
} // namespace defs
194211

195212
// Settings namespace for persistent configuration
@@ -210,7 +227,7 @@ namespace settings {
210227
* Migration is handled automatically by VersionedStruct base class.
211228
*/
212229
#pragma pack(push, 1)
213-
struct LCDSettings : public xbot::driver::filesystem::VersionedStruct<xbot::driver::sabo::settings::LCDSettings> {
230+
struct LCDSettings : public xbot::driver::filesystem::VersionedStruct<LCDSettings> {
214231
VERSIONED_STRUCT_FIELDS(1); // Version 1 - automatically defines VERSION constant and version field
215232
static constexpr const char* PATH = "/cfg/sabo/lcd.bin";
216233

@@ -220,8 +237,36 @@ struct LCDSettings : public xbot::driver::filesystem::VersionedStruct<xbot::driv
220237
};
221238
#pragma pack(pop)
222239

223-
static_assert(sizeof(LCDSettings) == 5,
224-
"LCDSettings must be 5 bytes (2 version + 3 data)"); // Protect against thoughtless changes
240+
// Protect against thoughtless changes
241+
static_assert(sizeof(LCDSettings) == 5, "LCDSettings must be 5 bytes (2 version + 3 data)");
242+
243+
/**
244+
* @brief GPS persistent settings stored in LittleFS
245+
*
246+
* This struct is serialized directly to flash as binary data.
247+
* Evolution strategy: version field + append-only new fields.
248+
*
249+
* Rules for evolution:
250+
* - NEVER change existing field types or order
251+
* - ALWAYS increment VERSION when adding fields
252+
* - ONLY append new fields at the end
253+
* - Use padding to maintain alignment if needed
254+
*
255+
* Migration is handled automatically by VersionedStruct base class.
256+
*/
257+
#pragma pack(push, 1)
258+
struct GPSSettings : public xbot::driver::filesystem::VersionedStruct<GPSSettings> {
259+
VERSIONED_STRUCT_FIELDS(1); // Version 1 - automatically defines VERSION constant and version field
260+
static constexpr const char* PATH = "/cfg/sabo/gps.bin";
261+
262+
ProtocolType protocol = ProtocolType::NMEA; // GPS protocol (UBX or NMEA)
263+
uint8_t uart = 0; // UART index (0 = default robot port)
264+
uint32_t baudrate = 921600; // Baudrate
265+
};
266+
#pragma pack(pop)
267+
268+
// Protect against thoughtless changes
269+
static_assert(sizeof(GPSSettings) == 8, "GPSSettings must be 8 bytes (2 version + 1 protocol + 1 uart + 4 baudrate)");
225270

226271
} // namespace settings
227272

@@ -236,7 +281,12 @@ inline types::HardwareVersion GetHardwareVersion(const struct carrier_board_info
236281
if (board_info.version_major == 0) {
237282
switch (board_info.version_minor) {
238283
case 1: version = types::HardwareVersion::V0_1; break;
239-
case 2: version = types::HardwareVersion::V0_2; break;
284+
case 2:
285+
switch (board_info.version_patch) {
286+
case 0: version = types::HardwareVersion::V0_2_0; break;
287+
case 1: version = types::HardwareVersion::V0_2_1; break;
288+
}
289+
break;
240290
case 3: version = types::HardwareVersion::V0_3; break;
241291
}
242292
}

robots/include/sabo_robot.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define SABO_ROBOT_HPP
33

44
#include <cstdint>
5+
#include <drivers/adc/adc1.hpp>
56
#include <drivers/bms/sabo_bms_driver.hpp>
67
#include <drivers/charger/bq_2576/bq_2576.hpp>
78
#include <drivers/input/sabo_input_driver.hpp>
@@ -15,6 +16,7 @@ using namespace xbot::driver::ui;
1516
using namespace xbot::driver::motor;
1617
using namespace xbot::driver::sabo;
1718
using namespace xbot::driver::bms;
19+
using namespace xbot::driver::adc1;
1820

1921
class SaboRobot : public MowerRobot {
2022
public:
@@ -54,6 +56,8 @@ class SaboRobot : public MowerRobot {
5456
return 1.95f; // Lets stay save and conservative for now
5557
}
5658

59+
bool SaveGpsSettings(ProtocolType protocol, uint8_t uart, uint32_t baudrate) override;
60+
5761
// ----- Some driver Test* functions used by Boot-Screen -----
5862

5963
bool TestCharger() {
@@ -126,6 +130,11 @@ class SaboRobot : public MowerRobot {
126130
SaboCoverUIController cover_ui_{hardware_config};
127131
SaboInputDriver sabo_input_driver_{hardware_config};
128132
SaboBmsDriver bms_{hardware_config.bms};
133+
134+
/**
135+
* @brief Register all ADC1 sensors
136+
*/
137+
void RegisterAdc1Sensors();
129138
};
130139

131140
#endif // SABO_ROBOT_HPP

0 commit comments

Comments
 (0)