Skip to content

Commit

Permalink
undo nRF24#646; add broken FakeBLE example
Browse files Browse the repository at this point in the history
  • Loading branch information
2bndy5 committed Oct 27, 2020
1 parent 5833cd0 commit 08f39fa
Show file tree
Hide file tree
Showing 8 changed files with 373 additions and 5 deletions.
30 changes: 27 additions & 3 deletions .github/workflows/build_arduino.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,14 @@ jobs:
- name: Compile examples
uses: arduino/compile-sketches@main
with:
# sketch-paths: |
# - examples_backup/GettingStarted
# - examples_backup/GettingStarted_CallResponse
sketch-paths: |
- examples/GettingStarted
- examples/GettingStarted_CallResponse
- examples/AcknowledgementPayloads
- examples/StreamingData
- examples/InterruptConfigure
- examples/MulticeiverDemo
- examples/FakeBLE
# - examples_backup/GettingStarted_HandlingData
# - examples_backup/GettingStarted_HandlingFailures
# - examples_backup/pingpair_ack
Expand All @@ -93,3 +98,22 @@ jobs:
# - examples_backup/Usage/led_remote
# - examples_backup/Usage/nordic_fob
fqbn: ${{ matrix.fqbn }}
attiny:
stradegy:
fail-fast: false

fqbn:
- arduino:avr:ATtinyX5
- arduino:avr:ATtinyX4

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Compile examples
uses: arduino/compile-sketches@main
with:
name: arduino:avr
source-url: https://github.com/damellis/attiny.git
sketch-paths: - examples/rf24_ATTiny
fqbn: ${{ matrix.fqbn }}
40 changes: 40 additions & 0 deletions RF24.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1608,3 +1608,43 @@ void RF24::stopConstCarrier()
write_register(RF_SETUP, (read_register(RF_SETUP)) & ~_BV(CONT_WAVE) & ~_BV(PLL_LOCK));
ce(LOW);
}

//ATTiny support code pulled in from https://github.com/jscrane/RF24
#if defined(RF24_TINY)

void SPIClass::begin() {
// set USCK and DO for output
// set DI for input
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
DDRB |= (1 << PB2) | (1 << PB1);
DDRB &= ~(1 << PB0);
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
DDRA |= (1 << PA4) | (1 << PA5);
DDRA &= ~(1 << PA6);
#elif defined(__AVR_ATtiny2313__) || defined(__AVR_ATtiny4313__)
DDRB |= (1 << PB7) | (1 << PB6);
DDRB &= ~(1 << PB5);
#elif defined(__AVR_ATtiny861__)
DDRB |= (1 << PB2) | (1 << PB1);
DDRB &= ~(1 << PB0);
#endif // defined(__AVR_ATtiny861__)
USICR = _BV(USIWM0);
}

byte SPIClass::transfer(byte b)
{
USIDR = b;
USISR = _BV(USIOIF);
do {
USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC);
}
while ((USISR & _BV(USIOIF)) == 0);
return USIDR;
}

void SPIClass::end() {}
void SPIClass::setDataMode(uint8_t mode){}
void SPIClass::setBitOrder(uint8_t bitOrder){}
void SPIClass::setClockDivider(uint8_t rate){}

#endif
249 changes: 249 additions & 0 deletions examples/FakeBLE/FakeBLE.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/*
* See documentation at https://tmrh20.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/

/**
* A simple example of using the nRF24L01 transceiver as a BLE advertising
* beacon.
*
* Original research was done by Dmitry Grinberg; his research can be found at
* http://dmitry.gr/index.php?r=05.Projects&proj=11.%20Bluetooth%20LE%20fakery
*
* Some of this example's code has been taken from Dmitry Grinberg's research,
* while other bits of code has been derived from the
* BTLE library by Florian Echtler. If this example seems to limited for your
* projects needs, we highly recommend Florian Echtler's BTLE library, which
* can be found in the Arduino IDE and directly on github at
* https://github.com/floe/BTLE
*/
#include <SPI.h>
#include "RF24.h"

// instantiate an object for the nRF24L01 transceiver
RF24 radio(6, 5); // using pin 7 for the CE pin, and pin 8 for the CSN pin

// BLE only operates on 3 specified frequencies channels. It usually employ a
// technique called "channel hopping"
const uint8_t frequency[3] = {2, 26, 80}; // translates {37, 38, 39} per BLE
uint8_t currentChannel = 0; // used for "channel hopping"

// Because the nRF24L01 transceiver wasn't designed for BLE advertisements,
// this technique has some limits. The members of the following struct that
// are not declared as `const` can be adjusted (except checksum).
struct PayloadStruct {
uint8_t pduType = 0x42; // iPhone & Android compatible
const uint8_t size = 27; // actual size is 30 + size bytes
uint8_t mac[6]; // an arbitrary 6 byte MAC address
const uint8_t flags[3] = {0x02, 0x01, 0x05}; // 0x05 = discoverable & non-connectable
const uint8_t namePrefix[2] = {0x04, 0x08}; // appears as "short name"
uint8_t name[3] = {'n', 'R', 'F'}; // must be 3 bytes long in this example
const uint8_t prefixBatt[4] = {0x04, 0x16, 0x0F, 0x18}; // Battery service data header
uint8_t batteryPercent; // we can set this in loop()
const uint8_t prefixTemp[4] = {0x07, 0x16, 0x09, 0x18}; // temperature service data header
int8_t temperatureInC[4]; // we can set this with temperatureData()
uint8_t checksum[3] = {0x55, 0x55, 0x55}; // we set this with crc24()
};
PayloadStruct payload; // instantiate the payload

// we a buffer to manipulate the data without altering the payload values
uint8_t packet[32]; // allocate 32 bytes for copying the payload data

void temperatureData(float celcius);
void crc(uint8_t *data, uint8_t len, uint8_t* checksum);
void swapbuf(uint8_t *data, uint8_t len);
void whiten(uint8_t *data, uint8_t len);

void setup() {

Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
}

// initialize the transceiver on the SPI bus
if (!radio.begin()) {
Serial.println(F("nRF24L01 is not responding!!"));
while(1) {} // hold in infinite loop
}

// print example's introductory prompt
Serial.println(F("RF24/examples/FakeBLE"));
Serial.println(F("Advertising"));


// initialize the random number generator and use it to set the MAC address
// randomSeed(analogRead(A3)); // analog input pin A3 is open/unconnected
// for (uint8_t i = 0; i < 6; ++i)
// payload.mac[i] = random(255); // use a random byte

// or make the mac address consistent
uint8_t mac[] = {0xa1, 0xb2, 0xc3, 0xd4, 0xe5, 0xf6};
for (uint8_t i = 0; i < 6; ++i)
payload.mac[i] = mac[i]; // use a preset address

payload.batteryPercent = 85;
temperatureData(42.0);

memcpy(packet, &payload, 32);
crc(packet, 29, packet + 29);
for (uint8_t i = 0; i < 32; ++i) {
Serial.print("packet[");
Serial.print(i);
Serial.print("]");
Serial.println(packet[i], HEX);
}

// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other. BLE specifications allow this to be changed.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.

// The following functions disable the features that are incompatible with BLE specifications
radio.disableDynamicPayloads(); // disable dynamic payloads
radio.setAutoAck(false); // disable auto-ack feature
radio.disableCRC(); // disable CRC checking
radio.setRetries(0, 0); // disable auto-retry feature

// the following functions configure the nRF24L01 to be compatible with BLE
// specifications.
radio.setDataRate(RF24_1MBPS);
radio.setAddressWidth(4);
radio.openWritingPipe(0x6B7D9171);
radio.setChannel(frequency[currentChannel]); // we will manage this in the loop()
radio.stopListening(); // powerUp() into TX mode
} // setup

void loop() {
// broadcast BLE advertisement, hop channel, then wait till next try

// set the service data
payload.batteryPercent = 85; // must be a percentage in range [0, 100]
temperatureData(42.0); // degree of percision = 2 decimal places

// prepare the payload for BLE compliance
memcpy(packet, &payload, 32); // copy payload to a temporary buffer
crc(packet, 29, packet + 29); // calculate checksum
whiten(packet, 32); // whiten (to avoid repeating bit patterns OTA)
swapbuf(packet, 32); // reverse the bit order

// broadcast advertisement payload
if (radio.write(&packet, 32)) {
// print something to show the program isn't frozen
// Serial.println('*');

// hop to next frequency
currentChannel += currentChannel < 2 ? 1 : -2; // increment frequency index
radio.setChannel(frequency[currentChannel]); // set new frequency
delayMicroseconds(150); // let the change in channel settle

} else {
// due to all the features that disabled, we will never get here.
// Serial.println(F("There must be a power supply problem.")); // if we do get here
}

// slow down transmissions so save power
delay(500); // change this to your liking (preferrably in range [10, 10000] ms)
}

void temperatureData(float celcius) {
// set the temperature as a 4 byte float
payload.temperatureInC[3] = ((int8_t)(-2) & 0xFF); // exponent
int32_t base = (int32_t)(celcius * 100);
payload.temperatureInC[2] = (base & 0xFF0000) >> 16;
payload.temperatureInC[1] = (base & 0xFF00) >> 8;
payload.temperatureInC[0] = (base & 0xFF);
}

void crc(uint8_t *data, uint8_t len, uint8_t* dst) {
// calculate CRC24 with according to BT Core Spec 4.0, Section 6.B.3.1.1

uint8_t *buffer = (uint8_t*)&data;
// initialize 24-bit shift register in "wire bit order"
// dst[0] = bits 23-16, dst[1] = bits 15-8, dst[2] = bits 7-0
// dst[0] = 0xAA;
// dst[1] = 0xAA;
// dst[2] = 0xAA;

while (len--) {

uint8_t d = *(buffer++);

for (uint8_t i = 1; i; i <<= 1, d >>= 1) {

// save bit 23 (highest-value), left-shift the entire register by one
uint8_t t = dst[0] & 0x01; dst[0] >>= 1;
if (dst[1] & 0x01) dst[0] |= 0x80; dst[1] >>= 1;
if (dst[2] & 0x01) dst[1] |= 0x80; dst[2] >>= 1;

// if the bit just shifted out (former bit 23) and the incoming data
// bit are not equal (i.e. bit_out ^ bit_in == 1) => toggle tap bits
if (t != (d & 1)) {
// toggle register tap bits (=XOR with 1) according to CRC polynom
dst[2] ^= 0xDA; // 0b11011010 inv. = 0b01011011 ^= x^6+x^4+x^3+x+1
dst[1] ^= 0x60; // 0b01100000 inv. = 0b00000110 ^= x^10+x^9
}
}
}
// for (uint8_t i = 0; i < 3; ++i) {
// Serial.print("calc'd crc[");
// Serial.print(i);
// Serial.print("]");
// Serial.println(dst[i], HEX);
// }
}

void swapbuf(uint8_t *data, uint8_t len) {

uint8_t *buffer = data;

while (len--) {
// reverse all the bits for each byte
uint8_t a = *buffer;
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;

*(buffer++) = v;
}
// for (uint8_t i = 0; i < 31; ++i) {
// Serial.print("swapped[");
// Serial.print(i);
// Serial.print("]");
// Serial.println(packet[i], HEX);
// }
}

void whiten(uint8_t *data, uint8_t len) {
// whiten the payload so that there are less repeating bits (for OTA stability)

// initialize LFSR with current channel, set bit 6
uint8_t lfsr = (currentChannel + 37) | 0x40;

while (len--) {
uint8_t res = 0;
// LFSR in "wire bit order"
for (uint8_t i = 1; i; i <<= 1) {
if (lfsr & 0x01) {
lfsr ^= 0x88;
res |= i;
}
lfsr >>= 1;
}
*(data++) ^= res;
}
// for (uint8_t i = 0; i < 31; ++i) {
// Serial.print("whitened[");
// Serial.print(i);
// Serial.print("]");
// Serial.println(packet[i], HEX);
// }
}
4 changes: 2 additions & 2 deletions utility/ATTiny/RF24_arch_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
#include <Arduino.h>
#endif

#include <stddef.h>
#include <stddef.h>

#include <SPI.h>
#include "SPI.h"

#define _SPI SPI

Expand Down
Loading

0 comments on commit 08f39fa

Please sign in to comment.