Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
BasedHardware#567 

This is a rebase of the previous PR.

How to test:
In the firmware_v1.0 file,

Flash the zephyr.uf2 file in the file "build_speaker".
-Then use the script "discover_devices.py" to find the device id of your
Omi device. This is to avoid cases where there are multiple friends
connected at once. If there is more than one friend then just test all
of them.
In the script play_sound_on_friend.py, (in firmware_v1.0)

On line 20 add the device id of your friend. This is to avoid cases
where there is more than one friend nearby.
On line 21 add your Deepgram API key.
Then save and run the script by typing a small string. For example, one
line could be

python3 play_sound_on_friend.py "hello"

Which should get the speaker to say hello. Make sure your device is
connected by USB or you have connected a 3.3V pin to the speaker.

BasedHardware#573 (For now it is disabled
but since this uses very similar code).

A sound should play automatically when you compile and run the
zephyr.uf2 file. Of course this file can be modified to play any haptic
sound provided you enter the appropriate lookup table.
  • Loading branch information
josancamon19 authored Aug 29, 2024
2 parents 1f11011 + 945178d commit a32050f
Show file tree
Hide file tree
Showing 8 changed files with 350 additions and 18 deletions.
1 change: 1 addition & 0 deletions Friend/firmware/firmware_v1.0/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ target_sources(app PRIVATE
src/codec.c
src/lib/battery/battery.c
src/button.c
src/speaker.c
)

target_sources_ifdef(CONFIG_CODEC_OPUS app PRIVATE
Expand Down
4 changes: 4 additions & 0 deletions Friend/firmware/firmware_v1.0/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ config OFFLINE_STORAGE
default n
config ACCELEROMETER
bool "Accelerometer Support"
default n
config ENABLE_BUTTON
bool "Button support on Devkit2"
default n
config ENABLE_SPEAKER
bool "Enable the speaker!!"
default n
endmenu
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,16 @@ CONFIG_BT_AUTO_PHY_UPDATE=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_SERIAL=y
CONFIG_UART_CONSOLE=y
CONFIG_LOG_BACKEND_UART=y
CONFIG_LOG_BACKEND_UART_OUTPUT_TEXT=y
CONFIG_LOG_DEFAULT_LEVEL=3
# CONFIG_DEBUG=y
# CONFIG_DEBUG_OPTIMIZATIONS=y
# CONFIG_LOG=y
# CONFIG_LOG_PRINTK=y
# CONFIG_LOG_MODE_IMMEDIATE=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
Expand Down Expand Up @@ -119,12 +119,12 @@ CONFIG_OFFLINE_STORAGE=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
# 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
Expand Down Expand Up @@ -157,3 +157,5 @@ CONFIG_SPI_NRFX=y
CONFIG_ACCELEROMETER=y
#ENABLE THE BUTTON!
CONFIG_ENABLE_BUTTON=y
#ENABLE THE SPEAKER
CONFIG_ENABLE_SPEAKER=y
129 changes: 129 additions & 0 deletions Friend/firmware/firmware_v1.0/src/speaker.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/device.h>

#include <zephyr/drivers/pwm.h>
#include <zephyr/drivers/i2s.h>
#include <zephyr/drivers/gpio.h>

#include <string.h>
#include <zephyr/logging/log.h>
#include <zephyr/logging/log_ctrl.h>

LOG_MODULE_REGISTER(speaker, CONFIG_LOG_DEFAULT_LEVEL);

#define MAX_BLOCK_SIZE 25000 //24000 * 2
#define BLOCK_COUNT 2
#define SAMPLE_FREQUENCY 8000
#define NUMBER_OF_CHANNELS 2
#define PACKET_SIZE 400
#define WORD_SIZE 16
K_MEM_SLAB_DEFINE_STATIC(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, 4);
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;
int speaker_init() {
const struct device *mic = device_get_binding("I2S_0");
speaker = mic;
if (!device_is_ready(mic)) {
LOG_ERR("Speaker device is not supported : %s", mic->name);
return 0;
}
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(mic, I2S_DIR_TX, &config);
if (err < 0) {
LOG_INF("Failed to configure Microphone (%d)", err);
return 0;
}
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, &buzz_buffer, K_MSEC(200));
if (err) {
LOG_INF("Failed to allocate memory again(%d)", err);
return 0;
}

memset(rx_buffer, 0, MAX_BLOCK_SIZE);
int16_t *noise = (int16_t*)buzz_buffer;

memset(buzz_buffer, 0, MAX_BLOCK_SIZE);
return 1;
}

uint16_t speak(uint16_t len, const void *buf) {

uint16_t amount = 0;
amount = len;
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;
clear_ptr = (int16_t *)rx_buffer;
}
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++) {
*ptr2++ = ((int16_t *)buf)[i];
ptr2++;

}
offset = offset + len;
}
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++) {
*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);

//clear the buffer

k_sleep(K_MSEC(4000));
memset(clear_ptr, 0, MAX_BLOCK_SIZE);
}

}
return amount;
}


void buzz() {
i2s_write(speaker, buzz_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);
k_msleep(4000);
}
5 changes: 5 additions & 0 deletions Friend/firmware/firmware_v1.0/src/speaker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once
#include <zephyr/kernel.h>
int speaker_init();
uint16_t speak();
void buzz();
29 changes: 27 additions & 2 deletions Friend/firmware/firmware_v1.0/src/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "utils.h"
#include "btutils.h"
#include "lib/battery/battery.h"

#include "speaker.h"

#include <zephyr/drivers/sensor.h>

Expand All @@ -28,8 +28,9 @@ uint16_t current_package_index = 0;
// Internal
//

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);

static struct bt_conn_cb _callback_references;
struct bt_conn *current_connection = NULL;
static void audio_ccc_config_changed_handler(const struct bt_gatt_attr *attr, uint16_t value);
static ssize_t audio_data_read_characteristic(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset);
static ssize_t audio_codec_read_characteristic(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset);
Expand All @@ -49,12 +50,18 @@ static ssize_t dfu_control_point_write_handler(struct bt_conn *conn, const struc
static struct bt_uuid_128 audio_service_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x19B10000, 0xE8F2, 0x537E, 0x4F6C, 0xD104768A1214));
static struct bt_uuid_128 audio_characteristic_data_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x19B10001, 0xE8F2, 0x537E, 0x4F6C, 0xD104768A1214));
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_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),
#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

};

static struct bt_gatt_service audio_service = BT_GATT_SERVICE(audio_service_attr);
Expand Down Expand Up @@ -231,6 +238,14 @@ static ssize_t audio_codec_read_characteristic(struct bt_conn *conn, const struc
return bt_gatt_attr_read(conn, attr, buf, len, offset, value, sizeof(value));
}

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;
}

//
// DFU Service Handlers
//
Expand Down Expand Up @@ -587,6 +602,16 @@ int transport_start()

button_init();
register_button_service();
#endif

#ifdef CONFIG_ENABLE_SPEAKER

err = speaker_init();
if(!err) {
LOG_ERR("Speaker failed to start");
return 0;
}

#endif
// Start advertising

Expand Down
9 changes: 9 additions & 0 deletions Friend/firmware/testing/discover_devices.py
Original file line number Diff line number Diff line change
@@ -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())
Loading

0 comments on commit a32050f

Please sign in to comment.