Created
February 11, 2014 04:35
-
-
Save jwhitehorn/8929306 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <avr/io.h> | |
#include <avr/interrupt.h> | |
#include <avr/sleep.h> | |
#include <util/delay.h> | |
#define PIN_CE 1 //Output | |
#define PIN_nCS 2 //Output | |
#define output_low(port,pin) port &= ~(1<<pin) | |
#define output_high(port,pin) port |= (1<<pin) | |
#define set_input(portdir,pin) portdir &= ~(1<<pin) | |
#define set_output(portdir,pin) portdir |= (1<<pin) | |
#define MY_MAC_0 0xEF | |
#define MY_MAC_1 0xFF | |
#define MY_MAC_2 0xC0 | |
#define MY_MAC_3 0xAA | |
#define MY_MAC_4 0x18 | |
#define MY_MAC_5 0x00 | |
ISR(PCINT0_vect) | |
{ | |
//useless | |
} | |
void btLeCrc(const uint8_t* data, uint8_t len, uint8_t* dst){ | |
uint8_t v, t, d; | |
while(len--){ | |
d = *data++; | |
for(v = 0; v < 8; v++, d >>= 1){ | |
t = dst[0] >> 7; | |
dst[0] <<= 1; | |
if(dst[1] & 0x80) dst[0] |= 1; | |
dst[1] <<= 1; | |
if(dst[2] & 0x80) dst[1] |= 1; | |
dst[2] <<= 1; | |
if(t != (d & 1)){ | |
dst[2] ^= 0x5B; | |
dst[1] ^= 0x06; | |
} | |
} | |
} | |
} | |
uint8_t swapbits(uint8_t a){ | |
uint8_t v = 0; | |
if(a & 0x80) v |= 0x01; | |
if(a & 0x40) v |= 0x02; | |
if(a & 0x20) v |= 0x04; | |
if(a & 0x10) v |= 0x08; | |
if(a & 0x08) v |= 0x10; | |
if(a & 0x04) v |= 0x20; | |
if(a & 0x02) v |= 0x40; | |
if(a & 0x01) v |= 0x80; | |
return v; | |
} | |
void btLeWhiten(uint8_t* data, uint8_t len, uint8_t whitenCoeff){ | |
uint8_t m; | |
while(len--){ | |
for(m = 1; m; m <<= 1){ | |
if(whitenCoeff & 0x80){ | |
whitenCoeff ^= 0x11; | |
(*data) ^= m; | |
} | |
whitenCoeff <<= 1; | |
} | |
data++; | |
} | |
} | |
static inline uint8_t btLeWhitenStart(uint8_t chan){ | |
//the value we actually use is what BT'd use left shifted one...makes our life easier | |
return swapbits(chan) | 2; | |
} | |
void btLePacketEncode(uint8_t* packet, uint8_t len, uint8_t chan){ | |
//length is of packet, including crc. pre-populate crc in packet with initial crc value! | |
uint8_t i, dataLen = len - 3; | |
btLeCrc(packet, dataLen, packet + dataLen); | |
for(i = 0; i < 3; i++, dataLen++) packet[dataLen] = swapbits(packet[dataLen]); | |
btLeWhiten(packet, len, btLeWhitenStart(chan)); | |
for(i = 0; i < len; i++) packet[i] = swapbits(packet[i]); | |
} | |
void SPI_init(void){ | |
DDRB = ((1<<DDB2)|(1<<DDB1)|(1<<DDB0)); //spi pins on port b MOSI SCK,SS outputs | |
SPCR = ((1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<CPOL)|(1<<CPHA)); // SPI enable, Master, f/16 | |
} | |
uint8_t spi_byte(uint8_t byte){ | |
SPDR = byte; | |
while(!(SPSR & (1<<SPIF))) | |
; | |
return SPDR; | |
} | |
void nrf_cmd(uint8_t cmd, uint8_t data){ | |
output_low(PORTB, PIN_nCS); | |
spi_byte(cmd); | |
spi_byte(data); | |
output_high(PORTB, PIN_nCS); | |
} | |
void nrf_simplebyte(uint8_t cmd){ | |
output_low(PORTB, PIN_nCS); | |
spi_byte(cmd); | |
output_high(PORTB, PIN_nCS); | |
} | |
void nrf_manybytes(uint8_t* data, uint8_t len){ | |
output_low(PORTB, PIN_nCS); | |
do{ | |
spi_byte(*data++); | |
}while(--len); | |
output_high(PORTB, PIN_nCS); | |
} | |
void fob_init (void){ | |
//DDRA = (uint8_t)~(1<<5); | |
DDRB = 0b00000110; | |
//PORTA = 0b10001111; | |
output_low(PORTB, PIN_CE); | |
TCCR0B = (1<<CS00); | |
MCUCR = (1<<SM1)|(1<<SE); | |
sei(); | |
} | |
int main (void) | |
{ | |
static const uint8_t chRf[] = {2, 26,80}; | |
static const uint8_t chLe[] = {37,38,39}; | |
uint8_t i, L, ch = 0; | |
uint8_t buf[32]; | |
fob_init(); | |
SPI_init(); | |
//DDRA |= 4; | |
//PORTA |= 4; | |
nrf_cmd(0x20, 0x12); //on, no crc, int on RX/TX done | |
nrf_cmd(0x21, 0x00); //no auto-acknowledge | |
nrf_cmd(0x22, 0x00); //no RX | |
nrf_cmd(0x23, 0x02); //5-byte address | |
nrf_cmd(0x24, 0x00); //no auto-retransmit | |
nrf_cmd(0x26, 0x06); //1MBps at 0dBm | |
nrf_cmd(0x27, 0x3E); //clear various flags | |
nrf_cmd(0x3C, 0x00); //no dynamic payloads | |
nrf_cmd(0x3D, 0x00); //no features | |
nrf_cmd(0x31, 32); //always RX 32 bytes | |
nrf_cmd(0x22, 0x01); //RX on pipe 0 | |
buf[0] = 0x30; //set addresses | |
buf[1] = swapbits(0x8E); | |
buf[2] = swapbits(0x89); | |
buf[3] = swapbits(0xBE); | |
buf[4] = swapbits(0xD6); | |
nrf_manybytes(buf, 5); | |
buf[0] = 0x2A; | |
nrf_manybytes(buf, 5); | |
while(1){ | |
L = 0; | |
buf[L++] = 0x42; //PDU type, given address is random | |
buf[L++] = 11;//17 bytes of payload | |
buf[L++] = MY_MAC_0; | |
buf[L++] = MY_MAC_1; | |
buf[L++] = MY_MAC_2; | |
buf[L++] = MY_MAC_3; | |
buf[L++] = MY_MAC_4; | |
buf[L++] = MY_MAC_5; | |
buf[L++] = 2; //flags (LE-only, limited discovery mode) | |
buf[L++] = 0x01; | |
buf[L++] = 0x05; | |
buf[L++] = 7; | |
buf[L++] = 0x08; | |
buf[L++] = 'n'; | |
buf[L++] = 'R'; | |
buf[L++] = 'F'; | |
buf[L++] = ' '; | |
buf[L++] = 'L'; | |
buf[L++] = 'E'; | |
buf[L++] = 0x55; //CRC start value: 0x555555 | |
buf[L++] = 0x55; | |
buf[L++] = 0x55; | |
if(++ch == sizeof(chRf)) ch = 0; | |
nrf_cmd(0x25, chRf[ch]); | |
nrf_cmd(0x27, 0x6E); //clear flags | |
btLePacketEncode(buf, L, chLe[ch]); | |
nrf_simplebyte(0xE2); //Clear RX Fifo | |
nrf_simplebyte(0xE1); //Clear TX Fifo | |
output_low(PORTB, PIN_nCS); | |
spi_byte(0xA0); | |
for(i = 0 ; i < L ; i++) spi_byte(buf[i]); | |
output_high(PORTB, PIN_nCS); | |
nrf_cmd(0x20, 0x12); //tx on | |
output_high(PORTB, PIN_CE); | |
_delay_ms(10); | |
output_low(PORTB, PIN_CE); //(in preparation of switching to RX quickly) | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment