diff --git a/c_mpos/esp32-quirc/CMakeLists.txt b/c_mpos/esp32-quirc_from_blockstream_jade/CMakeLists.txt similarity index 100% rename from c_mpos/esp32-quirc/CMakeLists.txt rename to c_mpos/esp32-quirc_from_blockstream_jade/CMakeLists.txt diff --git a/c_mpos/esp32-quirc/LICENSE b/c_mpos/esp32-quirc_from_blockstream_jade/LICENSE similarity index 100% rename from c_mpos/esp32-quirc/LICENSE rename to c_mpos/esp32-quirc_from_blockstream_jade/LICENSE diff --git a/c_mpos/esp32-quirc/Makefile b/c_mpos/esp32-quirc_from_blockstream_jade/Makefile similarity index 100% rename from c_mpos/esp32-quirc/Makefile rename to c_mpos/esp32-quirc_from_blockstream_jade/Makefile diff --git a/c_mpos/esp32-quirc/lib/LICENSE b/c_mpos/esp32-quirc_from_blockstream_jade/lib/LICENSE similarity index 100% rename from c_mpos/esp32-quirc/lib/LICENSE rename to c_mpos/esp32-quirc_from_blockstream_jade/lib/LICENSE diff --git a/c_mpos/esp32-quirc/lib/README.md b/c_mpos/esp32-quirc_from_blockstream_jade/lib/README.md similarity index 100% rename from c_mpos/esp32-quirc/lib/README.md rename to c_mpos/esp32-quirc_from_blockstream_jade/lib/README.md diff --git a/c_mpos/esp32-quirc/lib/decode.c b/c_mpos/esp32-quirc_from_blockstream_jade/lib/decode.c similarity index 100% rename from c_mpos/esp32-quirc/lib/decode.c rename to c_mpos/esp32-quirc_from_blockstream_jade/lib/decode.c diff --git a/c_mpos/esp32-quirc/lib/identify.c b/c_mpos/esp32-quirc_from_blockstream_jade/lib/identify.c similarity index 100% rename from c_mpos/esp32-quirc/lib/identify.c rename to c_mpos/esp32-quirc_from_blockstream_jade/lib/identify.c diff --git a/c_mpos/esp32-quirc/lib/quirc.c b/c_mpos/esp32-quirc_from_blockstream_jade/lib/quirc.c similarity index 100% rename from c_mpos/esp32-quirc/lib/quirc.c rename to c_mpos/esp32-quirc_from_blockstream_jade/lib/quirc.c diff --git a/c_mpos/esp32-quirc/lib/quirc.h b/c_mpos/esp32-quirc_from_blockstream_jade/lib/quirc.h similarity index 100% rename from c_mpos/esp32-quirc/lib/quirc.h rename to c_mpos/esp32-quirc_from_blockstream_jade/lib/quirc.h diff --git a/c_mpos/esp32-quirc/lib/quirc_internal.h b/c_mpos/esp32-quirc_from_blockstream_jade/lib/quirc_internal.h similarity index 100% rename from c_mpos/esp32-quirc/lib/quirc_internal.h rename to c_mpos/esp32-quirc_from_blockstream_jade/lib/quirc_internal.h diff --git a/c_mpos/esp32-quirc/lib/version_db.c b/c_mpos/esp32-quirc_from_blockstream_jade/lib/version_db.c similarity index 100% rename from c_mpos/esp32-quirc/lib/version_db.c rename to c_mpos/esp32-quirc_from_blockstream_jade/lib/version_db.c diff --git a/c_mpos/esp32-quirc/openmv/collections.c b/c_mpos/esp32-quirc_from_blockstream_jade/openmv/collections.c similarity index 100% rename from c_mpos/esp32-quirc/openmv/collections.c rename to c_mpos/esp32-quirc_from_blockstream_jade/openmv/collections.c diff --git a/c_mpos/esp32-quirc/openmv/collections.h b/c_mpos/esp32-quirc_from_blockstream_jade/openmv/collections.h similarity index 100% rename from c_mpos/esp32-quirc/openmv/collections.h rename to c_mpos/esp32-quirc_from_blockstream_jade/openmv/collections.h diff --git a/c_mpos/esp32-quirc/openmv/fmath.h b/c_mpos/esp32-quirc_from_blockstream_jade/openmv/fmath.h similarity index 100% rename from c_mpos/esp32-quirc/openmv/fmath.h rename to c_mpos/esp32-quirc_from_blockstream_jade/openmv/fmath.h diff --git a/c_mpos/micropython.cmake b/c_mpos/micropython.cmake index f7c7d5b3..18f6e45a 100644 --- a/c_mpos/micropython.cmake +++ b/c_mpos/micropython.cmake @@ -8,6 +8,11 @@ set(MPOS_C_INCLUDES) set(MPOS_C_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/hello_world.c + ${CMAKE_CURRENT_LIST_DIR}/src/quirc_decode.c + ${CMAKE_CURRENT_LIST_DIR}/quirc/lib/identify.c + ${CMAKE_CURRENT_LIST_DIR}/quirc/lib/version_db.c + ${CMAKE_CURRENT_LIST_DIR}/quirc/lib/decode.c + ${CMAKE_CURRENT_LIST_DIR}/quirc/lib/quirc.c ) # Add our source files to the lib diff --git a/c_mpos/micropython.mk b/c_mpos/micropython.mk index f95776c2..861f0f85 100644 --- a/c_mpos/micropython.mk +++ b/c_mpos/micropython.mk @@ -10,10 +10,11 @@ ifneq (,$(findstring -Wno-missing-field-initializers, $(CFLAGS_USERMOD))) endif SRC_USERMOD_C += $(MOD_DIR)/src/hello_world.c +SRC_USERMOD_C += $(MOD_DIR)/src/quirc_decode.c -SRC_USERMOD_C += $(MOD_DIR)/esp32-quirc/lib/identify.c -SRC_USERMOD_C += $(MOD_DIR)/esp32-quirc/lib/version_db.c -SRC_USERMOD_C += $(MOD_DIR)/esp32-quirc/lib/decode.c -SRC_USERMOD_C += $(MOD_DIR)/esp32-quirc/lib/quirc.c -SRC_USERMOD_C += $(MOD_DIR)/esp32-quirc/openmv/collections.c +SRC_USERMOD_C += $(MOD_DIR)/quirc/lib/identify.c +SRC_USERMOD_C += $(MOD_DIR)/quirc/lib/version_db.c +SRC_USERMOD_C += $(MOD_DIR)/quirc/lib/decode.c +SRC_USERMOD_C += $(MOD_DIR)/quirc/lib/quirc.c +#SRC_USERMOD_C += $(MOD_DIR)/quirc/openmv/collections.c diff --git a/c_mpos/quirc b/c_mpos/quirc new file mode 160000 index 00000000..a9c52e79 --- /dev/null +++ b/c_mpos/quirc @@ -0,0 +1 @@ +Subproject commit a9c52e79283d6872728e68fec7892dc7c276c827 diff --git a/c_mpos/src/hello_world.c b/c_mpos/src/hello_world.c index ed9bf38b..38ca79f9 100644 --- a/c_mpos/src/hello_world.c +++ b/c_mpos/src/hello_world.c @@ -1,18 +1,12 @@ #include "py/obj.h" #include "py/runtime.h" -#include "../esp32-quirc/lib/quirc.h" //#error "building hello world from lcd_utils" // C function to print "Hello World" static mp_obj_t hello_world(void) { - printf("Hello World from C with quirc!\n"); - - struct quirc *qr; - qr = quirc_new(); - quirc_destroy(qr); - + printf("Hello World from C!\n"); return mp_const_none; // MicroPython functions typically return None } diff --git a/c_mpos/src/quirc_decode.c b/c_mpos/src/quirc_decode.c new file mode 100644 index 00000000..f2097eb2 --- /dev/null +++ b/c_mpos/src/quirc_decode.c @@ -0,0 +1,97 @@ +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mperrno.h" + +#include + +#include "../quirc/lib/quirc.h" + +// Function to decode a QR code from a grayscale image buffer +static mp_obj_t qrdecode(mp_uint_t n_args, const mp_obj_t *args) { + printf("qrdecode running\n") + // Check argument count (expecting buffer, width, height) + if (n_args != 3) { + mp_raise_ValueError(MP_ERROR_TEXT("quirc_decode expects 3 arguments: buffer, width, height")); + } + + // Extract buffer + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + + // Extract width and height + mp_int_t width = mp_obj_get_int(args[1]); + mp_int_t height = mp_obj_get_int(args[2]); + + // Validate dimensions + if (width <= 0 || height <= 0) { + mp_raise_ValueError(MP_ERROR_TEXT("width and height must be positive")); + } + if (bufinfo.len != (size_t)(width * height)) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer size must match width * height")); + } + + // Initialize quirc + struct quirc *qr = quirc_new(); + if (!qr) { + mp_raise_OSError(MP_ENOMEM); + } + + // Resize quirc for the image dimensions + if (quirc_resize(qr, width, height) < 0) { + quirc_destroy(qr); + mp_raise_OSError(MP_ENOMEM); + } + + // Get quirc image buffer and copy grayscale data + uint8_t *image; + quirc_begin(qr, NULL, NULL); + image = quirc_begin(qr, NULL, NULL); // Get pointer to quirc's image buffer + memcpy(image, bufinfo.buf, width * height); // Copy buffer directly (grayscale, 8-bit) + quirc_end(qr); + + // Check for QR codes + int count = quirc_count(qr); + if (count == 0) { + quirc_destroy(qr); + mp_raise_ValueError(MP_ERROR_TEXT("no QR code found")); + } + + // Extract and decode the first QR code + struct quirc_code code; + struct quirc_data data; + quirc_extract(qr, 0, &code); // Extract first QR code + + // Decode the QR code + int err = quirc_decode(&code, &data); + if (err != QUIRC_SUCCESS) { + quirc_destroy(qr); + mp_raise_ValueError(MP_ERROR_TEXT("failed to decode QR code")); + } + + // Convert decoded data to Python string + mp_obj_t result = mp_obj_new_str((const char *)data.payload, data.payload_len); + + // Clean up + quirc_destroy(qr); + + return result; +} + +// Define the MicroPython function +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qrdecode_obj, 3, 3, qrdecode); + +// Module definition +static const mp_rom_map_elem_t qrdecode_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_qrdecode) }, + { MP_ROM_QSTR(MP_QSTR_qrdecode), MP_ROM_PTR(&qrdecode_obj) }, +}; + +static MP_DEFINE_CONST_DICT(qrdecode_module_globals, qrdecode_module_globals_table); + +const mp_obj_module_t qrdecode_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&qrdecode_module_globals, +}; + +// Register the module +MP_REGISTER_MODULE(MP_QSTR_qrdecode, qrdecode_module); diff --git a/draft_code/qrdecode.py b/draft_code/qrdecode.py new file mode 100644 index 00000000..fb25c06d --- /dev/null +++ b/draft_code/qrdecode.py @@ -0,0 +1,29 @@ +import qrdecode + + +# Image dimensions +width = 240 +height = 240 +buffer_size = width * height # 240 * 240 = 57600 bytes +try: + # Allocate buffer for grayscale image + buffer = bytearray(buffer_size) + # Read the raw grayscale image file + with open('qrcode2.raw', 'rb') as f: + bytes_read = f.readinto(buffer) + if bytes_read != buffer_size: + raise ValueError("File size does not match expected 240x240 grayscale image") + # Decode QR code using qrdecode module + print("decoding...") + result = qrdecode.qrdecode(buffer, width, height) + print(f"result: {result}") + # Remove BOM (\ufeff) from the start of the decoded string, if present + if result.startswith('\ufeff'): + result = result[1:] + print(f"result: {result}") +except OSError as e: + print("Error reading file:", e) + raise +except ValueError as e: + print("Error:", e) + raise diff --git a/internal_filesystem/apps/com.example.camtest/assets/camtest.py b/internal_filesystem/apps/com.example.camtest/assets/camtest.py index 0fa81e3c..3d59d9de 100644 --- a/internal_filesystem/apps/com.example.camtest/assets/camtest.py +++ b/internal_filesystem/apps/com.example.camtest/assets/camtest.py @@ -4,6 +4,10 @@ keepgoing = True width = 240 height = 240 +# Variable to hold the current memoryview to prevent garbage collection +current_cam_buffer = None + + cont = lv.obj(appscreen) cont.set_style_pad_all(0, 0) cont.set_style_border_width(0, 0) @@ -12,19 +16,59 @@ cont.set_scrollbar_mode(lv.SCROLLBAR_MODE.OFF) snap_button = lv.button(cont) snap_button.set_size(60, 60) -snap_button.align(lv.ALIGN.RIGHT_MID, 0, -20) +snap_button.align(lv.ALIGN.RIGHT_MID, 0, 0) snap_label = lv.label(snap_button) snap_label.set_text(lv.SYMBOL.OK) snap_label.center() + def snap_button_click(e): print("Picture taken!") - # TODO: keep it on-screen for a while, or save it to storage, or show it in miniature + try: + import os + os.mkdir("data") + os.mkdir("data/com.example.camtest") + except OSError: + pass + if current_cam_buffer is not None: + filename="data/com.example.camtest/capture.raw" + try: + with open(filename, 'wb') as f: + f.write(current_cam_buffer) + print(f"Successfully wrote current_cam_buffer to {filename}") + except OSError as e: + print(f"Error writing to file: {e}") snap_button.add_event_cb(snap_button_click,lv.EVENT.CLICKED,None) +qr_button = lv.button(cont) +qr_button.set_size(60, 60) +qr_button.align(lv.ALIGN.BOTTOM_RIGHT, 0, 0) +qr_label = lv.label(qr_button) +qr_label.set_text(lv.SYMBOL.EYE_OPEN) +qr_label.center() + +def qr_button_click(e): + print("Decoding QR") + # Image dimensions + width = 240 + height = 240 + buffer_size = width * height # 240 * 240 = 57600 bytes + try: + result = qrdecode.qrdecode(current_cam_buffer, width, height) + if result.startswith('\ufeff'): # Remove BOM (\ufeff) from the start of the decoded string, if present + result = result[1:] + print(f"QR decoding found: {result}") + except ValueError as e: + print("Error:", e) + raise + + +qr_button.add_event_cb(qr_button_click,lv.EVENT.CLICKED,None) + + close_button = lv.button(cont) -close_button.set_size(40,40) +close_button.set_size(60,60) close_button.align(lv.ALIGN.TOP_RIGHT, 0, 0) close_label = lv.label(close_button) close_label.set_text(lv.SYMBOL.CLOSE) @@ -50,7 +94,8 @@ cam = Camera( xclk_freq=20000000, powerdown_pin=-1, reset_pin=-1, - pixel_format=PixelFormat.RGB565, + #pixel_format=PixelFormat.RGB565, + pixel_format=PixelFormat.GRAYSCALE, frame_size=FrameSize.R240X240, grab_mode=GrabMode.LATEST ) @@ -75,18 +120,17 @@ image_dsc = lv.image_dsc_t({ "magic": lv.IMAGE_HEADER_MAGIC, "w": width, "h": height, - "stride": width * 2, - "cf": lv.COLOR_FORMAT.RGB565 + "stride": width , + #"cf": lv.COLOR_FORMAT.RGB565 + "cf": lv.COLOR_FORMAT.L8 }, - 'data_size': width * height * 2, + 'data_size': width * height, 'data': None # Will be updated per frame }) # Set initial image source (optional, can be set in try_capture) image.set_src(image_dsc) -# Variable to hold the current memoryview to prevent garbage collection -current_cam_buffer = None def try_capture(): global current_cam_buffer