apps/mesh_badge: Copy files from Zephyr

This commit is contained in:
Michał Narajowski
2020-09-17 10:34:06 +02:00
parent d665f41935
commit fad96b6057
9 changed files with 939 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.8.2)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(NONE)
target_sources(app PRIVATE src/main.c src/mesh.c src/${BOARD}.c)
+50
View File
@@ -0,0 +1,50 @@
.. _mesh_badge:
Mesh Badge
##########
Overview
********
This sample app for the reel board showcases Bluetooth Mesh
The app starts off as a regular Bluetooth GATT peripheral application.
Install the the "nRF Connect" app on your phone (available both for
Android and iOS) to access the service that the app exposes. The service
can also be accessed with any Bluetooth LE GATT client from your PC,
however these instructions focus on the necessary steps for phones.
Steps to set up
***************
#. On your phone, use the nRF Connect app to Scan for devices and look
for "reel board"
#. Connect to the device. You'll see a single service - select it
#. Request to write to the characteristic by pressing on the upward pointing
arrow symbol
#. Select "Text" to enter text instead of hex
#. Enter your name (or any other arbitrary text). Multiple words
separated by spaces are possible. The font used on the reel display
allows three rows of up to 12 characters
wide text. You can force line breaks with a comma.
#. Press "Send" - this will trigger pairing since this is a protected
characteristic. The passkey for the pairing will be shown on the board's
display. Enter the passkey in your phone.
#. Once pairing is complete the board will show the text you sent. If
you're not happy with it you can try writing something else.
#. When you're happy with the text, disconnect from the board (exit the app or
go back to the device scan page)
#. Once disconnected the board switches over to Bluetooth Mesh mode, and you
can't connect to it anymore over GATT.
If you configure multiple boards like this they can communicate with
each other over mesh: by pressing the user button on the board the first
word (name) of the stored text will be sent to all other boards in
the network and cause the other boards to display "<name> says hi!".
To reset a board to its initial state (disable mesh, erase the stored
text, and make it connectable over GATT):
#. Keep the user button pressed when powering on (or press the reset button
when powered)
#. Wait until "Reseting Device" is shown
+66
View File
@@ -0,0 +1,66 @@
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
CONFIG_BT_RX_STACK_SIZE=4096
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
CONFIG_BT_DEVICE_NAME_GATT_WRITABLE=y
CONFIG_BT_SMP=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_PRIVACY=y
CONFIG_BT_DEVICE_NAME="reel board"
CONFIG_BT_DEVICE_NAME_MAX=32
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_MESH_DEBUG=y
#CONFIG_BT_DEBUG_HCI_CORE=y
#CONFIG_BT_MESH_DEBUG_ADV=y
CONFIG_BT_OBSERVER=y
CONFIG_BT_BROADCASTER=y
CONFIG_BT_RX_BUF_COUNT=30
CONFIG_BT_L2CAP_RX_MTU=69
CONFIG_BT_L2CAP_TX_MTU=69
CONFIG_BT_L2CAP_TX_BUF_COUNT=8
CONFIG_BT_MESH=y
CONFIG_BT_MESH_RELAY=y
#CONFIG_BT_MESH_GATT_PROXY=y
CONFIG_BT_MESH_PB_ADV=n
CONFIG_BT_MESH_PB_GATT=n
CONFIG_BT_MESH_ADV_BUF_COUNT=30
CONFIG_BT_MESH_LABEL_COUNT=0
CONFIG_BT_MESH_CFG_CLI=y
CONFIG_BT_MESH_TX_SEG_MAX=6
CONFIG_BT_MESH_TX_SEG_MSG_COUNT=3
CONFIG_BT_MESH_RX_SEG_MSG_COUNT=3
CONFIG_BT_MESH_CRPL=128
CONFIG_BT_MESH_RPL_STORE_TIMEOUT=120
CONFIG_PRINTK=y
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_I2C=y
CONFIG_GPIO=y
CONFIG_SENSOR=y
CONFIG_APDS9960=y
CONFIG_HDC1008=y
CONFIG_SPI=y
CONFIG_SPI_ASYNC=y
CONFIG_HEAP_MEM_POOL_SIZE=16384
CONFIG_DISPLAY=y
CONFIG_SSD1673=y
CONFIG_CHARACTER_FRAMEBUFFER=y
CONFIG_BT_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_FCB=y
CONFIG_SETTINGS=y
CONFIG_SETTINGS_FCB=y
+8
View File
@@ -0,0 +1,8 @@
sample:
description: reel board mesh badge sample
name: mesh badge
tests:
test:
platform_whitelist: reel_board
tags: samples sensor
harness: sensor
+11
View File
@@ -0,0 +1,11 @@
/*
* Copyright (c) 2018 Phytec Messtechnik GmbH
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
void board_refresh_display(void);
void board_show_text(const char *text, bool center, s32_t duration);
void board_blink_leds(void);
int board_init(void);
+235
View File
@@ -0,0 +1,235 @@
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <misc/printk.h>
#include <string.h>
#include <settings/settings.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/gatt.h>
#include "mesh.h"
#include "board.h"
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
};
static size_t first_name_len(const char *name)
{
size_t len;
for (len = 0; *name; name++, len++) {
switch (*name) {
case ' ':
case ',':
case '\n':
return len;
}
}
return len;
}
static ssize_t read_name(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, u16_t len, u16_t offset)
{
const char *value = bt_get_name();
return bt_gatt_attr_read(conn, attr, buf, len, offset, value,
strlen(value));
}
static ssize_t write_name(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, u16_t len, u16_t offset,
u8_t flags)
{
char name[CONFIG_BT_DEVICE_NAME_MAX];
int err;
if (offset) {
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
}
if (len >= CONFIG_BT_DEVICE_NAME_MAX) {
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
}
memcpy(name, buf, len);
name[len] = '\0';
err = bt_set_name(name);
if (err) {
return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
}
mesh_set_name(name, first_name_len(name));
board_refresh_display();
return len;
}
static struct bt_uuid_128 name_uuid = BT_UUID_INIT_128(
0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
static struct bt_uuid_128 name_enc_uuid = BT_UUID_INIT_128(
0xf1, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
#define CPF_FORMAT_UTF8 0x19
static const struct bt_gatt_cpf name_cpf = {
.format = CPF_FORMAT_UTF8,
};
/* Vendor Primary Service Declaration */
static struct bt_gatt_attr name_attrs[] = {
/* Vendor Primary Service Declaration */
BT_GATT_PRIMARY_SERVICE(&name_uuid),
BT_GATT_CHARACTERISTIC(&name_enc_uuid.uuid,
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT,
read_name, write_name, NULL),
BT_GATT_CUD("Badge Name", BT_GATT_PERM_READ),
BT_GATT_CPF(&name_cpf),
};
static struct bt_gatt_service name_svc = BT_GATT_SERVICE(name_attrs);
static void passkey_display(struct bt_conn *conn, unsigned int passkey)
{
char buf[20];
snprintk(buf, sizeof(buf), "Passkey:\n%06u", passkey);
printk("%s\n", buf);
board_show_text(buf, false, K_FOREVER);
}
static void passkey_cancel(struct bt_conn *conn)
{
printk("Cancel\n");
}
static void pairing_complete(struct bt_conn *conn, bool bonded)
{
printk("Pairing Complete\n");
board_show_text("Pairing Complete", false, K_SECONDS(2));
}
static void pairing_failed(struct bt_conn *conn)
{
printk("Pairing Failed\n");
board_show_text("Pairing Failed", false, K_SECONDS(2));
}
const struct bt_conn_auth_cb auth_cb = {
.passkey_display = passkey_display,
.cancel = passkey_cancel,
.pairing_complete = pairing_complete,
.pairing_failed = pairing_failed,
};
static void connected(struct bt_conn *conn, u8_t err)
{
printk("Connected (err 0x%02x)\n", err);
if (err) {
board_show_text("Connection failed", false, K_SECONDS(2));
} else {
board_show_text("Connected", false, K_FOREVER);
}
}
static void disconnected(struct bt_conn *conn, u8_t reason)
{
printk("Disconnected (reason 0x%02x)\n", reason);
if (strcmp(CONFIG_BT_DEVICE_NAME, bt_get_name()) &&
!mesh_is_initialized()) {
/* Mesh will take over advertising control */
bt_le_adv_stop();
mesh_start();
} else {
board_show_text("Disconnected", false, K_SECONDS(2));
}
}
static struct bt_conn_cb conn_cb = {
.connected = connected,
.disconnected = disconnected,
};
static void bt_ready(int err)
{
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\n");
err = mesh_init();
if (err) {
printk("Initializing mesh failed (err %d)\n", err);
return;
}
printk("Mesh initialized\n");
bt_conn_cb_register(&conn_cb);
bt_conn_auth_cb_register(&auth_cb);
bt_gatt_service_register(&name_svc);
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
if (!mesh_is_initialized()) {
/* Start advertising */
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME,
ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
printk("Advertising failed to start (err %d)\n", err);
return;
}
} else {
const char *name = bt_get_name();
printk("Already provisioned\n");
mesh_set_name(name, first_name_len(name));
}
board_refresh_display();
printk("Board started\n");
}
void main(void)
{
int err;
err = board_init();
if (err) {
printk("board init failed (err %d)\n", err);
return;
}
printk("Starting Board Demo\n");
/* Initialize the Bluetooth Subsystem */
err = bt_enable(bt_ready);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
}
+249
View File
@@ -0,0 +1,249 @@
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <string.h>
#include <misc/printk.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/mesh.h>
#include <bluetooth/hci.h>
#include "mesh.h"
#include "board.h"
#define MOD_LF 0x0000
#define OP_LF 0xbb
#define OP_VENDOR_MSG BT_MESH_MODEL_OP_3(OP_LF, BT_COMP_ID_LF)
#define DEFAULT_TTL 7
#define GROUP_ADDR 0xc123
#define NET_IDX 0x000
#define APP_IDX 0x000
#define FLAGS 0
static struct k_work publish_work;
static struct k_work mesh_start_work;
static void heartbeat(u8_t hops, u16_t feat)
{
board_show_text("Heartbeat Received", false, K_SECONDS(2));
}
static struct bt_mesh_cfg_srv cfg_srv = {
.relay = BT_MESH_RELAY_ENABLED,
.beacon = BT_MESH_BEACON_ENABLED,
.default_ttl = DEFAULT_TTL,
/* 3 transmissions with 20ms interval */
.net_transmit = BT_MESH_TRANSMIT(2, 20),
.relay_retransmit = BT_MESH_TRANSMIT(3, 20),
.hb_sub.func = heartbeat,
};
static struct bt_mesh_cfg_cli cfg_cli = {
};
static void attention_on(struct bt_mesh_model *model)
{
board_show_text("Attention!", false, K_SECONDS(2));
}
static void attention_off(struct bt_mesh_model *model)
{
board_refresh_display();
}
static const struct bt_mesh_health_srv_cb health_srv_cb = {
.attn_on = attention_on,
.attn_off = attention_off,
};
static struct bt_mesh_health_srv health_srv = {
.cb = &health_srv_cb,
};
BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);
static struct bt_mesh_model root_models[] = {
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
};
static void vnd_message(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
char str[32];
size_t len;
printk("Vendor message from 0x%04x\n", ctx->addr);
if (ctx->addr == bt_mesh_model_elem(model)->addr) {
printk("Ignoring message from self\n");
return;
}
len = min(buf->len, 8);
memcpy(str, buf->data, len);
strcpy(str + len, " says hi!");
board_show_text(str, false, K_SECONDS(3));
board_blink_leds();
}
static const struct bt_mesh_model_op vnd_ops[] = {
{ OP_VENDOR_MSG, 1, vnd_message },
BT_MESH_MODEL_OP_END,
};
/* Limit the payload to 11 bytes so that it doesn't get segmented */
BT_MESH_MODEL_PUB_DEFINE(vnd_pub, NULL, 3 + 8);
static struct bt_mesh_model vnd_models[] = {
BT_MESH_MODEL_VND(BT_COMP_ID_LF, MOD_LF, vnd_ops, &vnd_pub, NULL),
};
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(0, root_models, vnd_models),
};
static const struct bt_mesh_comp comp = {
.cid = BT_COMP_ID_LF,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
static void publish_message(struct k_work *work)
{
if (bt_mesh_model_publish(&vnd_models[0]) == 0) {
board_show_text("Saying \"hi!\" to everyone", false,
K_SECONDS(2));
} else {
board_show_text("Sending Failed!", false, K_SECONDS(2));
}
}
void mesh_publish(void)
{
k_work_submit(&publish_work);
}
static int provision_and_configure(void)
{
static const u8_t net_key[16] = {
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
};
static const u8_t app_key[16] = {
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
};
static const u16_t iv_index;
struct bt_mesh_cfg_mod_pub pub = {
.addr = GROUP_ADDR,
.app_idx = APP_IDX,
.ttl = DEFAULT_TTL,
};
u8_t dev_key[16];
u16_t addr;
int err;
err = bt_rand(dev_key, sizeof(dev_key));
if (err) {
return err;
}
do {
err = bt_rand(&addr, sizeof(addr));
if (err) {
return err;
}
} while (!addr);
/* Make sure it's a unicast address (highest bit unset) */
addr &= ~0x8000;
err = bt_mesh_provision(net_key, NET_IDX, FLAGS, iv_index, addr,
dev_key);
if (err) {
return err;
}
printk("Configuring...\n");
/* Add Application Key */
bt_mesh_cfg_app_key_add(NET_IDX, addr, NET_IDX, APP_IDX, app_key, NULL);
/* Bind to vendor model */
bt_mesh_cfg_mod_app_bind_vnd(NET_IDX, addr, addr, APP_IDX,
MOD_LF, BT_COMP_ID_LF, NULL);
/* Bind to Health model */
bt_mesh_cfg_mod_app_bind(NET_IDX, addr, addr, APP_IDX,
BT_MESH_MODEL_ID_HEALTH_SRV, NULL);
/* Add model subscription */
bt_mesh_cfg_mod_sub_add_vnd(NET_IDX, addr, addr, GROUP_ADDR,
MOD_LF, BT_COMP_ID_LF, NULL);
bt_mesh_cfg_mod_pub_set_vnd(NET_IDX, addr, addr, MOD_LF, BT_COMP_ID_LF,
&pub, NULL);
printk("Configuration complete\n");
return addr;
}
static void start_mesh(struct k_work *work)
{
int err;
err = provision_and_configure();
if (err < 0) {
board_show_text("Starting Mesh Failed", false,
K_SECONDS(2));
} else {
char buf[32];
snprintk(buf, sizeof(buf),
"Mesh Started\nAddr: 0x%04x", err);
board_show_text(buf, false, K_SECONDS(4));
}
}
void mesh_start(void)
{
k_work_submit(&mesh_start_work);
}
void mesh_set_name(const char *name, size_t len)
{
bt_mesh_model_msg_init(vnd_pub.msg, OP_VENDOR_MSG);
len = min(len, net_buf_simple_tailroom(vnd_pub.msg));
net_buf_simple_add_mem(vnd_pub.msg, name, len);
}
bool mesh_is_initialized(void)
{
return elements[0].addr != BT_MESH_ADDR_UNASSIGNED;
}
int mesh_init(void)
{
static const u8_t dev_uuid[16] = { 0xc0, 0xff, 0xee };
static const struct bt_mesh_prov prov = {
.uuid = dev_uuid,
};
k_work_init(&publish_work, publish_message);
k_work_init(&mesh_start_work, start_mesh);
return bt_mesh_init(&prov, &comp);
}
+12
View File
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
void mesh_publish(void);
void mesh_set_name(const char *name, size_t len);
bool mesh_is_initialized(void);
void mesh_start(void);
int mesh_init(void);
+303
View File
@@ -0,0 +1,303 @@
/*
* Copyright (c) 2018 Phytec Messtechnik GmbH
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <device.h>
#include <gpio.h>
#include <display/cfb.h>
#include <misc/printk.h>
#include <flash.h>
#include <string.h>
#include <bluetooth/bluetooth.h>
#include "mesh.h"
#include "board.h"
#define EDGE (GPIO_INT_EDGE | GPIO_INT_DOUBLE_EDGE)
#ifdef SW0_GPIO_FLAGS
#define PULL_UP SW0_GPIO_FLAGS
#else
#define PULL_UP 0
#endif
#define LINE_MAX 12
static struct device *epd_dev;
static bool pressed;
static struct device *gpio;
static struct k_delayed_work epd_work;
static struct {
struct device *dev;
const char *name;
u32_t pin;
} leds[] = {
{ .name = LED0_GPIO_CONTROLLER, .pin = LED0_GPIO_PIN, },
{ .name = LED1_GPIO_CONTROLLER, .pin = LED1_GPIO_PIN, },
{ .name = LED2_GPIO_CONTROLLER, .pin = LED2_GPIO_PIN, },
{ .name = LED3_GPIO_CONTROLLER, .pin = LED3_GPIO_PIN, },
};
struct k_delayed_work led_timer;
static size_t print_line(int row, const char *text, size_t len, bool center)
{
u8_t font_height, font_width;
u8_t line[LINE_MAX + 1];
int pad;
len = min(len, LINE_MAX);
memcpy(line, text, len);
line[len] = '\0';
if (center) {
pad = (LINE_MAX - len) / 2;
} else {
pad = 0;
}
cfb_get_font_size(epd_dev, 0, &font_width, &font_height);
if (cfb_print(epd_dev, line, font_width * pad, font_height * row)) {
printk("Failed to print a string\n");
}
return len;
}
static size_t get_len(const char *text)
{
const char *space = NULL;
size_t i;
for (i = 0; i <= LINE_MAX; i++) {
switch (text[i]) {
case '\n':
case '\0':
return i;
case ' ':
space = &text[i];
break;
default:
continue;
}
}
/* If we got more characters than fits a line, and a space was
* encountered, fall back to the last space.
*/
if (space) {
return space - text;
}
return LINE_MAX;
}
void board_blink_leds(void)
{
k_delayed_work_submit(&led_timer, K_MSEC(100));
}
void board_show_text(const char *text, bool center, s32_t duration)
{
int i;
cfb_framebuffer_set_font(epd_dev, 0);
cfb_framebuffer_clear(epd_dev, false);
for (i = 0; i < 3; i++) {
size_t len;
while (*text == ' ' || *text == '\n') {
text++;
}
len = get_len(text);
if (!len) {
break;
}
text += print_line(i, text, len, center);
if (!*text) {
break;
}
}
cfb_framebuffer_finalize(epd_dev);
if (duration != K_FOREVER) {
k_delayed_work_submit(&epd_work, duration);
}
}
static void epd_update(struct k_work *work)
{
char buf[CONFIG_BT_DEVICE_NAME_MAX];
int i;
strncpy(buf, bt_get_name(), sizeof(buf));
/* Convert commas to newlines */
for (i = 0; buf[i] != '\0'; i++) {
if (buf[i] == ',') {
buf[i] = '\n';
}
}
board_show_text(buf, true, K_FOREVER);
}
static bool button_is_pressed(void)
{
u32_t val;
gpio_pin_read(gpio, SW0_GPIO_PIN, &val);
return !val;
}
static void button_interrupt(struct device *dev, struct gpio_callback *cb,
u32_t pins)
{
if (button_is_pressed() == pressed) {
return;
}
pressed = !pressed;
printk("Button %s\n", pressed ? "pressed" : "released");
/* We only care about button release for now */
if (pressed) {
return;
}
if (!mesh_is_initialized()) {
return;
}
if (pins & BIT(SW0_GPIO_PIN)) {
mesh_publish();
}
}
static int configure_button(void)
{
static struct gpio_callback button_cb;
gpio = device_get_binding(GPIO_KEYS_BUTTON_0_GPIO_CONTROLLER);
if (!gpio) {
return -ENODEV;
}
gpio_pin_configure(gpio, SW0_GPIO_PIN,
(GPIO_DIR_IN | GPIO_INT | PULL_UP | EDGE));
gpio_init_callback(&button_cb, button_interrupt, BIT(SW0_GPIO_PIN));
gpio_add_callback(gpio, &button_cb);
gpio_pin_enable_callback(gpio, SW0_GPIO_PIN);
return 0;
}
static void led_timeout(struct k_work *work)
{
static int led_cntr;
int i;
/* Disable all LEDs */
for (i = 0; i < ARRAY_SIZE(leds); i++) {
gpio_pin_write(leds[i].dev, leds[i].pin, 1);
}
/* Stop after 5 iterations */
if (led_cntr > (ARRAY_SIZE(leds) * 5)) {
led_cntr = 0;
return;
}
/* Select and enable current LED */
i = led_cntr++ % ARRAY_SIZE(leds);
gpio_pin_write(leds[i].dev, leds[i].pin, 0);
k_delayed_work_submit(&led_timer, K_MSEC(100));
}
static int configure_leds(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(leds); i++) {
leds[i].dev = device_get_binding(leds[i].name);
if (!leds[i].dev) {
printk("Failed to get %s device\n", leds[i].name);
return -ENODEV;
}
gpio_pin_configure(leds[i].dev, leds[i].pin, GPIO_DIR_OUT);
gpio_pin_write(leds[i].dev, leds[i].pin, 1);
}
k_delayed_work_init(&led_timer, led_timeout);
return 0;
}
static int erase_storage(void)
{
struct device *dev;
dev = device_get_binding(FLASH_DEV_NAME);
return flash_erase(dev, FLASH_AREA_STORAGE_OFFSET,
FLASH_AREA_STORAGE_SIZE);
}
void board_refresh_display(void)
{
k_delayed_work_submit(&epd_work, K_NO_WAIT);
}
int board_init(void)
{
epd_dev = device_get_binding(CONFIG_SSD1673_DEV_NAME);
if (epd_dev == NULL) {
printk("SSD1673 device not found\n");
return -ENODEV;
}
if (cfb_framebuffer_init(epd_dev)) {
printk("Framebuffer initialization failed\n");
return -EIO;
}
cfb_framebuffer_clear(epd_dev, true);
if (configure_button()) {
printk("Failed to configure button\n");
return -EIO;
}
if (configure_leds()) {
printk("LED init failed\n");
return -EIO;
}
k_delayed_work_init(&epd_work, epd_update);
pressed = button_is_pressed();
if (pressed) {
printk("Erasing storage\n");
board_show_text("Resetting Device", false, K_SECONDS(4));
erase_storage();
}
return 0;
}