diff options
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | README.md | 9 | ||||
-rw-r--r-- | app.cpp | 91 | ||||
-rw-r--r-- | app.h | 66 | ||||
-rw-r--r-- | services.h | 213 | ||||
-rw-r--r-- | services_lock.h | 217 | ||||
-rw-r--r-- | trygvisio_soil_moisture.ino | 420 | ||||
-rw-r--r-- | trygvisio_soil_moisture.xml | 167 |
8 files changed, 1193 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d52f7b7 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +BOARD_TAG = leonardo +#BOARD_TAG = blendmicro16 +#DEVICE_PORT = /dev/ttyACM0 +MONITOR_BAUDRATE = 115200 +MONITOR_PORT ?= /dev/ttyACM0 + +ARDUINO_LIBS = BLE SPI + +ARDMK_DIR ?= /usr/share/arduino +include $(ARDMK_DIR)/Arduino.mk diff --git a/README.md b/README.md new file mode 100644 index 0000000..428ce70 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Endpoints + +## Soil Moisture + +### Soil Moisture Level + +Format: two bytes of data. Byte #1: sensor id, byte #2: sensor level (unsigned int, 0-255). + +Sends notices, same data format. @@ -0,0 +1,91 @@ +#include "app.h" + +#include <Arduino.h> +#include <HardwareSerial.h> + +// http://bleaklow.com/2010/09/05/progmem_and_gcc_bug_34734.html +#undef PROGMEM +#define PROGMEM __attribute__((section(".progmem.data"))) + +#define SENSOR_COUNT 1 + +// See http://redbearlab.com/blendmicro/ +struct sm_sensor { + uint8_t pin; + uint8_t value; +} gauges[SENSOR_COUNT] = { + { 9, 0}, +}; + +void on_loop() { + static unsigned long last = 0, now; + + static uint8_t x = 10; + + now = millis(); + if (now - last > 3000) { + last = now; + sm_res data; + data.len = sizeof(struct sm_get_sensor_level_res); + data.code = SM_CMD_GET_SENSOR_LEVEL; + data.get_sensor_level.level = x; + x++; + if(x == 0) { + x = 10; + } + + if(x % 2 == 0) { + notify_soil_moisture(&data); + } else { + notify_battery_level(x); + } + } +} + +void on_soil_moisture(uint8_t *data, uint8_t len) { + Serial.print(F("on_soil_moisture, data[0]=")); + Serial.print(data[0], HEX); + Serial.print(F(", data[1]=")); + Serial.println(data[1], HEX); + + struct sm_req *cmd = (struct sm_req *) data; + struct sm_res res; + + res.code = cmd->code; + + Serial.print("code="); + Serial.println(cmd->code, DEC); + + switch(cmd->code) { + case SM_CMD_GET_SENSOR_COUNT: + res.len = sizeof(struct sm_get_sensor_count_res); + res.get_sensor_count.count = SENSOR_COUNT; + break; + case SM_CMD_SET_SENSOR_THRESHOLD: +// res.len = sizeof(struct fsp_set_gauge_res); +// if (cmd->set_gauge.gauge < GAUGE_COUNT) { +// analogWrite(gauges[cmd->set_gauge.gauge].pin, cmd->set_gauge.value); +// gauges[cmd->set_gauge.gauge].value = cmd->set_gauge.value; +// } + + break; + case SM_CMD_GET_SENSOR_LEVEL: +// res.len = sizeof(struct fsp_get_gauge_res); +// if (cmd->get_gauge.gauge < GAUGE_COUNT) { +// res.get_gauge.gauge = cmd->get_gauge.gauge; +// res.get_gauge.value = gauges[cmd->get_gauge.gauge].value; +// } else { +// res.code = FSP_CMD_FAIL; +// res.len = 0; +// } + break; + default: + res.code = SM_CMD_FAIL; + res.len = 0; + break; + } + +// tx_soil_moisture(&res); +} + + @@ -0,0 +1,66 @@ +#ifndef APP_H +#define APP_H + +#include <stdint.h> + +enum sm_cmd_code { + SM_CMD_GET_SENSOR_COUNT = 1, + SM_CMD_SET_SENSOR_THRESHOLD = 2, + SM_CMD_GET_SENSOR_LEVEL = 3, + SM_CMD_FAIL = 255, +}; + +struct sm_get_sensor_count_req { +}; + +struct sm_get_sensor_count_res { + uint8_t count; +}; + +struct sm_set_sensor_threshold_req { + uint8_t sensor; + uint8_t threshold; +}; + +struct sm_set_sensor_threshold_res { +}; + +struct sm_get_sensor_level_req { + uint8_t sensor; +}; + +struct sm_get_sensor_level_res { + uint8_t sensor; + uint8_t level; +}; + +struct sm_req { + uint8_t code; + union { + struct sm_get_sensor_count_req get_sensor_count; + struct sm_get_sensor_level_req get_sensor_level; + struct sm_set_sensor_threshold_req set_sensor_threshold; + }; +}; + +struct sm_res { + uint8_t len; + uint8_t code; + union { + struct sm_get_sensor_count_res get_sensor_count; + struct sm_get_sensor_level_res get_sensor_level; + struct sm_set_sensor_threshold_res set_sensor_threshold; + }; +}; + +void on_loop(); + +bool tx_soil_moisture(struct sm_res *res); +void notify_soil_moisture(struct sm_res *res); +void notify_battery_level(uint8_t value); + +void on_soil_moisture(uint8_t *data, uint8_t len); + +#endif + + diff --git a/services.h b/services.h new file mode 100644 index 0000000..0344b5f --- /dev/null +++ b/services.h @@ -0,0 +1,213 @@ +/** +* This file is autogenerated by nRFgo Studio 1.17.1.3252 +*/ + +#ifndef SETUP_MESSAGES_H__ +#define SETUP_MESSAGES_H__ + +#include "hal_platform.h" +#include "aci.h" + + +#define SETUP_ID 0 +#define SETUP_FORMAT 3 /** nRF8001 D */ +#define ACI_DYNAMIC_DATA_SIZE 165 + +/* Service: Gap - Characteristic: Device name - Pipe: SET */ +#define PIPE_GAP_DEVICE_NAME_SET 1 +#define PIPE_GAP_DEVICE_NAME_SET_MAX_SIZE 10 + +/* Service: Battery - Characteristic: Battery Level - Pipe: BROADCAST */ +#define PIPE_BATTERY_BATTERY_LEVEL_BROADCAST 2 +#define PIPE_BATTERY_BATTERY_LEVEL_BROADCAST_MAX_SIZE 1 + +/* Service: Battery - Characteristic: Battery Level - Pipe: TX */ +#define PIPE_BATTERY_BATTERY_LEVEL_TX 3 +#define PIPE_BATTERY_BATTERY_LEVEL_TX_MAX_SIZE 1 + +/* Service: Battery - Characteristic: Battery Level - Pipe: SET */ +#define PIPE_BATTERY_BATTERY_LEVEL_SET 4 +#define PIPE_BATTERY_BATTERY_LEVEL_SET_MAX_SIZE 1 + +/* Service: Battery - Characteristic: Battery Power State - Pipe: SET */ +#define PIPE_BATTERY_BATTERY_POWER_STATE_SET 5 +#define PIPE_BATTERY_BATTERY_POWER_STATE_SET_MAX_SIZE 1 + +/* Service: Battery - Characteristic: Battery Level State - Pipe: SET */ +#define PIPE_BATTERY_BATTERY_LEVEL_STATE_SET 6 +#define PIPE_BATTERY_BATTERY_LEVEL_STATE_SET_MAX_SIZE 2 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: BROADCAST */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_BROADCAST 7 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_BROADCAST_MAX_SIZE 5 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: TX */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_TX 8 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_TX_MAX_SIZE 5 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: SET */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_SET 9 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_SET_MAX_SIZE 5 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: BROADCAST */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_BROADCAST_1 10 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_BROADCAST_1_MAX_SIZE 5 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: TX */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_TX_1 11 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_TX_1_MAX_SIZE 5 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: SET */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_SET_1 12 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_SET_1_MAX_SIZE 5 + + +#define NUMBER_OF_PIPES 12 + +#define SERVICES_PIPE_TYPE_MAPPING_CONTENT {\ + {ACI_STORE_LOCAL, ACI_SET}, \ + {ACI_STORE_LOCAL, ACI_TX_BROADCAST}, \ + {ACI_STORE_LOCAL, ACI_TX}, \ + {ACI_STORE_LOCAL, ACI_SET}, \ + {ACI_STORE_LOCAL, ACI_SET}, \ + {ACI_STORE_LOCAL, ACI_SET}, \ + {ACI_STORE_LOCAL, ACI_TX_BROADCAST}, \ + {ACI_STORE_LOCAL, ACI_TX}, \ + {ACI_STORE_LOCAL, ACI_SET}, \ + {ACI_STORE_LOCAL, ACI_TX_BROADCAST}, \ + {ACI_STORE_LOCAL, ACI_TX}, \ + {ACI_STORE_LOCAL, ACI_SET}, \ +} + +#define GAP_PPCP_MAX_CONN_INT 0xffff /**< Maximum connection interval as a multiple of 1.25 msec , 0xFFFF means no specific value requested */ +#define GAP_PPCP_MIN_CONN_INT 0xffff /**< Minimum connection interval as a multiple of 1.25 msec , 0xFFFF means no specific value requested */ +#define GAP_PPCP_SLAVE_LATENCY 0 +#define GAP_PPCP_CONN_TIMEOUT 0xffff /** Connection Supervision timeout multiplier as a multiple of 10msec, 0xFFFF means no specific value requested */ + +#define NB_SETUP_MESSAGES 21 +#define SETUP_MESSAGES_CONTENT {\ + {0x00,\ + {\ + 0x07,0x06,0x00,0x00,0x03,0x02,0x42,0x07,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0c,0x01,0x01,0x00,0x00,0x06,0x00,0x01,\ + 0x81,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x10,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x90,0x00,0xff,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x10,0x38,0xff,0xff,0x02,0x58,0x0a,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x05,0x06,0x10,0x54,0x00,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x00,0x04,0x04,0x02,0x02,0x00,0x01,0x28,0x00,0x01,0x00,0x18,0x04,0x04,0x05,0x05,0x00,\ + 0x02,0x28,0x03,0x01,0x0e,0x03,0x00,0x00,0x2a,0x04,0x14,0x0a,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x1c,0x03,0x00,0x03,0x2a,0x00,0x01,0x77,0x61,0x74,0x64,0x69,0x63,0x73,0x65,0x6d,0x69,\ + 0x04,0x04,0x05,0x05,0x00,0x04,0x28,0x03,0x01,0x02,0x05,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x38,0x01,0x2a,0x06,0x04,0x03,0x02,0x00,0x05,0x2a,0x01,0x01,0x00,0x00,0x04,0x04,0x05,\ + 0x05,0x00,0x06,0x28,0x03,0x01,0x02,0x07,0x00,0x04,0x2a,0x06,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x54,0x04,0x09,0x08,0x00,0x07,0x2a,0x04,0x01,0xff,0xff,0xff,0xff,0x00,0x00,0xff,0xff,\ + 0x04,0x04,0x02,0x02,0x00,0x08,0x28,0x00,0x01,0x01,0x18,0x04,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x70,0x04,0x02,0x02,0x00,0x09,0x28,0x00,0x01,0x0f,0x18,0x04,0x04,0x05,0x05,0x00,0x0a,\ + 0x28,0x03,0x01,0x12,0x0b,0x00,0x19,0x2a,0x16,0x04,0x02,0x01,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x8c,0x00,0x0b,0x2a,0x19,0x01,0x10,0x46,0x14,0x03,0x02,0x00,0x0c,0x29,0x02,0x01,0x00,\ + 0x00,0x04,0x04,0x05,0x05,0x00,0x0d,0x28,0x03,0x01,0x02,0x0e,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0xa8,0x00,0x1a,0x2a,0x06,0x04,0x02,0x01,0x00,0x0e,0x2a,0x1a,0x01,0x00,0x04,0x04,0x05,\ + 0x05,0x00,0x0f,0x28,0x03,0x01,0x02,0x10,0x00,0x1b,0x2a,0x06,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0xc4,0x04,0x03,0x02,0x00,0x10,0x2a,0x1b,0x01,0x00,0x00,0x04,0x04,0x02,0x02,0x00,0x11,\ + 0x28,0x00,0x01,0x10,0x00,0x04,0x04,0x05,0x05,0x00,0x12,0x28,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0xe0,0x03,0x01,0x12,0x13,0x00,0x11,0x00,0x16,0x04,0x06,0x05,0x00,0x13,0x00,0x11,0x01,\ + 0xaa,0x55,0xaa,0x55,0xaa,0x46,0x14,0x03,0x02,0x00,0x14,0x29,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0xfc,0x02,0x01,0x00,0x00,0x04,0x04,0x02,0x02,0x00,0x15,0x28,0x00,0x01,0x10,0x00,0x04,\ + 0x04,0x05,0x05,0x00,0x16,0x28,0x03,0x01,0x12,0x17,0x00,0x11,\ + },\ + },\ + {0x00,\ + {\ + 0x1e,0x06,0x21,0x18,0x00,0x14,0x04,0x05,0x00,0x00,0x17,0x00,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x46,\ + 0x14,0x03,0x02,0x00,0x18,0x29,0x02,0x01,0x00,0x00,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x40,0x00,0x2a,0x00,0x01,0x00,0x80,0x04,0x00,0x03,0x00,0x00,0x2a,0x19,0x01,0x00,0x83,0x04,\ + 0x00,0x0b,0x00,0x0c,0x2a,0x1a,0x01,0x00,0x80,0x04,0x00,0x0e,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x40,0x1c,0x00,0x00,0x2a,0x1b,0x01,0x00,0x80,0x04,0x00,0x10,0x00,0x00,0x00,0x11,0x01,0x00,\ + 0x83,0x04,0x00,0x13,0x00,0x14,0x00,0x11,0x01,0x00,0x83,0x04,\ + },\ + },\ + {0x00,\ + {\ + 0x07,0x06,0x40,0x38,0x00,0x17,0x00,0x18,\ + },\ + },\ + {0x00,\ + {\ + 0x15,0x06,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x06,0x06,0xf0,0x00,0x03,0xda,0x64,\ + },\ + },\ +} + +#endif diff --git a/services_lock.h b/services_lock.h new file mode 100644 index 0000000..fe0057a --- /dev/null +++ b/services_lock.h @@ -0,0 +1,217 @@ +/** +* This file is autogenerated by nRFgo Studio 1.17.1.3252 +*/ + +#ifndef SETUP_MESSAGES_H__ +#define SETUP_MESSAGES_H__ + +#include "hal_platform.h" +#include "aci.h" + +// You have now chosen to upload the configuration to OTP on the device. +// This will result in a device that you can not modify afterwards. If this is your intention, +// remove this comment and the #error below +#error Generating configuration for OTP. Please verify usage by removing this error message from include file. + +#define SETUP_ID 0 +#define SETUP_FORMAT 3 /** nRF8001 D */ +#define ACI_DYNAMIC_DATA_SIZE 165 + +/* Service: Gap - Characteristic: Device name - Pipe: SET */ +#define PIPE_GAP_DEVICE_NAME_SET 1 +#define PIPE_GAP_DEVICE_NAME_SET_MAX_SIZE 10 + +/* Service: Battery - Characteristic: Battery Level - Pipe: BROADCAST */ +#define PIPE_BATTERY_BATTERY_LEVEL_BROADCAST 2 +#define PIPE_BATTERY_BATTERY_LEVEL_BROADCAST_MAX_SIZE 1 + +/* Service: Battery - Characteristic: Battery Level - Pipe: TX */ +#define PIPE_BATTERY_BATTERY_LEVEL_TX 3 +#define PIPE_BATTERY_BATTERY_LEVEL_TX_MAX_SIZE 1 + +/* Service: Battery - Characteristic: Battery Level - Pipe: SET */ +#define PIPE_BATTERY_BATTERY_LEVEL_SET 4 +#define PIPE_BATTERY_BATTERY_LEVEL_SET_MAX_SIZE 1 + +/* Service: Battery - Characteristic: Battery Power State - Pipe: SET */ +#define PIPE_BATTERY_BATTERY_POWER_STATE_SET 5 +#define PIPE_BATTERY_BATTERY_POWER_STATE_SET_MAX_SIZE 1 + +/* Service: Battery - Characteristic: Battery Level State - Pipe: SET */ +#define PIPE_BATTERY_BATTERY_LEVEL_STATE_SET 6 +#define PIPE_BATTERY_BATTERY_LEVEL_STATE_SET_MAX_SIZE 2 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: BROADCAST */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_BROADCAST 7 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_BROADCAST_MAX_SIZE 5 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: TX */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_TX 8 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_TX_MAX_SIZE 5 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: SET */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_SET 9 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_SET_MAX_SIZE 5 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: BROADCAST */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_BROADCAST_1 10 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_BROADCAST_1_MAX_SIZE 5 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: TX */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_TX_1 11 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_TX_1_MAX_SIZE 5 + +/* Service: Soil Moisture - Characteristic: Soil Moisture Level - Pipe: SET */ +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_SET_1 12 +#define PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_SET_1_MAX_SIZE 5 + + +#define NUMBER_OF_PIPES 12 + +#define SERVICES_PIPE_TYPE_MAPPING_CONTENT {\ + {ACI_STORE_LOCAL, ACI_SET}, \ + {ACI_STORE_LOCAL, ACI_TX_BROADCAST}, \ + {ACI_STORE_LOCAL, ACI_TX}, \ + {ACI_STORE_LOCAL, ACI_SET}, \ + {ACI_STORE_LOCAL, ACI_SET}, \ + {ACI_STORE_LOCAL, ACI_SET}, \ + {ACI_STORE_LOCAL, ACI_TX_BROADCAST}, \ + {ACI_STORE_LOCAL, ACI_TX}, \ + {ACI_STORE_LOCAL, ACI_SET}, \ + {ACI_STORE_LOCAL, ACI_TX_BROADCAST}, \ + {ACI_STORE_LOCAL, ACI_TX}, \ + {ACI_STORE_LOCAL, ACI_SET}, \ +} + +#define GAP_PPCP_MAX_CONN_INT 0xffff /**< Maximum connection interval as a multiple of 1.25 msec , 0xFFFF means no specific value requested */ +#define GAP_PPCP_MIN_CONN_INT 0xffff /**< Minimum connection interval as a multiple of 1.25 msec , 0xFFFF means no specific value requested */ +#define GAP_PPCP_SLAVE_LATENCY 0 +#define GAP_PPCP_CONN_TIMEOUT 0xffff /** Connection Supervision timeout multiplier as a multiple of 10msec, 0xFFFF means no specific value requested */ + +#define NB_SETUP_MESSAGES 21 +#define SETUP_MESSAGES_CONTENT {\ + {0x00,\ + {\ + 0x07,0x06,0x00,0x00,0x03,0x02,0x42,0x07,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0c,0x01,0x01,0x00,0x00,0x06,0x00,0x01,\ + 0x81,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x10,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x90,0x00,0xff,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x10,0x38,0xff,0xff,0x02,0x58,0x0a,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x05,0x06,0x10,0x54,0x00,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x00,0x04,0x04,0x02,0x02,0x00,0x01,0x28,0x00,0x01,0x00,0x18,0x04,0x04,0x05,0x05,0x00,\ + 0x02,0x28,0x03,0x01,0x0e,0x03,0x00,0x00,0x2a,0x04,0x14,0x0a,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x1c,0x03,0x00,0x03,0x2a,0x00,0x01,0x77,0x61,0x74,0x64,0x69,0x63,0x73,0x65,0x6d,0x69,\ + 0x04,0x04,0x05,0x05,0x00,0x04,0x28,0x03,0x01,0x02,0x05,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x38,0x01,0x2a,0x06,0x04,0x03,0x02,0x00,0x05,0x2a,0x01,0x01,0x00,0x00,0x04,0x04,0x05,\ + 0x05,0x00,0x06,0x28,0x03,0x01,0x02,0x07,0x00,0x04,0x2a,0x06,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x54,0x04,0x09,0x08,0x00,0x07,0x2a,0x04,0x01,0xff,0xff,0xff,0xff,0x00,0x00,0xff,0xff,\ + 0x04,0x04,0x02,0x02,0x00,0x08,0x28,0x00,0x01,0x01,0x18,0x04,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x70,0x04,0x02,0x02,0x00,0x09,0x28,0x00,0x01,0x0f,0x18,0x04,0x04,0x05,0x05,0x00,0x0a,\ + 0x28,0x03,0x01,0x12,0x0b,0x00,0x19,0x2a,0x16,0x04,0x02,0x01,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0x8c,0x00,0x0b,0x2a,0x19,0x01,0x10,0x46,0x14,0x03,0x02,0x00,0x0c,0x29,0x02,0x01,0x00,\ + 0x00,0x04,0x04,0x05,0x05,0x00,0x0d,0x28,0x03,0x01,0x02,0x0e,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0xa8,0x00,0x1a,0x2a,0x06,0x04,0x02,0x01,0x00,0x0e,0x2a,0x1a,0x01,0x00,0x04,0x04,0x05,\ + 0x05,0x00,0x0f,0x28,0x03,0x01,0x02,0x10,0x00,0x1b,0x2a,0x06,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0xc4,0x04,0x03,0x02,0x00,0x10,0x2a,0x1b,0x01,0x00,0x00,0x04,0x04,0x02,0x02,0x00,0x11,\ + 0x28,0x00,0x01,0x10,0x00,0x04,0x04,0x05,0x05,0x00,0x12,0x28,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0xe0,0x03,0x01,0x12,0x13,0x00,0x11,0x00,0x16,0x04,0x06,0x05,0x00,0x13,0x00,0x11,0x01,\ + 0xaa,0x55,0xaa,0x55,0xaa,0x46,0x14,0x03,0x02,0x00,0x14,0x29,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x20,0xfc,0x02,0x01,0x00,0x00,0x04,0x04,0x02,0x02,0x00,0x15,0x28,0x00,0x01,0x10,0x00,0x04,\ + 0x04,0x05,0x05,0x00,0x16,0x28,0x03,0x01,0x12,0x17,0x00,0x11,\ + },\ + },\ + {0x00,\ + {\ + 0x1e,0x06,0x21,0x18,0x00,0x14,0x04,0x05,0x00,0x00,0x17,0x00,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x46,\ + 0x14,0x03,0x02,0x00,0x18,0x29,0x02,0x01,0x00,0x00,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x40,0x00,0x2a,0x00,0x01,0x00,0x80,0x04,0x00,0x03,0x00,0x00,0x2a,0x19,0x01,0x00,0x83,0x04,\ + 0x00,0x0b,0x00,0x0c,0x2a,0x1a,0x01,0x00,0x80,0x04,0x00,0x0e,\ + },\ + },\ + {0x00,\ + {\ + 0x1f,0x06,0x40,0x1c,0x00,0x00,0x2a,0x1b,0x01,0x00,0x80,0x04,0x00,0x10,0x00,0x00,0x00,0x11,0x01,0x00,\ + 0x83,0x04,0x00,0x13,0x00,0x14,0x00,0x11,0x01,0x00,0x83,0x04,\ + },\ + },\ + {0x00,\ + {\ + 0x07,0x06,0x40,0x38,0x00,0x17,0x00,0x18,\ + },\ + },\ + {0x00,\ + {\ + 0x15,0x06,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,\ + },\ + },\ + {0x00,\ + {\ + 0x06,0x06,0xf0,0x00,0x83,0x4b,0xec,\ + },\ + },\ +} + +#endif diff --git a/trygvisio_soil_moisture.ino b/trygvisio_soil_moisture.ino new file mode 100644 index 0000000..b8b3bfd --- /dev/null +++ b/trygvisio_soil_moisture.ino @@ -0,0 +1,420 @@ +#include <SPI.h> +#include <lib_aci.h> +#include <aci_setup.h> + +#include "services.h" +#include "app.h" + +static services_pipe_type_mapping_t services_pipe_type_mapping[NUMBER_OF_PIPES] = SERVICES_PIPE_TYPE_MAPPING_CONTENT; +static hal_aci_data_t setup_msgs[NB_SETUP_MESSAGES] PROGMEM = SETUP_MESSAGES_CONTENT; + +static struct aci_state_t aci_state; +static hal_aci_evt_t aci_data; +static bool timing_change_done = false; + +void __ble_assert(const char *file, uint16_t line) +{ + Serial.print("ERROR "); + Serial.print(file); + Serial.print(": "); + Serial.print(line); + Serial.print("\n"); + while(1); +} + +void setup() { +#if defined(BLEND_MICRO_8MHZ) + // As the F_CPU = 8000000UL, the USB core make the PLLCSR = 0x02 + // But the external xtal is 16000000Hz, so correct it here. + PLLCSR |= 0x10; // Need 16 MHz xtal + while (!(PLLCSR & (1<<PLOCK))); // wait for lock pll +#elif defined(BLEND_MICRO_16MHZ) + // The CPU clock in bootloader is 8MHz, change to 16MHz for sketches to run (i.e. overclock running at 3.3v). + CLKPR = 0x80; + CLKPR = 0; +#endif + + Serial.begin((unsigned int)115200); + + // Wait until the serial port is available (useful only for the Leonardo) + // As the Leonardo board is not reseted every time you open the Serial Monitor +#if defined (__AVR_ATmega32U4__) + while(!Serial) { + } + + delay(1000); +#elif defined(__PIC32MX__) + delay(1000); +#endif + + setup_rf(); +} + +void setup_rf() { + Serial.println(F("setup_rf()")); + // Point ACI data structures to the the setup data that the nRFgo studio generated for the nRF8001 + if (NULL != services_pipe_type_mapping) { + aci_state.aci_setup_info.services_pipe_type_mapping = &services_pipe_type_mapping[0]; + } + else { + aci_state.aci_setup_info.services_pipe_type_mapping = NULL; + } + aci_state.aci_setup_info.number_of_pipes = NUMBER_OF_PIPES; + aci_state.aci_setup_info.setup_msgs = (hal_aci_data_t*)setup_msgs; + aci_state.aci_setup_info.num_setup_msgs = NB_SETUP_MESSAGES; + + // Tell the ACI library, the MCU to nRF8001 pin connections. + // The Active pin is optional and can be marked UNUSED +// aci_state.aci_pins.board_name = REDBEARLAB_SHIELD_V2; + aci_state.aci_pins.board_name = REDBEARLAB_SHIELD_V1_1; + aci_state.aci_pins.reqn_pin = 6; + aci_state.aci_pins.rdyn_pin = 7; + aci_state.aci_pins.mosi_pin = MOSI; + aci_state.aci_pins.miso_pin = MISO; + aci_state.aci_pins.sck_pin = SCK; + + // SPI_CLOCK_DIV8 = 2MHz SPI speed + // SPI_CLOCK_DIV16 = 1MHz SPI speed + aci_state.aci_pins.spi_clock_divider = SPI_CLOCK_DIV8; + aci_state.aci_pins.reset_pin = UNUSED; //4 for Nordic board, UNUSED for REDBEARLAB_SHIELD_V1_1 + aci_state.aci_pins.active_pin = UNUSED; + aci_state.aci_pins.optional_chip_sel_pin = UNUSED; + + aci_state.aci_pins.interface_is_interrupt = false; //Interrupts still not available in Chipkit + aci_state.aci_pins.interrupt_number = 4; + + // We reset the nRF8001 here by toggling the RESET line connected to the nRF8001 + // If the RESET line is not available we call the ACI Radio Reset to soft reset the nRF8001 + // then we initialize the data structures required to setup the nRF8001 + // The second parameter is for turning debug printing on for the ACI Commands and Events so they be printed on the Serial + lib_aci_init(&aci_state, false); + Serial.println(F("lib_aci_init done")); +} + +static bool rf_started = false; +static bool setup_required = false; + +static void aci_loop() { + uint8_t pipe_number; + int ret; + + // We enter the if statement only when there is a ACI event available to be processed + if (lib_aci_event_get(&aci_state, &aci_data)) { + aci_evt_t * aci_evt; + aci_evt = &aci_data.evt; + + switch(aci_evt->evt_opcode) { + case ACI_EVT_DEVICE_STARTED: + Serial.println(F("ACI_EVT_DEVICE_STARTED")); + aci_state.data_credit_total = aci_evt->params.device_started.credit_available; + + Serial.print(F("aci_state.data_credit_total=")); + Serial.println(aci_state.data_credit_total, DEC); + + switch(aci_evt->params.device_started.device_mode) { + case ACI_DEVICE_SETUP: + Serial.println(F("ACI_DEVICE_SETUP")); + rf_started = true; + setup_required = true; + break; + + case ACI_DEVICE_STANDBY: + Serial.println(F("ACI_DEVICE_STANDBY")); + if (aci_evt->params.device_started.hw_error) { + delay(20); // Magic number used to make sure the HW error event is handled correctly. + } + else { + lib_aci_connect(180/* in seconds */, 0x0050 /* advertising interval 50ms*/); + // lib_aci_broadcast(10/* in seconds */, 0x0100 /* advertising interval 100ms */); + ret = lib_aci_open_adv_pipe(PIPE_BATTERY_BATTERY_LEVEL_BROADCAST); + ret = lib_aci_open_adv_pipe(PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_BROADCAST); + Serial.print(F("Advertising started, ret=")); + Serial.println(ret, DEC); + } + break; + case ACI_DEVICE_INVALID: + case ACI_DEVICE_TEST: + case ACI_DEVICE_SLEEP: + // Ignored + break; + } + break; + + case ACI_EVT_CMD_RSP: + // Serial.println(F("ACI_EVT_CMD_RSP")); + // Serial.print(F("aci_evt->params.cmd_rsp.cmd_opcode=")); + // Serial.println(aci_evt->params.cmd_rsp.cmd_opcode, HEX); + // Serial.print(F("aci_evt->params.cmd_rsp.cmd_status=")); + // Serial.println(aci_evt->params.cmd_rsp.cmd_status, HEX); + + //If an ACI command response event comes with an error -> stop + if (aci_evt->params.cmd_rsp.cmd_status != ACI_STATUS_SUCCESS) { + //ACI ReadDynamicData and ACI WriteDynamicData will have status codes of + //TRANSACTION_CONTINUE and TRANSACTION_COMPLETE + //all other ACI commands will have status code of ACI_STATUS_SCUCCESS for a successful command// + // Serial.print(F("ACI Command ")); + // Serial.println(aci_evt->params.cmd_rsp.cmd_opcode, HEX); + // Serial.print(F("Evt Cmd respone: Status ")); + // Serial.println(aci_evt->params.cmd_rsp.cmd_status, HEX); + } + if (aci_evt->params.cmd_rsp.cmd_opcode == ACI_CMD_GET_DEVICE_VERSION) { + //Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic + // lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET, + // (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), + // sizeof(aci_evt_cmd_rsp_params_get_device_version_t)); + } + break; + + case ACI_EVT_CONNECTED: + Serial.println(F("ACI_EVT_CONNECTED")); + timing_change_done = false; + aci_state.data_credit_available = aci_state.data_credit_total; + Serial.print(F("aci_state.data_credit_available=")); + Serial.println(aci_state.data_credit_available, DEC); + + // Get the device version of the nRF8001 and store it in the Hardware Revision String. + // This will trigger a ACI_CMD_GET_DEVICE_VERSION. + lib_aci_device_version(); + break; + + case ACI_EVT_PIPE_STATUS: + Serial.println(F("ACI_EVT_PIPE_STATUS")); + show_pipes(); + break; + + case ACI_EVT_TIMING: + Serial.println(F("ACI_EVT_TIMING")); + break; + + case ACI_EVT_DISCONNECTED: + Serial.println(F("ACI_EVT_DISCONNECTED")); + + lib_aci_connect(180/* in seconds */, 0x0100 /* advertising interval 100ms*/); + ret = lib_aci_open_adv_pipe(PIPE_BATTERY_BATTERY_LEVEL_BROADCAST); + ret = lib_aci_open_adv_pipe(PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_BROADCAST); + Serial.print(F("Advertising started, ret=")); + Serial.println(ret, DEC); + +// Serial.print(F("ACI_EVT_DISCONNECTED: ")); +// Serial.println(ACI_STATUS_ERROR_ADVT_TIMEOUT == aci_evt->params.disconnected.aci_status ? +// F("Broadcasting timed out") : F("Link loss")); + // lib_aci_broadcast(10/* in seconds */, 0x0100 /* advertising interval 100ms */); + // Serial.print(F("Broadcast advertising started, ret=")); + // Serial.println(ret, DEC); + break; + + case ACI_EVT_DATA_RECEIVED: + pipe_number = aci_evt->params.data_received.rx_data.pipe_number; + + Serial.print(F("ACI_EVT_DATA_RECEIVED: pipe_number=")); + Serial.println(pipe_number, DEC); + /* + if (pipe_number == PIPE_FIKEN_STATUS_PANEL_GAUGE_DATA_RX_ACK) { + if (aci_evt->len != PIPE_FIKEN_STATUS_PANEL_GAUGE_DATA_RX_ACK_MAX_SIZE) { + break; + } + on_gauge_data(aci_evt->params.data_received.rx_data.aci_data, aci_evt->len - 2); + lib_aci_send_ack(&aci_state, PIPE_FIKEN_STATUS_PANEL_GAUGE_DATA_RX_ACK); + } + + if (pipe_number == PIPE_FIKEN_STATUS_PANEL_GAUGE_CONTROL_RX) { + uint8_t len = aci_evt->len - 2; + // if (aci_evt->len != PIPE_FIKEN_STATUS_PANEL_GAUGE_CONTROL_RX_MAX_SIZE) { + // break; + // } + + on_gauge_ctrl(aci_evt->params.data_received.rx_data.aci_data, len); + } + */ + break; + + case ACI_EVT_DATA_CREDIT: + Serial.println(F("ACI_EVT_DATA_CREDIT")); + aci_state.data_credit_available = aci_state.data_credit_available + aci_evt->params.data_credit.credit; + Serial.print(F("aci_state.data_credit_available=")); + Serial.println(aci_state.data_credit_available, DEC); + break; + + case ACI_EVT_PIPE_ERROR: + Serial.println(F("ACI_EVT_PIPE_ERROR")); + //See the appendix in the nRF8001 Product Specication for details on the error codes + Serial.print(F("ACI Evt Pipe Error: Pipe #:")); + Serial.print(aci_evt->params.pipe_error.pipe_number, DEC); + Serial.print(F(" Pipe Error Code: 0x")); + Serial.println(aci_evt->params.pipe_error.error_code, HEX); + + // Increment the credit available as the data packet was not sent. + // The pipe error also represents the Attribute protocol Error Response sent from the peer and that should not be counted + // for the credit. + if (ACI_STATUS_ERROR_PEER_ATT_ERROR != aci_evt->params.pipe_error.error_code) { + aci_state.data_credit_available++; + } + break; + + case ACI_EVT_HW_ERROR: + Serial.println(F("ACI_EVT_HW_ERROR")); + Serial.print(F("HW error: ")); + Serial.println(aci_evt->params.hw_error.line_num, DEC); + + for(uint8_t counter = 0; counter <= (aci_evt->len - 3); counter++) { + Serial.write(aci_evt->params.hw_error.file_name[counter]); //uint8_t file_name[20]; + } + Serial.println(); + lib_aci_connect(180/* in seconds */, 0x0050 /* advertising interval 50ms*/); + Serial.println(F("Advertising started")); + break; + + case ACI_EVT_INVALID: + Serial.println(F("ACI_EVT_INVALID")); + break; + case ACI_EVT_ECHO: + Serial.println(F("ACI_EVT_ECHO")); + break; + case ACI_EVT_BOND_STATUS: + Serial.println(F("ACI_EVT_BOND_STATUS")); + break; + case ACI_EVT_DATA_ACK: + Serial.println(F("ACI_EVT_DATA_ACK")); + break; + case ACI_EVT_DISPLAY_PASSKEY: + Serial.println(F("ACI_EVT_DISPLAY_PASSKEY")); + break; + case ACI_EVT_KEY_REQUEST: + Serial.println(F("ACI_EVT_KEY_REQUEST")); + break; + } + } + else { + // Serial.println(F("No ACI Events available")); + // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep + // Arduino can go to sleep now + // Wakeup from sleep from the RDYN line + } + + /* setup_required is set to true when the device starts up and enters setup mode. + * It indicates that do_aci_setup() should be called. The flag should be cleared if + * do_aci_setup() returns ACI_STATUS_TRANSACTION_COMPLETE. + */ + if (setup_required) { + int ret = do_aci_setup(&aci_state); + Serial.print(F("do_aci_setup ret=")); + Serial.println(ret, DEC); + if (SETUP_SUCCESS == ret) { + setup_required = false; + } + } +} + +static uint8_t value = 0; +void loop() { + static unsigned long last = 0, now; + + aci_loop(); + + if (Serial.available()) { + Serial.write(Serial.read()); + } + + now = millis(); + if (now - last > 3000) { + last = now; + + if (!rf_started) { + static int count = 0; + static boolean reset_attempted = false; + count++; + + if (!reset_attempted) { + + if (count == 3) { + reset_attempted = true; + Serial.println(F("RF did not start, resetting RF")); + + // asm volatile ("jmp 0"); + // lib_aci_pin_reset(); + setup_rf(); + count = 0; + return; + } else { + Serial.println(F("waiting for RF to start")); + } + } + /**/ + } + else if (!setup_required) { + value++; +// lib_aci_set_local_data(&aci_state, PIPE_FIKEN_STATUS_PANEL_GAUGE_DATA_SET, &value, 1); +// Serial.print(F("value=")); +// Serial.println(value, HEX); + + // show_pipes(); + } + } + + on_loop(); +} + +void show_pipes() { + for (uint8_t i = 1; i <= NUMBER_OF_PIPES; i++) { + uint8_t x = lib_aci_is_pipe_available(&aci_state, i); + Serial.print(F("pipe #")); + Serial.print(i, DEC); + Serial.print(F(", available=?")); + Serial.println(x, DEC); + } +} + +bool tx__moisture(sm_res *res) { + static const uint8_t pipe = PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_TX; + uint8_t *data = (uint8_t *)res; + uint8_t len = 2 + res->len; + bool status = false; + + bool available = lib_aci_is_pipe_available(&aci_state, pipe); + + Serial.print(F("tx_soil_moisture, len=")); + Serial.println(len, DEC); + Serial.print(F("aci_state.data_credit_available=")); + Serial.println(aci_state.data_credit_available, DEC); + Serial.print(F("available=")); + Serial.println(available, DEC); + + if (available && aci_state.data_credit_available > 0) { + status = lib_aci_send_data(pipe, data, len); + if (status) { + aci_state.data_credit_available--; + } + } + return status; +} + +void notify_battery_level(uint8_t value) { + static const uint8_t pipe = PIPE_BATTERY_BATTERY_LEVEL_SET; + + Serial.print(F("notify_battery_level, value=")); + Serial.println(value, DEC); + + value = value % 101; + + lib_aci_set_local_data(&aci_state, pipe, &value, 1); +} + +void notify_soil_moisture(sm_res *res) { + static const uint8_t pipe = PIPE_SOIL_MOISTURE_SOIL_MOISTURE_LEVEL_SET; + + uint8_t *data = (uint8_t *)res; + uint8_t len = 2 + res->len; + bool status = false; + + Serial.print(F("notify_soil_moisture, len=")); + Serial.println(len, DEC); + Serial.print(F("aci_state.data_credit_available=")); + Serial.println(aci_state.data_credit_available, DEC); + +// bool available = lib_aci_is_pipe_available(&aci_state, pipe); +// Serial.print(F("available=")); +// Serial.println(available, DEC); + + status = lib_aci_set_local_data(&aci_state, pipe, data, len); +} + diff --git a/trygvisio_soil_moisture.xml b/trygvisio_soil_moisture.xml new file mode 100644 index 0000000..3041f3a --- /dev/null +++ b/trygvisio_soil_moisture.xml @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE AttributeServer> +<Profile Version="1.3"> + <SetupId>0</SetupId> + <Device>nRF8001_Dx</Device> + <Service Type="local" PrimaryService="true"> + <Name>Battery</Name> + <Uuid>180f</Uuid> + <Characteristic> + <Name>Battery Level</Name> + <Uuid>2a19</Uuid> + <DefaultValue>10</DefaultValue> + <UsePresentationFormat>0</UsePresentationFormat> + <MaxDataLength>1</MaxDataLength> + <AttributeLenType>1</AttributeLenType> + <ForceOpen>false</ForceOpen> + <ForceEncryption>false</ForceEncryption> + <Properties> + <WriteWithoutResponse>false</WriteWithoutResponse> + <Write>false</Write> + <Notify>false</Notify> + <Indicate>false</Indicate> + <Broadcast>false</Broadcast> + </Properties> + <SetPipe>true</SetPipe> + <AckIsAuto>false</AckIsAuto> + <PresentationFormatDescriptor Value="0000" Exponent="0" Format="1" NameSpace="01" Unit="0000"/> + <PeriodForReadingThisCharacteristic>0</PeriodForReadingThisCharacteristic> + <PeriodForProperties/> + </Characteristic> + <Characteristic> + <Name>Battery Power State</Name> + <Uuid>2a1a</Uuid> + <DefaultValue>0</DefaultValue> + <UsePresentationFormat>0</UsePresentationFormat> + <MaxDataLength>1</MaxDataLength> + <AttributeLenType>1</AttributeLenType> + <ForceOpen>false</ForceOpen> + <ForceEncryption>false</ForceEncryption> + <Properties> + <WriteWithoutResponse>false</WriteWithoutResponse> + <Write>false</Write> + <Notify>false</Notify> + <Indicate>false</Indicate> + <Broadcast>false</Broadcast> + </Properties> + <SetPipe>true</SetPipe> + <AckIsAuto>false</AckIsAuto> + <PresentationFormatDescriptor Value="0000" Exponent="0" Format="1" NameSpace="01" Unit="0000"/> + <PeriodForReadingThisCharacteristic>0</PeriodForReadingThisCharacteristic> + <PeriodForProperties/> + </Characteristic> + <Characteristic> + <Name>Battery Level State</Name> + <Uuid>2a1b</Uuid> + <DefaultValue>0</DefaultValue> + <UsePresentationFormat>0</UsePresentationFormat> + <MaxDataLength>2</MaxDataLength> + <AttributeLenType>1</AttributeLenType> + <ForceOpen>false</ForceOpen> + <ForceEncryption>false</ForceEncryption> + <Properties> + <WriteWithoutResponse>false</WriteWithoutResponse> + <Write>false</Write> + <Notify>false</Notify> + <Indicate>false</Indicate> + <Broadcast>false</Broadcast> + </Properties> + <SetPipe>true</SetPipe> + <AckIsAuto>false</AckIsAuto> + <PresentationFormatDescriptor Value="0000" Exponent="0" Format="1" NameSpace="01" Unit="0000"/> + <PeriodForReadingThisCharacteristic>0</PeriodForReadingThisCharacteristic> + <PeriodForProperties/> + </Characteristic> + </Service> + <Service Type="local" PrimaryService="true"> + <Name>Soil Moisture</Name> + <Uuid>0010</Uuid> + <Characteristic> + <Name>Soil Moisture Level</Name> + <Uuid>0011</Uuid> + <DefaultValue>aa55aa55aa</DefaultValue> + <UsePresentationFormat>0</UsePresentationFormat> + <MaxDataLength>5</MaxDataLength> + <AttributeLenType>1</AttributeLenType> + <ForceOpen>false</ForceOpen> + <ForceEncryption>false</ForceEncryption> + <Properties> + <WriteWithoutResponse>false</WriteWithoutResponse> + <Write>false</Write> + <Notify>true</Notify> + <Indicate>false</Indicate> + <Broadcast>true</Broadcast> + </Properties> + <SetPipe>true</SetPipe> + <AckIsAuto>false</AckIsAuto> + <PresentationFormatDescriptor Value="0000" Exponent="0" Format="4" NameSpace="01" Unit="0000"/> + <PeriodForReadingThisCharacteristic>0</PeriodForReadingThisCharacteristic> + <PeriodForProperties/> + </Characteristic> + </Service> + <Gapsettings> + <Name>wat</Name> + <DeviceNameWriteLength>0</DeviceNameWriteLength> + <LocalPipeOnDeviceName>false</LocalPipeOnDeviceName> + <DeviceNameShortLength>1</DeviceNameShortLength> + <Apperance>0000</Apperance> + <SecurityLevel>0</SecurityLevel> + <AuthenticationReq>0</AuthenticationReq> + <IoCapabilities>0</IoCapabilities> + <BondTimeout>600</BondTimeout> + <SecurityRequestDelay>10</SecurityRequestDelay> + <MinimumKeySize>7</MinimumKeySize> + <MaximumKeySize>16</MaximumKeySize> + <AdvertisingDataBondedBitmap>0</AdvertisingDataBondedBitmap> + <AdvertisingDataGeneralBitmap>0</AdvertisingDataGeneralBitmap> + <AdvertisingDataBrodcastBitmap>0</AdvertisingDataBrodcastBitmap> + <AdvertisingDataBondedScanResponseBitmap>0</AdvertisingDataBondedScanResponseBitmap> + <AdvertisingDataGeneralScanResponseBitmap>1000</AdvertisingDataGeneralScanResponseBitmap> + <AdvertisingDataBrodcastScanResponseBitmap>0</AdvertisingDataBrodcastScanResponseBitmap> + <AdvertisingDataBondedBitmapCustom>0</AdvertisingDataBondedBitmapCustom> + <AdvertisingDataGeneralBitmapCustom>0</AdvertisingDataGeneralBitmapCustom> + <AdvertisingDataBrodcastBitmapCustom>0</AdvertisingDataBrodcastBitmapCustom> + <AdvertisingDataBondedScanResponseBitmapCustom>0</AdvertisingDataBondedScanResponseBitmapCustom> + <AdvertisingDataGeneralScanResponseBitmapCustom>0</AdvertisingDataGeneralScanResponseBitmapCustom> + <AdvertisingDataBrodcastScanResponseBitmapCustom>0</AdvertisingDataBrodcastScanResponseBitmapCustom> + <TxPowerLevelOffset>0</TxPowerLevelOffset> + <MinimumConnectionInterval>65535</MinimumConnectionInterval> + <MaximumConnectionInterval>65535</MaximumConnectionInterval> + <SlaveLatency>0</SlaveLatency> + <TimeoutMultipler>65535</TimeoutMultipler> + <AddServiceUpdateCharacteristic>false</AddServiceUpdateCharacteristic> + <AddServiceUpdateCharacteristicPipe>false</AddServiceUpdateCharacteristicPipe> + <TimingChangeDelay>5</TimingChangeDelay> + <ServiceToAdvertise> + <Uuid>0010</Uuid> + </ServiceToAdvertise> + <CustomAdTypes> + <AdType index="1"> + <Type>19</Type> + <Value>0000</Value> + </AdType> + <AdType index="2"> + <Type>18</Type> + <Value></Value> + </AdType> + </CustomAdTypes> + </Gapsettings> + <Hardwaresettings> + <Clocksource>1</Clocksource> + <ClockAccuracy>1</ClockAccuracy> + <InitialTxPower>3</InitialTxPower> + <HfClkSource>0</HfClkSource> + <DcDcConverter>0</DcDcConverter> + <ActiveSignalModeIndex>0</ActiveSignalModeIndex> + <ActiveSignalToTickDistance>0</ActiveSignalToTickDistance> + <DynamicWindowLimitingEnabled>false</DynamicWindowLimitingEnabled> + </Hardwaresettings> + <CurrentInput> + <BatteryCharge>220</BatteryCharge> + <Master32KhzClockAccuracy>10</Master32KhzClockAccuracy> + <ConnectionInterval>1000</ConnectionInterval> + <PercentOfTimeSleeping>0</PercentOfTimeSleeping> + <PercentOfTimeAdvertising>0</PercentOfTimeAdvertising> + <AdvertisingInterval>1280</AdvertisingInterval> + </CurrentInput> +</Profile> |