Added inital software build of control software to repo
Added inital software build of control software to repo

--- /dev/null
+++ b/code/BLE_AC_Controller/BLE_AC_Controller.ino
@@ -1,1 +1,436 @@
-
+#include <RFduinoBLE.h>
+#include <inttypes.h>
+#include <string.h>
+#include <Wire.h>
+
+#include "hotp.h"
+
+#define TRIAC_PIN 2
+#define SWITCH_PIN 3
+#define SCL_PIN 5
+#define SDA_PIN 6
+
+#define MB85RC_ADDRESS 0x50
+#define MB85RC_SLAVE_ID 0xF8
+
+#define FRAM_SIZE 512
+#define HOTP_BLOCKS FRAM_SIZE / sizeof(hotp)
+
+#define COMMAND_BUFFER_SIZE 40
+#define RANDOM_BUFFER_SIZE 4
+
+#define ON 0x01
+#define OFF 0x02
+#define DISABLE_SWITCH 0x03
+#define ENABLE_SWITCH 0x04
+#define SPOOKY_MODE 0x05
+
+hotp hotp_clients[HOTP_BLOCKS];
+
+char command_buffer[COMMAND_BUFFER_SIZE];
+uint8_t command_buffer_pos;
+
+uint8_t random_buffer[RANDOM_BUFFER_SIZE];
+uint8_t random_buffer_pos;
+
+uint8_t mode = OFF;
+uint8_t state = OFF;
+
+uint8_t switch_state;
+
+void triac_on(){
+    state = ON;
+    digitalWrite(TRIAC_PIN, HIGH);
+}
+
+void triac_off(){
+  state = OFF;
+  digitalWrite(TRIAC_PIN, LOW);
+}
+
+void triac_toggle(){
+
+  if(state == OFF)
+    triac_on();
+  else if(state == ON)
+    triac_off();
+
+}
+
+int switch_isr(uint32_t ulPin){
+
+  Serial.print("Switch Toggle\n\r");
+
+  if(mode != SPOOKY_MODE && mode != DISABLE_SWITCH){
+    triac_toggle();
+  }
+
+  return 0;
+
+}
+
+void setup() {
+
+  Serial.begin(9600);
+
+  pinMode(SWITCH_PIN, INPUT_PULLUP);
+  pinMode(TRIAC_PIN, OUTPUT);
+  digitalWrite(TRIAC_PIN, LOW);
+
+  switch_state = digitalRead(SWITCH_PIN);
+
+  //RFduino_pinWakeCallback(SWITCH_PIN, HIGH, switch_isr);
+  //NVIC_EnableIRQ(GPIOTE_IRQn);
+  //NRF_GPIOTE->CONFIG[0] =  (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos)
+  //            | (SWITCH_PIN << GPIOTE_CONFIG_PSEL_Pos)
+  //            | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
+  //NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos;
+
+  Wire.begin();
+
+  for(int i = 0; i < HOTP_BLOCKS; i++)
+    read_hotp(&hotp_clients[i], i);
+
+  RFduinoBLE.customUUID = "ac85f920-76bb-11e4-b116-123b93f75cba";
+  RFduinoBLE.advertisementData = "ac_control";
+  RFduinoBLE.advertisementInterval = 2000; // 2 seconds
+  RFduinoBLE.begin();
+
+  command_buffer_pos = 0;
+
+}
+
+void RFduinoBLE_onConnect(){
+}
+
+void RFduinoBLE_onDisconnect(){
+}
+
+void RFduinoBLE_onReceive(char *data, int len){
+
+  Serial.print(len);
+  Serial.print("\n\r");
+
+  if(len >= 6){
+
+    uint8_t cmd = data[1];
+    uint8_t idx = data[2];
+
+    int val = 0;
+    val = (val << 8) + data[3];
+    val = (val << 8) + data[4];
+    val = (val << 8) + data[5];
+    val = (val << 8) + data[6];
+
+    if(idx < HOTP_BLOCKS){
+
+      if(hotp_clients[idx].enabled){
+
+        Serial.print("Command: ");
+        Serial.print(cmd);
+        Serial.print("\n\rHMAC: ");
+        Serial.print(val);
+        Serial.print("\n\r");
+    
+        bool match = hotp_check(&hotp_clients[idx], val);
+    
+        Serial.print("Status: ");
+        Serial.print(match);
+        Serial.print("\n\r");
+    
+        if(match){
+    
+          write_hotp_counter(&hotp_clients[idx], idx);
+
+          if(cmd == ON){
+            digitalWrite(TRIAC_PIN, HIGH);
+            if(mode == SPOOKY_MODE)
+              mode = ON;
+          } else if(cmd == OFF) {
+            digitalWrite(TRIAC_PIN, LOW);
+            if(mode == SPOOKY_MODE)
+              mode = OFF;
+          } else if(cmd == SPOOKY_MODE){
+            mode = SPOOKY_MODE;
+          } else if(cmd == DISABLE_SWITCH){
+            mode = DISABLE_SWITCH;
+          } else if(cmd == ENABLE_SWITCH){
+            mode = ENABLE_SWITCH;
+          }
+    
+        } else {
+          Serial.print("Bad OTP\n\r");
+        }
+      } else {
+        Serial.print("User ID not enabled\n\r");
+      }
+
+    } else {
+      Serial.print("User ID out of range\n\r");
+    }
+
+  } else {
+      Serial.print("Message to short\n\r");
+  }
+
+}
+
+void print_hotp(hotp *_hotp){
+
+  Serial.print("Enabled: ");
+  Serial.print(_hotp->enabled);
+  Serial.print("\n\r");
+  Serial.print("Key: ");
+  for(uint8_t i = 0; i < _hotp->key_len; i++)
+    Serial.print((char) _hotp->key[i]);
+  Serial.print("\n\r");
+  Serial.print("Counter: ");
+  Serial.print((long)_hotp->counter);
+  Serial.print("\n\r");
+
+}
+
+void write_hotp_counter(hotp *_hotp, uint8_t idx){
+
+  uint8_t addr = MB85RC_ADDRESS;
+  if((idx * sizeof(hotp)) + offsetof(hotp, counter) >= 0x100)
+    addr |= 0x02;
+
+  Wire.beginTransmission(addr);
+  Wire.write(((idx * sizeof(hotp))  + offsetof(hotp, counter)) % 0x100);
+
+  for(uint8_t i = 0; i < sizeof(uint64_t); i++)
+    Wire.write(((uint8_t*)&(_hotp->counter))[i]);
+
+  Wire.endTransmission();
+
+}
+
+void write_hotp(hotp *_hotp, uint8_t idx){
+
+  uint8_t addr = MB85RC_ADDRESS;
+  if(idx * sizeof(hotp) >= 0x100)
+    addr |= 0x02;
+
+  Wire.beginTransmission(addr);
+  Wire.write((idx * sizeof(hotp)) % 0x100);
+
+  for(uint8_t i = 0; i < sizeof(hotp); i++)
+    Wire.write(((uint8_t*)_hotp)[i]);
+
+  Wire.endTransmission();
+
+}
+
+void read_hotp(hotp *_hotp, uint8_t idx){
+
+  uint8_t addr = MB85RC_ADDRESS;
+  if(idx * sizeof(hotp) >= 0x100)
+    addr |= 0x02;
+
+  Wire.beginTransmission(addr);
+  Wire.write((idx * sizeof(hotp)) % 0x100);
+  Wire.endTransmission();
+
+  Wire.requestFrom(addr, (uint8_t) sizeof(hotp));
+
+  for(uint8_t i = 0; i < sizeof(hotp); i++)
+    ((uint8_t*)_hotp)[i] = Wire.read();
+
+}
+
+void get_fram_id(uint16_t* manufacturer_id, uint16_t* product_id){
+
+  uint8_t a[3] = {0, 0, 0};
+
+  Wire.beginTransmission(MB85RC_SLAVE_ID >> 1);
+  Wire.write(MB85RC_ADDRESS << 1);
+  Wire.endTransmission(false);
+
+  Wire.requestFrom(MB85RC_SLAVE_ID >> 1, 3);
+  a[0] = Wire.read();
+  a[1] = Wire.read();
+  a[2] = Wire.read();
+
+  *manufacturer_id = (a[0] << 4) + (a[1] >> 4);
+  *product_id = ((a[1] & 0x0F) << 8) + a[2];
+
+}
+
+bool check_idx(int idx){
+
+  if(idx >= 0 && idx < HOTP_BLOCKS)
+    return true;
+  else {
+    Serial.print("Bad index: ");
+    Serial.print(idx);
+    Serial.print("\n\r");
+  }
+  return false;
+
+}
+
+void proccess_command_char(char c){
+
+  switch(c){
+    case 0x0A:
+    case 0x0D:
+      Serial.print("\n\r");
+      command_buffer[command_buffer_pos] = '\0';
+      if(strcmp(command_buffer, "next") == 0){
+        Serial.print("HOTP: ");
+        Serial.print(hotp_next(&hotp_clients[0]));
+        write_hotp_counter(&hotp_clients[0], 0);
+        Serial.print("\n\r");
+      }
+      else if(strncmp(command_buffer, "hotp_set_key", 12) == 0){
+        char * space = strchr(&(command_buffer[13]), ' ');
+        if(space > 0){
+
+          *space = '\0';
+          int idx = atoi(&(command_buffer[13]));
+
+          if(check_idx(idx)){
+
+            int len = strlen(space + 1);
+            if(len <= MAX_KEY_LENGTH){
+              memcpy(hotp_clients[idx].key, space + 1, len);
+              hotp_clients[idx].key_len = len;
+              write_hotp(&hotp_clients[idx], idx);
+            } else {
+              Serial.print("Key to long\n\r");
+            }
+
+          }
+
+        } else {
+          Serial.print("Not enough arguments\n\r");
+        }
+      }
+      else if(strncmp(command_buffer, "switch_read", 11) == 0){
+        Serial.print("Switch state: ");
+        Serial.print(digitalRead(SWITCH_PIN));
+        Serial.print("\n\r");
+      }
+      else if(strncmp(command_buffer, "state", 5) == 0){
+        Serial.print("State: ");
+        Serial.print(state);
+        Serial.print("\n\r");
+      }
+      else if(strncmp(command_buffer, "hotp_reset_counter", 18) == 0){
+        int idx = atoi(&(command_buffer[19]));
+        if(check_idx(idx)){
+          hotp_clients[idx].counter = 0;
+          write_hotp(&hotp_clients[idx], idx);
+        }
+      }
+      else if(strncmp(command_buffer, "hotp_enable", 11) == 0){
+        int idx = atoi(&(command_buffer[12]));
+        if(check_idx(idx)){
+          hotp_clients[idx].enabled = true;
+          write_hotp(&hotp_clients[idx], idx);
+        }
+      }
+      else if(strncmp(command_buffer, "hotp_disable", 12) == 0){
+        int idx = atoi(&(command_buffer[13]));
+        if(check_idx(idx)){
+          hotp_clients[idx].enabled = false;
+          write_hotp(&hotp_clients[idx], idx);
+        }
+      }
+      else if(strncmp(command_buffer, "hotp_info", 9) == 0){
+        int idx = atoi(&(command_buffer[10]));
+        if(check_idx(idx))
+          print_hotp(&hotp_clients[idx]);
+      }
+      else if(strcmp(command_buffer, "id") == 0){
+        Serial.print("ID: ");
+        Serial.print((long) getDeviceId());
+        Serial.print("\n\r");
+      }
+      else if(strcmp(command_buffer, "framid") == 0){
+
+        uint16_t manufacturer_id;
+        uint16_t product_id;
+        get_fram_id(&manufacturer_id, &product_id);
+
+        Serial.print("Manufacturer: ");
+        Serial.print(manufacturer_id);
+        Serial.print("\n\r");
+
+        Serial.print("Product: ");
+        Serial.print(product_id);
+        Serial.print("\n\r");
+
+      }
+      else if(strcmp(command_buffer, "off") == 0){
+        triac_off();
+        mode = ON;
+      }
+      else if(strcmp(command_buffer, "on") == 0){
+        triac_on();
+        mode = OFF;
+      }
+      else if(strcmp(command_buffer, "toggle") == 0){
+        triac_toggle();
+      }
+      else if(strcmp(command_buffer, "disable_switch") == 0){
+        mode = DISABLE_SWITCH;
+      }
+      else if(strcmp(command_buffer, "enable_switch") == 0){
+        mode = ENABLE_SWITCH;
+      }
+      else if(strcmp(command_buffer, "spooky") == 0){
+        mode = SPOOKY_MODE;
+      }
+      else {
+        Serial.print("Unknown Command...\n\r");
+      }
+      command_buffer_pos = 0;
+      break;
+    case 0x7F:
+    case 0x08:
+      if(command_buffer_pos > 0){
+        command_buffer_pos--;
+        Serial.print(c);
+      }
+      break;
+    default:
+      command_buffer[command_buffer_pos++] = c;
+      if(command_buffer_pos == COMMAND_BUFFER_SIZE)
+        command_buffer_pos--;
+      else Serial.print(c);
+      break;
+  }
+
+}
+
+unsigned long last_time;
+long rand_num = 0;
+
+void loop() {
+
+  uint8_t new_switch_state = digitalRead(SWITCH_PIN);
+  if(new_switch_state != switch_state){
+    switch_isr(SWITCH_PIN);
+    switch_state = new_switch_state;
+  }
+
+  if(mode == SPOOKY_MODE){
+    unsigned long cur_time = millis();
+    if(last_time + rand_num < cur_time){
+      triac_toggle();
+      last_time = cur_time;
+      rand_num = random(1000);
+      if(rand_num == 0)
+        rand_num = 1;
+      rand_num = (3 - log(rand_num)) * 333;
+    }
+  }
+
+  if(Serial.available() != 0)
+    proccess_command_char(Serial.read());
+
+}
+
+

--- /dev/null
+++ b/code/BLE_AC_Controller/hotp.c
@@ -1,1 +1,60 @@
+#include "hotp.h"
 
+long calc_hotp(const uint8_t *key, uint8_t len, uint64_t counter){
+
+	uint8_t *hash;
+	uint8_t i;
+
+	uint8_t buf[8];
+
+	for(i = 0; i < 8; i++)
+		buf[i] = ((uint8_t*)&counter)[7 - i];
+
+	sha1 sha_hash;
+
+	sha1_init_hmac(&sha_hash, key, len);
+	sha1_write_data(&sha_hash, buf, 8);
+	hash = sha1_result_hmac(&sha_hash);
+
+	int offset = hash[19] & 0xF;
+	long otp = 0;
+	for(i = 0; i < 4; ++i){
+		otp = otp << 8;
+		otp = otp | hash[offset + i];
+	}
+
+	otp = otp & 0x7FFFFFFF;
+
+	return otp;
+
+}
+
+void hotp_init(hotp *self, const uint8_t *key, uint8_t len, uint64_t start){
+
+	memcpy(self->key, key, len);
+	self->key_len = len;
+	self->counter = start;
+	self->enabled = true;
+
+}
+
+long hotp_next(hotp *self){
+
+	return calc_hotp(self->key, self->key_len, self->counter++);
+
+}
+
+bool hotp_check(hotp *self, int value){
+
+  long val = calc_hotp(self->key, self->key_len, self->counter);
+  if(value == val){
+    self->counter++;
+    return true;
+  }
+  else {
+    return false;
+  }
+
+}
+
+

--- /dev/null
+++ b/code/BLE_AC_Controller/hotp.h
@@ -1,1 +1,36 @@
+#ifndef HOTP_H
+#define HOTP_H
 
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "sha1.h"
+
+#define MAX_KEY_LENGTH 20
+
+typedef struct {
+
+        uint8_t enabled;
+  	uint8_t reserved[2];
+	uint8_t key[MAX_KEY_LENGTH];
+	uint8_t key_len;
+	uint64_t counter;
+
+} hotp;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+long calc_hotp(const uint8_t *key, uint8_t len, uint64_t counter);
+void hotp_init(hotp *self, const uint8_t *key, uint8_t len, uint64_t start);
+long hotp_next(hotp *self);
+bool hotp_check(hotp *self, int value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+

--- /dev/null
+++ b/code/BLE_AC_Controller/sha1.c
@@ -1,1 +1,208 @@
-
+#include "sha1.h"
+
+#define SHA1_K0 0x5a827999
+#define SHA1_K20 0x6ed9eba1
+#define SHA1_K40 0x8f1bbcdc
+#define SHA1_K60 0xca62c1d6
+
+static const uint8_t sha1_init_state[] = {
+
+	0x01, 0x23, 0x45, 0x67, // H0
+	0x89, 0xab, 0xcd, 0xef, // H1
+	0xfe, 0xdc, 0xba, 0x98, // H2
+	0x76, 0x54, 0x32, 0x10, // H3
+	0xf0, 0xe1, 0xd2, 0xc3  // H4
+
+};
+
+void sha1_init(sha1 *self){
+
+	memcpy(self->state.b, sha1_init_state, HASH_LENGTH);
+	self->byte_count = 0;
+	self->buffer_offset = 0;
+
+}
+
+static uint32_t rol32(uint32_t number, uint8_t bits){
+
+	return ((number << bits) | (number >> (32 - bits)));
+
+}
+
+static void sha1_hash_block(sha1 *self){
+
+	uint8_t i;
+	uint32_t a, b, c, d, e, t;
+
+	a = self->state.w[0];
+	b = self->state.w[1];
+	c = self->state.w[2];
+	d = self->state.w[3];
+	e = self->state.w[4];
+
+	for(i = 0; i < 80; i++){
+
+		if(i >= 16){
+
+			t =   self->buffer.w[(i + 13) & 15]
+				^ self->buffer.w[(i + 8) & 15]
+				^ self->buffer.w[(i + 2) & 15]
+				^ self->buffer.w[i & 15];
+			self->buffer.w[i & 15] = rol32(t, 1);
+
+		}
+
+		if(i < 20){
+			t = (d ^ (b & (c ^ d))) + SHA1_K0;
+		} else if(i < 40){
+			t = (b ^ c ^ d) + SHA1_K20;
+		} else if(i < 60){
+			t = ((b & c) | (d & (b | c))) + SHA1_K40;
+		} else {
+			t = (b ^ c ^ d) + SHA1_K60;
+		}
+
+		t += rol32(a, 5) + e + self->buffer.w[i & 15];
+		e = d;
+		d = c;
+
+		c = rol32(b, 30);
+		b = a;
+		a = t;
+
+	}
+
+	self->state.w[0] += a;
+	self->state.w[1] += b;
+	self->state.w[2] += c;
+	self->state.w[3] += d;
+	self->state.w[4] += e;
+
+}
+
+static void sha1_add_uncounted(sha1 *self, uint8_t data){
+
+	self->buffer.b[self->buffer_offset ^ 3] = data;
+	self->buffer_offset++;
+
+	if(self->buffer_offset == BLOCK_LENGTH){
+		sha1_hash_block(self);
+		self->buffer_offset = 0;
+	}
+
+}
+
+void sha1_write(sha1 *self, uint8_t data){
+
+	++self->byte_count;
+	sha1_add_uncounted(self, data);
+
+}
+
+void sha1_write_data(sha1 *self, const uint8_t *data, uint8_t len){
+
+	uint8_t i;
+
+	for(i = 0; i < len; i++) sha1_write(self, data[i]);
+
+}
+
+static void sha1_pad(sha1 *self){
+
+	// Implement SHA-1 padding (fips180-2 §5.1.1)
+
+	// Pad with 0x80 followed by 0x00 until the end of the block
+	sha1_add_uncounted(self, 0x80);
+	while(self->buffer_offset != 56) sha1_add_uncounted(self, 0x00);
+
+	// Append length in the last 8 bytes
+	sha1_add_uncounted(self, 0); // We're only using 32 bit lengths
+	sha1_add_uncounted(self, 0); // But SHA-1 supports 64 bit lengths
+	sha1_add_uncounted(self, 0); // So zero pad the top bits
+	sha1_add_uncounted(self, self->byte_count >> 29); // Shifting to multiply by 8
+	sha1_add_uncounted(self, self->byte_count >> 21); // as SHA-1 supports bitstreams as well as
+	sha1_add_uncounted(self, self->byte_count >> 13); // byte.
+	sha1_add_uncounted(self, self->byte_count >> 5);
+	sha1_add_uncounted(self, self->byte_count << 3);
+
+}
+
+
+uint8_t* sha1_result(sha1 *self){
+
+	uint8_t i;
+
+	// Pad to complete the last block
+	sha1_pad(self);
+  
+	// Swap byte order back
+	for(i = 0; i < 5; i++){
+
+		uint32_t a, b;
+
+		a = self->state.w[i];
+		b = a << 24;
+		b |= (a << 8) & 0x00ff0000;
+		b |= (a >> 8) & 0x0000ff00;
+		b |= a >> 24;
+
+		self->state.w[i] = b;
+
+	}
+  
+	// Return pointer to hash (20 characters)
+	return self->state.b;
+
+}
+
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+
+void sha1_init_hmac(sha1 *self, const uint8_t* key, int key_length){
+
+	uint8_t i;
+
+	memset(self->key_buffer, 0, BLOCK_LENGTH);
+
+	if(key_length > BLOCK_LENGTH){
+
+		// Hash long keys
+		sha1_init(self);
+		for(;key_length--;) sha1_write(self, *key++);
+
+		memcpy(self->key_buffer, sha1_result(self), HASH_LENGTH);
+
+	} else {
+
+		// Block length keys are used as is
+		memcpy(self->key_buffer, key, key_length);
+
+	}
+
+	// Start inner hash
+	sha1_init(self);
+
+	for(i = 0; i < BLOCK_LENGTH; i++){
+		sha1_write(self, self->key_buffer[i] ^ HMAC_IPAD);
+	}
+
+}
+
+uint8_t* sha1_result_hmac(sha1 *self){
+
+	uint8_t i;
+
+	// Complete inner hash
+	memcpy(self->inner_hash, sha1_result(self), HASH_LENGTH);
+
+	// Calculate outer hash
+	sha1_init(self);
+
+	for(i = 0; i < BLOCK_LENGTH; i++) sha1_write(self, self->key_buffer[i] ^ HMAC_OPAD);
+	for(i = 0; i < HASH_LENGTH; i++) sha1_write(self, self->inner_hash[i]);
+
+	return sha1_result(self);
+
+}
+
+

--- /dev/null
+++ b/code/BLE_AC_Controller/sha1.h
@@ -1,1 +1,51 @@
+#ifndef SHA1_H
+#define SHA1_H
 
+#include <inttypes.h>
+#include <string.h>
+#include "sha1.h"
+
+#define HASH_LENGTH 20
+#define BLOCK_LENGTH 64
+
+typedef union {
+
+  uint8_t b[BLOCK_LENGTH];
+  uint32_t w[BLOCK_LENGTH/4];
+
+} _buffer;
+
+typedef union {
+
+  uint8_t b[HASH_LENGTH];
+  uint32_t w[HASH_LENGTH/4];
+
+} _state;
+
+typedef struct {
+
+    _buffer buffer;
+    _state state;
+    uint8_t buffer_offset;
+    uint32_t byte_count;
+    uint8_t key_buffer[BLOCK_LENGTH];
+    uint8_t inner_hash[HASH_LENGTH];
+    
+} sha1;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void sha1_write_data(sha1 *self, const uint8_t *data, uint8_t len);
+void sha1_write(sha1 *self, const uint8_t data);
+void sha1_init_hmac(sha1 *self, const uint8_t* key, int key_length);
+uint8_t* sha1_result_hmac(sha1 *self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+