スマートロックソフトウェア(BLE nano用)

Dependencies:   BLE_API mbed nRF51822

Committer:
toshiyukisaito
Date:
Fri Sep 04 13:29:59 2015 +0000
Revision:
0:fcfa8140d2db
SmartLock Version1

Who changed what in which revision?

UserRevisionLine numberNew contents of line
toshiyukisaito 0:fcfa8140d2db 1 #include "mbed.h"
toshiyukisaito 0:fcfa8140d2db 2 #include "ble/BLE.h"
toshiyukisaito 0:fcfa8140d2db 3 #include "Servo.h"
toshiyukisaito 0:fcfa8140d2db 4
toshiyukisaito 0:fcfa8140d2db 5 #define LOCAL_NAME "SmartLock"
toshiyukisaito 0:fcfa8140d2db 6 #define TXRX_BUF_LEN 20
toshiyukisaito 0:fcfa8140d2db 7 #define SERVO_PIN P0_8 // RTS
toshiyukisaito 0:fcfa8140d2db 8 #define SERVO_PWR_PIN P0_11 // RXD
toshiyukisaito 0:fcfa8140d2db 9 #define SWITCH_PIN P0_9 // TXD
toshiyukisaito 0:fcfa8140d2db 10
toshiyukisaito 0:fcfa8140d2db 11 #define SERVO_ON_TIME 1 // s
toshiyukisaito 0:fcfa8140d2db 12 #define SWITCH_WATCH_INTERVAL 2 // s
toshiyukisaito 0:fcfa8140d2db 13 #define UNLOCK_PHRASE "O"
toshiyukisaito 0:fcfa8140d2db 14 #define LOCK_PHRASE "C"
toshiyukisaito 0:fcfa8140d2db 15 #define STATUS_PHRASE "S"
toshiyukisaito 0:fcfa8140d2db 16 #define PAIRING_PHRASE "PAIR"
toshiyukisaito 0:fcfa8140d2db 17 #define PASSPHRASE "PSS_"
toshiyukisaito 0:fcfa8140d2db 18 #define SET_PASSPHRASE "PHRASE"
toshiyukisaito 0:fcfa8140d2db 19 #define ALREADY_PAIRING "ALREADY"
toshiyukisaito 0:fcfa8140d2db 20 #define PASSPHRASE_LENGTH 10
toshiyukisaito 0:fcfa8140d2db 21
toshiyukisaito 0:fcfa8140d2db 22 #define UNLOCK_SERVO_POS 90
toshiyukisaito 0:fcfa8140d2db 23 #define LOCK_SERVO_POS 0
toshiyukisaito 0:fcfa8140d2db 24
toshiyukisaito 0:fcfa8140d2db 25 #define ADVERTISING_INTERVAL 1000 // ms
toshiyukisaito 0:fcfa8140d2db 26
toshiyukisaito 0:fcfa8140d2db 27 BLE ble;
toshiyukisaito 0:fcfa8140d2db 28 Servo servo(SERVO_PIN);
toshiyukisaito 0:fcfa8140d2db 29 DigitalOut sw(SERVO_PWR_PIN);
toshiyukisaito 0:fcfa8140d2db 30 DigitalIn toggle(SWITCH_PIN);
toshiyukisaito 0:fcfa8140d2db 31 DigitalOut led(P0_19);
toshiyukisaito 0:fcfa8140d2db 32
toshiyukisaito 0:fcfa8140d2db 33 #define DEBUG 0
toshiyukisaito 0:fcfa8140d2db 34
toshiyukisaito 0:fcfa8140d2db 35 #if DEBUG
toshiyukisaito 0:fcfa8140d2db 36 Serial pc(USBTX, USBRX);
toshiyukisaito 0:fcfa8140d2db 37 #endif
toshiyukisaito 0:fcfa8140d2db 38
toshiyukisaito 0:fcfa8140d2db 39 static const uint8_t uart_base_uuid[] = {0x71, 0x3D, 0x00, 0x00, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
toshiyukisaito 0:fcfa8140d2db 40 static const uint8_t uart_tx_uuid[] = {0x71, 0x3D, 0x00, 0x03, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
toshiyukisaito 0:fcfa8140d2db 41 static const uint8_t uart_rx_uuid[] = {0x71, 0x3D, 0x00, 0x02, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
toshiyukisaito 0:fcfa8140d2db 42 static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0x00, 0x00, 0x3D, 0x71};
toshiyukisaito 0:fcfa8140d2db 43
toshiyukisaito 0:fcfa8140d2db 44 uint8_t txPayload[TXRX_BUF_LEN] = {0,};
toshiyukisaito 0:fcfa8140d2db 45 uint8_t rxPayload[TXRX_BUF_LEN] = {0,};
toshiyukisaito 0:fcfa8140d2db 46
toshiyukisaito 0:fcfa8140d2db 47 GattCharacteristic txCharacteristic (uart_tx_uuid, txPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
toshiyukisaito 0:fcfa8140d2db 48 GattCharacteristic rxCharacteristic (uart_rx_uuid, rxPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
toshiyukisaito 0:fcfa8140d2db 49 GattCharacteristic *uartChars[] = {&txCharacteristic, &rxCharacteristic};
toshiyukisaito 0:fcfa8140d2db 50 GattService uartService(uart_base_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));
toshiyukisaito 0:fcfa8140d2db 51
toshiyukisaito 0:fcfa8140d2db 52 bool isUnlock = false; // ロック状態
toshiyukisaito 0:fcfa8140d2db 53 bool isPairing = false; // ペアリング状態
toshiyukisaito 0:fcfa8140d2db 54 bool onPairing = false; // ペアリング中フラグ
toshiyukisaito 0:fcfa8140d2db 55 char phrase[TXRX_BUF_LEN] = {0,}; // パスフレーズ
toshiyukisaito 0:fcfa8140d2db 56
toshiyukisaito 0:fcfa8140d2db 57 /*
toshiyukisaito 0:fcfa8140d2db 58 文字列prefix+s1とs2の比較を行います。
toshiyukisaito 0:fcfa8140d2db 59 */
toshiyukisaito 0:fcfa8140d2db 60 bool str_equal(const char* prefix, const char* s1, uint8_t* s2) {
toshiyukisaito 0:fcfa8140d2db 61 int i = 0;
toshiyukisaito 0:fcfa8140d2db 62 while (prefix[i] != '\0') {
toshiyukisaito 0:fcfa8140d2db 63 if (prefix[i] != (char) s2[i]) {
toshiyukisaito 0:fcfa8140d2db 64 return false;
toshiyukisaito 0:fcfa8140d2db 65 }
toshiyukisaito 0:fcfa8140d2db 66 i++;
toshiyukisaito 0:fcfa8140d2db 67 }
toshiyukisaito 0:fcfa8140d2db 68 int j = 0;
toshiyukisaito 0:fcfa8140d2db 69 while(s1[j] != '\0') {
toshiyukisaito 0:fcfa8140d2db 70 if (s1[j] != (char) s2[i]) {
toshiyukisaito 0:fcfa8140d2db 71 return false;
toshiyukisaito 0:fcfa8140d2db 72 }
toshiyukisaito 0:fcfa8140d2db 73 i++;
toshiyukisaito 0:fcfa8140d2db 74 j++;
toshiyukisaito 0:fcfa8140d2db 75 }
toshiyukisaito 0:fcfa8140d2db 76 return true;
toshiyukisaito 0:fcfa8140d2db 77 }
toshiyukisaito 0:fcfa8140d2db 78
toshiyukisaito 0:fcfa8140d2db 79 /*
toshiyukisaito 0:fcfa8140d2db 80 char*の文字列をuint8_t*の文字列にコピーします。
toshiyukisaito 0:fcfa8140d2db 81 */
toshiyukisaito 0:fcfa8140d2db 82 void uintstr_cpy(uint8_t* dest, const char* src) {
toshiyukisaito 0:fcfa8140d2db 83 int i;
toshiyukisaito 0:fcfa8140d2db 84 for (i = 0; src[i] != '\0'; i++) {
toshiyukisaito 0:fcfa8140d2db 85 dest[i] = src[i];
toshiyukisaito 0:fcfa8140d2db 86 }
toshiyukisaito 0:fcfa8140d2db 87 dest[i] = '\0';
toshiyukisaito 0:fcfa8140d2db 88 }
toshiyukisaito 0:fcfa8140d2db 89
toshiyukisaito 0:fcfa8140d2db 90 /*
toshiyukisaito 0:fcfa8140d2db 91 ロック状態のステータス更新
toshiyukisaito 0:fcfa8140d2db 92 */
toshiyukisaito 0:fcfa8140d2db 93 void UpdateStatus() {
toshiyukisaito 0:fcfa8140d2db 94 // ペアリングされていなければUpdateしない。
toshiyukisaito 0:fcfa8140d2db 95 if (!isPairing) return;
toshiyukisaito 0:fcfa8140d2db 96 uint8_t buf[2];
toshiyukisaito 0:fcfa8140d2db 97 uintstr_cpy(buf, isUnlock ? UNLOCK_PHRASE : LOCK_PHRASE);
toshiyukisaito 0:fcfa8140d2db 98 ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 2);
toshiyukisaito 0:fcfa8140d2db 99 }
toshiyukisaito 0:fcfa8140d2db 100
toshiyukisaito 0:fcfa8140d2db 101 /*
toshiyukisaito 0:fcfa8140d2db 102 サムターン回転処理。unlock=trueで開錠。
toshiyukisaito 0:fcfa8140d2db 103 */
toshiyukisaito 0:fcfa8140d2db 104 void Thumbturn(bool unlock) {
toshiyukisaito 0:fcfa8140d2db 105 isUnlock = unlock;
toshiyukisaito 0:fcfa8140d2db 106 sw.write(1);
toshiyukisaito 0:fcfa8140d2db 107 wait(0.05);
toshiyukisaito 0:fcfa8140d2db 108 servo.write(isUnlock ? UNLOCK_SERVO_POS : LOCK_SERVO_POS);
toshiyukisaito 0:fcfa8140d2db 109 wait(SERVO_ON_TIME);
toshiyukisaito 0:fcfa8140d2db 110 UpdateStatus();
toshiyukisaito 0:fcfa8140d2db 111 sw.write(0);
toshiyukisaito 0:fcfa8140d2db 112 wait(0.05);
toshiyukisaito 0:fcfa8140d2db 113 }
toshiyukisaito 0:fcfa8140d2db 114
toshiyukisaito 0:fcfa8140d2db 115 /*
toshiyukisaito 0:fcfa8140d2db 116 BLEのコールバック。centralと接続が切れた場合の処理。
toshiyukisaito 0:fcfa8140d2db 117 */
toshiyukisaito 0:fcfa8140d2db 118 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) {
toshiyukisaito 0:fcfa8140d2db 119 ble.startAdvertising();
toshiyukisaito 0:fcfa8140d2db 120 }
toshiyukisaito 0:fcfa8140d2db 121
toshiyukisaito 0:fcfa8140d2db 122 /*
toshiyukisaito 0:fcfa8140d2db 123 BLEのコールバック。centralから書き込みがあった場合の処理
toshiyukisaito 0:fcfa8140d2db 124 */
toshiyukisaito 0:fcfa8140d2db 125 void WrittenHandler(const GattWriteCallbackParams *Handler) {
toshiyukisaito 0:fcfa8140d2db 126 uint8_t buf[TXRX_BUF_LEN];
toshiyukisaito 0:fcfa8140d2db 127 uint16_t bytesRead;
toshiyukisaito 0:fcfa8140d2db 128
toshiyukisaito 0:fcfa8140d2db 129 if (Handler->handle == txCharacteristic.getValueAttribute().getHandle()) {
toshiyukisaito 0:fcfa8140d2db 130 ble.readCharacteristicValue(txCharacteristic.getValueAttribute().getHandle(), buf, &bytesRead);
toshiyukisaito 0:fcfa8140d2db 131 memset(txPayload, 0, TXRX_BUF_LEN);
toshiyukisaito 0:fcfa8140d2db 132 memcpy(txPayload, buf, bytesRead);
toshiyukisaito 0:fcfa8140d2db 133 #if DEBUG
toshiyukisaito 0:fcfa8140d2db 134 pc.printf("Receive: %d, %s\r\n", bytesRead, buf);
toshiyukisaito 0:fcfa8140d2db 135 #endif
toshiyukisaito 0:fcfa8140d2db 136
toshiyukisaito 0:fcfa8140d2db 137 // ペアリングしていなくて、ステータスチェックが来たら
toshiyukisaito 0:fcfa8140d2db 138 if (!isPairing && str_equal(STATUS_PHRASE, "", buf)) {
toshiyukisaito 0:fcfa8140d2db 139 // ペアリングの必要があるよ。
toshiyukisaito 0:fcfa8140d2db 140 uint8_t buf[TXRX_BUF_LEN];
toshiyukisaito 0:fcfa8140d2db 141 memset(txPayload, 0, TXRX_BUF_LEN);
toshiyukisaito 0:fcfa8140d2db 142 uintstr_cpy(buf, PAIRING_PHRASE);
toshiyukisaito 0:fcfa8140d2db 143 ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 5);
toshiyukisaito 0:fcfa8140d2db 144 return;
toshiyukisaito 0:fcfa8140d2db 145 }
toshiyukisaito 0:fcfa8140d2db 146
toshiyukisaito 0:fcfa8140d2db 147 // ペアリング要求
toshiyukisaito 0:fcfa8140d2db 148 if (str_equal(PAIRING_PHRASE, "", buf)) {
toshiyukisaito 0:fcfa8140d2db 149 #if DEBUG
toshiyukisaito 0:fcfa8140d2db 150 pc.printf("Receive: PAIRING REQUEST\r\n", bytesRead, buf);
toshiyukisaito 0:fcfa8140d2db 151 #endif
toshiyukisaito 0:fcfa8140d2db 152 if (!isPairing) {
toshiyukisaito 0:fcfa8140d2db 153 // パスフレーズ要求
toshiyukisaito 0:fcfa8140d2db 154 onPairing = true;
toshiyukisaito 0:fcfa8140d2db 155 uint8_t buf[TXRX_BUF_LEN];
toshiyukisaito 0:fcfa8140d2db 156 memset(txPayload, 0, TXRX_BUF_LEN);
toshiyukisaito 0:fcfa8140d2db 157 uintstr_cpy(buf, SET_PASSPHRASE);
toshiyukisaito 0:fcfa8140d2db 158 ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 7);
toshiyukisaito 0:fcfa8140d2db 159 } else {
toshiyukisaito 0:fcfa8140d2db 160 // ペアリング不可。電源を落としてください。
toshiyukisaito 0:fcfa8140d2db 161 uint8_t buf[TXRX_BUF_LEN];
toshiyukisaito 0:fcfa8140d2db 162 memset(txPayload, 0, TXRX_BUF_LEN);
toshiyukisaito 0:fcfa8140d2db 163 uintstr_cpy(buf, ALREADY_PAIRING);
toshiyukisaito 0:fcfa8140d2db 164 ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 8);
toshiyukisaito 0:fcfa8140d2db 165 }
toshiyukisaito 0:fcfa8140d2db 166 return;
toshiyukisaito 0:fcfa8140d2db 167 }
toshiyukisaito 0:fcfa8140d2db 168
toshiyukisaito 0:fcfa8140d2db 169 // ペアリング処理中
toshiyukisaito 0:fcfa8140d2db 170 if (onPairing) {
toshiyukisaito 0:fcfa8140d2db 171 if (str_equal(PASSPHRASE, "", buf)) {
toshiyukisaito 0:fcfa8140d2db 172 // appから10桁のコードをもらう
toshiyukisaito 0:fcfa8140d2db 173 for (int i = 0; i < PASSPHRASE_LENGTH; i++) {
toshiyukisaito 0:fcfa8140d2db 174 phrase[i] = buf[i + strlen(PASSPHRASE)];
toshiyukisaito 0:fcfa8140d2db 175 }
toshiyukisaito 0:fcfa8140d2db 176 phrase[PASSPHRASE_LENGTH+1] = '\0';
toshiyukisaito 0:fcfa8140d2db 177 onPairing = false;
toshiyukisaito 0:fcfa8140d2db 178 isPairing = true;
toshiyukisaito 0:fcfa8140d2db 179 led.write(1);
toshiyukisaito 0:fcfa8140d2db 180 wait(0.5);
toshiyukisaito 0:fcfa8140d2db 181 }
toshiyukisaito 0:fcfa8140d2db 182 return;
toshiyukisaito 0:fcfa8140d2db 183 }
toshiyukisaito 0:fcfa8140d2db 184
toshiyukisaito 0:fcfa8140d2db 185 // ペアリング済み
toshiyukisaito 0:fcfa8140d2db 186 if(str_equal(UNLOCK_PHRASE, phrase, buf)) {
toshiyukisaito 0:fcfa8140d2db 187 Thumbturn(true);
toshiyukisaito 0:fcfa8140d2db 188 } else if(str_equal(LOCK_PHRASE, phrase, buf)) {
toshiyukisaito 0:fcfa8140d2db 189 Thumbturn(false);
toshiyukisaito 0:fcfa8140d2db 190 } else if(str_equal(STATUS_PHRASE, phrase, buf)) {
toshiyukisaito 0:fcfa8140d2db 191 UpdateStatus();
toshiyukisaito 0:fcfa8140d2db 192 }
toshiyukisaito 0:fcfa8140d2db 193 }
toshiyukisaito 0:fcfa8140d2db 194 }
toshiyukisaito 0:fcfa8140d2db 195
toshiyukisaito 0:fcfa8140d2db 196 /*
toshiyukisaito 0:fcfa8140d2db 197 ステータスチェック。
toshiyukisaito 0:fcfa8140d2db 198 タイマーで一定時間ごとに呼び出される。
toshiyukisaito 0:fcfa8140d2db 199 */
toshiyukisaito 0:fcfa8140d2db 200 void StatusCheckHundler() {
toshiyukisaito 0:fcfa8140d2db 201 #if DEBUG
toshiyukisaito 0:fcfa8140d2db 202 pc.printf("SC %d %d\r\n", isPairing, onPairing);
toshiyukisaito 0:fcfa8140d2db 203 #endif
toshiyukisaito 0:fcfa8140d2db 204 if (isPairing) {
toshiyukisaito 0:fcfa8140d2db 205 // ペアリング済みならtoggleボタンでUnlock/Lockできる
toshiyukisaito 0:fcfa8140d2db 206 if (toggle.read() == 0) {
toshiyukisaito 0:fcfa8140d2db 207 if (isUnlock) {
toshiyukisaito 0:fcfa8140d2db 208 Thumbturn(false);
toshiyukisaito 0:fcfa8140d2db 209 } else {
toshiyukisaito 0:fcfa8140d2db 210 Thumbturn(true);
toshiyukisaito 0:fcfa8140d2db 211 }
toshiyukisaito 0:fcfa8140d2db 212 }
toshiyukisaito 0:fcfa8140d2db 213 } else {
toshiyukisaito 0:fcfa8140d2db 214 // 未ペアリング
toshiyukisaito 0:fcfa8140d2db 215
toshiyukisaito 0:fcfa8140d2db 216 // onPairgingになったときにLEDを点滅させる
toshiyukisaito 0:fcfa8140d2db 217 if (onPairing) {
toshiyukisaito 0:fcfa8140d2db 218 if (led.read() != 0) {
toshiyukisaito 0:fcfa8140d2db 219 led.write(0);
toshiyukisaito 0:fcfa8140d2db 220 } else {
toshiyukisaito 0:fcfa8140d2db 221 led.write(1);
toshiyukisaito 0:fcfa8140d2db 222 }
toshiyukisaito 0:fcfa8140d2db 223 }
toshiyukisaito 0:fcfa8140d2db 224 }
toshiyukisaito 0:fcfa8140d2db 225 }
toshiyukisaito 0:fcfa8140d2db 226
toshiyukisaito 0:fcfa8140d2db 227 int main(void) {
toshiyukisaito 0:fcfa8140d2db 228 #if DEBUG
toshiyukisaito 0:fcfa8140d2db 229 pc.baud(9600);
toshiyukisaito 0:fcfa8140d2db 230 pc.printf("INIT\r\n");
toshiyukisaito 0:fcfa8140d2db 231 #endif
toshiyukisaito 0:fcfa8140d2db 232
toshiyukisaito 0:fcfa8140d2db 233 Ticker ticker;
toshiyukisaito 0:fcfa8140d2db 234 ticker.attach_us(StatusCheckHundler, SWITCH_WATCH_INTERVAL * 1000 * 1000);
toshiyukisaito 0:fcfa8140d2db 235
toshiyukisaito 0:fcfa8140d2db 236 ble.init();
toshiyukisaito 0:fcfa8140d2db 237 ble.onDisconnection(disconnectionCallback);
toshiyukisaito 0:fcfa8140d2db 238 ble.onDataWritten(WrittenHandler);
toshiyukisaito 0:fcfa8140d2db 239
toshiyukisaito 0:fcfa8140d2db 240 // setup advertising
toshiyukisaito 0:fcfa8140d2db 241 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
toshiyukisaito 0:fcfa8140d2db 242 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
toshiyukisaito 0:fcfa8140d2db 243 ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
toshiyukisaito 0:fcfa8140d2db 244 (const uint8_t *)LOCAL_NAME, sizeof(LOCAL_NAME) - 1);
toshiyukisaito 0:fcfa8140d2db 245 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
toshiyukisaito 0:fcfa8140d2db 246 (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid));
toshiyukisaito 0:fcfa8140d2db 247 ble.setDeviceName(LOCAL_NAME);
toshiyukisaito 0:fcfa8140d2db 248 ble.setAdvertisingInterval(ADVERTISING_INTERVAL/0.625);
toshiyukisaito 0:fcfa8140d2db 249 ble.addService(uartService);
toshiyukisaito 0:fcfa8140d2db 250
toshiyukisaito 0:fcfa8140d2db 251 ble.startAdvertising();
toshiyukisaito 0:fcfa8140d2db 252
toshiyukisaito 0:fcfa8140d2db 253 // 起動時に、Lock状態にして、LEDを点灯させる(未ペアリングのため。)
toshiyukisaito 0:fcfa8140d2db 254 Thumbturn(false);
toshiyukisaito 0:fcfa8140d2db 255 led.write(0);
toshiyukisaito 0:fcfa8140d2db 256 toggle.mode(PullUp);
toshiyukisaito 0:fcfa8140d2db 257
toshiyukisaito 0:fcfa8140d2db 258 while(true) {
toshiyukisaito 0:fcfa8140d2db 259 ble.waitForEvent();
toshiyukisaito 0:fcfa8140d2db 260 }
toshiyukisaito 0:fcfa8140d2db 261 }