Implement Serial Console app & more (#239)
- Implemented new app: Serial Console - `Uart::writeString()`: fixed 2 mutex bugs - `AlertDialog::start()` with default "OK" button added - Created `tt::lvgl::defaultLockTime` for re-use - Removed various usages of deprecated `lvgl::obj_set_style_no_padding()` - Implemented `hal::uart::getNames()` to list all interface names
This commit is contained in:
parent
83a82be901
commit
13d7e84ef3
@ -33,6 +33,9 @@
|
||||
- Scanning SD card for external apps and auto-register them (in a temporary register?)
|
||||
- Support hot-plugging SD card
|
||||
- All drivers (e.g. display, touch, etc.) should call stop() in their destructor, or at least assert that they should not be running.
|
||||
- Use GPS time to set/update the current time
|
||||
- Investigate EEZ Studio
|
||||
- Remove flex_flow from app_container in Gui.cpp
|
||||
|
||||
# Nice-to-haves
|
||||
- Give external app a different icon. Allow an external app update their id, icon, type and name once they are running(and persist that info?). Loader will need to be able to find app by (external) location.
|
||||
@ -66,3 +69,7 @@
|
||||
- GPS app
|
||||
- Investigate CSI https://stevenmhernandez.github.io/ESP32-CSI-Tool/
|
||||
- Compile unix tools to ELF apps?
|
||||
- Calculator
|
||||
- Text editor
|
||||
- Todo list
|
||||
- Calendar
|
||||
|
||||
@ -21,6 +21,13 @@ namespace tt::app::alertdialog {
|
||||
*/
|
||||
void start(const std::string& title, const std::string& message, const std::vector<std::string>& buttonLabels);
|
||||
|
||||
/**
|
||||
* Show a dialog with the provided title, message and an OK button
|
||||
* @param[in] title the title to show in the toolbar
|
||||
* @param[in] message the message to display
|
||||
*/
|
||||
void start(const std::string& title, const std::string& message);
|
||||
|
||||
/**
|
||||
* Get the index of the button that the user selected.
|
||||
*
|
||||
|
||||
143
Tactility/Include/Tactility/app/serialconsole/ConnectView.h
Normal file
143
Tactility/Include/Tactility/app/serialconsole/ConnectView.h
Normal file
@ -0,0 +1,143 @@
|
||||
#pragma once
|
||||
|
||||
#include "./View.h"
|
||||
|
||||
#include "Tactility/Preferences.h"
|
||||
#include "Tactility/Tactility.h"
|
||||
#include "Tactility/app/alertdialog/AlertDialog.h"
|
||||
#include "Tactility/hal/uart/Uart.h"
|
||||
#include "Tactility/lvgl/LvglSync.h"
|
||||
#include "Tactility/lvgl/Style.h"
|
||||
#include "Tactility/service/gui/Gui.h"
|
||||
|
||||
#include <Tactility/StringUtils.h>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace tt::app::serialconsole {
|
||||
|
||||
class ConnectView final : public View {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::function<void(std::unique_ptr<hal::uart::Uart>)> OnConnectedFunction;
|
||||
std::vector<std::string> uartNames;
|
||||
Preferences preferences = Preferences("SerialConsole");
|
||||
|
||||
private:
|
||||
|
||||
OnConnectedFunction onConnected;
|
||||
lv_obj_t* busDropdown = nullptr;
|
||||
lv_obj_t* speedTextarea = nullptr;
|
||||
|
||||
int32_t getSpeedInput() const {
|
||||
auto* speed_text = lv_textarea_get_text(speedTextarea);
|
||||
return std::stoi(speed_text);
|
||||
}
|
||||
|
||||
void onConnect() {
|
||||
auto lock = lvgl::getSyncLock()->asScopedLock();
|
||||
if (!lock.lock(lvgl::defaultLockTime)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto selected_uart_index = lv_dropdown_get_selected(busDropdown);
|
||||
if (selected_uart_index >= uartNames.size()) {
|
||||
alertdialog::start("Error", "No UART selected");
|
||||
return;
|
||||
}
|
||||
|
||||
auto uart_name = uartNames[selected_uart_index];
|
||||
auto uart = hal::uart::open(uart_name);
|
||||
if (uart == nullptr) {
|
||||
alertdialog::start("Error", "Failed to connect to UART");
|
||||
return;
|
||||
}
|
||||
|
||||
int speed = getSpeedInput();
|
||||
if (speed <= 0) {
|
||||
alertdialog::start("Error", "Invalid speed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uart->start()) {
|
||||
alertdialog::start("Error", "Failed to initialize");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uart->setBaudRate(speed)) {
|
||||
uart->stop();
|
||||
alertdialog::start("Error", "Failed to set baud rate");
|
||||
return;
|
||||
}
|
||||
|
||||
onConnected(std::move(uart));
|
||||
}
|
||||
|
||||
static void onConnectCallback(lv_event_t* event) {
|
||||
auto* view = (ConnectView*)lv_event_get_user_data(event);
|
||||
view->onConnect();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit ConnectView(OnConnectedFunction onConnected) : onConnected(std::move(onConnected)) {}
|
||||
|
||||
void onStart(lv_obj_t* parent) {
|
||||
uartNames = hal::uart::getNames();
|
||||
|
||||
auto* wrapper = lv_obj_create(parent);
|
||||
lv_obj_set_size(wrapper, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_style_pad_ver(wrapper, 0, 0);
|
||||
lv_obj_set_style_border_width(wrapper, 0, 0);
|
||||
lvgl::obj_set_style_bg_invisible(wrapper);
|
||||
|
||||
busDropdown = lv_dropdown_create(wrapper);
|
||||
|
||||
auto bus_options = string::join(uartNames, "\n");
|
||||
lv_dropdown_set_options(busDropdown, bus_options.c_str());
|
||||
lv_obj_align(busDropdown, LV_ALIGN_TOP_RIGHT, 0, 0);
|
||||
lv_obj_set_width(busDropdown, LV_PCT(50));
|
||||
int32_t bus_index = 0;
|
||||
preferences.optInt32("bus", bus_index);
|
||||
if (bus_index < uartNames.size()) {
|
||||
lv_dropdown_set_selected(busDropdown, bus_index);
|
||||
}
|
||||
|
||||
auto* bus_label = lv_label_create(wrapper);
|
||||
lv_obj_align(bus_label, LV_ALIGN_TOP_LEFT, 0, 10);
|
||||
lv_label_set_text(bus_label, "Bus");
|
||||
|
||||
int32_t speed = 115200;
|
||||
preferences.optInt32("speed", speed);
|
||||
speedTextarea = lv_textarea_create(wrapper);
|
||||
lv_textarea_set_text(speedTextarea, std::to_string(speed).c_str());
|
||||
lv_textarea_set_one_line(speedTextarea, true);
|
||||
lv_obj_set_width(speedTextarea, LV_PCT(50));
|
||||
lv_obj_align(speedTextarea, LV_ALIGN_TOP_RIGHT, 0, 40);
|
||||
service::gui::keyboardAddTextArea(speedTextarea);
|
||||
|
||||
auto* baud_rate_label = lv_label_create(wrapper);
|
||||
lv_obj_align(baud_rate_label, LV_ALIGN_TOP_LEFT, 0, 50);
|
||||
lv_label_set_text(baud_rate_label, "Baud");
|
||||
|
||||
auto* connect_button = lv_button_create(wrapper);
|
||||
auto* connect_label = lv_label_create(connect_button);
|
||||
lv_label_set_text(connect_label, "Connect");
|
||||
lv_obj_align(connect_button, LV_ALIGN_TOP_MID, 0, 90);
|
||||
lv_obj_add_event_cb(connect_button, onConnectCallback, LV_EVENT_SHORT_CLICKED, this);
|
||||
}
|
||||
|
||||
void onStop() final {
|
||||
int speed = getSpeedInput();
|
||||
if (speed > 0) {
|
||||
preferences.putInt32("speed", speed);
|
||||
}
|
||||
|
||||
auto bus_index = (int32_t)lv_dropdown_get_selected(busDropdown);
|
||||
preferences.putInt32("bus", bus_index);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace tt::app::serialconsole
|
||||
296
Tactility/Include/Tactility/app/serialconsole/ConsoleView.h
Normal file
296
Tactility/Include/Tactility/app/serialconsole/ConsoleView.h
Normal file
@ -0,0 +1,296 @@
|
||||
#pragma once
|
||||
|
||||
#include "./View.h"
|
||||
#include "Tactility/Timer.h"
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
#define TAG "SerialConsole"
|
||||
|
||||
namespace tt::app::serialconsole {
|
||||
|
||||
constexpr size_t receiveBufferSize = 512;
|
||||
constexpr size_t renderBufferSize = receiveBufferSize + 2; // Leave space for newline at split and null terminator at the end
|
||||
|
||||
class ConsoleView final : public View {
|
||||
|
||||
private:
|
||||
|
||||
lv_obj_t* _Nullable parent = nullptr;
|
||||
lv_obj_t* _Nullable logTextarea = nullptr;
|
||||
lv_obj_t* _Nullable inputTextarea = nullptr;
|
||||
std::unique_ptr<hal::uart::Uart> _Nullable uart = nullptr;
|
||||
std::shared_ptr<Thread> uartThread _Nullable = nullptr;
|
||||
bool uartThreadInterrupted = false;
|
||||
std::shared_ptr<Thread> viewThread _Nullable = nullptr;
|
||||
bool viewThreadInterrupted = false;
|
||||
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
||||
uint8_t receiveBuffer[receiveBufferSize];
|
||||
uint8_t renderBuffer[renderBufferSize];
|
||||
size_t receiveBufferPosition = 0;
|
||||
std::string terminatorString = "\n";
|
||||
|
||||
bool isUartThreadInterrupted() const {
|
||||
auto lock = mutex.asScopedLock();
|
||||
lock.lock();
|
||||
return uartThreadInterrupted;
|
||||
}
|
||||
|
||||
bool isViewThreadInterrupted() const {
|
||||
auto lock = mutex.asScopedLock();
|
||||
lock.lock();
|
||||
return viewThreadInterrupted;
|
||||
}
|
||||
|
||||
void updateViews() {
|
||||
auto lvgl_lock = lvgl::getSyncLock()->asScopedLock();
|
||||
if (!lvgl_lock.lock(lvgl::defaultLockTime)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Updating the view is expensive, so we only want to set the text once:
|
||||
// Gather all the lines in a single buffer
|
||||
if (mutex.lock()) {
|
||||
size_t first_part_size = receiveBufferSize - receiveBufferPosition;
|
||||
memcpy(renderBuffer, receiveBuffer + receiveBufferPosition, first_part_size);
|
||||
renderBuffer[receiveBufferPosition] = '\n';
|
||||
if (receiveBufferPosition > 0) {
|
||||
memcpy(renderBuffer + first_part_size + 1, receiveBuffer, (receiveBufferSize - first_part_size));
|
||||
renderBuffer[receiveBufferSize - 1] = 0x00;
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
if (lvgl::lock(lvgl::defaultLockTime)) {
|
||||
lv_textarea_set_text(logTextarea, (const char*)renderBuffer);
|
||||
lvgl::unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t viewThreadMain() {
|
||||
while (!isViewThreadInterrupted()) {
|
||||
auto start_time = kernel::getTicks();
|
||||
|
||||
updateViews();
|
||||
|
||||
auto end_time = kernel::getTicks();
|
||||
auto time_diff = end_time - start_time;
|
||||
if (time_diff < 500U) {
|
||||
kernel::delayTicks((500U - time_diff) / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t uartThreadMain() {
|
||||
uint8_t byte;
|
||||
|
||||
while (!isUartThreadInterrupted()) {
|
||||
assert(uart != nullptr);
|
||||
bool success = uart->readByte(&byte, 50 / portTICK_PERIOD_MS);
|
||||
|
||||
// Thread might've been interrupted in the meanwhile
|
||||
if (isUartThreadInterrupted()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
mutex.lock();
|
||||
receiveBuffer[receiveBufferPosition++] = byte;
|
||||
if (receiveBufferPosition == receiveBufferSize) {
|
||||
receiveBufferPosition = 0;
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t viewThreadMainStatic(void* parameter) {
|
||||
auto* view = (ConsoleView*)parameter;
|
||||
return view->viewThreadMain();
|
||||
}
|
||||
|
||||
static int32_t uartThreadMainStatic(void* parameter) {
|
||||
auto* view = (ConsoleView*)parameter;
|
||||
return view->uartThreadMain();
|
||||
}
|
||||
|
||||
static void onSendClickedCallback(lv_event_t* event) {
|
||||
auto* view = (ConsoleView*)lv_event_get_user_data(event);
|
||||
view->onSendClicked();
|
||||
}
|
||||
|
||||
static void onTerminatorDropdownValueChangedCallback(lv_event_t* event) {
|
||||
auto* view = (ConsoleView*)lv_event_get_user_data(event);
|
||||
view->onTerminatorDropDownValueChanged(event);
|
||||
}
|
||||
|
||||
void onTerminatorDropDownValueChanged(lv_event_t* event) {
|
||||
auto* dropdown = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||
mutex.lock();
|
||||
switch (lv_dropdown_get_selected(dropdown)) {
|
||||
case 0:
|
||||
terminatorString = "\n";
|
||||
break;
|
||||
case 1:
|
||||
terminatorString = "\r\n";
|
||||
break;
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void onSendClicked() {
|
||||
mutex.lock();
|
||||
std::string input_text = lv_textarea_get_text(inputTextarea);
|
||||
std::string to_send = input_text + terminatorString;
|
||||
mutex.unlock();
|
||||
|
||||
auto* safe_uart = uart.get();
|
||||
if (safe_uart != nullptr) {
|
||||
if (!safe_uart->writeString(to_send.c_str(), 100 / portTICK_PERIOD_MS)) {
|
||||
TT_LOG_E(TAG, "Failed to send \"%s\"", input_text.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
lv_textarea_set_text(inputTextarea, "");
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void startLogic(std::unique_ptr<hal::uart::Uart> newUart) {
|
||||
memset(receiveBuffer, 0, receiveBufferSize);
|
||||
|
||||
assert(uartThread == nullptr);
|
||||
assert(uart == nullptr);
|
||||
|
||||
uart = std::move(newUart);
|
||||
|
||||
uartThreadInterrupted = false;
|
||||
uartThread = std::make_unique<Thread>(
|
||||
"SerConsUart",
|
||||
4096,
|
||||
uartThreadMainStatic,
|
||||
this
|
||||
);
|
||||
uartThread->setPriority(tt::Thread::Priority::High);
|
||||
uartThread->start();
|
||||
}
|
||||
|
||||
void startViews(lv_obj_t* parent) {
|
||||
this->parent = parent;
|
||||
|
||||
lv_obj_set_style_pad_gap(parent, 2, 0);
|
||||
|
||||
logTextarea = lv_textarea_create(parent);
|
||||
lv_textarea_set_placeholder_text(logTextarea, "Waiting for data...");
|
||||
lv_obj_set_flex_grow(logTextarea, 1);
|
||||
lv_obj_set_width(logTextarea, LV_PCT(100));
|
||||
lv_obj_add_state(logTextarea, LV_STATE_DISABLED);
|
||||
lv_obj_set_style_margin_ver(logTextarea, 0, 0);
|
||||
service::gui::keyboardAddTextArea(logTextarea);
|
||||
|
||||
auto* input_wrapper = lv_obj_create(parent);
|
||||
lv_obj_set_size(input_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_all(input_wrapper, 0, 0);
|
||||
lv_obj_set_style_border_width(input_wrapper, 0, 0);
|
||||
lv_obj_set_width(input_wrapper, LV_PCT(100));
|
||||
lv_obj_set_flex_flow(input_wrapper, LV_FLEX_FLOW_ROW);
|
||||
|
||||
inputTextarea = lv_textarea_create(input_wrapper);
|
||||
lv_textarea_set_one_line(inputTextarea, true);
|
||||
lv_textarea_set_placeholder_text(inputTextarea, "Text to send");
|
||||
lv_obj_set_width(inputTextarea, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(inputTextarea, 1);
|
||||
service::gui::keyboardAddTextArea(inputTextarea);
|
||||
|
||||
auto* terminator_dropdown = lv_dropdown_create(input_wrapper);
|
||||
lv_dropdown_set_options(terminator_dropdown, "\\n\n\\r\\n");
|
||||
lv_obj_set_width(terminator_dropdown, 70);
|
||||
lv_obj_add_event_cb(terminator_dropdown, onTerminatorDropdownValueChangedCallback, LV_EVENT_VALUE_CHANGED, this);
|
||||
|
||||
|
||||
auto* button = lv_button_create(input_wrapper);
|
||||
auto* button_label = lv_label_create(button);
|
||||
lv_label_set_text(button_label, "Send");
|
||||
lv_obj_add_event_cb(button, onSendClickedCallback, LV_EVENT_SHORT_CLICKED, this);
|
||||
|
||||
viewThreadInterrupted = false;
|
||||
viewThread = std::make_unique<Thread>(
|
||||
"SerConsView",
|
||||
4096,
|
||||
viewThreadMainStatic,
|
||||
this
|
||||
);
|
||||
viewThread->setPriority(THREAD_PRIORITY_RENDER);
|
||||
viewThread->start();
|
||||
}
|
||||
|
||||
void stopLogic() {
|
||||
auto lock = mutex.asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
uartThreadInterrupted = true;
|
||||
|
||||
// Detach thread, it will auto-delete when leaving the current scope
|
||||
auto old_uart_thread = std::move(uartThread);
|
||||
// Unlock so thread can lock
|
||||
lock.unlock();
|
||||
|
||||
if (old_uart_thread->getState() != Thread::State::Stopped) {
|
||||
// Wait for thread to finish
|
||||
old_uart_thread->join();
|
||||
}
|
||||
}
|
||||
|
||||
void stopViews() {
|
||||
auto lock = mutex.asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
viewThreadInterrupted = true;
|
||||
|
||||
// Detach thread, it will auto-delete when leaving the current scope
|
||||
auto old_view_thread = std::move(viewThread);
|
||||
|
||||
// Unlock so thread can lock
|
||||
lock.unlock();
|
||||
|
||||
if (old_view_thread->getState() != Thread::State::Stopped) {
|
||||
// Wait for thread to finish
|
||||
old_view_thread->join();
|
||||
}
|
||||
}
|
||||
|
||||
void stopUart() {
|
||||
auto lock = mutex.asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
if (uart != nullptr && uart->isStarted()) {
|
||||
uart->stop();
|
||||
uart = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void onStart(lv_obj_t* parent, std::unique_ptr<hal::uart::Uart> newUart) {
|
||||
auto lock = mutex.asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
startLogic(std::move(newUart));
|
||||
startViews(parent);
|
||||
}
|
||||
|
||||
void onStop() final {
|
||||
stopViews();
|
||||
stopLogic();
|
||||
stopUart();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace tt::app::serialconsole
|
||||
12
Tactility/Include/Tactility/app/serialconsole/View.h
Normal file
12
Tactility/Include/Tactility/app/serialconsole/View.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <lvgl.h>
|
||||
|
||||
namespace tt::app::serialconsole {
|
||||
|
||||
class View {
|
||||
public:
|
||||
virtual void onStop() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@ -6,6 +6,8 @@
|
||||
|
||||
namespace tt::lvgl {
|
||||
|
||||
constexpr TickType_t defaultLockTime = 500 / portTICK_PERIOD_MS;
|
||||
|
||||
/**
|
||||
* LVGL locking function
|
||||
* @param[in] timeoutMillis timeout in milliseconds. waits forever when 0 is passed.
|
||||
|
||||
@ -45,6 +45,7 @@ namespace app {
|
||||
namespace log { extern const AppManifest manifest; }
|
||||
namespace power { extern const AppManifest manifest; }
|
||||
namespace selectiondialog { extern const AppManifest manifest; }
|
||||
namespace serialconsole { extern const AppManifest manifest; }
|
||||
namespace settings { extern const AppManifest manifest; }
|
||||
namespace systeminfo { extern const AppManifest manifest; }
|
||||
namespace textviewer { extern const AppManifest manifest; }
|
||||
@ -80,6 +81,7 @@ static void registerSystemApps() {
|
||||
addApp(app::inputdialog::manifest);
|
||||
addApp(app::launcher::manifest);
|
||||
addApp(app::log::manifest);
|
||||
addApp(app::serialconsole::manifest);
|
||||
addApp(app::settings::manifest);
|
||||
addApp(app::selectiondialog::manifest);
|
||||
addApp(app::systeminfo::manifest);
|
||||
|
||||
@ -31,6 +31,14 @@ void start(const std::string& title, const std::string& message, const std::vect
|
||||
service::loader::startApp(manifest.id, bundle);
|
||||
}
|
||||
|
||||
void start(const std::string& title, const std::string& message) {
|
||||
auto bundle = std::make_shared<Bundle>();
|
||||
bundle->putString(PARAMETER_BUNDLE_KEY_TITLE, title);
|
||||
bundle->putString(PARAMETER_BUNDLE_KEY_MESSAGE, message);
|
||||
bundle->putString(PARAMETER_BUNDLE_KEY_BUTTON_LABELS, "OK");
|
||||
service::loader::startApp(manifest.id, bundle);
|
||||
}
|
||||
|
||||
int32_t getResultIndex(const Bundle& bundle) {
|
||||
int32_t index = -1;
|
||||
bundle.optInt32(RESULT_BUNDLE_KEY_INDEX, index);
|
||||
@ -76,6 +84,7 @@ private:
|
||||
lv_label_set_text(button_label, text.c_str());
|
||||
lv_obj_add_event_cb(button, onButtonClickedCallback, LV_EVENT_SHORT_CLICKED, (void*)index);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void onShow(AppContext& app, lv_obj_t* parent) override {
|
||||
@ -89,6 +98,7 @@ public:
|
||||
lv_obj_t* message_label = lv_label_create(parent);
|
||||
lv_obj_align(message_label, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_set_width(message_label, LV_PCT(80));
|
||||
lv_obj_set_style_text_align(message_label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
|
||||
std::string message;
|
||||
if (parameters->optString(PARAMETER_BUNDLE_KEY_MESSAGE, message)) {
|
||||
@ -107,21 +117,9 @@ public:
|
||||
std::string items_concatenated;
|
||||
if (parameters->optString(PARAMETER_BUNDLE_KEY_BUTTON_LABELS, items_concatenated)) {
|
||||
std::vector<std::string> labels = string::split(items_concatenated, PARAMETER_ITEM_CONCATENATION_TOKEN);
|
||||
if (labels.empty() || labels.front().empty()) {
|
||||
TT_LOG_E(TAG, "No items provided");
|
||||
setResult(Result::Error);
|
||||
service::loader::stopApp();
|
||||
} else if (labels.size() == 1) {
|
||||
auto result_bundle = std::make_unique<Bundle>();
|
||||
result_bundle->putInt32(RESULT_BUNDLE_KEY_INDEX, 0);
|
||||
setResult(Result::Ok, std::move(result_bundle));
|
||||
service::loader::stopApp();
|
||||
TT_LOG_W(TAG, "Auto-selecting single item");
|
||||
} else {
|
||||
size_t index = 0;
|
||||
for (const auto& label: labels) {
|
||||
createButton(button_wrapper, label, index++);
|
||||
}
|
||||
size_t index = 0;
|
||||
for (const auto& label: labels) {
|
||||
createButton(button_wrapper, label, index++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
96
Tactility/Source/app/serialconsole/SerialConsole.cpp
Normal file
96
Tactility/Source/app/serialconsole/SerialConsole.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
#include "Tactility/app/serialconsole/ConnectView.h"
|
||||
#include "Tactility/app/serialconsole/ConsoleView.h"
|
||||
|
||||
#include "Tactility/lvgl/LvglSync.h"
|
||||
#include "Tactility/lvgl/Style.h"
|
||||
#include "Tactility/lvgl/Toolbar.h"
|
||||
#include "Tactility/service/loader/Loader.h"
|
||||
|
||||
#include <Tactility/hal/uart/Uart.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "text_viewer"
|
||||
|
||||
namespace tt::app::serialconsole {
|
||||
|
||||
class SerialConsoleApp final : public App {
|
||||
|
||||
private:
|
||||
|
||||
lv_obj_t* disconnectButton = nullptr;
|
||||
lv_obj_t* wrapperWidget = nullptr;
|
||||
ConnectView connectView = ConnectView([this](auto uart){
|
||||
showConsoleView(std::move(uart));
|
||||
});
|
||||
ConsoleView consoleView;
|
||||
View* activeView = nullptr;
|
||||
|
||||
void stopActiveView() {
|
||||
if (activeView != nullptr) {
|
||||
activeView->onStop();
|
||||
lv_obj_clean(wrapperWidget);
|
||||
activeView = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void showConsoleView(std::unique_ptr<hal::uart::Uart> uart) {
|
||||
stopActiveView();
|
||||
activeView = &consoleView;
|
||||
consoleView.onStart(wrapperWidget, std::move(uart));
|
||||
lv_obj_remove_flag(disconnectButton, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
void showConnectView() {
|
||||
stopActiveView();
|
||||
activeView = &connectView;
|
||||
connectView.onStart(wrapperWidget);
|
||||
lv_obj_add_flag(disconnectButton, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
void onDisconnect() {
|
||||
// Changing views (calling ConsoleView::stop()) also disconnects the UART
|
||||
showConnectView();
|
||||
}
|
||||
|
||||
static void onDisconnectPressed(lv_event_t* event) {
|
||||
auto* app = (SerialConsoleApp*)lv_event_get_user_data(event);
|
||||
app->onDisconnect();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
SerialConsoleApp() = default;
|
||||
|
||||
void onShow(AppContext& app, lv_obj_t* parent) final {
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
auto* toolbar = lvgl::toolbar_create(parent, app);
|
||||
|
||||
disconnectButton = lvgl::toolbar_add_button_action(toolbar, LV_SYMBOL_POWER, onDisconnectPressed, this);
|
||||
lv_obj_add_flag(disconnectButton, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
wrapperWidget = lv_obj_create(parent);
|
||||
lv_obj_set_width(wrapperWidget, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(wrapperWidget, 1);
|
||||
lv_obj_set_flex_flow(wrapperWidget, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_all(wrapperWidget, 0, 0);
|
||||
lv_obj_set_style_border_width(wrapperWidget, 0, 0);
|
||||
lvgl::obj_set_style_bg_invisible(wrapperWidget);
|
||||
|
||||
showConnectView();
|
||||
}
|
||||
|
||||
void onHide(AppContext& app) final {
|
||||
stopActiveView();
|
||||
}
|
||||
};
|
||||
|
||||
extern const AppManifest manifest = {
|
||||
.id = "SerialConsole",
|
||||
.name = "Serial Console",
|
||||
.icon = LV_SYMBOL_LIST,
|
||||
.type = Type::System,
|
||||
.createApp = create<SerialConsoleApp>
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@ -53,13 +53,16 @@ lv_obj_t* toolbar_create(lv_obj_t* parent, const std::string& title) {
|
||||
|
||||
auto* toolbar = (Toolbar*)obj;
|
||||
|
||||
obj_set_style_no_padding(obj);
|
||||
lv_obj_set_style_pad_all(obj, 0, 0);
|
||||
lv_obj_set_style_pad_gap(obj, 0, 0);
|
||||
|
||||
lv_obj_center(obj);
|
||||
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
|
||||
|
||||
toolbar->close_button = lv_button_create(obj);
|
||||
lv_obj_set_size(toolbar->close_button, TOOLBAR_HEIGHT - 4, TOOLBAR_HEIGHT - 4);
|
||||
obj_set_style_no_padding(toolbar->close_button);
|
||||
lv_obj_set_style_pad_all(toolbar->close_button, 0, 0);
|
||||
lv_obj_set_style_pad_gap(toolbar->close_button, 0, 0);
|
||||
toolbar->close_button_image = lv_image_create(toolbar->close_button);
|
||||
lv_obj_align(toolbar->close_button_image, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
|
||||
@ -47,13 +47,14 @@ Gui* gui_alloc() {
|
||||
lv_obj_t* vertical_container = lv_obj_create(screen_root);
|
||||
lv_obj_set_size(vertical_container, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_flex_flow(vertical_container, LV_FLEX_FLOW_COLUMN);
|
||||
lvgl::obj_set_style_no_padding(vertical_container);
|
||||
lv_obj_set_style_pad_all(vertical_container, 0, 0);
|
||||
lv_obj_set_style_pad_gap(vertical_container, 0, 0);
|
||||
lvgl::obj_set_style_bg_blacken(vertical_container);
|
||||
|
||||
instance->statusbarWidget = lvgl::statusbar_create(vertical_container);
|
||||
|
||||
auto* app_container = lv_obj_create(vertical_container);
|
||||
lvgl::obj_set_style_no_padding(app_container);
|
||||
lv_obj_set_style_pad_all(app_container, 0, 0);
|
||||
lv_obj_set_style_border_width(app_container, 0, 0);
|
||||
lvgl::obj_set_style_bg_blacken(app_container);
|
||||
lv_obj_set_width(app_container, LV_PCT(100));
|
||||
|
||||
@ -58,14 +58,10 @@ std::basic_string<T> lowercase(const std::basic_string<T>& input) {
|
||||
return std::move(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true when input only has hex characters: [a-z], [A-Z], [0-9]
|
||||
*/
|
||||
/** @return true when input only has hex characters: [a-z], [A-Z], [0-9] */
|
||||
bool isAsciiHexString(const std::string& input);
|
||||
|
||||
/**
|
||||
* @return the first part of a file name right up (and excluding) the first period character.
|
||||
*/
|
||||
/** @return the first part of a file name right up (and excluding) the first period character. */
|
||||
std::string removeFileExtension(const std::string& input);
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -50,12 +50,14 @@ void Thread::mainBody(void* context) {
|
||||
assert(pvTaskGetThreadLocalStoragePointer(nullptr, 0) == nullptr);
|
||||
vTaskSetThreadLocalStoragePointer(nullptr, 0, thread);
|
||||
|
||||
TT_LOG_I(TAG, "Starting %s", thread->name.c_str());
|
||||
assert(thread->state == Thread::State::Starting);
|
||||
thread->setState(Thread::State::Running);
|
||||
thread->callbackResult = thread->callback(thread->callbackContext);
|
||||
assert(thread->state == Thread::State::Running);
|
||||
|
||||
thread->setState(Thread::State::Stopped);
|
||||
TT_LOG_I(TAG, "Stopped %s", thread->name.c_str());
|
||||
|
||||
vTaskSetThreadLocalStoragePointer(nullptr, 0, nullptr);
|
||||
thread->taskHandle = nullptr;
|
||||
|
||||
@ -121,4 +121,6 @@ public:
|
||||
*/
|
||||
std::unique_ptr<Uart> open(std::string name);
|
||||
|
||||
std::vector<std::string> getNames();
|
||||
|
||||
} // namespace tt::hal::uart
|
||||
|
||||
@ -12,6 +12,7 @@ namespace tt {
|
||||
bool Preferences::optBool(const std::string& key, bool& out) const {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace_, NVS_READWRITE, &handle) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open namespace %s", namespace_);
|
||||
return false;
|
||||
} else {
|
||||
uint8_t out_number;
|
||||
@ -27,6 +28,7 @@ bool Preferences::optBool(const std::string& key, bool& out) const {
|
||||
bool Preferences::optInt32(const std::string& key, int32_t& out) const {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace_, NVS_READWRITE, &handle) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open namespace %s", namespace_);
|
||||
return false;
|
||||
} else {
|
||||
bool success = nvs_get_i32(handle, key.c_str(), &out) == ESP_OK;
|
||||
@ -38,6 +40,7 @@ bool Preferences::optInt32(const std::string& key, int32_t& out) const {
|
||||
bool Preferences::optString(const std::string& key, std::string& out) const {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace_, NVS_READWRITE, &handle) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to open namespace %s", namespace_);
|
||||
return false;
|
||||
} else {
|
||||
size_t out_size = 256;
|
||||
@ -69,11 +72,11 @@ void Preferences::putBool(const std::string& key, bool value) {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace_, NVS_READWRITE, &handle) == ESP_OK) {
|
||||
if (nvs_set_u8(handle, key.c_str(), (uint8_t)value) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "failed to write %s:%s", namespace_, key.c_str());
|
||||
TT_LOG_E(TAG, "Failed to write %s:%s", namespace_, key.c_str());
|
||||
}
|
||||
nvs_close(handle);
|
||||
} else {
|
||||
TT_LOG_E(TAG, "failed to open namespace %s for writing", namespace_);
|
||||
TT_LOG_E(TAG, "Failed to open namespace %s", namespace_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,11 +84,11 @@ void Preferences::putInt32(const std::string& key, int32_t value) {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace_, NVS_READWRITE, &handle) == ESP_OK) {
|
||||
if (nvs_set_i32(handle, key.c_str(), value) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "failed to write %s:%s", namespace_, key.c_str());
|
||||
TT_LOG_E(TAG, "Failed to write %s:%s", namespace_, key.c_str());
|
||||
}
|
||||
nvs_close(handle);
|
||||
} else {
|
||||
TT_LOG_E(TAG, "failed to open namespace %s for writing", namespace_);
|
||||
TT_LOG_E(TAG, "Failed to open namespace %s", namespace_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +98,7 @@ void Preferences::putString(const std::string& key, const std::string& text) {
|
||||
nvs_set_str(handle, key.c_str(), text.c_str());
|
||||
nvs_close(handle);
|
||||
} else {
|
||||
TT_LOG_E(TAG, "failed to open namespace %s for writing", namespace_);
|
||||
TT_LOG_E(TAG, "Failed to open namespace %s", namespace_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -101,7 +101,7 @@ int32_t GpsDevice::threadMain() {
|
||||
|
||||
if (bytes_read > 0U) {
|
||||
|
||||
TT_LOG_I(TAG, "%s", buffer);
|
||||
TT_LOG_D(TAG, "%s", buffer);
|
||||
|
||||
switch (minmea_sentence_id((char*)buffer, false)) {
|
||||
case MINMEA_SENTENCE_RMC:
|
||||
|
||||
@ -4,12 +4,15 @@
|
||||
#include <Tactility/Mutex.h>
|
||||
|
||||
#include <ranges>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <esp_check.h>
|
||||
#include "Tactility/TactilityHeadless.h"
|
||||
#include "Tactility/hal/uart/UartEsp.h"
|
||||
#include <esp_check.h>
|
||||
#else
|
||||
#include "Tactility/hal/uart/UartPosix.h"
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#define TAG "uart"
|
||||
@ -39,15 +42,8 @@ bool init(const std::vector<uart::Configuration>& configurations) {
|
||||
}
|
||||
|
||||
bool Uart::writeString(const char* buffer, TickType_t timeout) {
|
||||
while (*buffer != 0) {
|
||||
if (writeBytes(reinterpret_cast<const std::byte*>(buffer), 1, timeout)) {
|
||||
buffer++;
|
||||
} else {
|
||||
TT_LOG_E(TAG, "Failed to write - breaking off");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto size = strlen(buffer);
|
||||
writeBytes((std::byte*)buffer, size, timeout);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -105,6 +101,8 @@ size_t Uart::readUntil(std::byte* buffer, size_t bufferSize, uint8_t untilByte,
|
||||
}
|
||||
|
||||
std::unique_ptr<Uart> open(std::string name) {
|
||||
TT_LOG_I(TAG, "Open %s", name.c_str());
|
||||
|
||||
auto result = std::views::filter(uartEntries, [&name](auto& entry) {
|
||||
return entry.configuration.name == name;
|
||||
});
|
||||
@ -123,10 +121,12 @@ std::unique_ptr<Uart> open(std::string name) {
|
||||
auto uart = create(entry.configuration);
|
||||
assert(uart != nullptr);
|
||||
entry.usageId = uart->getId();
|
||||
TT_LOG_I(TAG, "Opened %lu", entry.usageId);
|
||||
return uart;
|
||||
}
|
||||
|
||||
void close(uint32_t uartId) {
|
||||
TT_LOG_I(TAG, "Close %lu", uartId);
|
||||
auto result = std::views::filter(uartEntries, [&uartId](auto& entry) {
|
||||
return entry.usageId == uartId;
|
||||
});
|
||||
@ -139,6 +139,32 @@ void close(uint32_t uartId) {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> getNames() {
|
||||
std::vector<std::string> names;
|
||||
#ifdef ESP_PLATFORM
|
||||
for (auto& config : getConfiguration()->uart) {
|
||||
names.push_back(config.name);
|
||||
}
|
||||
#else
|
||||
DIR* dir = opendir("/dev");
|
||||
if (dir == nullptr) {
|
||||
TT_LOG_E(TAG, "Failed to read /dev");
|
||||
return names;
|
||||
}
|
||||
struct dirent* current_entry;
|
||||
while ((current_entry = readdir(dir)) != nullptr) {
|
||||
auto name = std::string(current_entry->d_name);
|
||||
if (name.starts_with("tty")) {
|
||||
auto path = std::string("/dev/") + name;
|
||||
names.push_back(path);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
#endif
|
||||
return names;
|
||||
}
|
||||
|
||||
Uart::Uart() : id(++lastUartId) {}
|
||||
|
||||
Uart::~Uart() {
|
||||
|
||||
@ -13,11 +13,13 @@
|
||||
namespace tt::hal::uart {
|
||||
|
||||
bool UartEsp::start() {
|
||||
TT_LOG_I(TAG, "[%s] Starting", configuration.name.c_str());
|
||||
|
||||
auto lock = mutex.asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
if (started) {
|
||||
TT_LOG_E(TAG, "(%d) Starting: Already started", configuration.port);
|
||||
TT_LOG_E(TAG, "[%s] Starting: Already started", configuration.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -30,46 +32,53 @@ bool UartEsp::start() {
|
||||
|
||||
esp_err_t result = uart_param_config(configuration.port, &configuration.config);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "(%d) Starting: Failed to configure: %s", configuration.port, esp_err_to_name(result));
|
||||
TT_LOG_E(TAG, "[%s] Starting: Failed to configure: %s", configuration.name.c_str(), esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uart_is_driver_installed(configuration.port)) {
|
||||
TT_LOG_W(TAG, "[%s] Driver was still installed. You probably forgot to stop, or another system uses/used the driver.", configuration.name.c_str());
|
||||
uart_driver_delete(configuration.port);
|
||||
}
|
||||
|
||||
result = uart_set_pin(configuration.port, configuration.txPin, configuration.rxPin, configuration.rtsPin, configuration.ctsPin);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "(%d) Starting: Failed set pins: %s", configuration.port, esp_err_to_name(result));
|
||||
TT_LOG_E(TAG, "[%s] Starting: Failed set pins: %s", configuration.name.c_str(), esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
result = uart_driver_install(configuration.port, (int)configuration.rxBufferSize, (int)configuration.txBufferSize, 0, nullptr, intr_alloc_flags);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "(%d) Starting: Failed to install driver: %s", configuration.port, esp_err_to_name(result));
|
||||
TT_LOG_E(TAG, "[%s] Starting: Failed to install driver: %s", configuration.name.c_str(), esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
started = true;
|
||||
|
||||
TT_LOG_I(TAG, "(%d) Started", configuration.port);
|
||||
TT_LOG_I(TAG, "[%s] Started", configuration.name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UartEsp::stop() {
|
||||
TT_LOG_I(TAG, "[%s] Stopping", configuration.name.c_str());
|
||||
|
||||
auto lock = mutex.asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
if (!started) {
|
||||
TT_LOG_E(TAG, "(%d) Stopping: Not started", configuration.port);
|
||||
TT_LOG_E(TAG, "[%s] Stopping: Not started", configuration.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t result = uart_driver_delete(configuration.port);
|
||||
if (result != ESP_OK) {
|
||||
TT_LOG_E(TAG, "(%d) Stopping: Failed to delete driver: %s", configuration.port, esp_err_to_name(result));
|
||||
TT_LOG_E(TAG, "[%s] Stopping: Failed to delete driver: %s", configuration.name.c_str(), esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
started = false;
|
||||
|
||||
TT_LOG_I(TAG, "(%d) Stopped", configuration.port);
|
||||
TT_LOG_I(TAG, "[%s] Stopped", configuration.name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -97,7 +106,8 @@ bool UartEsp::readByte(std::byte* output, TickType_t timeout) {
|
||||
}
|
||||
|
||||
size_t UartEsp::writeBytes(const std::byte* buffer, size_t bufferSize, TickType_t timeout) {
|
||||
if (!mutex.lock(timeout)) {
|
||||
auto lock = mutex.asScopedLock();
|
||||
if (!lock.lock(timeout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -19,13 +19,13 @@ bool UartPosix::start() {
|
||||
lock.lock();
|
||||
|
||||
if (device != nullptr) {
|
||||
TT_LOG_E(TAG, "(%s) Starting: Already started", configuration.name.c_str());
|
||||
TT_LOG_E(TAG, "[%s] Starting: Already started", configuration.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto file = fopen(configuration.name.c_str(), "w");
|
||||
if (file == nullptr) {
|
||||
TT_LOG_E(TAG, "(%s) failed to open", configuration.name.c_str());
|
||||
TT_LOG_E(TAG, "[%s] Open device failed", configuration.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -33,18 +33,16 @@ bool UartPosix::start() {
|
||||
|
||||
struct termios tty;
|
||||
if (tcgetattr(fileno(file), &tty) < 0) {
|
||||
printf("(%s) tcgetattr failed: %s\n", configuration.name.c_str(), strerror(errno));
|
||||
printf("[%s] tcgetattr failed: %s\n", configuration.name.c_str(), strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cfsetospeed(&tty, (speed_t)configuration.baudRate) == -1) {
|
||||
TT_LOG_E(TAG, "(%s) failed to set output speed", configuration.name.c_str());
|
||||
return false;
|
||||
TT_LOG_E(TAG, "[%s] Setting output speed failed", configuration.name.c_str());
|
||||
}
|
||||
|
||||
if (cfsetispeed(&tty, (speed_t)configuration.baudRate) == -1) {
|
||||
TT_LOG_E(TAG, "(%s) failed to set input speed", configuration.name.c_str());
|
||||
return false;
|
||||
TT_LOG_E(TAG, "[%s] Setting input speed failed", configuration.name.c_str());
|
||||
}
|
||||
|
||||
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
|
||||
@ -63,13 +61,13 @@ bool UartPosix::start() {
|
||||
tty.c_cc[VTIME] = 1;
|
||||
|
||||
if (tcsetattr(fileno(file), TCSANOW, &tty) != 0) {
|
||||
printf("(%s) tcsetattr failed: %s\n", configuration.name.c_str(), strerror(errno));
|
||||
printf("[%s] tcsetattr failed: %s\n", configuration.name.c_str(), strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
device = std::move(new_device);
|
||||
|
||||
TT_LOG_I(TAG, "(%s) Started", configuration.name.c_str());
|
||||
TT_LOG_I(TAG, "[%s] Started", configuration.name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -78,13 +76,13 @@ bool UartPosix::stop() {
|
||||
lock.lock();
|
||||
|
||||
if (device == nullptr) {
|
||||
TT_LOG_E(TAG, "(%s) Stopping: Not started", configuration.name.c_str());
|
||||
TT_LOG_E(TAG, "[%s] Stopping: Not started", configuration.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
device = nullptr;
|
||||
|
||||
TT_LOG_I(TAG, "(%s) Stopped", configuration.name.c_str());
|
||||
TT_LOG_I(TAG, "[%s] Stopped", configuration.name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -141,7 +139,7 @@ void UartPosix::flushInput() {
|
||||
uint32_t UartPosix::getBaudRate() {
|
||||
struct termios tty;
|
||||
if (tcgetattr(fileno(device.get()), &tty) < 0) {
|
||||
printf("(%s) tcgetattr failed: %s\n", configuration.name.c_str(), strerror(errno));
|
||||
printf("[%s] tcgetattr failed: %s\n", configuration.name.c_str(), strerror(errno));
|
||||
return false;
|
||||
} else {
|
||||
return (uint32_t)cfgetispeed(&tty);
|
||||
@ -156,17 +154,17 @@ bool UartPosix::setBaudRate(uint32_t baudRate, TickType_t timeout) {
|
||||
|
||||
struct termios tty;
|
||||
if (tcgetattr(fileno(device.get()), &tty) < 0) {
|
||||
printf("(%s) tcgetattr failed: %s\n", configuration.name.c_str(), strerror(errno));
|
||||
printf("[%s] tcgetattr failed: %s\n", configuration.name.c_str(), strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cfsetospeed(&tty, (speed_t)configuration.baudRate) == -1) {
|
||||
TT_LOG_E(TAG, "(%s) failed to set output speed", configuration.name.c_str());
|
||||
TT_LOG_E(TAG, "[%s] Failed to set output speed", configuration.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cfsetispeed(&tty, (speed_t)configuration.baudRate) == -1) {
|
||||
TT_LOG_E(TAG, "(%s) failed to set input speed", configuration.name.c_str());
|
||||
TT_LOG_E(TAG, "[%s] Failed to set input speed", configuration.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user