From 1a39656ff0191a38beacf656d1ac8f7dcee628fa Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Tue, 29 Jun 2021 13:24:11 +0200 Subject: [PATCH] LVGL Prepare last phase custom types --- lib/libesp32/Berry/src/be_byteslib.c | 356 ++++++++++++++- lib/libesp32/Berry/src/be_solidifylib.c | 2 +- lib/libesp32/Berry/tests/bytes.be | 30 ++ tasmota/berry/modules/ctypes.be | 563 ++++++++++++++++++++++++ tasmota/berry/modules/lvgl_ctypes.be | 315 +++++++++++++ tasmota/xdrv_52_3_berry_lvgl_ctypes.ino | 318 +++++++++++++ 6 files changed, 1567 insertions(+), 17 deletions(-) create mode 100644 tasmota/berry/modules/ctypes.be create mode 100644 tasmota/berry/modules/lvgl_ctypes.be create mode 100644 tasmota/xdrv_52_3_berry_lvgl_ctypes.ino diff --git a/lib/libesp32/Berry/src/be_byteslib.c b/lib/libesp32/Berry/src/be_byteslib.c index f26fe1909..1227f4bca 100644 --- a/lib/libesp32/Berry/src/be_byteslib.c +++ b/lib/libesp32/Berry/src/be_byteslib.c @@ -13,6 +13,7 @@ #include "be_exec.h" #include "be_vm.h" #include "be_mem.h" +#include "be_constobj.h" #include #include @@ -47,13 +48,6 @@ static void buf_set_len(buf_impl* buf, const size_t len) } } -static void buf_set1(buf_impl* buf, const size_t offset, const uint8_t data) -{ - if (offset < buf->len) { - buf->buf[offset] = data; - } -} - static size_t buf_add1(buf_impl* buf, const uint8_t data) // append 8 bits value { if (buf->len < buf->size) { // do we have room for 1 byte @@ -120,7 +114,31 @@ static uint8_t buf_get1(buf_impl* buf, int offset) return 0; } -static uint16_t buf_get2_le(buf_impl* buf, int offset) { +static void buf_set1(buf_impl* buf, const size_t offset, const uint8_t data) +{ + if (offset < buf->len) { + buf->buf[offset] = data; + } +} + +static void buf_set2_le(buf_impl* buf, const size_t offset, const uint16_t data) +{ + if ((offset >= 0) && (offset < buf->len - 1)) { + buf->buf[offset] = data & 0xFF; + buf->buf[offset+1] = data >> 8; + } +} + +static void buf_set2_be(buf_impl* buf, const size_t offset, const uint16_t data) +{ + if ((offset >= 0) && (offset < buf->len - 1)) { + buf->buf[offset+1] = data & 0xFF; + buf->buf[offset] = data >> 8; + } +} + +static uint16_t buf_get2_le(buf_impl* buf, int offset) +{ if ((offset >= 0) && (offset < buf->len - 1)) { return buf->buf[offset] | (buf->buf[offset+1] << 8); } @@ -135,6 +153,26 @@ static uint16_t buf_get2_be(buf_impl* buf, int offset) return 0; } +static void buf_set4_le(buf_impl* buf, const size_t offset, const uint32_t data) +{ + if ((offset >= 0) && (offset < buf->len - 3)) { + buf->buf[offset] = data & 0xFF; + buf->buf[offset+1] = (data >> 8) & 0xFF; + buf->buf[offset+2] = (data >> 16) & 0xFF; + buf->buf[offset+3] = data >> 24; + } +} + +static void buf_set4_be(buf_impl* buf, const size_t offset, const uint32_t data) +{ + if ((offset >= 0) && (offset < buf->len - 3)) { + buf->buf[offset+3] = data & 0xFF; + buf->buf[offset+2] = (data >> 8) & 0xFF; + buf->buf[offset+1] = (data >> 16) & 0xFF; + buf->buf[offset] = data >> 24; + } +} + static uint32_t buf_get4_le(buf_impl* buf, int offset) { if ((offset >= 0) && (offset < buf->len - 3)) { @@ -383,13 +421,13 @@ static int m_add(bvm *vm) /* * Get an int made of 1, 2 or 4 bytes, in little or big endian - * `get(index:int[, size:int = 1]) -> instance` + * `get(index:int[, size:int = 1]) -> int` * * size: may be 1, 2, 4 (little endian), or -1, -2, -4 (big endian) - * obvisouly -1 is idntical to 1 + * obvisouly -1 is identical to 1 * 0 returns nil */ -static int m_get(bvm *vm) +static int m_get(bvm *vm, bbool sign) { int argc = be_top(vm); buf_impl * buf = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ @@ -403,10 +441,16 @@ static int m_get(bvm *vm) switch (vsize) { case 0: break; case -1: /* fallback below */ - case 1: ret = buf_get1(buf, idx); break; - case 2: ret = buf_get2_le(buf, idx); break; + case 1: ret = buf_get1(buf, idx); + if (sign) { ret = (int8_t)(uint8_t) ret; } + break; + case 2: ret = buf_get2_le(buf, idx); + if (sign) { ret = (int16_t)(uint16_t) ret; } + break; case 4: ret = buf_get4_le(buf, idx); break; - case -2: ret = buf_get2_be(buf, idx); break; + case -2: ret = buf_get2_be(buf, idx); + if (sign) { ret = (int16_t)(uint16_t) ret; } + break; case -4: ret = buf_get4_be(buf, idx); break; default: be_raise(vm, "type_error", "size must be -4, -2, -1, 0, 1, 2 or 4."); } @@ -421,6 +465,53 @@ static int m_get(bvm *vm) be_return_nil(vm); } +/* signed int */ +static int m_geti(bvm *vm) +{ + return m_get(vm, 1); +} + +/* unsigned int */ +static int m_getu(bvm *vm) +{ + return m_get(vm, 0); +} + +/* + * Set an int made of 1, 2 or 4 bytes, in little or big endian + * `set(index:int, value:int[, size:int = 1]) -> nil` + * + * size: may be 1, 2, 4 (little endian), or -1, -2, -4 (big endian) + * obvisouly -1 is identical to 1 + * 0 returns nil + */ +static int m_set(bvm *vm) +{ + int argc = be_top(vm); + buf_impl * buf = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ + if (argc >=3 && be_isint(vm, 2) && be_isint(vm, 3)) { + int32_t idx = be_toint(vm, 2); + int32_t value = be_toint(vm, 3); + int vsize = 1; + if (argc >= 4 && be_isint(vm, 4)) { + vsize = be_toint(vm, 4); + } + switch (vsize) { + case 0: break; + case -1: /* fallback below */ + case 1: buf_set1(buf, idx, value); break; + case 2: buf_set2_le(buf, idx, value); break; + case 4: buf_set4_le(buf, idx, value); break; + case -2: buf_set2_be(buf, idx, value); break; + case -4: buf_set4_be(buf, idx, value); break; + default: be_raise(vm, "type_error", "size must be -4, -2, -1, 0, 1, 2 or 4."); + } + be_pop(vm, argc - 1); + be_return_nil(vm); + } + be_return_nil(vm); +} + static int m_setitem(bvm *vm) { int argc = be_top(vm); @@ -608,6 +699,26 @@ static int m_nequal(bvm *vm) return bytes_equal(vm, bfalse); } +/* + * Advanced API + */ + +/* + * Retrieve the memory address of the raw buffer + * to be used in C functions. + * + * Note: the address is guaranteed not to move unless you + * resize the buffer + * + * `_buffer() -> comptr` + */ +static int m_buffer(bvm *vm) +{ + buf_impl * buf = bytes_check_data(vm, 0); + be_pushcomptr(vm, &buf->buf); + be_return(vm); +} + /* * External API */ @@ -642,17 +753,219 @@ BERRY_API const void *be_tobytes(bvm *vm, int rel_index, size_t *len) return NULL; } +/* Helper code to compile bytecode + + +class Bytes : bytes +#------------------------------------------------------------- +#- 'getbits' function +#- +#- Reads a bit-field in a `bytes()` object +#- +#- Input: +#- offset_bytes (int): byte offset in the bytes() object +#- offset_bits (int): bit number to start reading from (0 = LSB) +#- len_bits (int): how many bits to read +#- Output: +#- valuer (int) +#-------------------------------------------------------------# + def getbits(offset_bits, len_bits) + if len_bits <= 0 || len_bits > 32 raise "value_error", "length in bits must be between 0 and 32" end + var ret = 0 + + var offset_bytes = offset_bits >> 3 + offset_bits = offset_bits % 8 + + var bit_shift = 0 #- bit number to write to -# + + while (len_bits > 0) + var block_bits = 8 - offset_bits # how many bits to read in the current block (block = byte) -# + if block_bits > len_bits block_bits = len_bits end + + var mask = ( (1<> offset_bits) << bit_shift) + + #- move the input window -# + bit_shift += block_bits + len_bits -= block_bits + offset_bits = 0 #- start at full next byte -# + offset_bytes += 1 + end + + return ret + end + + #------------------------------------------------------------- + #- 'setbits' function + #- + #- Writes a bit-field in a `bytes()` object + #- + #- Input: + #- offset_bytes (int): byte offset in the bytes() object + #- offset_bits (int): bit number to start writing to (0 = LSB) + #- len_bits (int): how many bits to write + #- Output: + #- bytes() object modified (by reference) + #-------------------------------------------------------------# + def setbits(offset_bits, len_bits, val) + if len_bits < 0 || len_bits > 32 raise "value_error", "length in bits must be between 0 and 32" end + + var offset_bytes = offset_bits >> 3 + offset_bits = offset_bits % 8 + + while (len_bits > 0) + var block_bits = 8 - offset_bits #- how many bits to write in the current block (block = byte) -# + if block_bits > len_bits block_bits = len_bits end + + var mask_val = (1<>= block_bits + len_bits -= block_bits + offset_bits = 0 #- start at full next byte -# + offset_bytes += 1 + end + return self + end +end + +*/ + +/******************************************************************** +** Solidified function: getbits +********************************************************************/ +be_local_closure(getbits, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + { { .i=0 }, BE_INT}, + { { .s=be_nested_const_str("value_error", 773297791, 11) }, BE_STRING}, + { { .s=be_nested_const_str("length in bits must be between 0 and 32", -1710458168, 39) }, BE_STRING}, + { { .i=3 }, BE_INT}, + { { .i=1 }, BE_INT}, + }), + (be_nested_const_str("getbits", -1200798317, 7)), + (be_nested_const_str("stdin", -1529146723, 5)), + ( &(const binstruction[32]) { /* code */ + 0x180C0500, // 0000 LE R3 R2 R256 + 0x740E0002, // 0001 JMPT R3 #0005 + 0x540E001F, // 0002 LDINT R3 32 + 0x240C0403, // 0003 GT R3 R2 R3 + 0x780E0000, // 0004 JMPF R3 #0006 + 0xB0060302, // 0005 RAISE 1 R257 R258 + 0x580C0000, // 0006 LDCONST R3 K0 + 0x3C100303, // 0007 SHR R4 R1 R259 + 0x54160007, // 0008 LDINT R5 8 + 0x10040205, // 0009 MOD R1 R1 R5 + 0x58140000, // 000A LDCONST R5 K0 + 0x24180500, // 000B GT R6 R2 R256 + 0x781A0011, // 000C JMPF R6 #001F + 0x541A0007, // 000D LDINT R6 8 + 0x04180C01, // 000E SUB R6 R6 R1 + 0x241C0C02, // 000F GT R7 R6 R2 + 0x781E0000, // 0010 JMPF R7 #0012 + 0x5C180400, // 0011 MOVE R6 R2 + 0x381E0806, // 0012 SHL R7 R260 R6 + 0x041C0F04, // 0013 SUB R7 R7 R260 + 0x381C0E01, // 0014 SHL R7 R7 R1 + 0x94200004, // 0015 GETIDX R8 R0 R4 + 0x2C201007, // 0016 AND R8 R8 R7 + 0x3C201001, // 0017 SHR R8 R8 R1 + 0x38201005, // 0018 SHL R8 R8 R5 + 0x300C0608, // 0019 OR R3 R3 R8 + 0x00140A06, // 001A ADD R5 R5 R6 + 0x04080406, // 001B SUB R2 R2 R6 + 0x58040000, // 001C LDCONST R1 K0 + 0x00100904, // 001D ADD R4 R4 R260 + 0x7001FFEB, // 001E JMP #000B + 0x80040600, // 001F RET 1 R3 + }) + ) +); +/*******************************************************************/ + +/******************************************************************** +** Solidified function: setbits +********************************************************************/ +be_local_closure(setbits, /* name */ + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + { { .i=0 }, BE_INT}, + { { .s=be_nested_const_str("value_error", 773297791, 11) }, BE_STRING}, + { { .s=be_nested_const_str("length in bits must be between 0 and 32", -1710458168, 39) }, BE_STRING}, + { { .i=3 }, BE_INT}, + { { .i=1 }, BE_INT}, + }), + (be_nested_const_str("setbits", -1532559129, 7)), + (be_nested_const_str("stdin", -1529146723, 5)), + ( &(const binstruction[33]) { /* code */ + 0x14100500, // 0000 LT R4 R2 R256 + 0x74120002, // 0001 JMPT R4 #0005 + 0x5412001F, // 0002 LDINT R4 32 + 0x24100404, // 0003 GT R4 R2 R4 + 0x78120000, // 0004 JMPF R4 #0006 + 0xB0060302, // 0005 RAISE 1 R257 R258 + 0x3C100303, // 0006 SHR R4 R1 R259 + 0x54160007, // 0007 LDINT R5 8 + 0x10040205, // 0008 MOD R1 R1 R5 + 0x24140500, // 0009 GT R5 R2 R256 + 0x78160014, // 000A JMPF R5 #0020 + 0x54160007, // 000B LDINT R5 8 + 0x04140A01, // 000C SUB R5 R5 R1 + 0x24180A02, // 000D GT R6 R5 R2 + 0x781A0000, // 000E JMPF R6 #0010 + 0x5C140400, // 000F MOVE R5 R2 + 0x381A0805, // 0010 SHL R6 R260 R5 + 0x04180D04, // 0011 SUB R6 R6 R260 + 0x541E00FE, // 0012 LDINT R7 255 + 0x38200C01, // 0013 SHL R8 R6 R1 + 0x041C0E08, // 0014 SUB R7 R7 R8 + 0x94200004, // 0015 GETIDX R8 R0 R4 + 0x2C201007, // 0016 AND R8 R8 R7 + 0x2C240606, // 0017 AND R9 R3 R6 + 0x38241201, // 0018 SHL R9 R9 R1 + 0x30201009, // 0019 OR R8 R8 R9 + 0x98000808, // 001A SETIDX R0 R4 R8 + 0x3C0C0605, // 001B SHR R3 R3 R5 + 0x04080405, // 001C SUB R2 R2 R5 + 0x58040000, // 001D LDCONST R1 K0 + 0x00100904, // 001E ADD R4 R4 R260 + 0x7001FFE8, // 001F JMP #0009 + 0x80040000, // 0020 RET 1 R0 + }) + ) +); +/*******************************************************************/ + #if !BE_USE_PRECOMPILED_OBJECT void be_load_byteslib(bvm *vm) { static const bnfuncinfo members[] = { { ".p", NULL }, + { "_buffer", m_buffer }, { "init", m_init }, { "tostring", m_tostring }, { "asstring", m_asstring }, { "fromstring", m_fromstring }, { "add", m_add }, - { "get", m_get }, + { "get", m_getu }, + { "geti", m_geti }, + { "set", m_set }, { "item", m_item }, { "setitem", m_setitem }, { "size", m_size }, @@ -663,6 +976,11 @@ void be_load_byteslib(bvm *vm) { "..", m_connect }, { "==", m_equal }, { "!=", m_nequal }, + + { NULL, (bntvfunc) BE_CLOSURE }, /* mark section for berry closures */ + { "getbits", (bntvfunc) &getbits_closure }, + { "setbits", (bntvfunc) &setbits_closure }, + { NULL, NULL } }; be_regclass(vm, "bytes", members); @@ -671,12 +989,15 @@ void be_load_byteslib(bvm *vm) /* @const_object_info_begin class be_class_bytes (scope: global, name: bytes) { .p, var + _buffer, func(m_buffer) init, func(m_init) tostring, func(m_tostring) asstring, func(m_asstring) fromstring, func(m_fromstring) add, func(m_add) - get, func(m_get) + get, func(m_getu) + geti, func(m_geti) + set, func(m_set) item, func(m_item) setitem, func(m_setitem) size, func(m_size) @@ -687,6 +1008,9 @@ class be_class_bytes (scope: global, name: bytes) { .., func(m_connect) ==, func(m_equal) !=, func(m_nequal) + + getbits, closure(getbits_closure) + setbits, closure(setbits_closure) } @const_object_info_end */ #include "../generate/be_fixed_be_class_bytes.h" diff --git a/lib/libesp32/Berry/src/be_solidifylib.c b/lib/libesp32/Berry/src/be_solidifylib.c index 5ef505126..03523c9a8 100644 --- a/lib/libesp32/Berry/src/be_solidifylib.c +++ b/lib/libesp32/Berry/src/be_solidifylib.c @@ -122,7 +122,7 @@ static void m_solidify_proto(bvm *vm, bproto *pr, const char * func_name, int bu logfmt("%*s( &(const binstruction[%2d]) { /* code */\n", indent, "", pr->codesize); for (int pc = 0; pc < pr->codesize; pc++) { uint32_t ins = pr->code[pc]; - logfmt("%*s 0x%04X, //", indent, "", ins); + logfmt("%*s 0x%08X, //", indent, "", ins); be_print_inst(ins, pc); bopcode op = IGET_OP(ins); if (op == OP_GETGBL || op == OP_SETGBL) { diff --git a/lib/libesp32/Berry/tests/bytes.be b/lib/libesp32/Berry/tests/bytes.be index cce46120f..40a784c34 100644 --- a/lib/libesp32/Berry/tests/bytes.be +++ b/lib/libesp32/Berry/tests/bytes.be @@ -165,3 +165,33 @@ assert(str(b) =="bytes('416130')") b=bytes() b.fromstring("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") assert(str(b) =="bytes('4C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E73656374657475722061646970697363696E6720656C69742C2073656420646F20656975736D6F642074656D706F7220696E6369646964756E74207574206C61626F726520657420646F6C6F7265206D61676E6120616C697175612E')") + +#- setters -# +b=bytes().resize(16) +b.set(5,-1,2) +assert(b == bytes('0000000000FFFF000000000000000000')) +b.set(10,-2,4) +assert(b == bytes('0000000000FFFF000000FEFFFFFF0000')) +b.set(0,0xAA55,1) +assert(b == bytes('5500000000FFFF000000FEFFFFFF0000')) + +#- getbits -# +b=bytes("00AAFF55010300") +assert(b.getbits(8,8) == 0xAA) +assert(b.getbits(0,1) == 0) +assert(b.getbits(8,1) == 0) +assert(b.getbits(9,1) == 1) +assert(b.getbits(16,8) == 0xFF) +assert(b.getbits(16,16) == 0x55FF) +assert(b.getbits(16,24) == 0x0155FF) +assert(b.getbits(16,32) == 0x030155FF) +assert(b.getbits(20,8) == 0x5F) + +#- setbits -# +b=bytes("00000000FFFFFFFF") +assert(b.setbits(0,1,1) == bytes('01000000FFFFFFFF')) +assert(b.setbits(1,1,1) == bytes('03000000FFFFFFFF')) +assert(b.setbits(0,1,0) == bytes('02000000FFFFFFFF')) +assert(b.setbits(12,16,0xAA55) == bytes('0250A50AFFFFFFFF')) +assert(b.setbits(63,0,0) == bytes('0250A50AFFFFFFFF')) +assert(b.setbits(63,1,0) == bytes('0250A50AFFFFFF7F')) diff --git a/tasmota/berry/modules/ctypes.be b/tasmota/berry/modules/ctypes.be new file mode 100644 index 000000000..e7d73103a --- /dev/null +++ b/tasmota/berry/modules/ctypes.be @@ -0,0 +1,563 @@ +#------------------------------------------------------------- +#- Ctypes for Berry +#- +#- Inspired from Python's ctypes structure +#-------------------------------------------------------------# +import string + +ctypes = module('ctypes') + +#------------------------------------------------------------- +#- Basic types for mapping +#- +#- ints of size 1/2/4 bytes (little endian by default) +#- usigned ints of size 1/2/4 bytes (little endian by default) +#- +#- (Big Endian are negative numbers) +#-------------------------------------------------------------# + +# default is little_endian +ctypes.i32 = 14 +ctypes.i16 = 12 +ctypes.i8 = 11 +ctypes.u32 = 4 +ctypes.u16 = 2 +ctypes.u8 = 1 + +# explicit little endian +ctypes.le_i32 = 14 +ctypes.le_i16 = 12 +ctypes.le_i8 = 11 +ctypes.le_u32 = 4 +ctypes.le_u16 = 2 +ctypes.le_u8 = 1 + +# big endian +ctypes.be_i32 = -14 +ctypes.be_i16 = -12 +ctypes.be_i8 = -11 +ctypes.be_u32 = -4 +ctypes.be_u16 = -2 +ctypes.be_u8 = -1 + +# bitfields (always unsigned) +ctypes.bf_0 = 100 # serves as base +ctypes.bf_1 = 101 +ctypes.bf_2 = 102 +ctypes.bf_3 = 103 +ctypes.bf_4 = 104 +ctypes.bf_5 = 105 +ctypes.bf_6 = 106 +ctypes.bf_7 = 107 +ctypes.bf_8 = 108 +ctypes.bf_9 = 109 +ctypes.bf_10 = 110 +ctypes.bf_11 = 111 +ctypes.bf_12 = 112 +ctypes.bf_13 = 113 +ctypes.bf_14 = 114 +ctypes.bf_15 = 115 + + +#------------------------------------------------------------- +#- 'get_bits' function +#- +#- Reads a bit-field in a `bytes()` object +#- +#- Input: +#- b: bytes() object to read from +#- offset_bytes (int): byte offset in the bytes() object +#- offset_bits (int): bit number to start reading from (0 = LSB) +#- len_bits (int): how many bits to read +#- Output: +#- valuer (int) +#-------------------------------------------------------------# +ctypes.get_bits = def (b, offset_bytes, offset_bits, len_bits) + if !isinstance(b, bytes) raise "value_error", "first argument must be of type 'bytes'" end + if offset_bits < 0 || offset_bits > 7 raise "value_error", "offset_bits must be between 0 and 7" end + if len_bits <= 0 || len_bits > 32 raise "value_error", "length in bits must be between 0 and 32" end + var ret = 0 + + var bit_shift = 0 # bit number to write to + + while (len_bits > 0) + var block_bits = 8 - offset_bits # how many bits to read in the current block (block = byte) + if block_bits > len_bits block_bits = len_bits end + + var mask = ( (1<> offset_bits) << bit_shift) + + # move the input window + bit_shift += block_bits + len_bits -= block_bits + offset_bits = 0 # start at full next byte + offset_bytes += 1 + end + + return ret +end + +ctypes.sort = def (l) + # insertion sort + for i:1..size(l)-1 + var k = l[i] + var j = i + while (j > 0) && (l[j-1] > k) + l[j] = l[j-1] + j -= 1 + end + l[j] = k + end + return l +end + +#------------------------------------------------------------- +#- 'set_bits' function +#- +#- Writes a bit-field in a `bytes()` object +#- +#- Input: +#- b: bytes() object to write to +#- offset_bytes (int): byte offset in the bytes() object +#- offset_bits (int): bit number to start writing to (0 = LSB) +#- len_bits (int): how many bits to write +#- Output: +#- bytes() object modified (by reference) +#-------------------------------------------------------------# +ctypes.set_bits = def (b, offset_bytes, offset_bits, len_bits, val) + if !isinstance(b, bytes) raise "value_error", "first argument must be of type 'bytes'" end + if offset_bits < 0 || offset_bits > 7 raise "value_error", "offset_bits must be between 0 and 7" end + if len_bits <= 0 || len_bits > 32 raise "value_error", "length in bits must be between 0 and 32" end + + while (len_bits > 0) + var block_bits = 8 - offset_bits # how many bits to write in the current block (block = byte) + if block_bits > len_bits block_bits = len_bits end + + var mask_val = (1<>= block_bits + len_bits -= block_bits + offset_bits = 0 # start at full next byte + offset_bytes += 1 + end + return b +end + + +#- print the C types -#1 +ctypes.print_types = def () + print("enum {") + print(" ctypes_ptr = 0,") + print(" ctypes_uint = 1,") + print(" ctypes_int = 2,") + print(" ctypes_str = 3,") + print("};") + print() + print("typedef struct be_ctypes_structure_t {") + print(" const char * name;") + print(" uint16_t offset_bits;") + print(" uint16_t len_bits : 13;") + print(" uint16_t type : 3;") + print("} be_ctypes_structure_t;") +end + + +#------------------------------------------------------------- +#- 'ctypes.structure' class +#- +#- Parses a ctypes structure descriptor and creates +#- a set of getters and setters +#- +#-------------------------------------------------------------# +class structure + var cur_offset # offset in bytes from buffer start + var bit_offset # are we intra-byte? + var get_closures # + var set_closures # + var size_bytes # size in bytes + var mapping # map to generate C binding + + # init world + def init(mapping, name) + self.cur_offset = 0 + self.bit_offset = 0 + self.size_bytes = 0 # overall size in bytes + self.get_closures = {} + self.set_closures = {} + self.mapping = {} + + # parse mapping + self.parse_mapping(mapping, name) + end + #- iteratively parse mapping + #- + #- if name is not nil, it also outputs a C structure for the mapping + #- + #-------------------------------------------------------------# + def parse_mapping(mapping, name) + for map_line: mapping + self.parse_line(map_line) + end + + if name != nil + print(string.format("const be_ctypes_structure_t be_%s[%d] = {", name, size(self.mapping))) + # list keys for future binary search + var names = [] + for n:self.mapping.keys() names.push(n) end # convert to list + ctypes.sort(names) + for n:names + var args = self.mapping[n] + print(string.format(" { \"%s\", %i, %i, %s },", n, args[0], args[1], args[2])) + end + print("};") + print() + end + + # clear any outstanding bitfield + self.align(1) + self.size_bytes = self.cur_offset + end + + def size() + return self.size_bytes + end + + # parse a single line + def parse_line(map_line) + var type_obj = map_line[0] + var name = map_line[1] + var bits = 0 + if size(map_line) >= 3 bits = map_line[2] end + + if isinstance(type_obj, ctypes.structure) + # nested structure + self.nested(name, type_obj) + elif type(type_obj) == 'int' + # TODO check actual type + if type_obj > ctypes.bf_0 + # bit field + self.get_bitfield_closure(name, type_obj - ctypes.bf_0) + else + # multi-bytes + self.get_int_closure(name, type_obj) + end + end + end + + #- ensure alignment to 1/2/4 bytes -# + def align(n) + if n != 1 && n != 2 && n != 4 raise "value_error", "acceptable values are 1/2/4" end + + #- align to byte boundary if we're in a bitfield -# + if self.bit_offset != 0 + #- we are not byte aligned, let's re-aling -# + self.cur_offset += 1 + self.bit_offset = 0 + + #- check 2/4 bytes alignment -# + if self.cur_offset % n != 0 + # we are not aligned with current size + self.cur_offset += n - self.cur_offset % n + end + end + end + + def nested(name, type_obj) + var sub_size = type_obj.size() + if sub_size <= 0 raise "value_error", "empty sub-structure not supported" end + + # align to appropriate sub-size + var align_size = sub_size + if align_size == 3 || align_size > 4 align_size = 4 end + self.align(align_size) + + var offset = self.cur_offset # var for closure + + # inlcude nested + for subname:type_obj.mapping.keys() + var val = type_obj.mapping[subname] + self.mapping[name+"_"+subname] = [val[0] + (offset << 3), val[1], val[2]] + end + # self.mapping[name] = [offset << 3, sub_size << 3] + + self.get_closures[name] = def (b, p) return ctypes.nested_buffer(type_obj, offset + p, b) end + # self.set_closures[name] = def (b, p, v) return ctypes.nested_buffer(type_obj, offset + p, b) end + + self.cur_offset += sub_size + end + + def get_int_closure(name, size_in_bytes_le_be) # can be 1/2/4 + #- abs size -# + var size_in_bytes = size_in_bytes_le_be < 0 ? - size_in_bytes_le_be : size_in_bytes_le_be + var signed = size_in_bytes > 10 + size_in_bytes_le_be = size_in_bytes_le_be % 10 # remove sign marker + size_in_bytes = size_in_bytes % 10 # remove sign marker + + self.align(size_in_bytes) # force alignment + var offset = self.cur_offset # prepare variable for capture in closure + + self.mapping[name] = [offset << 3, size_in_bytes_le_be << 3, signed ? "ctypes_int" : "ctypes_uint"] + + #- add closures -# + if signed + self.get_closures[name] = def (b, p) return b.geti(offset + p, size_in_bytes_le_be) end + else + self.get_closures[name] = def (b, p) return b.get(offset + p, size_in_bytes_le_be) end + end + self.set_closures[name] = def (b, p, v) return b.set(offset+ p, v, size_in_bytes_le_be) end + + self.cur_offset += size_in_bytes # next offset + end + + + def get_bitfield_closure(name, size_in_bits) # can be 1..32 + var cur_offset = self.cur_offset # prepare variable for capture in closure + var bit_offset = self.bit_offset + self.mapping[name] = [bit_offset + (cur_offset << 3), size_in_bits, "ctypes_uint"] + self.get_closures[name] = def (b, p) return ctypes.get_bits(b, cur_offset + p, bit_offset, size_in_bits) end + self.set_closures[name] = def (b, p, v) return ctypes.set_bits(b, cur_offset+ p, bit_offset, size_in_bits, v) end + + self.cur_offset += size_in_bits / 8 + self.cur_offset += (self.bit_offset + size_in_bits) / 8 + self.bit_offset = (self.bit_offset + size_in_bits) % 8 + end +end + +ctypes.structure = structure + +#------------------------------------------------------------- +#- Structured buffer +#- +#- Inspired from Python's ctypes structure +#- +#- This class is a wrapper around `bytes()` object (actually a subclass) +#- providing virtual members mapped to the ctypes structure. +#- +#- Takes as argument a ctypes.structure and an optional bytes() object +#-------------------------------------------------------------# +class buffer : bytes + var _cs # ctypes_structure associated + + def init(cs, b) + if !isinstance(cs, ctypes.structure) raise "value_error", "first argument must be an instance of 'ctypes.structure'" end + self._cs = cs + var size = self._cs.size() # size in bytes of the structure + + super(self, bytes).init(size) # init bytes object with reserved size in memory + + if isinstance(b, bytes) + self..b + end + self.resize(size) # size once for all to the target size and complete with 00s + end + + # accessor for virtual member + def member(name) + return self._cs.get_closures[name](self, 0) + end + + # setter for virtual member + def setmember(name, value) + self._cs.set_closures[name](self, 0, value) + end +end +ctypes.buffer = buffer + +#------------------------------------------------------------- +#- Nested buffer +#- +#- Nested structures are just pointers to the master bytes() object +#-------------------------------------------------------------# +class nested_buffer + var _cs # ctypes.structure instance for this buffer + var _offset # offset un bytes() to the structure + var _bytes # reference to the overall buffer (by reference) + + def init(cs, offset, b) + if !isinstance(cs, ctypes.structure) raise "value_error", "first argument must be an instance of 'ctypes.structure'" end + if type(offset) != 'int' raise "value_error", "second argument must be of type 'int'" end + if !isinstance(b, bytes) raise "value_error", "third argument must be an instance of 'bytes'" end + self._cs = cs + self._offset = offset + self._bytes = b + end + + # accessor for virtual member + def member(name) + return self._cs.get_closures[name](self._bytes, self._offset) + end + + # setter for virtual member + def setmember(name, value) + self._cs.set_closures[name](self._bytes, self._offset, value) + end + + def tostring() + return self._bytes[self._offset..self._offset+self._cs.size()-1].tostring() + end +end +ctypes.nested_buffer = nested_buffer + + +return ctypes + +# ex = [ +# [ctypes.u32, "a"], +# [ctypes.u16, "b"], +# [ctypes.i8, "c"], +# [ctypes.i32, "d"], # should infer an empty byte +# ] + +# cs = ctypes.structure(ex) +# bb = ctypes.buffer(cs, bytes("aabb")) + +# fa = cp.get_int_closure('a', 4) +# fb = cp.get_int_closure('b', 2) +# fc = cp.get_int_closure('c', 1) +# fd = cp.get_int_closure('d', 4) + +# b = bytes("04030201AA55FFFF00010001") + +# cp.get_closures['a'](b) +# cp.get_closures['b'](b) +# cp.get_closures['c'](b) +# cp.get_closures['d'](b) + +# bb = ctypes_buffer(cp, b) + +# bb.a = 0x11223344 +# bb +# bb.a + + +# > bb = ctypes_buffer(cp, b) +# > bb.a +# 16909060 +# > bb.b +# 21930 +# > bb.c +# 255 +# > bb.d +# 16777472 +# > bb.e +# key_error: e +# stack traceback: +# : in native function +# stdin:11: in function `member` +# stdin:1: in function `main` + + +# > bb['a'] +# 16909060 +# > bb['b'] +# 21930 +# > bb['c'] +# 255 +# > bb['d'] +# 16777472 + +#- +> fa(b) +16909060 +> fb(b) +21930 +> fc(b) +255 +> fd(b) +16777472 + +-# + +# def get_bits(b, offset_bytes, offset_bits, len_bits) +# if !isinstance(b, bytes) raise "value_error", "first argument must be of type 'bytes'" end +# if offset_bits < 0 || offset_bits > 7 raise "value_error", "offset_bits must be between 0 and 7" end +# if len_bits <= 0 || len_bits > 32 raise "value_error", "length in bits must be between 0 and 32" end +# var ret = 0 + +# var bit_shift = 0 # bit number to wrtie to + +# while (len_bits > 0) +# var block_bits = 8 - offset_bits # bit number to read in current block (block = byte) +# if block_bits > len_bits block_bits = len_bits end + +# var mask = ( (1<> offset_bits) << bit_shift) + +# # move the input window +# bit_shift += block_bits +# len_bits -= block_bits +# offset_bits = 0 # start at full next byte +# offset_bytes += 1 +# end + +# return ret +# end + +# Test + +# b=bytes("AAFF10") +# assert(get_bits(b, 0, 0, 1) == 0) +# assert(get_bits(b, 0, 1, 1) == 1) +# assert(get_bits(b, 0, 2, 1) == 0) +# assert(get_bits(b, 0, 3, 1) == 1) + +# assert(get_bits(b, 0, 0, 2) == 2) +# assert(get_bits(b, 0, 1, 2) == 1) +# assert(get_bits(b, 0, 2, 2) == 2) + +# assert(get_bits(b, 0, 0, 8) == 0xAA) +# assert(get_bits(b, 0, 0, 10) == 0x3AA) +# assert(get_bits(b, 0, 2, 8) == 0xEA) + +# assert(get_bits(b, 1, 0, 8) == 0xFF) +# assert(get_bits(b, 1, 0, 10) == 0x0FF) + +# assert(get_bits(b, 1, 0, 16) == 0x10FF) + + +# assert(get_bits(b, 1, 7, 4) == 0x01) +# assert(get_bits(b, 1, 7, 6) == 0x21) + +# def set_bits(b, offset_bytes, offset_bits, len_bits, val) +# if !isinstance(b, bytes) raise "value_error", "first argument must be of type 'bytes'" end +# if offset_bits < 0 || offset_bits > 7 raise "value_error", "offset_bits must be between 0 and 7" end +# if len_bits <= 0 || len_bits > 32 raise "value_error", "length in bits must be between 0 and 32" end + +# while (len_bits > 0) +# var block_bits = 8 - offset_bits # how many bits to write in the current block (block = byte) +# if block_bits > len_bits block_bits = len_bits end + +# var mask_val = (1<>= block_bits +# len_bits -= block_bits +# offset_bits = 0 # start at full next byte +# offset_bytes += 1 +# end +# return b +# end + +# b=bytes("00000000") + +# assert(set_bits(b,0,0,1,1) == bytes('01000000')) +# assert(set_bits(b,1,0,1,1) == bytes('01010000')) +# assert(set_bits(b,0,0,1,2) == bytes('00010000')) +# assert(set_bits(b,0,4,1,1) == bytes('10010000')) +# assert(set_bits(b,0,4,1,0) == bytes('00010000')) + +# b=bytes("FF000000") +# assert(set_bits(b,0,4,1,0) == bytes('EF000000')) +# assert(set_bits(b,0,4,1,1) == bytes('FF000000')) + +# b=bytes("00000000") +# assert(set_bits(b,2,6,1,-1) == bytes('00004000')) +# b=bytes("00000000") +# assert(set_bits(b,2,1,6,-1) == bytes('00007E00')) \ No newline at end of file diff --git a/tasmota/berry/modules/lvgl_ctypes.be b/tasmota/berry/modules/lvgl_ctypes.be new file mode 100644 index 000000000..28bb5c03d --- /dev/null +++ b/tasmota/berry/modules/lvgl_ctypes.be @@ -0,0 +1,315 @@ +# +# ctype buidings for LVGL +# +# To generate C bindings, do: +# > compile("lvgl_ctypes.be","file")() +# +# and copy/paste output in C format +# +import ctypes + +ctypes.print_types() + +lv_style_int_t = ctypes.i16 +lv_color_t = ctypes.u16 # depends on colors +lv_grad_dir_t = ctypes.u8 +lv_opa_t = ctypes.u8 +lv_blend_mode_t = ctypes.u8 +lv_align_t = ctypes.u8 +lv_coord_t = ctypes.i16 +lv_bidi_dir_t = ctypes.u8 +lv_txt_flag_t = ctypes.u8 +lv_text_decor_t = ctypes.u8 +lv_font_t = ctypes.u32 +uint8_t_1 = ctypes.bf_1 +uint8_t_2 = ctypes.bf_2 +uint8_t = ctypes.u8 +uint16_t = ctypes.u16 +uint32_t = ctypes.u32 +int32_t = ctypes.i32 +ptr = ctypes.u32 + +lv_point_t = [ + [lv_coord_t, "x"], + [lv_coord_t, "y"], +] +lv_point_t = ctypes.structure(lv_point_t, "lv_point_t") + +lv_area_t = [ + [lv_coord_t, "x1"], + [lv_coord_t, "y1"], + [lv_coord_t, "x2"], + [lv_coord_t, "y2"], +] +lv_area_t = ctypes.structure(lv_area_t, "lv_area_t") + +test_t = [ + [lv_area_t, "a"], + [lv_area_t, "b"] +] +test_t = ctypes.structure(test_t, "test_t") + +lv_draw_rect_dsc_t = [ + [lv_style_int_t, "radius"], + + #/*Background*/ + [lv_color_t, "bg_color"], + [lv_color_t, "bg_grad_color"], + [lv_grad_dir_t, "bg_grad_dir"], + [lv_style_int_t, "bg_main_color_stop"], + [lv_style_int_t, "bg_grad_color_stop"], + [lv_opa_t, "bg_opa"], + [lv_blend_mode_t, "bg_blend_mode"], + + #/*Border*/ + [lv_color_t, "border_color"], + [lv_style_int_t, "border_width"], + [lv_style_int_t, "border_side"], + [lv_opa_t, "border_opa"], + [lv_blend_mode_t, "border_blend_mode"], + [uint8_t_1, "border_post"], + + #/*Outline*/ + [lv_color_t, "outline_color"], + [lv_style_int_t, "outline_width"], + [lv_style_int_t, "outline_pad"], + [lv_opa_t, "outline_opa"], + [lv_blend_mode_t, "outline_blend_mode"], + + #/*Shadow*/ + [lv_color_t, "shadow_color"], + [lv_style_int_t, "shadow_width"], + [lv_style_int_t, "shadow_ofs_x"], + [lv_style_int_t, "shadow_ofs_y"], + [lv_style_int_t, "shadow_spread"], + [lv_opa_t, "shadow_opa"], + [lv_blend_mode_t, "shadow_blend_mode"], + + #/*Pattern*/ + [ptr, "pattern_image"], + [ptr, "pattern_font"], + [lv_color_t, "pattern_recolor"], + [lv_opa_t, "pattern_opa"], + [lv_opa_t, "pattern_recolor_opa"], + [uint8_t_1, "pattern_repeat"], + [lv_blend_mode_t, "pattern_blend_mode"], + + #/*Value*/ + [ptr, "value_str"], + [ptr, "value_font"], + [lv_opa_t, "value_opa"], + [lv_color_t, "value_color"], + [lv_style_int_t, "value_ofs_x"], + [lv_style_int_t, "value_ofs_y"], + [lv_style_int_t, "value_letter_space"], + [lv_style_int_t, "value_line_space"], + [lv_align_t, "value_align"], + [lv_blend_mode_t, "value_blend_mode"], +] +lv_draw_rect_dsc_t = ctypes.structure(lv_draw_rect_dsc_t, "lv_draw_rect_dsc_t") + +lv_draw_line_dsc_t = [ + [lv_color_t, "color"], + [lv_style_int_t, "width"], + [lv_style_int_t, "dash_width"], + [lv_style_int_t, "dash_gap"], + [lv_opa_t, "opa"], + [uint8_t_2, "blend_mode"], + [uint8_t_1, "round_start"], + [uint8_t_1, "round_end"], + [uint8_t_1, "raw_end"], +] +lv_draw_line_dsc_t = ctypes.structure(lv_draw_line_dsc_t, "lv_draw_line_dsc_t") + +lv_draw_img_dsc_t = [ + [lv_opa_t, "opa"], + [uint16_t, "angle"], + [lv_point_t, "pivot"], + [uint16_t, "zoom"], + [lv_opa_t, "recolor_opa"], + [lv_color_t, "recolor"], + [lv_blend_mode_t, "blend_mode"], + [uint8_t_1, "antialias"], +] +lv_draw_img_dsc_t = ctypes.structure(lv_draw_img_dsc_t, "lv_draw_img_dsc_t") + +lv_draw_label_dsc_t = [ + [lv_color_t, "color"], + [lv_color_t, "sel_color"], + [lv_color_t, "sel_bg_color"], + [lv_font_t, "font"], + [lv_opa_t, "opa"], + [lv_style_int_t, "line_space"], + [lv_style_int_t, "letter_space"], + [uint32_t, "sel_start"], + [uint32_t, "sel_end"], + [lv_coord_t, "ofs_x"], + [lv_coord_t, "ofs_y"], + [lv_bidi_dir_t, "bidi_dir"], + [lv_txt_flag_t, "flag"], + [lv_text_decor_t, "decor"], + [lv_blend_mode_t, "blend_mode"], +] +lv_draw_label_dsc_t = ctypes.structure(lv_draw_label_dsc_t, "lv_draw_label_dsc_t") + +#- --------- lv_mask --------- -# +lv_draw_mask_xcb_t = ptr # callback +lv_draw_mask_type_t = ctypes.u8 +lv_draw_mask_line_side_t = ctypes.u8 + +lv_draw_mask_common_dsc_t = [ + [lv_draw_mask_xcb_t, "cb"], + [lv_draw_mask_type_t, "type"], +] +lv_draw_mask_common_dsc_t = ctypes.structure(lv_draw_mask_common_dsc_t, "lv_draw_mask_common_dsc_t") + +lv_draw_mask_line_param_cfg_t = [ + #/*First point */ + [lv_point_t, "p1"], + + #/*Second point*/ + [lv_point_t, "p2"], + + #/*Which side to keep?*/ + [uint8_t_2, "side"], +] +lv_draw_mask_line_param_cfg_t = ctypes.structure(lv_draw_mask_line_param_cfg_t, "lv_draw_mask_line_param_cfg_t") + +lv_draw_mask_line_param_t = [ + #/*The first element must be the common descriptor*/ + [lv_draw_mask_common_dsc_t, "dsc"], + [lv_draw_mask_line_param_cfg_t, "cfg"], + #/*A point of the line*/ + [lv_point_t, "origo"], + #/* X / (1024*Y) steepness (X is 0..1023 range). What is the change of X in 1024 Y?*/ + [int32_t, "xy_steep"], + #/* Y / (1024*X) steepness (Y is 0..1023 range). What is the change of Y in 1024 X?*/ + [int32_t, "yx_steep"], + #/*Helper which stores yx_steep for flat lines and xy_steep for steep (non flat) lines */ + [int32_t, "steep"], + #/*Steepness in 1 px in 0..255 range. Used only by flat lines. */ + [int32_t, "spx"], + #/*1: It's a flat line? (Near to horizontal)*/ + [uint8_t_1, "flat"], + #/* Invert the mask. The default is: Keep the left part. + # * It is used to select left/right/top/bottom*/ + [uint8_t_1, "inv"], +] +lv_draw_mask_line_param_t = ctypes.structure(lv_draw_mask_line_param_t, "lv_draw_mask_line_param_t") + +lv_draw_mask_angle_param_cfg_t = [ + [lv_point_t, "vertex_p"], + [lv_coord_t, "start_angle"], + [lv_coord_t, "end_angle"], +] +lv_draw_mask_angle_param_cfg_t = ctypes.structure(lv_draw_mask_angle_param_cfg_t, "lv_draw_mask_angle_param_cfg_t") + +lv_draw_mask_angle_param_t = [ + #/*The first element must be the common descriptor*/ + [lv_draw_mask_common_dsc_t, "dsc"], + [lv_draw_mask_angle_param_cfg_t, "cfg"], + + [lv_draw_mask_line_param_t, "start_line"], + [lv_draw_mask_line_param_t, "end_line"], + [uint16_t, "delta_deg"], +] +lv_draw_mask_angle_param_t = ctypes.structure(lv_draw_mask_angle_param_t, "lv_draw_mask_angle_param_t") + + +lv_draw_mask_radius_param_cfg_t = [ + [lv_area_t, "rect"], + [lv_coord_t, "radius"], + [uint8_t_1, "outer"], +] +lv_draw_mask_radius_param_cfg_t = ctypes.structure(lv_draw_mask_radius_param_cfg_t, "lv_draw_mask_radius_param_cfg_t") + +lv_sqrt_res_t = [ + [uint16_t, "i"], + [uint16_t, "f"], +] +lv_sqrt_res_t = ctypes.structure(lv_sqrt_res_t, "lv_sqrt_res_t") + +lv_draw_mask_radius_param_t = [ + #/*The first element must be the common descriptor*/ + [lv_draw_mask_common_dsc_t, "dsc"], + [lv_draw_mask_radius_param_cfg_t, "cfg"], + [int32_t, "y_prev"], + [lv_sqrt_res_t, "y_prev_x"], +] +lv_draw_mask_radius_param_t = ctypes.structure(lv_draw_mask_radius_param_t, "lv_draw_mask_radius_param_t") + + +lv_draw_mask_fade_param_cfg_t = [ + [lv_area_t, "coords"], + [lv_coord_t, "y_top"], + [lv_coord_t, "y_bottom"], + [lv_opa_t, "opa_top"], + [lv_opa_t, "opa_bottom"], +] +lv_draw_mask_fade_param_cfg_t = ctypes.structure(lv_draw_mask_fade_param_cfg_t, "lv_draw_mask_fade_param_cfg_t") + +lv_draw_mask_fade_param_t = [ + # /*The first element must be the common descriptor*/ + [lv_draw_mask_common_dsc_t, "dsc"], + [lv_draw_mask_fade_param_cfg_t, "cfg"], +] +lv_draw_mask_fade_param_t = ctypes.structure(lv_draw_mask_fade_param_t, "lv_draw_mask_fade_param_t") + + +lv_draw_mask_map_param_cfg_t = [ + [lv_area_t, "coords"], + [ptr, "map"], +] +lv_draw_mask_map_param_cfg_t = ctypes.structure(lv_draw_mask_map_param_cfg_t, "lv_draw_mask_map_param_cfg_t") + +lv_draw_mask_map_param_t = [ + #/*The first element must be the common descriptor*/ + [lv_draw_mask_common_dsc_t, "dsc"], + [lv_draw_mask_map_param_cfg_t, "cfg"], +] +lv_draw_mask_map_param_t = ctypes.structure(lv_draw_mask_map_param_t, "lv_draw_mask_map_param_t") + +lv_draw_mask_saved_t = [ + [ptr, "param"], + [ptr, "custom_id"], +] +lv_draw_mask_saved_t = ctypes.structure(lv_draw_mask_saved_t, "lv_draw_mask_saved_t") + + +# Ex: +# bb = ctypes.buffer(test_t, bytes("0101020203030404FFFFFEFEFCFC8080")) + +# Ex: +# bb = ctypes.buffer(lv_draw_rect) + +#- Ex + +bb=ctypes.buffer(lv_draw_line_dsc_t) +bb.color +bb.blend_mode + +bb.color = -1 +- bytes('FFFF0000000000000003') + +bb.blend_mode=3 +- bytes('FFFF0000000000000003') + +bb.raw_end = 1 +- bytes('FFFF0000000000000013') + +bb.blend_mode=0 +- bytes('FFFF0000000000000010') + +lv_draw_line_dsc_t = [ + [lv_color_t, "color"], + [lv_style_int_t, "width"], + [lv_style_int_t, "dash_width"], + [lv_style_int_t, "dash_gap"], + [lv_opa_t, "opa"], + [uint8_t_2, "blend_mode"], + [uint8_t_1, "round_start"], + [uint8_t_1, "round_end"], + [uint8_t_1, "raw_end"], +] + +-# \ No newline at end of file diff --git a/tasmota/xdrv_52_3_berry_lvgl_ctypes.ino b/tasmota/xdrv_52_3_berry_lvgl_ctypes.ino new file mode 100644 index 000000000..80f822451 --- /dev/null +++ b/tasmota/xdrv_52_3_berry_lvgl_ctypes.ino @@ -0,0 +1,318 @@ +/* + xdrv_52_3_berry_native.ino - Berry scripting language, native fucnctions + + Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifdef USE_BERRY +#ifdef USE_LVGL + +#include +#include "lvgl.h" +#include "be_lvgl.h" + +// Berry easy logging +extern "C" { + extern void berry_log_C(const char * berry_buf, ...); +} + + +/******************************************************************** + * Generated code, don't edit + *******************************************************************/ +enum { + ctypes_ptr = 0, + ctypes_uint = 1, + ctypes_int = 2, + ctypes_str = 3, +}; + +typedef struct be_ctypes_structure_t { + const char * name; + uint16_t offset_bits; + uint16_t len_bits : 13; + uint16_t type : 3; +} be_ctypes_structure_t; +const be_ctypes_structure_t be_lv_point_t[2] = { + { "x", 0, 16, ctypes_int }, + { "y", 16, 16, ctypes_int }, +}; + +const be_ctypes_structure_t be_lv_area_t[4] = { + { "x1", 0, 16, ctypes_int }, + { "x2", 32, 16, ctypes_int }, + { "y1", 16, 16, ctypes_int }, + { "y2", 48, 16, ctypes_int }, +}; + +const be_ctypes_structure_t be_test_t[8] = { + { "a_x1", 0, 16, ctypes_int }, + { "a_x2", 32, 16, ctypes_int }, + { "a_y1", 16, 16, ctypes_int }, + { "a_y2", 48, 16, ctypes_int }, + { "b_x1", 64, 16, ctypes_int }, + { "b_x2", 96, 16, ctypes_int }, + { "b_y1", 80, 16, ctypes_int }, + { "b_y2", 112, 16, ctypes_int }, +}; + +const be_ctypes_structure_t be_lv_draw_rect_dsc_t[43] = { + { "bg_blend_mode", 96, 8, ctypes_uint }, + { "bg_color", 16, 16, ctypes_uint }, + { "bg_grad_color", 32, 16, ctypes_uint }, + { "bg_grad_color_stop", 72, 16, ctypes_int }, + { "bg_grad_dir", 48, 8, ctypes_uint }, + { "bg_main_color_stop", 56, 16, ctypes_int }, + { "bg_opa", 88, 8, ctypes_uint }, + { "border_blend_mode", 160, 8, ctypes_uint }, + { "border_color", 104, 16, ctypes_uint }, + { "border_opa", 152, 8, ctypes_uint }, + { "border_post", 168, 1, ctypes_uint }, + { "border_side", 136, 16, ctypes_int }, + { "border_width", 120, 16, ctypes_int }, + { "outline_blend_mode", 232, 8, ctypes_uint }, + { "outline_color", 176, 16, ctypes_uint }, + { "outline_opa", 224, 8, ctypes_uint }, + { "outline_pad", 208, 16, ctypes_int }, + { "outline_width", 192, 16, ctypes_int }, + { "pattern_blend_mode", 440, 8, ctypes_uint }, + { "pattern_font", 368, 32, ctypes_uint }, + { "pattern_image", 336, 32, ctypes_uint }, + { "pattern_opa", 416, 8, ctypes_uint }, + { "pattern_recolor", 400, 16, ctypes_uint }, + { "pattern_recolor_opa", 424, 8, ctypes_uint }, + { "pattern_repeat", 432, 1, ctypes_uint }, + { "radius", 0, 16, ctypes_int }, + { "shadow_blend_mode", 328, 8, ctypes_uint }, + { "shadow_color", 240, 16, ctypes_uint }, + { "shadow_ofs_x", 272, 16, ctypes_int }, + { "shadow_ofs_y", 288, 16, ctypes_int }, + { "shadow_opa", 320, 8, ctypes_uint }, + { "shadow_spread", 304, 16, ctypes_int }, + { "shadow_width", 256, 16, ctypes_int }, + { "value_align", 600, 8, ctypes_uint }, + { "value_blend_mode", 608, 8, ctypes_uint }, + { "value_color", 520, 16, ctypes_uint }, + { "value_font", 480, 32, ctypes_uint }, + { "value_letter_space", 568, 16, ctypes_int }, + { "value_line_space", 584, 16, ctypes_int }, + { "value_ofs_x", 536, 16, ctypes_int }, + { "value_ofs_y", 552, 16, ctypes_int }, + { "value_opa", 512, 8, ctypes_uint }, + { "value_str", 448, 32, ctypes_uint }, +}; + +const be_ctypes_structure_t be_lv_draw_line_dsc_t[9] = { + { "blend_mode", 72, 2, ctypes_uint }, + { "color", 0, 16, ctypes_uint }, + { "dash_gap", 48, 16, ctypes_int }, + { "dash_width", 32, 16, ctypes_int }, + { "opa", 64, 8, ctypes_uint }, + { "raw_end", 76, 1, ctypes_uint }, + { "round_end", 75, 1, ctypes_uint }, + { "round_start", 74, 1, ctypes_uint }, + { "width", 16, 16, ctypes_int }, +}; + +const be_ctypes_structure_t be_lv_draw_img_dsc_t[9] = { + { "angle", 8, 16, ctypes_uint }, + { "antialias", 104, 1, ctypes_uint }, + { "blend_mode", 96, 8, ctypes_uint }, + { "opa", 0, 8, ctypes_uint }, + { "pivot_x", 24, 16, ctypes_int }, + { "pivot_y", 40, 16, ctypes_int }, + { "recolor", 80, 16, ctypes_uint }, + { "recolor_opa", 72, 8, ctypes_uint }, + { "zoom", 56, 16, ctypes_uint }, +}; + +const be_ctypes_structure_t be_lv_draw_label_dsc_t[15] = { + { "bidi_dir", 216, 8, ctypes_uint }, + { "blend_mode", 240, 8, ctypes_uint }, + { "color", 0, 16, ctypes_uint }, + { "decor", 232, 8, ctypes_uint }, + { "flag", 224, 8, ctypes_uint }, + { "font", 48, 32, ctypes_uint }, + { "letter_space", 104, 16, ctypes_int }, + { "line_space", 88, 16, ctypes_int }, + { "ofs_x", 184, 16, ctypes_int }, + { "ofs_y", 200, 16, ctypes_int }, + { "opa", 80, 8, ctypes_uint }, + { "sel_bg_color", 32, 16, ctypes_uint }, + { "sel_color", 16, 16, ctypes_uint }, + { "sel_end", 152, 32, ctypes_uint }, + { "sel_start", 120, 32, ctypes_uint }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_common_dsc_t[2] = { + { "cb", 0, 32, ctypes_uint }, + { "type", 32, 8, ctypes_uint }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_line_param_cfg_t[5] = { + { "p1_x", 0, 16, ctypes_int }, + { "p1_y", 16, 16, ctypes_int }, + { "p2_x", 32, 16, ctypes_int }, + { "p2_y", 48, 16, ctypes_int }, + { "side", 64, 2, ctypes_uint }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_line_param_t[15] = { + { "cfg_p1_x", 40, 16, ctypes_int }, + { "cfg_p1_y", 56, 16, ctypes_int }, + { "cfg_p2_x", 72, 16, ctypes_int }, + { "cfg_p2_y", 88, 16, ctypes_int }, + { "cfg_side", 104, 2, ctypes_uint }, + { "dsc_cb", 0, 32, ctypes_uint }, + { "dsc_type", 32, 8, ctypes_uint }, + { "flat", 272, 1, ctypes_uint }, + { "inv", 273, 1, ctypes_uint }, + { "origo_x", 112, 16, ctypes_int }, + { "origo_y", 128, 16, ctypes_int }, + { "spx", 240, 32, ctypes_int }, + { "steep", 208, 32, ctypes_int }, + { "xy_steep", 144, 32, ctypes_int }, + { "yx_steep", 176, 32, ctypes_int }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_angle_param_cfg_t[4] = { + { "end_angle", 48, 16, ctypes_int }, + { "start_angle", 32, 16, ctypes_int }, + { "vertex_p_x", 0, 16, ctypes_int }, + { "vertex_p_y", 16, 16, ctypes_int }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_angle_param_t[37] = { + { "cfg_end_angle", 88, 16, ctypes_int }, + { "cfg_start_angle", 72, 16, ctypes_int }, + { "cfg_vertex_p_x", 40, 16, ctypes_int }, + { "cfg_vertex_p_y", 56, 16, ctypes_int }, + { "delta_deg", 664, 16, ctypes_uint }, + { "dsc_cb", 0, 32, ctypes_uint }, + { "dsc_type", 32, 8, ctypes_uint }, + { "end_line_cfg_p1_x", 424, 16, ctypes_int }, + { "end_line_cfg_p1_y", 440, 16, ctypes_int }, + { "end_line_cfg_p2_x", 456, 16, ctypes_int }, + { "end_line_cfg_p2_y", 472, 16, ctypes_int }, + { "end_line_cfg_side", 488, 2, ctypes_uint }, + { "end_line_dsc_cb", 384, 32, ctypes_uint }, + { "end_line_dsc_type", 416, 8, ctypes_uint }, + { "end_line_flat", 656, 1, ctypes_uint }, + { "end_line_inv", 657, 1, ctypes_uint }, + { "end_line_origo_x", 496, 16, ctypes_int }, + { "end_line_origo_y", 512, 16, ctypes_int }, + { "end_line_spx", 624, 32, ctypes_int }, + { "end_line_steep", 592, 32, ctypes_int }, + { "end_line_xy_steep", 528, 32, ctypes_int }, + { "end_line_yx_steep", 560, 32, ctypes_int }, + { "start_line_cfg_p1_x", 144, 16, ctypes_int }, + { "start_line_cfg_p1_y", 160, 16, ctypes_int }, + { "start_line_cfg_p2_x", 176, 16, ctypes_int }, + { "start_line_cfg_p2_y", 192, 16, ctypes_int }, + { "start_line_cfg_side", 208, 2, ctypes_uint }, + { "start_line_dsc_cb", 104, 32, ctypes_uint }, + { "start_line_dsc_type", 136, 8, ctypes_uint }, + { "start_line_flat", 376, 1, ctypes_uint }, + { "start_line_inv", 377, 1, ctypes_uint }, + { "start_line_origo_x", 216, 16, ctypes_int }, + { "start_line_origo_y", 232, 16, ctypes_int }, + { "start_line_spx", 344, 32, ctypes_int }, + { "start_line_steep", 312, 32, ctypes_int }, + { "start_line_xy_steep", 248, 32, ctypes_int }, + { "start_line_yx_steep", 280, 32, ctypes_int }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_radius_param_cfg_t[6] = { + { "outer", 80, 1, ctypes_uint }, + { "radius", 64, 16, ctypes_int }, + { "rect_x1", 0, 16, ctypes_int }, + { "rect_x2", 32, 16, ctypes_int }, + { "rect_y1", 16, 16, ctypes_int }, + { "rect_y2", 48, 16, ctypes_int }, +}; + +const be_ctypes_structure_t be_lv_sqrt_res_t[2] = { + { "f", 16, 16, ctypes_uint }, + { "i", 0, 16, ctypes_uint }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_radius_param_t[11] = { + { "cfg_outer", 120, 1, ctypes_uint }, + { "cfg_radius", 104, 16, ctypes_int }, + { "cfg_rect_x1", 40, 16, ctypes_int }, + { "cfg_rect_x2", 72, 16, ctypes_int }, + { "cfg_rect_y1", 56, 16, ctypes_int }, + { "cfg_rect_y2", 88, 16, ctypes_int }, + { "dsc_cb", 0, 32, ctypes_uint }, + { "dsc_type", 32, 8, ctypes_uint }, + { "y_prev", 128, 32, ctypes_int }, + { "y_prev_x_f", 176, 16, ctypes_uint }, + { "y_prev_x_i", 160, 16, ctypes_uint }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_fade_param_cfg_t[8] = { + { "coords_x1", 0, 16, ctypes_int }, + { "coords_x2", 32, 16, ctypes_int }, + { "coords_y1", 16, 16, ctypes_int }, + { "coords_y2", 48, 16, ctypes_int }, + { "opa_bottom", 104, 8, ctypes_uint }, + { "opa_top", 96, 8, ctypes_uint }, + { "y_bottom", 80, 16, ctypes_int }, + { "y_top", 64, 16, ctypes_int }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_fade_param_t[10] = { + { "cfg_coords_x1", 40, 16, ctypes_int }, + { "cfg_coords_x2", 72, 16, ctypes_int }, + { "cfg_coords_y1", 56, 16, ctypes_int }, + { "cfg_coords_y2", 88, 16, ctypes_int }, + { "cfg_opa_bottom", 144, 8, ctypes_uint }, + { "cfg_opa_top", 136, 8, ctypes_uint }, + { "cfg_y_bottom", 120, 16, ctypes_int }, + { "cfg_y_top", 104, 16, ctypes_int }, + { "dsc_cb", 0, 32, ctypes_uint }, + { "dsc_type", 32, 8, ctypes_uint }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_map_param_cfg_t[5] = { + { "coords_x1", 0, 16, ctypes_int }, + { "coords_x2", 32, 16, ctypes_int }, + { "coords_y1", 16, 16, ctypes_int }, + { "coords_y2", 48, 16, ctypes_int }, + { "map", 64, 32, ctypes_uint }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_map_param_t[7] = { + { "cfg_coords_x1", 40, 16, ctypes_int }, + { "cfg_coords_x2", 72, 16, ctypes_int }, + { "cfg_coords_y1", 56, 16, ctypes_int }, + { "cfg_coords_y2", 88, 16, ctypes_int }, + { "cfg_map", 104, 32, ctypes_uint }, + { "dsc_cb", 0, 32, ctypes_uint }, + { "dsc_type", 32, 8, ctypes_uint }, +}; + +const be_ctypes_structure_t be_lv_draw_mask_saved_t[2] = { + { "custom_id", 32, 32, ctypes_uint }, + { "param", 0, 32, ctypes_uint }, +}; + +/********************************************************************/ + +#endif // USE_LVGL + +#endif // USE_BERRY