Skip to content

Commit 24b371b

Browse files
ClemensElfleinrovo89
authored andcommitted
wip
1 parent cd023da commit 24b371b

File tree

3 files changed

+179
-55
lines changed

3 files changed

+179
-55
lines changed

src/drivers/ui/YardForceCoverUI/yard_force_cover_ui_driver.cpp

Lines changed: 135 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
#include <sys/unistd.h>
88
#include <ulog.h>
99

10+
#include <services.hpp>
11+
1012
#include "COBS.h"
13+
#include "services/mower_ui_service/mower_ui_service.hpp"
1114
#include "ui_board.h"
1215

1316
static constexpr uint8_t EVT_PACKET_RECEIVED = 1;
@@ -46,11 +49,11 @@ void YardForceCoverUIDriver::UartRxChar(UARTDriver *driver, uint16_t data) {
4649
YardForceCoverUIDriver *instance = reinterpret_cast<const UARTConfigEx *>(driver->config)->context;
4750
chDbgAssert(instance != nullptr, "instance cannot be null!");
4851
chSysLockFromISR();
49-
if (instance->processing) {
52+
if (instance->processing_) {
5053
chSysUnlockFromISR();
5154
return;
5255
}
53-
instance->buffer[instance->buffer_fill++] = data;
56+
instance->buffer_[instance->buffer_fill_++] = data;
5457
if (data == 0) {
5558
chEvtSignalI(instance->thread_, EVT_PACKET_RECEIVED);
5659
}
@@ -60,36 +63,133 @@ void YardForceCoverUIDriver::ThreadFunc() {
6063
while (true) {
6164
bool timeout = chEvtWaitAnyTimeout(EVT_PACKET_RECEIVED, TIME_S2I(1)) == 0;
6265
if (timeout) {
63-
RequestFWVersion();
64-
65-
msg_set_leds msg{};
66-
msg.type = Set_LEDs;
67-
static double value = 0.0f;
68-
setBars7(msg, value);
69-
value += 0.1f;
70-
sendUIMessage(&msg, sizeof(msg));
66+
if (!board_found_) {
67+
// Try to find the board
68+
RequestFWVersion();
69+
} else {
70+
UpdateUILeds();
71+
}
7172

7273
continue;
7374
}
7475
chSysLock();
7576
// Forbid packet reception
76-
processing = true;
77+
processing_ = true;
7778
chSysUnlock();
78-
if (buffer_fill > 0) {
79+
if (buffer_fill_ > 0) {
7980
ProcessPacket();
8081
}
81-
buffer_fill = 0;
82+
buffer_fill_ = 0;
8283
chSysLock();
8384
// Allow packet reception
84-
processing = false;
85+
processing_ = false;
8586
chSysUnlock();
8687
}
8788
}
89+
90+
void YardForceCoverUIDriver::UpdateUILeds() {
91+
// Show Info Docking LED
92+
msg_set_leds leds_message{};
93+
leds_message.type = Set_LEDs;
94+
95+
float charging_current = power_service.GetChargeCurrent();
96+
float adapter_volts = power_service.GetAdapterVolts();
97+
float battery_percent = power_service.GetBatteryPercent();
98+
float gps_quality_percent = mower_ui_service.GetGpsQuality();
99+
const auto high_level_state = mower_ui_service.GetHighLevelState();
100+
bool emergency = emergency_service.GetEmergency();
101+
102+
if ((charging_current > 0.80f) && (adapter_volts > 10.0f))
103+
setLed(leds_message, LED_CHARGING, LED_blink_fast);
104+
else if ((charging_current <= 0.80f) && (charging_current >= 0.15f) && (adapter_volts > 20.0f))
105+
setLed(leds_message, LED_CHARGING, LED_blink_slow);
106+
else if ((charging_current < 0.15f) && (adapter_volts > 20.0f))
107+
setLed(leds_message, LED_CHARGING, LED_on);
108+
else
109+
setLed(leds_message, LED_CHARGING, LED_off);
110+
111+
// Show Info Battery state
112+
if (battery_percent >= 0.1)
113+
setLed(leds_message, LED_BATTERY_LOW, LED_off);
114+
else
115+
setLed(leds_message, LED_BATTERY_LOW, LED_on);
116+
117+
if (adapter_volts < 10.0f) // activate only when undocked
118+
{
119+
// use the first LED row as bargraph
120+
setBars7(leds_message, battery_percent);
121+
if (gps_quality_percent == 0) {
122+
// if quality is 0, flash all LEDs to notify the user to calibrate.
123+
setBars4(leds_message, -1.0);
124+
} else {
125+
setBars4(leds_message, gps_quality_percent);
126+
}
127+
} else {
128+
setBars7(leds_message, 0);
129+
setBars4(leds_message, 0);
130+
}
131+
132+
if (gps_quality_percent < 0.25) {
133+
setLed(leds_message, LED_POOR_GPS, LED_on);
134+
} else if (gps_quality_percent < 0.50) {
135+
setLed(leds_message, LED_POOR_GPS, LED_blink_fast);
136+
} else if (gps_quality_percent < 0.75) {
137+
setLed(leds_message, LED_POOR_GPS, LED_blink_slow);
138+
} else {
139+
setLed(leds_message, LED_POOR_GPS, LED_off);
140+
}
141+
142+
// Let S1 show if ros is connected and which state it's in
143+
if (high_level_state == MowerUiService::HighLevelState::MODE_UNKNOWN) {
144+
setLed(leds_message, LED_S1, LED_off);
145+
} else {
146+
switch (high_level_state) {
147+
case MowerUiService::HighLevelState::MODE_IDLE:
148+
setLed(leds_message, LED_S1, LED_on);
149+
setLed(leds_message, LED_S2, LED_off);
150+
break;
151+
case MowerUiService::HighLevelState::MODE_AUTONOMOUS_MOWING:
152+
setLed(leds_message, LED_S1, LED_blink_slow);
153+
setLed(leds_message, LED_S2, LED_off);
154+
break;
155+
case MowerUiService::HighLevelState::MODE_AUTONOMOUS_DOCKING:
156+
setLed(leds_message, LED_S1, LED_blink_slow);
157+
setLed(leds_message, LED_S2, LED_blink_slow);
158+
break;
159+
case MowerUiService::HighLevelState::MODE_AUTONOMOUS_UNDOCKING:
160+
setLed(leds_message, LED_S1, LED_blink_slow);
161+
setLed(leds_message, LED_S2, LED_blink_fast);
162+
break;
163+
case MowerUiService::HighLevelState::MODE_RECORDING_OUTLINE:
164+
setLed(leds_message, LED_S1, LED_blink_fast);
165+
setLed(leds_message, LED_S2, LED_blink_slow);
166+
break;
167+
case MowerUiService::HighLevelState::MODE_RECORDING_OBSTACLE:
168+
setLed(leds_message, LED_S1, LED_blink_fast);
169+
setLed(leds_message, LED_S2, LED_blink_fast);
170+
break;
171+
default:
172+
setLed(leds_message, LED_S1, LED_blink_fast);
173+
setLed(leds_message, LED_S2, LED_on);
174+
break;
175+
}
176+
}
177+
178+
// Show Info mower lifted or stop button pressed
179+
if (emergency) {
180+
setLed(leds_message, LED_MOWER_LIFTED, LED_blink_fast);
181+
} else {
182+
setLed(leds_message, LED_MOWER_LIFTED, LED_off);
183+
}
184+
185+
sendUIMessage(&leds_message, sizeof(leds_message));
186+
}
187+
88188
void YardForceCoverUIDriver::ProcessPacket() {
89-
if (buffer_fill == 0) return;
90-
uint16_t size = cobs_.decode((uint8_t *)buffer, buffer_fill - 1, encode_decode_buf_);
189+
if (buffer_fill_ == 0) return;
190+
uint16_t size = COBS::decode(const_cast<uint8_t *>(buffer_), buffer_fill_ - 1, encode_decode_buf_);
91191

92-
u_int16_t *crc_pointer = (uint16_t *)(encode_decode_buf_ + (size - 2));
192+
auto *crc_pointer = reinterpret_cast<uint16_t *>(encode_decode_buf_ + (size - 2));
93193
u_int16_t readcrc = *crc_pointer;
94194

95195
// check structure size
@@ -105,23 +205,22 @@ void YardForceCoverUIDriver::ProcessPacket() {
105205

106206
if (crc != readcrc) return;
107207

108-
/*if (buffer[0] == Get_Version && size == sizeof(struct msg_get_version)) {
109-
struct msg_get_version *msg = (struct msg_get_version *)buffer;
110-
board_found = true;
111-
} else if (buffer[0] == Get_Button && size == sizeof(struct msg_event_button)) {
112-
struct msg_event_button *msg = (struct msg_event_button *)buffer;
113-
114-
} else if (buffer[0] == Get_Emergency && size == sizeof(struct msg_event_emergency)) {
115-
struct msg_event_emergency *msg = (struct msg_event_emergency *)buffer;
116-
stock_ui_emergency_state = msg->state;
117-
} else if (buffer[0] == Get_Rain && size == sizeof(struct msg_event_rain)) {
118-
struct msg_event_rain *msg = (struct msg_event_rain *)buffer;
119-
stock_ui_rain = (msg->value < llhl_config.rain_threshold);
120-
} else if (buffer[0] == Get_Subscribe && size == sizeof(struct msg_event_subscribe)) {
121-
struct msg_event_subscribe *msg = (struct msg_event_subscribe *)buffer;
122-
ui_topic_bitmask = msg->topic_bitmask;
123-
ui_interval = msg->interval;
124-
}*/
208+
if (encode_decode_buf_[0] == Get_Version && size == sizeof(struct msg_get_version)) {
209+
board_found_ = true;
210+
} else if (encode_decode_buf_[0] == Get_Button && size == sizeof(struct msg_event_button)) {
211+
msg_event_button *msg = (struct msg_event_button *)encode_decode_buf_;
212+
mower_ui_service.SendButtonPressedEvent(msg->button_id);
213+
} /* else if (encode_decode_buf_[0] == Get_Emergency && size == sizeof(struct msg_event_emergency)) {
214+
struct msg_event_emergency *msg = (struct msg_event_emergency *)encode_decode_buf_;
215+
stock_ui_emergency_state = msg->state;
216+
} else if (encode_decode_buf_[0] == Get_Rain && size == sizeof(struct msg_event_rain)) {
217+
struct msg_event_rain *msg = (struct msg_event_rain *)encode_decode_buf_;
218+
stock_ui_rain = (msg->value < llhl_config.rain_threshold);
219+
} else if (encode_decode_buf_[0] == Get_Subscribe && size == sizeof(struct msg_event_subscribe)) {
220+
struct msg_event_subscribe *msg = (struct msg_event_subscribe *)encode_decode_buf_;
221+
ui_topic_bitmask = msg->topic_bitmask;
222+
ui_interval = msg->interval;
223+
}*/
125224
}
126225
void YardForceCoverUIDriver::sendUIMessage(void *msg, size_t size) {
127226
// packages need to be at least 1 byte of type, 1 byte of data and 2 bytes of CRC
@@ -137,12 +236,12 @@ void YardForceCoverUIDriver::sendUIMessage(void *msg, size_t size) {
137236
data_pointer[size - 1] = (crc >> 8) & 0xFF;
138237
data_pointer[size - 2] = crc & 0xFF;
139238

140-
if (cobs_.getEncodedBufferSize(size) >= sizeof(encode_decode_buf_)) {
239+
if (COBS::getEncodedBufferSize(size) >= sizeof(encode_decode_buf_)) {
141240
ULOG_ERROR("out_but_ size too small!");
142241
return;
143242
}
144243

145-
size_t encoded_size = cobs_.encode(data_pointer, size, encode_decode_buf_);
244+
size_t encoded_size = COBS::encode(data_pointer, size, encode_decode_buf_);
146245
encode_decode_buf_[encoded_size] = 0;
147246
encoded_size++;
148247
uartSendFullTimeout(uart_, &encoded_size, encode_decode_buf_, TIME_INFINITE);

src/drivers/ui/YardForceCoverUI/yard_force_cover_ui_driver.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
#include <drivers/input/input_driver.hpp>
1111

12-
#include "COBS.h"
1312
#include "ch.h"
1413
#include "hal.h"
1514
#include "ui_board.h"
@@ -27,19 +26,20 @@ class YardForceCoverUIDriver {
2726
UARTConfigEx uart_config_{};
2827
etl::crc16_ccitt CRC16{};
2928

30-
volatile uint8_t buffer[255];
31-
volatile uint8_t buffer_fill = 0;
32-
volatile bool processing = false;
29+
volatile uint8_t buffer_[255];
30+
volatile uint8_t buffer_fill_ = 0;
31+
volatile bool processing_ = false;
3332

34-
bool board_found = false;
33+
bool board_found_ = false;
3534
uint8_t encode_decode_buf_[100]{};
36-
COBS cobs_{};
3735

3836
static void ThreadHelper(void *instance);
3937
static void UartRxChar(UARTDriver *driver, uint16_t data);
4038

4139
void ThreadFunc();
4240

41+
void UpdateUILeds();
42+
4343
void ProcessPacket();
4444

4545
void sendUIMessage(void *msg, size_t size);

src/services/mower_ui_service/mower_ui_service.hpp

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,54 +5,79 @@
55
#ifndef OPENMOWER_MOWER_UI_SERVICE_HPP
66
#define OPENMOWER_MOWER_UI_SERVICE_HPP
77

8+
#include <etl/string.h>
9+
810
#include <MowerUiServiceBase.hpp>
11+
#include <xbot-service/Lock.hpp>
912

1013
#include "globals.hpp"
11-
#include <etl/string.h>
12-
#include <xbot-service/Lock.hpp>
1314

1415
using namespace xbot::service;
1516

17+
#define HL_SUBMODE_SHIFT 6
18+
1619
class MowerUiService : public MowerUiServiceBase {
1720
private:
1821
THD_WORKING_AREA(wa, 1024){};
1922

2023
public:
24+
enum class HighLevelState : uint8_t {
25+
// UNKNOWN (0)
26+
MODE_UNKNOWN = 0,
27+
28+
// IDLE mode (1) and submodes
29+
MODE_IDLE = 1,
30+
31+
// AUTONOMOUS mode (2) and submodes
32+
MODE_AUTONOMOUS = 2,
33+
MODE_AUTONOMOUS_MOWING = (0 << HL_SUBMODE_SHIFT) | MODE_AUTONOMOUS,
34+
MODE_AUTONOMOUS_DOCKING = (1 << HL_SUBMODE_SHIFT) | MODE_AUTONOMOUS,
35+
MODE_AUTONOMOUS_UNDOCKING = (2 << HL_SUBMODE_SHIFT) | MODE_AUTONOMOUS,
36+
37+
// RECORDING mode (3) and submodes
38+
MODE_RECORDING = 3,
39+
MODE_RECORDING_OUTLINE = (1 << HL_SUBMODE_SHIFT) | MODE_RECORDING,
40+
MODE_RECORDING_OBSTACLE = (2 << HL_SUBMODE_SHIFT) | MODE_RECORDING,
41+
};
42+
2143
explicit MowerUiService(uint16_t service_id) : MowerUiServiceBase(service_id, wa, sizeof(wa)) {
2244
}
23-
24-
[[nodiscard]] HighLevelStatus getStateId() {
45+
46+
[[nodiscard]] HighLevelState GetHighLevelState() {
2547
xbot::service::Lock lk{&mtx_};
26-
return state_id_;
48+
return static_cast<HighLevelState>(state_id_);
2749
}
28-
[[nodiscard]] etl::string<100> getStateName() {
50+
[[nodiscard]] etl::string<100> GetStateName() {
2951
xbot::service::Lock lk{&mtx_};
3052
return state_name_;
3153
}
32-
[[nodiscard]] etl::string<100> getSubStateName() {
54+
[[nodiscard]] etl::string<100> GetSubStateName() {
3355
xbot::service::Lock lk{&mtx_};
3456
return sub_state_name_;
3557
}
36-
[[nodiscard]] float getGpsQuality() {
58+
[[nodiscard]] float GetGpsQuality() {
3759
xbot::service::Lock lk{&mtx_};
3860
return gps_quality_;
3961
}
40-
[[nodiscard]] int16_t getCurrentArea() {
62+
[[nodiscard]] int16_t GetCurrentArea() {
4163
xbot::service::Lock lk{&mtx_};
4264
return current_area_;
4365
}
44-
[[nodiscard]] int16_t getCurrentPath() {
66+
[[nodiscard]] int16_t GetCurrentPath() {
4567
xbot::service::Lock lk{&mtx_};
4668
return current_path_;
4769
}
48-
[[nodiscard]] int16_t getCurrentPathIndex() {
70+
[[nodiscard]] int16_t GetCurrentPathIndex() {
4971
xbot::service::Lock lk{&mtx_};
5072
return current_path_index_;
5173
}
5274

53-
void SendAction(HighLevelAction action);
75+
void SendButtonPressedEvent(uint8_t button_id) {
76+
xbot::service::Lock lk{&mtx_};
77+
MowerUiServiceBase::SendButtonPressedEvent(button_id);
78+
}
5479

55-
void SetCallback(const etl::delegate<void()> &callback) {
80+
void SetCallback(const etl::delegate<void()>& callback) {
5681
xbot::service::Lock lk{&mtx_};
5782
state_changed_callback_ = callback;
5883
}

0 commit comments

Comments
 (0)