summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2015-05-29 00:00:05 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2015-05-29 00:00:05 +0200
commit6d7141db0c73af34fd887fda9723c77aaaf1e349 (patch)
treeef8d2ebf816e70a4a63073700b9097b8467f2380
downloadphone_remote_nrf51-6d7141db0c73af34fd887fda9723c77aaaf1e349.tar.gz
phone_remote_nrf51-6d7141db0c73af34fd887fda9723c77aaaf1e349.tar.bz2
phone_remote_nrf51-6d7141db0c73af34fd887fda9723c77aaaf1e349.tar.xz
phone_remote_nrf51-6d7141db0c73af34fd887fda9723c77aaaf1e349.zip
o Initial import of Phone Remote firmware, forked from the old soil moisture project.
-rw-r--r--.gitignore5
-rw-r--r--LiquidCrystal.c141
-rw-r--r--LiquidCrystal.h19
-rw-r--r--Makefile61
-rw-r--r--main.c429
-rw-r--r--phone_remote.c91
-rw-r--r--phone_remote.h9
7 files changed, 755 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dd4c77b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+build
+.project
+.settings
+.idea
+.cproject
diff --git a/LiquidCrystal.c b/LiquidCrystal.c
new file mode 100644
index 0000000..becc07e
--- /dev/null
+++ b/LiquidCrystal.c
@@ -0,0 +1,141 @@
+#include "LiquidCrystal.h"
+#include "nrf_gpio.h"
+#include "app_timer.h"
+
+/*
+ * Arduino | LCD | nrf51
+ * D4 | DB4 | P0.16
+ * D5 | DB5 | P0.17
+ * D6 | DB6 | P0.18
+ * D7 | DB7 | P0.10
+ * D8 | RS | P0.20, register select. 0=instruction (write), 0=busy (read), 1=data
+ * D9 | EN | P0.23, clock, data is clocked in/out on falling edge
+ * D10 | DB4 | P0.24
+ */
+
+enum liquid_crystal_cmd {
+ LIQUID_CRYSTAL_CMD_CLEAR = 0x01,
+ LIQUID_CRYSTAL_CMD_RETURN_HOME = 0x02,
+ LIQUID_CRYSTAL_CMD_ENTRY_MODE_SET = 0x04,
+ LIQUID_CRYSTAL_CMD_DISPLAY = 0x08,
+ LIQUID_CRYSTAL_CMD_SHIFT = 0x10,
+ LIQUID_CRYSTAL_CMD_FUNCTION_SET = 0x20,
+ LIQUID_CRYSTAL_CMD_SET_CGRAM_ADDDRESS = 0x40,
+ LIQUID_CRYSTAL_CMD_SET_DDRAM_ADDDRESS = 0x80,
+};
+
+static struct {
+ uint8_t pin_db4;
+ uint8_t pin_db5;
+ uint8_t pin_db6;
+ uint8_t pin_db7;
+ uint8_t pin_rs;
+ uint8_t pin_en;
+
+ app_gpiote_user_id_t gpio_user_id;
+} data = { .pin_db4 = 16, .pin_db5 = 17, .pin_db6 = 18, .pin_db7 = 19, .pin_rs =
+ 20, .pin_en = 23, };
+
+static uint32_t ticks_per_ms;
+
+static void event_handler() {
+}
+
+static void wait_ms(uint32_t ms) {
+ uint32_t ticks;
+
+ app_timer_cnt_get(&ticks);
+
+ const uint32_t end_ticks = ticks + ms * ticks_per_ms;
+
+ do {
+ app_timer_cnt_get(&ticks);
+ } while (ticks < end_ticks);
+}
+
+static void write_4(uint8_t value) {
+ nrf_gpio_pin_write(data.pin_db4, value & 0x01);
+ nrf_gpio_pin_write(data.pin_db5, value & 0x02);
+ nrf_gpio_pin_write(data.pin_db6, value & 0x04);
+ nrf_gpio_pin_write(data.pin_db7, value & 0x08);
+
+ nrf_gpio_pin_set(data.pin_en);
+ nrf_gpio_pin_clear(data.pin_en);
+}
+
+static void write_value(uint8_t value, bool is_data) {
+ nrf_gpio_pin_write(data.pin_rs, is_data);
+
+ write_4(value >> 4);
+ write_4(value);
+}
+
+static void begin() {
+ nrf_gpio_pin_clear(data.pin_rs);
+ nrf_gpio_pin_clear(data.pin_en);
+
+ // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
+ // according to datasheet, we need at least 40ms after power rises above 2.7V
+ // before sending commands. Arduino can turn on way before 4.5V so we'll wait 50
+ wait_ms(50);
+
+ write_4(0x03);
+ wait_ms(5); // 4.5ms
+
+ write_4(0x03);
+ wait_ms(5); // 4.5ms
+
+ write_4(0x03);
+ wait_ms(5); // 4.5ms
+
+ write_4(0x02);
+
+ write_value(LIQUID_CRYSTAL_CMD_DISPLAY, false);
+
+// _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
+ liquid_crystal_display(true, true, true);
+}
+
+void liquid_crystal_write_char(char chr) {
+ write_value(chr, true);
+}
+
+void liquid_crystal_write_string(char *chr) {
+ while (*chr != '\0') {
+ liquid_crystal_write_char(*chr);
+ }
+}
+
+uint32_t liquid_crystal_display(bool display_on, bool cursor_on, bool blink) {
+ uint8_t value = LIQUID_CRYSTAL_CMD_DISPLAY;
+
+ value |= display_on ? 0x04 : 0x00;
+ value |= cursor_on ? 0x02 : 0x00;
+ value |= blink ? 0x01 : 0x00;
+
+ write_value(value, false);
+
+ return NRF_SUCCESS;
+}
+
+uint32_t liquid_crystal_init(uint32_t _ticks_per_ms) {
+ ticks_per_ms = _ticks_per_ms;
+
+ uint32_t err_code = app_gpiote_user_register(&data.gpio_user_id, 0x0000,
+ 0x0000, event_handler);
+
+ if (err_code != NRF_SUCCESS) {
+ return err_code;
+ }
+
+ nrf_gpio_cfg_output(data.pin_db4);
+ nrf_gpio_cfg_output(data.pin_db5);
+ nrf_gpio_cfg_output(data.pin_db6);
+ nrf_gpio_cfg_output(data.pin_db7);
+ nrf_gpio_cfg_output(data.pin_rs);
+ nrf_gpio_cfg_output(data.pin_en);
+
+ begin(data);
+
+ return NRF_SUCCESS;
+}
diff --git a/LiquidCrystal.h b/LiquidCrystal.h
new file mode 100644
index 0000000..341d729
--- /dev/null
+++ b/LiquidCrystal.h
@@ -0,0 +1,19 @@
+/*
+ * LiquidCrystal
+ */
+
+#ifndef LIQUIDCRYSTAL_H_
+#define LIQUIDCRYSTAL_H_
+
+#include <stdint.h>
+#include "app_gpiote.h"
+
+uint32_t liquid_crystal_init();
+
+uint32_t liquid_crystal_display(bool display_on, bool cursor_on, bool blink);
+
+void liquid_crystal_write_char(char chr);
+
+void liquid_crystal_write_string(char *chr);
+
+#endif
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..47155d4
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,61 @@
+FLASHER ?= jlink
+BOARD := BOARD_PCA10028
+
+#TARGET_CHIP := NRF51822_QFAA_CA
+#TARGET_CHIP := NRF51422_QFAC_AB
+# nrf51442 - qfac
+#DEVICE_VARIANT := xxac
+USE_SOFTDEVICE = S110
+
+ifeq ($(BOARD),BOARD_PCA10028)
+TARGET_CHIP := NRF51422_QFAC_AB
+DEVICE_VARIANT := xxac
+else ifeq ($(BOARD),BOARD_PCA10031)
+TARGET_CHIP := NRF51422_QFAC_AB
+DEVICE_VARIANT := xxac
+endif
+
+CFLAGS += -DBLE_STACK_SUPPORT_REQD
+CFLAGS += -DSOFTDEVICE_PRESENT
+
+CFLAGS += -D$(USE_SOFTDEVICE)
+
+debug: CFLAGS += -DSM_DEBUG
+debug: CFLAGS += -DENABLE_DEBUG_LOG_SUPPORT
+debug: CFLAGS += -DDM_DISABLE_LOGS
+
+C_SOURCE_FILES += main.c
+C_SOURCE_FILES += phone_remote.c
+C_SOURCE_FILES += LiquidCrystal.c
+
+C_SOURCE_FILES += nrf_assert.c
+C_SOURCE_FILES += nrf_delay.c
+C_SOURCE_FILES += retarget.c
+C_SOURCE_FILES += ble_sensorsim.c
+C_SOURCE_FILES += bsp.c
+C_SOURCE_FILES += app_button.c
+C_SOURCE_FILES += app_error.c
+C_SOURCE_FILES += app_timer.c
+C_SOURCE_FILES += app_gpiote.c
+#C_SOURCE_FILES += app_scheduler.c
+C_SOURCE_FILES += app_trace.c
+C_SOURCE_FILES += app_fifo.c
+C_SOURCE_FILES += app_uart_fifo.c
+C_SOURCE_FILES += pstorage.c
+#C_SOURCE_FILES += ble_hrs.c
+#C_SOURCE_FILES += ble_dis.c
+#C_SOURCE_FILES += ble_bas.c
+C_SOURCE_FILES += ble_conn_params.c
+C_SOURCE_FILES += ble_advdata.c
+C_SOURCE_FILES += ble_srv_common.c
+C_SOURCE_FILES += device_manager_peripheral.c
+C_SOURCE_FILES += softdevice_handler.c
+
+PROJECT_NAME := phone_remote_nrf51
+SDK_SOURCE_PATH = $(SDK_PATH)/components
+SOFTDEVICE_HEX_PATH = $(HOME)/opt/nrf-sdk/s110/s110_nrf51822_7.1.0_softdevice.hex
+
+all: debug
+
+include ~/.nrf51822-posix-build-scripts.mk
+include $(TEMPLATE_PATH)/Makefile.common
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..34b8ae4
--- /dev/null
+++ b/main.c
@@ -0,0 +1,429 @@
+/* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+/** @example examples/ble_peripheral/ble_app_hrs/main.c
+ *
+ * @brief Heart Rate Service Sample Application main file.
+ *
+ * This file contains the source code for a sample application using the Heart Rate service
+ * (and also Battery and Device Information services). This application uses the
+ * @ref srvlib_conn_params module.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "nordic_common.h"
+#include "nrf.h"
+#include "app_error.h"
+#include "nrf51_bitfields.h"
+#include "ble.h"
+#include "ble_hci.h"
+#include "ble_srv_common.h"
+#include "ble_advdata.h"
+#include "ble_gatt.h"
+#include "ble_bas.h"
+#include "ble_hrs.h"
+#include "ble_dis.h"
+#ifdef BLE_DFU_APP_SUPPORT
+#include "ble_dfu.h"
+#include "dfu_app_handler.h"
+#endif // BLE_DFU_APP_SUPPORT
+#include "ble_conn_params.h"
+#include "boards.h"
+#include "ble_sensorsim.h"
+#include "softdevice_handler.h"
+#include "app_timer.h"
+#include "device_manager.h"
+#include "pstorage.h"
+#include "app_trace.h"
+#include "app_timer.h"
+#include "app_gpiote.h"
+#include "app_timer.h"
+#include "bsp.h"
+
+#include "phone_remote.h"
+#include "LiquidCrystal.h"
+
+#include <inttypes.h>
+
+#define dbg printf
+
+#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*/
+
+// BOARD_PCA10031 doesn't have any buttons according to the BSP
+#ifndef BOARD_PCA10031
+#define WAKEUP_BUTTON_ID 0 /**< Button used to wake up the application. */
+#define BOND_DELETE_ALL_BUTTON_ID 1 /**< Button used for deleting all bonded centrals during startup. */
+#endif
+
+#define DEVICE_NAME "Woot-51"
+#define MANUFACTURER_NAME "NordicSemiconductor"
+#define APP_ADV_INTERVAL 40 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 25 ms). */
+#define APP_ADV_TIMEOUT_IN_SECONDS 180 /**< The advertising timeout in units of seconds. */
+
+#define APP_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. */
+#define APP_TIMER_MAX_TIMERS (6+BSP_APP_TIMERS_NUMBER) /**< Maximum number of simultaneously created timers. */
+#define APP_TIMER_OP_QUEUE_SIZE 4 /**< Size of timer operation queues. */
+
+#define SENSOR_CONTACT_DETECTED_INTERVAL APP_TIMER_TICKS(5000, APP_TIMER_PRESCALER) /**< Sensor Contact Detected toggle interval (ticks). */
+
+#define MIN_CONN_INTERVAL MSEC_TO_UNITS(500, UNIT_1_25_MS) /**< Minimum acceptable connection interval (0.5 seconds). */
+#define MAX_CONN_INTERVAL MSEC_TO_UNITS(1000, UNIT_1_25_MS) /**< Maximum acceptable connection interval (1 second). */
+#define SLAVE_LATENCY 0 /**< Slave latency. */
+#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Connection supervisory timeout (4 seconds). */
+
+#define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000, APP_TIMER_PRESCALER) /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
+#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000, APP_TIMER_PRESCALER)/**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
+#define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */
+
+#define SEC_PARAM_TIMEOUT 30 /**< Timeout for Pairing Request or Security Request (in seconds). */
+#define SEC_PARAM_BOND 1 /**< Perform bonding. */
+#define SEC_PARAM_MITM 0 /**< Man In The Middle protection not required. */
+#define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE /**< No I/O capabilities. */
+#define SEC_PARAM_OOB 0 /**< Out Of Band data not available. */
+#define SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */
+#define SEC_PARAM_MAX_KEY_SIZE 16 /**< Maximum encryption key size. */
+
+#define DEAD_BEEF 0xDEADBEEF /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
+
+static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */
+static ble_gap_adv_params_t m_adv_params; /**< Parameters to be passed to the stack when starting advertising. */
+
+static dm_application_instance_t m_app_handle; /**< Application identifier allocated by device manager */
+
+static bool m_memory_access_in_progress = false; /**< Flag to keep track of ongoing operations on persistent memory. */
+
+
+static app_timer_id_t hello_timer;
+
+void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
+{
+ app_error_handler(DEAD_BEEF, line_num, p_file_name);
+}
+
+static uint32_t seconds = 0;
+
+static void hello_timer_handler(void* data)
+{
+ uint32_t ticks;
+ app_timer_cnt_get(&ticks);
+
+ uint32_t ms = (1000 * (1 + APP_TIMER_PRESCALER) * ticks) / APP_TIMER_CLOCK_FREQ;
+
+ seconds++;
+ printf("hello world, seconds=%" PRIu32 ", ticks=%" PRIu32 ", ms=%" PRIu32 "\r\n", seconds, ticks, ms);
+}
+
+static void timers_init(void)
+{
+ uint32_t err_code;
+
+ // Initialize timer module.
+ APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);
+
+ err_code = app_timer_create(&hello_timer, APP_TIMER_MODE_REPEATED, hello_timer_handler);
+ APP_ERROR_CHECK(err_code);
+}
+
+static void timers_start() {
+ uint32_t err_code;
+
+ uint32_t ticks = APP_TIMER_TICKS(1000, APP_TIMER_PRESCALER);
+ err_code = app_timer_start(hello_timer, ticks, NULL);
+ APP_ERROR_CHECK(err_code);
+}
+
+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);
+
+ err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT);
+ 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);
+}
+
+
+static void advertising_init(void)
+{
+ uint32_t err_code;
+ ble_advdata_t advdata;
+ uint8_t flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
+
+ ble_uuid_t adv_uuids[] = {};
+
+ // Build and set advertising data.
+ memset(&advdata, 0, sizeof(advdata));
+
+ advdata.name_type = BLE_ADVDATA_FULL_NAME;
+ advdata.include_appearance = true;
+ advdata.flags.size = sizeof(flags);
+ advdata.flags.p_data = &flags;
+ advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
+ advdata.uuids_complete.p_uuids = adv_uuids;
+
+ err_code = ble_advdata_set(&advdata, NULL);
+ APP_ERROR_CHECK(err_code);
+
+ // Initialize advertising parameters (used when starting advertising).
+ memset(&m_adv_params, 0, sizeof(m_adv_params));
+
+ m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND;
+ m_adv_params.p_peer_addr = NULL; // Undirected advertisement.
+ m_adv_params.fp = BLE_GAP_ADV_FP_ANY;
+ m_adv_params.interval = APP_ADV_INTERVAL;
+ m_adv_params.timeout = APP_ADV_TIMEOUT_IN_SECONDS;
+}
+
+/**@brief Function for initializing services that will be used by the application.
+ *
+ * @details Initialize the Heart Rate, Battery and Device Information services.
+ */
+static void services_init(void)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+// err_code = sm_add_services();
+ APP_ERROR_CHECK(err_code);
+}
+
+static void advertising_start(void)
+{
+ uint32_t err_code;
+ uint32_t count;
+
+ // Verify if there is any flash access pending, if yes delay starting advertising until
+ // it's complete.
+ err_code = pstorage_access_status_get(&count);
+ APP_ERROR_CHECK(err_code);
+
+ if (count != 0)
+ {
+ m_memory_access_in_progress = true;
+ return;
+ }
+
+ err_code = sd_ble_gap_adv_start(&m_adv_params);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
+ APP_ERROR_CHECK(err_code);
+}
+
+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);
+ }
+}
+
+static void conn_params_error_handler(uint32_t nrf_error)
+{
+ APP_ERROR_HANDLER(nrf_error);
+}
+
+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.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);
+}
+
+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;
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ err_code = bsp_indication_set(BSP_INDICATE_IDLE);
+ APP_ERROR_CHECK(err_code);
+ advertising_start();
+ break;
+
+ case BLE_GAP_EVT_TIMEOUT:
+
+ if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT)
+ {
+ printf("re-starting advertisement");
+ advertising_start();
+ /*
+ err_code = bsp_indication_set(BSP_INDICATE_IDLE);
+ APP_ERROR_CHECK(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);
+ */
+ }
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
+{
+// sm_on_ble_evt(p_ble_evt);
+
+ dm_ble_evt_handler(p_ble_evt);
+ on_ble_evt(p_ble_evt);
+}
+
+static void sys_evt_dispatch(uint32_t sys_evt)
+{
+ pstorage_sys_event_handler(sys_evt);
+}
+
+static void ble_stack_init(void)
+{
+ uint32_t err_code;
+
+ // Initialize the SoftDevice handler module.
+ SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);
+
+ ble_enable_params_t ble_enable_params;
+ memset(&ble_enable_params, 0, sizeof(ble_enable_params));
+ ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT;
+ err_code = sd_ble_enable(&ble_enable_params);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
+ APP_ERROR_CHECK(err_code);
+}
+
+static uint32_t device_manager_evt_handler(dm_handle_t const * p_handle,
+ dm_event_t const * p_event,
+ api_result_t event_result)
+{
+ APP_ERROR_CHECK(event_result);
+
+ switch(p_event->event_id)
+ {
+ }
+
+ return NRF_SUCCESS;
+}
+
+static void device_manager_init(void)
+{
+ uint32_t err_code;
+ dm_init_param_t init_data;
+ dm_application_param_t register_param;
+
+ // Initialize persistent storage module.
+ err_code = pstorage_init();
+ APP_ERROR_CHECK(err_code);
+
+ init_data.clear_persistent_data = false; // was true
+
+ err_code = dm_init(&init_data);
+ APP_ERROR_CHECK(err_code);
+
+ memset(&register_param.sec_param, 0, sizeof(ble_gap_sec_params_t));
+
+ register_param.sec_param.timeout = SEC_PARAM_TIMEOUT;
+ 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, &register_param);
+ APP_ERROR_CHECK(err_code);
+}
+
+static void power_manage(void)
+{
+ uint32_t err_code = sd_app_evt_wait();
+ APP_ERROR_CHECK(err_code);
+}
+
+int main(void)
+{
+ app_trace_init();
+
+ dbg("Soil Moisture device starting...\r\n");
+
+ ble_stack_init();
+ timers_init();
+
+ APP_GPIOTE_INIT(2);
+
+ uint32_t err_code = bsp_init(BSP_INIT_LED | BSP_INIT_BUTTONS, APP_TIMER_TICKS(100, APP_TIMER_PRESCALER), NULL);
+ APP_ERROR_CHECK(err_code);
+
+// device_manager_init();
+// gap_params_init();
+// advertising_init();
+// services_init();
+// conn_params_init();
+
+ timers_start();
+
+ liquid_crystal_init(APP_TIMER_TICKS(1, APP_TIMER_PRESCALER));
+ liquid_crystal_write_string("hello world!");
+
+ advertising_start();
+
+ for (;; )
+ {
+ power_manage();
+ }
+}
diff --git a/phone_remote.c b/phone_remote.c
new file mode 100644
index 0000000..c37123a
--- /dev/null
+++ b/phone_remote.c
@@ -0,0 +1,91 @@
+#include "phone_remote.h"
+#include "ble.h"
+#include "nrf_error.h"
+#include "nrf_gpio.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+// 32D0xxxx-035D-59C5-70D3-BC8E4A1FD83F
+#define TRYGVIS_IO_UUID_BASE {0x3f, 0xd8, 0x1f, 0x4a, 0x8e, 0xbc, 0xd3, 0x70, 0xc5, 0x59, 0x5d, 0x03, 0, 0, 0xd0, 0x32}
+
+#define TRYGVIS_IO_UUID_SERVICE_PHONE_REMOTE 0x0020
+#define TRYGVIS_IO_UUID_CHARACTERISTIC_PHONE_REMOTE_BUTTON 0x0021
+
+static uint8_t trygvis_io_uuid_type;
+static uint16_t pr_service_handle;
+static ble_gatts_char_handles_t pr_char_handle;
+
+static uint16_t conn_handle = BLE_CONN_HANDLE_INVALID;
+
+// The value of the soil moisture control characteristic.
+static uint8_t control_value[100] = {1, 2, 3};
+
+#define dbg printf
+
+uint32_t pr_add_services() {
+ uint32_t err_code;
+
+ dbg("pr: pr_add_services\r\n");
+
+ ble_uuid128_t base_uuid = {TRYGVIS_IO_UUID_BASE};
+ err_code = sd_ble_uuid_vs_add(&base_uuid, &trygvis_io_uuid_type);
+ if (err_code != NRF_SUCCESS) {
+ return err_code;
+ }
+
+ // -------------------------------------------------------------------------
+ // Service
+ // -------------------------------------------------------------------------
+
+ ble_uuid_t ble_uuid_svc = {
+ .type = trygvis_io_uuid_type,
+ .uuid = TRYGVIS_IO_UUID_SERVICE_PHONE_REMOTE
+ };
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid_svc, &pr_service_handle);
+ if (err_code != NRF_SUCCESS) {
+ return err_code;
+ }
+
+ // -------------------------------------------------------------------------
+ // Characteristic
+ // -------------------------------------------------------------------------
+
+ ble_gatts_char_md_t char_md;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.write = 1;
+ char_md.char_props.notify = 1;
+
+ ble_uuid_t ble_uuid_chr = {
+ .type = trygvis_io_uuid_type,
+ .uuid = TRYGVIS_IO_UUID_CHARACTERISTIC_PHONE_REMOTE_BUTTON
+ };
+
+ ble_gatts_attr_md_t attr_md;
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
+ attr_md.vlen = 1;
+ attr_md.vloc = BLE_GATTS_VLOC_USER;
+
+ ble_gatts_attr_t attr_char_value;
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid_chr;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = 3;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof(control_value);
+ attr_char_value.p_value = control_value;
+
+ return sd_ble_gatts_characteristic_add(pr_service_handle,
+ &char_md,
+ &attr_char_value,
+ &pr_char_handle);
+}
diff --git a/phone_remote.h b/phone_remote.h
new file mode 100644
index 0000000..6437cbc
--- /dev/null
+++ b/phone_remote.h
@@ -0,0 +1,9 @@
+#ifndef PHONE_REMOTE_H_
+#define PHONE_REMOTE_H_
+
+#include "ble.h"
+
+uint32_t pr_add_services();
+void pr_on_ble_evt(ble_evt_t* ble_evt);
+
+#endif