mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
Merge remote-tracking branch 'OFW/dev' into dev
This commit is contained in:
@@ -16,6 +16,9 @@
|
|||||||
#define LINES_ON_SCREEN 6
|
#define LINES_ON_SCREEN 6
|
||||||
#define COLUMNS_ON_SCREEN 21
|
#define COLUMNS_ON_SCREEN 21
|
||||||
#define DEFAULT_BAUD_RATE 230400
|
#define DEFAULT_BAUD_RATE 230400
|
||||||
|
#define DEFAULT_DATA_BITS FuriHalSerialDataBits8
|
||||||
|
#define DEFAULT_PARITY FuriHalSerialParityNone
|
||||||
|
#define DEFAULT_STOP_BITS FuriHalSerialStopBits1
|
||||||
|
|
||||||
typedef struct UartDumpModel UartDumpModel;
|
typedef struct UartDumpModel UartDumpModel;
|
||||||
|
|
||||||
@@ -49,11 +52,12 @@ typedef enum {
|
|||||||
WorkerEventRxOverrunError = (1 << 4),
|
WorkerEventRxOverrunError = (1 << 4),
|
||||||
WorkerEventRxFramingError = (1 << 5),
|
WorkerEventRxFramingError = (1 << 5),
|
||||||
WorkerEventRxNoiseError = (1 << 6),
|
WorkerEventRxNoiseError = (1 << 6),
|
||||||
|
WorkerEventRxParityError = (1 << 7),
|
||||||
} WorkerEventFlags;
|
} WorkerEventFlags;
|
||||||
|
|
||||||
#define WORKER_EVENTS_MASK \
|
#define WORKER_EVENTS_MASK \
|
||||||
(WorkerEventStop | WorkerEventRxData | WorkerEventRxIdle | WorkerEventRxOverrunError | \
|
(WorkerEventStop | WorkerEventRxData | WorkerEventRxIdle | WorkerEventRxOverrunError | \
|
||||||
WorkerEventRxFramingError | WorkerEventRxNoiseError)
|
WorkerEventRxFramingError | WorkerEventRxNoiseError | WorkerEventRxParityError)
|
||||||
|
|
||||||
const NotificationSequence sequence_notification = {
|
const NotificationSequence sequence_notification = {
|
||||||
&message_display_backlight_on,
|
&message_display_backlight_on,
|
||||||
@@ -62,6 +66,13 @@ const NotificationSequence sequence_notification = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const NotificationSequence sequence_error = {
|
||||||
|
&message_display_backlight_on,
|
||||||
|
&message_red_255,
|
||||||
|
&message_delay_10,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
static void uart_echo_view_draw_callback(Canvas* canvas, void* _model) {
|
static void uart_echo_view_draw_callback(Canvas* canvas, void* _model) {
|
||||||
UartDumpModel* model = _model;
|
UartDumpModel* model = _model;
|
||||||
|
|
||||||
@@ -133,6 +144,9 @@ static void
|
|||||||
if(event & FuriHalSerialRxEventOverrunError) {
|
if(event & FuriHalSerialRxEventOverrunError) {
|
||||||
flag |= WorkerEventRxOverrunError;
|
flag |= WorkerEventRxOverrunError;
|
||||||
}
|
}
|
||||||
|
if(event & FuriHalSerialRxEventParityError) {
|
||||||
|
flag |= WorkerEventRxParityError;
|
||||||
|
}
|
||||||
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), flag);
|
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), flag);
|
||||||
}
|
}
|
||||||
@@ -227,13 +241,21 @@ static int32_t uart_echo_worker(void* context) {
|
|||||||
if(events & WorkerEventRxNoiseError) {
|
if(events & WorkerEventRxNoiseError) {
|
||||||
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect NE\r\n", 13);
|
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect NE\r\n", 13);
|
||||||
}
|
}
|
||||||
|
if(events & WorkerEventRxParityError) {
|
||||||
|
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect PE\r\n", 13);
|
||||||
|
}
|
||||||
|
notification_message(app->notification, &sequence_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) {
|
static UartEchoApp* uart_echo_app_alloc(
|
||||||
|
uint32_t baudrate,
|
||||||
|
FuriHalSerialDataBits data_bits,
|
||||||
|
FuriHalSerialParity parity,
|
||||||
|
FuriHalSerialStopBits stop_bits) {
|
||||||
UartEchoApp* app = malloc(sizeof(UartEchoApp));
|
UartEchoApp* app = malloc(sizeof(UartEchoApp));
|
||||||
|
|
||||||
app->rx_stream = furi_stream_buffer_alloc(2048, 1);
|
app->rx_stream = furi_stream_buffer_alloc(2048, 1);
|
||||||
@@ -275,6 +297,7 @@ static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) {
|
|||||||
app->serial_handle = furi_hal_serial_control_acquire(FuriHalSerialIdUsart);
|
app->serial_handle = furi_hal_serial_control_acquire(FuriHalSerialIdUsart);
|
||||||
furi_check(app->serial_handle);
|
furi_check(app->serial_handle);
|
||||||
furi_hal_serial_init(app->serial_handle, baudrate);
|
furi_hal_serial_init(app->serial_handle, baudrate);
|
||||||
|
furi_hal_serial_configure_framing(app->serial_handle, data_bits, parity, stop_bits);
|
||||||
|
|
||||||
furi_hal_serial_async_rx_start(app->serial_handle, uart_echo_on_irq_cb, app, true);
|
furi_hal_serial_async_rx_start(app->serial_handle, uart_echo_on_irq_cb, app, true);
|
||||||
|
|
||||||
@@ -319,19 +342,76 @@ static void uart_echo_app_free(UartEchoApp* app) {
|
|||||||
free(app);
|
free(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// silences "same-assignment" false positives in the arg parser below
|
||||||
|
// -V::1048
|
||||||
|
|
||||||
int32_t uart_echo_app(void* p) {
|
int32_t uart_echo_app(void* p) {
|
||||||
uint32_t baudrate = DEFAULT_BAUD_RATE;
|
uint32_t baudrate = DEFAULT_BAUD_RATE;
|
||||||
|
FuriHalSerialDataBits data_bits = DEFAULT_DATA_BITS;
|
||||||
|
FuriHalSerialParity parity = DEFAULT_PARITY;
|
||||||
|
FuriHalSerialStopBits stop_bits = DEFAULT_STOP_BITS;
|
||||||
|
|
||||||
if(p) {
|
if(p) {
|
||||||
const char* baudrate_str = p;
|
// parse argument
|
||||||
if(strint_to_uint32(baudrate_str, NULL, &baudrate, 10) != StrintParseNoError) {
|
char* parse_ptr = p;
|
||||||
FURI_LOG_E(TAG, "Invalid baudrate: %s", baudrate_str);
|
bool parse_success = false;
|
||||||
baudrate = DEFAULT_BAUD_RATE;
|
|
||||||
|
do {
|
||||||
|
if(strint_to_uint32(parse_ptr, &parse_ptr, &baudrate, 10) != StrintParseNoError) break;
|
||||||
|
|
||||||
|
if(*(parse_ptr++) != '_') break;
|
||||||
|
|
||||||
|
uint16_t data_bits_int;
|
||||||
|
if(strint_to_uint16(parse_ptr, &parse_ptr, &data_bits_int, 10) != StrintParseNoError)
|
||||||
|
break;
|
||||||
|
if(data_bits_int == 6)
|
||||||
|
data_bits = FuriHalSerialDataBits6;
|
||||||
|
else if(data_bits_int == 7)
|
||||||
|
data_bits = FuriHalSerialDataBits7;
|
||||||
|
else if(data_bits_int == 8)
|
||||||
|
data_bits = FuriHalSerialDataBits8;
|
||||||
|
else if(data_bits_int == 9)
|
||||||
|
data_bits = FuriHalSerialDataBits9;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
char parity_char = *(parse_ptr++);
|
||||||
|
if(parity_char == 'N')
|
||||||
|
parity = FuriHalSerialParityNone;
|
||||||
|
else if(parity_char == 'E')
|
||||||
|
parity = FuriHalSerialParityEven;
|
||||||
|
else if(parity_char == 'O')
|
||||||
|
parity = FuriHalSerialParityOdd;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
uint16_t stop_bits_int;
|
||||||
|
if(strint_to_uint16(parse_ptr, &parse_ptr, &stop_bits_int, 10) != StrintParseNoError)
|
||||||
|
break;
|
||||||
|
if(stop_bits_int == 5)
|
||||||
|
stop_bits = FuriHalSerialStopBits0_5;
|
||||||
|
else if(stop_bits_int == 1)
|
||||||
|
stop_bits = FuriHalSerialStopBits1;
|
||||||
|
else if(stop_bits_int == 15)
|
||||||
|
stop_bits = FuriHalSerialStopBits1_5;
|
||||||
|
else if(stop_bits_int == 2)
|
||||||
|
stop_bits = FuriHalSerialStopBits2;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
parse_success = true;
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
if(!parse_success) {
|
||||||
|
FURI_LOG_I(
|
||||||
|
TAG,
|
||||||
|
"Couldn't parse baud rate and framing (%s). Applying defaults (%d_8N1)",
|
||||||
|
(const char*)p,
|
||||||
|
DEFAULT_BAUD_RATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_I(TAG, "Using baudrate: %lu", baudrate);
|
UartEchoApp* app = uart_echo_app_alloc(baudrate, data_bits, parity, stop_bits);
|
||||||
|
|
||||||
UartEchoApp* app = uart_echo_app_alloc(baudrate);
|
|
||||||
view_dispatcher_run(app->view_dispatcher);
|
view_dispatcher_run(app->view_dispatcher);
|
||||||
uart_echo_app_free(app);
|
uart_echo_app_free(app);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -12,4 +12,4 @@ tests.assert_eq(false, doesSdkSupport(["abobus", "other-nonexistent-feature"]));
|
|||||||
|
|
||||||
tests.assert_eq("flipperdevices", flipper.firmwareVendor);
|
tests.assert_eq("flipperdevices", flipper.firmwareVendor);
|
||||||
tests.assert_eq(0, flipper.jsSdkVersion[0]);
|
tests.assert_eq(0, flipper.jsSdkVersion[0]);
|
||||||
tests.assert_eq(2, flipper.jsSdkVersion[1]);
|
tests.assert_eq(3, flipper.jsSdkVersion[1]);
|
||||||
|
|||||||
@@ -13,10 +13,12 @@ typedef union {
|
|||||||
} InfraredSceneState;
|
} InfraredSceneState;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
void infrared_scene_universal_common_item_callback(void* context, uint32_t index) {
|
void infrared_scene_universal_common_item_callback(void* context, uint32_t index, InputType type) {
|
||||||
InfraredApp* infrared = context;
|
InfraredApp* infrared = context;
|
||||||
uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeButtonSelected, index);
|
if(type == InputTypeShort) {
|
||||||
view_dispatcher_send_custom_event(infrared->view_dispatcher, event);
|
uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeButtonSelected, index);
|
||||||
|
view_dispatcher_send_custom_event(infrared->view_dispatcher, event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void infrared_scene_universal_common_progress_input_callback(
|
static void infrared_scene_universal_common_progress_input_callback(
|
||||||
|
|||||||
@@ -5,4 +5,4 @@
|
|||||||
void infrared_scene_universal_common_on_enter(void* context);
|
void infrared_scene_universal_common_on_enter(void* context);
|
||||||
bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent event);
|
bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent event);
|
||||||
void infrared_scene_universal_common_on_exit(void* context);
|
void infrared_scene_universal_common_on_exit(void* context);
|
||||||
void infrared_scene_universal_common_item_callback(void* context, uint32_t index);
|
void infrared_scene_universal_common_item_callback(void* context, uint32_t index, InputType type);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <gui/canvas.h>
|
#include <gui/canvas.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal_resources.h>
|
#include <furi_hal_resources.h>
|
||||||
@@ -46,6 +47,7 @@ ARRAY_DEF(ButtonMatrix, ButtonArray_t);
|
|||||||
|
|
||||||
struct ButtonPanel {
|
struct ButtonPanel {
|
||||||
View* view;
|
View* view;
|
||||||
|
bool freeze_input;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -63,7 +65,7 @@ static void button_panel_process_up(ButtonPanel* button_panel);
|
|||||||
static void button_panel_process_down(ButtonPanel* button_panel);
|
static void button_panel_process_down(ButtonPanel* button_panel);
|
||||||
static void button_panel_process_left(ButtonPanel* button_panel);
|
static void button_panel_process_left(ButtonPanel* button_panel);
|
||||||
static void button_panel_process_right(ButtonPanel* button_panel);
|
static void button_panel_process_right(ButtonPanel* button_panel);
|
||||||
static void button_panel_process_ok(ButtonPanel* button_panel);
|
static void button_panel_process_ok(ButtonPanel* button_panel, InputType input);
|
||||||
static void button_panel_view_draw_callback(Canvas* canvas, void* _model);
|
static void button_panel_view_draw_callback(Canvas* canvas, void* _model);
|
||||||
static bool button_panel_view_input_callback(InputEvent* event, void* context);
|
static bool button_panel_view_input_callback(InputEvent* event, void* context);
|
||||||
|
|
||||||
@@ -358,7 +360,7 @@ static void button_panel_process_right(ButtonPanel* button_panel) {
|
|||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void button_panel_process_ok(ButtonPanel* button_panel) {
|
void button_panel_process_ok(ButtonPanel* button_panel, InputType type) {
|
||||||
ButtonItem* button_item = NULL;
|
ButtonItem* button_item = NULL;
|
||||||
|
|
||||||
with_view_model(
|
with_view_model(
|
||||||
@@ -371,7 +373,7 @@ void button_panel_process_ok(ButtonPanel* button_panel) {
|
|||||||
true);
|
true);
|
||||||
|
|
||||||
if(button_item && button_item->callback) {
|
if(button_item && button_item->callback) {
|
||||||
button_item->callback(button_item->callback_context, button_item->index);
|
button_item->callback(button_item->callback_context, button_item->index, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,8 +381,15 @@ static bool button_panel_view_input_callback(InputEvent* event, void* context) {
|
|||||||
ButtonPanel* button_panel = context;
|
ButtonPanel* button_panel = context;
|
||||||
furi_assert(button_panel);
|
furi_assert(button_panel);
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
if(event->key == InputKeyOk) {
|
||||||
if(event->type == InputTypeShort) {
|
if((event->type == InputTypePress) || (event->type == InputTypeRelease)) {
|
||||||
|
button_panel->freeze_input = (event->type == InputTypePress);
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
button_panel_process_ok(button_panel, event->type);
|
||||||
|
}
|
||||||
|
if(!button_panel->freeze_input &&
|
||||||
|
(!(event->type == InputTypePress) && !(event->type == InputTypeRelease))) {
|
||||||
switch(event->key) {
|
switch(event->key) {
|
||||||
case InputKeyUp:
|
case InputKeyUp:
|
||||||
consumed = true;
|
consumed = true;
|
||||||
@@ -398,10 +407,6 @@ static bool button_panel_view_input_callback(InputEvent* event, void* context) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
button_panel_process_right(button_panel);
|
button_panel_process_right(button_panel);
|
||||||
break;
|
break;
|
||||||
case InputKeyOk:
|
|
||||||
consumed = true;
|
|
||||||
button_panel_process_ok(button_panel);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ extern "C" {
|
|||||||
typedef struct ButtonPanel ButtonPanel;
|
typedef struct ButtonPanel ButtonPanel;
|
||||||
|
|
||||||
/** Callback type to call for handling selecting button_panel items */
|
/** Callback type to call for handling selecting button_panel items */
|
||||||
typedef void (*ButtonItemCallback)(void* context, uint32_t index);
|
typedef void (*ButtonItemCallback)(void* context, uint32_t index, InputType type);
|
||||||
|
|
||||||
/** Allocate new button_panel module.
|
/** Allocate new button_panel module.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// This script is like uart_echo, except it uses 8E1 framing (8 data bits, even
|
||||||
|
// parity, 1 stop bit) as opposed to the default 8N1 (8 data bits, no parity,
|
||||||
|
// 1 stop bit)
|
||||||
|
|
||||||
|
let serial = require("serial");
|
||||||
|
serial.setup("usart", 230400, { dataBits: "8", parity: "even", stopBits: "1" });
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
let rx_data = serial.readBytes(1, 1000);
|
||||||
|
if (rx_data !== undefined) {
|
||||||
|
serial.write(rx_data);
|
||||||
|
let data_view = Uint8Array(rx_data);
|
||||||
|
print("0x" + data_view[0].toString(16));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -269,6 +269,7 @@ static const char* extra_features[] = {
|
|||||||
"baseline", // dummy "feature"
|
"baseline", // dummy "feature"
|
||||||
"gpio-pwm",
|
"gpio-pwm",
|
||||||
"gui-widget",
|
"gui-widget",
|
||||||
|
"serial-framing",
|
||||||
|
|
||||||
// extra modules
|
// extra modules
|
||||||
"blebeacon",
|
"blebeacon",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#define JS_SDK_VENDOR_FIRMWARE "unleashed"
|
#define JS_SDK_VENDOR_FIRMWARE "unleashed"
|
||||||
#define JS_SDK_VENDOR "flipperdevices"
|
#define JS_SDK_VENDOR "flipperdevices"
|
||||||
#define JS_SDK_MAJOR 0
|
#define JS_SDK_MAJOR 0
|
||||||
#define JS_SDK_MINOR 2
|
#define JS_SDK_MINOR 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the foreign pointer in `obj["_"]`
|
* @brief Returns the foreign pointer in `obj["_"]`
|
||||||
@@ -82,6 +82,11 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
#define JS_AT_LEAST >=
|
#define JS_AT_LEAST >=
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* name;
|
||||||
|
size_t value;
|
||||||
|
} JsEnumMapping;
|
||||||
|
|
||||||
#define JS_ENUM_MAP(var_name, ...) \
|
#define JS_ENUM_MAP(var_name, ...) \
|
||||||
static const JsEnumMapping var_name##_mapping[] = { \
|
static const JsEnumMapping var_name##_mapping[] = { \
|
||||||
{NULL, sizeof(var_name)}, \
|
{NULL, sizeof(var_name)}, \
|
||||||
@@ -91,8 +96,14 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* name;
|
const char* name;
|
||||||
size_t value;
|
size_t offset;
|
||||||
} JsEnumMapping;
|
} JsObjectMapping;
|
||||||
|
|
||||||
|
#define JS_OBJ_MAP(var_name, ...) \
|
||||||
|
static const JsObjectMapping var_name##_mapping[] = { \
|
||||||
|
__VA_ARGS__, \
|
||||||
|
{NULL, 0}, \
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void* out;
|
void* out;
|
||||||
@@ -200,6 +211,54 @@ static inline void
|
|||||||
_js_validate_enum, \
|
_js_validate_enum, \
|
||||||
var_name##_mapping})
|
var_name##_mapping})
|
||||||
|
|
||||||
|
static inline bool _js_validate_object(struct mjs* mjs, mjs_val_t val, const void* extra) {
|
||||||
|
for(const JsObjectMapping* mapping = (JsObjectMapping*)extra; mapping->name; mapping++)
|
||||||
|
if(mjs_get(mjs, val, mapping->name, ~0) == MJS_UNDEFINED) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static inline void
|
||||||
|
_js_convert_object(struct mjs* mjs, mjs_val_t* val, void* out, const void* extra) {
|
||||||
|
const JsObjectMapping* mapping = (JsObjectMapping*)extra;
|
||||||
|
for(; mapping->name; mapping++) {
|
||||||
|
mjs_val_t field_val = mjs_get(mjs, *val, mapping->name, ~0);
|
||||||
|
*(mjs_val_t*)((uint8_t*)out + mapping->offset) = field_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define JS_ARG_OBJECT(var_name, name) \
|
||||||
|
((_js_arg_decl){ \
|
||||||
|
&var_name, \
|
||||||
|
mjs_is_object, \
|
||||||
|
_js_convert_object, \
|
||||||
|
name " object", \
|
||||||
|
_js_validate_object, \
|
||||||
|
var_name##_mapping})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validates and converts a JS value with a declarative interface
|
||||||
|
*
|
||||||
|
* Example: `int32_t my_value; JS_CONVERT_OR_RETURN(mjs, &mjs_val, JS_ARG_INT32(&my_value), "value source");`
|
||||||
|
*
|
||||||
|
* @warning This macro executes `return;` by design in case of a validation failure
|
||||||
|
*/
|
||||||
|
#define JS_CONVERT_OR_RETURN(mjs, value, decl, source, ...) \
|
||||||
|
if(decl.validator) \
|
||||||
|
if(!decl.validator(*value)) \
|
||||||
|
JS_ERROR_AND_RETURN( \
|
||||||
|
mjs, \
|
||||||
|
MJS_BAD_ARGS_ERROR, \
|
||||||
|
source ": expected %s", \
|
||||||
|
##__VA_ARGS__, \
|
||||||
|
decl.expected_type); \
|
||||||
|
if(decl.extended_validator) \
|
||||||
|
if(!decl.extended_validator(mjs, *value, decl.extra_data)) \
|
||||||
|
JS_ERROR_AND_RETURN( \
|
||||||
|
mjs, \
|
||||||
|
MJS_BAD_ARGS_ERROR, \
|
||||||
|
source ": expected %s", \
|
||||||
|
##__VA_ARGS__, \
|
||||||
|
decl.expected_type); \
|
||||||
|
decl.converter(mjs, value, decl.out, decl.extra_data);
|
||||||
|
|
||||||
//-V:JS_FETCH_ARGS_OR_RETURN:1008
|
//-V:JS_FETCH_ARGS_OR_RETURN:1008
|
||||||
/**
|
/**
|
||||||
* @brief Fetches and validates the arguments passed to a JS function
|
* @brief Fetches and validates the arguments passed to a JS function
|
||||||
@@ -209,38 +268,21 @@ static inline void
|
|||||||
* @warning This macro executes `return;` by design in case of an argument count
|
* @warning This macro executes `return;` by design in case of an argument count
|
||||||
* mismatch or a validation failure
|
* mismatch or a validation failure
|
||||||
*/
|
*/
|
||||||
#define JS_FETCH_ARGS_OR_RETURN(mjs, arg_operator, ...) \
|
#define JS_FETCH_ARGS_OR_RETURN(mjs, arg_operator, ...) \
|
||||||
_js_arg_decl _js_args[] = {__VA_ARGS__}; \
|
_js_arg_decl _js_args[] = {__VA_ARGS__}; \
|
||||||
int _js_arg_cnt = COUNT_OF(_js_args); \
|
int _js_arg_cnt = COUNT_OF(_js_args); \
|
||||||
mjs_val_t _js_arg_vals[_js_arg_cnt]; \
|
mjs_val_t _js_arg_vals[_js_arg_cnt]; \
|
||||||
if(!(mjs_nargs(mjs) arg_operator _js_arg_cnt)) \
|
if(!(mjs_nargs(mjs) arg_operator _js_arg_cnt)) \
|
||||||
JS_ERROR_AND_RETURN( \
|
JS_ERROR_AND_RETURN( \
|
||||||
mjs, \
|
mjs, \
|
||||||
MJS_BAD_ARGS_ERROR, \
|
MJS_BAD_ARGS_ERROR, \
|
||||||
"expected %s%d arguments, got %d", \
|
"expected %s%d arguments, got %d", \
|
||||||
#arg_operator, \
|
#arg_operator, \
|
||||||
_js_arg_cnt, \
|
_js_arg_cnt, \
|
||||||
mjs_nargs(mjs)); \
|
mjs_nargs(mjs)); \
|
||||||
for(int _i = 0; _i < _js_arg_cnt; _i++) { \
|
for(int _i = 0; _i < _js_arg_cnt; _i++) { \
|
||||||
_js_arg_vals[_i] = mjs_arg(mjs, _i); \
|
_js_arg_vals[_i] = mjs_arg(mjs, _i); \
|
||||||
if(_js_args[_i].validator) \
|
JS_CONVERT_OR_RETURN(mjs, &_js_arg_vals[_i], _js_args[_i], "argument %d", _i); \
|
||||||
if(!_js_args[_i].validator(_js_arg_vals[_i])) \
|
|
||||||
JS_ERROR_AND_RETURN( \
|
|
||||||
mjs, \
|
|
||||||
MJS_BAD_ARGS_ERROR, \
|
|
||||||
"argument %d: expected %s", \
|
|
||||||
_i, \
|
|
||||||
_js_args[_i].expected_type); \
|
|
||||||
if(_js_args[_i].extended_validator) \
|
|
||||||
if(!_js_args[_i].extended_validator(mjs, _js_arg_vals[_i], _js_args[_i].extra_data)) \
|
|
||||||
JS_ERROR_AND_RETURN( \
|
|
||||||
mjs, \
|
|
||||||
MJS_BAD_ARGS_ERROR, \
|
|
||||||
"argument %d: expected %s", \
|
|
||||||
_i, \
|
|
||||||
_js_args[_i].expected_type); \
|
|
||||||
_js_args[_i].converter( \
|
|
||||||
mjs, &_js_arg_vals[_i], _js_args[_i].out, _js_args[_i].extra_data); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,14 +20,6 @@ typedef struct {
|
|||||||
char* data;
|
char* data;
|
||||||
} PatternArrayItem;
|
} PatternArrayItem;
|
||||||
|
|
||||||
static const struct {
|
|
||||||
const char* name;
|
|
||||||
const FuriHalSerialId value;
|
|
||||||
} serial_channels[] = {
|
|
||||||
{"usart", FuriHalSerialIdUsart},
|
|
||||||
{"lpuart", FuriHalSerialIdLpuart},
|
|
||||||
};
|
|
||||||
|
|
||||||
ARRAY_DEF(PatternArray, PatternArrayItem, M_POD_OPLIST);
|
ARRAY_DEF(PatternArray, PatternArrayItem, M_POD_OPLIST);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -43,9 +35,54 @@ static void
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void js_serial_setup(struct mjs* mjs) {
|
static void js_serial_setup(struct mjs* mjs) {
|
||||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
FuriHalSerialId serial_id;
|
||||||
JsSerialInst* serial = mjs_get_ptr(mjs, obj_inst);
|
int32_t baudrate;
|
||||||
furi_assert(serial);
|
JS_ENUM_MAP(serial_id, {"lpuart", FuriHalSerialIdLpuart}, {"usart", FuriHalSerialIdUsart});
|
||||||
|
JS_FETCH_ARGS_OR_RETURN(
|
||||||
|
mjs, JS_AT_LEAST, JS_ARG_ENUM(serial_id, "SerialId"), JS_ARG_INT32(&baudrate));
|
||||||
|
|
||||||
|
FuriHalSerialDataBits data_bits = FuriHalSerialDataBits8;
|
||||||
|
FuriHalSerialParity parity = FuriHalSerialParityNone;
|
||||||
|
FuriHalSerialStopBits stop_bits = FuriHalSerialStopBits1;
|
||||||
|
if(mjs_nargs(mjs) > 2) {
|
||||||
|
struct framing {
|
||||||
|
mjs_val_t data_bits;
|
||||||
|
mjs_val_t parity;
|
||||||
|
mjs_val_t stop_bits;
|
||||||
|
} framing;
|
||||||
|
JS_OBJ_MAP(
|
||||||
|
framing,
|
||||||
|
{"dataBits", offsetof(struct framing, data_bits)},
|
||||||
|
{"parity", offsetof(struct framing, parity)},
|
||||||
|
{"stopBits", offsetof(struct framing, stop_bits)});
|
||||||
|
JS_ENUM_MAP(
|
||||||
|
data_bits,
|
||||||
|
{"6", FuriHalSerialDataBits6},
|
||||||
|
{"7", FuriHalSerialDataBits7},
|
||||||
|
{"8", FuriHalSerialDataBits8},
|
||||||
|
{"9", FuriHalSerialDataBits9});
|
||||||
|
JS_ENUM_MAP(
|
||||||
|
parity,
|
||||||
|
{"none", FuriHalSerialParityNone},
|
||||||
|
{"even", FuriHalSerialParityEven},
|
||||||
|
{"odd", FuriHalSerialParityOdd});
|
||||||
|
JS_ENUM_MAP(
|
||||||
|
stop_bits,
|
||||||
|
{"0.5", FuriHalSerialStopBits0_5},
|
||||||
|
{"1", FuriHalSerialStopBits1},
|
||||||
|
{"1.5", FuriHalSerialStopBits1_5},
|
||||||
|
{"2", FuriHalSerialStopBits2});
|
||||||
|
mjs_val_t framing_obj = mjs_arg(mjs, 2);
|
||||||
|
JS_CONVERT_OR_RETURN(mjs, &framing_obj, JS_ARG_OBJECT(framing, "Framing"), "argument 2");
|
||||||
|
JS_CONVERT_OR_RETURN(
|
||||||
|
mjs, &framing.data_bits, JS_ARG_ENUM(data_bits, "DataBits"), "argument 2: dataBits");
|
||||||
|
JS_CONVERT_OR_RETURN(
|
||||||
|
mjs, &framing.parity, JS_ARG_ENUM(parity, "Parity"), "argument 2: parity");
|
||||||
|
JS_CONVERT_OR_RETURN(
|
||||||
|
mjs, &framing.stop_bits, JS_ARG_ENUM(stop_bits, "StopBits"), "argument 2: stopBits");
|
||||||
|
}
|
||||||
|
|
||||||
|
JsSerialInst* serial = JS_GET_CONTEXT(mjs);
|
||||||
|
|
||||||
if(serial->setup_done) {
|
if(serial->setup_done) {
|
||||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Serial is already configured");
|
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Serial is already configured");
|
||||||
@@ -53,43 +90,6 @@ static void js_serial_setup(struct mjs* mjs) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool args_correct = false;
|
|
||||||
FuriHalSerialId serial_id = FuriHalSerialIdMax;
|
|
||||||
uint32_t baudrate = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if(mjs_nargs(mjs) != 2) break;
|
|
||||||
|
|
||||||
mjs_val_t arg = mjs_arg(mjs, 0);
|
|
||||||
if(!mjs_is_string(arg)) break;
|
|
||||||
|
|
||||||
size_t str_len = 0;
|
|
||||||
const char* arg_str = mjs_get_string(mjs, &arg, &str_len);
|
|
||||||
for(size_t i = 0; i < COUNT_OF(serial_channels); i++) {
|
|
||||||
size_t name_len = strlen(serial_channels[i].name);
|
|
||||||
if(str_len != name_len) continue;
|
|
||||||
if(strncmp(arg_str, serial_channels[i].name, str_len) == 0) {
|
|
||||||
serial_id = serial_channels[i].value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(serial_id == FuriHalSerialIdMax) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
arg = mjs_arg(mjs, 1);
|
|
||||||
if(!mjs_is_number(arg)) break;
|
|
||||||
baudrate = mjs_get_int32(mjs, arg);
|
|
||||||
|
|
||||||
args_correct = true;
|
|
||||||
} while(0);
|
|
||||||
|
|
||||||
if(!args_correct) {
|
|
||||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "");
|
|
||||||
mjs_return(mjs, MJS_UNDEFINED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
expansion_disable(furi_record_open(RECORD_EXPANSION));
|
expansion_disable(furi_record_open(RECORD_EXPANSION));
|
||||||
furi_record_close(RECORD_EXPANSION);
|
furi_record_close(RECORD_EXPANSION);
|
||||||
|
|
||||||
@@ -97,6 +97,7 @@ static void js_serial_setup(struct mjs* mjs) {
|
|||||||
if(serial->serial_handle) {
|
if(serial->serial_handle) {
|
||||||
serial->rx_stream = furi_stream_buffer_alloc(RX_BUF_LEN, 1);
|
serial->rx_stream = furi_stream_buffer_alloc(RX_BUF_LEN, 1);
|
||||||
furi_hal_serial_init(serial->serial_handle, baudrate);
|
furi_hal_serial_init(serial->serial_handle, baudrate);
|
||||||
|
furi_hal_serial_configure_framing(serial->serial_handle, data_bits, parity, stop_bits);
|
||||||
furi_hal_serial_async_rx_start(
|
furi_hal_serial_async_rx_start(
|
||||||
serial->serial_handle, js_serial_on_async_rx, serial, false);
|
serial->serial_handle, js_serial_on_async_rx, serial, false);
|
||||||
serial->setup_done = true;
|
serial->setup_done = true;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
* @brief Checks compatibility between the script and the JS SDK that the
|
* @brief Checks compatibility between the script and the JS SDK that the
|
||||||
* firmware provides
|
* firmware provides
|
||||||
*
|
*
|
||||||
* @note You're looking at JS SDK v0.1
|
* @note You're looking at JS SDK v0.3
|
||||||
*
|
*
|
||||||
* @param expectedMajor JS SDK major version expected by the script
|
* @param expectedMajor JS SDK major version expected by the script
|
||||||
* @param expectedMinor JS SDK minor version expected by the script
|
* @param expectedMinor JS SDK minor version expected by the script
|
||||||
@@ -92,7 +92,7 @@ declare function sdkCompatibilityStatus(expectedMajor: number, expectedMinor: nu
|
|||||||
* @brief Checks compatibility between the script and the JS SDK that the
|
* @brief Checks compatibility between the script and the JS SDK that the
|
||||||
* firmware provides in a boolean fashion
|
* firmware provides in a boolean fashion
|
||||||
*
|
*
|
||||||
* @note You're looking at JS SDK v0.1
|
* @note You're looking at JS SDK v0.3
|
||||||
*
|
*
|
||||||
* @param expectedMajor JS SDK major version expected by the script
|
* @param expectedMajor JS SDK major version expected by the script
|
||||||
* @param expectedMinor JS SDK minor version expected by the script
|
* @param expectedMinor JS SDK minor version expected by the script
|
||||||
@@ -105,7 +105,7 @@ declare function isSdkCompatible(expectedMajor: number, expectedMinor: number):
|
|||||||
* @brief Asks the user whether to continue executing the script if the versions
|
* @brief Asks the user whether to continue executing the script if the versions
|
||||||
* are not compatible. Does nothing if they are.
|
* are not compatible. Does nothing if they are.
|
||||||
*
|
*
|
||||||
* @note You're looking at JS SDK v0.1
|
* @note You're looking at JS SDK v0.3
|
||||||
*
|
*
|
||||||
* @param expectedMajor JS SDK major version expected by the script
|
* @param expectedMajor JS SDK major version expected by the script
|
||||||
* @param expectedMinor JS SDK minor version expected by the script
|
* @param expectedMinor JS SDK minor version expected by the script
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@darkflippers/fz-sdk-ul",
|
"name": "@darkflippers/fz-sdk-ul",
|
||||||
"version": "0.2.0",
|
"version": "0.3.0",
|
||||||
"description": "Type declarations and documentation for native JS modules available on Unleashed Custom Firmware for Flipper Zero",
|
"description": "Type declarations and documentation for native JS modules available on Unleashed Custom Firmware for Flipper Zero",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"unleashed",
|
"unleashed",
|
||||||
|
|||||||
@@ -4,16 +4,33 @@
|
|||||||
* @module
|
* @module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export interface Framing {
|
||||||
|
/**
|
||||||
|
* @note 6 data bits can only be selected when parity is enabled (even or
|
||||||
|
* odd)
|
||||||
|
* @note 9 data bits can only be selected when parity is disabled (none)
|
||||||
|
*/
|
||||||
|
dataBits: "6" | "7" | "8" | "9";
|
||||||
|
parity: "none" | "even" | "odd";
|
||||||
|
/**
|
||||||
|
* @note LPUART only supports whole stop bit lengths (i.e. 1 and 2 but not
|
||||||
|
* 0.5 and 1.5)
|
||||||
|
*/
|
||||||
|
stopBits: "0.5" | "1" | "1.5" | "2";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes the serial port
|
* @brief Initializes the serial port
|
||||||
*
|
*
|
||||||
* Automatically disables Expansion module service to prevent interference.
|
* Automatically disables Expansion module service to prevent interference.
|
||||||
*
|
*
|
||||||
* @param port The port to initialize (`"lpuart"` or `"start"`)
|
* @param port The port to initialize (`"lpuart"` or `"usart"`)
|
||||||
* @param baudRate
|
* @param baudRate Baud rate
|
||||||
|
* @param framing See `Framing` type
|
||||||
* @version Added in JS SDK 0.1
|
* @version Added in JS SDK 0.1
|
||||||
|
* @version Added `framing` parameter in JS SDK 0.3, extra feature `"serial-framing"`
|
||||||
*/
|
*/
|
||||||
export declare function setup(port: "lpuart" | "usart", baudRate: number): void;
|
export declare function setup(port: "lpuart" | "usart", baudRate: number, framing?: Framing): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Writes data to the serial port
|
* @brief Writes data to the serial port
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,80.3,,
|
Version,+,80.4,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
@@ -1437,6 +1437,7 @@ Function,+,furi_hal_serial_async_rx,uint8_t,FuriHalSerialHandle*
|
|||||||
Function,+,furi_hal_serial_async_rx_available,_Bool,FuriHalSerialHandle*
|
Function,+,furi_hal_serial_async_rx_available,_Bool,FuriHalSerialHandle*
|
||||||
Function,+,furi_hal_serial_async_rx_start,void,"FuriHalSerialHandle*, FuriHalSerialAsyncRxCallback, void*, _Bool"
|
Function,+,furi_hal_serial_async_rx_start,void,"FuriHalSerialHandle*, FuriHalSerialAsyncRxCallback, void*, _Bool"
|
||||||
Function,+,furi_hal_serial_async_rx_stop,void,FuriHalSerialHandle*
|
Function,+,furi_hal_serial_async_rx_stop,void,FuriHalSerialHandle*
|
||||||
|
Function,+,furi_hal_serial_configure_framing,void,"FuriHalSerialHandle*, FuriHalSerialDataBits, FuriHalSerialParity, FuriHalSerialStopBits"
|
||||||
Function,+,furi_hal_serial_control_acquire,FuriHalSerialHandle*,FuriHalSerialId
|
Function,+,furi_hal_serial_control_acquire,FuriHalSerialHandle*,FuriHalSerialId
|
||||||
Function,+,furi_hal_serial_control_deinit,void,
|
Function,+,furi_hal_serial_control_deinit,void,
|
||||||
Function,+,furi_hal_serial_control_init,void,
|
Function,+,furi_hal_serial_control_init,void,
|
||||||
|
|||||||
|
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,80.3,,
|
Version,+,80.4,,
|
||||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
@@ -1662,6 +1662,7 @@ Function,+,furi_hal_serial_async_rx,uint8_t,FuriHalSerialHandle*
|
|||||||
Function,+,furi_hal_serial_async_rx_available,_Bool,FuriHalSerialHandle*
|
Function,+,furi_hal_serial_async_rx_available,_Bool,FuriHalSerialHandle*
|
||||||
Function,+,furi_hal_serial_async_rx_start,void,"FuriHalSerialHandle*, FuriHalSerialAsyncRxCallback, void*, _Bool"
|
Function,+,furi_hal_serial_async_rx_start,void,"FuriHalSerialHandle*, FuriHalSerialAsyncRxCallback, void*, _Bool"
|
||||||
Function,+,furi_hal_serial_async_rx_stop,void,FuriHalSerialHandle*
|
Function,+,furi_hal_serial_async_rx_stop,void,FuriHalSerialHandle*
|
||||||
|
Function,+,furi_hal_serial_configure_framing,void,"FuriHalSerialHandle*, FuriHalSerialDataBits, FuriHalSerialParity, FuriHalSerialStopBits"
|
||||||
Function,+,furi_hal_serial_control_acquire,FuriHalSerialHandle*,FuriHalSerialId
|
Function,+,furi_hal_serial_control_acquire,FuriHalSerialHandle*,FuriHalSerialId
|
||||||
Function,+,furi_hal_serial_control_deinit,void,
|
Function,+,furi_hal_serial_control_deinit,void,
|
||||||
Function,+,furi_hal_serial_control_init,void,
|
Function,+,furi_hal_serial_control_init,void,
|
||||||
|
|||||||
|
@@ -258,85 +258,85 @@ FURI_ALWAYS_INLINE static void furi_hal_gpio_int_call(uint16_t pin_num) {
|
|||||||
/* Interrupt handlers */
|
/* Interrupt handlers */
|
||||||
void EXTI0_IRQHandler(void) {
|
void EXTI0_IRQHandler(void) {
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_0)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_0)) {
|
||||||
furi_hal_gpio_int_call(0);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_0);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_0);
|
||||||
|
furi_hal_gpio_int_call(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXTI1_IRQHandler(void) {
|
void EXTI1_IRQHandler(void) {
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_1)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_1)) {
|
||||||
furi_hal_gpio_int_call(1);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_1);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_1);
|
||||||
|
furi_hal_gpio_int_call(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXTI2_IRQHandler(void) {
|
void EXTI2_IRQHandler(void) {
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_2)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_2)) {
|
||||||
furi_hal_gpio_int_call(2);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_2);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_2);
|
||||||
|
furi_hal_gpio_int_call(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXTI3_IRQHandler(void) {
|
void EXTI3_IRQHandler(void) {
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_3)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_3)) {
|
||||||
furi_hal_gpio_int_call(3);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3);
|
||||||
|
furi_hal_gpio_int_call(3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXTI4_IRQHandler(void) {
|
void EXTI4_IRQHandler(void) {
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_4)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_4)) {
|
||||||
furi_hal_gpio_int_call(4);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4);
|
||||||
|
furi_hal_gpio_int_call(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXTI9_5_IRQHandler(void) {
|
void EXTI9_5_IRQHandler(void) {
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_5)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_5)) {
|
||||||
furi_hal_gpio_int_call(5);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5);
|
||||||
|
furi_hal_gpio_int_call(5);
|
||||||
}
|
}
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_6)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_6)) {
|
||||||
furi_hal_gpio_int_call(6);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6);
|
||||||
|
furi_hal_gpio_int_call(6);
|
||||||
}
|
}
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_7)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_7)) {
|
||||||
furi_hal_gpio_int_call(7);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_7);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_7);
|
||||||
|
furi_hal_gpio_int_call(7);
|
||||||
}
|
}
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_8)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_8)) {
|
||||||
furi_hal_gpio_int_call(8);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_8);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_8);
|
||||||
|
furi_hal_gpio_int_call(8);
|
||||||
}
|
}
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_9)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_9)) {
|
||||||
furi_hal_gpio_int_call(9);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_9);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_9);
|
||||||
|
furi_hal_gpio_int_call(9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXTI15_10_IRQHandler(void) {
|
void EXTI15_10_IRQHandler(void) {
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_10)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_10)) {
|
||||||
furi_hal_gpio_int_call(10);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_10);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_10);
|
||||||
|
furi_hal_gpio_int_call(10);
|
||||||
}
|
}
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_11)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_11)) {
|
||||||
furi_hal_gpio_int_call(11);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_11);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_11);
|
||||||
|
furi_hal_gpio_int_call(11);
|
||||||
}
|
}
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_12)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_12)) {
|
||||||
furi_hal_gpio_int_call(12);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12);
|
||||||
|
furi_hal_gpio_int_call(12);
|
||||||
}
|
}
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_13)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_13)) {
|
||||||
furi_hal_gpio_int_call(13);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_13);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_13);
|
||||||
|
furi_hal_gpio_int_call(13);
|
||||||
}
|
}
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_14)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_14)) {
|
||||||
furi_hal_gpio_int_call(14);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_14);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_14);
|
||||||
|
furi_hal_gpio_int_call(14);
|
||||||
}
|
}
|
||||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_15)) {
|
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_15)) {
|
||||||
furi_hal_gpio_int_call(15);
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_15);
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_15);
|
||||||
|
furi_hal_gpio_int_call(15);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ static void furi_hal_serial_usart_irq_callback(void* context) {
|
|||||||
}
|
}
|
||||||
if(USART1->ISR & USART_ISR_PE) {
|
if(USART1->ISR & USART_ISR_PE) {
|
||||||
USART1->ICR = USART_ICR_PECF;
|
USART1->ICR = USART_ICR_PECF;
|
||||||
event |= FuriHalSerialRxEventFrameError;
|
event |= FuriHalSerialRxEventParityError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr == NULL) {
|
if(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr == NULL) {
|
||||||
@@ -321,7 +321,7 @@ static void furi_hal_serial_lpuart_irq_callback(void* context) {
|
|||||||
}
|
}
|
||||||
if(LPUART1->ISR & USART_ISR_PE) {
|
if(LPUART1->ISR & USART_ISR_PE) {
|
||||||
LPUART1->ICR = USART_ICR_PECF;
|
LPUART1->ICR = USART_ICR_PECF;
|
||||||
event |= FuriHalSerialRxEventFrameError;
|
event |= FuriHalSerialRxEventParityError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr == NULL) {
|
if(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr == NULL) {
|
||||||
@@ -605,6 +605,92 @@ void furi_hal_serial_set_br(FuriHalSerialHandle* handle, uint32_t baud) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avoid duplicating look-up tables between USART and LPUART
|
||||||
|
static_assert(LL_LPUART_DATAWIDTH_7B == LL_USART_DATAWIDTH_7B);
|
||||||
|
static_assert(LL_LPUART_DATAWIDTH_8B == LL_USART_DATAWIDTH_8B);
|
||||||
|
static_assert(LL_LPUART_DATAWIDTH_9B == LL_USART_DATAWIDTH_9B);
|
||||||
|
static_assert(LL_LPUART_PARITY_NONE == LL_USART_PARITY_NONE);
|
||||||
|
static_assert(LL_LPUART_PARITY_EVEN == LL_USART_PARITY_EVEN);
|
||||||
|
static_assert(LL_LPUART_PARITY_ODD == LL_USART_PARITY_ODD);
|
||||||
|
static_assert(LL_LPUART_STOPBITS_1 == LL_USART_STOPBITS_1);
|
||||||
|
static_assert(LL_LPUART_STOPBITS_2 == LL_USART_STOPBITS_2);
|
||||||
|
|
||||||
|
static const uint32_t serial_data_bits_lut[] = {
|
||||||
|
[FuriHalSerialDataBits7] = LL_USART_DATAWIDTH_7B,
|
||||||
|
[FuriHalSerialDataBits8] = LL_USART_DATAWIDTH_8B,
|
||||||
|
[FuriHalSerialDataBits9] = LL_USART_DATAWIDTH_9B,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t serial_parity_lut[] = {
|
||||||
|
[FuriHalSerialParityNone] = LL_USART_PARITY_NONE,
|
||||||
|
[FuriHalSerialParityEven] = LL_USART_PARITY_EVEN,
|
||||||
|
[FuriHalSerialParityOdd] = LL_USART_PARITY_ODD,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t serial_stop_bits_lut[] = {
|
||||||
|
[FuriHalSerialStopBits0_5] = LL_USART_STOPBITS_0_5,
|
||||||
|
[FuriHalSerialStopBits1] = LL_USART_STOPBITS_1,
|
||||||
|
[FuriHalSerialStopBits1_5] = LL_USART_STOPBITS_1_5,
|
||||||
|
[FuriHalSerialStopBits2] = LL_USART_STOPBITS_2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void furi_hal_serial_usart_configure_framing(
|
||||||
|
FuriHalSerialDataBits data_bits,
|
||||||
|
FuriHalSerialParity parity,
|
||||||
|
FuriHalSerialStopBits stop_bits) {
|
||||||
|
LL_USART_SetDataWidth(USART1, serial_data_bits_lut[data_bits]);
|
||||||
|
LL_USART_SetParity(USART1, serial_parity_lut[parity]);
|
||||||
|
LL_USART_SetStopBitsLength(USART1, serial_stop_bits_lut[stop_bits]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void furi_hal_serial_lpuart_configure_framing(
|
||||||
|
FuriHalSerialDataBits data_bits,
|
||||||
|
FuriHalSerialParity parity,
|
||||||
|
FuriHalSerialStopBits stop_bits) {
|
||||||
|
LL_LPUART_SetDataWidth(LPUART1, serial_data_bits_lut[data_bits]);
|
||||||
|
LL_LPUART_SetParity(LPUART1, serial_parity_lut[parity]);
|
||||||
|
// Unsupported non-whole stop bit numbers have been furi_check'ed away
|
||||||
|
LL_LPUART_SetStopBitsLength(LPUART1, serial_stop_bits_lut[stop_bits]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void furi_hal_serial_configure_framing(
|
||||||
|
FuriHalSerialHandle* handle,
|
||||||
|
FuriHalSerialDataBits data_bits,
|
||||||
|
FuriHalSerialParity parity,
|
||||||
|
FuriHalSerialStopBits stop_bits) {
|
||||||
|
furi_check(handle);
|
||||||
|
|
||||||
|
// Unsupported combinations
|
||||||
|
if(data_bits == FuriHalSerialDataBits9) furi_check(parity == FuriHalSerialParityNone);
|
||||||
|
if(data_bits == FuriHalSerialDataBits6) furi_check(parity != FuriHalSerialParityNone);
|
||||||
|
|
||||||
|
// Extend data word to account for parity bit
|
||||||
|
if(parity != FuriHalSerialParityNone) data_bits++;
|
||||||
|
|
||||||
|
if(handle->id == FuriHalSerialIdUsart) {
|
||||||
|
if(LL_USART_IsEnabled(USART1)) {
|
||||||
|
// Wait for transfer complete flag
|
||||||
|
while(!LL_USART_IsActiveFlag_TC(USART1))
|
||||||
|
;
|
||||||
|
LL_USART_Disable(USART1);
|
||||||
|
furi_hal_serial_usart_configure_framing(data_bits, parity, stop_bits);
|
||||||
|
LL_USART_Enable(USART1);
|
||||||
|
}
|
||||||
|
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||||
|
// Unsupported configurations
|
||||||
|
furi_check(stop_bits == FuriHalSerialStopBits1 || stop_bits == FuriHalSerialStopBits2);
|
||||||
|
|
||||||
|
if(LL_LPUART_IsEnabled(LPUART1)) {
|
||||||
|
// Wait for transfer complete flag
|
||||||
|
while(!LL_LPUART_IsActiveFlag_TC(LPUART1))
|
||||||
|
;
|
||||||
|
LL_LPUART_Disable(LPUART1);
|
||||||
|
furi_hal_serial_lpuart_configure_framing(data_bits, parity, stop_bits);
|
||||||
|
LL_LPUART_Enable(LPUART1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void furi_hal_serial_deinit(FuriHalSerialHandle* handle) {
|
void furi_hal_serial_deinit(FuriHalSerialHandle* handle) {
|
||||||
furi_check(handle);
|
furi_check(handle);
|
||||||
furi_hal_serial_async_rx_configure(handle, NULL, NULL);
|
furi_hal_serial_async_rx_configure(handle, NULL, NULL);
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ extern "C" {
|
|||||||
|
|
||||||
/** Initialize Serial
|
/** Initialize Serial
|
||||||
*
|
*
|
||||||
* Configures GPIO, configures and enables transceiver.
|
* Configures GPIO, configures and enables transceiver. Default framing settings
|
||||||
|
* are used: 8 data bits, no parity, 1 stop bit. Override them with
|
||||||
|
* `furi_hal_serial_configure_framing`.
|
||||||
*
|
*
|
||||||
* @param handle Serial handle
|
* @param handle Serial handle
|
||||||
* @param baud baud rate
|
* @param baud baud rate
|
||||||
@@ -64,6 +66,20 @@ bool furi_hal_serial_is_baud_rate_supported(FuriHalSerialHandle* handle, uint32_
|
|||||||
*/
|
*/
|
||||||
void furi_hal_serial_set_br(FuriHalSerialHandle* handle, uint32_t baud);
|
void furi_hal_serial_set_br(FuriHalSerialHandle* handle, uint32_t baud);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures framing of a serial interface
|
||||||
|
*
|
||||||
|
* @param handle Serial handle
|
||||||
|
* @param data_bits Data bits
|
||||||
|
* @param parity Parity
|
||||||
|
* @param stop_bits Stop bits
|
||||||
|
*/
|
||||||
|
void furi_hal_serial_configure_framing(
|
||||||
|
FuriHalSerialHandle* handle,
|
||||||
|
FuriHalSerialDataBits data_bits,
|
||||||
|
FuriHalSerialParity parity,
|
||||||
|
FuriHalSerialStopBits stop_bits);
|
||||||
|
|
||||||
/** Transmits data in semi-blocking mode
|
/** Transmits data in semi-blocking mode
|
||||||
*
|
*
|
||||||
* Fills transmission pipe with data, returns as soon as all bytes from buffer
|
* Fills transmission pipe with data, returns as soon as all bytes from buffer
|
||||||
@@ -93,6 +109,7 @@ typedef enum {
|
|||||||
FuriHalSerialRxEventFrameError = (1 << 2), /**< Framing Error: incorrect frame detected */
|
FuriHalSerialRxEventFrameError = (1 << 2), /**< Framing Error: incorrect frame detected */
|
||||||
FuriHalSerialRxEventNoiseError = (1 << 3), /**< Noise Error: noise on the line detected */
|
FuriHalSerialRxEventNoiseError = (1 << 3), /**< Noise Error: noise on the line detected */
|
||||||
FuriHalSerialRxEventOverrunError = (1 << 4), /**< Overrun Error: no space for received data */
|
FuriHalSerialRxEventOverrunError = (1 << 4), /**< Overrun Error: no space for received data */
|
||||||
|
FuriHalSerialRxEventParityError = (1 << 5), /**< Parity Error: incorrect parity bit received */
|
||||||
} FuriHalSerialRxEvent;
|
} FuriHalSerialRxEvent;
|
||||||
|
|
||||||
/** Receive callback
|
/** Receive callback
|
||||||
@@ -172,7 +189,7 @@ typedef void (*FuriHalSerialDmaRxCallback)(
|
|||||||
void* context);
|
void* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enable an input/output directon
|
* @brief Enable an input/output direction
|
||||||
*
|
*
|
||||||
* Takes over the respective pin by reconfiguring it to
|
* Takes over the respective pin by reconfiguring it to
|
||||||
* the appropriate alternative function.
|
* the appropriate alternative function.
|
||||||
@@ -185,7 +202,7 @@ void furi_hal_serial_enable_direction(
|
|||||||
FuriHalSerialDirection direction);
|
FuriHalSerialDirection direction);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Disable an input/output directon
|
* @brief Disable an input/output direction
|
||||||
*
|
*
|
||||||
* Releases the respective pin by reconfiguring it to
|
* Releases the respective pin by reconfiguring it to
|
||||||
* initial state, making possible its use for other purposes.
|
* initial state, making possible its use for other purposes.
|
||||||
|
|||||||
@@ -19,4 +19,39 @@ typedef enum {
|
|||||||
FuriHalSerialDirectionMax,
|
FuriHalSerialDirectionMax,
|
||||||
} FuriHalSerialDirection;
|
} FuriHalSerialDirection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Actual data bits, i.e. not including start/stop and parity bits
|
||||||
|
* @note 6 data bits are only permitted when parity is enabled
|
||||||
|
* @note 9 data bits are only permitted when parity is disabled
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FuriHalSerialDataBits6,
|
||||||
|
FuriHalSerialDataBits7,
|
||||||
|
FuriHalSerialDataBits8,
|
||||||
|
FuriHalSerialDataBits9,
|
||||||
|
|
||||||
|
FuriHalSerialDataBitsMax,
|
||||||
|
} FuriHalSerialDataBits;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FuriHalSerialParityNone,
|
||||||
|
FuriHalSerialParityEven,
|
||||||
|
FuriHalSerialParityOdd,
|
||||||
|
|
||||||
|
FuriHalSerialParityMax,
|
||||||
|
} FuriHalSerialParity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop bit length
|
||||||
|
* @note LPUART only supports whole stop bit lengths (i.e. 1 and 2, but not 0.5 and 1.5)
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FuriHalSerialStopBits0_5,
|
||||||
|
FuriHalSerialStopBits1,
|
||||||
|
FuriHalSerialStopBits1_5,
|
||||||
|
FuriHalSerialStopBits2,
|
||||||
|
|
||||||
|
FuriHalSerialStopBits2Max,
|
||||||
|
} FuriHalSerialStopBits;
|
||||||
|
|
||||||
typedef struct FuriHalSerialHandle FuriHalSerialHandle;
|
typedef struct FuriHalSerialHandle FuriHalSerialHandle;
|
||||||
|
|||||||
Reference in New Issue
Block a user