diff --git a/samples/boards/microbit/pong/prj.conf b/samples/boards/microbit/pong/prj.conf index bfb004c9b5b..4079abc5b31 100644 --- a/samples/boards/microbit/pong/prj.conf +++ b/samples/boards/microbit/pong/prj.conf @@ -2,7 +2,7 @@ CONFIG_BLUETOOTH=y CONFIG_BLUETOOTH_CENTRAL=y CONFIG_BLUETOOTH_PERIPHERAL=y CONFIG_BLUETOOTH_GATT_CLIENT=y -CONFIG_BLUETOOTH_GATT_DYNAMIC_DB=n +CONFIG_BLUETOOTH_GATT_DYNAMIC_DB=y CONFIG_BLUETOOTH_DEVICE_NAME="Zephyr Pong" CONFIG_GPIO=y CONFIG_MICROBIT_DISPLAY=y diff --git a/samples/boards/microbit/pong/src/Makefile b/samples/boards/microbit/pong/src/Makefile index 00066e15678..1ec06befff5 100644 --- a/samples/boards/microbit/pong/src/Makefile +++ b/samples/boards/microbit/pong/src/Makefile @@ -1 +1,3 @@ -obj-y = main.o +ccflags-y +=-I${ZEPHYR_BASE}/samples/bluetooth + +obj-y = main.o ble.o ../../../../bluetooth/gatt/gap.o diff --git a/samples/boards/microbit/pong/src/ble.c b/samples/boards/microbit/pong/src/ble.c new file mode 100644 index 00000000000..94859c5096b --- /dev/null +++ b/samples/boards/microbit/pong/src/ble.c @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "pong.h" + +#define SCAN_TIMEOUT K_SECONDS(2) + +#define APPEARANCE 0 +#define DEVICE_NAME CONFIG_BLUETOOTH_DEVICE_NAME +#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) + +#define PONG_SVC_UUID 0x90, 0x6c, 0x55, 0x0f, 0xee, 0x6f, 0x4d, 0x0d, \ + 0xa1, 0x7e, 0x24, 0x4e, 0x38, 0xea, 0x4f, 0xf9 +#define PONG_CHR_UUID 0xdd, 0x94, 0xaf, 0xd7, 0xcd, 0x2c, 0x40, 0xc6, \ + 0xb5, 0x82, 0x6a, 0xc5, 0x1c, 0x8f, 0xbf, 0xab + +static struct bt_uuid_128 pong_svc_uuid = BT_UUID_INIT_128(PONG_SVC_UUID); +static struct bt_uuid_128 pong_chr_uuid = BT_UUID_INIT_128(PONG_CHR_UUID); +static struct bt_uuid_16 gatt_ccc_uuid = BT_UUID_INIT_16(BT_UUID_GATT_CCC_VAL); + +static struct bt_gatt_discover_params discov_param; +static struct bt_gatt_subscribe_params subscribe_param; + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID128_ALL, PONG_SVC_UUID), +}; + +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), +}; + +static struct bt_conn *default_conn; + +static const struct bt_gatt_attr *local_attr; +static u16_t remote_handle; +static bool remote_ready; +static bool initiator; + +static struct k_delayed_work ble_work; + +static bool connect_canceled; + +static enum { + BLE_DISCONNECTED, + BLE_SCAN_START, + BLE_SCAN, + BLE_CONNECT_CREATE, + BLE_CONNECT_CANCEL, + BLE_ADV_START, + BLE_ADVERTISING, + BLE_CONNECTED, +} ble_state; + +enum { + BLE_BALL_INFO = 0x00, + BLE_LOST = 0x01, +}; + +struct ble_ball_info { + s8_t x_pos; + s8_t y_pos; + s8_t x_vel; + s8_t y_vel; +} __packed; + +struct ble_data { + u8_t op; + union { + struct ble_ball_info ball; + }; +} __packed; + +#define BALL_INFO_LEN (1 + sizeof(struct ble_ball_info)) + +void ble_send_ball(s8_t x_pos, s8_t y_pos, s8_t x_vel, s8_t y_vel) +{ + struct ble_data data = { + .op = BLE_BALL_INFO, + .ball.x_pos = x_pos, + .ball.y_pos = y_pos, + .ball.x_vel = x_vel, + .ball.y_vel = y_vel, + }; + int err; + + if (!default_conn || !remote_ready) { + printk("ble_send_ball(): not ready\n"); + return; + } + + printk("ble_send_ball(%d, %d, %d, %d)\n", x_pos, y_pos, x_vel, y_vel); + + err = bt_gatt_notify(default_conn, local_attr, &data, BALL_INFO_LEN); + if (err) { + printk("GATT notify failed (err %d)\n", err); + } +} + +void ble_send_lost(void) +{ + u8_t lost = BLE_LOST; + int err; + + if (!default_conn || !remote_ready) { + printk("ble_send_lost(): not ready\n"); + return; + } + + err = bt_gatt_notify(default_conn, local_attr, &lost, sizeof(lost)); + if (err) { + printk("GATT notify failed (err %d)\n", err); + } +} + +static u8_t notify_func(struct bt_conn *conn, + struct bt_gatt_subscribe_params *param, + const void *buf, u16_t len) +{ + const struct ble_data *data = buf; + + printk("notify_func() data %p len %u\n", data, len); + + if (!data || !len) { + printk("Unsubscribed, disconnecting...\n"); + remote_handle = 0; + if (default_conn) { + bt_conn_disconnect(default_conn, + BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } + return BT_GATT_ITER_STOP; + } + + switch (data->op) { + case BLE_BALL_INFO: + if (len < BALL_INFO_LEN) { + printk("Too small ball info\n"); + break; + } + + pong_ball_received(data->ball.x_pos, data->ball.y_pos, + data->ball.x_vel, data->ball.y_vel); + break; + case BLE_LOST: + pong_remote_lost(); + break; + default: + printk("Unknown op 0x%02x\n", data->op); + } + + return BT_GATT_ITER_CONTINUE; +} + +static u8_t discover_func(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *param) +{ + int err; + + if (!attr) { + printk("Discover complete\n"); + memset(&discov_param, 0, sizeof(discov_param)); + return BT_GATT_ITER_STOP; + } + + printk("Attribute handle %u\n", attr->handle); + + if (param->uuid == &pong_svc_uuid.uuid) { + printk("Pong service discovered\n"); + discov_param.uuid = &pong_chr_uuid.uuid; + discov_param.start_handle = attr->handle + 1; + discov_param.type = BT_GATT_DISCOVER_CHARACTERISTIC; + + err = bt_gatt_discover(conn, &discov_param); + if (err) { + printk("Char Discovery failed (err %d)\n", err); + } + } else if (param->uuid == &pong_chr_uuid.uuid) { + printk("Pong characteristic discovered\n"); + discov_param.uuid = &gatt_ccc_uuid.uuid; + discov_param.start_handle = attr->handle + 2; + discov_param.type = BT_GATT_DISCOVER_DESCRIPTOR; + subscribe_param.value_handle = attr->handle + 1; + + err = bt_gatt_discover(conn, &discov_param); + if (err) { + printk("CCC Discovery failed (err %d)\n", err); + } + } else { + printk("Pong CCC discovered\n"); + + subscribe_param.notify = notify_func; + subscribe_param.value = BT_GATT_CCC_NOTIFY; + subscribe_param.ccc_handle = attr->handle; + + printk("CCC handle 0x%04x Value handle 0x%04x\n", + subscribe_param.ccc_handle, + subscribe_param.value_handle); + + err = bt_gatt_subscribe(conn, &subscribe_param); + if (err && err != -EALREADY) { + printk("Subscribe failed (err %d)\n", err); + } else { + printk("Subscribed\n"); + } + + remote_handle = attr->handle; + } + + if (remote_handle && remote_ready) { + pong_conn_ready(initiator); + } + + return BT_GATT_ITER_STOP; +} + +static void connected(struct bt_conn *conn, u8_t err) +{ + struct bt_conn_info info; + + if (err) { + printk("Connection failed (err %u)\n", err); + return; + } + + if (!default_conn) { + default_conn = bt_conn_ref(conn); + } + + bt_conn_get_info(conn, &info); + initiator = (info.role == BT_CONN_ROLE_MASTER); + remote_ready = false; + remote_handle = 0; + + printk("Connected\n"); + ble_state = BLE_CONNECTED; + + k_delayed_work_submit(&ble_work, K_NO_WAIT); +} + +static void disconnected(struct bt_conn *conn, u8_t reason) +{ + printk("Disconnected (reason %u)\n", reason); + + if (default_conn) { + bt_conn_unref(default_conn); + default_conn = NULL; + } + + remote_handle = 0; + + if (ble_state == BLE_CONNECTED) { + ble_state = BLE_DISCONNECTED; + pong_remote_disconnected(); + } +} + +static struct bt_conn_cb conn_callbacks = { + .connected = connected, + .disconnected = disconnected, +}; + +void ble_connect(void) +{ + if (ble_state != BLE_DISCONNECTED) { + printk("Not ready to connect\n"); + return; + } + + ble_state = BLE_SCAN_START; + k_delayed_work_submit(&ble_work, K_NO_WAIT); +} + +void ble_cancel_connect(void) +{ + printk("ble_cancel_connect()\n"); + + k_delayed_work_cancel(&ble_work); + + switch (ble_state) { + case BLE_DISCONNECTED: + break; + case BLE_SCAN_START: + ble_state = BLE_DISCONNECTED; + break; + case BLE_SCAN: + connect_canceled = true; + k_delayed_work_submit(&ble_work, K_NO_WAIT); + break; + case BLE_ADV_START: + ble_state = BLE_DISCONNECTED; + break; + case BLE_ADVERTISING: + connect_canceled = true; + k_delayed_work_submit(&ble_work, K_NO_WAIT); + break; + case BLE_CONNECT_CREATE: + ble_state = BLE_CONNECT_CANCEL; + /* Intentional fall-through */ + case BLE_CONNECTED: + connect_canceled = true; + k_delayed_work_submit(&ble_work, K_NO_WAIT); + break; + case BLE_CONNECT_CANCEL: + break; + } +} + +static bool pong_uuid_match(const u8_t *data, u8_t len) +{ + while (len >= 16) { + if (!memcmp(data, pong_svc_uuid.val, 16)) { + return true; + } + + len -= 16; + data += 16; + } + + return false; +} + +static void create_conn(const bt_addr_le_t *addr) +{ + if (default_conn) { + return; + } + + printk("Found matching device, initiating connection...\n"); + + default_conn = bt_conn_create_le(addr, BT_LE_CONN_PARAM_DEFAULT); + if (!default_conn) { + printk("Failed to initiate connection"); + return; + } + + ble_state = BLE_CONNECT_CREATE; + k_delayed_work_submit(&ble_work, SCAN_TIMEOUT); +} + +static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t type, + struct net_buf_simple *ad) +{ + if (type != BT_LE_ADV_IND) { + return; + } + + while (ad->len > 1) { + u8_t len = net_buf_simple_pull_u8(ad); + u8_t type; + + /* Check for early termination */ + if (len == 0) { + return; + } + + if (len > ad->len || ad->len < 1) { + printk("AD malformed\n"); + return; + } + + type = net_buf_simple_pull_u8(ad); + if (type == BT_DATA_UUID128_ALL && + pong_uuid_match(ad->data, len - 1)) { + bt_le_scan_stop(); + create_conn(addr); + return; + } + + net_buf_simple_pull(ad, len - 1); + } +} + +static u32_t adv_timeout(void) +{ + u32_t timeout; + + if (bt_rand(&timeout, sizeof(timeout) < 0)) { + return K_SECONDS(10); + } + + timeout %= K_SECONDS(10); + + return timeout + K_SECONDS(1); +} + +static void cancel_connect(void) +{ + connect_canceled = false; + + switch (ble_state) { + case BLE_SCAN: + bt_le_scan_stop(); + break; + case BLE_ADVERTISING: + bt_le_adv_stop(); + break; + case BLE_CONNECT_CREATE: + case BLE_CONNECTED: + bt_conn_disconnect(default_conn, + BT_HCI_ERR_REMOTE_USER_TERM_CONN); + break; + default: + break; + } + + /* For CONNECTED the state will be updated in the disconnected cb */ + if (ble_state != BLE_CONNECTED) { + ble_state = BLE_DISCONNECTED; + } +} + +static void ble_timeout(struct k_work *work) +{ + int err; + + if (connect_canceled) { + cancel_connect(); + return; + } + + switch (ble_state) { + case BLE_DISCONNECTED: + break; + case BLE_SCAN_START: + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + } + + printk("Started scanning for devices\n"); + ble_state = BLE_SCAN; + k_delayed_work_submit(&ble_work, SCAN_TIMEOUT); + break; + case BLE_CONNECT_CREATE: + printk("Connection attempt timed out\n"); + bt_conn_disconnect(default_conn, + BT_HCI_ERR_REMOTE_USER_TERM_CONN); + ble_state = BLE_ADV_START; + k_delayed_work_submit(&ble_work, K_NO_WAIT); + break; + case BLE_SCAN: + printk("No devices found during scan\n"); + bt_le_scan_stop(); + ble_state = BLE_ADV_START; + k_delayed_work_submit(&ble_work, K_NO_WAIT); + break; + case BLE_ADV_START: + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), + sd, ARRAY_SIZE(sd)); + if (err) { + printk("Advertising failed to start (err %d)\n", err); + return; + } + + printk("Advertising successfully started\n"); + ble_state = BLE_ADVERTISING; + k_delayed_work_submit(&ble_work, adv_timeout()); + break; + case BLE_ADVERTISING: + printk("Timed out advertising\n"); + bt_le_adv_stop(); + ble_state = BLE_SCAN_START; + k_delayed_work_submit(&ble_work, K_NO_WAIT); + break; + case BLE_CONNECTED: + discov_param.uuid = &pong_svc_uuid.uuid; + discov_param.func = discover_func; + discov_param.start_handle = 0x0001; + discov_param.end_handle = 0xffff; + discov_param.type = BT_GATT_DISCOVER_PRIMARY; + + err = bt_gatt_discover(default_conn, &discov_param); + if (err) { + printk("Discover failed (err %d)\n", err); + return; + } + break; + case BLE_CONNECT_CANCEL: + break; + } +} + +static struct bt_gatt_ccc_cfg pong_ccc_cfg[CONFIG_BLUETOOTH_MAX_PAIRED]; + +static void pong_ccc_cfg_changed(const struct bt_gatt_attr *attr, u16_t val) +{ + printk("val %u\n", val); + + remote_ready = (val == BT_GATT_CCC_NOTIFY); + + if (remote_ready && remote_handle) { + pong_conn_ready(initiator); + } +} + +static struct bt_gatt_attr pong_attrs[] = { + /* Vendor Primary Service Declaration */ + BT_GATT_PRIMARY_SERVICE(&pong_svc_uuid.uuid), + BT_GATT_CHARACTERISTIC(&pong_chr_uuid.uuid, BT_GATT_CHRC_NOTIFY), + BT_GATT_DESCRIPTOR(&pong_chr_uuid.uuid, BT_GATT_PERM_NONE, + NULL, NULL, NULL), + BT_GATT_CCC(pong_ccc_cfg, pong_ccc_cfg_changed), +}; + +void ble_init(void) +{ + int err; + + err = bt_enable(NULL); + if (err) { + printk("Enabling Bluetooth failed (err %d)\n", err); + return; + } + + k_delayed_work_init(&ble_work, ble_timeout); + + bt_conn_cb_register(&conn_callbacks); + + gap_init(DEVICE_NAME, APPEARANCE); + + local_attr = &pong_attrs[2]; + bt_gatt_register(pong_attrs, ARRAY_SIZE(pong_attrs)); +} diff --git a/samples/boards/microbit/pong/src/main.c b/samples/boards/microbit/pong/src/main.c index d28b9553b9e..8c643b820e6 100644 --- a/samples/boards/microbit/pong/src/main.c +++ b/samples/boards/microbit/pong/src/main.c @@ -15,8 +15,7 @@ #include -/* Define this to do a single-device game */ -#define SOLO 1 +#include "pong.h" /* The micro:bit has a 5x5 LED display, using (x, y) notation the top-left * corner has coordinates (0, 0) and the bottom-right has (4, 4). To make @@ -24,6 +23,8 @@ * system where top-left is (0, 0) and bottom-right is (49, 49). */ +#define SCROLL_SPEED K_MSEC(400) /* Text scrolling speed */ + #define PIXEL_SIZE 10 /* Virtual coordinates per real pixel */ #define GAME_REFRESH K_MSEC(100) /* Animation refresh rate of the game */ @@ -40,7 +41,7 @@ #define BALL_POS_Y_MAX 39 /* Maximum ball Y coordinate */ #define START_THRESHOLD K_MSEC(100) /* Max time between A & B press */ -#define RESTART_THRESHOLD K_SECONDS(3) /* Time before restart is allowed */ +#define RESTART_THRESHOLD K_SECONDS(2) /* Time before restart is allowed */ #define REAL_TO_VIRT(r) ((r) * 10) #define VIRT_TO_REAL(v) ((v) / 10) @@ -53,6 +54,35 @@ struct x_y { int y; }; +enum pong_state { + INIT, + MULTI, + SINGLE, + CONNECTED, +}; + +static enum pong_state state = INIT; + +struct pong_choice { + int val; + const char *str; +}; + +struct pong_selection { + const struct pong_choice *choice; + size_t choice_count; + void (*complete)(int val); +}; + +static int select_idx; +static const struct pong_selection *select; + +static const struct pong_choice mode_choice[] = { + { SINGLE, "Single" }, + { MULTI, "Multi" }, +}; + +static bool remote_lost; static bool started; static s64_t ended; @@ -73,6 +103,88 @@ static struct x_y ball_vel = { 0, 0 }; static s64_t a_timestamp; static s64_t b_timestamp; +static void pong_select(const struct pong_selection *sel) +{ + struct mb_display *disp = mb_display_get(); + + if (select) { + printk("Other selection still busy\n"); + return; + } + + select = sel; + select_idx = 0; + + mb_display_print(disp, MB_DISPLAY_MODE_DEFAULT | MB_DISPLAY_FLAG_LOOP, + SCROLL_SPEED, "%s", select->choice[select_idx].str); +} + +static void pong_select_change(void) +{ + struct mb_display *disp = mb_display_get(); + + select_idx = (select_idx + 1) % select->choice_count; + mb_display_print(disp, MB_DISPLAY_MODE_DEFAULT | MB_DISPLAY_FLAG_LOOP, + SCROLL_SPEED, "%s", select->choice[select_idx].str); +} + +static void pong_select_complete(void) +{ + struct mb_display *disp = mb_display_get(); + void (*complete)(int val) = select->complete; + int val = select->choice[select_idx].val; + + mb_display_stop(disp); + + select = NULL; + complete(val); +} + +static void game_init(bool initiator) +{ + started = false; + ended = 0; + + ball_pos = BALL_START; + if (!initiator) { + ball_pos.y = -1; + } + + paddle_x = PADDLE_MIN; + + a_timestamp = 0; + b_timestamp = 0; +} + +static void mode_selected(int val) +{ + struct mb_display *disp = mb_display_get(); + + state = val; + + switch (state) { + case SINGLE: + game_init(true); + k_sem_give(&disp_update); + break; + case MULTI: + ble_connect(); + mb_display_print(disp, + MB_DISPLAY_MODE_DEFAULT | MB_DISPLAY_FLAG_LOOP, + SCROLL_SPEED, "Connecting..."); + break; + default: + printk("Unknown state %d\n", state); + return; + }; +} + +static const struct pong_selection mode_selection = { + .choice = mode_choice, + .choice_count = ARRAY_SIZE(mode_choice), + .complete = mode_selected, +}; + static bool ball_visible(void) { return (ball_pos.y >= BALL_POS_Y_MIN); @@ -111,43 +223,63 @@ static void check_start(void) } started = true; + remote_lost = false; k_delayed_work_submit(&refresh, K_NO_WAIT); } static void game_ended(bool won) { struct mb_display *disp = mb_display_get(); - const char *str; + remote_lost = won; ended = k_uptime_get(); started = false; if (won) { - str = "You won!"; + struct mb_image img = MB_IMAGE({ 0, 1, 0, 1, 0 }, + { 0, 1, 0, 1, 0 }, + { 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }); + mb_display_image(disp, MB_DISPLAY_MODE_SINGLE, + RESTART_THRESHOLD, &img, 1); + printk("You won!\n"); } else { - str = "You lost!"; + struct mb_image img = MB_IMAGE({ 0, 1, 0, 1, 0 }, + { 0, 1, 0, 1, 0 }, + { 0, 0, 0, 0, 0 }, + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }); + mb_display_image(disp, MB_DISPLAY_MODE_SINGLE, + RESTART_THRESHOLD, &img, 1); + printk("You lost!\n"); } - printk("%s\n", str); - - mb_display_print(disp, MB_DISPLAY_MODE_DEFAULT | MB_DISPLAY_FLAG_LOOP, - K_MSEC(500), "%s", str); + k_delayed_work_submit(&refresh, RESTART_THRESHOLD); } static void game_refresh(struct k_work *work) { + if (ended) { + game_init(state == SINGLE || remote_lost); + k_sem_give(&disp_update); + return; + } + ball_pos.x += ball_vel.x; ball_pos.y += ball_vel.y; /* Ball went over to the other side */ - if (ball_pos.y < BALL_POS_Y_MIN) { -#if defined(SOLO) - ball_pos.y = -ball_pos.y; - ball_vel.y = -ball_vel.y; -#else - k_sem_give(&disp_update); - return; -#endif + if (ball_vel.y < 0 && ball_pos.y < BALL_POS_Y_MIN) { + if (state == SINGLE) { + ball_pos.y = -ball_pos.y; + ball_vel.y = -ball_vel.y; + } else { + ble_send_ball(BALL_POS_X_MAX - ball_pos.x, ball_pos.y, + -ball_vel.x, -ball_vel.y); + k_sem_give(&disp_update); + return; + } } /* Check for side-wall collision */ @@ -164,10 +296,19 @@ static void game_refresh(struct k_work *work) if (ball_pos.x < REAL_TO_VIRT(paddle_x) || ball_pos.x >= REAL_TO_VIRT(paddle_x + 2)) { game_ended(false); + if (state == CONNECTED) { + ble_send_lost(); + } return; } ball_pos.y = (2 * BALL_POS_Y_MAX) - ball_pos.y; + + /* Make the game play gradually harder */ + if (ball_vel.y < PIXEL_SIZE) { + ball_vel.y++; + } + ball_vel.y = -ball_vel.y; } @@ -175,30 +316,43 @@ static void game_refresh(struct k_work *work) k_sem_give(&disp_update); } -static void game_init(void) +void pong_ball_received(s8_t x_pos, s8_t y_pos, s8_t x_vel, s8_t y_vel) { - ended = 0; + printk("ball_received(%d, %d, %d, %d)\n", x_pos, y_pos, x_vel, y_vel); - ball_pos = BALL_START; - paddle_x = PADDLE_MIN; + ball_pos.x = x_pos; + ball_pos.y = y_pos; + ball_vel.x = x_vel; + ball_vel.y = y_vel; - a_timestamp = 0; - b_timestamp = 0; - - k_sem_give(&disp_update); + k_delayed_work_submit(&refresh, K_NO_WAIT); } static void button_pressed(struct device *dev, struct gpio_callback *cb, u32_t pins) { if (ended && (k_uptime_get() - ended) > RESTART_THRESHOLD) { - game_init(); + k_delayed_work_cancel(&refresh); + game_init(state == SINGLE || remote_lost); + k_sem_give(&disp_update); + return; + } + + if (state == MULTI) { + ble_cancel_connect(); + state = INIT; + pong_select(&mode_selection); return; } if (pins & BIT(SW0_GPIO_PIN)) { printk("A pressed\n"); + if (select) { + pong_select_change(); + return; + } + if (!started) { a_timestamp = k_uptime_get(); check_start(); @@ -215,6 +369,11 @@ static void button_pressed(struct device *dev, struct gpio_callback *cb, } else { printk("B pressed\n"); + if (select) { + pong_select_complete(); + return; + } + if (!started) { b_timestamp = k_uptime_get(); check_start(); @@ -231,6 +390,25 @@ static void button_pressed(struct device *dev, struct gpio_callback *cb, } } +void pong_conn_ready(bool initiator) +{ + state = CONNECTED; + game_init(initiator); + k_sem_give(&disp_update); +} + +void pong_remote_disconnected(void) +{ + state = INIT; + pong_select(&mode_selection); +} + +void pong_remote_lost(void) +{ + printk("Remote lost!\n"); + game_ended(true); +} + static void configure_buttons(void) { static struct gpio_callback button_cb; @@ -260,7 +438,9 @@ void main(void) k_delayed_work_init(&refresh, game_refresh); - game_init(); + ble_init(); + + pong_select(&mode_selection); printk("Started\n"); diff --git a/samples/boards/microbit/pong/src/pong.h b/samples/boards/microbit/pong/src/pong.h new file mode 100644 index 00000000000..bbbea5973ca --- /dev/null +++ b/samples/boards/microbit/pong/src/pong.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +void pong_ball_received(s8_t x_pos, s8_t y_pos, s8_t x_vel, s8_t y_vel); +void pong_conn_ready(bool initiator); +void pong_remote_disconnected(void); +void pong_remote_lost(void); + +void ble_send_ball(s8_t x_pos, s8_t y_pos, s8_t x_vel, s8_t y_vel); +void ble_send_lost(void); +void ble_connect(void); +void ble_cancel_connect(void); +void ble_init(void);