OTA Bootloader
- including adjustments to library header files to allow usage across C (bootloader) and C++ (firmware sketches) - including definition of new message types for firmware config and firmware code
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
*.o
|
||||
*.hex
|
||||
*.elf
|
||||
@@ -0,0 +1,66 @@
|
||||
PROJECT = MyOtaBootloader
|
||||
INCLUDES = ../libraries/MySensors
|
||||
|
||||
MCU = atmega328p
|
||||
CLK = 16000000L
|
||||
|
||||
ISP_PORT = com5
|
||||
ISP_SPEED = 115200
|
||||
ISP_PROTOCOL = stk500v2
|
||||
ISP_MCU = m328p
|
||||
# HFUSE = D8 - 4096 byte boot
|
||||
ISP_HFUSE = D8
|
||||
# LFUSE = 4E - Low power resonator (16MHz), fast start, clkdiv/8
|
||||
ISP_LFUSE = FF
|
||||
# EFUSE = 06 - 1.8V brownout
|
||||
ISP_EFUSE = 06
|
||||
ISP_ARGS = -c$(ISP_PROTOCOL) -P$(ISP_PORT) -b$(ISP_SPEED) -p$(ISP_MCU)
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
BINPATH = C:/Program Files (x86)/Arduino/hardware/tools/avr/bin/
|
||||
JAVAPATH = C:/Program Files/Java/jdk1.7.0_40/bin/
|
||||
JAVAC = $(JAVAPATH)javac.exe
|
||||
JAVA = $(JAVAPATH)java.exe
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
UNAME_P := $(shell uname -p)
|
||||
UNAME_M := $(shell uname -m)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
ifeq ($(UNAME_P),x86_64)
|
||||
BINPATH = ../arduino/bin-linux64/bin/
|
||||
else ifneq ($(filter %86,$(UNAME_P)),)
|
||||
BINPATH = ../arduino/bin-linux32/bin/
|
||||
else ifneq ($(filter arm%,$(UNAME_M)),)
|
||||
BINPATH = /usr/bin/
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS = -c -g -Os -fno-inline-small-functions -fno-split-wide-types -mshort-calls -Wall -mmcu=$(MCU) -DF_CPU=$(CLK) -std=gnu99
|
||||
LDFLAGS = -Os -Wl,--section-start=.text=0x7000 -nostartfiles -mmcu=$(MCU)
|
||||
|
||||
all: clean out
|
||||
|
||||
clean:
|
||||
- rm *.o
|
||||
- rm *.elf
|
||||
- rm *.hex
|
||||
|
||||
$(PROJECT).o: $(PROJECT).c
|
||||
"$(BINPATH)avr-gcc" $(CFLAGS) -I$(INCLUDES) $< -o $@
|
||||
|
||||
$(PROJECT).elf: $(PROJECT).o
|
||||
"$(BINPATH)avr-gcc" $(LDFLAGS) -o $@ $< -lm
|
||||
|
||||
$(PROJECT).hex: $(PROJECT).elf
|
||||
"$(BINPATH)avr-objcopy" -O ihex -R .eeprom $< $@
|
||||
|
||||
out: $(PROJECT).hex
|
||||
"$(BINPATH)avr-size" $(PROJECT).elf
|
||||
|
||||
load: clean out isp
|
||||
|
||||
isp: $(PROJECT).hex
|
||||
"$(BINPATH)avrdude" $(ISP_ARGS) -e -u -Ulock:w:0x3f:m -qq -Uefuse:w:0x$(ISP_EFUSE):m -Uhfuse:w:0x$(ISP_HFUSE):m -Ulfuse:w:0x$(ISP_LFUSE):m -Ulock:w:0x0f:m
|
||||
"$(BINPATH)avrdude" $(ISP_ARGS) -V -q -s -Uflash:w:$(PROJECT).hex
|
||||
"$(BINPATH)avrdude" $(ISP_ARGS)
|
||||
@@ -0,0 +1,207 @@
|
||||
#include "MyOtaBootloader.h"
|
||||
|
||||
int main(void) __attribute__ ((naked)) __attribute__ ((section (".init9")));
|
||||
|
||||
volatile char dummy;
|
||||
|
||||
EMPTY_INTERRUPT(WDT_vect);
|
||||
|
||||
static uint16_t calcCRCrom (const void* ptr, uint16_t len) {
|
||||
uint16_t crc = ~0;
|
||||
for (uint16_t i = 0; i < len; ++i)
|
||||
crc = _crc16_update(crc, pgm_read_byte((uint16_t) ptr + i));
|
||||
return crc;
|
||||
}
|
||||
|
||||
static uint8_t validFirmware () {
|
||||
return calcCRCrom(0, fc.blocks * FIRMWARE_BLOCK_SIZE) == fc.crc;
|
||||
}
|
||||
|
||||
static void reboot() {
|
||||
wdt_enable(WDTO_15MS);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static void startup() {
|
||||
if (validFirmware()) {
|
||||
wdt_disable();
|
||||
clock_prescale_set(orgClockDiv);
|
||||
((void(*)()) 0)();
|
||||
} else
|
||||
reboot();
|
||||
}
|
||||
|
||||
static void boot_program_page(uint32_t page, uint8_t *buf) {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
eeprom_busy_wait();
|
||||
boot_page_erase(page);
|
||||
boot_spm_busy_wait();
|
||||
for (uint16_t i = 0; i < SPM_PAGESIZE; i += 2) {
|
||||
uint16_t w = *buf++;
|
||||
w += (*buf++) << 8;
|
||||
boot_page_fill(page + i, w);
|
||||
}
|
||||
boot_page_write(page);
|
||||
boot_spm_busy_wait();
|
||||
boot_rww_enable();
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
static boolean sendWrite(MyMessage message) {
|
||||
return write(nc.parentNodeId, message.array, HEADER_SIZE + mGetLength(message), (message.destination == BROADCAST_ADDRESS));
|
||||
}
|
||||
|
||||
static uint8_t sendAndWait(uint8_t reqType, uint8_t resType) {
|
||||
msg.type = reqType;
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
sendWrite(msg);
|
||||
for (uint16_t j = 0; j < 20; j++) {
|
||||
wdt_reset();
|
||||
for (uint16_t j = 0; j < 100; j++) {
|
||||
wdt_reset();
|
||||
uint8_t pipe;
|
||||
boolean avail = available(&pipe);
|
||||
if (avail && pipe<=6) {
|
||||
read(rmsg.array,pipe);
|
||||
if(!(mGetVersion(rmsg) == PROTOCOL_VERSION))
|
||||
continue;
|
||||
if (rmsg.destination == nc.nodeId) {
|
||||
if (mGetCommand(rmsg) == C_INTERNAL) {
|
||||
if (rmsg.type == I_PING_ACK) {
|
||||
if (rmsg.data[0] < nc.distance - 1) {
|
||||
nc.distance = rmsg.data[0] + 1;
|
||||
nc.parentNodeId = rmsg.sender;
|
||||
eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId);
|
||||
eeprom_write_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, nc.distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((mGetCommand(rmsg) == mGetCommand(msg)) && (rmsg.type == resType))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
delaym(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main () {
|
||||
asm volatile ("clr __zero_reg__");
|
||||
// switch to 4 MHz
|
||||
orgClockDiv = clock_prescale_get();
|
||||
clock_prescale_set(F_CPU_DIV);
|
||||
MCUSR = 0;
|
||||
// enable watchdog to avoid deadlock
|
||||
wdt_enable(WDTO_8S);
|
||||
|
||||
#ifdef LED_DEBUG
|
||||
// enable LEDs for debugging and blink once as visual "bootloader started" sign
|
||||
led_init();
|
||||
blink(LED_MBOTH, 250);
|
||||
#endif
|
||||
#ifdef UART_DEBUG
|
||||
// enable UART for debugging and send start message
|
||||
uart_init();
|
||||
uart_puts("Go\n");
|
||||
#endif
|
||||
|
||||
wdt_reset();
|
||||
// initialize RF module
|
||||
begin();
|
||||
wdt_reset();
|
||||
// Read settings from EEPROM
|
||||
eeprom_read_block((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(struct NodeConfig));
|
||||
wdt_reset();
|
||||
|
||||
msg.sender = nc.nodeId;
|
||||
msg.last = nc.nodeId;
|
||||
address(nc.nodeId);
|
||||
|
||||
msg.sensor = NODE_SENSOR_ID;
|
||||
mSetLength(msg, 0);
|
||||
mSetPayloadType(msg, P_STRING);
|
||||
mSetAck(msg,false);
|
||||
mSetVersion(msg, PROTOCOL_VERSION);
|
||||
|
||||
nc.distance = 255;
|
||||
mSetCommand(msg, C_INTERNAL);
|
||||
msg.destination = BROADCAST_ADDRESS;
|
||||
if (!sendAndWait(I_PING, I_PING_ACK))
|
||||
// starting existing firmware if no ping response (if firmware is valid)
|
||||
// reboot();
|
||||
startup();
|
||||
|
||||
msg.destination = GATEWAY_ADDRESS;
|
||||
|
||||
if (nc.nodeId == AUTO) {
|
||||
openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(nc.nodeId));
|
||||
if (!sendAndWait(I_ID_REQUEST, I_ID_RESPONSE))
|
||||
reboot();
|
||||
if (mGetPayloadType(rmsg) == P_BYTE)
|
||||
nc.nodeId = rmsg.data[0];
|
||||
else if (mGetPayloadType(rmsg) == P_STRING)
|
||||
nc.nodeId = atoi(rmsg.data);
|
||||
if (nc.nodeId == AUTO)
|
||||
reboot();
|
||||
eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, nc.nodeId);
|
||||
msg.sender = nc.nodeId;
|
||||
msg.last = nc.nodeId;
|
||||
address(nc.nodeId);
|
||||
}
|
||||
|
||||
// Read settings from EEPROM
|
||||
eeprom_read_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(struct FirmwareConfig));
|
||||
|
||||
mSetPayloadType(msg,P_CUSTOM);
|
||||
|
||||
FirmwareConfigRequest *firmwareConfigRequest = (FirmwareConfigRequest *)msg.data;
|
||||
mSetLength(msg, sizeof(FirmwareConfigRequest));
|
||||
mSetCommand(msg, C_STREAM);
|
||||
firmwareConfigRequest->type = fc.type;
|
||||
firmwareConfigRequest->version = fc.version;
|
||||
if (!sendAndWait(ST_FIRMWARE_CONFIG_REQUEST, ST_FIRMWARE_CONFIG_RESPONSE))
|
||||
// starting existing firmware if no firmware config response (if firmware is valid)
|
||||
// reboot();
|
||||
startup();
|
||||
FirmwareConfigResponse *firmwareConfigResponse = (FirmwareConfigResponse *)rmsg.data;
|
||||
if (firmwareConfigResponse->version == fc.version)
|
||||
if (firmwareConfigResponse->blocks == fc.blocks)
|
||||
if (firmwareConfigResponse->crc == fc.crc)
|
||||
if (validFirmware())
|
||||
startup();
|
||||
fc.type = firmwareConfigResponse->type;
|
||||
fc.version = firmwareConfigResponse->version;
|
||||
fc.blocks = firmwareConfigResponse->blocks;
|
||||
fc.crc = firmwareConfigResponse->crc;
|
||||
|
||||
FirmwareRequest *firmwareRequest = (FirmwareRequest *)msg.data;
|
||||
mSetLength(msg, sizeof(FirmwareRequest));
|
||||
firmwareRequest->type = fc.type;
|
||||
firmwareRequest->version = fc.version;
|
||||
for (uint16_t block = 0; block < fc.blocks; block++) {
|
||||
firmwareRequest->block = block;
|
||||
if (!sendAndWait(ST_FIRMWARE_REQUEST, ST_FIRMWARE_RESPONSE))
|
||||
reboot();
|
||||
FirmwareResponse *firmwareResponse = (FirmwareResponse *)rmsg.data;
|
||||
uint8_t offset = (block * FIRMWARE_BLOCK_SIZE) % SPM_PAGESIZE;
|
||||
memcpy(progBuf + offset, firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
|
||||
if (offset == SPM_PAGESIZE - FIRMWARE_BLOCK_SIZE)
|
||||
boot_program_page((block * FIRMWARE_BLOCK_SIZE) - offset, progBuf);
|
||||
}
|
||||
|
||||
wdt_reset();
|
||||
|
||||
if (validFirmware()) {
|
||||
eeprom_write_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(struct FirmwareConfig));
|
||||
#ifdef UART_DEBUG
|
||||
uart_puts("fw ok\n");
|
||||
} else {
|
||||
uart_puts("fw nok\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
reboot();
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef MyOtaBootloader_H
|
||||
#define MyOtaBootloader_H
|
||||
|
||||
#include <avr/boot.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <util/crc16.h>
|
||||
|
||||
#include "MyMessage.h"
|
||||
#include "MySensor.h"
|
||||
#include "MyOtaBootloaderRF24.h"
|
||||
|
||||
#define FIRMWARE_BLOCK_SIZE 16
|
||||
|
||||
struct FirmwareConfig
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t blocks;
|
||||
uint16_t crc;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
} FirmwareConfigRequest;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t blocks;
|
||||
uint16_t crc;
|
||||
} FirmwareConfigResponse;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t block;
|
||||
} FirmwareRequest;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t block;
|
||||
uint8_t data[FIRMWARE_BLOCK_SIZE];
|
||||
} FirmwareResponse;
|
||||
|
||||
static struct NodeConfig nc;
|
||||
static struct FirmwareConfig fc;
|
||||
static MyMessage msg;
|
||||
static MyMessage rmsg;
|
||||
|
||||
static clock_div_t orgClockDiv = 0;
|
||||
|
||||
static uint8_t progBuf[SPM_PAGESIZE];
|
||||
|
||||
#endif // MyOtaBootloader_H
|
||||
@@ -0,0 +1,154 @@
|
||||
#ifndef MyOtaBootloaderHW_H
|
||||
#define MyOtaBootloaderHW_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <avr/power.h>
|
||||
|
||||
//#define LED_DEBUG
|
||||
//#define UART_DEBUG
|
||||
|
||||
// hardware
|
||||
// ********
|
||||
|
||||
#define F_CPU_DIV clock_div_4
|
||||
#define F_CPU_REAL F_CPU / (1 << F_CPU_DIV)
|
||||
#define UART_BAUD 9600UL
|
||||
#define DELAY_M 125 * (1 << F_CPU_DIV)
|
||||
|
||||
// boolean definition
|
||||
// ******************
|
||||
|
||||
typedef uint8_t bool;
|
||||
typedef uint8_t boolean;
|
||||
#define false 0x0
|
||||
#define true 0x1
|
||||
#define LOW 0x0
|
||||
#define HIGH 0x1
|
||||
|
||||
// delay
|
||||
// *****
|
||||
|
||||
static void delayu() {
|
||||
asm("nop");
|
||||
}
|
||||
|
||||
static void delaym(uint16_t t) {
|
||||
uint16_t d, a;
|
||||
for (d = 0; d < t; d++)
|
||||
for (a = 0; a < DELAY_M; a++)
|
||||
asm("nop");
|
||||
}
|
||||
|
||||
// LED debug
|
||||
// *********
|
||||
|
||||
#ifdef LED_DEBUG
|
||||
#define LED_DDR DDRD
|
||||
#define LED_PORT PORTD
|
||||
#define LED_RED 6 // Arduino Pin 6 <-> Bit 6 of port D
|
||||
#define LED_GREEN 7 // Arduino Pin 7 <-> Bit 7 of port D
|
||||
#define LED_MRED (1 << LED_RED)
|
||||
#define LED_MGREEN (1 << LED_GREEN)
|
||||
#define LED_MBOTH (LED_MRED | LED_MGREEN)
|
||||
|
||||
static void led_init() {
|
||||
LED_DDR |= LED_MBOTH;
|
||||
LED_PORT &= ~LED_MBOTH;
|
||||
}
|
||||
|
||||
static void blink(uint8_t mask, uint16_t time) {
|
||||
LED_PORT |= mask;
|
||||
if (time > 0)
|
||||
{
|
||||
delaym(time);
|
||||
LED_PORT &= ~mask;
|
||||
delaym(time);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// UART debug
|
||||
// **********
|
||||
|
||||
#ifdef UART_DEBUG
|
||||
static void uart_init()
|
||||
{
|
||||
UCSR0A = _BV(U2X0); //Double speed mode USART0
|
||||
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
|
||||
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
|
||||
UBRR0L = (uint8_t)( (F_CPU_REAL + UART_BAUD * 4L) / (UART_BAUD * 8L) - 1 );
|
||||
}
|
||||
|
||||
static void uart_putc(char ch) {
|
||||
while (!(UCSR0A & _BV(UDRE0)));
|
||||
UDR0 = ch;
|
||||
}
|
||||
|
||||
static void uart_puts(char *s)
|
||||
{
|
||||
while (*s)
|
||||
uart_putc(*s++);
|
||||
}
|
||||
|
||||
static void uart_puti(uint8_t i)
|
||||
{
|
||||
char s[5];
|
||||
itoa( i, s, 10 );
|
||||
uart_puts( s );
|
||||
}
|
||||
#endif
|
||||
|
||||
// SPI communication
|
||||
// *****************
|
||||
|
||||
#define SPI_DDR DDRB
|
||||
#define SPI_PORT PORTB
|
||||
#define SPI_PIN PINB
|
||||
#define SPI_SCLK 5 // Arduino Pin 13 <-> Bit 5 of port B
|
||||
#define SPI_MISO 4 // Arduino Pin 12 <-> Bit 4 of port B
|
||||
#define SPI_MOSI 3 // Arduino Pin 11 <-> Bit 3 of port B
|
||||
#define SPI_CSN 2 // Arduino Pin 10 <-> Bit 2 of port B
|
||||
#define SPI_CE 1 // Arduino Pin 9 <-> Bit 1 of port B
|
||||
|
||||
#define csnlow() SPI_PORT &= ~(1<<SPI_CSN);delaym(1)
|
||||
#define csnhigh() SPI_PORT |= (1<<SPI_CSN);delaym(1)
|
||||
#define celow() SPI_PORT &= ~(1<<SPI_CE);delaym(1)
|
||||
#define cehigh() SPI_PORT |= (1<<SPI_CE);delaym(1)
|
||||
|
||||
static void SPIinit()
|
||||
{
|
||||
SPI_DDR |= (1 << SPI_MOSI) + (1 << SPI_SCLK) + (1 << SPI_CE) + (1 << SPI_CSN);
|
||||
SPI_DDR &= ~(1 << SPI_MISO);
|
||||
SPI_PORT &= ~((1 << SPI_MOSI) + (1 << SPI_SCLK) + (1 << SPI_CE));
|
||||
SPI_PORT |= (1 << SPI_CSN);
|
||||
}
|
||||
|
||||
static uint8_t SPItransfer(uint8_t value)
|
||||
{
|
||||
uint8_t i;
|
||||
for(i = 0 ;i < 8;i++) {
|
||||
delayu();
|
||||
if ((value & 0x80) == 0x00)
|
||||
SPI_PORT &= ~(1 << SPI_MOSI);
|
||||
else
|
||||
SPI_PORT |= (1 << SPI_MOSI);
|
||||
value = (value << 1); // shift next bit into MSB..
|
||||
delayu();
|
||||
SPI_PORT |= (1 << SPI_SCLK);
|
||||
value |= ((SPI_PIN >> SPI_MISO) & 0x01); // capture current MISO bit
|
||||
delayu();
|
||||
SPI_PORT &= ~(1 << SPI_SCLK);
|
||||
delayu();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint8_t spiTrans(uint8_t cmd){
|
||||
uint8_t status;
|
||||
csnlow();
|
||||
status = SPItransfer( cmd );
|
||||
csnhigh();
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif // MyOtaBootloaderHW_H
|
||||
@@ -0,0 +1,253 @@
|
||||
#ifndef MyOtaBootloaderRF24_H
|
||||
#define MyOtaBootloaderRF24_H
|
||||
|
||||
#include "MyOtaBootloaderHW.h"
|
||||
#include "../libraries/MySensors/utility/nRF24L01.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// hardware-agnostic interface to transceiver
|
||||
// ******************************************
|
||||
// static void begin()
|
||||
// static void address(uint8_t addr)
|
||||
// static boolean write(uint8_t next, uint8_t* packet, uint8_t length, boolean multicast)
|
||||
// static bool available(uint8_t* pipe_num)
|
||||
// static void read(uint8_t* buf, uint8_t pipe)
|
||||
|
||||
typedef enum { RF24_PA_MIN = 0,RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX, RF24_PA_ERROR } rf24_pa_dbm_e ;
|
||||
typedef enum { RF24_1MBPS = 0, RF24_2MBPS, RF24_250KBPS } rf24_datarate_e;
|
||||
|
||||
uint64_t pipe0_reading_address; /**< Last address set on pipe 0 for reading. */
|
||||
|
||||
static uint8_t read_register(uint8_t reg)
|
||||
{
|
||||
csnlow();
|
||||
SPItransfer( R_REGISTER | ( REGISTER_MASK & reg ) );
|
||||
uint8_t result = SPItransfer(0xff);
|
||||
csnhigh();
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t write_registers(uint8_t reg, const uint8_t* buf, uint8_t len)
|
||||
{
|
||||
uint8_t status;
|
||||
csnlow();
|
||||
status = SPItransfer( W_REGISTER | ( REGISTER_MASK & reg ) );
|
||||
while ( len-- )
|
||||
SPItransfer(*buf++);
|
||||
csnhigh();
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint8_t write_register(uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t status;
|
||||
csnlow();
|
||||
status = SPItransfer( W_REGISTER | ( REGISTER_MASK & reg ) );
|
||||
SPItransfer(value);
|
||||
csnhigh();
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint8_t read_payload(uint8_t* buf, uint8_t data_len)
|
||||
{
|
||||
#ifdef UART_DEBUG
|
||||
uart_puts("-> ");
|
||||
#endif
|
||||
uint8_t status;
|
||||
uint8_t* current = buf;
|
||||
csnlow();
|
||||
status = SPItransfer( R_RX_PAYLOAD );
|
||||
while ( data_len-- ) {
|
||||
*current = SPItransfer(0xFF);
|
||||
#ifdef UART_DEBUG
|
||||
uart_puti(*current);
|
||||
uart_putc(',');
|
||||
#endif
|
||||
current++;
|
||||
}
|
||||
csnhigh();
|
||||
#ifdef UART_DEBUG
|
||||
uart_putc('\n');
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
#define get_status() spiTrans(NOP)
|
||||
|
||||
static void powerUp(void)
|
||||
{
|
||||
if (!(read_register(CONFIG) & _BV(PWR_UP))){
|
||||
write_register(CONFIG,read_register(CONFIG) | _BV(PWR_UP));
|
||||
delaym(5);
|
||||
}
|
||||
}
|
||||
|
||||
#define convert_64_bit_to_byte_array(value, data) ((*(uint64_t *)(data)) = (uint64_t)(value))
|
||||
|
||||
static void startListening(void)
|
||||
{
|
||||
powerUp();
|
||||
write_register(CONFIG, read_register(CONFIG) | _BV(PRIM_RX));
|
||||
write_register(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||
if (pipe0_reading_address){
|
||||
uint8_t addressa[8];
|
||||
convert_64_bit_to_byte_array(pipe0_reading_address, addressa);
|
||||
write_registers(RX_ADDR_P0, addressa, 5);
|
||||
}
|
||||
spiTrans(FLUSH_RX);
|
||||
spiTrans(FLUSH_TX);
|
||||
cehigh();
|
||||
}
|
||||
|
||||
static void stopListening(void)
|
||||
{
|
||||
celow();
|
||||
spiTrans(FLUSH_TX);
|
||||
spiTrans(FLUSH_RX);
|
||||
write_register(CONFIG, read_register(CONFIG) & ~_BV(PRIM_RX));
|
||||
}
|
||||
|
||||
static void write_payload(const uint8_t* buf, uint8_t data_len, const uint8_t writeType)
|
||||
{
|
||||
#ifdef UART_DEBUG
|
||||
uart_puts("<- ");
|
||||
#endif
|
||||
const uint8_t* current = buf;
|
||||
csnlow();
|
||||
SPItransfer(writeType);
|
||||
while ( data_len-- ) {
|
||||
#ifdef UART_DEBUG
|
||||
uart_puti(*current);
|
||||
uart_putc(',');
|
||||
#endif
|
||||
SPItransfer(*current++);
|
||||
}
|
||||
csnhigh();
|
||||
#ifdef UART_DEBUG
|
||||
uart_putc('\n');
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool writem( const uint8_t* buf, uint8_t len, const bool multicast )
|
||||
{
|
||||
write_payload( buf, len, multicast ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD) ;
|
||||
cehigh();
|
||||
celow();
|
||||
while( ! ( get_status() & ( _BV(TX_DS) | _BV(MAX_RT) ))) { }
|
||||
uint8_t status = write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||
if( status & _BV(MAX_RT)){
|
||||
spiTrans(FLUSH_TX);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t getDynamicPayloadSize(void)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
csnlow();
|
||||
SPItransfer( R_RX_PL_WID );
|
||||
result = SPItransfer(0xff);
|
||||
csnhigh();
|
||||
if(result > 32) {
|
||||
spiTrans(FLUSH_RX);
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool available(uint8_t* pipe_num)
|
||||
{
|
||||
if (!(read_register(FIFO_STATUS) & _BV(RX_EMPTY) )){
|
||||
if (pipe_num) {
|
||||
uint8_t status = get_status();
|
||||
*pipe_num = ( status >> RX_P_NO ) & 0b111;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void writeAckPayload(uint8_t pipe, const uint8_t* buf, uint8_t len)
|
||||
{
|
||||
const uint8_t* current = buf;
|
||||
uint8_t data_len = len;
|
||||
csnlow();
|
||||
SPItransfer(W_ACK_PAYLOAD | ( pipe & 0b111 ) );
|
||||
while ( data_len-- )
|
||||
SPItransfer(*current++);
|
||||
csnhigh();
|
||||
}
|
||||
|
||||
static void read( uint8_t* buf, uint8_t pipe ){
|
||||
read_payload(buf, getDynamicPayloadSize());
|
||||
write_register(STATUS,_BV(RX_DR) | _BV(MAX_RT) | _BV(TX_DS));
|
||||
writeAckPayload(pipe,&pipe, 1 );
|
||||
}
|
||||
|
||||
static void openWritingPipe(uint64_t value)
|
||||
{
|
||||
uint8_t valuea[8];
|
||||
convert_64_bit_to_byte_array(value, valuea);
|
||||
write_registers(RX_ADDR_P0, valuea, 5);
|
||||
write_registers(TX_ADDR, valuea, 5);
|
||||
}
|
||||
|
||||
static void openReadingPipe(uint8_t child, uint64_t address)
|
||||
{
|
||||
if (child == 0)
|
||||
pipe0_reading_address = address;
|
||||
uint8_t addressa[8];
|
||||
convert_64_bit_to_byte_array(address, addressa);
|
||||
if ( child < 2 )
|
||||
write_registers(RX_ADDR_P0 + child, addressa, 5);
|
||||
write_register(EN_RXADDR,read_register(EN_RXADDR) | _BV(ERX_P0 + child));
|
||||
}
|
||||
|
||||
static boolean write(uint8_t next, uint8_t* packet, uint8_t length, boolean multicast) {
|
||||
powerUp();
|
||||
stopListening();
|
||||
openWritingPipe(TO_ADDR(next));
|
||||
bool ok = writem(packet, length, multicast);
|
||||
startListening();
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void address(uint8_t addr)
|
||||
{
|
||||
if (addr != BROADCAST_ADDRESS) {
|
||||
openReadingPipe(WRITE_PIPE, TO_ADDR(addr));
|
||||
openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(addr));
|
||||
}
|
||||
}
|
||||
|
||||
static void begin(void)
|
||||
{
|
||||
pipe0_reading_address = 0;
|
||||
|
||||
SPIinit();
|
||||
delaym( 10 ) ;
|
||||
|
||||
write_register(SETUP_RETR, 5 << ARD | 15 << ARC);
|
||||
write_register(EN_AA, 0b00111111 & ~_BV(BROADCAST_PIPE)) ;
|
||||
write_register(RF_CH, RF24_CHANNEL);
|
||||
write_register(RF_SETUP, (read_register(RF_SETUP) & 0b11010000) | ((RF24_PA_LEVEL << 1) + 1) | ((RF24_DATARATE & 0b00000010 ) << 4) | ((RF24_DATARATE & 0b00000001 ) << 3));
|
||||
write_register(CONFIG, read_register(CONFIG) | _BV(CRCO) | _BV(EN_CRC)) ;
|
||||
write_register(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT));
|
||||
|
||||
csnlow();
|
||||
SPItransfer(ACTIVATE);
|
||||
SPItransfer(0x73);
|
||||
csnhigh();
|
||||
write_register(FEATURE, read_register(FEATURE) | _BV(EN_ACK_PAY) | _BV(EN_DPL) );
|
||||
write_register(DYNPD, read_register(DYNPD) | _BV(DPL_P5) | _BV(DPL_P4) | _BV(DPL_P3) | _BV(DPL_P2) | _BV(DPL_P1) | _BV(DPL_P0));
|
||||
|
||||
spiTrans(FLUSH_RX);
|
||||
spiTrans(FLUSH_TX);
|
||||
|
||||
powerUp(); //Power up by default when begin() is called
|
||||
write_register(CONFIG, read_register(CONFIG) & ~_BV(PRIM_RX));
|
||||
openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS));
|
||||
}
|
||||
#endif // MyOtaBootloaderRF24_H
|
||||
@@ -12,9 +12,11 @@
|
||||
#ifndef MyMessage_h
|
||||
#define MyMessage_h
|
||||
|
||||
#include <SPI.h>
|
||||
#ifdef __cplusplus
|
||||
#include <Arduino.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#define PROTOCOL_VERSION 2
|
||||
#define MAX_MESSAGE_LENGTH 32
|
||||
@@ -56,7 +58,8 @@ typedef enum {
|
||||
|
||||
// Type of data stream (for streamed message)
|
||||
typedef enum {
|
||||
ST_FIRMWARE, ST_SOUND, ST_IMAGE
|
||||
ST_FIRMWARE_CONFIG_REQUEST, ST_FIRMWARE_CONFIG_RESPONSE, ST_FIRMWARE_REQUEST, ST_FIRMWARE_RESPONSE,
|
||||
ST_SOUND, ST_IMAGE
|
||||
} stream;
|
||||
|
||||
typedef enum {
|
||||
@@ -101,7 +104,7 @@ typedef enum {
|
||||
#define miSetLength(_length) BF_SET(version_length, _length, 3, 5)
|
||||
#define miSetPayloadType(_pt) BF_SET(command_ack_payload, _pt, 4, 4)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
class MyMessage
|
||||
{
|
||||
public:
|
||||
@@ -144,6 +147,13 @@ public:
|
||||
MyMessage& set(unsigned int value);
|
||||
MyMessage& set(int value);
|
||||
|
||||
#else
|
||||
|
||||
typedef union {
|
||||
struct
|
||||
{
|
||||
|
||||
#endif
|
||||
|
||||
uint8_t version_length; // 3 bit - Protocol version
|
||||
// 5 bit - Length of payload
|
||||
@@ -167,6 +177,12 @@ public:
|
||||
int iValue;
|
||||
char data[MAX_PAYLOAD + 1];
|
||||
} __attribute__((packed));
|
||||
#ifdef __cplusplus
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
};
|
||||
uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1];
|
||||
} __attribute__((packed)) MyMessage;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,16 +15,19 @@
|
||||
#include "Version.h" // Auto generated by bot
|
||||
#include "MyConfig.h"
|
||||
#include "MyMessage.h"
|
||||
#include <Arduino.h>
|
||||
#include <stddef.h>
|
||||
#include <SPI.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "utility/LowPower.h"
|
||||
#include "utility/RF24.h"
|
||||
#include "utility/RF24_config.h"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(x,...) debugPrint(x, ##__VA_ARGS__)
|
||||
@@ -47,7 +50,11 @@
|
||||
#define EEPROM_DISTANCE_ADDRESS (EEPROM_PARENT_NODE_ID_ADDRESS+1)
|
||||
#define EEPROM_ROUTES_ADDRESS (EEPROM_DISTANCE_ADDRESS+1) // Where to start storing routing information in EEPROM. Will allocate 256 bytes.
|
||||
#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS+256) // Location of controller sent configuration (we allow one payload of config data from controller)
|
||||
#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS+24) // First free address for sketch static configuration
|
||||
#define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS+24)
|
||||
#define EEPROM_FIRMWARE_VERSION_ADDRESS (EEPROM_FIRMWARE_TYPE_ADDRESS+2)
|
||||
#define EEPROM_FIRMWARE_BLOCKS_ADDRESS (EEPROM_FIRMWARE_VERSION_ADDRESS+2)
|
||||
#define EEPROM_FIRMWARE_CRC_ADDRESS (EEPROM_FIRMWARE_BLOCKS_ADDRESS+2)
|
||||
#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) // First free address for sketch static configuration
|
||||
|
||||
// This is the nodeId for sensor net gateway receiver sketch (where all sensors should send their data).
|
||||
// This is also act as base value for sensor nodeId
|
||||
@@ -74,8 +81,7 @@ struct ControllerConfig {
|
||||
uint8_t isMetric;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
class MySensor : public RF24
|
||||
{
|
||||
public:
|
||||
@@ -267,5 +273,6 @@ class MySensor : public RF24
|
||||
void removeChildRoute(uint8_t childId);
|
||||
void internalSleep(int ms);
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user