diff --git a/Friend/firmware/firmware_v1.0/CMakeLists.txt b/Friend/firmware/firmware_v1.0/CMakeLists.txt index 919dafa04..a592faa00 100644 --- a/Friend/firmware/firmware_v1.0/CMakeLists.txt +++ b/Friend/firmware/firmware_v1.0/CMakeLists.txt @@ -10,14 +10,13 @@ target_sources(app PRIVATE src/transport.c src/mic.c src/led.c - src/audio.c src/codec.c - src/nfc.c src/lib/battery/battery.c src/button.c src/speaker.c src/sdcard.c src/storage.c + # src/nfc.c future release ) target_sources_ifdef(CONFIG_CODEC_OPUS app PRIVATE @@ -168,3 +167,4 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_CONFIG_H") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_ALLOCA_H") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsingle-precision-constant") # A lot of constants are written as doubles set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_LRINT -DHAVE_LRINTF") + diff --git a/Friend/firmware/firmware_v1.0/prj_xiao_ble_sense_devkitv2-adafruit.conf b/Friend/firmware/firmware_v1.0/prj_xiao_ble_sense_devkitv2-adafruit.conf index 00b85b327..4c40cd2d4 100644 --- a/Friend/firmware/firmware_v1.0/prj_xiao_ble_sense_devkitv2-adafruit.conf +++ b/Friend/firmware/firmware_v1.0/prj_xiao_ble_sense_devkitv2-adafruit.conf @@ -22,15 +22,17 @@ CONFIG_BT_MAX_PAIRED=1 CONFIG_BT_DEVICE_APPEARANCE=22 CONFIG_BT_GATT_DYNAMIC_DB=y +# # Max transmit power supported by nRF52840 +# + CONFIG_BT_CTLR_TX_PWR_ANTENNA=8 CONFIG_BT_PHY_UPDATE=y -# CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -# CONFIG_BT_SMP=y -# CONFIG_BT_LL_SW_SPLIT=y # Alternative implementation - +# # Battery and Device Information services +# + CONFIG_BT_BAS=y CONFIG_BT_DIS=y CONFIG_BT_DIS_PNP=n @@ -41,7 +43,10 @@ CONFIG_BT_DIS_HW_REV=y CONFIG_BT_DIS_FW_REV_STR="1.0.5" CONFIG_BT_DIS_HW_REV_STR="Seeed Xiao BLE Sense" -# Large packets +# +# Large BLE packets / BLE Buffers +# + CONFIG_BT_L2CAP_TX_MTU=498 CONFIG_BT_L2CAP_TX_BUF_COUNT=10 # CONFIG_BT_ATT_TX_COUNT=10 @@ -55,27 +60,32 @@ CONFIG_BT_AUTO_DATA_LEN_UPDATE=y CONFIG_BT_USER_PHY_UPDATE=y CONFIG_BT_AUTO_PHY_UPDATE=y -# Codecs -# CONFIG_LIBLC3=y - +# # Debug +# # Enable the lines below to enable debug logs via UART/USB # CONFIG_DEBUG=y -# CONFIG_DEBUG_OPTIMIZATIONS=y # CONFIG_LOG=y # CONFIG_LOG_PRINTK=y # CONFIG_LOG_MODE_IMMEDIATE=y +# CONFIG_DEBUG_OPTIMIZATIONS=y # CONFIG_SERIAL=y # CONFIG_UART_CONSOLE=y # CONFIG_LOG_BACKEND_UART=y # CONFIG_LOG_BACKEND_UART_OUTPUT_TEXT=y # CONFIG_LOG_DEFAULT_LEVEL=3 +# # Debug (This value breaks some builds) +# + # CONFIG_ASSERT=y +# # Log Levels +# + # CONFIG_BT_DEBUG_LOG=y # CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y # CONFIG_BT_LOG_LEVEL_DBG=y @@ -90,14 +100,15 @@ CONFIG_BT_AUTO_PHY_UPDATE=y # CONFIG_BT_RX_STACK_SIZE=4096 # CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=4096 -# RTT -# CONFIG_UART_CONSOLE=n -# CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=2048 -# CONFIG_RTT_CONSOLE=y -# CONFIG_LOG_BACKEND_RTT=y +# +# Codecs +# CONFIG_CODEC_OPUS=y +# # SD Card Support (all devices required) +# + CONFIG_OFFLINE_STORAGE=y CONFIG_DISK_ACCESS=y CONFIG_FILE_SYSTEM=y @@ -110,62 +121,52 @@ CONFIG_MAIN_STACK_SIZE=5096 # CONFIG_SPI=y CONFIG_HEAP_MEM_POOL_SIZE=3048 -# # SD Card for Arduino Audio BFF (v2 device) -# CONFIG_MMC_STACK=y -# CONFIG_SDMMC_STACK=y -# # CONFIG_SDIO_STACK=y -# CONFIG_DISK_DRIVER_SDMMC=y -# CONFIG_SDHC=y -# CONFIG_SPI_SDHC=y - -# SD Card Support -# CONFIG_DISK_DRIVER_SDMMC=y -# CONFIG_MMC_STACK=y -# CONFIG_SDMMC_STACK=y -# CONFIG_SPI=y -# CONFIG_SDHC=y -# CONFIG_SPI_SDHC=y - -# File System -# CONFIG_FILE_SYSTEM=y -# CONFIG_FAT_FILESYSTEM_ELM=y -# CONFIG_FS_FATFS_LFN=y -# CONFIG_FS_FATFS_READ_ONLY=n -# CONFIG_FS_FATFS_MOUNT_MKFS=y -# CONFIG_FS_FATFS_EXFAT=y - +# # Increase stack and heap sizes +# + CONFIG_MAIN_STACK_SIZE=8192 CONFIG_HEAP_MEM_POOL_SIZE=4096 +# # Disable unused peripherals -# CONFIG_I2C=n +# +CONFIG_I2C=n # CONFIG_NRFX_TWIM0=n # CONFIG_NRFX_TWIM1=n -# Disable LSM6DSL sensor (accelerometer and gyroscope) -CONFIG_LSM6DSL=n +# +# LSM6DSL sensor (accelerometer and gyroscope) +# +CONFIG_LSM6DSL=y CONFIG_LSM6DSL_ENABLE_TEMP=n -CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y +# CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y CONFIG_SENSOR=y + +# # Speaker +# CONFIG_I2S=y CONFIG_I2S_NRFX=y CONFIG_SPI_NRFX=y -# NFC -CONFIG_NFC_T2T_NRFXLIB=y -CONFIG_NFC_NDEF=y -CONFIG_NFC_NDEF_MSG=y -CONFIG_NFC_NDEF_RECORD=y -CONFIG_NFC_NDEF_URI_MSG=y -CONFIG_NFC_NDEF_URI_REC=y -CONFIG_HWINFO=y - -#THE ACCELEROMETER -CONFIG_ACCELEROMETER=n -#ENABLE THE BUTTON! -CONFIG_ENABLE_BUTTON=n -#ENABLE THE SPEAKER -CONFIG_ENABLE_SPEAKER=n +# +# NFC (in the future) +# + +# CONFIG_NFC_T2T_NRFXLIB=y +# CONFIG_NFC_NDEF=y +# CONFIG_NFC_NDEF_MSG=y +# CONFIG_NFC_NDEF_RECORD=y +# CONFIG_NFC_NDEF_URI_MSG=y +# CONFIG_NFC_NDEF_URI_REC=y +# CONFIG_HWINFO=y + +# +#EVERYTHING ELSE +# + +CONFIG_ACCELEROMETER=y +CONFIG_ENABLE_BUTTON=y +CONFIG_ENABLE_SPEAKER=y diff --git a/Friend/firmware/firmware_v1.0/src/audio.c b/Friend/firmware/firmware_v1.0/src/audio.c deleted file mode 100644 index 581f88b47..000000000 --- a/Friend/firmware/firmware_v1.0/src/audio.c +++ /dev/null @@ -1,44 +0,0 @@ -#define BIAS (0x84) /* Bias for linear code. */ - -static int search(int val, short* table, int size) -{ - int i; - - for (i = 0; i < size; i++) { - if (val <= *table++) - return (i); - } - return (size); -} - -static short seg_end[8] = { 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF }; - -unsigned char linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */ -{ - int mask; - int seg; - unsigned char uval; - - /* Get the sign and the magnitude of the value. */ - if (pcm_val < 0) { - pcm_val = BIAS - pcm_val; - mask = 0x7F; - } else { - pcm_val += BIAS; - mask = 0xFF; - } - - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_end, 8); - - /* - * Combine the sign, segment, quantization bits; - * and complement the code word. - */ - if (seg >= 8) /* out of range, return maximum value. */ - return (0x7F ^ mask); - else { - uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF); - return (uval ^ mask); - } -} \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/audio.h b/Friend/firmware/firmware_v1.0/src/audio.h deleted file mode 100644 index 2be44000f..000000000 --- a/Friend/firmware/firmware_v1.0/src/audio.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -unsigned char linear2ulaw(int pcm_val); \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/btutils.h b/Friend/firmware/firmware_v1.0/src/btutils.h deleted file mode 100644 index 0352eeb0f..000000000 --- a/Friend/firmware/firmware_v1.0/src/btutils.h +++ /dev/null @@ -1,12 +0,0 @@ -#include - -static const char *phy2str(uint8_t phy) -{ - switch (phy) { - case 0: return "No packets"; - case BT_GAP_LE_PHY_1M: return "LE 1M"; - case BT_GAP_LE_PHY_2M: return "LE 2M"; - case BT_GAP_LE_PHY_CODED: return "LE Coded"; - default: return "Unknown"; - } -} \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index e60a5226e..32eab6373 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -1,13 +1,14 @@ -#include -#include #include #include #include #include #include #include -#include "transport.h" +#include +#include #include "button.h" +#include "transport.h" + LOG_MODULE_REGISTER(button, CONFIG_LOG_DEFAULT_LEVEL); static void button_ccc_config_changed_handler(const struct bt_gatt_attr *attr, uint16_t value); @@ -25,8 +26,9 @@ static struct bt_gatt_attr button_service_attr[] = { static struct bt_gatt_service button_service = BT_GATT_SERVICE(button_service_attr); -static void button_ccc_config_changed_handler(const struct bt_gatt_attr *attr, uint16_t value) { - if (value == BT_GATT_CCC_NOTIFY) +static void button_ccc_config_changed_handler(const struct bt_gatt_attr *attr, uint16_t value) +{ + if (value == BT_GATT_CCC_NOTIFY) { LOG_INF("Client subscribed for notifications"); } @@ -56,16 +58,20 @@ void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { current_button_time = k_cycle_get_32(); - if (current_button_time - previous_button_time < max_debounce_interval) { //too low! + if (current_button_time - previous_button_time < max_debounce_interval) + { //too low! } - else { //right... + else + { //right... int temp = gpio_pin_get_raw(dev,d5_pin_input.pin); - if (temp) { - was_pressed = true; - } - else { + if (temp) + { was_pressed = false; } + else + { + was_pressed = true; + } } previous_button_time = current_button_time; } @@ -89,87 +95,113 @@ static FSM_STATE_T current_button_state = IDLE; static uint32_t inc_count_1 = 0; static uint32_t inc_count_0 = 0; - static int final_button_state[2] = {0,0}; const static int threshold = 10; - -static void reset_count() { +static void reset_count() +{ inc_count_0 = 0; inc_count_1 = 0; } -static void notify_press() { +static inline void notify_press() +{ final_button_state[0] = BUTTON_PRESS; LOG_INF("pressed"); - bt_gatt_notify(get_current_connection(), &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); + struct bt_conn *conn = get_current_connection(); + if (conn != NULL) + { + bt_gatt_notify(conn, &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); + } } -static void notify_unpress() { +static inline void notify_unpress() +{ final_button_state[0] = BUTTON_RELEASE; LOG_INF("unpressed"); - bt_gatt_notify(get_current_connection(), &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); + struct bt_conn *conn = get_current_connection(); + if (conn != NULL) + { + bt_gatt_notify(conn, &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); + } } -static void notify_tap() { - final_button_state[0] = SINGLE_TAP; +static inline void notify_tap() +{ + final_button_state[0] = SINGLE_TAP; LOG_INF("tap"); - bt_gatt_notify(get_current_connection(), &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); + struct bt_conn *conn = get_current_connection(); + if (conn != NULL) + { + bt_gatt_notify(conn, &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); + } } -static void notify_double_tap() { - final_button_state[0] = DOUBLE_TAP; //button press +static inline void notify_double_tap() +{ + final_button_state[0] = DOUBLE_TAP; //button press LOG_INF("double tap"); - bt_gatt_notify(get_current_connection(), &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); + struct bt_conn *conn = get_current_connection(); + if (conn != NULL) + { + bt_gatt_notify(conn, &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); + } } -static void notify_long_tap() { +static inline void notify_long_tap() +{ final_button_state[0] = LONG_TAP; //button press LOG_INF("long tap"); - bt_gatt_notify(get_current_connection(), &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); + struct bt_conn *conn = get_current_connection(); + if (conn != NULL) + { + bt_gatt_notify(conn, &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); + } } #define LONG_PRESS_INTERVAL 50 #define SINGLE_PRESS_INTERVAL 2 -void check_button_level(struct k_work *work_item) { - if (get_current_connection() == NULL) { - return; - } - +void check_button_level(struct k_work *work_item) +{ //insert the current button state here int state_ = was_pressed ? 1 : 0; - if (current_button_state == IDLE) { - - if (state_ == 0) { + if (current_button_state == IDLE) + { + if (state_ == 0) + { //Do nothing! } - - else if (state_ == 1) { + else if (state_ == 1) + { //Also do nothing, but transition to the next state notify_press(); current_button_state = ONE_PRESS; } - } - else if (current_button_state == ONE_PRESS) { - - if (state_ == 0) { + else if (current_button_state == ONE_PRESS) + { + if (state_ == 0) + { - if(inc_count_0 == 0) { - notify_unpress(); + if(inc_count_0 == 0) + { + notify_unpress(); } inc_count_0++; //button is unpressed - if (inc_count_0 > SINGLE_PRESS_INTERVAL) { + if (inc_count_0 > SINGLE_PRESS_INTERVAL) + { //If button is not pressed for a little while....... //transition to Two_press. button could be a single or double tap current_button_state = TWO_PRESS; reset_count(); } } - if (state_ == 1) { + if (state_ == 1) + { inc_count_1++; //button is pressed - if (inc_count_1 > LONG_PRESS_INTERVAL) { + if (inc_count_1 > LONG_PRESS_INTERVAL) + { //If button is pressed for a long time....... notify_long_tap(); //Fire the long mode notify and enter a grace period @@ -181,35 +213,40 @@ void check_button_level(struct k_work *work_item) { } - else if (current_button_state == TWO_PRESS) { - - if (state_ == 0) { - - if (inc_count_1 > 0) { // if button has been pressed...... + else if (current_button_state == TWO_PRESS) + { + if (state_ == 0) + { + if (inc_count_1 > 0) + { // if button has been pressed...... notify_unpress(); notify_double_tap(); //Fire the notify and enter a grace period current_button_state = GRACE; reset_count(); - } + } //single button press - else if (inc_count_0 > 10){ + else if (inc_count_0 > 10) + { notify_tap(); //Fire the notify and enter a grace period current_button_state = GRACE; reset_count(); - - } - else { + } + else + { inc_count_0++; //not pressed - } + } } - else if (state_ == 1 ) { - if (inc_count_1 == 0) { + else if (state_ == 1 ) + { + if (inc_count_1 == 0) + { notify_press(); inc_count_1++; } - if (inc_count_1 > threshold) { + if (inc_count_1 > threshold) + { notify_long_tap(); //Fire the notify and enter a grace period current_button_state = GRACE; @@ -218,91 +255,109 @@ void check_button_level(struct k_work *work_item) { } } - else if (current_button_state == GRACE) { - if (state_ == 0) { - if (inc_count_0 == 0 && (inc_count_1 > 0)) { - notify_unpress(); + else if (current_button_state == GRACE) + { + if (state_ == 0) + { + if (inc_count_0 == 0 && (inc_count_1 > 0)) + { + notify_unpress(); } inc_count_0++; - if (inc_count_0 > 10) { - current_button_state = IDLE; - reset_count(); + if (inc_count_0 > 10) + { + current_button_state = IDLE; + reset_count(); } } - else if (state_ == 1) { - inc_count_1++; + else if (state_ == 1) + { + inc_count_1++; } } - k_work_reschedule(&button_work, K_MSEC(BUTTON_CHECK_INTERVAL)); - } -static ssize_t button_data_read_characteristic(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - LOG_INF("button_data_read_characteristic"); - int lint = 1; - LOG_INF("was_pressed: %d", was_pressed); +static ssize_t button_data_read_characteristic(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) +{ + LOG_INF("button_data_read_characteristic"); + int lint = 1; + LOG_INF("was_pressed: %d", was_pressed); return bt_gatt_attr_read(conn, attr, buf, len, offset, &lint, sizeof(lint)); } -int button_init() { - if (gpio_is_ready_dt(&d4_pin)) { - LOG_INF("D4 Pin ready"); +int button_init() +{ + if (gpio_is_ready_dt(&d4_pin)) + { + LOG_INF("D4 Pin ready"); } - else { + else + { LOG_ERR("Error setting up D4 Pin"); - return 0; + return -1; } - - if (gpio_pin_configure_dt(&d4_pin, GPIO_OUTPUT_ACTIVE) < 0) { + if (gpio_pin_configure_dt(&d4_pin, GPIO_OUTPUT_ACTIVE) < 0) + { LOG_ERR("Error setting up D4 Pin Voltage"); - return 0; + return -1; } - else { + else + { LOG_INF("D4 ready to transmit voltage"); } - if (gpio_is_ready_dt(&d5_pin_input)) { + if (gpio_is_ready_dt(&d5_pin_input)) + { LOG_INF("D5 Pin ready"); } - else { + else + { LOG_ERR("D5 Pin not ready"); - return 0; + return -1; } int err2 = gpio_pin_configure_dt(&d5_pin_input,GPIO_INPUT); - if (err2 != 0) { + if (err2 != 0) + { LOG_ERR("Error setting up D5 Pin"); - return 0; + return -1; } - else { + else + { LOG_INF("D5 ready"); } + err2 = gpio_pin_interrupt_configure_dt(&d5_pin_input,GPIO_INT_EDGE_BOTH); - if (err2 != 0) { + if (err2 != 0) + { LOG_ERR("D5 unable to detect button presses"); - return 0; + return -1; } - else { + else + { LOG_INF("D5 ready to detect button presses"); } gpio_init_callback(&button_cb_data, button_pressed, BIT(d5_pin_input.pin)); gpio_add_callback(d5_pin_input.port, &button_cb_data); - return 1; + return 0; } -void activate_button_work() { +void activate_button_work() +{ k_work_schedule(&button_work, K_MSEC(BUTTON_CHECK_INTERVAL)); } -void register_button_service() { +void register_button_service() +{ bt_gatt_service_register(&button_service); } -FSM_STATE_T get_current_button_state() { +FSM_STATE_T get_current_button_state() +{ return current_button_state; } \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/button.h b/Friend/firmware/firmware_v1.0/src/button.h index 6902bb14a..7108889b0 100644 --- a/Friend/firmware/firmware_v1.0/src/button.h +++ b/Friend/firmware/firmware_v1.0/src/button.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef BUTTON_H +#define BUTTON_H typedef enum { IDLE, @@ -11,4 +12,6 @@ int button_init(); void activate_button_work(); void register_button_service(); -FSM_STATE_T get_current_button_state(); \ No newline at end of file +FSM_STATE_T get_current_button_state(); + +#endif \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/codec.c b/Friend/firmware/firmware_v1.0/src/codec.c index 24f8c43ef..c99d0f71c 100644 --- a/Friend/firmware/firmware_v1.0/src/codec.c +++ b/Friend/firmware/firmware_v1.0/src/codec.c @@ -1,14 +1,12 @@ #include #include #include "codec.h" -#include "audio.h" #include "config.h" #include "utils.h" -#include "sdcard.h" #ifdef CODEC_OPUS #include "lib/opus-1.2.1/opus.h" #endif -// #include "sdcard.c" + LOG_MODULE_REGISTER(codec, CONFIG_LOG_DEFAULT_LEVEL); // @@ -34,8 +32,7 @@ int codec_receive_pcm(int16_t *data, size_t len) //this gets called after mic da int written = ring_buf_put(&codec_ring_buf, (uint8_t *)data, len * 2); if (written != len * 2) { - - // printk("Failed to write %d bytes to codec ring buffer\n", len * 2); + LOG_ERR("Failed to write %d bytes to codec ring buffer", len * 2); return -1; } @@ -122,40 +119,6 @@ int codec_start() return 0; } -// -// MU-Law codec -// - -#if CODEC_MU_LAW - -uint16_t execute_codec() -{ - for (int i = 0; i < CODEC_PACKAGE_SAMPLES / CODEC_DIVIDER; i++) - { - codec_output_bytes[i] = linear2ulaw(codec_input_samples[i * CODEC_DIVIDER]); - } - return CODEC_PACKAGE_SAMPLES / CODEC_DIVIDER; -} - -#endif - -// -// PCM codec -// - -#if CODEC_PCM - -uint16_t execute_codec() -{ - for (int i = 0; i < CODEC_PACKAGE_SAMPLES / CODEC_DIVIDER; i++) - { - codec_output_bytes[i * 2] = codec_input_samples[i * CODEC_DIVIDER] & 0xFF; - codec_output_bytes[i * 2 + 1] = (codec_input_samples[i * CODEC_DIVIDER] >> 8) & 0xFF; - } - return (CODEC_PACKAGE_SAMPLES / CODEC_DIVIDER) * 2; -} -#endif - // // Opus codec // diff --git a/Friend/firmware/firmware_v1.0/src/codec.h b/Friend/firmware/firmware_v1.0/src/codec.h index 1ea82cc8a..bb542dd0f 100644 --- a/Friend/firmware/firmware_v1.0/src/codec.h +++ b/Friend/firmware/firmware_v1.0/src/codec.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef CODEC_H +#define CODEC_H #include // Callback @@ -6,5 +7,16 @@ typedef void (*codec_callback)(uint8_t *data, size_t len); void set_codec_callback(codec_callback callback); // Integration + int codec_receive_pcm(int16_t *data, size_t len); -int codec_start(); \ No newline at end of file + +/** + * @brief Initialize the Codec + * + * Initializes the codec + * + * @return 0 if successful, negative errno code if error + */ +int codec_start(); + +#endif \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/config.h b/Friend/firmware/firmware_v1.0/src/config.h index 0091e1bf8..f28d8afbb 100644 --- a/Friend/firmware/firmware_v1.0/src/config.h +++ b/Friend/firmware/firmware_v1.0/src/config.h @@ -15,21 +15,8 @@ #define PDM_PWR_PIN NRF_GPIO_PIN_MAP(1, 10) // Codecs -// #define CODEC_PCM 1 -// #define CODEC_MU_LAW 1 #define CODEC_OPUS 1 -// Codec packages -#if CODEC_PCM | CODEC_MU_LAW -#define CODEC_DIVIDER 2 // 1 or 2 -#define CODEC_PACKAGE_SAMPLES 160 // 10ms -#if CODEC_PCM -#define CODEC_OUTPUT_MAX_BYTES CODEC_PACKAGE_SAMPLES * 2 -#else -#define CODEC_OUTPUT_MAX_BYTES CODEC_PACKAGE_SAMPLES -#endif -#endif - #if CODEC_OPUS #define CODEC_PACKAGE_SAMPLES 160 #define CODEC_OUTPUT_MAX_BYTES CODEC_PACKAGE_SAMPLES * 2 // Let's assume that 16bit is enough @@ -41,21 +28,6 @@ #define CONFIG_OPUS_MODE CONFIG_OPUS_MODE_CELT // Codec IDs -#ifdef CODEC_PCM -#if CODEC_DIVIDER == 1 -#define CODEC_ID 0 -#elif CODEC_DIVIDER == 2 -#define CODEC_ID 1 -#endif -#endif - -#ifdef CODEC_MU_LAW -#if CODEC_DIVIDER == 1 -#define CODEC_ID 10 -#elif CODEC_DIVIDER == 2 -#define CODEC_ID 11 -#endif -#endif #ifdef CODEC_OPUS #define CODEC_ID 20 diff --git a/Friend/firmware/firmware_v1.0/src/led.c b/Friend/firmware/firmware_v1.0/src/led.c index af68ab3f1..062eb8b67 100644 --- a/Friend/firmware/firmware_v1.0/src/led.c +++ b/Friend/firmware/firmware_v1.0/src/led.c @@ -4,6 +4,7 @@ #include "utils.h" LOG_MODULE_REGISTER(led, CONFIG_LOG_DEFAULT_LEVEL); + int led_start() { ASSERT_TRUE(gpio_is_ready_dt(&led_red)); diff --git a/Friend/firmware/firmware_v1.0/src/led.h b/Friend/firmware/firmware_v1.0/src/led.h index 712b67e41..68b1058cd 100644 --- a/Friend/firmware/firmware_v1.0/src/led.h +++ b/Friend/firmware/firmware_v1.0/src/led.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef LED_H +#define LED_H #include #include @@ -7,7 +8,16 @@ static const struct gpio_dt_spec led_red = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpio static const struct gpio_dt_spec led_green = GPIO_DT_SPEC_GET(DT_ALIAS(led1), gpios); static const struct gpio_dt_spec led_blue = GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios); +/** + * @brief Initialize the LEDs + * + * Initializes the LEDs + * + * @return 0 if successful, negative errno code if error + */ int led_start(); void set_led_red(bool on); void set_led_green(bool on); -void set_led_blue(bool on); \ No newline at end of file +void set_led_blue(bool on); + +#endif \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/main.c b/Friend/firmware/firmware_v1.0/src/main.c index dd84f6f0d..07e495739 100644 --- a/Friend/firmware/firmware_v1.0/src/main.c +++ b/Friend/firmware/firmware_v1.0/src/main.c @@ -5,10 +5,8 @@ #include "utils.h" #include "led.h" #include "config.h" -#include "audio.h" #include "codec.h" // #include "nfc.h" - #include "sdcard.h" #include "storage.h" #include "speaker.h" @@ -20,7 +18,8 @@ LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL); static void codec_handler(uint8_t *data, size_t len) { int err = broadcast_audio_packets(data, len); - if (err) { + if (err) + { LOG_ERR("Failed to broadcast audio packets: %d", err); } } @@ -28,7 +27,8 @@ static void codec_handler(uint8_t *data, size_t len) static void mic_handler(int16_t *buffer) { int err = codec_receive_pcm(buffer, MIC_BUFFER_SAMPLES); - if (err) { + if (err) + { LOG_ERR("Failed to process PCM data: %d", err); } } @@ -103,19 +103,6 @@ void set_led_state() set_led_blue(false); } -// void test_sd_card(void) { -// char test_data[] = "Hello, SD card!"; -// int ret = create_file("test.txt"); -// if (ret) { -// LOG_ERR("Failed to create test file: %d", ret); -// } -// ret = write_file((uint8_t *)test_data, strlen(test_data), false, true); -// if (ret) { -// LOG_ERR("Failed to write test data: %d", ret); -// } -// LOG_INF("Successfully wrote test data to SD card"); -// } - // Main loop int main(void) { @@ -123,7 +110,8 @@ int main(void) LOG_INF("Friend device firmware starting..."); err = led_start(); - if (err) { + if (err) + { LOG_ERR("Failed to initialize LEDs: %d", err); return err; } @@ -131,33 +119,49 @@ int main(void) boot_led_sequence(); // Indicate transport initialization set_led_green(true); + set_led_green(false); + err = transport_start(); - if (err) { + if (err) + { LOG_ERR("Failed to start transport: %d", err); // Blink green LED to indicate error - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { set_led_green(!gpio_pin_get_dt(&led_green)); k_msleep(200); } set_led_green(false); - return err; + // return err; } - set_led_green(false); - err = mount_sd_card(); + if (err) + { + LOG_ERR("Failed to mount SD card: %d", err); + } LOG_INF("result of mount:%d",err); k_msleep(500); - storage_init(); - - init_haptic_pin(); + err = storage_init(); + if (err) + { + LOG_ERR("Failed to initialize storage: %d", err); + } + err = init_haptic_pin(); + if (err) + { + LOG_ERR("Failed to initialize haptic pin: %d", err); + } + set_led_blue(true); set_codec_callback(codec_handler); err = codec_start(); - if (err) { + if (err) + { LOG_ERR("Failed to start codec: %d", err); // Blink blue LED to indicate error - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { set_led_blue(!gpio_pin_get_dt(&led_blue)); k_msleep(200); } @@ -172,10 +176,12 @@ int main(void) LOG_INF("Starting microphone initialization"); set_mic_callback(mic_handler); err = mic_start(); - if (err) { + if (err) + { LOG_ERR("Failed to start microphone: %d", err); // Blink red and green LEDs to indicate error - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { set_led_red(!gpio_pin_get_dt(&led_red)); set_led_green(!gpio_pin_get_dt(&led_green)); k_msleep(200); @@ -208,7 +214,6 @@ int main(void) set_led_state(); k_msleep(500); } - // Unreachable return 0; } diff --git a/Friend/firmware/firmware_v1.0/src/mic.c b/Friend/firmware/firmware_v1.0/src/mic.c index 080c2446e..3cf951a4e 100644 --- a/Friend/firmware/firmware_v1.0/src/mic.c +++ b/Friend/firmware/firmware_v1.0/src/mic.c @@ -97,6 +97,7 @@ int mic_start() return 0; } -void set_mic_callback(mix_handler callback) { +void set_mic_callback(mix_handler callback) +{ _callback = callback; } diff --git a/Friend/firmware/firmware_v1.0/src/mic.h b/Friend/firmware/firmware_v1.0/src/mic.h index 9f484ee3d..33865c77a 100644 --- a/Friend/firmware/firmware_v1.0/src/mic.h +++ b/Friend/firmware/firmware_v1.0/src/mic.h @@ -1,5 +1,16 @@ -#pragma once +#ifndef MIC_H +#define MIC_H typedef void (*mix_handler)(int16_t *); + +/** + * @brief Initialize the Microphone + * + * Initializes the Microphone + * + * @return 0 if successful, negative errno code if error + */ int mic_start(); void set_mic_callback(mix_handler _callback); + +#endif \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/nfc.c b/Friend/firmware/firmware_v1.0/src/nfc.c index 9623477f0..fe86fd730 100644 --- a/Friend/firmware/firmware_v1.0/src/nfc.c +++ b/Friend/firmware/firmware_v1.0/src/nfc.c @@ -5,6 +5,7 @@ #include #include +//for later...... LOG_MODULE_REGISTER(nfc, CONFIG_LOG_DEFAULT_LEVEL); #define MAX_URI_LENGTH 64 diff --git a/Friend/firmware/firmware_v1.0/src/nfc.h b/Friend/firmware/firmware_v1.0/src/nfc.h index 448d89632..48e75ee75 100644 --- a/Friend/firmware/firmware_v1.0/src/nfc.h +++ b/Friend/firmware/firmware_v1.0/src/nfc.h @@ -1,6 +1,7 @@ #ifndef NFC_H #define NFC_H +//for later....... int nfc_sleep(void); int nfc_wake(void); diff --git a/Friend/firmware/firmware_v1.0/src/sdcard.c b/Friend/firmware/firmware_v1.0/src/sdcard.c index 54b0ef491..c858ec4d5 100644 --- a/Friend/firmware/firmware_v1.0/src/sdcard.c +++ b/Friend/firmware/firmware_v1.0/src/sdcard.c @@ -1,11 +1,11 @@ +#include #include -#include -#include #include +#include #include -#include #include -#include +#include +#include #include #include "sdcard.h" @@ -18,189 +18,209 @@ static struct fs_mount_t mount_point = { .fs_data = &fat_fs, }; -struct gpio_dt_spec sd_en_gpio_pin = {.port = DEVICE_DT_GET(DT_NODELABEL(gpio0)), .pin=19, .dt_flags = GPIO_INT_DISABLE}; - -static char *current_header; -#define MAX_PATH_LENGTH 32 +struct gpio_dt_spec sd_en_gpio_pin = { .port = DEVICE_DT_GET(DT_NODELABEL(gpio0)), .pin=19, .dt_flags = GPIO_INT_DISABLE }; uint8_t file_count = 0; +#define MAX_PATH_LENGTH 32 static char current_full_path[MAX_PATH_LENGTH]; static char read_buffer[MAX_PATH_LENGTH]; static char write_buffer[MAX_PATH_LENGTH]; -static const char *disk_mount_pt = "/SD:/"; - -uint32_t get_file_size(uint8_t num){ - char *ptr = generate_new_audio_header(num); - snprintf(current_full_path, sizeof(current_full_path), "%s%s", disk_mount_pt, ptr); - k_free(ptr); - struct fs_dirent entry; - fs_stat(¤t_full_path,&entry); - return (uint32_t)entry.size; - } - -int move_read_pointer(uint8_t num) { - char *read_ptr = generate_new_audio_header(num); - snprintf(read_buffer, sizeof(read_buffer), "%s%s", disk_mount_pt, read_ptr); - k_free(read_ptr); - struct fs_dirent entry; - int res = fs_stat(&read_buffer,&entry); - if (res) { - LOG_ERR("invalid file\n"); - - return -1; - } - return 0; -} -int move_write_pointer(uint8_t num) { - char *write_ptr = generate_new_audio_header(num); - snprintf(write_buffer, sizeof(write_buffer), "%s%s", disk_mount_pt, write_ptr); - k_free(write_ptr); - struct fs_dirent entry; - int res = fs_stat(&write_buffer,&entry); - if (res) { - LOG_ERR("invalid file\n"); - - return -1; - } - - return 0; -} +uint32_t file_num_array[40]; -uint32_t file_num_array[40]; +static const char *disk_mount_pt = "/SD:/"; int mount_sd_card(void) { - - if (gpio_is_ready_dt(&sd_en_gpio_pin)) { - printk("Haptic Pin ready\n"); + //initialize the sd card enable pin (v2) + if (gpio_is_ready_dt(&sd_en_gpio_pin)) + { + LOG_INF("SD Enable Pin ready"); } - else { - printk("Error setting up Haptic Pin\n"); - return 1; + else + { + LOG_ERR("Error setting up SD Enable Pin"); + return -1; } - if (gpio_pin_configure_dt(&sd_en_gpio_pin, GPIO_OUTPUT_ACTIVE) < 0) { - printk("Error setting up Haptic Pin\n"); - return 1; + if (gpio_pin_configure_dt(&sd_en_gpio_pin, GPIO_OUTPUT_ACTIVE) < 0) + { + LOG_ERR("Error setting up SD Pin"); + return -1; } - - static const char *disk_pdrv = "SD"; + //initialize the sd card + const char *disk_pdrv = "SD"; int err = disk_access_init(disk_pdrv); LOG_INF("disk_access_init: %d\n", err); - if (err) { - k_msleep(2000); + if (err) + { //reattempt + k_msleep(1000); err = disk_access_init(disk_pdrv); - if (err) { + if (err) + { + LOG_ERR("disk_access_init failed"); return -1; } } + mount_point.mnt_point = "/SD:"; int res = fs_mount(&mount_point); - - if (res == FR_OK) { + if (res == FR_OK) + { LOG_INF("SD card mounted successfully"); - } else { + } + else + { LOG_ERR("f_mount failed: %d", res); return -1; } res = fs_mkdir("/SD:/audio"); - if (res == FR_OK) { + + if (res == FR_OK) + { LOG_INF("audio directory created successfully"); + initialize_audio_file(1); } - else if (res == FR_EXIST) { + else if (res == FR_EXIST) + { LOG_INF("audio directory already exists"); } - else { + else + { LOG_INF("audio directory creation failed: %d", res); } - struct fs_dir_t zdp; - fs_dir_t_init(&zdp); - err = fs_opendir(&zdp,"/SD:/audio"); - if (err) { + struct fs_dir_t audio_dir_entry; + fs_dir_t_init(&audio_dir_entry); + err = fs_opendir(&audio_dir_entry,"/SD:/audio"); + if (err) + { LOG_ERR("error while opening directory ",err); return -1; } LOG_INF("result of opendir: %d",err); - struct fs_dirent entry_; - - file_count =get_next_item(&zdp, &entry_); - if (file_count < 0) { + struct fs_dirent file_count_entry; + file_count = get_file_contents(&audio_dir_entry, &file_count_entry); + file_count = 1; + if (file_count < 0) + { LOG_ERR(" error getting file count"); return -1; } - fs_closedir(&zdp); - LOG_INF("current num files: %d",file_count); - file_count++; + fs_closedir(&audio_dir_entry); + // file_count++; LOG_INF("new num files: %d",file_count); - initialize_audio_file(file_count); - err = move_write_pointer(file_count); - if (err) { + + res = move_write_pointer(file_count); + if (res) + { LOG_ERR("erro while moving the write pointer"); return -1; } + move_read_pointer(file_count); - if (err) { + + if (res) + { LOG_ERR("error while moving the reader pointer\n"); return -1; } - printk("file count: %d\n",file_count); - clear_audio_directory(); - struct fs_dirent entry; //check if the info file exists. if not, generate new info file + LOG_INF("file count: %d",file_count); + + struct fs_dirent info_file_entry; //check if the info file exists. if not, generate new info file const char *info_path = "/SD:/info.txt"; - res = fs_stat(info_path,&entry); - if (res) { + res = fs_stat(info_path,&info_file_entry); //for later + if (res) + { res = create_file("info.txt"); LOG_INF("result of info.txt creation: %d ",res); - } LOG_INF("result of check: %d",res); - return 0; } -int create_file(const char *file_path){ - //MAGIC STRING CAT!!!!!!! - snprintf(current_full_path, sizeof(current_full_path), "%s%s", disk_mount_pt, file_path); +uint32_t get_file_size(uint8_t num) +{ + char *ptr = generate_new_audio_header(num); + snprintf(current_full_path, sizeof(current_full_path), "%s%s", disk_mount_pt, ptr); + k_free(ptr); + struct fs_dirent entry; + int res = fs_stat(¤t_full_path,&entry); + if (res) + { + LOG_ERR("invalid file\n"); + return 0; + } + return (uint32_t)entry.size; +} - int ret = 0; - struct fs_file_t data_filp; - fs_file_t_init(&data_filp); +int move_read_pointer(uint8_t num) +{ + char *read_ptr = generate_new_audio_header(num); + snprintf(read_buffer, sizeof(read_buffer), "%s%s", disk_mount_pt, read_ptr); + k_free(read_ptr); + struct fs_dirent entry; + int res = fs_stat(&read_buffer,&entry); + if (res) + { + LOG_ERR("invalid file\n"); + return -1; + } + return 0; +} - ret = fs_open(&data_filp, current_full_path, FS_O_WRITE | FS_O_CREATE); +int move_write_pointer(uint8_t num) +{ + char *write_ptr = generate_new_audio_header(num); + snprintf(write_buffer, sizeof(write_buffer), "%s%s", disk_mount_pt, write_ptr); + k_free(write_ptr); + struct fs_dirent entry; + int res = fs_stat(&write_buffer,&entry); + if (res) + { + LOG_ERR("invalid file\n"); + return -1; + } + return 0; +} +int create_file(const char *file_path) +{ + int ret = 0; + snprintf(current_full_path, sizeof(current_full_path), "%s%s", disk_mount_pt, file_path); + struct fs_file_t data_file; + fs_file_t_init(&data_file); + ret = fs_open(&data_file, current_full_path, FS_O_WRITE | FS_O_CREATE); if (ret) { - LOG_ERR("File creation failed %d", ret); + LOG_ERR("File creation failed %d", ret); return -2; } - fs_close(&data_filp); - + fs_close(&data_file); return 0; } -int read_audio_data(uint8_t *buf, int amount,int offset) { - struct fs_file_t file; - fs_file_t_init(&file); +int read_audio_data(uint8_t *buf, int amount,int offset) +{ + struct fs_file_t read_file; + fs_file_t_init(&read_file); uint8_t *temp_ptr = buf; struct fs_dirent entry; - - int rc = fs_open(&file, read_buffer, FS_O_READ | FS_O_RDWR); - rc = fs_seek(&file,offset,FS_SEEK_SET); - rc = fs_read(&file, temp_ptr, amount); + int rc = fs_open(&read_file, read_buffer, FS_O_READ | FS_O_RDWR); + rc = fs_seek(&read_file,offset,FS_SEEK_SET); + rc = fs_read(&read_file, temp_ptr, amount); // printk("read data :"); // for (int i = 0; i < amount;i++) { // printk("%d ",temp_ptr[i]); // } // printk("\n"); - fs_close(&file); + fs_close(&read_file); return rc; } @@ -208,19 +228,21 @@ int read_audio_data(uint8_t *buf, int amount,int offset) { int write_to_file(uint8_t *data,uint32_t length) { - struct fs_file_t data_loc; - fs_file_t_init(&data_loc); - uint8_t *temp_ptr = data; - fs_open(&data_loc, write_buffer , FS_O_WRITE | FS_O_APPEND); - fs_write(&data_loc, temp_ptr, length); - fs_close(&data_loc); + struct fs_file_t write_file; + fs_file_t_init(&write_file); + uint8_t *write_ptr = data; + fs_open(&write_file, write_buffer , FS_O_WRITE | FS_O_APPEND); + fs_write(&write_file, write_ptr, length); + fs_close(&write_file); return 0; } -int initialize_audio_file(uint8_t num) { +int initialize_audio_file(uint8_t num) +{ char *header = generate_new_audio_header(num); - if (header == NULL) { + if (header == NULL) + { return -1; } k_free(header); @@ -228,30 +250,8 @@ int initialize_audio_file(uint8_t num) { return 0; } -void print_directory_contents(struct fs_dir_t *zdp, struct fs_dirent *entry) { - - int rc = zdp->mp->fs->readdir(zdp, entry); - printk("%s %d ",entry->name,entry->size); - while (true) { - rc = zdp->mp->fs->readdir(zdp, entry); - - if (rc < 0) { - break; - } - if (entry->name[0] == 0) { - break; - } - printk("%s %d ",entry->name,entry->size); - } - if (rc < 0) { - } - printk("\n"); - -} - - - -char* generate_new_audio_header(uint8_t num) { +char* generate_new_audio_header(uint8_t num) +{ if (num > 99 ) return NULL; char *ptr_ = k_malloc(14); ptr_[0] = 'a'; @@ -272,11 +272,14 @@ char* generate_new_audio_header(uint8_t num) { return ptr_; } -int get_next_item(struct fs_dir_t *zdp, struct fs_dirent *entry) { - if (zdp->mp->fs->readdir(zdp, entry) ) { +int get_file_contents(struct fs_dir_t *zdp, struct fs_dirent *entry) +{ + if (zdp->mp->fs->readdir(zdp, entry) ) + { return -1; } - if (entry->name[0] == 0) { + if (entry->name[0] == 0) + { return 0; } int count = 0; @@ -284,33 +287,38 @@ int get_next_item(struct fs_dir_t *zdp, struct fs_dirent *entry) { LOG_INF("file numarray %d %d ",count,file_num_array[count]); LOG_INF("file name is %s ", entry->name); count++; - while (zdp->mp->fs->readdir(zdp, entry) == 0 ) { - if (entry->name[0] == 0 ) { - break; - } - file_num_array[count] = entry->size; - LOG_INF("file numarray %d %d ",count,file_num_array[count]); - LOG_INF("file name is %s ", entry->name); - count++; + while (zdp->mp->fs->readdir(zdp, entry) == 0 ) + { + if (entry->name[0] == 0 ) + { + break; + } + file_num_array[count] = entry->size; + LOG_INF("file numarray %d %d ",count,file_num_array[count]); + LOG_INF("file name is %s ", entry->name); + count++; } return count; } //we should clear instead of delete since we lose fifo structure -int clear_audio_file(uint8_t num) { - +int clear_audio_file(uint8_t num) +{ char *clear_header = generate_new_audio_header(num); snprintf(current_full_path, sizeof(current_full_path), "%s%s", disk_mount_pt, clear_header); k_free(clear_header); int res = fs_unlink(current_full_path); - if (res) { + if (res) + { LOG_ERR("error deleting file"); return -1; } + char *create_file_header = generate_new_audio_header(num); k_msleep(10); res = create_file(create_file_header); k_free(create_file_header); - if (res) { + if (res) + { LOG_ERR("error creating file"); return -1; } @@ -318,13 +326,14 @@ int clear_audio_file(uint8_t num) { return 0; } -int delete_audio_file(uint8_t num) { - +int delete_audio_file(uint8_t num) +{ char *ptr = generate_new_audio_header(num); snprintf(current_full_path, sizeof(current_full_path), "%s%s", disk_mount_pt, ptr); k_free(ptr); int res = fs_unlink(current_full_path); - if (res) { + if (res) + { printk("error deleting file in delete\n"); return -1; } @@ -332,38 +341,46 @@ int delete_audio_file(uint8_t num) { return 0; } //the nuclear option. -int clear_audio_directory() { - if (file_count == 1) { +int clear_audio_directory() +{ + if (file_count == 1) + { return 0; } //check if all files are zero // char* path_ = "/SD:/audio"; // clear_audio_file(file_count); int res=0; - for (uint8_t i = file_count ; i > 0; i-- ) { + for (uint8_t i = file_count ; i > 0; i-- ) + { res = delete_audio_file(i); k_msleep(10); - if (res) { - printk("error on %d\n",i); + if (res) + { + printk("error on %d\n",i); return -1; } } - res = fs_unlink("/SD:/audio"); - if (res) { + res = fs_unlink("/SD:/audio"); + if (res) + { printk("error deleting file\n"); return -1; } res = fs_mkdir("/SD:/audio"); - if (res) { + if (res) + { printk("failed to make directory \n"); return -1; } res = create_file("audio/a01.txt"); - if (res) { + if (res) + { printk("failed to make new file in directory files\n"); return -1; } printk("done with clearing\n"); + file_count = 1; move_write_pointer(1); return 0; diff --git a/Friend/firmware/firmware_v1.0/src/sdcard.h b/Friend/firmware/firmware_v1.0/src/sdcard.h index e48673e45..7c5ed1a92 100644 --- a/Friend/firmware/firmware_v1.0/src/sdcard.h +++ b/Friend/firmware/firmware_v1.0/src/sdcard.h @@ -1,25 +1,96 @@ -#pragma once -#include -#include -#include -#include -#include -#include - - +#ifndef SDCARD_H +#define SDCARD_H +/** + * @brief Mount the SD Card. Initializes the audio files + * + * Mounts the SD Card and initializes the audio files. If the SD card does not contain those files, the + * function will create them. + * + * @return 0 if successful, negative errno code if error + */ int mount_sd_card(void); +/** + * @brief Create a file + * + * Creates a file at the given path + * + * @return 0 if successful, negative errno code if error + */ int create_file(const char* file_path); - +//private char* generate_new_audio_header(uint8_t num); + +/** + * @brief Initialize an audio file of number 1 + * + * Initializes an audio file. It will be called a nn.txt, where nn is the number of the file. + * example: initialize_audio_file(1) will create a file called a01.txt + * @return 0 if successful, negative errno code if error + */ int initialize_audio_file(uint8_t num); + +/** + * @brief Write to the current audio file specified by the write pointer + * + * + * + * @return number of bytes written + */ int write_to_file(uint8_t *data,uint32_t length); + +/** + * @brief Read from the current audio file specified by the read pointer + * + * + * + * @return number of bytes read + */ int read_audio_data(uint8_t *buf, int amount,int offset); +/** + * @brief Get the size of the specified audio file number + * + * + * + * @return size of the file in bytes + */ uint32_t get_file_size(uint8_t num); - +/** + * @brief Move the read pointer to the specified audio file position + * + * + * + * @return 0 if successful, negative errno code if error + */ int move_read_pointer(uint8_t num); + +/** + * @brief Move the write pointer to the specified audio file position + * + * + * + * @return 0 if successful, negative errno code if error + */ int move_write_pointer(uint8_t num); + +/** + * @brief Clear the specified audio file + * + * + * + * @return 0 if successful, negative errno code if error + */ int clear_audio_file(uint8_t num); + +/** + * @brief Clear the audio directory. + * + * This deletes all audio files and leaves the audio directory with only one file left, a01.txt. + * This automatically moves the read and write pointers to a01.txt. + * @return 0 if successful, negative errno code if error + */ int clear_audio_directory(); + +#endif diff --git a/Friend/firmware/firmware_v1.0/src/speaker.c b/Friend/firmware/firmware_v1.0/src/speaker.c index b54c58be9..24660ab42 100644 --- a/Friend/firmware/firmware_v1.0/src/speaker.c +++ b/Friend/firmware/firmware_v1.0/src/speaker.c @@ -1,15 +1,12 @@ #include #include #include - -#include #include #include - -#include +#include #include #include - +#include "speaker.h" LOG_MODULE_REGISTER(speaker, CONFIG_LOG_DEFAULT_LEVEL); @@ -24,58 +21,68 @@ LOG_MODULE_REGISTER(speaker, CONFIG_LOG_DEFAULT_LEVEL); #define PI 3.14159265358979323846 -K_MEM_SLAB_DEFINE_STATIC(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, 4); +K_MEM_SLAB_DEFINE_STATIC(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, 2); + +struct device *audio_speaker; + static void* rx_buffer; static void* buzz_buffer; static int16_t *ptr2; static int16_t *clear_ptr; -static struct device *speaker; + static uint16_t current_length; static uint16_t offset; struct gpio_dt_spec haptic_gpio_pin = {.port = DEVICE_DT_GET(DT_NODELABEL(gpio1)), .pin=11, .dt_flags = GPIO_INT_DISABLE}; -int speaker_init() { - const struct device *speaker = device_get_binding("I2S_0"); - if (!device_is_ready(speaker)) { - LOG_ERR("Speaker device is not supported : %s", speaker->name); - return 0; +int speaker_init() +{ + LOG_INF("Speaker init"); + audio_speaker = device_get_binding("I2S_0"); + + if (!device_is_ready(audio_speaker)) + { + LOG_ERR("Speaker device is not supported : %s", audio_speaker->name); + return -1; } - struct i2s_config config = { - .word_size= WORD_SIZE, //how long is one left/right word. - .channels = NUMBER_OF_CHANNELS, //how many words in a frame 2 - .format = I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED, //format - // .format = I2S_FMT_DATA_FORMAT_I2S, - .options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER | I2S_OPT_BIT_CLK_GATED, //how to configure the mclock - .frame_clk_freq = SAMPLE_FREQUENCY, /* Sampling rate */ - .mem_slab = &mem_slab,/* Memory slab to store rx/tx data */ - .block_size = MAX_BLOCK_SIZE,/* size of ONE memory block in bytes */ - .timeout = -1, /* Number of milliseconds to wait in case Tx queue is full or RX queue is empty, or 0, or SYS_FOREVER_MS */ + struct i2s_config config = { + .word_size= WORD_SIZE, //how long is one left/right word. + .channels = NUMBER_OF_CHANNELS, //how many words in a frame 2 + .format = I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED, //format + // .format = I2S_FMT_DATA_FORMAT_I2S, + .options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER | I2S_OPT_BIT_CLK_GATED, //how to configure the mclock + .frame_clk_freq = SAMPLE_FREQUENCY, /* Sampling rate */ + .mem_slab = &mem_slab,/* Memory slab to store rx/tx data */ + .block_size = MAX_BLOCK_SIZE,/* size of ONE memory block in bytes */ + .timeout = -1, /* Number of milliseconds to wait in case Tx queue is full or RX queue is empty, or 0, or SYS_FOREVER_MS */ }; - int err = i2s_configure(speaker, I2S_DIR_TX, &config); - if (err < 0) { - LOG_INF("Failed to configure Microphone (%d)", err); - return 0; + int err = i2s_configure(audio_speaker, I2S_DIR_TX, &config); + if (err) + { + LOG_ERR("Failed to configure Speaker (%d)", err); + return -1; } - err = k_mem_slab_alloc(&mem_slab, &rx_buffer, K_MSEC(200)); - if (err) { - LOG_INF("Failed to allocate memory again(%d)", err); - return 0; + err = k_mem_slab_alloc(&mem_slab, &rx_buffer, K_MSEC(200)); + if (err) + { + LOG_INF("Failed to allocate memory for speaker%d)", err); + return -1; } err = k_mem_slab_alloc(&mem_slab, &buzz_buffer, K_MSEC(200)); - if (err) { - LOG_INF("Failed to allocate memory again(%d)", err); - return 0; + if (err) + { + LOG_INF("Failed to allocate for chime (%d)", err); + return -1; } - memset(rx_buffer, 0, MAX_BLOCK_SIZE); - memset(buzz_buffer, 0, MAX_BLOCK_SIZE); - return 1; + memset(rx_buffer, 0, MAX_BLOCK_SIZE); + memset(buzz_buffer, 0, MAX_BLOCK_SIZE); + return 0; } -uint16_t speak(uint16_t len, const void *buf) { - +uint16_t speak(uint16_t len, const void *buf) //direct from bt +{ uint16_t amount = 0; amount = len; if (len == 4) //if stage 1 @@ -85,38 +92,41 @@ uint16_t speak(uint16_t len, const void *buf) { ptr2 = (int16_t *)rx_buffer; clear_ptr = (int16_t *)rx_buffer; } - else { //if not stage 1 - if (current_length > PACKET_SIZE) { + else + { //if not stage 1 + if (current_length > PACKET_SIZE) + { LOG_INF("Data length: %u", len); current_length = current_length - PACKET_SIZE; LOG_INF("remaining data: %u", current_length); - for (int i = 0; i < len/2; i++) { + for (int i = 0; i < (int)(len/2); i++) + { *ptr2++ = ((int16_t *)buf)[i]; ptr2++; - } offset = offset + len; } - else if (current_length < PACKET_SIZE) { + else if (current_length < PACKET_SIZE) + { LOG_INF("entered the final stretch"); LOG_INF("Data length: %u", len); current_length = current_length - len; LOG_INF("remaining data: %u", current_length); // memcpy(rx_buffer+offset, buf, len); - for (int i = 0; i < len/2; i++) { + for (int i = 0; i < len/2; i++) + { *ptr2++ = ((int16_t *)buf)[i]; ptr2++; } offset = offset + len; LOG_INF("offset: %u", offset); - i2s_write(speaker, rx_buffer, MAX_BLOCK_SIZE); - i2s_trigger(speaker, I2S_DIR_TX, I2S_TRIGGER_START);// calls are probably non blocking - i2s_trigger(speaker, I2S_DIR_TX, I2S_TRIGGER_DRAIN); + i2s_write(audio_speaker, rx_buffer, MAX_BLOCK_SIZE); + i2s_trigger(audio_speaker, I2S_DIR_TX, I2S_TRIGGER_START);// calls are probably non blocking + i2s_trigger(audio_speaker, I2S_DIR_TX, I2S_TRIGGER_DRAIN); //clear the buffer - k_sleep(K_MSEC(4000)); memset(clear_ptr, 0, MAX_BLOCK_SIZE); @@ -127,65 +137,78 @@ uint16_t speak(uint16_t len, const void *buf) { } -static void generate_gentle_chime(int16_t *buffer, int num_samples) - { - float frequencies[] = {523.25, 659.25, 783.99, 1046.50}; // C5, E5, G5, C6 - int num_freqs = sizeof(frequencies) / sizeof(frequencies[0]); - - for (int i = 0; i < num_samples; i++) { - float t = (float)i / SAMPLE_FREQUENCY; - float sample = 0; - for (int j = 0; j < num_freqs; j++) { - sample += sinf(2 * PI * frequencies[j] * t) * (1.0 - t); - } - int16_t int_sample = (int16_t)(sample / num_freqs * 32767 * 0.5); - buffer[i * NUM_CHANNELS] = int_sample; - buffer[i * NUM_CHANNELS + 1] = int_sample; - } - } - - int play_boot_sound(void) - { - int ret; - int16_t *buffer = (int16_t *) buzz_buffer; - int samples_per_block = MAX_BLOCK_SIZE / (NUM_CHANNELS * sizeof(int16_t)); - - generate_gentle_chime(buffer, samples_per_block); - - ret = i2s_write(speaker, buffer, MAX_BLOCK_SIZE); - if (ret < 0) { - LOG_ERR("Failed to write initial I2S data: %d", ret); - return ret; - } - - ret = i2s_trigger(speaker, I2S_DIR_TX, I2S_TRIGGER_START); - if (ret != 0) { - LOG_ERR("Failed to start I2S transmission: %d", ret); - return ret; - } - k_sleep(K_MSEC(2000)); // Increased from 1000 to 2000 ms - - ret = i2s_trigger(speaker, I2S_DIR_TX, I2S_TRIGGER_DRAIN); - if (ret != 0) { - LOG_ERR("Failed to drain I2S transmission: %d", ret); - return ret; - } - - return 0; - } - - int init_haptic_pin() { - if (gpio_is_ready_dt(&haptic_gpio_pin)) { +void generate_gentle_chime(int16_t *buffer, int num_samples) +{ + LOG_INF("Generating gentle chime");//2500 + const float frequencies[] = {523.25, 659.25, 783.99, 1046.50}; // C5, E5, G5, C6 + const int num_freqs = sizeof(frequencies) / sizeof(frequencies[0]);//4 + + for (int i = 0; i < num_samples; i++) + { + float t = (float)i / SAMPLE_FREQUENCY;//0.000125 + float sample = 0; + for (int j = 0; j < num_freqs; j++) + { + sample += sinf(2 * PI * frequencies[j] * t) * (1.0 - t); + } + int16_t int_sample = (int16_t)(sample / num_freqs * 32767 * 0.5); + buffer[i * NUM_CHANNELS] = int_sample; + buffer[i * NUM_CHANNELS + 1] = int_sample; + } + LOG_INF("Done generating gentle chime"); +} + +int play_boot_sound(void) +{ + int ret; + int16_t *buffer = (int16_t *) buzz_buffer; + const int samples_per_block = MAX_BLOCK_SIZE / (NUM_CHANNELS * sizeof(int16_t)); + + generate_gentle_chime(buffer, samples_per_block); + LOG_INF("Writing to speaker"); + k_sleep(K_MSEC(100)); + ret = i2s_write(audio_speaker, buffer, MAX_BLOCK_SIZE); + if (ret) + { + LOG_ERR("Failed to write initial I2S data: %d", ret); + return ret; + } + + ret = i2s_trigger(audio_speaker, I2S_DIR_TX, I2S_TRIGGER_START); + if (ret) + { + LOG_ERR("Failed to start I2S transmission: %d", ret); + return ret; + } + k_sleep(K_MSEC(500)); + + ret = i2s_trigger(audio_speaker, I2S_DIR_TX, I2S_TRIGGER_DRAIN); + if (ret != 0) + { + LOG_ERR("Failed to drain I2S transmission: %d", ret); + return ret; + } + + return 0; +} + +int init_haptic_pin() +{ + if (gpio_is_ready_dt(&haptic_gpio_pin)) + { LOG_INF("Haptic Pin ready"); } - else { + else + { LOG_ERR("Error setting up Haptic Pin"); - return 1; + return -1; } - - if (gpio_pin_configure_dt(&haptic_gpio_pin, GPIO_OUTPUT_INACTIVE) < 0) { + if (gpio_pin_configure_dt(&haptic_gpio_pin, GPIO_OUTPUT_INACTIVE) < 0) + { LOG_ERR("Error setting up Haptic Pin"); - return 1; + return -1; } + gpio_pin_set_dt(&haptic_gpio_pin, 1); + return 0; - } \ No newline at end of file +} \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/speaker.h b/Friend/firmware/firmware_v1.0/src/speaker.h index 64aa24c90..62a201956 100644 --- a/Friend/firmware/firmware_v1.0/src/speaker.h +++ b/Friend/firmware/firmware_v1.0/src/speaker.h @@ -1,6 +1,45 @@ -#pragma once +#ifndef SPEAKER_H +#define SPEAKER_H + #include +/** + * @brief Initialize the Speaker + * + * Initializes the speaker + * + * @return 0 if successful, negative errno code if error + */ int speaker_init(); -uint16_t speak(); + +/** + * @brief Endpoint function for streaming audio + * + * Call this function in the following way (Via ble) + * 1. Send a 2 byte packet containing the audio data size + * 2. Send to the ble notify id 400 byte packets (with notify), with each 2 bytes being the audio data + * 3. Repeat step 2 until the audio data is sent. Then the speaker will automatically play the sound + * when the audio data sent is equal to the audio data size sent in step 1 + * + * @return The amount of data successfully sent in bytes. + */ +uint16_t speak(uint16_t len, const void *buf); + +/** + * @brief Play a chime effect + * + * This function plays a chime effect. Use this to check if the speaker works correctly + * + * @return 0 if successful, negative errno code if error + */ int play_boot_sound(); -int init_haptic_pin(); \ No newline at end of file + +/** + * @brief Initialize the Haptic Pin + * + * On Call, activates the haptic pin + * + * @return 0 if successful, negative errno code if error + */ +int init_haptic_pin(); + +#endif \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/storage.c b/Friend/firmware/firmware_v1.0/src/storage.c index a7e26172f..ded23824a 100644 --- a/Friend/firmware/firmware_v1.0/src/storage.c +++ b/Friend/firmware/firmware_v1.0/src/storage.c @@ -1,16 +1,16 @@ -#include +#include +#include #include #include #include #include #include #include +#include #include #include "utils.h" -#include "btutils.h" #include "sdcard.h" -#include -#include +#include "storage.h" #include "transport.h" LOG_MODULE_REGISTER(storage, CONFIG_LOG_DEFAULT_LEVEL); @@ -102,13 +102,15 @@ static uint8_t delete_started = 0; static uint8_t current_read_num = 1; uint32_t remaining_length = 0; -static int setup_storage_tx() { - transport_started= (uint8_t)0; +static int setup_storage_tx() +{ + transport_started = (uint8_t)0; // offset = 0; LOG_INF("about to transmit storage\n"); k_msleep(1000); int res = move_read_pointer(current_read_num); - if (res) { + if (res) + { LOG_INF("bad pointer"); transport_started = 0; current_read_num = 1; @@ -119,7 +121,8 @@ static int setup_storage_tx() { LOG_INF("current read ptr %d",current_read_num); remaining_length = file_num_array[current_read_num-1]; - if(current_read_num == file_count) { + if(current_read_num == file_count) + { remaining_length = get_file_size(file_count); } @@ -135,68 +138,78 @@ static int setup_storage_tx() { } uint8_t delete_num = 0; uint8_t nuke_started = 0; -static uint8_t parse_storage_command(void *buf,uint16_t len) { +static uint8_t parse_storage_command(void *buf,uint16_t len) +{ - if (len != 6 && len != 2) { + if (len != 6 && len != 2) + { LOG_INF("invalid command"); return INVALID_COMMAND; } - uint8_t command = ((uint8_t*)buf)[0]; - uint8_t file_num = ((uint8_t*)buf)[1]; + const uint8_t command = ((uint8_t*)buf)[0]; + const uint8_t file_num = ((uint8_t*)buf)[1]; uint32_t size = 0; - if ( len == 6 ) { - - size = ((uint8_t*)buf)[2] <<24 |((uint8_t*)buf)[3] << 16 | ((uint8_t*)buf)[4] << 8 | ((uint8_t*)buf)[5]; - + if ( len == 6 ) + { + size = ((uint8_t*)buf)[2] <<24 |((uint8_t*)buf)[3] << 16 | ((uint8_t*)buf)[4] << 8 | ((uint8_t*)buf)[5]; } printk("command successful: command: %d file: %d size: %d \n",command,file_num,size); - if (file_num == 0) { - LOG_INF("invalid file count 0"); - return INVALID_FILE_SIZE; + if (file_num == 0) + { + LOG_INF("invalid file count 0"); + return INVALID_FILE_SIZE; } - if (file_num > file_count) { //invalid file count - LOG_INF("invalid file count"); - return INVALID_FILE_SIZE; -//add audio all? + if (file_num > file_count) //invalid file count + { + LOG_INF("invalid file count"); + return INVALID_FILE_SIZE; + //add audio all? } - if (command == READ_COMMAND) { //read + if (command == READ_COMMAND) //read + { uint32_t temp = file_num_array[file_num-1]; - if ( file_num == (file_count ) ) { + if ( file_num == ( file_count ) ) + { LOG_INF("file_count == final file"); offset = size; current_read_num = file_num; transport_started = 1; } - else if (temp == 0) { + else if (temp == 0) + { LOG_INF("file size is 0"); return ZERO_FILE_SIZE; } - else if (size > temp) { + else if (size > temp) + { LOG_INF("requested size is too large"); return 5; } - else { + else + { LOG_INF("valid command, setting up "); offset = size; current_read_num = file_num; transport_started = 1; } } - else if (command == DELETE_COMMAND) { - + else if (command == DELETE_COMMAND) + { delete_num = file_num; delete_started = 1; } - else if (command == NUKE) { + else if (command == NUKE) + { nuke_started = 1; } - else if (command == STOP_COMMAND) - { - remaining_length = 80; - stop_started = 1; - } - else { + else if (command == STOP_COMMAND) + { + remaining_length = 80; + stop_started = 1; + } + else + { LOG_INF("invalid command \n"); return 6; } @@ -204,8 +217,8 @@ static uint8_t parse_storage_command(void *buf,uint16_t len) { } -static ssize_t storage_write_handler(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { - +static ssize_t storage_write_handler(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) +{ LOG_INF("about to schedule the storage"); LOG_INF("was sent %d ", ((uint8_t*)buf)[0] ); @@ -219,14 +232,15 @@ static ssize_t storage_write_handler(struct bt_conn *conn, const struct bt_gatt_ return len; } -static void write_to_gatt(struct bt_conn *conn) { +static void write_to_gatt(struct bt_conn *conn) +{ uint32_t id = packet_next_index++; index = 0; storage_write_buffer[0] = id & 0xFF; storage_write_buffer[1] = (id >> 8) & 0xFF; storage_write_buffer[2] = index; - uint32_t packet_size = MIN(remaining_length,OPUS_ENTRY_LENGTH); + const uint32_t packet_size = MIN(remaining_length,OPUS_ENTRY_LENGTH); int r = read_audio_data(storage_write_buffer+FRAME_PREFIX_LENGTH,packet_size,offset); offset = offset + packet_size; @@ -247,23 +261,24 @@ static void write_to_gatt(struct bt_conn *conn) { // int err = bt_gatt_notify(conn, &storage_service.attrs[1], &storage_write_buffer,packet_size); // } - - -void storage_write(void) { - while (1) { +void storage_write(void) +{ + while (1) + { struct bt_conn *conn = get_current_connection(); - if ( transport_started ) { + if ( transport_started ) + { LOG_INF("transpor started in side : %d",transport_started); setup_storage_tx(); } //probably prefer to implement using work orders for delete,nuke,etc... - if (delete_started) { - - - LOG_INF("delete:%d\n",delete_started); + if (delete_started) + { + LOG_INF("delete:%d\n",delete_started); int err = clear_audio_file(delete_num); - if (err) { + if (err) + { printk("error clearing\n"); } else @@ -277,21 +292,21 @@ void storage_write(void) { delete_started = 0; k_msleep(10); } - if (nuke_started) { + if (nuke_started) + { clear_audio_directory(); nuke_started = 0; } if (stop_started) - { + { remaining_length = 0; stop_started = 0; + } - } - - if(remaining_length > 0 ) { - - - if (conn == NULL) { + if(remaining_length > 0 ) + { + if (conn == NULL) + { LOG_ERR("invalid connection"); remaining_length = 0; k_yield(); @@ -300,20 +315,20 @@ void storage_write(void) { transport_started = 0; if (remaining_length == 0 ) - { - if(stop_started) - { - stop_started = 0; - } - else - { - printk("done. attempting to download more files\n"); - uint8_t stop_result[1] = {100}; - int err = bt_gatt_notify(conn, &storage_service.attrs[1], &stop_result,1); - k_sleep(K_MSEC(10)); - } - - } + { + if(stop_started) + { + stop_started = 0; + } + else + { + printk("done. attempting to download more files\n"); + uint8_t stop_result[1] = {100}; + int err = bt_gatt_notify(get_current_connection(), &storage_service.attrs[1], &stop_result,1); + k_sleep(K_MSEC(10)); + } + + } } k_yield(); @@ -321,11 +336,8 @@ void storage_write(void) { } -int storage_init() { - - bt_gatt_service_register(&storage_service); +int storage_init() +{ k_thread_create(&storage_thread, storage_stack, K_THREAD_STACK_SIZEOF(storage_stack), (k_thread_entry_t)storage_write, NULL, NULL, NULL, K_PRIO_PREEMPT(7), 0, K_NO_WAIT); - return 0; - } \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/storage.h b/Friend/firmware/firmware_v1.0/src/storage.h index c421a89fe..13c0366f3 100644 --- a/Friend/firmware/firmware_v1.0/src/storage.h +++ b/Friend/firmware/firmware_v1.0/src/storage.h @@ -1,4 +1,14 @@ -#pragma once +#ifndef STORAGE_H +#define STORAGE_H #include -int storage_init(); \ No newline at end of file +/** + * @brief Initializes the Storage Transport thread + * + * Initializes the Storage Transport thread + * + * @return 0 if successful, negative errno code if error + */ +int storage_init(); + +#endif \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index c56756c5c..b6514ae34 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -1,23 +1,24 @@ -#include #include -#include #include #include #include #include #include -#include +#include #include +#include +#include +#include #include "transport.h" #include "config.h" #include "utils.h" -#include "btutils.h" // #include "nfc.h" -#include "lib/battery/battery.h" #include "speaker.h" #include "button.h" #include "sdcard.h" -#include +#include "storage.h" +#include "lib/battery/battery.h" +#include "btutils.h" LOG_MODULE_REGISTER(transport, CONFIG_LOG_DEFAULT_LEVEL); @@ -62,10 +63,10 @@ static struct bt_gatt_attr audio_service_attr[] = { BT_GATT_CHARACTERISTIC(&audio_characteristic_data_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ, audio_data_read_characteristic, NULL, NULL), BT_GATT_CCC(audio_ccc_config_changed_handler, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), BT_GATT_CHARACTERISTIC(&audio_characteristic_format_uuid.uuid, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, audio_codec_read_characteristic, NULL, NULL), -#ifdef CONFIG_ENABLE_SPEAKER - BT_GATT_CHARACTERISTIC(&audio_characteristic_speaker_uuid.uuid, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_WRITE, NULL, audio_data_write_handler, NULL), - BT_GATT_CCC(audio_ccc_config_changed_handler, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), // -#endif +// #ifdef CONFIG_ENABLE_SPEAKER +// BT_GATT_CHARACTERISTIC(&audio_characteristic_speaker_uuid.uuid, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_WRITE, NULL, audio_data_write_handler, NULL), +// BT_GATT_CCC(audio_ccc_config_changed_handler, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), // +// #endif }; @@ -87,16 +88,6 @@ static struct bt_gatt_service dfu_service = BT_GATT_SERVICE(dfu_service_attr); //Acceleration data //this code activates the onboard accelerometer. some cute ideas may include shaking the necklace to color strobe // -typedef struct sensors{ - - struct sensor_value a_x; - struct sensor_value a_y; - struct sensor_value a_z; - struct sensor_value g_x; - struct sensor_value g_y; - struct sensor_value g_z; - -}; static struct sensors mega_sensor; static struct device *lsm6dsl_dev; //Arbritrary uuid, feel free to change @@ -140,7 +131,8 @@ void broadcast_accel(struct k_work *work_item) { //only time mega sensor is changed is through here (hopefully), so no chance of race condition int err = bt_gatt_notify(current_connection, &accel_service.attrs[1], &mega_sensor, sizeof(mega_sensor)); - if (err) { + if (err) + { LOG_ERR("Error updating Accelerometer data"); } k_work_reschedule(&accel_work, K_MSEC(ACCEL_REFRESH_INTERVAL)); @@ -148,8 +140,9 @@ void broadcast_accel(struct k_work *work_item) { //use d4,d5 -static void accel_ccc_config_changed_handler(const struct bt_gatt_attr *attr, uint16_t value) { - if (value == BT_GATT_CCC_NOTIFY) +static void accel_ccc_config_changed_handler(const struct bt_gatt_attr *attr, uint16_t value) +{ + if (value == BT_GATT_CCC_NOTIFY) { LOG_INF("Client subscribed for notifications"); } @@ -163,15 +156,18 @@ static void accel_ccc_config_changed_handler(const struct bt_gatt_attr *attr, ui } } -int accel_start() { +int accel_start() +{ struct sensor_value odr_attr; lsm6dsl_dev = DEVICE_DT_GET_ONE(st_lsm6dsl); k_msleep(50); - if (lsm6dsl_dev == NULL) { + if (lsm6dsl_dev == NULL) + { LOG_ERR("Could not get LSM6DSL device"); return 0; } - if (!device_is_ready(lsm6dsl_dev)) { + if (!device_is_ready(lsm6dsl_dev)) + { LOG_ERR("LSM6DSL: not ready"); return 0; } @@ -179,18 +175,20 @@ int accel_start() { odr_attr.val2 = 0; if (sensor_attr_set(lsm6dsl_dev, SENSOR_CHAN_ACCEL_XYZ, - SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { - LOG_ERR("Cannot set sampling frequency for Accelerometer."); + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) + { + LOG_ERR("Cannot set sampling frequency for Accelerometer."); return 0; } if (sensor_attr_set(lsm6dsl_dev, SENSOR_CHAN_GYRO_XYZ, - SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { - LOG_ERR("Cannot set sampling frequency for gyro."); + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + LOG_ERR("Cannot set sampling frequency for gyro."); return 0; } - if (sensor_sample_fetch(lsm6dsl_dev) < 0) { - LOG_ERR("Sensor sample update error"); - return 0; + if (sensor_sample_fetch(lsm6dsl_dev) < 0) + { + LOG_ERR("Sensor sample update error"); + return 0; } LOG_INF("Accelerometer is ready for use \n"); @@ -244,12 +242,12 @@ static ssize_t audio_codec_read_characteristic(struct bt_conn *conn, const struc } static ssize_t audio_data_write_handler(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) - { - uint16_t amount = 0; - bt_gatt_notify(conn, attr, &amount, sizeof(amount)); - amount = speak(len, buf); - return len; - } +{ + uint16_t amount = 0; + bt_gatt_notify(conn, attr, &amount, sizeof(amount)); + amount = speak(len, buf); + return len; +} // // DFU Service Handlers @@ -351,16 +349,13 @@ static void _transport_connected(struct bt_conn *conn, uint8_t err) k_work_schedule(&battery_work, K_MSEC(BATTERY_REFRESH_INTERVAL)); - is_connected = true; + is_connected = true; // // Put NFC to sleep when Bluetooth is connected // nfc_sleep(); -#ifdef CONFIG_ACCELEROMETER - k_work_schedule(&accel_work, K_MSEC(ACCEL_REFRESH_INTERVAL)); -#endif -#ifdef CONFIG_ENABLE_BUTTON - activate_button_work(); -#endif +// #ifdef CONFIG_ACCELEROMETER +// k_work_schedule(&accel_work, K_MSEC(ACCEL_REFRESH_INTERVAL)); +// #endif } @@ -397,8 +392,8 @@ static void _le_param_updated(struct bt_conn *conn, uint16_t interval, static void _le_phy_updated(struct bt_conn *conn, struct bt_conn_le_phy_info *param) { - LOG_DBG("LE PHY updated: TX PHY %s, RX PHY %s", - phy2str(param->tx_phy), phy2str(param->rx_phy)); + // LOG_DBG("LE PHY updated: TX PHY %s, RX PHY %s", + // phy2str(param->tx_phy), phy2str(param->rx_phy)); } static void _le_data_length_updated(struct bt_conn *conn, @@ -480,7 +475,7 @@ static bool read_from_tx_queue() // // Thread -K_THREAD_STACK_DEFINE(pusher_stack, 2048); +K_THREAD_STACK_DEFINE(pusher_stack, 4096); static struct k_thread pusher_thread; static uint16_t packet_next_index = 0; static uint8_t pusher_temp_data[CODEC_OUTPUT_MAX_BYTES + NET_BUFFER_HEADER_SIZE]; @@ -544,14 +539,15 @@ static bool push_to_gatt(struct bt_conn *conn) #define MAX_WRITE_SIZE 400 static uint32_t offset = 0; static uint16_t buffer_offset = 0; -bool write_to_storage(void) { +bool write_to_storage(void) +{ if (!read_from_tx_queue()) { return false; } uint8_t *buffer = tx_buffer+2; - uint32_t packet_size = tx_buffer_size; + const uint32_t packet_size = tx_buffer_size; //load into write at 400 bytes at a time. is faster memcpy(storage_temp_data + OPUS_PREFIX_LENGTH + buffer_offset, buffer, packet_size); storage_temp_data[buffer_offset] = (uint8_t)tx_buffer_size; @@ -611,40 +607,40 @@ static bool use_storage = true; #define MAX_AUDIO_FILE_SIZE 300000 static int recent_file_size_updated = 0; - void update_file_size() - { - file_num_array[0] = get_file_size(1); - printk("file size for file count %d %d\n",file_count,file_num_array[0]); - } +void update_file_size() +{ + file_num_array[0] = get_file_size(1); + printk("file size for file count %d %d\n",file_count,file_num_array[0]); +} void pusher(void) { k_msleep(500); while (1) { - - // // Load current connection // - struct bt_conn *conn = current_connection; - bool use_gatt = true; //updating the most recent file size is expensive! - static bool file_size_updated = true; - static bool connection_was_true = false; - if (conn && !connection_was_true) { - k_msleep(100); - file_size_updated = false; - connection_was_true = true; - } else if (!conn) { - connection_was_true = false; - } - if (!file_size_updated) { - printk("updating file size\n"); - update_file_size(); - file_size_updated = true; - } + static bool file_size_updated = true; + static bool connection_was_true = false; + if (conn && !connection_was_true) + { + k_msleep(100); + file_size_updated = false; + connection_was_true = true; + } + else if (!conn) + { + connection_was_true = false; + } + if (!file_size_updated) + { + printk("updating file size\n"); + update_file_size(); + file_size_updated = true; + } if (conn) { conn = bt_conn_ref(conn); @@ -665,29 +661,24 @@ void pusher(void) if (!valid && !storage_is_on) { - bool result = write_to_storage(); - if (result) { - + } else { - k_sleep(K_MSEC(10)); + } } - if (valid) { - bool sent = push_to_gatt(conn); if (!sent) { - k_sleep(K_MSEC(50)); + // k_sleep(K_MSEC(50)); } } - if (conn) { bt_conn_unref(conn); @@ -697,8 +688,6 @@ void pusher(void) } } extern struct bt_gatt_service storage_service; - - // // Public functions // @@ -716,38 +705,46 @@ int transport_start() return err; } LOG_INF("Transport bluetooth initialized"); + // Enable accelerometer #ifdef CONFIG_ACCELEROMETER err = accel_start(); - if (!err) { + if (!err) + { LOG_INF("Accelerometer failed to activate\n"); } - else { + else + { + LOG_INF("Accelerometer initialized"); bt_gatt_service_register(&accel_service); } #endif - + // Enable button #ifdef CONFIG_ENABLE_BUTTON - - button_init(); - register_button_service(); + button_init(); + register_button_service(); + activate_button_work(); #endif #ifdef CONFIG_ENABLE_SPEAKER + err = speaker_init(); + if (err) + { + LOG_ERR("Speaker failed to start"); + return 0; + } + else + { + LOG_INF("Speaker initialized"); + } -err = speaker_init(); -if(!err) { - LOG_ERR("Speaker failed to start"); - return 0; -} - -play_boot_sound(); - + play_boot_sound(); #endif // Start advertising + + memset(storage_temp_data, 0, OPUS_PADDED_LENGTH * 4); bt_gatt_service_register(&storage_service); bt_gatt_service_register(&audio_service); bt_gatt_service_register(&dfu_service); - memset(storage_temp_data, 0, OPUS_PADDED_LENGTH * 4); err = bt_le_adv_start(BT_LE_ADV_CONN, bt_ad, ARRAY_SIZE(bt_ad), bt_sd, ARRAY_SIZE(bt_sd)); if (err) { @@ -760,10 +757,8 @@ play_boot_sound(); } int battErr = 0; - battErr |= battery_init(); battErr |= battery_charge_start(); - if (battErr) { LOG_ERR("Battery init failed (err %d)", battErr); diff --git a/Friend/firmware/firmware_v1.0/src/transport.h b/Friend/firmware/firmware_v1.0/src/transport.h index b7e45648d..6b22d6d4f 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.h +++ b/Friend/firmware/firmware_v1.0/src/transport.h @@ -1,5 +1,26 @@ -#pragma once -#include +#ifndef TRANSPORT_H +#define TRANSPORT_H + +#include +typedef struct sensors { + + struct sensor_value a_x; + struct sensor_value a_y; + struct sensor_value a_z; + struct sensor_value g_x; + struct sensor_value g_y; + struct sensor_value g_z; + +}; +/** + * @brief Initialize the BLE transport logic + * + * Initializes the BLE Logic + * + * @return 0 if successful, negative errno code if error + */ int transport_start(); int broadcast_audio_packets(uint8_t *buffer, size_t size); -struct bt_conn *get_current_connection(); \ No newline at end of file +struct bt_conn *get_current_connection(); + +#endif \ No newline at end of file diff --git a/Friend/firmware/firmware_v1.0/src/utils.h b/Friend/firmware/firmware_v1.0/src/utils.h index 6dabc59c1..fc23b8d52 100644 --- a/Friend/firmware/firmware_v1.0/src/utils.h +++ b/Friend/firmware/firmware_v1.0/src/utils.h @@ -1,4 +1,6 @@ -#pragma once +#ifndef UTILS_H +#define UTILS_H + #include #include @@ -15,3 +17,5 @@ LOG_ERR("Error at %s:%d:%d", __FILE__, __LINE__, result); \ return -1; \ } + +#endif \ No newline at end of file diff --git a/Friend/firmware/testing/button_test_files/button_test.py b/Friend/firmware/testing/button_test_files/button_test.py new file mode 100644 index 000000000..e68658570 --- /dev/null +++ b/Friend/firmware/testing/button_test_files/button_test.py @@ -0,0 +1,34 @@ + +import os +from dotenv import load_dotenv +import asyncio +import bleak +import numpy as np +from bleak import BleakClient +load_dotenv() +audio_frames = [] + +device_id = "3C71D8C0-B1AF-5976-A47F-5D7A96267F67" #Please enter the id of your device (that is, the device id used to connect to your BT device here) +button_uuid = "23BA7924-0000-1000-7450-346EAC492E92" #dont change this +button_read_uuid = "23BA7925-0000-1000-7450-346EAC492E92" +read_or_clear = 0 # 0 for read, 1 for clear +file_num = 1 +count = 1 +async def main(): + + global device_uuid + global storage_uuid + global count + + async with BleakClient(device_id) as client: + + async def on_notify(sender: bleak.BleakGATTCharacteristic, data: bytearray): + print(data) + stuff = await client.start_notify(button_read_uuid, on_notify) + await asyncio.sleep(1) + while True: + await asyncio.sleep(1) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/Friend/firmware/testing/button_test_files/discover_devices.py b/Friend/firmware/testing/button_test_files/discover_devices.py new file mode 100644 index 000000000..b78cbf582 --- /dev/null +++ b/Friend/firmware/testing/button_test_files/discover_devices.py @@ -0,0 +1,9 @@ +import asyncio +from bleak import BleakScanner + +async def main(): + devices = await BleakScanner.discover() + for d in devices: + print(d) + +asyncio.run(main()) \ No newline at end of file diff --git a/Friend/firmware/testing/sdcard_test_files/decode_audio.py b/Friend/firmware/testing/sdcard_test_files/decode_audio.py new file mode 100644 index 000000000..d3b26363c --- /dev/null +++ b/Friend/firmware/testing/sdcard_test_files/decode_audio.py @@ -0,0 +1,37 @@ +import opuslib +import numpy as np +import wave +opus_decoder = opuslib.Decoder(16000, 1) +pcm_data = bytearray() +f=[] +count = 0 +with open("my_file.txt", "rb") as binary_file: + info_char = binary_file.read() + count = int(len(info_char) / 83) + + + for i in range(0,count): + sample_frame = info_char[i*83:(i+1)*83] + amount = int(sample_frame[3]) + frame_to_decode = bytes(list(sample_frame[4:4+amount])) + + f.append(frame_to_decode) + + # print(i) + opus_frame = opus_decoder.decode(bytes(frame_to_decode), 160,decode_fec=False) + + + for frame in f: + try: + decoded_frame = opus_decoder.decode(bytes(frame), 960) + pcm_data.extend(decoded_frame) + except Exception as e: + print(f"Error decoding frame: {e}") + count+=1 + + with wave.open('decoded_audio.wav', 'wb') as wav_file: + wav_file.setnchannels(1) # Mono + wav_file.setsampwidth(2) # 16-bit + wav_file.setframerate(16000) # Sample rate + wav_file.writeframes(pcm_data) +# print(count) diff --git a/Friend/firmware/testing/sdcard_test_files/delete_audio_files.py b/Friend/firmware/testing/sdcard_test_files/delete_audio_files.py new file mode 100644 index 000000000..3fc670836 --- /dev/null +++ b/Friend/firmware/testing/sdcard_test_files/delete_audio_files.py @@ -0,0 +1,42 @@ +import asyncio +import bleak +import numpy as np +from bleak import BleakClient + +device_id = "3C71D8C0-B1AF-5976-A47F-5D7A96267F67" #Please enter the id of your device (that is, the device id used to connect to your BT device here) +storage_uuid = "30295781-4301-EABD-2904-2849ADFEAE43" #dont change this +storage_read_uuid = "30295782-4301-EABD-2904-2849ADFEAE43" +read_or_clear = 0 # 0 for read, 1 for clear +file_num = 1 +command_num = 1 +count = 1 +async def main(): + + global device_uuid + global storage_uuid + global count + + async with BleakClient(device_id) as client: + + + async def on_notify(sender: bleak.BleakGATTCharacteristic, data: bytearray): + global count + # Write bytes to file + if (len(data)==1): + print(data[0]) + if (data[0] == 200): + print('done') + + stuff = await client.start_notify(storage_uuid, on_notify) + + await asyncio.sleep(1) + command = bytearray([command_num,file_num ,0,0,0,0]) + await client.write_gatt_char(storage_uuid, command, response=True) + await asyncio.sleep(1) + while True: + await asyncio.sleep(1) + + +if __name__ == "__main__": + asyncio.run(main()) + diff --git a/Friend/firmware/testing/sdcard_test_files/discover_devices.py b/Friend/firmware/testing/sdcard_test_files/discover_devices.py new file mode 100644 index 000000000..b78cbf582 --- /dev/null +++ b/Friend/firmware/testing/sdcard_test_files/discover_devices.py @@ -0,0 +1,9 @@ +import asyncio +from bleak import BleakScanner + +async def main(): + devices = await BleakScanner.discover() + for d in devices: + print(d) + +asyncio.run(main()) \ No newline at end of file diff --git a/Friend/firmware/testing/sdcard_test_files/get_audio_file.py b/Friend/firmware/testing/sdcard_test_files/get_audio_file.py new file mode 100644 index 000000000..a10cfa31b --- /dev/null +++ b/Friend/firmware/testing/sdcard_test_files/get_audio_file.py @@ -0,0 +1,71 @@ +import asyncio +import bleak +import numpy as np +from bleak import BleakClient +import time + +audio_frames = [] +device_id = "3C71D8C0-B1AF-5976-A47F-5D7A96267F67" #Please enter the id of your device (that is, the device id used to connect to your BT device here) +storage_uuid = "30295781-4301-EABD-2904-2849ADFEAE43" #dont change this +storage_read_uuid = "30295782-4301-EABD-2904-2849ADFEAE43" +read_or_clear = 0 # 0 for read, 1 for clear +file_num = 1 +count = 0 +pcm_data=bytearray() +done =False +start_time = time.time() +total = 0 +async def main(): + + global device_uuid + global storage_uuid + global count + global pcm_data + global done + global decoder + global start_time + global total + async with BleakClient(device_id) as client: + with open("my_file.txt", "wb") as binary_file: + result = bytearray() + + async def on_notify(sender: bleak.BleakGATTCharacteristic, data: bytearray): + # Write bytes to file + global start_time + global count + global done + global total + + if (len(data)==1): + if (data[0] == 100): + print('total bandwidth in bytes/second') + result = total / (time.time()-start_time) + print(result) + print('audio transfer done') + if(data[0] == 0): + print('valid response') + else: + + if (len(data) == 83): + total +=83 + # audio_frames.append(data) + binary_file.write(data) + # print('current rate') + # f = total / (time.time()-start_time) + # print(f) + + stuff = await client.start_notify(storage_uuid, on_notify) + await asyncio.sleep(1) + command = bytearray([read_or_clear,file_num ,0,0,0,0]) + await client.write_gatt_char(storage_uuid, command, response=True) + + print(stuff) + await asyncio.sleep(1) + while True: + await asyncio.sleep(1) + + +if __name__ == "__main__": + asyncio.run(main()) + + diff --git a/Friend/firmware/testing/sdcard_test_files/get_info_list.py b/Friend/firmware/testing/sdcard_test_files/get_info_list.py new file mode 100644 index 000000000..9f573bd1b --- /dev/null +++ b/Friend/firmware/testing/sdcard_test_files/get_info_list.py @@ -0,0 +1,23 @@ +import asyncio +import bleak +import numpy as np +from bleak import BleakClient + +device_id = "8C8ED9F9-8A05-F50F-AECE-E89674761304" #Please enter the id of your device (that is, the device id used to connect to your BT device here) +storage_uuid = "30295782-4301-EABD-2904-2849ADFEAE43" #dont change this + +async def main(): + async with BleakClient(device_id) as client: + + r = await client.read_gatt_char(storage_uuid) + await asyncio.sleep(2.0) + + while(True): + await asyncio.sleep(2.0) + print(np.frombuffer(r,dtype=np.uint32)) + + +if __name__ == "__main__": + asyncio.run(main()) + + diff --git a/Friend/firmware/testing/sdcard_test_files/requirements.txt b/Friend/firmware/testing/sdcard_test_files/requirements.txt new file mode 100644 index 000000000..c38c769e8 --- /dev/null +++ b/Friend/firmware/testing/sdcard_test_files/requirements.txt @@ -0,0 +1,4 @@ +bleak==0.21.1 +numpy==1.26.4 +scipy==1.12.0 +opuslib==3.0.1 diff --git a/Friend/firmware/v2_build/omi_v2.uf2 b/Friend/firmware/v2_build/omi_v2.uf2 new file mode 100644 index 000000000..c09ceed1e Binary files /dev/null and b/Friend/firmware/v2_build/omi_v2.uf2 differ diff --git a/Friend/firmware/v2_build/zephyr.uf2 b/Friend/firmware/v2_build/zephyr.uf2 new file mode 100644 index 000000000..d893cc3da Binary files /dev/null and b/Friend/firmware/v2_build/zephyr.uf2 differ