diff --git a/lib_nbgl/include/nbgl_obj.h b/lib_nbgl/include/nbgl_obj.h index b9a1a4e26..984f08066 100644 --- a/lib_nbgl/include/nbgl_obj.h +++ b/lib_nbgl/include/nbgl_obj.h @@ -497,6 +497,7 @@ void nbgl_objAllowDrawing(bool enable); void nbgl_objPoolRelease(uint8_t layer); nbgl_obj_t *nbgl_objPoolGet(nbgl_obj_type_t type, uint8_t layer); nbgl_obj_t *nbgl_objPoolGetPrevious(nbgl_obj_t *obj, uint8_t layer); +uint8_t nbgl_objPoolGetId(nbgl_obj_t *obj); int nbgl_objPoolGetArray(nbgl_obj_type_t type, uint8_t nbObjs, uint8_t layer, diff --git a/lib_nbgl/serialization/Makefile b/lib_nbgl/serialization/Makefile index d37cfb7d1..eaffd2b8d 100644 --- a/lib_nbgl/serialization/Makefile +++ b/lib_nbgl/serialization/Makefile @@ -1,9 +1,9 @@ -INC := -I ../include/ -I ../../lib_ux_stax/ +INC := -I . -I ../include DEFINES := -DLINUX_SIMU -DHAVE_LANGUAGE_PACK -DNBGL_GENERATE_DATA_TEST default: generate_data_test.c - gcc $(INC) generate_data_test.c $(DEFINES) ../src/nbgl_serialize.c -o generate_data_test + gcc $(INC) generate_data_test.c $(DEFINES) ../src/nbgl_serialize.c ../src/nbgl_obj_pool.c -o generate_data_test run_test: default ./generate_data_test > data_test.txt diff --git a/lib_nbgl/serialization/README.md b/lib_nbgl/serialization/README.md index 990c65f01..01df40ddf 100644 --- a/lib_nbgl/serialization/README.md +++ b/lib_nbgl/serialization/README.md @@ -5,7 +5,7 @@ Deserialize raw bytes into an Nbgl event: ```python >>> from nbgl_lib import deserialize_nbgl_bytes ->>> data = bytes.fromhex("000601f403e800ff003201000301020403015465737420627574746f6e00") +>>> data = bytes.fromhex("00010501f403e800ff003201000301020403015465737420627574746f6e00") >>> nbgl_event = deserialize_nbgl_bytes(data) >>> nbgl_event NbglDrawObjectEvent(obj=NbglButton(area=NbglArea(width=255, height=50, x0=500, y0=1000, background_color=, bpp=), inner_color=, border_color=, foreground_color=, radius=, font_id=, localized=True, text='Test button')) diff --git a/lib_nbgl/serialization/generate_data_test.c b/lib_nbgl/serialization/generate_data_test.c index c1fe32c56..a76e473fb 100644 --- a/lib_nbgl/serialization/generate_data_test.c +++ b/lib_nbgl/serialization/generate_data_test.c @@ -4,6 +4,17 @@ #include "nbgl_types.h" #include "nbgl_serialize.h" #include "nbgl_obj.h" +#include "nbgl_screen.h" + +static uint8_t const C_leftArrow32px_bitmap[] = { + 0x20, 0x00, 0x20, 0x00, 0x02, 0x4d, 0x00, 0x00, 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, + 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, + 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, 0xe3, 0xf0, 0x32, 0x93, 0x92, + 0x64, 0x83, 0x84, 0x64, 0x73, 0x74, 0x84, 0x63, 0x64, 0xa4, 0x53, 0x54, 0xc4, 0x43, 0x44, + 0xe4, 0x33, 0x34, 0xf0, 0x14, 0x23, 0x24, 0xf0, 0x34, 0x13, 0x14, 0xf0, 0x5b, 0xf0, 0x79, + 0xf0, 0x97, 0xf0, 0xb5, 0xf0, 0xd3, 0xf0, 0xf1, 0xf0, 0x10, +}; +const nbgl_icon_details_t C_leftArrow32px = {32, 32, NBGL_BPP_1, true, C_leftArrow32px_bitmap}; void print_hex(const char *name, uint8_t *buffer, size_t len) { @@ -25,16 +36,32 @@ void run_serialize_and_print(const char *name, nbgl_serialized_event_type_e even #define SERIALIZE_AND_PRINT(obj, event) \ run_serialize_and_print(__FUNCTION__, event, (nbgl_obj_t *) obj) +void test_draw_nbgl_screen() +{ + nbgl_screen_t screen = { + .container.obj.type = SCREEN, + + .container.obj.area.backgroundColor = WHITE, + .container.obj.area.bpp = NBGL_BPP_4, + .container.obj.area.height = 670, + .container.obj.area.width = 400, + .container.obj.area.x0 = 0, + .container.obj.area.y0 = 0, + }; + + SERIALIZE_AND_PRINT(&screen, NBGL_DRAW_OBJ); +} + void test_draw_nbgl_container() { - nbgl_container_t container = {.type = CONTAINER, + nbgl_container_t container = {.obj.type = CONTAINER, - .backgroundColor = DARK_GRAY, - .bpp = NBGL_BPP_4, - .height = 450, - .width = 460, - .x0 = 56, - .y0 = 12, + .obj.area.backgroundColor = DARK_GRAY, + .obj.area.bpp = NBGL_BPP_4, + .obj.area.height = 450, + .obj.area.width = 460, + .obj.area.x0 = 56, + .obj.area.y0 = 12, .layout = VERTICAL, .nbChildren = 4, @@ -45,14 +72,14 @@ void test_draw_nbgl_container() void test_draw_nbgl_text_area() { - nbgl_text_area_t text = {.type = TEXT_AREA, + nbgl_text_area_t text = {.obj.type = TEXT_AREA, - .backgroundColor = DARK_GRAY, - .bpp = NBGL_BPP_4, - .height = 400, - .width = 360, - .x0 = 12, - .y0 = 256, + .obj.area.backgroundColor = DARK_GRAY, + .obj.area.bpp = NBGL_BPP_4, + .obj.area.height = 400, + .obj.area.width = 360, + .obj.area.x0 = 12, + .obj.area.y0 = 256, .textColor = BLACK, .textAlignment = BOTTOM_RIGHT, @@ -67,31 +94,31 @@ void test_draw_nbgl_text_area() void test_draw_nbgl_line() { - nbgl_line_t line = {.type = LINE, - .backgroundColor = WHITE, - .bpp = NBGL_BPP_1, - .height = 267, - .width = 36, - .x0 = 0, - .y0 = 42, - .direction = HORIZONTAL, - .lineColor = DARK_GRAY, - .thickness = 4, - .offset = 2}; + nbgl_line_t line = {.obj.type = LINE, + .obj.area.backgroundColor = WHITE, + .obj.area.bpp = NBGL_BPP_1, + .obj.area.height = 267, + .obj.area.width = 36, + .obj.area.x0 = 0, + .obj.area.y0 = 42, + .direction = HORIZONTAL, + .lineColor = DARK_GRAY, + .thickness = 4, + .offset = 2}; SERIALIZE_AND_PRINT(&line, NBGL_DRAW_OBJ); } void test_draw_nbgl_qr_code() { - nbgl_qrcode_t qr_code = {.type = QR_CODE, + nbgl_qrcode_t qr_code = {.obj.type = QR_CODE, - .backgroundColor = DARK_GRAY, - .bpp = NBGL_BPP_2, - .height = 55, - .width = 66, - .x0 = 400, - .y0 = 300, + .obj.area.backgroundColor = DARK_GRAY, + .obj.area.bpp = NBGL_BPP_2, + .obj.area.height = 55, + .obj.area.width = 66, + .obj.area.x0 = 400, + .obj.area.y0 = 300, .foregroundColor = DARK_GRAY, .text = "fatstacks", @@ -102,14 +129,14 @@ void test_draw_nbgl_qr_code() void test_draw_nbgl_radio() { - nbgl_radio_t radio = {.type = RADIO_BUTTON, + nbgl_radio_t radio = {.obj.type = RADIO_BUTTON, - .backgroundColor = BLACK, - .bpp = NBGL_BPP_4, - .height = 100, - .width = 200, - .x0 = 123, - .y0 = 234, + .obj.area.backgroundColor = BLACK, + .obj.area.bpp = NBGL_BPP_4, + .obj.area.height = 100, + .obj.area.width = 200, + .obj.area.x0 = 123, + .obj.area.y0 = 234, .activeColor = BLACK, .borderColor = DARK_GRAY, @@ -120,14 +147,14 @@ void test_draw_nbgl_radio() void test_draw_nbgl_switch() { - nbgl_switch_t switch_obj = {.type = SWITCH, + nbgl_switch_t switch_obj = {.obj.type = SWITCH, - .backgroundColor = LIGHT_GRAY, - .bpp = NBGL_BPP_1, - .height = 333, - .width = 89, - .x0 = 1, - .y0 = 10000, + .obj.area.backgroundColor = LIGHT_GRAY, + .obj.area.bpp = NBGL_BPP_1, + .obj.area.height = 333, + .obj.area.width = 89, + .obj.area.x0 = 1, + .obj.area.y0 = 10000, .offColor = WHITE, .onColor = BLACK, @@ -138,14 +165,14 @@ void test_draw_nbgl_switch() void test_draw_nbgl_progress_bar() { - nbgl_progress_bar_t progress_bar = {.type = PROGRESS_BAR, + nbgl_progress_bar_t progress_bar = {.obj.type = PROGRESS_BAR, - .backgroundColor = BLACK, - .bpp = NBGL_BPP_1, - .height = 10000, - .width = 11000, - .x0 = 12000, - .y0 = 13000, + .obj.area.backgroundColor = BLACK, + .obj.area.bpp = NBGL_BPP_1, + .obj.area.height = 10000, + .obj.area.width = 11000, + .obj.area.x0 = 12000, + .obj.area.y0 = 13000, .withBorder = true, .state = 91}; @@ -155,14 +182,14 @@ void test_draw_nbgl_progress_bar() void test_draw_nbgl_page_indicator() { - nbgl_page_indicator_t page_indicator = {.type = PAGE_INDICATOR, + nbgl_page_indicator_t page_indicator = {.obj.type = PAGE_INDICATOR, - .backgroundColor = BLACK, - .bpp = NBGL_BPP_2, - .height = 11, - .width = 22, - .x0 = 33, - .y0 = 44, + .obj.area.backgroundColor = BLACK, + .obj.area.bpp = NBGL_BPP_2, + .obj.area.height = 11, + .obj.area.width = 22, + .obj.area.x0 = 33, + .obj.area.y0 = 44, .activePage = 2, .nbPages = 10}; @@ -173,14 +200,14 @@ void test_draw_nbgl_page_indicator() void test_draw_nbgl_button() { nbgl_button_t button = { - .type = BUTTON, + .obj.type = BUTTON, - .backgroundColor = DARK_GRAY, - .bpp = NBGL_BPP_1, - .height = 50, - .width = 255, - .x0 = 500, - .y0 = 1000, + .obj.area.backgroundColor = DARK_GRAY, + .obj.area.bpp = NBGL_BPP_1, + .obj.area.height = 50, + .obj.area.width = 255, + .obj.area.x0 = 500, + .obj.area.y0 = 1000, .innerColor = WHITE, .borderColor = DARK_GRAY, @@ -196,16 +223,17 @@ void test_draw_nbgl_button() void test_draw_nbgl_image() { - nbgl_image_t image = {.type = IMAGE, + nbgl_image_t image = {.obj.type = IMAGE, - .backgroundColor = WHITE, - .bpp = NBGL_BPP_2, - .height = 101, - .width = 201, - .x0 = 124, - .y0 = 235, + .obj.area.backgroundColor = WHITE, + .obj.area.bpp = NBGL_BPP_1, + .obj.area.height = 32, + .obj.area.width = 32, + .obj.area.x0 = 124, + .obj.area.y0 = 235, - .foregroundColor = DARK_GRAY}; + .foregroundColor = DARK_GRAY, + .buffer = &C_leftArrow32px}; SERIALIZE_AND_PRINT(&image, NBGL_DRAW_OBJ); } @@ -213,19 +241,19 @@ void test_draw_nbgl_image() void test_draw_nbgl_keyboard() { nbgl_keyboard_t keyboard = { - .type = KEYBOARD, + .obj.type = KEYBOARD, - .backgroundColor = LIGHT_GRAY, - .bpp = NBGL_BPP_2, - .height = 210, - .width = 225, - .x0 = 332, - .y0 = 431, + .obj.area.backgroundColor = LIGHT_GRAY, + .obj.area.bpp = NBGL_BPP_2, + .obj.area.height = 210, + .obj.area.width = 225, + .obj.area.x0 = 332, + .obj.area.y0 = 431, .textColor = WHITE, .borderColor = BLACK, .lettersOnly = true, - .upperCase = false, + .casing = 0, .mode = MODE_DIGITS, .keyMask = 0x12345678, }; @@ -235,33 +263,35 @@ void test_draw_nbgl_keyboard() void test_draw_nbgl_keypad() { - nbgl_keypad_t keypad = {.type = KEYPAD, + nbgl_keypad_t keypad = {.obj.type = KEYPAD, - .backgroundColor = WHITE, - .bpp = NBGL_BPP_4, - .height = 4, - .width = 4, - .x0 = 3, - .y0 = 4, + .obj.area.backgroundColor = WHITE, + .obj.area.bpp = NBGL_BPP_4, + .obj.area.height = 4, + .obj.area.width = 4, + .obj.area.x0 = 3, + .obj.area.y0 = 4, .textColor = WHITE, .borderColor = BLACK, .enableBackspace = true, - .enableValidate = false}; + .enableValidate = false, + .enableDigits = true, + .shuffled = false}; SERIALIZE_AND_PRINT(&keypad, NBGL_DRAW_OBJ); } void test_draw_nbgl_spinner() { - nbgl_spinner_t spinner = {.type = SPINNER, + nbgl_spinner_t spinner = {.obj.type = SPINNER, - .backgroundColor = LIGHT_GRAY, - .bpp = NBGL_BPP_1, - .height = 14, - .width = 25, - .x0 = 12, - .y0 = 10, + .obj.area.backgroundColor = LIGHT_GRAY, + .obj.area.bpp = NBGL_BPP_1, + .obj.area.height = 14, + .obj.area.width = 25, + .obj.area.x0 = 12, + .obj.area.y0 = 10, .position = 2}; @@ -271,14 +301,14 @@ void test_draw_nbgl_spinner() void test_draw_nbgl_image_file() { nbgl_image_file_t image_file = { - .type = IMAGE_FILE, - - .backgroundColor = DARK_GRAY, - .bpp = NBGL_BPP_4, - .height = 24, - .width = 35, - .x0 = 22, - .y0 = 20, + .obj.type = IMAGE_FILE, + + .obj.area.backgroundColor = DARK_GRAY, + .obj.area.bpp = NBGL_BPP_4, + .obj.area.height = 24, + .obj.area.width = 35, + .obj.area.x0 = 22, + .obj.area.y0 = 20, }; SERIALIZE_AND_PRINT(&image_file, NBGL_DRAW_OBJ); @@ -300,6 +330,7 @@ void test_refresh_area() int main() { + test_draw_nbgl_screen(); test_draw_nbgl_container(); test_draw_nbgl_line(); test_draw_nbgl_text_area(); diff --git a/lib_nbgl/serialization/nbgl_lib.py b/lib_nbgl/serialization/nbgl_lib.py index 7e767c79d..a69e55fc4 100644 --- a/lib_nbgl/serialization/nbgl_lib.py +++ b/lib_nbgl/serialization/nbgl_lib.py @@ -56,22 +56,20 @@ class NbglKeyboardMode(IntEnum): class NbglObjType(IntEnum): SCREEN, = 0, # Main screen CONTAINER, = 1, # Empty container - PANEL, = 2, # Container with special border - IMAGE, = 3, # Bitmap (x and width must be multiple of 4) - LINE, = 4, # Vertical or Horizontal line - TEXT_AREA, = 5, # Area to contain text line(s) - BUTTON, = 6, # Rounded rectangle button with icon and/or text - SWITCH, = 7, # Switch to turn on/off something - PAGE_INDICATOR, = 8, # horizontal bar to indicate navigation across pages - # horizontal bar to indicate progression of something (between 0% and 100%) - PROGRESS_BAR, = 9, - RADIO_BUTTON, = 10, # Indicator to inform whether something is on or off - # Notification bar, to inform user about alarm... only for internal usage - QR_CODE, = 11, # QR Code - KEYBOARD, = 12, # Keyboard - KEYPAD, = 13, # Keypad - SPINNER, = 14, # Spinner - IMAGE_FILE = 15, # Image file (with Ledger compression) + IMAGE, = 2, # Bitmap (x and width must be multiple of 4) + LINE, = 3, # Vertical or Horizontal line + TEXT_AREA, = 4, # Area to contain text line(s) + BUTTON, = 5, # Rounded rectangle button with icon and/or text + SWITCH, = 6, # Switch to turn on/off something + PAGE_INDICATOR, = 7, # horizontal bar to indicate navigation across pages + + PROGRESS_BAR, = 8, # horizontal bar to indicate progression of something (between 0% and 100%) + RADIO_BUTTON, = 9, # Indicator to inform whether something is on or off + QR_CODE, = 10, # QR Code + KEYBOARD, = 11, # Keyboard + KEYPAD, = 12, # Keypad + SPINNER, = 13, # Spinner + IMAGE_FILE = 14, # Image file (with Ledger compression) class NbglAlignment(IntEnum): @@ -96,6 +94,9 @@ class NbglFontId(IntEnum): BAGL_FONT_INTER_SEMIBOLD_24px = 1, BAGL_FONT_INTER_MEDIUM_32px = 2, BAGL_FONT_HM_ALPHA_MONO_MEDIUM_32px = 3 + BAGL_FONT_INTER_REGULAR_24px_1bpp = 4 + BAGL_FONT_INTER_SEMIBOLD_24px_1bpp = 5 + BAGL_FONT_INTER_MEDIUM_32px_1bpp = 6 class NbglStyle(IntEnum): @@ -183,7 +184,7 @@ class NbglArea(NbglObj): @classmethod def from_bytes(cls, data: bytes): - x0, y0, width, height, color_n, bpp_n = struct.unpack('>HHHHBB', data) + x0, y0, width, height, color_n, bpp_n = struct.unpack('>HHHHBB', data[:10]) color = NbglColor(color_n) bpp = NbglBpp(bpp_n) return cls(width, height, x0, y0, color, bpp) @@ -193,6 +194,18 @@ def size(): return struct.calcsize('>HHHHBB') +@dataclass +class NbglScreen(NbglObj): + area: NbglArea + + @classmethod + def from_bytes(cls, data: bytes): + area = NbglArea.from_bytes(data[0:NbglArea.size()]) + return cls( + area=area + ) + + @dataclass class NbglContainer(NbglObj): area: NbglArea @@ -405,14 +418,25 @@ def from_bytes(cls, data: bytes): @dataclass class NbglImage(NbglObj): area: NbglArea + width: int + height: int + bpp: int + isFile: int foreground_color: NbglColor @classmethod def from_bytes(cls, data): + area = NbglArea.from_bytes(data[0:NbglArea.size()]) - foreground_color, = struct.unpack('>B', data[NbglArea.size():]) + + width,height,bpp,isFile,size, = struct.unpack('>HHBBI', data[NbglArea.size():NbglArea.size()+10]) + foreground_color, = struct.unpack('>B', data[NbglArea.size()+10:]) return cls( area=area, + width=width, + height=height, + bpp=bpp, + isFile=isFile, foreground_color=NbglColor(foreground_color) ) @@ -488,23 +512,28 @@ class NbglKeypad(NbglObj): border_color: NbglColor enable_backspace: bool enable_validate: bool + enable_digits: bool + shuffled:bool @classmethod def from_bytes(cls, data: bytes): area = NbglArea.from_bytes(data[0:NbglArea.size()]) - text_color, border_color, enable_backspace, enable_validate = struct.unpack( - '>BBBB', data[NbglArea.size():]) + text_color, border_color, enable_backspace, enable_validate, enable_digits, shuffled = \ + struct.unpack('>BBBBBB', data[NbglArea.size():NbglArea.size()+6]) return cls( area=area, text_color=NbglColor(text_color), border_color=NbglColor(border_color), enable_backspace=enable_backspace, - enable_validate=enable_validate + enable_validate=enable_validate, + enable_digits=enable_digits, + shuffled=shuffled ) # Mapping of NbglObjType and their associated class. NBGL_OBJ_TYPES = { + NbglObjType.SCREEN: NbglScreen, NbglObjType.CONTAINER: NbglContainer, NbglObjType.LINE: NbglLine, NbglObjType.IMAGE: NbglImage, @@ -549,11 +578,13 @@ class NbglDrawObjectEvent(NbglGenericJsonSerializable): @classmethod def from_bytes(cls, data: bytes): - obj_type = NbglObjType(data[0]) + # the first byte is the object id + # the second one is the object type + obj_type = NbglObjType(data[1]) class_type = NBGL_OBJ_TYPES[obj_type] return cls( - obj=class_type.from_bytes(data[1:]) + obj=class_type.from_bytes(data[2:]) ) def to_json_dict(self) -> Dict: diff --git a/lib_nbgl/serialization/test_bytes_deserialize.py b/lib_nbgl/serialization/test_bytes_deserialize.py index 2d80b6826..28fb8b831 100644 --- a/lib_nbgl/serialization/test_bytes_deserialize.py +++ b/lib_nbgl/serialization/test_bytes_deserialize.py @@ -1,4 +1,3 @@ -from turtle import back from nbgl_lib import * import pytest @@ -17,6 +16,26 @@ def run_deserialize_nbgl(hex_str: str): return deserialize_nbgl_bytes(bytes_in) +def test_draw_nbgl_screen(data_test): + serialized = data_test["test_draw_nbgl_screen"] + deserialized = run_deserialize_nbgl(serialized) + expected = \ + NbglDrawObjectEvent( + obj=NbglScreen( + area=NbglArea( + background_color=NbglColor.WHITE, + bpp=NbglBpp.BPP_4, + height=670, + width=400, + x0=0, + y0=0 + ) + ) + ) + + assert deserialized == expected + + def test_draw_nbgl_container(data_test): serialized = data_test["test_draw_nbgl_container"] deserialized = run_deserialize_nbgl(serialized) @@ -231,12 +250,16 @@ def test_draw_nbgl_image(data_test): obj=NbglImage( area=NbglArea( background_color=NbglColor.WHITE, - bpp=NbglBpp.BPP_2, - height=101, - width=201, + bpp=NbglBpp.BPP_1, + height=32, + width=32, x0=124, y0=235 ), + height=32, + width=32, + bpp=0, + isFile=1, foreground_color=NbglColor.DARK_GRAY ) ) @@ -285,7 +308,9 @@ def test_draw_nbgl_keypad(data_test): text_color=NbglColor.WHITE, border_color=NbglColor.BLACK, enable_backspace=True, - enable_validate=False + enable_validate=False, + enable_digits=True, + shuffled=False ) ) assert deserialized == expected diff --git a/lib_nbgl/serialization/test_json_ser_deser.py b/lib_nbgl/serialization/test_json_ser_deser.py index ca9cba077..0c52da0e9 100644 --- a/lib_nbgl/serialization/test_json_ser_deser.py +++ b/lib_nbgl/serialization/test_json_ser_deser.py @@ -3,6 +3,41 @@ import pytest +def test_json_deserialize_screen(): + serialized = { + 'event': 'NBGL_DRAW_OBJ', + 'obj': { + 'type': 'SCREEN', + 'content': { + 'area': { + 'width': 400, + 'height': 670, + 'x0': 0, + 'y0': 0, + 'background_color': 'WHITE', + 'bpp': 'BPP_4' + } + } + } + } + deserialized = \ + NbglDrawObjectEvent( + obj=NbglScreen( + area=NbglArea( + width=400, + height=670, + x0=0, + y0=0, + background_color=NbglColor.WHITE, + bpp=NbglBpp.BPP_4 + ) + ) + + ) + + assert serialize_nbgl_json(deserialized) == serialized + assert deserialized == deserialize_nbgl_json(serialized) + def test_json_deserialize_container(): serialized = { 'event': 'NBGL_DRAW_OBJ', @@ -396,6 +431,10 @@ def test_json_deserialize_image(): 'background_color': 'BLACK', 'bpp': 'BPP_2' }, + 'height':35, + 'width':36, + 'bpp':2, + 'isFile':1, 'foreground_color': 'WHITE' } } @@ -411,6 +450,10 @@ def test_json_deserialize_image(): background_color=NbglColor.BLACK, bpp=NbglBpp.BPP_2 ), + height=35, + width=36, + bpp=2, + isFile=1, foreground_color=NbglColor.WHITE ) ) @@ -558,7 +601,9 @@ def test_json_deserialize_keypad(): 'text_color': 'WHITE', 'border_color': 'LIGHT_GRAY', 'enable_backspace': True, - 'enable_validate': False + 'enable_validate': False, + 'enable_digits': True, + 'shuffled': False } } } @@ -576,7 +621,9 @@ def test_json_deserialize_keypad(): text_color=NbglColor.WHITE, border_color=NbglColor.LIGHT_GRAY, enable_backspace=True, - enable_validate=False + enable_validate=False, + enable_digits=True, + shuffled=False ) ) diff --git a/lib_nbgl/serialization/ux_loc.h b/lib_nbgl/serialization/ux_loc.h new file mode 100644 index 000000000..010970af1 --- /dev/null +++ b/lib_nbgl/serialization/ux_loc.h @@ -0,0 +1,3 @@ +#pragma once + +typedef unsigned short UX_LOC_STRINGS_INDEX; diff --git a/lib_nbgl/src/nbgl_obj.c b/lib_nbgl/src/nbgl_obj.c index 9afe3d5e4..de2bccab2 100644 --- a/lib_nbgl/src/nbgl_obj.c +++ b/lib_nbgl/src/nbgl_obj.c @@ -11,10 +11,10 @@ #include "nbgl_draw.h" #include "nbgl_front.h" #include "nbgl_debug.h" -#include "nbgl_serialize.h" #include "os_print.h" #include "glyphs.h" #ifdef HAVE_SERIALIZED_NBGL +#include "nbgl_serialize.h" #include "os_io_seproxyhal.h" #endif @@ -39,7 +39,7 @@ void extendRefreshArea(nbgl_obj_t *obj); static nbgl_area_t refreshArea; // boolean used to enable/forbid drawing/refresh -bool objDrawingDisabled; +static bool objDrawingDisabled; /********************** * VARIABLES diff --git a/lib_nbgl/src/nbgl_obj_pool.c b/lib_nbgl/src/nbgl_obj_pool.c index 5d8e309a6..13948d10e 100644 --- a/lib_nbgl/src/nbgl_obj_pool.c +++ b/lib_nbgl/src/nbgl_obj_pool.c @@ -198,6 +198,21 @@ nbgl_obj_t *nbgl_objPoolGetPrevious(nbgl_obj_t *obj, uint8_t layer) return NULL; } +/** + * @brief Gets a unique index for the given object, in the pool + * @param obj object to get id from + * @return an unique index of the object + */ +uint8_t nbgl_objPoolGetId(nbgl_obj_t *obj) +{ + uint8_t index; + + // retrieve object index + index = (genericObj_t *) obj - objPool; + + return index; +} + /** * @brief Gets nbObjects new graphic object from the pool, with the given type, for the given layer * (screen). The type field of the object is set. diff --git a/lib_nbgl/src/nbgl_serialize.c b/lib_nbgl/src/nbgl_serialize.c index 85c1acc65..441a63f89 100644 --- a/lib_nbgl/src/nbgl_serialize.c +++ b/lib_nbgl/src/nbgl_serialize.c @@ -1,5 +1,8 @@ +#include +#include #include "nbgl_obj.h" #include "nbgl_serialize.h" +#include "nbgl_image_utils.h" // Utility functions @@ -19,17 +22,22 @@ static void nbgl_appendU32(uint32_t value, uint8_t *out, size_t *w_cnt, size_t m nbgl_appendU8((uint8_t) (value & 0xFF), out, w_cnt, max_len); } -static void nbgl_appendU16(uint16_t value, uint8_t *out, size_t *w_cnt, size_t max_len) +static void nbgl_appendPtr(void *value, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_appendU8((uint8_t) ((value >> 8) & 0xFF), out, w_cnt, max_len); - nbgl_appendU8((uint8_t) (value & 0xFF), out, w_cnt, max_len); + if (max_len < (*w_cnt + sizeof(void *))) { + return; + } + memcpy(&out[*w_cnt], &value, sizeof(void *)); + (*w_cnt) = (*w_cnt) + sizeof(void *); } -static void nbgl_serializeType(nbgl_obj_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) +static void nbgl_appendU16(uint16_t value, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_appendU8((uint8_t) obj->type, out, w_cnt, max_len); + nbgl_appendU8((uint8_t) ((value >> 8) & 0xFF), out, w_cnt, max_len); + nbgl_appendU8((uint8_t) (value & 0xFF), out, w_cnt, max_len); } +// serialize a nbgl_area_t structure static void nbgl_serializeArea(nbgl_area_t *area, uint8_t *out, size_t *w_cnt, size_t max_len) { nbgl_appendU16(area->x0, out, w_cnt, max_len); @@ -40,6 +48,27 @@ static void nbgl_serializeArea(nbgl_area_t *area, uint8_t *out, size_t *w_cnt, s nbgl_appendU8((uint8_t) area->bpp, out, w_cnt, max_len); } +static uint8_t getObjId(nbgl_obj_t *obj) +{ + if (obj->type != SCREEN) { + // return the internal offset + 1 + return nbgl_objPoolGetId(obj) + 1; + } + // no ID for screen, because it's not a real object, and not taken from pool + return 0; +} + +// serialize a nbgl_obj_t structure (including nbgl_area_t) +static void nbgl_serializeObj(nbgl_obj_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) +{ + // at first serialize an id + nbgl_appendU8(getObjId(obj), out, w_cnt, max_len); + // the only field to be serialized is the object type + nbgl_appendU8((uint8_t) obj->type, out, w_cnt, max_len); + // then serialize the area + nbgl_serializeArea((nbgl_area_t *) &obj->area, out, w_cnt, max_len); +} + // Serialization functions static void nbgl_serializeText(const char *text, uint8_t *out, size_t *w_cnt, size_t max_len) @@ -61,13 +90,97 @@ static void nbgl_serializeText(const char *text, uint8_t *out, size_t *w_cnt, si } } +/** + * Mapping of nbgl_bpp_t type and their associated driver configuration + * and actual number of bit per pixel. + */ +static const uint8_t NBGL_BPP_MAPPING[NB_NBGL_BPP] + = {[NBGL_BPP_1] = 1, [NBGL_BPP_2] = 2, [NBGL_BPP_4] = 4}; + +/** + * @brief Returns the number of bits per pixel associated to the input nbgl_bpp + * @param nbgl_bpp Input nbgl_bpp + * + * @return + * - Number of bits per pixel if nbgl_bpp is valid + * - -1 otherwise + */ +static int8_t nbgl_bpp_get_number_of_bits_per_pixel(nbgl_bpp_t nbgl_bpp) +{ + if (nbgl_bpp >= NB_NBGL_BPP) { + return -1; + } + + return NBGL_BPP_MAPPING[nbgl_bpp]; +} + +/** + * @brief Calculate the size in bytes of a window + * @param width Width of the input window + * @param height Height of the input window + * @param nbgl_bpp Bpp of the input window + * + * @return + * - Window size if parameters are correct + * - (-1) otherwise + */ +static int32_t nbgl_bpp_get_window_size(uint16_t width, uint16_t height, nbgl_bpp_t nbgl_bpp) +{ + if ((width > SCREEN_WIDTH) || (height > SCREEN_HEIGHT) || (nbgl_bpp >= NB_NBGL_BPP)) { + return -1; + } + + int32_t nb_bits = (width * height * nbgl_bpp_get_number_of_bits_per_pixel(nbgl_bpp)); + uint8_t remain = nb_bits % 8; + + // Ceil division to ensure the output number of bytes contains + // all the bits of the window. + if (remain == 0) { + return nb_bits / 8; + } + else { + return (nb_bits + (8 - remain)) / 8; + } +} + +static void nbgl_serializeIcon(const nbgl_icon_details_t *icon, + uint8_t *out, + size_t *w_cnt, + size_t max_len) +{ + int32_t size = 0; + if (icon == NULL) { + nbgl_appendU16(0, out, w_cnt, max_len); + nbgl_appendU16(0, out, w_cnt, max_len); + nbgl_appendU8(0, out, w_cnt, max_len); + nbgl_appendU8(0, out, w_cnt, max_len); + } + else { + nbgl_appendU16(icon->width, out, w_cnt, max_len); + nbgl_appendU16(icon->height, out, w_cnt, max_len); + nbgl_appendU8(icon->bpp, out, w_cnt, max_len); + nbgl_appendU8(icon->isFile, out, w_cnt, max_len); + if (!icon->isFile) { + size = nbgl_bpp_get_window_size(icon->width, icon->height, icon->bpp); + } + else { + size = GET_IMAGE_FILE_BUFFER_LEN(icon->bitmap) + IMAGE_FILE_HEADER_SIZE; + } + } + nbgl_appendU32(size, out, w_cnt, max_len); +#ifdef SERIALIZE_DATA + for (int32_t i = 0; i < size; i++) { + nbgl_appendU8(icon->bitmap[i], out, w_cnt, max_len); + } +#endif // SERIALIZE_DATA +} + static void nbgl_serializeTextArea(nbgl_text_area_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->textColor, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->textAlignment, out, w_cnt, max_len); @@ -81,8 +194,7 @@ static void nbgl_serializeTextArea(nbgl_text_area_t *obj, static void nbgl_serializeLine(nbgl_line_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->direction, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->lineColor, out, w_cnt, max_len); @@ -92,8 +204,7 @@ static void nbgl_serializeLine(nbgl_line_t *obj, uint8_t *out, size_t *w_cnt, si static void nbgl_serializeQrCode(nbgl_qrcode_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->foregroundColor, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->version, out, w_cnt, max_len); @@ -102,8 +213,7 @@ static void nbgl_serializeQrCode(nbgl_qrcode_t *obj, uint8_t *out, size_t *w_cnt static void nbgl_serializeRadio(nbgl_radio_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->activeColor, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->borderColor, out, w_cnt, max_len); @@ -112,8 +222,7 @@ static void nbgl_serializeRadio(nbgl_radio_t *obj, uint8_t *out, size_t *w_cnt, static void nbgl_serializeSwitch(nbgl_switch_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->onColor, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->offColor, out, w_cnt, max_len); @@ -125,20 +234,18 @@ static void nbgl_serializeProgressBar(nbgl_progress_bar_t *obj, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->withBorder, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->state, out, w_cnt, max_len); } -static void nbgl_serializeNavigationBar(nbgl_page_indicator_t *obj, +static void nbgl_serializePageIndicator(nbgl_page_indicator_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->activePage, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->nbPages, out, w_cnt, max_len); @@ -146,8 +253,7 @@ static void nbgl_serializeNavigationBar(nbgl_page_indicator_t *obj, static void nbgl_serializeButton(nbgl_button_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->innerColor, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->borderColor, out, w_cnt, max_len); @@ -156,21 +262,19 @@ static void nbgl_serializeButton(nbgl_button_t *obj, uint8_t *out, size_t *w_cnt nbgl_appendU8((uint8_t) obj->fontId, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->localized, out, w_cnt, max_len); nbgl_serializeText(obj->text, out, w_cnt, max_len); + nbgl_serializeIcon((void *) obj->icon, out, w_cnt, max_len); } static void nbgl_serializeImage(nbgl_image_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); - + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); + nbgl_serializeIcon((void *) obj->buffer, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->foregroundColor, out, w_cnt, max_len); } static void nbgl_serializeSpinner(nbgl_spinner_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); - + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8(obj->position, out, w_cnt, max_len); } @@ -179,8 +283,7 @@ static void nbgl_serializeKeyboard(nbgl_keyboard_t *obj, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->textColor, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->borderColor, out, w_cnt, max_len); @@ -192,13 +295,19 @@ static void nbgl_serializeKeyboard(nbgl_keyboard_t *obj, static void nbgl_serializeKeypad(nbgl_keypad_t *obj, uint8_t *out, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->textColor, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->borderColor, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->enableBackspace, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->enableValidate, out, w_cnt, max_len); + nbgl_appendU8((uint8_t) obj->enableDigits, out, w_cnt, max_len); + nbgl_appendU8((uint8_t) obj->shuffled, out, w_cnt, max_len); + nbgl_appendU8((uint8_t) obj->digitIndexes[0], out, w_cnt, max_len); + nbgl_appendU8((uint8_t) obj->digitIndexes[1], out, w_cnt, max_len); + nbgl_appendU8((uint8_t) obj->digitIndexes[2], out, w_cnt, max_len); + nbgl_appendU8((uint8_t) obj->digitIndexes[3], out, w_cnt, max_len); + nbgl_appendU8((uint8_t) obj->digitIndexes[4], out, w_cnt, max_len); } static void nbgl_serializeImageFile(nbgl_image_file_t *obj, @@ -206,8 +315,8 @@ static void nbgl_serializeImageFile(nbgl_image_file_t *obj, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); + nbgl_appendPtr((void *) obj->buffer, out, w_cnt, max_len); } static void nbgl_serializeContainer(nbgl_container_t *obj, @@ -215,8 +324,7 @@ static void nbgl_serializeContainer(nbgl_container_t *obj, size_t *w_cnt, size_t max_len) { - nbgl_serializeType((nbgl_obj_t *) obj, out, w_cnt, max_len); - nbgl_serializeArea((nbgl_area_t *) obj, out, w_cnt, max_len); + nbgl_serializeObj((nbgl_obj_t *) &obj->obj, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->layout, out, w_cnt, max_len); nbgl_appendU8((uint8_t) obj->nbChildren, out, w_cnt, max_len); @@ -227,7 +335,8 @@ static uint8_t nbgl_serializeObject(nbgl_obj_t *obj, uint8_t *out, size_t *w_cnt { switch (obj->type) { case SCREEN: - return NBGL_SERIALIZE_ERROR; + nbgl_serializeObj((nbgl_obj_t *) obj, out, w_cnt, max_len); + break; case CONTAINER: nbgl_serializeContainer((nbgl_container_t *) obj, out, w_cnt, max_len); break; @@ -247,7 +356,7 @@ static uint8_t nbgl_serializeObject(nbgl_obj_t *obj, uint8_t *out, size_t *w_cnt nbgl_serializeSwitch((nbgl_switch_t *) obj, out, w_cnt, max_len); break; case PAGE_INDICATOR: - nbgl_serializeNavigationBar((nbgl_page_indicator_t *) obj, out, w_cnt, max_len); + nbgl_serializePageIndicator((nbgl_page_indicator_t *) obj, out, w_cnt, max_len); break; case PROGRESS_BAR: nbgl_serializeProgressBar((nbgl_progress_bar_t *) obj, out, w_cnt, max_len);