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
1316static 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+
88188void 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}
126225void 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);
0 commit comments