/** * The main program. */ int main(int argc, char* argv[]) { struct gecko_cmd_packet *evt, *rsp; /** * Initialize BGLIB with our output function for sending messages. */ BGLIB_INITIALIZE(on_message_send, uart_rx); if (hw_init(argc, argv) < 0) { printf("Hardware initialization failure, check serial port and baud rate values\n"); exit(EXIT_FAILURE); } /** * Display welcome message. */ printf("\nBlue Gecko WSTK GPIO BLE Peripheral Application\n"); printf("-----------------------------------------------\n\n"); // trigger reset manually with an API command instead printf("--> Resetting device\n\tgecko_cmd_system_reset(0)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_system_reset(0); printf("\n--- No reponse expected, should go directly to 'system_boot' event\n"); printf("--- If this does not occur, please reset the module to trigger it\n\n"); // ======================================================================================== // This infinite loop is similar to the BGScript interpreter environment, and each "case" // represents one of the event handlers that you would define using BGScript code. You can // restructure this code to use your own function calls instead of placing all of the event // handler logic right inside each "case" block. // ======================================================================================== while (1) { // blocking wait for event API packet evt = gecko_wait_event(); // if a non-blocking implementation is needed, use gecko_peek_event() instead // (will return NULL instead of packet struct pointer if no event is ready) switch (BGLIB_MSG_ID(evt -> header)) { // SYSTEM BOOT (power-on/reset) case gecko_evt_system_boot_id: // VERBOSE PACKET OUTPUT printf("<-- Received event:\n\tgecko_evt_system_boot(%d, %d, %d, %d, %d, %d)\n", evt->data.evt_system_boot.major, evt->data.evt_system_boot.minor, evt->data.evt_system_boot.patch, evt->data.evt_system_boot.build, evt->data.evt_system_boot.bootloader, evt->data.evt_system_boot.hw ); // set device name (will appear in active scans and readable GATT characteristic) printf("--> Setting device name:\n\tgecko_cmd_gatt_server_write_attribute_value(%d, 0, 16, \"BGM111 GPIO Demo\")\n", gattdb_device_name); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_write_attribute_value(gattdb_device_name, 0, 16, "BGM111 GPIO Demo"); printf("<-- Received response:\n\tgecko_rsp_gatt_server_write_attribute_value(0x%04X)\n", rsp->data.rsp_gatt_server_write_attribute_value.result); // start advertisements after boot/reset printf("--> Starting advertisements:\n\tgecko_cmd_le_gap_set_mode(2, 2)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_le_gap_set_mode(le_gap_general_discoverable, le_gap_undirected_connectable); printf("<-- Received response:\n\tgecko_rsp_gap_set_mode(0x%04X)\n", rsp->data.rsp_le_gap_set_mode.result); printf("\n--- AWAITING CONNECTION FROM BLE MASTER\n\n"); break; // LE CONNECTION OPENED (remote device connected) case gecko_evt_le_connection_opened_id: // VERBOSE PACKET OUTPUT printf("<-- Received event:\n\tgecko_evt_le_connection_opened(%02X:%02X:%02X:%02X:%02X:%02X, %d, %d, %d, 0x%02X)\n", evt->data.evt_le_connection_opened.address.addr[5], // <-- address is little-endian evt->data.evt_le_connection_opened.address.addr[4], evt->data.evt_le_connection_opened.address.addr[3], evt->data.evt_le_connection_opened.address.addr[2], evt->data.evt_le_connection_opened.address.addr[1], evt->data.evt_le_connection_opened.address.addr[0], evt->data.evt_le_connection_opened.address_type, evt->data.evt_le_connection_opened.master, evt->data.evt_le_connection_opened.connection, evt->data.evt_le_connection_opened.bonding ); // update connection state var connection_state = 1; connection_handle = evt->data.evt_le_connection_opened.connection; // start soft timer for GPIO polling printf("--> Starting 50ms repeating timer for button status polling\n\thardware_set_soft_timer(205, 0, 0)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_set_soft_timer(205, 0, 0); printf("<-- Received response:\n\tgecko_rsp_hardware_set_soft_timer(0x%04X)\n", rsp->data.rsp_hardware_set_soft_timer.result); break; // LE CONNECTION CLOSED (remote device disconnected) case gecko_evt_le_connection_closed_id: // VERBOSE PACKET OUTPUT printf("<-- Received event:\n\tgecko_evt_le_connection_closed(%d, 0x%04X)\n", evt->data.evt_le_connection_closed.connection, evt->data.evt_le_connection_closed.reason ); // update status vars connection_state = 0; subscription_state = 0; // stop soft timer for GPIO polling printf("--> Ending 50ms repeating timer for button status polling\n\thardware_set_soft_timer(0, 0, 0)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_set_soft_timer(0, 0, 0); printf("<-- Received response:\n\tgecko_rsp_hardware_set_soft_timer(0x%04X)\n", rsp->data.rsp_hardware_set_soft_timer.result); // restart advertisements after disconnection printf("--> Restarting advertisements\n\tgecko_cmd_le_gap_set_mode(0x02, 0x02)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_le_gap_set_mode(le_gap_general_discoverable, le_gap_undirected_connectable); printf("<-- Received response:\n\tgecko_rsp_gap_set_mode(0x%04X)\n", rsp -> data.rsp_le_gap_set_mode.result); printf("\n--- AWAITING CONNECTION FROM BLE MASTER\n\n"); break; // GATT SERVER CHARACTERISTIC STATUS (remote GATT client changed subscription status) case gecko_evt_gatt_server_characteristic_status_id: // VERBOSE PACKET OUTPUT printf("<-- Received event:\n\tgecko_evt_gatt_server_characteristic_status(%d, %d, 0x%02X, 0x%04X)\n", evt->data.evt_gatt_server_characteristic_status.connection, evt->data.evt_gatt_server_characteristic_status.characteristic, evt->data.evt_gatt_server_characteristic_status.status_flags, evt->data.evt_gatt_server_characteristic_status.client_config_flags ); // make sure this is on the correct characteristic if (evt->data.evt_gatt_server_characteristic_status.characteristic == gattdb_gpio_control) { // make sure this update corresponds to a change in configuration status if (evt->data.evt_gatt_server_characteristic_status.status_flags == gatt_server_client_config) { // client characteristic configuration status changed for GPIO control if (evt->data.evt_gatt_server_characteristic_status.client_config_flags & gatt_indication) { printf("\n--- INDICATIONS ENABLED ON GPIO CHARACTERISTIC\n"); printf("\n--- Button1 press will now push value to client\n\n"); // update status vars subscription_state = 1; // read PF7 GPIO state to detect button press status immediately //printf("--> Reading PF7 state\n\thardware_read_gpio(5, 0x0080)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_read_gpio(5, 0x0080); // TODO: bugfix in BGLib - this response packet doesn't map correctly uint8_t *b = (uint8_t *)rsp; uint16_t manual_gpio_data = b[2] | (b[3] << 8); /* printf("<-- Received response:\n\tgecko_rsp_hardware_read_gpio(0x%04X, 0x%04X)\n", rsp->data.rsp_hardware_read_gpio.result, manual_gpio_data); //rsp->data.rsp_hardware_read_gpio.data); //*/ //button_state = (rsp->data.rsp_hardware_read_gpio.data & 0x0080) ? 0 : 1; // logic high = not pressed, logic low = pressed button_state = (manual_gpio_data & 0x0080) != 0 ? 0 : 1; // logic high = not pressed, logic low = pressed // push current status to client so they have it available printf("--> Pushing current PF7 state to client immediately\n\tgecko_cmd_gatt_server_send_characteristic_notification(%d, %d, 1, [ 0x%02X ])\n", evt->data.evt_gatt_server_characteristic_status.connection, evt->data.evt_gatt_server_characteristic_status.characteristic, button_state ); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_characteristic_notification( evt->data.evt_gatt_server_characteristic_status.connection, evt->data.evt_gatt_server_characteristic_status.characteristic, 1, &button_state); printf("<-- Received response:\n\tgatt_server_send_characteristic_notification(0x%04X)\n", rsp->data.rsp_gatt_server_send_characteristic_notification.result); } else { // update status vars subscription_state = 0; printf("\n--- INDICATIONS DISABLED ON GPIO CHARACTERISTIC\n"); printf("\n--- Button1 press will no longer push value to client\n\n"); } } } else { // how did this happen? the GATT structure only has one indication-enabled characteristic printf("\n--- STATUS UPDATED ON UNEXPECTED CHARACTERISTIC\n"); printf("--- (not a problem, just...very strange)\n\n"); } break; // GATT SERVER USER READ REQUEST (remote GATT client is reading a value from a user-type characteristic) case gecko_evt_gatt_server_user_read_request_id: // VERBOSE PACKET OUTPUT printf("<-- Received event:\n\tgecko_evt_gatt_server_user_read_request(%d, %d, %d, %d)\n", evt->data.evt_gatt_server_user_read_request.connection, evt->data.evt_gatt_server_user_read_request.characteristic, evt->data.evt_gatt_server_user_read_request.att_opcode, evt->data.evt_gatt_server_user_read_request.offset ); // make sure this is on the correct characteristic if (evt->data.evt_gatt_server_user_read_request.characteristic == gattdb_gpio_control) { // read PF7 GPIO state to detect button press status //printf("--> Reading PF7 state\n\thardware_read_gpio(5, 0x0080)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_read_gpio(5, 0x0080); // TODO: bugfix in BGLib - this response packet doesn't map correctly uint8_t *b = (uint8_t *)rsp; uint16_t manual_gpio_data = b[2] | (b[3] << 8); /* printf("<-- Received response:\n\tgecko_rsp_hardware_read_gpio(0x%04X, 0x%04X)\n", rsp->data.rsp_hardware_read_gpio.result, manual_gpio_data); //rsp->data.rsp_hardware_read_gpio.data); //*/ //button_state = (rsp->data.rsp_hardware_read_gpio.data & 0x0080) ? 0 : 1; button_state = (manual_gpio_data & 0x0080) != 0 ? 0 : 1; // send back "success" response packet with value manually (GATT structure has `type="user"` set) printf("--> Sending success response for read request\n\tgecko_cmd_gatt_server_send_user_read_response(%d, %d, 0x00, 1, [ 0x%02X ])\n", evt->data.evt_gatt_server_user_read_request.connection, evt->data.evt_gatt_server_user_read_request.characteristic, button_state); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_read_response( evt->data.evt_gatt_server_user_read_request.connection, evt->data.evt_gatt_server_user_read_request.characteristic, 0x00, /* SUCCESS */ 0x01, /* length */ &button_state); printf("<-- Received response:\n\tgecko_rsp_gatt_server_send_user_read_response(0x%04X)\n", rsp->data.rsp_gatt_server_send_user_write_response.result); } else { // send 0x81 error response for invalid characteristic (shouldn't be able to happen, but let's be safe) // send back "error" response packet manually (GATT structure has `type="user"` set) printf("--> Sending error response for write operation\n\tgecko_cmd_gatt_server_send_user_write_response(%d, %d, 0x81)\n", evt->data.evt_gatt_server_attribute_value.connection, evt->data.evt_gatt_server_attribute_value.attribute); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_write_response( evt->data.evt_gatt_server_attribute_value.connection, evt->data.evt_gatt_server_attribute_value.attribute, 0x81 /* CUSTOM ERROR (0x80-0xFF are user-defined) */); printf("<-- Received response:\n\tgecko_rsp_gatt_server_send_user_write_response(0x%04X)\n", rsp->data.rsp_gatt_server_send_user_write_response.result); } break; // GATT SERVER USER WRITE REQUEST (remote GATT client wrote a new value to a user-type characteristic) case gecko_evt_gatt_server_user_write_request_id: // VERBOSE PACKET OUTPUT printf("<-- Received event:\n\tgecko_evt_gatt_server_user_write_request(%d, %d, %d, %d, [ ", evt->data.evt_gatt_server_user_write_request.connection, evt->data.evt_gatt_server_user_write_request.characteristic, evt->data.evt_gatt_server_user_write_request.att_opcode, evt->data.evt_gatt_server_user_write_request.offset ); for (int i = 0; i < evt->data.evt_gatt_server_user_write_request.value.len; i++) printf("%02X ", evt->data.evt_gatt_server_user_write_request.value.data[i]); printf("])\n"); // make sure this is on the correct characteristic if (evt->data.evt_gatt_server_user_read_request.characteristic == gattdb_gpio_control) { // set LED0 (PF6) off/on based on zero/non-zero status of written byte if (evt->data.evt_gatt_server_user_write_request.value.len == 1) { // valid byte string, so process it if (evt->data.evt_gatt_server_user_write_request.value.data[0]) { // non-zero byte written, turn LED0 on printf("--> Turning on LED0 (PF6 low)\n\tgecko_cmd_hardware_write_gpio(0x05, 0x0040, 0x0000)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_write_gpio(5, 0x40, 0x00); printf("<-- Received response:\n\tgecko_rsp_hardware_write_gpio(0x%04X)\n", rsp->data.rsp_hardware_write_gpio.result); } else { // zero byte written, turn LED0 off printf("--> Turning off LED0 (PF6 high)\n\tgecko_cmd_hardware_write_gpio(0x05, 0x0040, 0x0040)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_write_gpio(5, 0x40, 0x40); printf("<-- Received response:\n\tgecko_rsp_hardware_write_gpio(0x%04X)\n", rsp->data.rsp_hardware_write_gpio.result); } // send back "success" response packet manually (GATT structure has `type="user"` set) printf("--> Sending success response for write operation\n\tgecko_cmd_gatt_server_send_user_write_response(%d, %d, 0x00)\n", evt->data.evt_gatt_server_user_write_request.connection, evt->data.evt_gatt_server_user_write_request.characteristic); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_write_response( evt->data.evt_gatt_server_user_write_request.connection, evt->data.evt_gatt_server_user_write_request.characteristic, 0x00 /* SUCCESS */); printf("<-- Received response:\n\tgecko_rsp_gatt_server_send_user_write_response(0x%04X)\n", rsp->data.rsp_gatt_server_send_user_write_response.result); } else { // invalid byte string, so don't process change anything with LEDs and send error response 0x80 // send back "error" response packet manually (GATT structure has `type="user"` set) printf("--> Sending error response for write operation\n\tgecko_cmd_gatt_server_send_user_write_response(%d, %d, 0x80)\n", evt->data.evt_gatt_server_attribute_value.connection, evt->data.evt_gatt_server_attribute_value.attribute); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_write_response( evt->data.evt_gatt_server_attribute_value.connection, evt->data.evt_gatt_server_attribute_value.attribute, 0x80 /* CUSTOM ERROR (0x80-0xFF are user-defined) */); printf("<-- Received response:\n\tgecko_rsp_gatt_server_send_user_write_response(0x%04X)\n", rsp->data.rsp_gatt_server_send_user_write_response.result); } } else { // send 0x81 error response for invalid characteristic (shouldn't be able to happen, but let's be safe) // send back "error" response packet manually (GATT structure has `type="user"` set) printf("--> Sending error response for write operation\n\tgecko_cmd_gatt_server_send_user_write_response(%d, %d, 0x81)\n", evt->data.evt_gatt_server_attribute_value.connection, evt->data.evt_gatt_server_attribute_value.attribute); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_write_response( evt->data.evt_gatt_server_attribute_value.connection, evt->data.evt_gatt_server_attribute_value.attribute, 0x81 /* CUSTOM ERROR (0x80-0xFF are user-defined) */); printf("<-- Received response:\n\tgecko_rsp_gatt_server_send_user_write_response(0x%04X)\n", rsp->data.rsp_gatt_server_send_user_write_response.result); } break; case gecko_evt_hardware_soft_timer_id: // VERBOSE PACKET OUTPUT // NOTE: this is suppresed because it would generate a LOT of useless content /* printf("<-- Received event:\n\tgecko_evt_hardware_soft_timer(%d)\n", evt->data.evt_hardware_soft_timer.handle ); */ // skip all of this if we're not connected but there are any residual timer // events still occurring (may be some API processing gap here) if (!connection_state) break; // make sure this is the correct timer (we scheduled handle 0 above) if (evt->data.evt_hardware_soft_timer.handle == 0) { // read PF7 GPIO state to detect button press status //printf("--> Reading PF7 state\n\thardware_read_gpio(5, 0x0080)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_read_gpio(5, 0x0080); // TODO: bugfix in BGLib - this response packet doesn't map correctly uint8_t *b = (uint8_t *)rsp; uint16_t manual_gpio_data = b[2] | (b[3] << 8); /* printf("<-- Received response:\n\tgecko_rsp_hardware_read_gpio(0x%04X, 0x%04X)\n", rsp->data.rsp_hardware_read_gpio.result, manual_gpio_data); //rsp->data.rsp_hardware_read_gpio.data); //*/ // compare with last known status //if (button_state != ((rsp->data.rsp_hardware_read_gpio.data & 0x0080) ? 0 : 1)) if (button_state != ((manual_gpio_data & 0x0080) != 0 ? 0 : 1)) { // update button_state //button_state = (rsp->data.rsp_hardware_read_gpio.data & 0x0080) ? 0 : 1; // logic high = not pressed, logic low = pressed button_state = (manual_gpio_data & 0x0080) != 0 ? 0 : 1; // logic high = not pressed, logic low = pressed // check to see if the client is subscribed to indications if (subscription_state) { // push updated status to client printf("--> Pushing current PF7 state to client immediately\n\tgecko_cmd_gatt_server_send_characteristic_notification(%d, %d, 1, [ 0x%02X ])\n", connection_handle, gattdb_gpio_control, button_state ); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_characteristic_notification( connection_handle, gattdb_gpio_control, 1, &button_state); printf("<-- Received response:\n\tgatt_server_send_characteristic_notification(0x%04X)\n", rsp->data.rsp_hardware_read_gpio.result); } } } break; } } return 0; }
/** * The main program. */ int main(int argc, char* argv[]) { struct gecko_cmd_packet *evt, *rsp; /** * Initialize BGLIB with our output function for sending messages. */ BGLIB_INITIALIZE(on_message_send, uart_rx); if (hw_init(argc, argv) < 0) { printf("Hardware initialization failure, check serial port and baud rate values\n"); exit(EXIT_FAILURE); } /** * Display welcome message. */ printf("\nBlue Gecko WSTK GPIO BLE Peripheral Application\n"); printf("-----------------------------------------------\n\n"); // trigger reset manually with an API command instead printf("--> Resetting device\n\tgecko_cmd_system_reset(0)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_system_reset(0); printf("\n--- No reponse expected, should go directly to 'system_boot' event\n"); printf("--- If this does not occur, please reset the module to trigger it\n\n"); // ======================================================================================== // This infinite loop is similar to the BGScript interpreter environment, and each "case" // represents one of the event handlers that you would define using BGScript code. You can // restructure this code to use your own function calls instead of placing all of the event // handler logic right inside each "case" block. // ======================================================================================== while (1) { // blocking wait for event API packet evt = gecko_wait_event(); // if a non-blocking implementation is needed, use gecko_peek_event() instead // (will return NULL instead of packet struct pointer if no event is ready) switch (BGLIB_MSG_ID(evt -> header)) { // SYSTEM BOOT (power-on/reset) case gecko_evt_system_boot_id: // set device name (will appear in active scans and readable GATT characteristic) rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_write_attribute_value(gattdb_device_name, 0, 16, "BGM111 GPIO Demo"); // start advertisements after boot/reset rsp = (struct gecko_cmd_packet *)gecko_cmd_le_gap_set_mode(le_gap_general_discoverable, le_gap_undirected_connectable); break; // LE CONNECTION OPENED (remote device connected) case gecko_evt_le_connection_opened_id: // update connection state var connection_state = 1; connection_handle = evt->data.evt_le_connection_opened.connection; // start soft timer for GPIO polling rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_set_soft_timer(205, 0, 0); break; // LE CONNECTION CLOSED (remote device disconnected) case gecko_evt_le_connection_closed_id: // update status vars connection_state = 0; subscription_state = 0; // stop soft timer for GPIO polling rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_set_soft_timer(0, 0, 0); // restart advertisements after disconnection rsp = (struct gecko_cmd_packet *)gecko_cmd_le_gap_set_mode(le_gap_general_discoverable, le_gap_undirected_connectable); break; // GATT SERVER CHARACTERISTIC STATUS (remote GATT client changed subscription status) case gecko_evt_gatt_server_characteristic_status_id: // make sure this is on the correct characteristic if (evt->data.evt_gatt_server_characteristic_status.characteristic == gattdb_gpio_control) { // make sure this update corresponds to a change in configuration status if (evt->data.evt_gatt_server_characteristic_status.status_flags == gatt_server_client_config) { // client characteristic configuration status changed for GPIO control if (evt->data.evt_gatt_server_characteristic_status.client_config_flags & gatt_indication) { // update status vars subscription_state = 1; // read PF7 GPIO state to detect button press status immediately //printf("--> Reading PF7 state\n\thardware_read_gpio(5, 0x0080)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_read_gpio(5, 0x0080); // TODO: bugfix in BGLib - this response packet doesn't map correctly uint8_t *b = (uint8_t *)rsp; uint16_t manual_gpio_data = b[2] | (b[3] << 8); //button_state = (rsp->data.rsp_hardware_read_gpio.data & 0x0080) ? 0 : 1; // logic high = not pressed, logic low = pressed button_state = (manual_gpio_data & 0x0080) != 0 ? 0 : 1; // logic high = not pressed, logic low = pressed // push current status to client so they have it available rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_characteristic_notification( evt->data.evt_gatt_server_characteristic_status.connection, evt->data.evt_gatt_server_characteristic_status.characteristic, 1, &button_state); } else { // update status vars subscription_state = 0; } } } break; // GATT SERVER USER READ REQUEST (remote GATT client is reading a value from a user-type characteristic) case gecko_evt_gatt_server_user_read_request_id: // make sure this is on the correct characteristic if (evt->data.evt_gatt_server_user_read_request.characteristic == gattdb_gpio_control) { // read PF7 GPIO state to detect button press status rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_read_gpio(5, 0x0080); // TODO: bugfix in BGLib - this response packet doesn't map correctly uint8_t *b = (uint8_t *)rsp; uint16_t manual_gpio_data = b[2] | (b[3] << 8); //button_state = (rsp->data.rsp_hardware_read_gpio.data & 0x0080) ? 0 : 1; button_state = (manual_gpio_data & 0x0080) != 0 ? 0 : 1; // send back "success" response packet with value manually (GATT structure has `type="user"` set) rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_read_response( evt->data.evt_gatt_server_user_read_request.connection, evt->data.evt_gatt_server_user_read_request.characteristic, 0x00, /* SUCCESS */ 0x01, /* length */ &button_state); } else { // send 0x81 error response for invalid characteristic (shouldn't be able to happen, but let's be safe) // send back "error" response packet manually (GATT structure has `type="user"` set) rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_write_response( evt->data.evt_gatt_server_attribute_value.connection, evt->data.evt_gatt_server_attribute_value.attribute, 0x81 /* CUSTOM ERROR (0x80-0xFF are user-defined) */); } break; // GATT SERVER USER WRITE REQUEST (remote GATT client wrote a new value to a user-type characteristic) case gecko_evt_gatt_server_user_write_request_id: // make sure this is on the correct characteristic if (evt->data.evt_gatt_server_user_read_request.characteristic == gattdb_gpio_control) { // set LED0 (PF6) off/on based on zero/non-zero status of written byte if (evt->data.evt_gatt_server_user_write_request.value.len == 1) { // valid byte string, so process it if (evt->data.evt_gatt_server_user_write_request.value.data[0]) { // non-zero byte written, turn LED0 on rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_write_gpio(5, 0x40, 0x00); } else { // zero byte written, turn LED0 off rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_write_gpio(5, 0x40, 0x40); } // send back "success" response packet manually (GATT structure has `type="user"` set) rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_write_response( evt->data.evt_gatt_server_user_write_request.connection, evt->data.evt_gatt_server_user_write_request.characteristic, 0x00 /* SUCCESS */); } else { // invalid byte string, so don't process change anything with LEDs and send error response 0x80 // send back "error" response packet manually (GATT structure has `type="user"` set) rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_write_response( evt->data.evt_gatt_server_attribute_value.connection, evt->data.evt_gatt_server_attribute_value.attribute, 0x80 /* CUSTOM ERROR (0x80-0xFF are user-defined) */); } } else { // send 0x81 error response for invalid characteristic (shouldn't be able to happen, but let's be safe) // send back "error" response packet manually (GATT structure has `type="user"` set) rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_write_response( evt->data.evt_gatt_server_attribute_value.connection, evt->data.evt_gatt_server_attribute_value.attribute, 0x81 /* CUSTOM ERROR (0x80-0xFF are user-defined) */); } break; case gecko_evt_hardware_soft_timer_id: // skip all of this if we're not connected but there are any residual timer // events still occurring (may be some API processing gap here) if (!connection_state) break; // make sure this is the correct timer (we scheduled handle 0 above) if (evt->data.evt_hardware_soft_timer.handle == 0) { // read PF7 GPIO state to detect button press status //printf("--> Reading PF7 state\n\thardware_read_gpio(5, 0x0080)\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_read_gpio(5, 0x0080); // TODO: bugfix in BGLib - this response packet doesn't map correctly uint8_t *b = (uint8_t *)rsp; uint16_t manual_gpio_data = b[2] | (b[3] << 8); // compare with last known status //if (button_state != ((rsp->data.rsp_hardware_read_gpio.data & 0x0080) ? 0 : 1)) if (button_state != ((manual_gpio_data & 0x0080) != 0 ? 0 : 1)) { // update button_state //button_state = (rsp->data.rsp_hardware_read_gpio.data & 0x0080) ? 0 : 1; // logic high = not pressed, logic low = pressed button_state = (manual_gpio_data & 0x0080) != 0 ? 0 : 1; // logic high = not pressed, logic low = pressed // check to see if the client is subscribed to indications if (subscription_state) { // push updated status to client rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_characteristic_notification( connection_handle, gattdb_gpio_control, 1, &button_state); } } } break; } } return 0; }
int main(int argc, char* argv[]){ // Setup struct gecko_cmd_packet *evt, *rsp; BGLIB_INITIALIZE(on_message_send, uart_rx); // Init Hardware if (uart_open(uart_port, baud_rate) < 0){ printf("Hardware initialization failure, check serial port and baud rate values\n"); exit(EXIT_FAILURE); } // Appliction start printf("Starting TTK8 demo app\n\n"); printf("If device doesn't reset automatically, reset it manually\n"); // Start thred for handling input pthread_t input_thr; pthread_create(&input_thr, NULL, handle_input, NULL); // Reset BGM111 rsp = (struct gecko_cmd_packet *)gecko_cmd_system_reset(0); while (1){ evt = gecko_wait_event(); // Blocking wait switch (BGLIB_MSG_ID(evt -> header)) { // Reset/Boot case gecko_evt_system_boot_id: printf("Device reset\n"); // Set device name rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_write_attribute_value(gattdb_device_name, 0, 13, application_name); // Start advertising rsp = (struct gecko_cmd_packet *)gecko_cmd_le_gap_set_mode(le_gap_general_discoverable, le_gap_undirected_connectable); printf("Waiting for connection...\n"); printf("\n"); break; case gecko_evt_le_connection_opened_id: printf("Connected to %02X:%02X:%02X:%02X:%02X:%02X\n\n", evt->data.evt_le_connection_opened.address.addr[5], evt->data.evt_le_connection_opened.address.addr[4], evt->data.evt_le_connection_opened.address.addr[3], evt->data.evt_le_connection_opened.address.addr[2], evt->data.evt_le_connection_opened.address.addr[1], evt->data.evt_le_connection_opened.address.addr[0]); connection_handle = evt->data.evt_le_connection_opened.connection; break; case gecko_evt_le_connection_closed_id: printf("\nDisconnected\n"); rsp = (struct gecko_cmd_packet *)gecko_cmd_le_gap_set_mode(le_gap_general_discoverable, le_gap_undirected_connectable); // Makes sure timer is off when disconnecting rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_set_soft_timer(0, 0, 0); printf("Waiting for connection...\n\n"); break; case gecko_evt_gatt_server_user_read_request_id: printf("Read request\n"); if (evt->data.evt_gatt_server_user_read_request.characteristic == gattdb_indication_control){ printf("Sending ( %c ) to conected device\n", ch); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_read_response( evt->data.evt_gatt_server_user_read_request.connection, evt->data.evt_gatt_server_user_read_request.characteristic, 0x00, /* SUCCESS */ 0x01, /* length */ &ch); if (!rsp->data.rsp_gatt_server_send_user_write_response.result){ printf("Read successful\n"); } else { printf("Read not successful\n"); } } else { printf("Something went wrong\n"); // Request for characteristic which doesn't exist(in this application) } printf("\n"); break; case gecko_evt_gatt_server_user_write_request_id: if (evt->data.evt_gatt_server_user_read_request.characteristic == gattdb_gpio_control){ printf("Write request\n"); if (evt->data.evt_gatt_server_user_write_request.value.len == 1){ if (evt->data.evt_gatt_server_user_write_request.value.data[0] == 0x01){ rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_write_gpio(5, 0x40, 0x00); printf("Led turned ON\n"); } else if (evt->data.evt_gatt_server_user_write_request.value.data[0] == 0x00){ rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_write_gpio(5, 0x40, 0x40); printf("Led turned OFF\n"); } } // Sends success message back(the device might excpect a response) rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_user_write_response( evt->data.evt_gatt_server_user_write_request.connection, evt->data.evt_gatt_server_user_write_request.characteristic, 0x00 /* SUCCESS */); } else { printf("Something went wrong"); // Request for characteristic which doesn't exist(in this application) } printf("\n"); break; case gecko_evt_gatt_server_characteristic_status_id: //printf("Connection trying to change subscription\n"); if (evt->data.evt_gatt_server_characteristic_status.characteristic == gattdb_indication_control){ // 1 means changed subscition, 2 means confirmation has been received. if (evt->data.evt_gatt_server_characteristic_status.status_flags == gatt_server_client_config){ if (evt->data.evt_gatt_server_characteristic_status.client_config_flags & gatt_indication){ subscription_state = 1; printf("Indication enabled\n"); printf("Starting timer..."); // Start timer, 205 is said to be 50ms. Not sure how to set the timer to the right interval. This does not result in 1s. rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_set_soft_timer(205*2*10, 0, 0); if (rsp){ printf("Timer started\n"); } else { printf("Timer not started\n"); } printf("Sending ( %c ) to conected device (indication)\n", ch); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_characteristic_notification( evt->data.evt_gatt_server_characteristic_status.connection, gattdb_indication_control, 1, &ch); } else { subscription_state = 0; printf("Indication disabled\n"); // Stop timer rsp = (struct gecko_cmd_packet *)gecko_cmd_hardware_set_soft_timer(0, 0, 0); } } else { //printf("Confirmed\n"); break; } } else { printf("Something went wrong\n"); // Request for characteristic which doesn't exist(in this application) } printf("\n"); break; // Most printfs are disabled so the console wont be flooded case gecko_evt_hardware_soft_timer_id: //printf("Timer event\n"); // Checks if its from the right timer, handle assigned earlier if (evt->data.evt_hardware_soft_timer.handle == 0){ // This should be true when the program gets here if (subscription_state){ //printf("Sending ( %c ) to conected device (indication)\n", ch); rsp = (struct gecko_cmd_packet *)gecko_cmd_gatt_server_send_characteristic_notification( connection_handle, gattdb_indication_control, 1, &ch); } else { printf("Something went wrong\n"); } } else { printf("Something went wrong\n"); } break; } } return 0; }