From 5135bd737c59d8b0b6417de8ded88fd64b494c58 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:30:04 +1100 Subject: [PATCH 01/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index b1bbb9344..bf4dcabfe 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -59,6 +59,9 @@ static struct bt_uuid_128 audio_characteristic_data_uuid = BT_UUID_INIT_128(BT_U static struct bt_uuid_128 audio_characteristic_format_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x19B10002, 0xE8F2, 0x537E, 0x4F6C, 0xD104768A1214)); static struct bt_uuid_128 audio_characteristic_speaker_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x19B10003, 0xE8F2, 0x537E, 0x4F6C, 0xD104768A1214)); +static struct bt_uuid_128 voice_interaction_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x19B10004, 0xE8F2, 0x537E, 0x4F6C, 0xD104768A1214)); +static struct bt_uuid_128 voice_interaction_rx_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x19B10005, 0xE8F2, 0x537E, 0x4F6C, 0xD104768A1214)); + static struct bt_gatt_attr audio_service_attr[] = { BT_GATT_PRIMARY_SERVICE(&audio_service_uuid), 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), @@ -68,7 +71,18 @@ static struct bt_gatt_attr audio_service_attr[] = { 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 - + + BT_GATT_CHARACTERISTIC(&voice_interaction_uuid.uuid, + BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ, + NULL, NULL, NULL), + BT_GATT_CCC(audio_ccc_config_changed_handler, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), + + BT_GATT_CHARACTERISTIC(&voice_interaction_rx_uuid.uuid, + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_WRITE, + NULL, voice_interaction_write_handler, NULL), }; static struct bt_gatt_service audio_service = BT_GATT_SERVICE(audio_service_attr); @@ -706,9 +720,11 @@ extern struct bt_gatt_service storage_service; int bt_on() { int err = bt_enable(NULL); - bt_le_adv_start(BT_LE_ADV_CONN, bt_ad, ARRAY_SIZE(bt_ad), bt_sd, ARRAY_SIZE(bt_sd)); - // bt_gatt_service_register(&storage_service); - + if (err) { + return err; + } + err = bt_le_adv_start(BT_LE_ADV_CONN, bt_ad, ARRAY_SIZE(bt_ad), bt_sd, ARRAY_SIZE(bt_sd)); + return err; } //periodic advertising @@ -804,8 +820,22 @@ struct bt_conn *get_current_connection() int broadcast_audio_packets(uint8_t *buffer, size_t size) { - while (!write_to_tx_queue(buffer, size)) - { + if (is_off) { + return -EPERM; // Device is sleeping + } + + if (voice_interaction_active) { + // Send through voice interaction characteristic + struct bt_conn *conn = get_current_connection(); + if (conn) { + int index = 6; // Index of voice interaction characteristic + bt_gatt_notify(conn, &audio_service.attrs[index], buffer, size); + } + return 0; + } + + // Normal audio handling + while (!write_to_tx_queue(buffer, size)) { k_sleep(K_MSEC(1)); } return 0; From 1637309451b2f35aa046916bf680b8b2802ff2c3 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:30:09 +1100 Subject: [PATCH 02/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index bf4dcabfe..9b379f19c 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -840,3 +840,50 @@ int broadcast_audio_packets(uint8_t *buffer, size_t size) } return 0; } + +static ssize_t voice_interaction_write_handler(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, + uint16_t len, + uint16_t offset, + uint8_t flags) { + // Handle incoming audio data for voice response using streaming + speak_stream(len, buf); + return len; +} + +static bool voice_interaction_active = false; + +void start_voice_interaction() { + if (!is_off) { // Only start if device is awake + voice_interaction_active = true; + LOG_INF("Voice interaction started"); + + // Optional: Play feedback sound + play_haptic_milli(50); + } +} + +void stop_voice_interaction() { + if (voice_interaction_active) { + voice_interaction_active = false; + LOG_INF("Voice interaction stopped"); + + // Optional: Play feedback sound + play_haptic_milli(25); + } +} + +static const char *phy2str(uint8_t phy) +{ + switch (phy) { + case BT_GAP_LE_PHY_1M: + return "1M"; + case BT_GAP_LE_PHY_2M: + return "2M"; + case BT_GAP_LE_PHY_CODED: + return "Coded"; + default: + return "Unknown"; + } +} From 2b23601dbc3022f9b5917ac0d9211b603b83c7f5 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:30:19 +1100 Subject: [PATCH 03/60] Update speaker.c --- Friend/firmware/firmware_v1.0/src/speaker.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/speaker.c b/Friend/firmware/firmware_v1.0/src/speaker.c index 746395319..e7f16b620 100644 --- a/Friend/firmware/firmware_v1.0/src/speaker.c +++ b/Friend/firmware/firmware_v1.0/src/speaker.c @@ -36,7 +36,13 @@ 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() +#define STREAM_BUFFER_SIZE 8192 +static uint8_t stream_buffer[STREAM_BUFFER_SIZE]; +static size_t stream_buffer_pos = 0; + +extern bool is_off; + +int speaker_init() { LOG_INF("Speaker init"); audio_speaker = device_get_binding("I2S_0"); From 25044a366d8b03db30c1ca5626a05bbbb3392d6d Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:30:28 +1100 Subject: [PATCH 04/60] Update speaker.c --- Friend/firmware/firmware_v1.0/src/speaker.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/speaker.c b/Friend/firmware/firmware_v1.0/src/speaker.c index e7f16b620..d1f83fdcf 100644 --- a/Friend/firmware/firmware_v1.0/src/speaker.c +++ b/Friend/firmware/firmware_v1.0/src/speaker.c @@ -90,7 +90,12 @@ int speaker_init() uint16_t speak(uint16_t len, const void *buf) //direct from bt { - uint16_t amount = 0; + // Don't process audio if device is sleeping + if (is_off) { + return 0; + } + + uint16_t amount = 0; amount = len; if (len == 4) //if stage 1 { From 26d591eeb606c11007707d94ccb4b167b26cd89b Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:30:36 +1100 Subject: [PATCH 05/60] Update speaker.c --- Friend/firmware/firmware_v1.0/src/speaker.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/speaker.c b/Friend/firmware/firmware_v1.0/src/speaker.c index d1f83fdcf..a11a7d213 100644 --- a/Friend/firmware/firmware_v1.0/src/speaker.c +++ b/Friend/firmware/firmware_v1.0/src/speaker.c @@ -97,8 +97,9 @@ uint16_t speak(uint16_t len, const void *buf) //direct from bt uint16_t amount = 0; amount = len; - if (len == 4) //if stage 1 - { + + if (len == 4) //if stage 1 + { current_length = ((uint32_t *)buf)[0]; LOG_INF("About to write %u bytes", current_length); ptr2 = (int16_t *)rx_buffer; From bcc79565cca3622151877377fe941a98245ed999 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:30:48 +1100 Subject: [PATCH 06/60] Update speaker.c --- Friend/firmware/firmware_v1.0/src/speaker.c | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/speaker.c b/Friend/firmware/firmware_v1.0/src/speaker.c index a11a7d213..1a7d3fd13 100644 --- a/Friend/firmware/firmware_v1.0/src/speaker.c +++ b/Friend/firmware/firmware_v1.0/src/speaker.c @@ -161,6 +161,34 @@ uint16_t speak(uint16_t len, const void *buf) //direct from bt return amount; } +// Add new function for streaming audio +uint16_t speak_stream(uint16_t len, const void *buf) { + // Don't process audio if device is sleeping + if (is_off) { + return 0; + } + + uint16_t amount = len; + + // Handle streaming audio + if (stream_buffer_pos + len > STREAM_BUFFER_SIZE) { + // Buffer full - play what we have + i2s_write(audio_speaker, stream_buffer, stream_buffer_pos); + stream_buffer_pos = 0; + } + + // Add new data to buffer + memcpy(stream_buffer + stream_buffer_pos, buf, len); + stream_buffer_pos += len; + + // If we have enough data or this is the end, play it + if (stream_buffer_pos >= 1024 || len < 400) { + i2s_write(audio_speaker, stream_buffer, stream_buffer_pos); + stream_buffer_pos = 0; + } + + return amount; +} void generate_gentle_chime(int16_t *buffer, int num_samples) { From 1ac0552ef2d1561d22d3b097425701e717bd7056 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:30:59 +1100 Subject: [PATCH 07/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 0d729e569..727d3bc68 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -84,12 +84,19 @@ K_WORK_DELAYABLE_DEFINE(button_work, check_button_level); #define DEFAULT_STATE 0 -#define SINGLE_TAP 1 -#define DOUBLE_TAP 2 -#define LONG_TAP 3 -#define BUTTON_PRESS 4 -#define BUTTON_RELEASE 5 - +#define SINGLE_TAP 1 // Quick press and release +#define DOUBLE_TAP 2 // Two quick presses - Currently used for voice interaction +#define LONG_TAP 3 // Long press - Currently used for sleep/wake +#define BUTTON_PRESS 4 // Button down event +#define BUTTON_RELEASE 5 // Button up event + +// FSM States +typedef enum { + IDLE, + ONE_PRESS, + TWO_PRESS, + GRACE +} FSM_STATE_T; // 4 is button down, 5 is button up static FSM_STATE_T current_button_state = IDLE; From 9f6fc90a3db29745a29cce78e532b697e8077bdf Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:31:09 +1100 Subject: [PATCH 08/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 727d3bc68..619c2ad59 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -144,14 +144,22 @@ static inline void notify_tap() } } -static inline void notify_double_tap() -{ - final_button_state[0] = DOUBLE_TAP; //button press - LOG_INF("double tap"); - 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 inline void notify_double_tap() { + // Only start voice interaction if device is not in sleep mode + if (!is_off) { + final_button_state[0] = DOUBLE_TAP; + LOG_INF("double tap - starting voice interaction"); + + 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)); + } + + // Start voice interaction mode + start_voice_interaction(); + + // Play feedback sound + play_haptic_milli(50); } } From 4a2273f02f6b9b706d41195b5c0e53489b1f2c22 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:31:15 +1100 Subject: [PATCH 09/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 619c2ad59..252c08f9f 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -163,9 +163,13 @@ static inline void notify_double_tap() { } } -static inline void notify_long_tap() -{ - final_button_state[0] = LONG_TAP; //button press +static inline void notify_long_tap() { + // If voice interaction is active, stop it first + if (voice_interaction_active) { + stop_voice_interaction(); + } + + final_button_state[0] = LONG_TAP; LOG_INF("long tap"); struct bt_conn *conn = get_current_connection(); if (conn != NULL) From be2e2fec29836fb672bbaee558baf7505b089404 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:31:26 +1100 Subject: [PATCH 10/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 252c08f9f..7f25d04cc 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -172,10 +172,26 @@ static inline void notify_long_tap() { final_button_state[0] = LONG_TAP; LOG_INF("long tap"); struct bt_conn *conn = get_current_connection(); - if (conn != NULL) - { + if (conn != NULL) { bt_gatt_notify(conn, &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); } + + // Handle sleep mode + is_off = !is_off; + play_haptic_milli(100); + if (is_off) { + bt_disable(); + int err = bt_le_adv_stop(); + if (err) { + printk("Failed to stop Bluetooth %d\n",err); + } + } else { + int err = bt_enable(NULL); + if (err) { + printk("Failed to enable Bluetooth %d\n",err); + } + bt_on(); + } } #define LONG_PRESS_INTERVAL 25 From ce62e98e7124a66df99b33c3edf8920958e9f40d Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:31:31 +1100 Subject: [PATCH 11/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 7f25d04cc..e8a4b5eb1 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -342,6 +342,9 @@ void check_button_level(struct k_work *work_item) if (inc_count_0 == 0 && (inc_count_1 > 0)) { notify_unpress(); + + // End voice interaction if it was active + stop_voice_interaction(); } inc_count_0++; if (inc_count_0 > 1) From 5a1d1c9e423fbc13648c0fa5429994306fd4c99b Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:31:40 +1100 Subject: [PATCH 12/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index e8a4b5eb1..2a06e5737 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -443,4 +443,8 @@ void register_button_service() FSM_STATE_T get_current_button_state() { return current_button_state; -} \ No newline at end of file +} + +extern void start_voice_interaction(void); +extern void stop_voice_interaction(void); +extern bool voice_interaction_active; From e64d49565aef52b086919482b001eeb73f35b478 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:33:32 +1100 Subject: [PATCH 13/60] Update speaker.h --- Friend/firmware/firmware_v1.0/src/speaker.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/speaker.h b/Friend/firmware/firmware_v1.0/src/speaker.h index c67887524..79a5ae02a 100644 --- a/Friend/firmware/firmware_v1.0/src/speaker.h +++ b/Friend/firmware/firmware_v1.0/src/speaker.h @@ -50,4 +50,17 @@ int init_haptic_pin(); * @return a sound hopefully */ void play_haptic_milli(uint32_t duration); -#endif \ No newline at end of file + +/** + * @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_stream(uint16_t len, const void *buf); +#endif From 0559d9ea7b9da1015524c272242a706946f3c838 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:33:52 +1100 Subject: [PATCH 14/60] Update button.h --- Friend/firmware/firmware_v1.0/src/button.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/button.h b/Friend/firmware/firmware_v1.0/src/button.h index 7108889b0..31dcf0fd3 100644 --- a/Friend/firmware/firmware_v1.0/src/button.h +++ b/Friend/firmware/firmware_v1.0/src/button.h @@ -13,5 +13,9 @@ void activate_button_work(); void register_button_service(); FSM_STATE_T get_current_button_state(); +// Voice interaction declarations +extern void start_voice_interaction(void); +extern void stop_voice_interaction(void); +extern bool voice_interaction_active; #endif \ No newline at end of file From 8635c496ca94f82c75dfab524c6dae58e75de8a6 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:47:52 +1100 Subject: [PATCH 15/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 2a06e5737..d18ffe594 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -43,8 +43,8 @@ static void button_ccc_config_changed_handler(const struct bt_gatt_attr *attr, u } } -struct gpio_dt_spec d4_pin = {.port = DEVICE_DT_GET(DT_NODELABEL(gpio0)), .pin=4, .dt_flags = GPIO_OUTPUT_ACTIVE}; //3.3 -struct gpio_dt_spec d5_pin_input = {.port = DEVICE_DT_GET(DT_NODELABEL(gpio0)), .pin=5, .dt_flags = GPIO_INT_EDGE_RISING}; +struct gpio_dt_spec d4_pin = {.port = DEVICE_DT_GET(DT_NODELABEL(gpio0)), .pin=4, .dt_flags = GPIO_OUTPUT}; +struct gpio_dt_spec d5_pin_input = { .port = DEVICE_DT_GET(DT_NODELABEL(gpio0)), .pin = 5, .dt_flags = GPIO_INPUT | GPIO_INT_EDGE_BOTH }; static uint32_t current_button_time = 0; static uint32_t previous_button_time = 0; From a9806be5ff985fbf3c2fa87bc0efc5afdb1b7d42 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:48:01 +1100 Subject: [PATCH 16/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index d18ffe594..aa0fd7079 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -83,22 +83,6 @@ void check_button_level(struct k_work *work_item); K_WORK_DELAYABLE_DEFINE(button_work, check_button_level); -#define DEFAULT_STATE 0 -#define SINGLE_TAP 1 // Quick press and release -#define DOUBLE_TAP 2 // Two quick presses - Currently used for voice interaction -#define LONG_TAP 3 // Long press - Currently used for sleep/wake -#define BUTTON_PRESS 4 // Button down event -#define BUTTON_RELEASE 5 // Button up event - -// FSM States -typedef enum { - IDLE, - ONE_PRESS, - TWO_PRESS, - GRACE -} FSM_STATE_T; - -// 4 is button down, 5 is button up static FSM_STATE_T current_button_state = IDLE; static uint32_t inc_count_1 = 0; static uint32_t inc_count_0 = 0; From 369588456b89b9afa8c0081cde81aafff0cbda94 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:48:12 +1100 Subject: [PATCH 17/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index aa0fd7079..ed0ed41b2 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -384,7 +384,7 @@ int button_init() return -1; } - int err2 = gpio_pin_configure_dt(&d5_pin_input,GPIO_INPUT); + int err2 = gpio_pin_configure_dt(&d5_pin_input, GPIO_INPUT | GPIO_INT_EDGE_BOTH); if (err2 != 0) { From 5c8d9a2de146aeba9307d54fcc92d170bfb13a3d Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:48:25 +1100 Subject: [PATCH 18/60] Update button.h --- Friend/firmware/firmware_v1.0/src/button.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.h b/Friend/firmware/firmware_v1.0/src/button.h index 31dcf0fd3..5dfb10123 100644 --- a/Friend/firmware/firmware_v1.0/src/button.h +++ b/Friend/firmware/firmware_v1.0/src/button.h @@ -1,8 +1,16 @@ #ifndef BUTTON_H #define BUTTON_H +// Button states +#define DEFAULT_STATE 0 +#define SINGLE_TAP 1 // Quick press and release +#define DOUBLE_TAP 2 // Two quick presses - Currently used for voice interaction +#define LONG_TAP 3 // Long press - Currently used for sleep/wake +#define BUTTON_PRESS 4 // Button down event +#define BUTTON_RELEASE 5 // Button up event + typedef enum { - IDLE, + IDLE, ONE_PRESS, TWO_PRESS, GRACE @@ -11,11 +19,6 @@ typedef enum { int button_init(); void activate_button_work(); void register_button_service(); - FSM_STATE_T get_current_button_state(); -// Voice interaction declarations -extern void start_voice_interaction(void); -extern void stop_voice_interaction(void); -extern bool voice_interaction_active; -#endif \ No newline at end of file +#endif#endif From 087f194a43978ec8eb348b0665c56f30fb9786d2 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:48:29 +1100 Subject: [PATCH 19/60] Update button.h --- Friend/firmware/firmware_v1.0/src/button.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.h b/Friend/firmware/firmware_v1.0/src/button.h index 5dfb10123..3f3c0398c 100644 --- a/Friend/firmware/firmware_v1.0/src/button.h +++ b/Friend/firmware/firmware_v1.0/src/button.h @@ -21,4 +21,4 @@ void activate_button_work(); void register_button_service(); FSM_STATE_T get_current_button_state(); -#endif#endif +#endif From 66ad8cd3473d4060746689a33e46622d0a36b76b Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:48:42 +1100 Subject: [PATCH 20/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index 9b379f19c..bbdb3958a 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -45,6 +45,10 @@ static ssize_t audio_codec_read_characteristic(struct bt_conn *conn, const struc static void dfu_ccc_config_changed_handler(const struct bt_gatt_attr *attr, uint16_t value); static ssize_t dfu_control_point_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 voice_interaction_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 const char *phy2str(uint8_t phy); + + // // Service and Characteristic // From 2c726d96e88b595ef265977e141897a9960de54a Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:49:04 +1100 Subject: [PATCH 21/60] Update transport.h --- Friend/firmware/firmware_v1.0/src/transport.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.h b/Friend/firmware/firmware_v1.0/src/transport.h index 5f54089e7..2f61d4fed 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.h +++ b/Friend/firmware/firmware_v1.0/src/transport.h @@ -1,6 +1,7 @@ #ifndef TRANSPORT_H #define TRANSPORT_H +#include // For uint8_t, size_t #include typedef struct sensors { @@ -20,7 +21,13 @@ typedef struct sensors { * @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(); +int broadcast_audio_packets(uint8_t *buffer, size_t size); + +// Voice interaction function prototypes and variable +void start_voice_interaction(void); +void stop_voice_interaction(void); +extern bool voice_interaction_active; + int bt_on(); -#endif \ No newline at end of file +#endif From 5d91948ba1700ded60b0e3daf7ac50b578a8c9c6 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:55:12 +1100 Subject: [PATCH 22/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index bbdb3958a..1cb9eb8b5 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -558,7 +558,6 @@ static bool push_to_gatt(struct bt_conn *conn) #define OPUS_PADDED_LENGTH 80 #define MAX_WRITE_SIZE 440 static uint8_t storage_temp_data[MAX_WRITE_SIZE]; -static uint32_t offset = 0; static uint16_t buffer_offset = 0; // bool write_to_storage(void) // { From e39c39e90db6bbb4d9eb16255fe34f2325526a83 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:55:21 +1100 Subject: [PATCH 23/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index 1cb9eb8b5..0f7356873 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -626,10 +626,8 @@ bool write_to_storage(void) {//max possible packing } extern bool is_off; -static bool use_storage = true; #define MAX_FILES 10 #define MAX_AUDIO_FILE_SIZE 300000 -static int recent_file_size_updated = 0; void update_file_size() { From b39bd78a81e493c7f622f3dad672d010b054a1f9 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:55:25 +1100 Subject: [PATCH 24/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index 0f7356873..2f43e5916 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -853,7 +853,7 @@ static ssize_t voice_interaction_write_handler(struct bt_conn *conn, return len; } -static bool voice_interaction_active = false; +bool voice_interaction_active = false; void start_voice_interaction() { if (!is_off) { // Only start if device is awake From 34b9f562eb0f1e0eb2203b1d62f0b116613d79eb Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 Nov 2024 23:55:44 +1100 Subject: [PATCH 25/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index ed0ed41b2..caee61d22 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -428,7 +428,3 @@ FSM_STATE_T get_current_button_state() { return current_button_state; } - -extern void start_voice_interaction(void); -extern void stop_voice_interaction(void); -extern bool voice_interaction_active; From 073d6b69ef9e432034343695d03aaaa2245723a0 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:13:15 +1100 Subject: [PATCH 26/60] Create talk_audio_on_friend.py --- .../firmware/testing/talk_audio_on_friend.py | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 Friend/firmware/testing/talk_audio_on_friend.py diff --git a/Friend/firmware/testing/talk_audio_on_friend.py b/Friend/firmware/testing/talk_audio_on_friend.py new file mode 100644 index 000000000..dc2b0423c --- /dev/null +++ b/Friend/firmware/testing/talk_audio_on_friend.py @@ -0,0 +1,156 @@ +import asyncio +import bleak +import wave +import numpy as np +from bleak import BleakClient +from deepgram import DeepgramClient, SpeakOptions +import os +from dotenv import load_dotenv + +load_dotenv() + +# Configuration +DEVICE_ID = "817D48F6-FAF0-A566-D013-D05916B5D7B8" # Your device ID +DEEPGRAM_API_KEY = "f2e9ebf2f223ae423c88bf601ce1a157699d3005" # Your Deepgram API key +BUTTON_READ_UUID = "23BA7925-0000-1000-7450-346EAC492E92" # Button characteristic + +# Updated UUIDs to match firmware +VOICE_INTERACTION_UUID = "19B10004-E8F2-537E-4F6C-D104768A1214" # Voice data characteristic for sending audio to cloud +VOICE_INTERACTION_RX_UUID = "19B10005-E8F2-537E-4F6C-D104768A1214" # Voice response characteristic for receiving TTS audio + +# Button states +SINGLE_TAP = 1 +DOUBLE_TAP = 2 +LONG_TAP = 3 +BUTTON_PRESS = 4 +BUTTON_RELEASE = 5 + +# Audio settings +MAX_ALLOWED_SAMPLES = 50000 +GAIN = 5 +PACKET_SIZE = 400 + +class VoiceInteractionClient: + def __init__(self): + self.audio_data = bytearray() + self.is_recording = False + self.deepgram = DeepgramClient(api_key=DEEPGRAM_API_KEY) + self.remaining_bytes = 0 + self.total_offset = 0 + + async def connect(self): + self.client = BleakClient(DEVICE_ID) + await self.client.connect() + print(f"Connected to {self.client.address}") + + # Print services and characteristics for debugging + for service in self.client.services: + print(f"Service: {service.uuid}") + for char in service.characteristics: + print(f" Characteristic: {char.uuid}") + print(f" Properties: {char.properties}") + + async def setup_notifications(self): + # Button notifications + await self.client.start_notify(BUTTON_READ_UUID, self.on_button_change) + # Voice data notifications + await self.client.start_notify(VOICE_INTERACTION_UUID, self.on_voice_data) + print("Notifications set up") + + def on_button_change(self, sender, data): + button_state = int.from_bytes(data, byteorder='little') + print(f"Button state: {button_state}") + + if button_state == DOUBLE_TAP: + print("Starting voice recording...") + self.is_recording = True + self.audio_data = bytearray() + elif button_state == BUTTON_RELEASE and self.is_recording: + print("Stopping voice recording...") + self.is_recording = False + asyncio.create_task(self.process_voice_command()) + + def on_voice_data(self, sender, data): + if self.is_recording: + self.audio_data.extend(data[3:]) # Skip header bytes + print(f"Received {len(data)} bytes of audio data") + + async def process_voice_command(self): + if len(self.audio_data) == 0: + print("No audio data recorded") + return + + # Save audio data to temporary WAV file + with wave.open('temp_input.wav', 'wb') as wav_file: + wav_file.setnchannels(1) + wav_file.setsampwidth(2) + wav_file.setframerate(8000) + wav_file.writeframes(self.audio_data) + + # Process with Deepgram + try: + # First, convert audio to text + # TODO: Add Deepgram STT here + text_prompt = "This is a test response" # Replace with actual STT result + print(f"Processing voice command: {text_prompt}") + + # Generate response audio + options = SpeakOptions( + model="aura-stella-en", + encoding="linear16", + container="wav" + ) + + print("Generating audio response...") + response = self.deepgram.speak.v("1").save("temp_output.wav", + {"text": f"You said: {text_prompt}"}, + options) + + # Process and send the audio response + print("Sending audio response...") + await self.send_audio_response("temp_output.wav") + + except Exception as e: + print(f"Error processing voice command: {e}") + + async def send_audio_response(self, filename): + # Read and process the audio file + with wave.open(filename, 'rb') as wav_file: + frames = wav_file.readframes(wav_file.getnframes()) + audio_data = np.frombuffer(frames, dtype=np.int16) + + # Downsample to 8kHz + third_samples = audio_data[::3] * GAIN + audio_bytes = third_samples.tobytes() + + # Send size first + size_bytes = len(audio_bytes).to_bytes(4, byteorder='little') + print(f"Sending audio size: {len(audio_bytes)} bytes") + await self.client.write_gatt_char(VOICE_INTERACTION_RX_UUID, size_bytes) + await asyncio.sleep(0.1) + + # Send audio data in chunks + for i in range(0, len(audio_bytes), PACKET_SIZE): + chunk = audio_bytes[i:i + PACKET_SIZE] + await self.client.write_gatt_char(VOICE_INTERACTION_RX_UUID, chunk) + print(f"Sent chunk of {len(chunk)} bytes") + await asyncio.sleep(0.01) + + async def run(self): + try: + await self.connect() + await self.setup_notifications() + print("Ready for voice interaction. Double-tap to start recording.") + while True: + await asyncio.sleep(1) + except Exception as e: + print(f"Error: {e}") + finally: + await self.client.disconnect() + +async def main(): + client = VoiceInteractionClient() + await client.run() + +if __name__ == "__main__": + asyncio.run(main()) From 3377663bca8249e50d3db2366a1873b9adb8cafd Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:13:19 +1100 Subject: [PATCH 27/60] Update discover_devices.py --- Friend/firmware/testing/discover_devices.py | 87 ++++++++++++++++++++- 1 file changed, 83 insertions(+), 4 deletions(-) diff --git a/Friend/firmware/testing/discover_devices.py b/Friend/firmware/testing/discover_devices.py index b78cbf582..7c8c9830f 100644 --- a/Friend/firmware/testing/discover_devices.py +++ b/Friend/firmware/testing/discover_devices.py @@ -1,9 +1,88 @@ import asyncio from bleak import BleakScanner +from typing import Optional +import logging + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +FRIEND_NAME = "Friend" +FRIEND_SERVICE_UUID = "19B10000-E8F2-537E-4F6C-D104768A1214" # Audio service UUID from transport.c + +async def find_friend_device(timeout: int = 5) -> Optional[str]: + """ + Specifically scan for Friend devices. + Returns the address of the first Friend device found or None. + """ + logger.info(f"Scanning for {FRIEND_NAME} devices...") + + try: + devices = await BleakScanner.discover( + timeout=timeout, + return_adv=True, + service_uuids=[FRIEND_SERVICE_UUID] + ) + + for d, adv_data in devices.values(): + logger.debug(f"Found device: {d.name} ({d.address})") + + if d.name and FRIEND_NAME in d.name: + logger.info(f"Found {FRIEND_NAME} device!") + logger.info(f"Name: {d.name}") + logger.info(f"Address: {d.address}") + logger.info(f"RSSI: {d.rssi}dBm") + logger.info(f"Metadata: {adv_data}") + return d.address + + logger.warning(f"No {FRIEND_NAME} devices found") + return None + + except Exception as e: + logger.error(f"Error during device discovery: {e}") + return None + +async def scan_all_devices(timeout: int = 5): + """Scan and display all available BLE devices""" + logger.info("Scanning for all BLE devices...") + + try: + devices = await BleakScanner.discover(timeout=timeout) + + if not devices: + logger.info("No BLE devices found") + return + + logger.info("\nDiscovered devices:") + for d in devices: + logger.info(f"Name: {d.name or 'Unknown'}") + logger.info(f"Address: {d.address}") + logger.info(f"RSSI: {d.rssi}dBm") + logger.info(f"Metadata: {d.metadata}") + logger.info("-" * 40) + + except Exception as e: + logger.error(f"Error during device discovery: {e}") async def main(): - devices = await BleakScanner.discover() - for d in devices: - print(d) + """Main function with menu for different scanning options""" + while True: + print("\nBLE Scanner Menu:") + print("1. Find Friend device") + print("2. Scan all BLE devices") + print("3. Exit") + + choice = input("Select an option (1-3): ") + + if choice == "1": + await find_friend_device() + elif choice == "2": + await scan_all_devices() + elif choice == "3": + print("Exiting...") + break + else: + print("Invalid choice. Please select 1-3") -asyncio.run(main()) \ No newline at end of file +if __name__ == "__main__": + asyncio.run(main()) From fd0be4aa6a1775421c64c973f9e6bff8f0393014 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:13:43 +1100 Subject: [PATCH 28/60] Update discover_devices.py --- Friend/firmware/testing/discover_devices.py | 37 ++++++++++++--------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/Friend/firmware/testing/discover_devices.py b/Friend/firmware/testing/discover_devices.py index 7c8c9830f..cdc294edc 100644 --- a/Friend/firmware/testing/discover_devices.py +++ b/Friend/firmware/testing/discover_devices.py @@ -3,18 +3,14 @@ from typing import Optional import logging -# Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) FRIEND_NAME = "Friend" -FRIEND_SERVICE_UUID = "19B10000-E8F2-537E-4F6C-D104768A1214" # Audio service UUID from transport.c +FRIEND_SERVICE_UUID = "19B10000-E8F2-537E-4F6C-D104768A1214" async def find_friend_device(timeout: int = 5) -> Optional[str]: - """ - Specifically scan for Friend devices. - Returns the address of the first Friend device found or None. - """ + """Specifically scan for Friend devices.""" logger.info(f"Scanning for {FRIEND_NAME} devices...") try: @@ -28,11 +24,15 @@ async def find_friend_device(timeout: int = 5) -> Optional[str]: logger.debug(f"Found device: {d.name} ({d.address})") if d.name and FRIEND_NAME in d.name: - logger.info(f"Found {FRIEND_NAME} device!") + logger.info("\nFound Friend Device!") + logger.info("─" * 40) logger.info(f"Name: {d.name}") logger.info(f"Address: {d.address}") - logger.info(f"RSSI: {d.rssi}dBm") - logger.info(f"Metadata: {adv_data}") + logger.info(f"RSSI: {adv_data.rssi}dBm") + logger.info("\nServices:") + for uuid in adv_data.service_uuids: + logger.info(f" • {uuid}") + logger.info("─" * 40) return d.address logger.warning(f"No {FRIEND_NAME} devices found") @@ -47,19 +47,26 @@ async def scan_all_devices(timeout: int = 5): logger.info("Scanning for all BLE devices...") try: - devices = await BleakScanner.discover(timeout=timeout) + devices = await BleakScanner.discover( + timeout=timeout, + return_adv=True + ) if not devices: logger.info("No BLE devices found") return - logger.info("\nDiscovered devices:") - for d in devices: + logger.info("\nDiscovered Devices:") + for d, adv_data in devices.values(): + logger.info("─" * 40) logger.info(f"Name: {d.name or 'Unknown'}") logger.info(f"Address: {d.address}") - logger.info(f"RSSI: {d.rssi}dBm") - logger.info(f"Metadata: {d.metadata}") - logger.info("-" * 40) + logger.info(f"RSSI: {adv_data.rssi}dBm") + if adv_data.service_uuids: + logger.info("\nServices:") + for uuid in adv_data.service_uuids: + logger.info(f" • {uuid}") + logger.info("─" * 40) except Exception as e: logger.error(f"Error during device discovery: {e}") From 5f0dd656c05d5081a7eea0be367e02d44055ceb0 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:17:59 +1100 Subject: [PATCH 29/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index 2f43e5916..d76f12470 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -848,8 +848,9 @@ static ssize_t voice_interaction_write_handler(struct bt_conn *conn, uint16_t len, uint16_t offset, uint8_t flags) { - // Handle incoming audio data for voice response using streaming - speak_stream(len, buf); + if (!is_off) { + speak_stream(len, buf); + } return len; } From ee0e05b98689c22d3a0ef36a07d885ceac26d486 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:18:03 +1100 Subject: [PATCH 30/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index d76f12470..07ee378d6 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -866,7 +866,7 @@ void start_voice_interaction() { } } -void stop_voice_interaction() { +void stop_voice_interaction(void) { if (voice_interaction_active) { voice_interaction_active = false; LOG_INF("Voice interaction stopped"); From 5b9fe67b062adcdb546bbbd73f39db9ce4920728 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:18:06 +1100 Subject: [PATCH 31/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index 07ee378d6..1dc16c5dd 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -856,8 +856,8 @@ static ssize_t voice_interaction_write_handler(struct bt_conn *conn, bool voice_interaction_active = false; -void start_voice_interaction() { - if (!is_off) { // Only start if device is awake +void start_voice_interaction(void) { + if (!is_off) { voice_interaction_active = true; LOG_INF("Voice interaction started"); From 7adea660f713fa00f8a48c9bee081d3fed1d7563 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:31:09 +1100 Subject: [PATCH 32/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index caee61d22..1ad6cb0e2 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -115,6 +115,11 @@ static inline void notify_unpress() { bt_gatt_notify(conn, &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); } + + // If we were recording, stop + if (voice_interaction_active) { + stop_voice_interaction(); + } } static inline void notify_tap() From 168577550765928b0a0b6c8c90e99f6b11ad0252 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:31:13 +1100 Subject: [PATCH 33/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 1ad6cb0e2..3f5a9b281 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -125,7 +125,7 @@ static inline void notify_unpress() static inline void notify_tap() { final_button_state[0] = SINGLE_TAP; - LOG_INF("tap"); + LOG_INF("single tap"); struct bt_conn *conn = get_current_connection(); if (conn != NULL) { From acd8243ff979975bc6b06e98881da6ec0a64ea1b Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:31:16 +1100 Subject: [PATCH 34/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 3f5a9b281..54fd9eddd 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -149,6 +149,10 @@ static inline void notify_double_tap() { // Play feedback sound play_haptic_milli(50); + + // Reset state + current_button_state = GRACE; + reset_count(); } } From 7193fd96db889845d63280be979797b2cce208b9 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:31:34 +1100 Subject: [PATCH 35/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 54fd9eddd..846fc1908 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -27,7 +27,13 @@ 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) +static inline void notify_tap(void); +static inline void notify_press(void); +static inline void notify_unpress(void); +static inline void notify_double_tap(void); +static inline void notify_long_tap(void); + +static void button_ccc_config_changed_handler(const struct bt_gatt_attr *attr, uint16_t value) { if (value == BT_GATT_CCC_NOTIFY) { From 123833b93da7c062ed5a0ab1f8ad2326526ec410 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:31:52 +1100 Subject: [PATCH 36/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index 1dc16c5dd..a9964a5e2 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -107,6 +107,15 @@ 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 // +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 From 32eeef257743a838c6cdd0cad46a0e8279e8d373 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:32:13 +1100 Subject: [PATCH 37/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index a9964a5e2..81166142b 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -869,8 +869,6 @@ void start_voice_interaction(void) { if (!is_off) { voice_interaction_active = true; LOG_INF("Voice interaction started"); - - // Optional: Play feedback sound play_haptic_milli(50); } } @@ -879,8 +877,6 @@ void stop_voice_interaction(void) { if (voice_interaction_active) { voice_interaction_active = false; LOG_INF("Voice interaction stopped"); - - // Optional: Play feedback sound play_haptic_milli(25); } } From 459b8e0a67523ce9854ddc38d42336ad200c767c Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:33:14 +1100 Subject: [PATCH 38/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index 81166142b..da4b3954c 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -68,12 +68,29 @@ static struct bt_uuid_128 voice_interaction_rx_uuid = BT_UUID_INIT_128(BT_UUID_1 static struct bt_gatt_attr audio_service_attr[] = { BT_GATT_PRIMARY_SERVICE(&audio_service_uuid), - 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), + 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), // + 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 BT_GATT_CHARACTERISTIC(&voice_interaction_uuid.uuid, From 5858e75de61deeee4b66915092f6cd56408debff Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:33:36 +1100 Subject: [PATCH 39/60] Update transport.h --- Friend/firmware/firmware_v1.0/src/transport.h | 32 +++++-------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.h b/Friend/firmware/firmware_v1.0/src/transport.h index 2f61d4fed..d942dcf53 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.h +++ b/Friend/firmware/firmware_v1.0/src/transport.h @@ -1,33 +1,17 @@ #ifndef TRANSPORT_H #define TRANSPORT_H -#include // For uint8_t, size_t -#include -typedef struct sensors { +#include - 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(); -struct bt_conn *get_current_connection(); -int broadcast_audio_packets(uint8_t *buffer, size_t size); - -// Voice interaction function prototypes and variable +// Voice interaction functions void start_voice_interaction(void); void stop_voice_interaction(void); extern bool voice_interaction_active; -int bt_on(); +// Other functions +int transport_start(void); +struct bt_conn *get_current_connection(void); +int broadcast_audio_packets(uint8_t *buffer, size_t size); +int bt_on(void); + #endif From f4ddee595a96254ef445dd5157cdfa240b781e78 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:34:08 +1100 Subject: [PATCH 40/60] Update talk_audio_on_friend.py --- .../firmware/testing/talk_audio_on_friend.py | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/Friend/firmware/testing/talk_audio_on_friend.py b/Friend/firmware/testing/talk_audio_on_friend.py index dc2b0423c..13e99c6ac 100644 --- a/Friend/firmware/testing/talk_audio_on_friend.py +++ b/Friend/firmware/testing/talk_audio_on_friend.py @@ -35,8 +35,6 @@ def __init__(self): self.audio_data = bytearray() self.is_recording = False self.deepgram = DeepgramClient(api_key=DEEPGRAM_API_KEY) - self.remaining_bytes = 0 - self.total_offset = 0 async def connect(self): self.client = BleakClient(DEVICE_ID) @@ -51,11 +49,17 @@ async def connect(self): print(f" Properties: {char.properties}") async def setup_notifications(self): - # Button notifications - await self.client.start_notify(BUTTON_READ_UUID, self.on_button_change) - # Voice data notifications - await self.client.start_notify(VOICE_INTERACTION_UUID, self.on_voice_data) - print("Notifications set up") + try: + # Button notifications + await self.client.start_notify(BUTTON_READ_UUID, self.on_button_change) + print("Button notifications set up") + + # Voice data notifications + await self.client.start_notify(VOICE_INTERACTION_UUID, self.on_voice_data) + print("Voice notifications set up") + + except Exception as e: + print(f"Error setting up notifications: {e}") def on_button_change(self, sender, data): button_state = int.from_bytes(data, byteorder='little') @@ -72,7 +76,8 @@ def on_button_change(self, sender, data): def on_voice_data(self, sender, data): if self.is_recording: - self.audio_data.extend(data[3:]) # Skip header bytes + # Skip the first 3 bytes (header) + self.audio_data.extend(data[3:]) print(f"Received {len(data)} bytes of audio data") async def process_voice_command(self): @@ -113,29 +118,23 @@ async def process_voice_command(self): except Exception as e: print(f"Error processing voice command: {e}") - async def send_audio_response(self, filename): - # Read and process the audio file - with wave.open(filename, 'rb') as wav_file: - frames = wav_file.readframes(wav_file.getnframes()) - audio_data = np.frombuffer(frames, dtype=np.int16) - - # Downsample to 8kHz - third_samples = audio_data[::3] * GAIN - audio_bytes = third_samples.tobytes() - + async def send_audio_response(self, audio_bytes): + try: # Send size first size_bytes = len(audio_bytes).to_bytes(4, byteorder='little') - print(f"Sending audio size: {len(audio_bytes)} bytes") - await self.client.write_gatt_char(VOICE_INTERACTION_RX_UUID, size_bytes) + await self.client.write_gatt_char(VOICE_INTERACTION_RX_UUID, size_bytes, response=True) await asyncio.sleep(0.1) # Send audio data in chunks for i in range(0, len(audio_bytes), PACKET_SIZE): chunk = audio_bytes[i:i + PACKET_SIZE] - await self.client.write_gatt_char(VOICE_INTERACTION_RX_UUID, chunk) + await self.client.write_gatt_char(VOICE_INTERACTION_RX_UUID, chunk, response=True) print(f"Sent chunk of {len(chunk)} bytes") await asyncio.sleep(0.01) + except Exception as e: + print(f"Error sending audio response: {e}") + async def run(self): try: await self.connect() From c70d2f3ce3a08762af62e3e6c0e3ee024e11c459 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:34:38 +1100 Subject: [PATCH 41/60] Update speaker.c --- Friend/firmware/firmware_v1.0/src/speaker.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/speaker.c b/Friend/firmware/firmware_v1.0/src/speaker.c index 1a7d3fd13..bd515d72b 100644 --- a/Friend/firmware/firmware_v1.0/src/speaker.c +++ b/Friend/firmware/firmware_v1.0/src/speaker.c @@ -173,7 +173,12 @@ uint16_t speak_stream(uint16_t len, const void *buf) { // Handle streaming audio if (stream_buffer_pos + len > STREAM_BUFFER_SIZE) { // Buffer full - play what we have - i2s_write(audio_speaker, stream_buffer, stream_buffer_pos); + int res = i2s_write(audio_speaker, stream_buffer, stream_buffer_pos); + if (res < 0) { + LOG_ERR("Failed to write stream data: %d", res); + } + i2s_trigger(audio_speaker, I2S_DIR_TX, I2S_TRIGGER_START); + i2s_trigger(audio_speaker, I2S_DIR_TX, I2S_TRIGGER_DRAIN); stream_buffer_pos = 0; } @@ -183,7 +188,12 @@ uint16_t speak_stream(uint16_t len, const void *buf) { // If we have enough data or this is the end, play it if (stream_buffer_pos >= 1024 || len < 400) { - i2s_write(audio_speaker, stream_buffer, stream_buffer_pos); + int res = i2s_write(audio_speaker, stream_buffer, stream_buffer_pos); + if (res < 0) { + LOG_ERR("Failed to write stream data: %d", res); + } + i2s_trigger(audio_speaker, I2S_DIR_TX, I2S_TRIGGER_START); + i2s_trigger(audio_speaker, I2S_DIR_TX, I2S_TRIGGER_DRAIN); stream_buffer_pos = 0; } From bbf044f11afad0fc3e6f0bd514a82d1b0343a33c Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:34:57 +1100 Subject: [PATCH 42/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index da4b3954c..e5b75eeee 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -875,6 +875,7 @@ static ssize_t voice_interaction_write_handler(struct bt_conn *conn, uint16_t offset, uint8_t flags) { if (!is_off) { + LOG_INF("Received voice response data: %d bytes", len); speak_stream(len, buf); } return len; @@ -887,6 +888,10 @@ void start_voice_interaction(void) { voice_interaction_active = true; LOG_INF("Voice interaction started"); play_haptic_milli(50); + + // Reset stream buffer + stream_buffer_pos = 0; + memset(stream_buffer, 0, STREAM_BUFFER_SIZE); } } @@ -895,6 +900,10 @@ void stop_voice_interaction(void) { voice_interaction_active = false; LOG_INF("Voice interaction stopped"); play_haptic_milli(25); + + // Clear stream buffer + stream_buffer_pos = 0; + memset(stream_buffer, 0, STREAM_BUFFER_SIZE); } } From af21c3341c37c37c9b6ceb2a05b617fbd0a5dc1b Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:39:11 +1100 Subject: [PATCH 43/60] Update talk_audio_on_friend.py --- .../firmware/testing/talk_audio_on_friend.py | 85 ++++++++++++------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/Friend/firmware/testing/talk_audio_on_friend.py b/Friend/firmware/testing/talk_audio_on_friend.py index 13e99c6ac..056c7c458 100644 --- a/Friend/firmware/testing/talk_audio_on_friend.py +++ b/Friend/firmware/testing/talk_audio_on_friend.py @@ -35,18 +35,33 @@ def __init__(self): self.audio_data = bytearray() self.is_recording = False self.deepgram = DeepgramClient(api_key=DEEPGRAM_API_KEY) + self.client = None + self.is_connected = False async def connect(self): - self.client = BleakClient(DEVICE_ID) - await self.client.connect() - print(f"Connected to {self.client.address}") - - # Print services and characteristics for debugging - for service in self.client.services: - print(f"Service: {service.uuid}") - for char in service.characteristics: - print(f" Characteristic: {char.uuid}") - print(f" Properties: {char.properties}") + while True: + try: + if not self.is_connected: + print("Attempting to connect...") + self.client = BleakClient(DEVICE_ID, disconnected_callback=self.handle_disconnect) + await self.client.connect() + self.is_connected = True + print(f"Connected to {self.client.address}") + await self.setup_notifications() + print("Ready for voice interaction. Double-tap to start recording.") + return + except Exception as e: + print(f"Connection failed: {e}") + await asyncio.sleep(5) # Wait before retrying + + def handle_disconnect(self, client): + print("Device disconnected!") + self.is_connected = False + asyncio.create_task(self.reconnect()) + + async def reconnect(self): + print("Attempting to reconnect...") + await self.connect() async def setup_notifications(self): try: @@ -118,34 +133,46 @@ async def process_voice_command(self): except Exception as e: print(f"Error processing voice command: {e}") - async def send_audio_response(self, audio_bytes): - try: - # Send size first - size_bytes = len(audio_bytes).to_bytes(4, byteorder='little') - await self.client.write_gatt_char(VOICE_INTERACTION_RX_UUID, size_bytes, response=True) - await asyncio.sleep(0.1) - - # Send audio data in chunks - for i in range(0, len(audio_bytes), PACKET_SIZE): - chunk = audio_bytes[i:i + PACKET_SIZE] - await self.client.write_gatt_char(VOICE_INTERACTION_RX_UUID, chunk, response=True) - print(f"Sent chunk of {len(chunk)} bytes") - await asyncio.sleep(0.01) - - except Exception as e: - print(f"Error sending audio response: {e}") + async def send_audio_response(self, filename): + # Read and process the audio file + with wave.open(filename, 'rb') as wav_file: + frames = wav_file.readframes(wav_file.getnframes()) + audio_data = np.frombuffer(frames, dtype=np.int16) + + # Downsample to 8kHz + third_samples = audio_data[::3] * GAIN + audio_bytes = third_samples.tobytes() + + try: + # Send size first + size_bytes = len(audio_bytes).to_bytes(4, byteorder='little') + await self.client.write_gatt_char(VOICE_INTERACTION_RX_UUID, size_bytes, response=True) + await asyncio.sleep(0.1) + + # Send audio data in chunks + for i in range(0, len(audio_bytes), PACKET_SIZE): + chunk = audio_bytes[i:i + PACKET_SIZE] + await self.client.write_gatt_char(VOICE_INTERACTION_RX_UUID, chunk, response=True) + print(f"Sent chunk of {len(chunk)} bytes") + await asyncio.sleep(0.01) + + except Exception as e: + print(f"Error sending audio response: {e}") + if not self.is_connected: + await self.reconnect() async def run(self): try: await self.connect() - await self.setup_notifications() - print("Ready for voice interaction. Double-tap to start recording.") while True: + if not self.is_connected: + await self.connect() await asyncio.sleep(1) except Exception as e: print(f"Error: {e}") finally: - await self.client.disconnect() + if self.client and self.client.is_connected: + await self.client.disconnect() async def main(): client = VoiceInteractionClient() From a90704d601ceef5f1f704c681ecc2c69cbbb8d35 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:39:27 +1100 Subject: [PATCH 44/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index e5b75eeee..1036cdc7b 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -23,6 +23,10 @@ // #include "friend.h" LOG_MODULE_REGISTER(transport, CONFIG_LOG_DEFAULT_LEVEL); +#define STREAM_BUFFER_SIZE 8192 +static uint8_t stream_buffer[STREAM_BUFFER_SIZE]; +static size_t stream_buffer_pos = 0; + extern bool is_connected; extern bool storage_is_on; extern uint8_t file_count; From 882a429520c25eba5f250d55bd7d569a874ae89e Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:43:32 +1100 Subject: [PATCH 45/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index 1036cdc7b..c5e42de29 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -859,10 +859,13 @@ int broadcast_audio_packets(uint8_t *buffer, size_t size) // Send through voice interaction characteristic struct bt_conn *conn = get_current_connection(); if (conn) { - int index = 6; // Index of voice interaction characteristic - bt_gatt_notify(conn, &audio_service.attrs[index], buffer, size); + int err = bt_gatt_notify(conn, &audio_service.attrs[6], buffer, size); + if (err) { + LOG_ERR("Failed to send voice data: %d", err); + } + return err; } - return 0; + return -ENOTCONN; } // Normal audio handling @@ -880,7 +883,15 @@ static ssize_t voice_interaction_write_handler(struct bt_conn *conn, uint8_t flags) { if (!is_off) { LOG_INF("Received voice response data: %d bytes", len); - speak_stream(len, buf); + if (len == 4) { + // This is the size packet + uint32_t size = *((uint32_t *)buf); + LOG_INF("Expected voice response size: %d bytes", size); + return len; + } + + // Process audio data + return speak_stream(len, buf); } return len; } From 827934fbd2601b6eaf7924ebe80035f961cbc10c Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:47:56 +1100 Subject: [PATCH 46/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index c5e42de29..a1b30e2bc 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -852,11 +852,12 @@ struct bt_conn *get_current_connection() int broadcast_audio_packets(uint8_t *buffer, size_t size) { if (is_off) { - return -EPERM; // Device is sleeping + LOG_WRN("Device is off, cannot broadcast audio"); + return -EPERM; } if (voice_interaction_active) { - // Send through voice interaction characteristic + LOG_DBG("Broadcasting voice interaction data: %d bytes", size); struct bt_conn *conn = get_current_connection(); if (conn) { int err = bt_gatt_notify(conn, &audio_service.attrs[6], buffer, size); @@ -865,10 +866,12 @@ int broadcast_audio_packets(uint8_t *buffer, size_t size) } return err; } + LOG_WRN("No connection available for voice data"); return -ENOTCONN; } // Normal audio handling + LOG_DBG("Broadcasting normal audio data: %d bytes", size); while (!write_to_tx_queue(buffer, size)) { k_sleep(K_MSEC(1)); } @@ -891,8 +894,12 @@ static ssize_t voice_interaction_write_handler(struct bt_conn *conn, } // Process audio data - return speak_stream(len, buf); + LOG_INF("Processing audio chunk of %d bytes", len); + uint16_t result = speak_stream(len, buf); + LOG_INF("Processed %d bytes", result); + return result; } + LOG_WRN("Device is off, ignoring voice data"); return len; } @@ -900,25 +907,29 @@ bool voice_interaction_active = false; void start_voice_interaction(void) { if (!is_off) { + LOG_INF("Starting voice interaction"); voice_interaction_active = true; - LOG_INF("Voice interaction started"); play_haptic_milli(50); // Reset stream buffer stream_buffer_pos = 0; memset(stream_buffer, 0, STREAM_BUFFER_SIZE); + LOG_INF("Voice interaction started, buffers cleared"); + } else { + LOG_WRN("Cannot start voice interaction while device is off"); } } void stop_voice_interaction(void) { + LOG_INF("Stopping voice interaction (active=%d)", voice_interaction_active); if (voice_interaction_active) { voice_interaction_active = false; - LOG_INF("Voice interaction stopped"); play_haptic_milli(25); // Clear stream buffer stream_buffer_pos = 0; memset(stream_buffer, 0, STREAM_BUFFER_SIZE); + LOG_INF("Voice interaction stopped, buffers cleared"); } } From c848140aec84e88e1cba2dc786e9cf54dcf3035a Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:48:22 +1100 Subject: [PATCH 47/60] Update speaker.c --- Friend/firmware/firmware_v1.0/src/speaker.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/speaker.c b/Friend/firmware/firmware_v1.0/src/speaker.c index bd515d72b..a21ea998e 100644 --- a/Friend/firmware/firmware_v1.0/src/speaker.c +++ b/Friend/firmware/firmware_v1.0/src/speaker.c @@ -163,16 +163,17 @@ uint16_t speak(uint16_t len, const void *buf) //direct from bt // Add new function for streaming audio uint16_t speak_stream(uint16_t len, const void *buf) { - // Don't process audio if device is sleeping if (is_off) { + LOG_WRN("Device is off, cannot play audio"); return 0; } uint16_t amount = len; + LOG_DBG("Processing stream data: %d bytes", len); // Handle streaming audio if (stream_buffer_pos + len > STREAM_BUFFER_SIZE) { - // Buffer full - play what we have + LOG_INF("Buffer full (%d bytes), playing current data", stream_buffer_pos); int res = i2s_write(audio_speaker, stream_buffer, stream_buffer_pos); if (res < 0) { LOG_ERR("Failed to write stream data: %d", res); @@ -183,11 +184,13 @@ uint16_t speak_stream(uint16_t len, const void *buf) { } // Add new data to buffer + LOG_DBG("Adding %d bytes to stream buffer at position %d", len, stream_buffer_pos); memcpy(stream_buffer + stream_buffer_pos, buf, len); stream_buffer_pos += len; // If we have enough data or this is the end, play it if (stream_buffer_pos >= 1024 || len < 400) { + LOG_INF("Playing %d bytes of audio data", stream_buffer_pos); int res = i2s_write(audio_speaker, stream_buffer, stream_buffer_pos); if (res < 0) { LOG_ERR("Failed to write stream data: %d", res); From 0693b22cb84e1d162e222929b85bf13db1cb9c6b Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 00:49:15 +1100 Subject: [PATCH 48/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 32 +++++++++++++--------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 846fc1908..3803be0c5 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -148,28 +148,32 @@ static inline void notify_double_tap() { 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)); - } - - // Start voice interaction mode - start_voice_interaction(); - // Play feedback sound - play_haptic_milli(50); + // Start voice interaction mode + start_voice_interaction(); - // Reset state - current_button_state = GRACE; - reset_count(); + // Play feedback sound + play_haptic_milli(50); + } else { + LOG_ERR("No connection available for voice interaction"); + } } + + // Reset state + current_button_state = GRACE; + reset_count(); } static inline void notify_long_tap() { - // If voice interaction is active, stop it first + // If voice interaction is active, stop it before sleep if (voice_interaction_active) { + LOG_INF("Stopping voice interaction before sleep"); stop_voice_interaction(); } final_button_state[0] = LONG_TAP; - LOG_INF("long tap"); + LOG_INF("long tap - toggling sleep mode"); + 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)); @@ -178,16 +182,18 @@ static inline void notify_long_tap() { // Handle sleep mode is_off = !is_off; play_haptic_milli(100); + if (is_off) { + LOG_INF("Entering sleep mode"); bt_disable(); int err = bt_le_adv_stop(); if (err) { - printk("Failed to stop Bluetooth %d\n",err); + LOG_ERR("Failed to stop Bluetooth %d", err); } } else { int err = bt_enable(NULL); if (err) { - printk("Failed to enable Bluetooth %d\n",err); + LOG_ERR("Failed to enable Bluetooth %d", err); } bt_on(); } From c00d916ef0f3b51d9efaa816ca7b5227d252d731 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 Nov 2024 08:43:15 +1100 Subject: [PATCH 49/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index a1b30e2bc..32a092ba2 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -885,22 +885,36 @@ static ssize_t voice_interaction_write_handler(struct bt_conn *conn, uint16_t offset, uint8_t flags) { if (!is_off) { - LOG_INF("Received voice response data: %d bytes", len); + LOG_INF("Voice write: %d bytes", len); + if (len == 4) { - // This is the size packet - uint32_t size = *((uint32_t *)buf); - LOG_INF("Expected voice response size: %d bytes", size); + // Size packet + uint32_t expected_size = *((uint32_t *)buf); + LOG_INF("Expected voice data size: %d", expected_size); return len; } - // Process audio data - LOG_INF("Processing audio chunk of %d bytes", len); - uint16_t result = speak_stream(len, buf); - LOG_INF("Processed %d bytes", result); - return result; + // Check buffer space + if (voice_buffer_pos + len > VOICE_BUFFER_SIZE) { + LOG_WRN("Voice buffer full, playing current data"); + speak_stream(voice_buffer_pos, voice_rx_buffer); + voice_buffer_pos = 0; + } + + // Add new data + memcpy(voice_rx_buffer + voice_buffer_pos, buf, len); + voice_buffer_pos += len; + + // If we have enough data or this is the end packet, play it + if (voice_buffer_pos >= 1024 || len < VOICE_PACKET_SIZE) { + LOG_INF("Playing voice data: %d bytes", voice_buffer_pos); + speak_stream(voice_buffer_pos, voice_rx_buffer); + voice_buffer_pos = 0; + } + + return len; } - LOG_WRN("Device is off, ignoring voice data"); - return len; + return 0; } bool voice_interaction_active = false; @@ -911,25 +925,21 @@ void start_voice_interaction(void) { voice_interaction_active = true; play_haptic_milli(50); - // Reset stream buffer - stream_buffer_pos = 0; - memset(stream_buffer, 0, STREAM_BUFFER_SIZE); - LOG_INF("Voice interaction started, buffers cleared"); - } else { - LOG_WRN("Cannot start voice interaction while device is off"); + // Reset buffer + voice_buffer_pos = 0; + memset(voice_rx_buffer, 0, VOICE_BUFFER_SIZE); } } void stop_voice_interaction(void) { - LOG_INF("Stopping voice interaction (active=%d)", voice_interaction_active); if (voice_interaction_active) { + LOG_INF("Stopping voice interaction"); voice_interaction_active = false; play_haptic_milli(25); - // Clear stream buffer - stream_buffer_pos = 0; - memset(stream_buffer, 0, STREAM_BUFFER_SIZE); - LOG_INF("Voice interaction stopped, buffers cleared"); + // Clear buffer + voice_buffer_pos = 0; + memset(voice_rx_buffer, 0, VOICE_BUFFER_SIZE); } } From 5e061f491977b59a16b26c69c4aea907789748ec Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 08:01:35 +1100 Subject: [PATCH 50/60] Revert "Update transport.c" This reverts commit c00d916ef0f3b51d9efaa816ca7b5227d252d731. --- Friend/firmware/firmware_v1.0/src/transport.c | 54 ++++++++----------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index 32a092ba2..a1b30e2bc 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -885,36 +885,22 @@ static ssize_t voice_interaction_write_handler(struct bt_conn *conn, uint16_t offset, uint8_t flags) { if (!is_off) { - LOG_INF("Voice write: %d bytes", len); - + LOG_INF("Received voice response data: %d bytes", len); if (len == 4) { - // Size packet - uint32_t expected_size = *((uint32_t *)buf); - LOG_INF("Expected voice data size: %d", expected_size); + // This is the size packet + uint32_t size = *((uint32_t *)buf); + LOG_INF("Expected voice response size: %d bytes", size); return len; } - // Check buffer space - if (voice_buffer_pos + len > VOICE_BUFFER_SIZE) { - LOG_WRN("Voice buffer full, playing current data"); - speak_stream(voice_buffer_pos, voice_rx_buffer); - voice_buffer_pos = 0; - } - - // Add new data - memcpy(voice_rx_buffer + voice_buffer_pos, buf, len); - voice_buffer_pos += len; - - // If we have enough data or this is the end packet, play it - if (voice_buffer_pos >= 1024 || len < VOICE_PACKET_SIZE) { - LOG_INF("Playing voice data: %d bytes", voice_buffer_pos); - speak_stream(voice_buffer_pos, voice_rx_buffer); - voice_buffer_pos = 0; - } - - return len; + // Process audio data + LOG_INF("Processing audio chunk of %d bytes", len); + uint16_t result = speak_stream(len, buf); + LOG_INF("Processed %d bytes", result); + return result; } - return 0; + LOG_WRN("Device is off, ignoring voice data"); + return len; } bool voice_interaction_active = false; @@ -925,21 +911,25 @@ void start_voice_interaction(void) { voice_interaction_active = true; play_haptic_milli(50); - // Reset buffer - voice_buffer_pos = 0; - memset(voice_rx_buffer, 0, VOICE_BUFFER_SIZE); + // Reset stream buffer + stream_buffer_pos = 0; + memset(stream_buffer, 0, STREAM_BUFFER_SIZE); + LOG_INF("Voice interaction started, buffers cleared"); + } else { + LOG_WRN("Cannot start voice interaction while device is off"); } } void stop_voice_interaction(void) { + LOG_INF("Stopping voice interaction (active=%d)", voice_interaction_active); if (voice_interaction_active) { - LOG_INF("Stopping voice interaction"); voice_interaction_active = false; play_haptic_milli(25); - // Clear buffer - voice_buffer_pos = 0; - memset(voice_rx_buffer, 0, VOICE_BUFFER_SIZE); + // Clear stream buffer + stream_buffer_pos = 0; + memset(stream_buffer, 0, STREAM_BUFFER_SIZE); + LOG_INF("Voice interaction stopped, buffers cleared"); } } From 1f3411409b214d5640e94c6a75004424c5b405f8 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 09:48:06 +1100 Subject: [PATCH 51/60] Update transport.h --- Friend/firmware/firmware_v1.0/src/transport.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.h b/Friend/firmware/firmware_v1.0/src/transport.h index d942dcf53..a64122889 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.h +++ b/Friend/firmware/firmware_v1.0/src/transport.h @@ -1,14 +1,19 @@ #ifndef TRANSPORT_H #define TRANSPORT_H -#include +#include +#include +#include // Voice interaction functions +extern bool voice_interaction_active; void start_voice_interaction(void); void stop_voice_interaction(void); -extern bool voice_interaction_active; -// Other functions +// Declare handle_voice_data as non-static +int handle_voice_data(uint8_t *data, size_t len); + +// Existing declarations... int transport_start(void); struct bt_conn *get_current_connection(void); int broadcast_audio_packets(uint8_t *buffer, size_t size); From c63f8399a07d06b7194ae09fca41852288e6fca6 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 09:48:13 +1100 Subject: [PATCH 52/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index a1b30e2bc..e9438b9e6 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -21,6 +21,9 @@ #include "button.h" #include "lib/battery/battery.h" // #include "friend.h" +#include "mic.h" +#include "codec.h" + LOG_MODULE_REGISTER(transport, CONFIG_LOG_DEFAULT_LEVEL); #define STREAM_BUFFER_SIZE 8192 From fe3586cc5f01146958c3b9e7addf6215cae70806 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 09:53:54 +1100 Subject: [PATCH 53/60] Update transport.c --- Friend/firmware/firmware_v1.0/src/transport.c | 115 +++++++++++++----- 1 file changed, 82 insertions(+), 33 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/transport.c b/Friend/firmware/firmware_v1.0/src/transport.c index e9438b9e6..1bccda20c 100644 --- a/Friend/firmware/firmware_v1.0/src/transport.c +++ b/Friend/firmware/firmware_v1.0/src/transport.c @@ -23,6 +23,7 @@ // #include "friend.h" #include "mic.h" #include "codec.h" +#include LOG_MODULE_REGISTER(transport, CONFIG_LOG_DEFAULT_LEVEL); @@ -854,25 +855,15 @@ struct bt_conn *get_current_connection() int broadcast_audio_packets(uint8_t *buffer, size_t size) { + if (voice_interaction_active) { + return handle_voice_data(buffer, size); + } + if (is_off) { LOG_WRN("Device is off, cannot broadcast audio"); return -EPERM; } - if (voice_interaction_active) { - LOG_DBG("Broadcasting voice interaction data: %d bytes", size); - struct bt_conn *conn = get_current_connection(); - if (conn) { - int err = bt_gatt_notify(conn, &audio_service.attrs[6], buffer, size); - if (err) { - LOG_ERR("Failed to send voice data: %d", err); - } - return err; - } - LOG_WRN("No connection available for voice data"); - return -ENOTCONN; - } - // Normal audio handling LOG_DBG("Broadcasting normal audio data: %d bytes", size); while (!write_to_tx_queue(buffer, size)) { @@ -908,32 +899,90 @@ static ssize_t voice_interaction_write_handler(struct bt_conn *conn, bool voice_interaction_active = false; +static atomic_t voice_state = ATOMIC_INIT(0); + void start_voice_interaction(void) { - if (!is_off) { - LOG_INF("Starting voice interaction"); - voice_interaction_active = true; - play_haptic_milli(50); - - // Reset stream buffer - stream_buffer_pos = 0; - memset(stream_buffer, 0, STREAM_BUFFER_SIZE); - LOG_INF("Voice interaction started, buffers cleared"); - } else { - LOG_WRN("Cannot start voice interaction while device is off"); + if (is_off || !current_connection) { + LOG_ERR("Cannot start voice interaction - device off or not connected"); + return; + } + + // Use atomic operation to prevent race conditions + if (!atomic_cas(&voice_state, 0, 1)) { + LOG_WRN("Voice interaction already active"); + return; + } + + LOG_INF("Starting voice interaction"); + + // Stop any ongoing audio processing + storage_is_on = false; + + // Clear buffers + ring_buf_reset(&ring_buf); + + // Configure mic first + int err = mic_configure_for_voice(); + if (err) { + LOG_ERR("Failed to configure mic: %d", err); + atomic_clear(&voice_state); + return; + } + + // Start mic last after everything is configured + voice_interaction_active = true; + err = mic_start(); + if (err) { + LOG_ERR("Failed to start mic: %d", err); + voice_interaction_active = false; + atomic_clear(&voice_state); + return; } + + LOG_INF("Voice interaction started successfully"); } void stop_voice_interaction(void) { - LOG_INF("Stopping voice interaction (active=%d)", voice_interaction_active); - if (voice_interaction_active) { - voice_interaction_active = false; - play_haptic_milli(25); + if (!atomic_cas(&voice_state, 1, 0)) { + LOG_WRN("Voice interaction not active"); + return; + } + + LOG_INF("Stopping voice interaction"); + + // Stop voice mode first + voice_interaction_active = false; + + // Reset mic + mic_start(); + + // Clear buffers + ring_buf_reset(&ring_buf); - // Clear stream buffer - stream_buffer_pos = 0; - memset(stream_buffer, 0, STREAM_BUFFER_SIZE); - LOG_INF("Voice interaction stopped, buffers cleared"); + // Resume normal operation last + storage_is_on = true; + + LOG_INF("Voice interaction stopped"); +} + +int handle_voice_data(uint8_t *data, size_t len) { + if (!atomic_get(&voice_state)) { + LOG_WRN("Voice interaction not active"); + return -EPERM; + } + + if (!current_connection) { + LOG_ERR("No BLE connection"); + return -ENOTCONN; + } + + // Use voice interaction characteristic + int err = bt_gatt_notify(current_connection, &audio_service.attrs[6], + data, len); + if (err) { + LOG_ERR("Failed to send voice data: %d", err); } + return err; } static const char *phy2str(uint8_t phy) From 66a2fba721f3f5aae318e5a771893e9efc701294 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 09:54:04 +1100 Subject: [PATCH 54/60] Update mic.h --- Friend/firmware/firmware_v1.0/src/mic.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/mic.h b/Friend/firmware/firmware_v1.0/src/mic.h index 33865c77a..de2052e19 100644 --- a/Friend/firmware/firmware_v1.0/src/mic.h +++ b/Friend/firmware/firmware_v1.0/src/mic.h @@ -1,16 +1,17 @@ #ifndef MIC_H #define MIC_H -typedef void (*mix_handler)(int16_t *); +#include -/** - * @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); +// Add voice configuration +#define VOICE_GAIN 0x50 // Adjusted gain for voice capture -#endif \ No newline at end of file +// Existing declarations... +typedef void (*mix_handler)(int16_t *data); +void set_mic_callback(mix_handler callback); +int mic_start(void); + +// Change return type to int +int mic_configure_for_voice(void); + +#endif From 7b59a55700d8c5abedd1703e86c6911b8ba7d6fd Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 09:54:12 +1100 Subject: [PATCH 55/60] Update mic.c --- Friend/firmware/firmware_v1.0/src/mic.c | 36 ++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Friend/firmware/firmware_v1.0/src/mic.c b/Friend/firmware/firmware_v1.0/src/mic.c index 3cf951a4e..04abbe1b5 100644 --- a/Friend/firmware/firmware_v1.0/src/mic.c +++ b/Friend/firmware/firmware_v1.0/src/mic.c @@ -97,7 +97,41 @@ int mic_start() return 0; } -void set_mic_callback(mix_handler callback) +void set_mic_callback(mix_handler callback) { _callback = callback; } + +// Add a public function to be called from transport.c +int mic_configure_for_voice(void) { + // Stop PDM first + nrfx_pdm_stop(); + k_msleep(10); // Give hardware time to stop + + // Uninit current config + nrfx_pdm_uninit(); + k_msleep(10); + + // Configure for voice + nrfx_pdm_config_t voice_config = NRFX_PDM_DEFAULT_CONFIG(PDM_CLK_PIN, PDM_DIN_PIN); + voice_config.gain_l = VOICE_GAIN; + voice_config.gain_r = VOICE_GAIN; + voice_config.clock_freq = NRF_PDM_FREQ_1032K; + voice_config.mode = NRF_PDM_MODE_MONO; + voice_config.edge = NRF_PDM_EDGE_LEFTFALLING; + + // Initialize with new config + if (nrfx_pdm_init(&voice_config, pdm_irq_handler) != NRFX_SUCCESS) { + LOG_ERR("Failed to initialize PDM for voice"); + return -1; + } + + // Start PDM + if (nrfx_pdm_start() != NRFX_SUCCESS) { + LOG_ERR("Failed to start PDM for voice"); + nrfx_pdm_uninit(); + return -1; + } + + return 0; +} From a9bb12ab87779b1f4e1ee6d9a58646ce4ebef771 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 09:54:19 +1100 Subject: [PATCH 56/60] Update codec.h --- Friend/firmware/firmware_v1.0/src/codec.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/codec.h b/Friend/firmware/firmware_v1.0/src/codec.h index bb542dd0f..fc07207ba 100644 --- a/Friend/firmware/firmware_v1.0/src/codec.h +++ b/Friend/firmware/firmware_v1.0/src/codec.h @@ -1,9 +1,19 @@ #ifndef CODEC_H #define CODEC_H -#include + +#include +#include +#include +#include + +// Expose codec ring buffer for voice interaction +extern struct ring_buf codec_ring_buf; + +// Voice mode functions +void set_voice_mode(bool enabled); // Callback -typedef void (*codec_callback)(uint8_t *data, size_t len); +typedef void (*codec_callback)(uint8_t *data, size_t size); void set_codec_callback(codec_callback callback); // Integration From b32e9a5314fcd6be734f035b33e2be3a1b5802af Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 09:54:27 +1100 Subject: [PATCH 57/60] Update codec.c --- Friend/firmware/firmware_v1.0/src/codec.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/codec.c b/Friend/firmware/firmware_v1.0/src/codec.c index c99d0f71c..8f89702dc 100644 --- a/Friend/firmware/firmware_v1.0/src/codec.c +++ b/Friend/firmware/firmware_v1.0/src/codec.c @@ -62,6 +62,21 @@ static uint8_t m_opus_encoder[OPUS_ENCODER_SIZE]; static OpusEncoder *const m_opus_state = (OpusEncoder *)m_opus_encoder; #endif +// Add voice mode configuration +static bool voice_mode = false; + +void set_voice_mode(bool enabled) { + voice_mode = enabled; + if (enabled) { + // Configure OPUS for voice settings + opus_encoder_ctl(m_opus_state, OPUS_SET_BITRATE(24000)); + opus_encoder_ctl(m_opus_state, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + } else { + // Restore normal settings + opus_encoder_ctl(m_opus_state, OPUS_SET_BITRATE(CODEC_OPUS_BITRATE)); + } +} + void codec_entry() { From d06c44a2f5d0f7809e80533e53a48a96cc07baf9 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 09:54:33 +1100 Subject: [PATCH 58/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 3803be0c5..d723968ed 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -9,6 +9,8 @@ #include "button.h" #include "transport.h" #include "speaker.h" +#include "codec.h" +#include "storage.h" LOG_MODULE_REGISTER(button, CONFIG_LOG_DEFAULT_LEVEL); bool is_off = false; @@ -58,6 +60,9 @@ static uint32_t previous_button_time = 0; const int max_debounce_interval = 700; static bool was_pressed = false; +// Add voice interaction state to button FSM +static bool voice_capture_active = false; + // // button // From 29bffa4e9ab4821e2d76a8435dce92aca30aaeeb Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 09:55:10 +1100 Subject: [PATCH 59/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 33 +++++++++------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index d723968ed..2f846cca1 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -117,19 +117,17 @@ static inline void notify_press() } } -static inline void notify_unpress() -{ - final_button_state[0] = BUTTON_RELEASE; - LOG_INF("unpressed"); - 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)); - } - - // If we were recording, stop +static inline void notify_unpress() { if (voice_interaction_active) { + LOG_INF("Button released, stopping voice interaction"); stop_voice_interaction(); + k_msleep(10); // Give time for cleanup + } + + final_button_state[0] = BUTTON_RELEASE; + 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)); } } @@ -148,7 +146,7 @@ static inline void notify_double_tap() { // Only start voice interaction if device is not in sleep mode if (!is_off) { final_button_state[0] = DOUBLE_TAP; - LOG_INF("double tap - starting voice interaction"); + LOG_INF("Double tap detected"); struct bt_conn *conn = get_current_connection(); if (conn != NULL) { @@ -156,17 +154,14 @@ static inline void notify_double_tap() { // Start voice interaction mode start_voice_interaction(); - - // Play feedback sound - play_haptic_milli(50); + if (!voice_interaction_active) { + LOG_ERR("Failed to start voice interaction"); + play_haptic_milli(25); // Error feedback + } } else { LOG_ERR("No connection available for voice interaction"); } } - - // Reset state - current_button_state = GRACE; - reset_count(); } static inline void notify_long_tap() { From bf2bd2a121b1ed44e4645d599d662f7c1ca0f920 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 Nov 2024 10:01:21 +1100 Subject: [PATCH 60/60] Update button.c --- Friend/firmware/firmware_v1.0/src/button.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Friend/firmware/firmware_v1.0/src/button.c b/Friend/firmware/firmware_v1.0/src/button.c index 2f846cca1..5e39941e0 100644 --- a/Friend/firmware/firmware_v1.0/src/button.c +++ b/Friend/firmware/firmware_v1.0/src/button.c @@ -152,16 +152,21 @@ static inline void notify_double_tap() { if (conn != NULL) { bt_gatt_notify(conn, &button_service.attrs[1], &final_button_state, sizeof(final_button_state)); - // Start voice interaction mode - start_voice_interaction(); if (!voice_interaction_active) { - LOG_ERR("Failed to start voice interaction"); - play_haptic_milli(25); // Error feedback + // Start voice interaction + start_voice_interaction(); + k_msleep(10); // Give time for state change + } else { + // Stop if already active + stop_voice_interaction(); + k_msleep(10); } - } else { - LOG_ERR("No connection available for voice interaction"); } } + + // Reset state + current_button_state = GRACE; + reset_count(); } static inline void notify_long_tap() {