124 proto::lacte::LacteHostProtocol<host_rx_buffer, host_tx_buffer>
m_host_proto;
139 : m_log_sink_(std::move(log_sink)) {}
142 std::unique_lock lock(m_worker_mtx_);
144 if (
const auto aeration_packet =
145 m_host_proto.get_param<proto::lacte::Params::AERATION>()) {
146 return aeration_packet.value().m_data;
152 proto::lacte::AerationParam packet;
153 packet.m_data = aeration;
154 std::unique_lock lock(m_worker_mtx_);
156 return m_host_proto.set_param<proto::lacte::Params::AERATION>(packet);
159 auto flash(
const std::string& path) ->
bool {
160 std::unique_lock lock(m_worker_mtx_);
163 if (info.value().m_status == proto::lacte::BoardStatus::WORK ||
164 info.value().m_status == proto::lacte::BoardStatus::CALIBRATION) {
166 "Device has status WORK or CALIBRATION. It's denied to update");
169 log(LogLevel::INFO,
"Device status is ", info.value().m_status);
171 log(LogLevel::INFO,
"Trying to reset board");
172 if (
const auto answer =
m_host_proto.restart(); not answer) {
173 log(LogLevel::WARNING,
174 "Failed to execute RESTART command; the device may already "
175 "be in bootloader mode.");
176 }
else if (answer.value().m_data == proto::lacte::BootAnswer::NO) {
178 "Device returned denied on RESTART command; aborting "
183 log(LogLevel::INFO,
"Starting firmware update: ", path);
184 return proto::lacte::LacteHostProtocol<
187 *m_flash_interface_);
193 proto::interface::IInterface& tx_interface) ->
bool {
194 m_host_proto.set_interfaces(rx_interface, tx_interface);
195 m_flash_interface_ = &tx_interface;
205 m_flash_interface_ = &tx_interface;
209 std::unique_lock lock(m_worker_mtx_);
211 log(LogLevel::WARNING,
"model lacte is running. Please call stop firs!");
216 m_thread_worker_ = std::thread(&BoardModel::worker,
this);
220 if (
bool expected =
true;
221 !m_running_.compare_exchange_strong(expected,
false)) {
225 if (m_thread_worker_.joinable()) {
226 log(LogLevel::INFO,
"Waiting for lacte model thread to finish...");
227 m_thread_worker_.join();
236 m_online_timeout_ = timeout;
240 return std::chrono::system_clock::now() - m_last_update_time_ <
249 [[nodiscard]]
auto is_running() const ->
bool {
return m_running_.load(); }
263 m_on_update_ = std::move(callback);
267 std::thread m_thread_worker_;
268 std::atomic<bool> m_running_{
false};
269 std::mutex m_worker_mtx_;
270 proto::interface::IInterface* m_flash_interface_{};
271 std::chrono::time_point<std::chrono::system_clock> m_last_update_time_;
280 bool m_reported_online_{
false};
281 std::function<void(
const BoardData&)> m_on_update_;
288 std::shared_ptr<ILogger> m_log_sink_;
290 template <
typename... Args>
291 void log(LogLevel level, Args&&... args)
const {
292 m_log_sink_->log(level, std::forward<Args>(args)...);
303 auto update_params(
const proto::lacte::InfoPacketType& info) ->
BoardData {
304 using namespace proto::lacte;
307 auto set_field = [&reading](
auto value) ->
void {
308 std::get<std::optional<
decltype(value)>>(reading) = std::move(value);
311 auto try_to_get = [&](
auto&& func) ->
decltype(func()) {
313 auto result = func();
332 const auto hard_version =
333 try_to_get([&]() ->
auto {
return m_host_proto.get_version(); });
335 try_to_get([&]() ->
auto {
return m_host_proto.get_uid(); });
336 const auto aeration = try_to_get(
337 [&]() ->
auto {
return m_host_proto.get_param<Params::AERATION>(); });
340 std::optional<RFIDDataPacketType> rfid_data;
341 std::optional<RFIDNumberType> rfid_num_new;
342 if (not(info.m_errors.has(BoardError::RFID_NO_CARD) and
343 info.m_errors.has(BoardError::RFID_BAD_CARD)) and
344 info.m_status != BoardStatus::CALIBRATION) {
346 try_to_get([&]() ->
auto {
return m_host_proto.get_rfid_data(); });
348 try_to_get([&]() ->
auto {
return m_host_proto.get_rfid(); });
352 set_field(BoardErrorDiff{info.m_errors});
354 set_field(BoardOnlineStatus{
"online"});
355 set_field(SoftVersion{SOFTWARE_VERSION});
358 set_field(*hard_version);
364 set_field(*aeration);
367 if (rfid_num_new and rfid_num_new.value().to_string() !=
"0" and
368 rfid_data and rfid_data->m_magicWord.m_data == MagicWord::DEFAULT_VAL) {
369 set_field(*rfid_num_new);
370 set_field(rfid_data->m_magicWord);
371 set_field(rfid_data->m_lacteId);
372 set_field(rfid_data->m_lacteSn);
373 set_field(rfid_data->m_productVolume);
374 set_field(rfid_data->m_prodDate);
375 set_field(rfid_data->m_shelfLife);
376 set_field(rfid_data->m_usageTime);
377 set_field(rfid_data->m_mcuUid);
378 set_field(rfid_data->m_machineSn);
379 set_field(rfid_data->m_activationTime);
380 set_field(rfid_data->m_milkCounter);
381 set_field(rfid_data->m_timeCounter);
382 }
else if (rfid_num_new and rfid_num_new.value().to_string() ==
"0") {
400 set_field(*rfid_num_new);
413 log(LogLevel::INFO,
"lacte model started ");
416 std::unique_lock lock(m_worker_mtx_);
418 m_last_update_time_ = std::chrono::system_clock::now();
419 m_reported_online_ =
true;
420 if (
const auto reading = update_params(*info); m_on_update_) {
421 m_on_update_(reading);
423 }
else if (not
is_online() and m_reported_online_) {
428 m_reported_online_ =
false;
429 log(LogLevel::WARNING,
430 "lacte board was disconnected or there is some "
431 "communication issue!");
434 std::get<std::optional<BoardOnlineStatus>>(reading) =
435 BoardOnlineStatus{
"false"};
436 m_on_update_(reading);
440 log(LogLevel::INFO,
"lacte model stopped ");