From bfe0258918f53e637f552a0872f897a917832d5b Mon Sep 17 00:00:00 2001 From: Raj Nakarja Date: Mon, 9 Dec 2024 12:26:33 +0100 Subject: [PATCH 1/5] Reset working on both hardware versions --- .vscode/launch.json | 4 +-- source/application/bluetooth.c | 37 +++++++++++--------- source/application/bluetooth.h | 6 +++- source/application/flash.c | 10 ++++-- source/application/luaport.c | 4 +-- source/application/luaport.h | 2 +- source/application/main.c | 62 ++++++++++++++++++++++++++++------ source/pinout.h | 8 ++++- 8 files changed, 98 insertions(+), 35 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index dc476f28..6d21085e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -71,8 +71,8 @@ "BMPGDBSerialPort": "/dev/ttyACM0", }, "osx": { - // "BMPGDBSerialPort": "/dev/cu.usbmodem72ADB7F21", - "BMPGDBSerialPort": "/dev/cu.usbmodem72AE45F31", + // "BMPGDBSerialPort": "/dev/cu.usbmodem72AE45F31", + "BMPGDBSerialPort": "/dev/cu.usbmodem72AE30F31", } }, { diff --git a/source/application/bluetooth.c b/source/application/bluetooth.c index 46a938c4..dc966465 100644 --- a/source/application/bluetooth.c +++ b/source/application/bluetooth.c @@ -356,7 +356,7 @@ void SD_EVT_IRQHandler(void) } } -void bluetooth_setup(bool factory_reset, bool *is_paired) +void bluetooth_setup() { // Enable the softdevice using internal RC oscillator check_error(sd_softdevice_enable(NULL, softdevice_assert_handler)); @@ -433,21 +433,6 @@ void bluetooth_setup(bool factory_reset, bool *is_paired) bond.sec_param.kdist_peer.enc = 1; bond.sec_param.kdist_peer.id = 1; - if (factory_reset) - { - flash_erase_page(bond_storage); - flash_wait_until_complete(); - } - - // Check if already paired - ble_gap_enc_info_t zero_struct; - memset(&zero_struct, 0xFF, sizeof(ble_gap_enc_info_t)); - if (memcmp((void *)bond_storage, &zero_struct, sizeof(ble_gap_enc_info_t))) - { - LOG("Device is paired"); - *is_paired = true; - } - // Read stored encryption key from memory memcpy(&bond.own_key.enc_info, (void *)bond_storage, @@ -578,6 +563,26 @@ void bluetooth_setup(bool factory_reset, bool *is_paired) check_error(sd_ble_gap_adv_start(ble_handles.advertising, 1)); } +bool bluetooth_is_paired(void) +{ + bool is_paired = false; + + ble_gap_enc_info_t zero_struct; + memset(&zero_struct, 0xFF, sizeof(ble_gap_enc_info_t)); + if (memcmp((void *)bond_storage, &zero_struct, sizeof(ble_gap_enc_info_t))) + { + is_paired = true; + } + + return is_paired; +} + +void bluetooth_unpair(void) +{ + flash_erase_page(bond_storage); + flash_wait_until_complete(); +} + bool bluetooth_is_connected(void) { return ble_handles.connection == BLE_CONN_HANDLE_INVALID ? false : true; diff --git a/source/application/bluetooth.h b/source/application/bluetooth.h index ff46f8bd..47e34dfd 100644 --- a/source/application/bluetooth.h +++ b/source/application/bluetooth.h @@ -31,7 +31,11 @@ #define BLE_PREFERRED_MAX_MTU 247 extern uint16_t ble_negotiated_mtu; -void bluetooth_setup(bool factory_reset, bool *is_paired); +void bluetooth_setup(void); + +bool bluetooth_is_paired(void); + +void bluetooth_unpair(void); bool bluetooth_is_connected(void); diff --git a/source/application/flash.c b/source/application/flash.c index 55786a3f..5a8d2dfb 100644 --- a/source/application/flash.c +++ b/source/application/flash.c @@ -27,6 +27,7 @@ #include "error_logging.h" #include "lfs.h" #include "main.h" +#include "nrf_sdm.h" #include "nrf_soc.h" #include "nrfx_log.h" @@ -62,9 +63,14 @@ void flash_write(uint32_t address, const uint32_t *data, size_t length) void flash_wait_until_complete(void) { - // TODO add a timeout - while (flash_is_busy) + uint8_t sd_is_enabled = false; + sd_softdevice_is_enabled(&sd_is_enabled); + + if (sd_is_enabled == 1) { + while (flash_is_busy) + { + } } } diff --git a/source/application/luaport.c b/source/application/luaport.c index aa8fad15..5a9f22b0 100644 --- a/source/application/luaport.c +++ b/source/application/luaport.c @@ -63,7 +63,7 @@ void lua_break_signal_interrupt(void) 1); } -void run_lua(bool factory_reset, bool is_paired) +void run_lua(bool is_paired) { lua_State *L = luaL_newstate(); L_global = L; // Only used for interrupts @@ -99,7 +99,7 @@ void run_lua(bool factory_reset, bool is_paired) lua_open_imu_library(L); lua_open_time_library(L); - lua_open_file_library(L, factory_reset); + lua_open_file_library(L, !is_paired); // Make sure the above functions cleared up the stack correctly if (lua_gettop(L) != 0) diff --git a/source/application/luaport.h b/source/application/luaport.h index 00c38134..00cca7da 100644 --- a/source/application/luaport.h +++ b/source/application/luaport.h @@ -38,4 +38,4 @@ void lua_write_to_repl(uint8_t *buffer, uint8_t length); void lua_break_signal_interrupt(void); -void run_lua(bool factory_reset, bool is_paired); \ No newline at end of file +void run_lua(bool is_paired); \ No newline at end of file diff --git a/source/application/main.c b/source/application/main.c index e870605f..0e8c31c8 100644 --- a/source/application/main.c +++ b/source/application/main.c @@ -164,6 +164,15 @@ void case_detect_pin_interrupt_handler(nrfx_gpiote_pin_t unused_gptiote_pin, shutdown(false); } +void frame_lite_button_interrupt_handler(nrfx_gpiote_pin_t unused_gptiote_pin, + nrfx_gpiote_trigger_t unused_gptiote_trigger, + void *unused_gptiote_context_pointer) +{ + nrfx_gpiote_trigger_disable(FRAME_LITE_BUTTON_PIN); + bluetooth_unpair(); + NVIC_SystemReset(); +} + static void fpga_send_bitstream_bytes(void *context, void *data, size_t data_size) @@ -171,7 +180,7 @@ static void fpga_send_bitstream_bytes(void *context, spi_write_raw(FPGA, data, data_size); } -static void hardware_setup(bool *factory_reset) +static void hardware_setup() { // Configure watchdog { @@ -183,6 +192,20 @@ static void hardware_setup(bool *factory_reset) nrfx_systick_init(); } + // Check if Frame or Frame lite + { + nrf_gpio_cfg_input(FRAME_LITE_HW_DETECT_PIN, NRF_GPIO_PIN_PULLUP); + + if (nrf_gpio_pin_read(FRAME_LITE_HW_DETECT_PIN)) + { + LOG("Running on Frame"); + } + else + { + LOG("Running on Frame Lite"); + } + } + // Configure the I2C and SPI drivers { i2c_configure(); @@ -299,7 +322,7 @@ static void hardware_setup(bool *factory_reset) else { LOG("Factory reset"); - *factory_reset = true; + bluetooth_unpair(); stay_awake = true; } } @@ -308,6 +331,30 @@ static void hardware_setup(bool *factory_reset) nrfx_gpiote_trigger_enable(CASE_DETECT_PIN, true); } + // Configure the Frame lite button + { + nrfx_gpiote_input_config_t input_config = { + .pull = NRF_GPIO_PIN_PULLUP, + }; + + nrfx_gpiote_trigger_config_t trigger_config = { + .trigger = NRFX_GPIOTE_TRIGGER_HITOLO, + .p_in_channel = NULL, + }; + + nrfx_gpiote_handler_config_t handler_config = { + .handler = frame_lite_button_interrupt_handler, + .p_context = NULL, + }; + + check_error(nrfx_gpiote_input_configure(FRAME_LITE_BUTTON_PIN, + &input_config, + &trigger_config, + &handler_config)); + + nrfx_gpiote_trigger_enable(FRAME_LITE_BUTTON_PIN, true); + } + // Load and start the FPGA image { nrf_gpio_cfg_output(FPGA_PROGRAM_PIN); @@ -412,19 +459,14 @@ int main(void) { LOG("Frame firmware " BUILD_VERSION " (" GIT_COMMIT ")"); - bool factory_reset = false; - bool is_paired = false; + hardware_setup(); - hardware_setup(&factory_reset); - - bluetooth_setup(factory_reset, &is_paired); + bluetooth_setup(); while (1) { reload_watchdog(NULL, NULL); - run_lua(factory_reset, is_paired); - - factory_reset = false; + run_lua(bluetooth_is_paired()); } } \ No newline at end of file diff --git a/source/pinout.h b/source/pinout.h index 3780ede3..0a433f36 100644 --- a/source/pinout.h +++ b/source/pinout.h @@ -48,4 +48,10 @@ #define IMU_INTERRUPT_PIN NRF_GPIO_PIN_MAP(1, 5) #define MICROPHONE_CLOCK_PIN NRF_GPIO_PIN_MAP(0, 4) -#define MICROPHONE_DATA_PIN NRF_GPIO_PIN_MAP(0, 1) \ No newline at end of file +#define MICROPHONE_DATA_PIN NRF_GPIO_PIN_MAP(0, 1) + +#define FRAME_LITE_HW_DETECT_PIN NRF_GPIO_PIN_MAP(0, 9) // Inverted pin +#define FRAME_LITE_BUTTON_PIN NRF_GPIO_PIN_MAP(1, 0) // Inverted pin +#define FRAME_LITE_LED_RED_PIN NRF_GPIO_PIN_MAP(1, 7) +#define FRAME_LITE_LED_GREEN_PIN NRF_GPIO_PIN_MAP(1, 4) +#define FRAME_LITE_LED_BLUE_PIN NRF_GPIO_PIN_MAP(1, 1) From da746035632169ab42506d777e5e926ac6cc1da7 Mon Sep 17 00:00:00 2001 From: Raj Nakarja Date: Tue, 10 Dec 2024 10:14:19 +0100 Subject: [PATCH 2/5] Added initial LED driver --- source/application/Makefile | 2 + .../lua_libraries/frame_lua_libraries.h | 1 + source/application/lua_libraries/led.c | 93 +++++++++++++++++++ source/application/luaport.c | 1 + source/application/nrfx_config.h | 5 + tests/test_led.py | 26 ++++++ 6 files changed, 128 insertions(+) create mode 100644 source/application/lua_libraries/led.c create mode 100644 tests/test_led.py diff --git a/source/application/Makefile b/source/application/Makefile index 9011df40..54bfd551 100644 --- a/source/application/Makefile +++ b/source/application/Makefile @@ -42,6 +42,7 @@ C_FILES += \ lua_libraries/display.c \ lua_libraries/file.c \ lua_libraries/imu.c \ + lua_libraries/led.c \ lua_libraries/microphone.c \ lua_libraries/system.c \ lua_libraries/time.c \ @@ -85,6 +86,7 @@ C_FILES += \ $(LIBRARIES)/lz4/lz4.c \ $(LIBRARIES)/nrfx/drivers/src/nrfx_gpiote.c \ $(LIBRARIES)/nrfx/drivers/src/nrfx_pdm.c \ + $(LIBRARIES)/nrfx/drivers/src/nrfx_pwm.c \ $(LIBRARIES)/nrfx/drivers/src/nrfx_rtc.c \ $(LIBRARIES)/nrfx/drivers/src/nrfx_saadc.c \ $(LIBRARIES)/nrfx/drivers/src/nrfx_spim.c \ diff --git a/source/application/lua_libraries/frame_lua_libraries.h b/source/application/lua_libraries/frame_lua_libraries.h index 599912ae..a7151ae6 100644 --- a/source/application/lua_libraries/frame_lua_libraries.h +++ b/source/application/lua_libraries/frame_lua_libraries.h @@ -35,6 +35,7 @@ void lua_open_bluetooth_library(lua_State *L); void lua_open_camera_library(lua_State *L); void lua_open_display_library(lua_State *L); void lua_open_imu_library(lua_State *L); +void lua_open_led_library(lua_State *L); void lua_open_microphone_library(lua_State *L); void lua_open_system_library(lua_State *L); void lua_open_time_library(lua_State *L); diff --git a/source/application/lua_libraries/led.c b/source/application/lua_libraries/led.c new file mode 100644 index 00000000..55dc04af --- /dev/null +++ b/source/application/lua_libraries/led.c @@ -0,0 +1,93 @@ +/* + * This file is a part of: https://github.com/brilliantlabsAR/frame-codebase + * + * Authored by: Raj Nakarja / Brilliant Labs Ltd. (raj@brilliant.xyz) + * Rohit Rathnam / Silicon Witchery AB (rohit@siliconwitchery.com) + * Uma S. Gupta / Techno Exponent (umasankar@technoexponent.com) + * + * ISC Licence + * + * Copyright © 2024 Brilliant Labs Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "error_logging.h" +#include "lauxlib.h" +#include "lua.h" +#include "nrfx_log.h" +#include "nrfx_pwm.h" +#include "pinout.h" + +static const nrfx_pwm_t pwm = NRFX_PWM_INSTANCE(0); + +static int lua_led_set_color(lua_State *L) +{ + lua_Integer red = luaL_checkinteger(L, 1); + lua_Integer green = luaL_checkinteger(L, 2); + lua_Integer blue = luaL_checkinteger(L, 3); + + if (red < 0 || red > 100 || green < 0 || green > 100 || blue < 0 || blue > 100) + { + luaL_error(L, "led color must be between 0 and 100"); + } + + static nrf_pwm_values_individual_t seq_values; + + seq_values.channel_0 = (uint16_t)red; + seq_values.channel_1 = (uint16_t)green; + seq_values.channel_2 = (uint16_t)blue; + + nrf_pwm_sequence_t const seq = { + .values.p_individual = &seq_values, + .length = NRF_PWM_VALUES_LENGTH(seq_values), + .repeats = 0, + .end_delay = 0, + }; + + nrfx_pwm_simple_playback(&pwm, &seq, 1, NRFX_PWM_FLAG_LOOP); + + return 0; +} + +void lua_open_led_library(lua_State *L) +{ + nrfx_pwm_config_t config = NRFX_PWM_DEFAULT_CONFIG( + FRAME_LITE_LED_RED_PIN, + FRAME_LITE_LED_GREEN_PIN, + FRAME_LITE_LED_BLUE_PIN, + NRF_PWM_PIN_NOT_CONNECTED); + + config.pin_inverted[0] = true; + config.pin_inverted[1] = true; + config.pin_inverted[2] = true; + + config.load_mode = NRF_PWM_LOAD_INDIVIDUAL; + config.top_value = 100; + + if (nrfx_pwm_init_check(&pwm) == false) + { + nrfx_pwm_init(&pwm, &config, NULL, NULL); + } + + lua_getglobal(L, "frame"); + + lua_newtable(L); + + lua_pushcfunction(L, lua_led_set_color); + lua_setfield(L, -2, "set_color"); + + lua_setfield(L, -2, "led"); + + lua_pop(L, 1); +} \ No newline at end of file diff --git a/source/application/luaport.c b/source/application/luaport.c index 5a9f22b0..befdd804 100644 --- a/source/application/luaport.c +++ b/source/application/luaport.c @@ -98,6 +98,7 @@ void run_lua(bool is_paired) lua_open_microphone_library(L); lua_open_imu_library(L); lua_open_time_library(L); + lua_open_led_library(L); lua_open_file_library(L, !is_paired); diff --git a/source/application/nrfx_config.h b/source/application/nrfx_config.h index 274e59ed..f4f168eb 100644 --- a/source/application/nrfx_config.h +++ b/source/application/nrfx_config.h @@ -33,6 +33,11 @@ #define NRFX_PDM_ENABLED 1 #define NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY 5 +#define NRFX_PWM_ENABLED 1 +#define NRFX_PWM0_ENABLED 1 +#define NRFX_PWM1_ENABLED 1 +#define NRFX_PWM2_ENABLED 1 + #define NRFX_RTC_ENABLED 1 #define NRFX_RTC1_ENABLED 1 diff --git a/tests/test_led.py b/tests/test_led.py new file mode 100644 index 00000000..22f4f1ad --- /dev/null +++ b/tests/test_led.py @@ -0,0 +1,26 @@ +""" +Tests the Frame specific Lua libraries over Bluetooth. +""" + +import asyncio +from frameutils import Bluetooth + + +async def main(): + b = Bluetooth() + + await b.connect(print_response_handler=lambda s: print(s)) + + # await b.send_lua("frame.led.set_color(100, 0, 0)") + await asyncio.sleep(1) + + # await b.send_lua("frame.led.set_color(0, 100, 0)") + await asyncio.sleep(1) + + await b.send_lua("frame.led.set_color(0, 0, 100)") + await asyncio.sleep(1) + + await b.disconnect() + + +asyncio.run(main()) From 7069aa94969d99445cecb279aec0204c7b2a5f65 Mon Sep 17 00:00:00 2001 From: Raj Nakarja Date: Fri, 13 Dec 2024 09:49:07 +0100 Subject: [PATCH 3/5] Added LED and display animation tests --- tests/test_display_animation.py | 134 ++++++++++++++++++++++++++++++++ tests/test_led.py | 4 +- 2 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 tests/test_display_animation.py diff --git a/tests/test_display_animation.py b/tests/test_display_animation.py new file mode 100644 index 00000000..6bf306ef --- /dev/null +++ b/tests/test_display_animation.py @@ -0,0 +1,134 @@ +from aioconsole import ainput +from frameutils import Bluetooth +import asyncio +import time + + +async def main(): + + main_script = """ + require("graphics") + + local graphics = Graphics.new() + local last_print_time = 0 + + graphics:append_text("This is a test. The quick brown fox jumps over the lazy dog.", "\\u{F0000}") + + while true do + if frame.time.utc() - last_print_time > 0.07 then + graphics:print() + last_print_time = frame.time.utc() + end + + collectgarbage("collect") + end + """ + + graphics_script = r""" + Graphics = {} + Graphics.__index = Graphics + + function Graphics.new() + local self = setmetatable({}, Graphics) + self:clear() + return self + end + + function Graphics:clear() + -- Set by append_text function + self.__text = "" + self.__emoji = "" + -- Used internally by print function + self.__this_line = "" + self.__last_line = "" + self.__last_last_line = "" + self.__starting_index = 1 + self.__current_index = 1 + self.__ending_index = 1 + self.__done_function = (function() end)() + end + + function Graphics:append_text(data, emoji) + self.__text = self.__text .. string.gsub(data, '\\n+', ' ') + self.__emoji = emoji + end + + function Graphics:on_complete(func) + self.__done_function = func + end + + function Graphics.__print_layout(last_last_line, last_line, this_line, emoji) + local TOP_MARGIN = 118 + local LINE_SPACING = 58 + local EMOJI_MAX_WIDTH = 91 + + frame.display.text(emoji, 640 - EMOJI_MAX_WIDTH, TOP_MARGIN, { color = 'YELLOW' }) + + if last_last_line == '' and last_line == '' then + frame.display.text(this_line, 1, TOP_MARGIN) + elseif last_last_line == '' then + frame.display.text(last_line, 1, TOP_MARGIN) + frame.display.text(this_line, 1, TOP_MARGIN + LINE_SPACING) + else + frame.display.text(last_last_line, 1, TOP_MARGIN) + frame.display.text(last_line, 1, TOP_MARGIN + LINE_SPACING) + frame.display.text(this_line, 1, TOP_MARGIN + LINE_SPACING * 2) + end + + frame.display.show() + end + + function Graphics:print() + if self.__text:sub(self.__starting_index, self.__starting_index) == ' ' then + self.__starting_index = self.__starting_index + 1 + end + + if self.__current_index >= self.__ending_index then + self.__starting_index = self.__ending_index + self.__last_last_line = self.__last_line + self.__last_line = self.__this_line + self.__starting_index = self.__ending_index + end + + for i = self.__starting_index + 22, self.__starting_index, -1 do + if self.__text:sub(i, i) == ' ' or self.__text:sub(i, i) == '' then + self.__ending_index = i + break + end + end + + self.__this_line = self.__text:sub(self.__starting_index, self.__current_index) + + self.__print_layout(self.__last_last_line, self.__last_line, self.__this_line, self.__emoji) + + if self.__current_index >= #self.__text then + pcall(self.__done_function) + self.__done_function = (function() end)() + return + end + + self.__current_index = self.__current_index + 1 + end + """ + + # Connect to bluetooth and upload file + b = Bluetooth() + await b.connect( + print_response_handler=lambda s: print(s), + ) + + print("Uploading script") + + await b.upload_file(graphics_script, "graphics.lua") + await b.upload_file(main_script, "main.lua") + await b.send_reset_signal() + + # Wait until a keypress + await ainput("") + + await b.send_break_signal() + await b.disconnect() + + +loop = asyncio.new_event_loop() +loop.run_until_complete(main()) diff --git a/tests/test_led.py b/tests/test_led.py index 22f4f1ad..3e92c948 100644 --- a/tests/test_led.py +++ b/tests/test_led.py @@ -11,10 +11,10 @@ async def main(): await b.connect(print_response_handler=lambda s: print(s)) - # await b.send_lua("frame.led.set_color(100, 0, 0)") + await b.send_lua("frame.led.set_color(100, 0, 0)") await asyncio.sleep(1) - # await b.send_lua("frame.led.set_color(0, 100, 0)") + await b.send_lua("frame.led.set_color(0, 100, 0)") await asyncio.sleep(1) await b.send_lua("frame.led.set_color(0, 0, 100)") From a57276b7189f27511e56720b7676313e4f28b003 Mon Sep 17 00:00:00 2001 From: Raj Nakarja Date: Mon, 16 Dec 2024 15:02:20 +0100 Subject: [PATCH 4/5] Added display/LED test to production script Refactored production & mic test scripts Added Lua frame.HARDWARE_VERSION string --- production/production_script.sh | 229 ++++++++++-------- production/test_display_led_script.py | 38 +++ ..._script.py => test_focus_camera_script.py} | 12 +- production/test_microphone_script.py | 73 ++++-- source/application/lua_libraries/version.c | 4 + source/application/main.c | 24 +- source/application/main.h | 2 + tests/test_api.py | 1 + 8 files changed, 245 insertions(+), 138 deletions(-) create mode 100644 production/test_display_led_script.py rename production/{focus_camera_script.py => test_focus_camera_script.py} (97%) diff --git a/production/production_script.sh b/production/production_script.sh index 97319d88..8d2d53d9 100755 --- a/production/production_script.sh +++ b/production/production_script.sh @@ -8,21 +8,25 @@ echo "-----------------------" while : do + NOW=`date -u +'%d/%m/%Y - %H:%M:%S'` + echo "" - read -p "Press Enter key to start, or Ctrl-C to quit" echo "" >> log.txt + read -p "Press Enter key to start, or Ctrl-C to quit" # Automatically assign port depending if MacOS or Linux if [ "`uname`" = Darwin ]; then - PORT=`ls /dev/cu.usbmodem*1 2> /dev/null | grep "cu."` + PORT=`ls /dev/cu.usbmodem*1 2> /dev/null` else - PORT=/dev/ttyACM0 2> /dev/null + PORT=`ls /dev/ttyACM0 2> /dev/null` fi - # Create timestamp - NOW=`date -u +'%d/%m/%Y - %H:%M:%S'` + if [ $? -eq 1 ]; then + echo "$NOW - Error: Programmer not found" | tee -a log.txt + continue + fi - # Unlock chip + # Unlock chip (and ignore errors) echo "$NOW - Unlocking chip" | tee -a log.txt arm-none-eabi-gdb \ -nx \ @@ -44,105 +48,122 @@ do -ex "monitor erase_mass" \ 2> /dev/null - # If successful, continue otherwise throw and error and return to top of loop - if [ $? -eq 0 ]; then - - # Get and print device ID - echo -n "$NOW - " | tee -a log.txt - arm-none-eabi-gdb \ - -nx \ - --batch-silent \ - -ex "target extended-remote ${PORT}" \ - -ex "monitor swd_scan" \ - -ex "attach 1" \ - -ex "set logging file /dev/stdout" \ - -ex "set logging enabled on" \ - -ex "monitor read deviceid" \ - -ex "set logging enabled off" \ - 2> /dev/null \ - | tee -a log.txt - - # Get and print device address - echo -n "$NOW - " | tee -a log.txt - arm-none-eabi-gdb \ - -nx \ - --batch-silent \ - -ex "target extended-remote ${PORT}" \ - -ex "monitor swd_scan" \ - -ex "attach 1" \ - -ex "set logging file /dev/stdout" \ - -ex "set logging enabled on" \ - -ex "monitor read deviceaddr" \ - -ex "set logging enabled off" \ - 2> /dev/null \ - | tee -a log.txt - - # Program sections - echo "$NOW - Programming chip. Please wait" - arm-none-eabi-gdb \ - -nx \ - --batch-silent \ - -ex "target extended-remote ${PORT}" \ - -ex 'monitor swd_scan' \ - -ex 'attach 1' \ - -ex 'load' \ - -ex 'compare-sections' \ - -ex 'kill' \ - frame-firmware-v*.hex \ - 2> /dev/null - - # If successful, start the camera focusing script otherwise throw error - if [ $? -eq 0 ]; then - echo "$NOW - Programmed successfully" | tee -a log.txt - echo -n " Press y if display is working, otherwise n" - read -s -n1 input - - # If okay, test the microphone - if [ $input == "y" ]; then - echo -e -n $"\r\033[2K" - echo "$NOW - Display okay" | tee -a log.txt - - echo -e -n " Recording audio\r" - python test_microphone_script.py - echo -e -n $"\r\033[2K" - echo -n " Press y if microphone is working, otherwise n" - read -s -n1 input - - # Run the camera focusing script - if [ $input == "y" ]; then - echo -e -n $"\r\033[2K" - echo "$NOW - Microphone okay" | tee -a log.txt - - python focus_camera_script.py 2> /dev/null - - # Done - if [ $? -eq 0 ]; then - - echo -e -n $"\r\033[2K" - echo "$NOW - Camera focused" | tee -a log.txt - echo "$NOW - Done" | tee -a log.txt - - else - echo -e -n $"\r\033[2K" - echo "$NOW - Error: Could not connect to start focusing" | tee -a log.txt - fi - - else - echo -e -n $"\r\033[2K" - echo "$NOW - Error: Microphone not working" | tee -a log.txt - fi - - else - echo -e -n $"\r\033[2K" - echo "$NOW - Error: Display not working" | tee -a log.txt - fi - - else - echo "$NOW - Error: Chip could not be programmed" | tee -a log.txt - fi - - else + if [ $? -eq 1 ]; then echo "$NOW - Error: Chip not found" | tee -a log.txt + continue + fi + + # Get and print device ID + echo -n "$NOW - " | tee -a log.txt + arm-none-eabi-gdb \ + -nx \ + --batch-silent \ + -ex "target extended-remote ${PORT}" \ + -ex "monitor swd_scan" \ + -ex "attach 1" \ + -ex "set logging file /dev/stdout" \ + -ex "set logging enabled on" \ + -ex "monitor read deviceid" \ + -ex "set logging enabled off" \ + 2> /dev/null \ + | tee -a log.txt + + # Get and print device address + echo -n "$NOW - " | tee -a log.txt + arm-none-eabi-gdb \ + -nx \ + --batch-silent \ + -ex "target extended-remote ${PORT}" \ + -ex "monitor swd_scan" \ + -ex "attach 1" \ + -ex "set logging file /dev/stdout" \ + -ex "set logging enabled on" \ + -ex "monitor read deviceaddr" \ + -ex "set logging enabled off" \ + 2> /dev/null \ + | tee -a log.txt + + # Program sections + echo "$NOW - Programming chip. Please wait" + arm-none-eabi-gdb \ + -nx \ + --batch-silent \ + -ex "target extended-remote ${PORT}" \ + -ex 'monitor swd_scan' \ + -ex 'attach 1' \ + -ex 'load' \ + -ex 'compare-sections' \ + -ex 'kill' \ + frame-firmware-v*.hex \ + 2> /dev/null + + if [ $? -eq 1 ]; then + echo "$NOW - Error: Chip could not be programmed" | tee -a log.txt + continue + fi + + echo "$NOW - Programmed successfully" | tee -a log.txt + + # Short delay to allow the chip to boot + sleep 3 + + # Test display/LED + echo -e -n " Running display/LED test\r" + python test_display_led_script.py 2> /dev/null + + if [ $? -eq 1 ]; then + echo -e -n $"\r\033[2K" + echo "$NOW - Error: Could not connect to start microphone test" | tee -a log.txt + continue + fi + + echo -n " Press y if display/LED is working, otherwise n" + read -s -n1 input + + if [ $input == "n" ]; then + echo -e -n $"\r\033[2K" + echo "$NOW - Error: Display/LED not working" | tee -a log.txt + continue fi + echo -e -n $"\r\033[2K" + echo "$NOW - Display/LED okay" | tee -a log.txt + + # Test microphone + echo -e -n " Recording audio\r" + python test_microphone_script.py 2> /dev/null + + if [ $? -eq 1 ]; then + echo -e -n $"\r\033[2K" + echo "$NOW - Error: Could not connect to start microphone test" | tee -a log.txt + continue + fi + + echo -e -n $"\r\033[2K" + echo -n " Press y if microphone is working, otherwise n" + read -s -n1 input + + if [ $input == "n" ]; then + echo -e -n $"\r\033[2K" + echo "$NOW - Error: Microphone not working" | tee -a log.txt + continue + fi + + echo -e -n $"\r\033[2K" + echo "$NOW - Microphone okay" | tee -a log.txt + + # Run the camera focusing script + python test_focus_camera_script.py 2> /dev/null + + if [ $? -eq 1 ]; then + echo -e -n $"\r\033[2K" + echo "$NOW - Error: Could not connect to start focusing" | tee -a log.txt + continue + fi + + echo -e -n $"\r\033[2K" + echo "$NOW - Camera focused" | tee -a log.txt + + echo "$NOW - Done" | tee -a log.txt + done \ No newline at end of file diff --git a/production/test_display_led_script.py b/production/test_display_led_script.py new file mode 100644 index 00000000..9d8cf4c5 --- /dev/null +++ b/production/test_display_led_script.py @@ -0,0 +1,38 @@ +from frameutils import Bluetooth +import asyncio + +lua_script = """ +if frame.HARDWARE_VERSION == 'Frame' then + width = 640 + height = 400 + t = string.rep('\\xFF', width * height / 8) + frame.display.bitmap(1, 1, width, 2, 2, t) + frame.display.show() + frame.sleep(1) + frame.display.bitmap(1, 1, width, 2, 9, t) + frame.display.show() + frame.sleep(1) + frame.display.bitmap(1, 1, width, 2, 13, t) + frame.display.show() + frame.sleep(1) +else + frame.led.set_color(100, 0, 0) + frame.sleep(1) + frame.led.set_color(0, 100, 0) + frame.sleep(1) + frame.led.set_color(0, 0, 100) + frame.sleep(1) +end +""" + + +async def main(): + b = Bluetooth() + await b.connect() + await b.upload_file(lua_script, "main.lua") + await b.send_reset_signal() + await asyncio.sleep(3) + await b.disconnect() + + +asyncio.run(main()) diff --git a/production/focus_camera_script.py b/production/test_focus_camera_script.py similarity index 97% rename from production/focus_camera_script.py rename to production/test_focus_camera_script.py index 4e0b0587..d2cbf161 100644 --- a/production/focus_camera_script.py +++ b/production/test_focus_camera_script.py @@ -701,9 +701,15 @@ async def main(): local state = 'CAPTURE' local state_time = 0 - frame.camera.set_gain(0) - frame.camera.set_shutter(550) - frame.camera.set_white_balance(255, 255, 255) + if frame.HARDWARE_VERSION == 'Frame Lite' then + frame.camera.set_gain(0) + frame.camera.set_shutter(330) + frame.camera.set_white_balance(255, 120, 220) + else + frame.camera.set_gain(0) + frame.camera.set_shutter(550) + frame.camera.set_white_balance(255, 255, 255) + end while true do if state == 'CAPTURE' then diff --git a/production/test_microphone_script.py b/production/test_microphone_script.py index 7a0469f7..54a0a698 100644 --- a/production/test_microphone_script.py +++ b/production/test_microphone_script.py @@ -4,32 +4,66 @@ import sounddevice as sd audio_buffer = b"" -expected_length = 0 +done = False + +lua_script = """ +frame.microphone.start { bit_depth=16 } + +local start_time = frame.time.utc() + +while frame.time.utc() < start_time + 5 do + local len = (frame.bluetooth.max_length()//2)*2 + + s=frame.microphone.read(len) + + if s==nil then + break + end + + if s~='' then + while true do + if (pcall(frame.bluetooth.send,'0'..s)) then + break + end + end + end +end + +while true do + if (pcall(frame.bluetooth.send,'0')) then + break + end +end + +frame.microphone.stop() +""" def receive_data(data): global audio_buffer - audio_buffer += data - print( - f" Downloading microphone data {str(len(audio_buffer))} bytes ", - end="\r", - ) + global done + if len(data) > 1: + audio_buffer += data[1:] + print( + f" Downloading microphone data {str(len(audio_buffer))} bytes ", + end="\r", + ) -async def test_microphone(b: Bluetooth): - global audio_buffer - audio_buffer = b"" + else: + done = True - await b.send_lua("frame.microphone.start { bit_depth=16 }") - await b.send_lua( - "while true do s=frame.microphone.read((frame.bluetooth.max_length()//2)*2); if s==nil then break end if s~='' then while true do if (pcall(frame.bluetooth.send,s)) then break end end end end" - ) +async def main(): + b = Bluetooth() + await b.connect(data_response_handler=receive_data) + await b.upload_file(lua_script, "main.lua") + await b.send_reset_signal() - await asyncio.sleep(5) + while not done: + await asyncio.sleep(0.1) - await b.send_break_signal() - await b.send_lua(f"frame.microphone.stop()") + await b.disconnect() audio_data = np.frombuffer(audio_buffer, dtype=np.int16) audio_data = audio_data.astype(np.float32) @@ -39,11 +73,4 @@ async def test_microphone(b: Bluetooth): sd.wait() -async def main(): - b = Bluetooth() - await b.connect(data_response_handler=receive_data) - await test_microphone(b) - await b.disconnect() - - asyncio.run(main()) diff --git a/source/application/lua_libraries/version.c b/source/application/lua_libraries/version.c index 6f74312a..917401d8 100644 --- a/source/application/lua_libraries/version.c +++ b/source/application/lua_libraries/version.c @@ -23,11 +23,15 @@ */ #include "lua.h" +#include "main.h" void lua_open_version_library(lua_State *L) { lua_getglobal(L, "frame"); + lua_pushstring(L, get_hardware_string()); + lua_setfield(L, -2, "HARDWARE_VERSION"); + lua_pushstring(L, BUILD_VERSION); lua_setfield(L, -2, "FIRMWARE_VERSION"); diff --git a/source/application/main.c b/source/application/main.c index 0e8c31c8..3d913237 100644 --- a/source/application/main.c +++ b/source/application/main.c @@ -157,6 +157,21 @@ void shutdown(bool enable_imu_wakeup) } } +const char *get_hardware_string(void) +{ + const char *frame_lite_string = "Frame Lite"; + const char *frame_string = "Frame"; + + if (nrf_gpio_pin_read(FRAME_LITE_HW_DETECT_PIN)) + { + return frame_lite_string; + } + else + { + return frame_string; + } +} + void case_detect_pin_interrupt_handler(nrfx_gpiote_pin_t unused_gptiote_pin, nrfx_gpiote_trigger_t unused_gptiote_trigger, void *unused_gptiote_context_pointer) @@ -196,14 +211,7 @@ static void hardware_setup() { nrf_gpio_cfg_input(FRAME_LITE_HW_DETECT_PIN, NRF_GPIO_PIN_PULLUP); - if (nrf_gpio_pin_read(FRAME_LITE_HW_DETECT_PIN)) - { - LOG("Running on Frame"); - } - else - { - LOG("Running on Frame Lite"); - } + LOG("Running on %s", get_hardware_string()); } // Configure the I2C and SPI drivers diff --git a/source/application/main.h b/source/application/main.h index cd632e19..7e8c4d53 100644 --- a/source/application/main.h +++ b/source/application/main.h @@ -30,3 +30,5 @@ extern bool not_real_hardware; extern bool stay_awake; void shutdown(bool enable_imu_wakeup); + +const char *get_hardware_string(void); diff --git a/tests/test_api.py b/tests/test_api.py index cd5ccee2..710cd371 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -83,6 +83,7 @@ async def main(): await test.initialize() # Version + await test.lua_is_type("frame.HARDWARE_VERSION", "string") await test.lua_has_length("frame.FIRMWARE_VERSION", 12) await test.lua_has_length("frame.GIT_TAG", 7) From 44b5645a6b17e66f4aebc4b682fb4aaf1d822cd3 Mon Sep 17 00:00:00 2001 From: Raj Nakarja Date: Mon, 6 Jan 2025 10:51:03 +0100 Subject: [PATCH 5/5] Added device version test --- tests/test_version.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/test_version.py diff --git a/tests/test_version.py b/tests/test_version.py new file mode 100644 index 00000000..c7b1f1e9 --- /dev/null +++ b/tests/test_version.py @@ -0,0 +1,23 @@ +""" +Tests the Frame specific Lua libraries over Bluetooth. +""" + +import asyncio +from frameutils import Bluetooth + + +async def main(): + b = Bluetooth() + + await b.connect(print_response_handler=lambda s: print(s)) + + await b.send_lua("print(frame.HARDWARE_VERSION)") + await b.send_lua("print(frame.FIRMWARE_VERSION)") + await b.send_lua("print(frame.GIT_TAG)") + + await asyncio.sleep(1) + + await b.disconnect() + + +asyncio.run(main())