/* * This example is not extensively tested and only * meant as a simple explanation and for inspiration. * NO WARRANTY of ANY KIND is provided. */ #include #include #include "nordic_common.h" #include "nrf.h" #include "app_error.h" #include "ble.h" #include "ble_hci.h" #include "ble_srv_common.h" #include "ble_advdata.h" #include "ble_advertising.h" #include "ble_conn_params.h" #include "boards.h" #include "softdevice_handler.h" #include "app_timer.h" #include "device_manager.h" #include "pstorage.h" #include "app_trace.h" #include "bsp.h" #include "app_uart.h" #include "app_mpu.h" #include "ble_mpu.h" #include #include "nrf_drv_pwm.h" #include "app_util_platform.h" #include "app_timer.h" #include "nrf_drv_clock.h" #include "nrf_delay.h" #define IS_SRVC_CHANGED_CHARACT_PRESENT 0 /**< Include or not the service_changed characteristic. if not enabled, the server's database cannot be changed for the lifetime of the device*/ #define CENTRAL_LINK_COUNT 0 /**= 100) { seq_values->channel_0 = 100; } else { seq_values->channel_0 = duty_cycle; } nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP); } static void pwm_init(void) { uint32_t err_code; nrf_drv_pwm_config_t const config0 = { .output_pins = { 17 , // channel 0 18 , // channel 1 19 , // channel 2 20 // channel 3 }, .irq_priority = APP_IRQ_PRIORITY_LOWEST, .base_clock = NRF_PWM_CLK_16MHz, .count_mode = NRF_PWM_MODE_UP, .top_value = 100, .load_mode = NRF_PWM_LOAD_INDIVIDUAL, .step_mode = NRF_PWM_STEP_AUTO }; err_code = nrf_drv_pwm_init(&m_pwm0, &config0, NULL); APP_ERROR_CHECK(err_code); m_used |= USED_PWM(0); // This array cannot be allocated on stack (hence "static") and it must // be in RAM (hence no "const", though its content is not changed). nrf_pwm_sequence_t const seq = { .values.p_individual = seq_values, .length = NRF_PWM_VALUES_LENGTH(seq_values), .repeats = 0, .end_delay = 0 }; nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP); } ble_mpu_t m_mpu; bool start_accel_update_flag = false; APP_TIMER_DEF(m_timer_accel_update_id); #define TIMER_INTERVAL_ACCEL_UPDATE APP_TIMER_TICKS(1000, APP_TIMER_PRESCALER) // 1000 ms intervals /**@brief Callback function for asserts in the SoftDevice. * * @details This function will be called in case of an assert in the SoftDevice. * * @warning This handler is an example only and does not fit a final product. You need to analyze * how your product is supposed to react in case of Assert. * @warning On assert from the SoftDevice, the system can only recover on reset. * * @param[in] line_num Line number of the failing ASSERT call. * @param[in] file_name File name of the failing ASSERT call. */ void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) { app_error_handler(DEAD_BEEF, line_num, p_file_name); } void timer_accel_update_handler(void * p_context) { start_accel_update_flag = true; } /**@brief Function for the Timer initialization. * * @details Initializes the timer module. This creates and starts application timers. */ static void timers_init(void) { // Initialize timer module. APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false); uint32_t err_code; err_code = app_timer_create(&m_timer_accel_update_id, APP_TIMER_MODE_REPEATED, timer_accel_update_handler); APP_ERROR_CHECK(err_code); } /**@brief Function for the GAP initialization. * * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the * device including the device name, appearance, and the preferred connection parameters. */ static void gap_params_init(void) { uint32_t err_code; ble_gap_conn_params_t gap_conn_params; ble_gap_conn_sec_mode_t sec_mode; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME)); APP_ERROR_CHECK(err_code); memset(&gap_conn_params, 0, sizeof(gap_conn_params)); gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL; gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL; gap_conn_params.slave_latency = SLAVE_LATENCY; gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; err_code = sd_ble_gap_ppcp_set(&gap_conn_params); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing services that will be used by the application. */ static void services_init(void) { ble_mpu_service_init(&m_mpu); } /**@brief Function for handling the Connection Parameters Module. * * @details This function will be called for all events in the Connection Parameters Module which * are passed to the application. * @note All this function does is to disconnect. This could have been done by simply * setting the disconnect_on_fail config parameter, but instead we use the event * handler mechanism to demonstrate its use. * * @param[in] p_evt Event received from the Connection Parameters Module. */ static void on_conn_params_evt(ble_conn_params_evt_t * p_evt) { uint32_t err_code; if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED) { err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE); APP_ERROR_CHECK(err_code); } } /**@brief Function for handling a Connection Parameters error. * * @param[in] nrf_error Error code containing information about what went wrong. */ static void conn_params_error_handler(uint32_t nrf_error) { APP_ERROR_HANDLER(nrf_error); } /**@brief Function for initializing the Connection Parameters module. */ static void conn_params_init(void) { uint32_t err_code; ble_conn_params_init_t cp_init; memset(&cp_init, 0, sizeof(cp_init)); cp_init.p_conn_params = NULL; cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY; cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY; cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT; cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID; cp_init.disconnect_on_fail = false; cp_init.evt_handler = on_conn_params_evt; cp_init.error_handler = conn_params_error_handler; err_code = ble_conn_params_init(&cp_init); APP_ERROR_CHECK(err_code); } /**@brief Function for starting timers. */ static void application_timers_start(void) { // uint32_t err_code; // err_code = app_timer_start(m_timer_accel_update_id, TIMER_INTERVAL_ACCEL_UPDATE, NULL); // APP_ERROR_CHECK(err_code); } /**@brief Function for putting the chip into sleep mode. * * @note This function will not return. */ static void sleep_mode_enter(void) { uint32_t err_code; // Go to system-off mode (this function will not return; wakeup will cause a reset). err_code = sd_power_system_off(); APP_ERROR_CHECK(err_code); } /**@brief Function for handling advertising events. * * @details This function will be called for advertising events which are passed to the application. * * @param[in] ble_adv_evt Advertising event. */ static void on_adv_evt(ble_adv_evt_t ble_adv_evt) { uint32_t err_code; switch (ble_adv_evt) { case BLE_ADV_EVT_FAST: err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING); APP_ERROR_CHECK(err_code); break; case BLE_ADV_EVT_IDLE: sleep_mode_enter(); break; default: break; } } /**@brief Function for handling the Application's BLE Stack events. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_evt(ble_evt_t * p_ble_evt) { uint32_t err_code; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: err_code = bsp_indication_set(BSP_INDICATE_CONNECTED); APP_ERROR_CHECK(err_code); m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; err_code = app_timer_start(m_timer_accel_update_id, TIMER_INTERVAL_ACCEL_UPDATE, NULL); APP_ERROR_CHECK(err_code); break; case BLE_GAP_EVT_DISCONNECTED: m_conn_handle = BLE_CONN_HANDLE_INVALID; app_timer_stop(m_timer_accel_update_id); break; default: // No implementation needed. break; } } /**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler. * * @details This function is called from the BLE Stack event interrupt handler after a BLE stack * event has been received. * * @param[in] p_ble_evt Bluetooth stack event. */ static void ble_evt_dispatch(ble_evt_t * p_ble_evt) { dm_ble_evt_handler(p_ble_evt); ble_conn_params_on_ble_evt(p_ble_evt); on_ble_evt(p_ble_evt); ble_advertising_on_ble_evt(p_ble_evt); ble_mpu_on_ble_evt(&m_mpu, p_ble_evt); } /**@brief Function for dispatching a system event to interested modules. * * @details This function is called from the System event interrupt handler after a system * event has been received. * * @param[in] sys_evt System stack event. */ static void sys_evt_dispatch(uint32_t sys_evt) { pstorage_sys_event_handler(sys_evt); ble_advertising_on_sys_evt(sys_evt); } /**@brief Function for initializing the BLE stack. * * @details Initializes the SoftDevice and the BLE event interrupt. */ static void ble_stack_init(void) { uint32_t err_code; nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC; // Initialize the SoftDevice handler module. SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL); ble_enable_params_t ble_enable_params; err_code = softdevice_enable_get_default_config(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT, &ble_enable_params); APP_ERROR_CHECK(err_code); //Check the ram settings against the used number of links CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT,PERIPHERAL_LINK_COUNT); // Enable BLE stack. err_code = softdevice_enable(&ble_enable_params); APP_ERROR_CHECK(err_code); // Register with the SoftDevice handler module for BLE events. err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch); APP_ERROR_CHECK(err_code); // Register with the SoftDevice handler module for BLE events. err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch); APP_ERROR_CHECK(err_code); } /**@brief Function for handling events from the BSP module. * * @param[in] event Event generated by button press. */ void bsp_event_handler(bsp_event_t event) { uint32_t err_code; switch (event) { case BSP_EVENT_SLEEP: sleep_mode_enter(); break; case BSP_EVENT_DISCONNECT: err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } break; case BSP_EVENT_WHITELIST_OFF: err_code = ble_advertising_restart_without_whitelist(); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } break; default: break; } } /**@brief Function for handling the Device Manager events. * * @param[in] p_evt Data associated to the device manager event. */ static uint32_t device_manager_evt_handler(dm_handle_t const * p_handle, dm_event_t const * p_event, ret_code_t event_result) { APP_ERROR_CHECK(event_result); #ifdef BLE_DFU_APP_SUPPORT if (p_event->event_id == DM_EVT_LINK_SECURED) { app_context_load(p_handle); } #endif // BLE_DFU_APP_SUPPORT return NRF_SUCCESS; } /**@brief Function for the Device Manager initialization. * * @param[in] erase_bonds Indicates whether bonding information should be cleared from * persistent storage during initialization of the Device Manager. */ static void device_manager_init(bool erase_bonds) { uint32_t err_code; dm_init_param_t init_param = {.clear_persistent_data = erase_bonds}; dm_application_param_t register_param; // Initialize persistent storage module. err_code = pstorage_init(); APP_ERROR_CHECK(err_code); err_code = dm_init(&init_param); APP_ERROR_CHECK(err_code); memset(®ister_param.sec_param, 0, sizeof(ble_gap_sec_params_t)); register_param.sec_param.bond = SEC_PARAM_BOND; register_param.sec_param.mitm = SEC_PARAM_MITM; register_param.sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES; register_param.sec_param.oob = SEC_PARAM_OOB; register_param.sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE; register_param.sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE; register_param.evt_handler = device_manager_evt_handler; register_param.service_type = DM_PROTOCOL_CNTXT_GATT_SRVR_ID; err_code = dm_register(&m_app_handle, ®ister_param); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the Advertising functionality. */ static void advertising_init(void) { uint32_t err_code; ble_advdata_t advdata; // Build advertising data struct to pass into @ref ble_advertising_init. memset(&advdata, 0, sizeof(advdata)); advdata.name_type = BLE_ADVDATA_FULL_NAME; advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; ble_adv_modes_config_t options = {0}; options.ble_adv_fast_enabled = BLE_ADV_FAST_ENABLED; options.ble_adv_fast_interval = APP_ADV_INTERVAL; options.ble_adv_fast_timeout = APP_ADV_TIMEOUT_IN_SECONDS; err_code = ble_advertising_init(&advdata, NULL, &options, on_adv_evt, NULL); APP_ERROR_CHECK(err_code); } /**@brief Function for the Power manager. */ static void power_manage(void) { uint32_t err_code = sd_app_evt_wait(); APP_ERROR_CHECK(err_code); } /** * @brief UART events handler. */ static void uart_events_handler(app_uart_evt_t * p_event) { switch (p_event->evt_type) { case APP_UART_COMMUNICATION_ERROR: APP_ERROR_HANDLER(p_event->data.error_communication); break; case APP_UART_FIFO_ERROR: APP_ERROR_HANDLER(p_event->data.error_code); break; default: break; } } /** * @brief UART initialization. * Just the usual way. Nothing special here */ static void uart_init(void) { uint32_t err_code; const app_uart_comm_params_t comm_params = { RX_PIN_NUMBER, TX_PIN_NUMBER, RTS_PIN_NUMBER, CTS_PIN_NUMBER, APP_UART_FLOW_CONTROL_DISABLED, false, UART_BAUDRATE_BAUDRATE_Baud115200 }; APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_events_handler, APP_IRQ_PRIORITY_LOW, err_code); APP_ERROR_CHECK(err_code); } void mpu_setup(void) { ret_code_t ret_code; // Initiate MPU driver ret_code = mpu_init(); APP_ERROR_CHECK(ret_code); // Check for errors in return value // Setup and configure the MPU with intial values mpu_config_t p_mpu_config = MPU_DEFAULT_CONFIG(); // Load default values p_mpu_config.smplrt_div = 19; // Change sampelrate. Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV). 19 gives a sample rate of 50Hz p_mpu_config.accel_config.afs_sel = AFS_2G; // Set accelerometer full scale range to 2G ret_code = mpu_config(&p_mpu_config); // Configure the MPU with above values APP_ERROR_CHECK(ret_code); // Check for errors in return value } /**@brief Function for application main entry. */ int main(void) { uint32_t err_code; bool erase_bonds; //LEDS_CONFIGURE(LEDS_MASK); //LEDS_OFF(LEDS_MASK); uart_init(); // printf("\n Riosh technologies \n"); // Initialize. timers_init(); ble_stack_init(); device_manager_init(erase_bonds); gap_params_init(); advertising_init(); services_init(); conn_params_init(); mpu_setup(); pwm_init(); // Start execution. application_timers_start(); err_code = ble_advertising_start(BLE_ADV_MODE_FAST); APP_ERROR_CHECK(err_code); accel_values_t accel_values; // Enter main loop. for (;;) { power_manage(); if(start_accel_update_flag == true) { mpu_read_accel(&accel_values); printf("\033[2J\033[;HAccel: %05d, %05d, %05d\r\n", accel_values.x, accel_values.y, accel_values.z); printf("Accel: %#02x, %#02x, %#02x, %#02x, %#02x, %#02x\r\n", (uint8_t)(accel_values.x >> 8), (uint8_t)accel_values.x, (uint8_t)(accel_values.y >> 8), (uint8_t)accel_values.y, (uint8_t)(accel_values.z >> 8), (uint8_t)accel_values.z); ble_mpu_update(&m_mpu, &accel_values); start_accel_update_flag = false; //nrf_gpio_pin_toggle(LED_4); if(accel_values.x > 0000 && accel_values.x < 8000) { for(int i = 0; i <= 100; i++) { pwm_update_duty_cycle(0); } } if(accel_values.x > 8000 && accel_values.x < 10000) { for(int i = 0; i <= 100; i++) { pwm_update_duty_cycle(25); } } if(accel_values.x > 10000 && accel_values.x < 12000) { for(int i = 0; i <= 100; i++) { pwm_update_duty_cycle(50); } } if(accel_values.x > 12000 && accel_values.x < 14000) { for(int i = 0; i <= 100; i++) { pwm_update_duty_cycle(75); } } if(accel_values.x > 14000 && accel_values.x < 16000) { for(int i = 0; i <= 100; i++) { pwm_update_duty_cycle(100); } } } } } /** * @} */