commit fa4728b922ebc14890eb3d8ba1c40ec33e776b87 Author: olafn Date: Mon Feb 23 18:35:45 2026 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6d27342 --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# PlatformIO +.pio/ +.pioenvs/ +.piolibdeps/ +.clang_complete +.c_cpp_properties.json +compile_commands.json + +# VS Code +.vscode/ +!.vscode/extensions.json +!.vscode/settings.json + +# Build artifacts +build/ +dist/ +*.o +*.a +*.so +*.elf +*.hex +*.bin + +# IDE and editors +*.swp +*.swo +*~ +.DS_Store +.project +.pydevproject +.settings/ +*.sublime-workspace + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.egg-info/ +*.egg +.Python +venv/ +env/ + +# Dependencies +lib/ +node_modules/ + +# OS files +.DS_Store +Thumbs.db diff --git a/AP300_TOOL/AP300_TOOL.ino b/AP300_TOOL/AP300_TOOL.ino new file mode 100644 index 0000000..7fe0f64 --- /dev/null +++ b/AP300_TOOL/AP300_TOOL.ino @@ -0,0 +1,239 @@ +/* + * BruteForce, Remote sniffing and Status-Tool for Pluggit AP300 + * + * If you have an "normal" nRF905 module, the distance between the nRF905 and the AP300 wireless module must be less than 1m!!! + */ + +/* + * PIN config for Arduino Pro Mini to nRF905 + * + * 7 -> PWR + * 8 -> CE + * 9 -> TxEN + * 2 -> CD + * 3 -> DR + * 10 -> CSN + * 12 -> MISO + * 11 -> MOSI + * 13 -> SCK + */ + +#include +#include + +/* + * ONLY USE BRUTEFORCE OR REMOTE_SNIFFING + */ +#define BRUTEFORCE 1 // enable(1)/disable(0) bruteforce +#if BRUTEFORCE + #define TIMEOUT 250 // 250ms data timeout +#else + #define TIMEOUT 1000 // 1 secon data timeout +#endif + +#define REMOTE_SNIFFING 0 // enable(1)/disable(0) remote sniffing + +uint8_t payload[4][NRF905_MAX_PAYLOAD]; +uint8_t plCounter; + +////////////////////////////////////////////////////////////////////////// +void nRF905_Config(byte buf1[], byte buf2[]) +{ + // Set control register 0 - CHANNEL + nRF905_setConfigReg0(0x76); + // config reg 1 + nRF905_setConfigReg1(0x0E); + // config reg 2 + nRF905_setConfigReg2(0x44); + // Set payload sizes + nRF905_setPayloadSizes(0x20); + // set TX and Rx addresses + nRF905_setTXAddress(buf1); + // set Rx addres + nRF905_setRXAddress(buf2); + // read config register 9 - just to be conform with data detected by sniffing + nRF905_getConfigReg(9); + // set config register 9 + nRF905_setConfigReg9(0xDB); + // Clear DR by reading receive payload + nRF905_flushRecBuffer(); +} +////////////////////////////////////////////////////////////////////////// +void nRF905_Initialise(byte buf1[], byte buf2[]) +{ + pinMode(PWR_MODE, OUTPUT); + digitalWrite(PWR_MODE, LOW); // activate power down mode + pinMode(TRX_EN, OUTPUT); + digitalWrite(TRX_EN, LOW); // activate standby mode + pinMode(TX_EN, OUTPUT); + pinMode(CSN, OUTPUT); + pinMode(CD, INPUT); + pinMode(DR, INPUT); + digitalWrite(CSN, HIGH); + + SPI.begin(); + SPI.setClockDivider(SPI_CLOCK_DIV2); + + nRF905_Config(buf1, buf2); + Serial.println(F("nRF905 configured...")); + + #if NRF905_INTERRUPTS + // Set interrupts + REG_EXTERNAL_INT_CTL |= BIT_EXTERNAL_INT_CTL; + nRF905_interrupt_on(); + Serial.println(F("nRF905 interrupts...")); + #endif + + // leave config mode + nRF905_powerUp(); + Serial.println(F("nRF905 powered up...")); +} +/////////////////////////////////////////////////////////////////// +void setup() +{ + byte buf1[] = {0x00, 0x00, 0x07, 0x7A}; // Address of device to send to (4 bytes) = TXADDR + byte buf2[] = {0x00, 0x00, 0x07, 0x7A}; // Address of this device (4 bytes) = RXADDR + + Serial.begin(57600); + Serial.println(F("Client started")); + + // Start up + nRF905_Initialise(buf1, buf2); + Serial.println(F("nRF905 initialised")); + + plCounter = 0; +} +////////////////////////////////////////////////////// +nRF905_radio_state_t nRF905_getStatus(void) +{ + if (!digitalRead(PWR_MODE)) return NRF905_RADIO_STATE_POWER_DOWN; + else if (!digitalRead(TRX_EN)) return NRF905_RADIO_STATE_STANDBY; + else if (!digitalRead(TX_EN)) { + if (!digitalRead(DR)) return NRF905_RADIO_STATE_RX; + else return NRF905_RADIO_STATE_RX_END; + } else { + if (!digitalRead(DR)) return NRF905_RADIO_STATE_TX; + else return NRF905_RADIO_STATE_TX_END; + } +} +///////////////////////////////////////////////////////////// +// brute force counter +byte bf[] = {0x00, 0x00}; +///////////////////////////////////////////////////////////// +void loop() +{ + byte ret; + + // HEX-Code for getting the address in brute force mode + char wr_for_bruteforce[] = {0x90, 0x80, 0x03, 0x04, 0x00, 0x00, 0x0C}; + + // HEX-Code from Remote Control to get status from AP300 (This code are sniffed from the remote control after having the valid address and set this programm in received mode and not sending data!!!!!) + char wr_get_status[] = {0x90, 0x80, 0x03, 0x04, 0x00, 0x00, 0x0C, 0xF3, 0xDB, 0xDA, 0xD3, 0xB7, 0x3E, 0x67, 0x7E, 0x0F, 0xEC, 0x3F, 0x30, 0xC0, 0xDF, 0xB5, 0xFF, 0x4D, 0xCC, 0x7C, 0xF5, 0x8F, 0xD5, 0xD0, 0x2F, 0x7B}; + + //// BRUTE FORCE + #if !REMOTE_SNIFFING + #if BRUTEFORCE + nRF905_powerDown(); + + byte buf1[] = {0x00, 0x00, bf[0], bf[1]}; // Address of device to send to (4 bytes) = TXADDR + byte buf2[] = {0x00, 0x00, bf[0], bf[1]}; // Address of this device (4 bytes) = RXADDR + byte view[] = {0x00, 0x00, bf[0], bf[1]}; // Address of this device (4 bytes) = VIEW + + Serial.print(F("TESTING ADDRESS: 0x")); + Serial.print(view[2], HEX); + Serial.print(F(", 0x")); + Serial.println(view[3], HEX); + + // very simple counter + if(bf[1] == 255) { + bf[0]++; + bf[1] = 0; + } else { + bf[1]++; + } + + nRF905_Initialise(buf1, buf2); //slow but good ;-) + #endif + #endif + + // set start time for timeout + unsigned long startTime = millis(); + + //// SET DATA + #if !REMOTE_SNIFFING + Serial.println(F("setting data ...")); + // Set payload data + #if BRUTEFORCE + ret = nRF905_setData(wr_for_bruteforce, sizeof(wr_for_bruteforce)); + #else + ret = nRF905_setData(wr_get_status, sizeof(wr_get_status)); + #endif + if (ret) Serial.println(F("Error by setting data!")); + + //// SEND DATA + Serial.println(F("sending data ...")); + // Send payload (send fails if other transmissions are going on, keep trying until success) + while(1) { + ret = nRF905_send(); + if (ret==0) break; + else { + Serial.print(F("nRF905_send returned: ")); + Serial.println(ret); + delay(100); + } + } + #endif + + + //// RECEIVE DATA + Serial.println(F("receiving data ...")); + // Put into receive mode + nRF905_receive(); + + + //// GETTING DATA + #define buffer payload // Make buffer for reply + unsigned long time0 = millis() + TIMEOUT; // Wait for reply with timeout + while(1) + { + ret = nRF905_getData(&buffer[plCounter][0], NRF905_MAX_PAYLOAD); + if (ret==0) {plCounter++; break;} // Got data + + // check timeout + if ( millis() > time0 ) break; + } + + + //// EVALUATE DATA + if ( ret==0 ) + { // data received. Do nothing, wait for time-out for display received data + #if BRUTEFORCE + Serial.print(F("Reply from Pluggit AP300. The brute force was successful. The matching Address is: {0x00, 0x00, 0x")); + Serial.print(view[2], HEX); + Serial.print(F(", 0x")); + Serial.print(view[3], HEX); + Serial.println(F("}")); + while (1); + #else + Serial.print(F("Reply from Pluggit AP300: ")); + for (uint8_t y = 0; y=1.5.0) diff --git a/nRF905_Pluggit_AP300/nRF905.cpp b/nRF905_Pluggit_AP300/nRF905.cpp new file mode 100644 index 0000000..44b408d --- /dev/null +++ b/nRF905_Pluggit_AP300/nRF905.cpp @@ -0,0 +1,640 @@ +/* + * Project: nRF905 AVR/Arduino Library/Driver + * Author: Zak Kemble, contact@zakkemble.co.uk + * Copyright: (C) 2013 by Zak Kemble + * License: GNU GPL v3 (see License.txt) + * Web: http://blog.zakkemble.co.uk/nrf905-avrarduino-librarydriver/ + */ + +#include + +// AVR-specific headers (only for AVR targets) +#if defined(__AVR__) +#include +#include +#include +#endif + +#ifdef ARDUINO +#include +#include +#else +#include "nRF905_spi.h" +#endif +#include "nRF905.h" +#include "nRF905_config.h" +#include "nRF905_defs.h" +#include "nRF905_types.h" + +#define noinline __attribute__ ((__noinline__)) + +#define AM_IS_USED_SW (NRF905_AM_SW) +#define NEED_SW_STATUS_SUPPORT (AM_IS_USED_SW || NRF905_DR_SW) + +//#define DISABLE_STANDBY_MODE() (nRF905_leaveStandBy()) +//#define ENABLE_STANDBY_MODE() (nRF905_enterStandBy()) + +static inline bool cselect(void) +{ + nRF905_interrupt_off(); +// spi_enable(); + SPI_SELECT(); + return true; +} + +static inline bool cdeselect(void) +{ + SPI_DESELECT(); +// spi_disable(); + nRF905_interrupt_on(); + return false; +} + +// Need to be in standby mode to write registers? +#define STANDBY (ENABLE_STANDBY_MODE()) + +#define CHIPSELECT(standby) standby; \ + for(bool cs = cselect(); cs; cs = cdeselect()) + +static inline bool interrupt_off(void) +{ + nRF905_interrupt_off(); + return true; +} + +static inline bool interrupt_on(void) +{ + nRF905_interrupt_on(); + return false; +} + +#define NRF905_ATOMIC() for(bool cs = interrupt_off(); cs; cs = interrupt_on()) + +typedef struct +{ + uint8_t reg1; // Change to array + uint8_t reg2; + uint8_t payloadSize; +} config_s; + +typedef struct{ + nRF905_radio_state_t state; + bool goToRxMode; +} state_s; + +typedef struct{ + uint8_t buffer[NRF905_MAX_PAYLOAD]; + bool ready; +} data_s; + +static void setConfigRegister(uint8_t, uint8_t); +static noinline void defaultConfig(void); +static void setAddress(uint8_t * addr, uint8_t cmd); +#if !NRF905_INTERRUPTS +static bool dataReady(void); +#endif +static inline void stateTx(void); +#if NEED_SW_STATUS_SUPPORT +static uint8_t readStatus(void); +#endif + +// We could instead read the registers over SPI, but that would be a bit slower +static config_s config; + +#if NRF905_INTERRUPTS +#define DATA_BUFFERS 4 // must be power of 2 !!! +static data_s rxData[DATA_BUFFERS]; +static volatile state_s radio; +static volatile uint8_t rxRecPtr; +static volatile uint8_t rxReadPtr; +#else +static state_s radio; +#endif + +static void spi_transfer_nr(uint8_t cmd, uint8_t * address, uint8_t len) +{ + SPI_SELECT(); + spi_transfer(cmd); + for(uint8_t i = 0; i>8) & 0x01); + + SPI_SELECT(); + spi_transfer(NRF905_CMD_W_CONFIG | NRF905_REG_CHANNEL); + spi_transfer(channel); + spi_transfer(config.reg1); + SPI_DESELECT(); +} +#endif + +#if 0 +// Set auto retransmit +void nRF905_setAutoRetransmit(nRF905_auto_retran_t val) +{ + setConfigReg1(val, NRF905_MASK_AUTO_RETRAN, NRF905_REG_AUTO_RETRAN); +} +// Set low power receive +void nRF905_setLowRxPower(nRF905_low_rx_t val) +{ + setConfigReg1(val, NRF905_MASK_LOW_RX, NRF905_REG_LOW_RX); +} +// Set output power +void nRF905_setTransmitPower(nRF905_pwr_t val) +{ + setConfigReg1(val, NRF905_MASK_PWR, NRF905_REG_PWR); +} +// Set CRC +void nRF905_setCRC(nRF905_crc_t val) +{ + setConfigReg2(val, NRF905_MASK_CRC, NRF905_REG_CRC); +} +// Set clock output +void nRF905_setClockOut(nRF905_outclk_t val) +{ + setConfigReg2(val, NRF905_MASK_OUTCLK, NRF905_REG_OUTCLK); +} +#endif +////////////////////////////////////////////////////////////////////// +void nRF905_setConfigReg0(uint8_t val) +{ + setConfigRegister(NRF905_CMD_W_CONFIG, val); +} + +void nRF905_setConfigReg1(uint8_t val) +{ + config.reg1 = val; + setConfigRegister(NRF905_CMD_W_CONFIG | 1, val); +} + +void nRF905_setConfigReg2(uint8_t val) +{ + config.reg2 = val; + setConfigRegister(NRF905_CMD_W_CONFIG | 2, val); +} + +void nRF905_setConfigReg9(uint8_t val) +{ + setConfigRegister(NRF905_CMD_W_CONFIG | 9, val); +} + +static void setConfigRegister(uint8_t cmd, uint8_t val) +{ + SPI_SELECT(); + spi_transfer(cmd); + spi_transfer(val); + SPI_DESELECT(); +} + +uint8_t nRF905_getConfigReg(uint8_t reg) +{ + SPI_SELECT(); + spi_transfer(NRF905_CMD_R_CONFIG | reg); + uint8_t retVal = spi_transfer(0); + SPI_DESELECT(); + return retVal; +} + +void nRF905_flushRecBuffer(void) +{ + SPI_SELECT(); + spi_transfer(NRF905_CMD_R_RX_PAYLOAD); + for(uint8_t i=NRF905_MAX_PAYLOAD; i>0;i--) + spi_transfer(NRF905_CMD_NOP); + SPI_DESELECT(); +#if NRF905_INTERRUPTS + rxRecPtr = 0; + rxReadPtr = 0; +#endif +} + +#if 1 +// Set configuration +// Radio should be in standby mode and interrupts disabled +static noinline void defaultConfig() +{ + uint16_t channel = NRF905_CALC_CHANNEL(NRF905_FREQ, NRF905_BAND); + uint8_t reg1 = NRF905_AUTO_RETRAN | NRF905_LOW_RX | NRF905_PWR | NRF905_BAND | ((channel>>8) & 0x01); + uint8_t reg2 = NRF905_CRC | NRF905_CLK_FREQ | NRF905_OUTCLK; + + config.reg1 = reg1; + config.reg2 = reg2; + config.payloadSize = NRF905_PAYLOAD_SIZE; + + // Set control registers + SPI_SELECT(); + spi_transfer(NRF905_CMD_W_CONFIG); + spi_transfer(channel); + spi_transfer(reg1); + spi_transfer((NRF905_ADDR_SIZE<<4) | NRF905_ADDR_SIZE); + spi_transfer(NRF905_PAYLOAD_SIZE); // RX payload size + spi_transfer(NRF905_PAYLOAD_SIZE); // TX payload size + for(uint8_t i=4;i--;) + spi_transfer(0xE7); // Default receive address + spi_transfer(reg2); + SPI_DESELECT(); + + // Default transmit address + SPI_SELECT(); + spi_transfer(NRF905_CMD_W_TX_ADDRESS); + for(uint8_t i=4;i--;) + spi_transfer(0xE7); + SPI_DESELECT(); + + // Clear transmit payload + SPI_SELECT(); + spi_transfer(NRF905_CMD_W_TX_PAYLOAD); + for(uint8_t i=NRF905_MAX_PAYLOAD;i--;) + spi_transfer(0x00); + SPI_DESELECT(); + + // Clear DR by reading receive payload + SPI_SELECT(); + spi_transfer(NRF905_CMD_R_RX_PAYLOAD); + for(uint8_t i=NRF905_MAX_PAYLOAD;i--;) + spi_transfer(NRF905_CMD_NOP); + SPI_DESELECT(); +} +#endif + +// Payload size +void nRF905_setPayloadSizes(uint8_t size) +{ + if(size > NRF905_MAX_PAYLOAD) + size = NRF905_MAX_PAYLOAD; + config.payloadSize = size; + SPI_SELECT(); + spi_transfer(NRF905_CMD_W_CONFIG | NRF905_REG_RX_PAYLOAD_SIZE); + spi_transfer(size); + spi_transfer(size); + SPI_DESELECT(); +} + +// Power up +void nRF905_powerUp() +{ + radio.state = NRF905_RADIO_STATE_STANDBY; + ENABLE_STANDBY_MODE(); + POWER_UP(); + + // Give it time to turn on + delay(3); +} + +void nRF905_powerDown() +{ + ENABLE_STANDBY_MODE(); + POWER_DOWN(); + radio.state = NRF905_RADIO_STATE_POWER_DOWN; +} + +void nRF905_enterStandBy() +{ + ENABLE_STANDBY_MODE(); + radio.state = NRF905_RADIO_STATE_STANDBY; +} + +/* +// +void nRF905_setAddressSize(uint8_t size) +{ + CHIPSELECT(STANDBY) + { + spi_transfer_nr(NRF905_CMD_W_CONFIG | NRF905_REG_ADDR_WIDTH); + spi_transfer_nr((size<<4) | size); + } +} +*/ +// Set address +static void setAddress(uint8_t cmd, uint8_t * address) +{ + // Address bytes are sent in reverse order, which is fine as long as both ends do the same thing. + spi_transfer_nr(cmd, address, NRF905_ADDR_SIZE); +} + +// Set address of device to send to +void nRF905_setTXAddress(uint8_t * address) +{ + setAddress(NRF905_CMD_W_TX_ADDRESS, address); +} + +// Set address for this device +void nRF905_setRXAddress(uint8_t * address) +{ + setAddress(NRF905_CMD_W_CONFIG | NRF905_REG_RX_ADDRESS, address); +} + +// Set the payload data +uint8_t nRF905_setData(uint8_t * data, uint8_t len) +{ +/* // Busy transmitting something else + if(radio.state == NRF905_RADIO_STATE_TX) + return 1;//false; +*/ + nRF905_enterStandBy(); + uint8_t maxPayload = config.payloadSize; + if(len > maxPayload) + len = maxPayload; + + // Load data + spi_transfer_nr(NRF905_CMD_W_TX_PAYLOAD, data, len); + + return 0;//true; +} + +// See if device is receiving something +// Hardware: Address match pin high +// Software: Address match status bit set +bool nRF905_receiveBusy() +{ +#if (!AM_IS_USED_HW && !AM_IS_USED_SW) + return false; +#elif AM_IS_USED_SW + return (readStatus() & _BV(NRF905_STATUS_AM)); +#else + return digitalRead(AM); +#endif +} + +// See if data ready, true if received new data/finished transmitting +// Hardware: Data ready pin high +// Software: Data ready status bit set +#if !NRF905_INTERRUPTS +static bool dataReady() +{ +#if NRF905_DR_SW + return (readStatus() & _BV(NRF905_STATUS_DR)); +#else + return digitalRead(DR); +#endif +} +#endif + +/////////////////////////////////////////////////////////// +// Transmit payload +/////////////////////////////////////////////////////////// +uint8_t nRF905_send(void) +{ + // Already transmitting + if(radio.state == NRF905_RADIO_STATE_TX) + return 1;//false; +#if NRF905_COLLISION_AVOID + // Don't transmit if busy + else if(nRF905_airwayBusy()) + return 2;//false; +#endif + + // Put into transmit mode + TRANSMIT_MODE(); + + radio.state = NRF905_RADIO_STATE_TX; + + // Pulse standby pin to start transmission + DISABLE_STANDBY_MODE(); + + delay(10); + +#if NRF905_AUTO_RETRAN == NRF905_AUTO_RETRAN_DISABLE + // Radio will go back into standby mode after transmission, unless nRF905_receive() + // is called in which case it will go straight to receive mode after transmission. + // If auto-retransmission is disabled and if the radio isn't set to go into standby or receive mode then it will + // transmit a carrier signal with no data. + ENABLE_STANDBY_MODE(); +#endif + + return 0;//true; +} + +// Return radio state +nRF905_radio_state_t nRF905_getState(void) +{ + return radio.state; +} + +// Get radio status by reading pin states +nRF905_radio_state_t nRF905_getStatus(void) +{ + if (!digitalRead(PWR_MODE)) + return NRF905_RADIO_STATE_POWER_DOWN; + else if (!digitalRead(TRX_EN)) + return NRF905_RADIO_STATE_STANDBY; + else if (!digitalRead(TX_EN)) { + if (!digitalRead(DR)) + return NRF905_RADIO_STATE_RX; + else + return NRF905_RADIO_STATE_RX_END; + } else { + if (!digitalRead(DR)) + return NRF905_RADIO_STATE_TX; + else + return NRF905_RADIO_STATE_TX_END; + } +} + +// Put into receive mode +void nRF905_receive(void) +{ +// NRF905_ATOMIC() +// { + if(radio.state == NRF905_RADIO_STATE_TX) // Currently transmitting, so wait until finished then go into receive mode + while (nRF905_getStatus()==NRF905_RADIO_STATE_TX); //radio.goToRxMode = true; +// else +// { + RECEIVE_MODE(); + DISABLE_STANDBY_MODE(); + radio.state = NRF905_RADIO_STATE_RX; + delay(1); +// } +// } +} + +// Get received data if available +uint8_t nRF905_getData(uint8_t * data, uint8_t len) +{ +static uint8_t i; +static uint8_t * ptr; + if(len > config.payloadSize) + len = config.payloadSize; + +#if NRF905_INTERRUPTS +/* // No data received + if(!rxData.ready) + return 1;//false; +*/ + if (rxReadPtr==rxRecPtr) + return 1;//false; + + // retrun actual read ptr +// NRF905_ATOMIC() +// { + // Copy and clear data buffer + //memcpy(data, (uint8_t*)rxData.buffer, len); + ptr = rxData[rxReadPtr].buffer; + for (i=0; i +#include "nRF905_config.h" + +//#define nRF905_packet nrf905_packet_s; + +/** + * \enum nRF905_radio_state_t + * \brief Radio state + */ +typedef enum +{ + NRF905_RADIO_STATE_POWER_DOWN, /**< Power down mode */ + NRF905_RADIO_STATE_STANDBY, /**< standby mode*/ + NRF905_RADIO_STATE_RX, /**< Receive mode */ + NRF905_RADIO_STATE_RX_END, /**< Received data available */ + NRF905_RADIO_STATE_TX, /**< Transmitting started */ + NRF905_RADIO_STATE_TX_END, /**< Transmitting finished */ +} nRF905_radio_state_t; + +/** + * \enum nRF905_band_t + * \brief Frequency bands. + */ +typedef enum +{ +// NOTE: +// When using NRF905_BAND_868 and NRF905_BAND_915 for calculating channel (NRF905_CALC_CHANNEL(f, b)) they should be value 0x01, +// but when using them for setting registers their value should be 0x02. +// They're defined as 0x02 here so when used for calculating channel they're right shifted by 1 + + NRF905_BAND_433 = 0x00, /**< 433MHz band */ + NRF905_BAND_868 = 0x02, /**< 868MHz band */ + NRF905_BAND_915 = 0x02 /**< 915MHz band */ +} nRF905_band_t; + +/** + * \enum nRF905_pwr_t + * \brief Output power (n means negative, n10 = -10). + */ +typedef enum +{ + NRF905_PWR_n10 = 0x00, /**< -10dBm = 100uW */ + NRF905_PWR_n2 = 0x04, /**< -2dBm = 631uW */ + NRF905_PWR_6 = 0x08, /**< 6dBm = 4mW */ + NRF905_PWR_10 = 0x0C /**< 10dBm = 10mW */ +} nRF905_pwr_t; + +/** + * \enum nRF905_low_rx_t + * \brief Save a few mA by reducing receive sensitivity. + */ +typedef enum +{ + NRF905_LOW_RX_DISABLE = 0x00, /**< Disable low power receive */ + NRF905_LOW_RX_ENABLE = 0x10 /**< Enable low power receive */ +} nRF905_low_rx_t; + +/** + * \enum nRF905_auto_retran_t + * \brief Constantly retransmit payload while in transmit mode. + * + * Can be useful in areas with lots of interference, but you'll need to make sure you can differentiate between re-transmitted packets and new packets (like an ID number). + * + * Other transmissions will be blocked if collision avoidance is enabled. + */ +typedef enum +{ + NRF905_AUTO_RETRAN_DISABLE = 0x00, /**< Disable auto re-transmit */ + NRF905_AUTO_RETRAN_ENABLE = 0x20 /**< Enable auto re-transmit */ +} nRF905_auto_retran_t; + +/** + * \enum nRF905_outclk_t + * \brief Output a clock signal on pin 3 of IC. + */ +typedef enum +{ + NRF905_OUTCLK_DISABLE = 0x00, /**< Disable output clock */ + NRF905_OUTCLK_4MHZ = 0x04, /**< 4MHz clock */ + NRF905_OUTCLK_2MHZ = 0x05, /**< 2MHz clock */ + NRF905_OUTCLK_1MHZ = 0x06, /**< 1MHz clock */ + NRF905_OUTCLK_500KHZ = 0x07, /**< 500KHz clock */ +} nRF905_outclk_t; + +/** + * \enum nRF905_crc_t + * \brief CRC Checksum. + */ +typedef enum +{ + NRF905_CRC_DISABLE = 0x00, /**< Disable CRC */ + NRF905_CRC_8 = 0x40, /**< 8bit CRC */ + NRF905_CRC_16 = 0xC0, /**< 16bit CRC */ +} nRF905_crc_t; + +/** + * \enum nRF905_addr_size_t + * \brief Address size. + */ +typedef enum +{ + NRF905_ADDR_SIZE_1 = 0x01, /**< 1 byte */ + NRF905_ADDR_SIZE_4 = 0x04, /**< 4 bytes */ +} nRF905_addr_size_t; + +// Setting options +//#define NRF905_BAND_433 0x00 +//#define NRF905_BAND_868 0x02 +//#define NRF905_BAND_915 0x02 +//#define NRF905_PWR_n10 0x00 +//#define NRF905_PWR_n2 0x04 +//#define NRF905_PWR_6 0x08 +//#define NRF905_PWR_10 0x0C +//#define NRF905_LOW_RX_ENABLE 0x10 +//#define NRF905_LOW_RX_DISABLE 0x00 +//#define NRF905_AUTO_RETRAN_ENABLE 0x20 +//#define NRF905_AUTO_RETRAN_DISABLE 0x00 +//#define NRF905_OUTCLK_DISABLE 0x00 +//#define NRF905_OUTCLK_4MHZ 0x04 +//#define NRF905_OUTCLK_2MHZ 0x05 +//#define NRF905_OUTCLK_1MHZ 0x06 +//#define NRF905_OUTCLK_500KHZ 0x07 +//#define NRF905_CRC_DISABLE 0x00 +//#define NRF905_CRC_8 0x40 +//#define NRF905_CRC_16 0xC0 +//#define NRF905_ADDR_SIZE_1 0x01 +//#define NRF905_ADDR_SIZE_4 0x04 + +/** +* Maximum payload size +*/ +#define NRF905_MAX_PAYLOAD 32 + +void nRF905_setConfigReg0(uint8_t value); +void nRF905_setConfigReg1(uint8_t value); +void nRF905_setConfigReg2(uint8_t value); +void nRF905_setConfigReg9(uint8_t value); +void nRF905_flushRecBuffer(void); +uint8_t nRF905_getConfigReg(uint8_t reg); +nRF905_radio_state_t nRF905_getStatus(void); + + +/** +* Initialise, must be called before anything else! +* +* @return (none) +*/ +void nRF905_init(void); + +/** +* Set frequency, workout the channel from the frequency +* +* 433MHz band: 422.4MHz - 473.5MHz, 100KHz steps +* +* 868/915MHz band: 844.8MHz - 947MHz, 200KHz steps +* +* @param [band] Frequency band +* @param [freq] Frequency in Hz +* @return (none) +*/ +void nRF905_setFrequency(nRF905_band_t band, uint32_t freq); + +/** +* Just set the channel, this skips having to workout the channel from the frequency +* +* @param [band] Frequency band +* @param [channel] The channel (0 - 511) +* @return (none) +*/ +void nRF905_setChannel(nRF905_band_t band, uint16_t channel); + +#if 0 +/** +* Set auto retransmit +* +* @param [val] Enable/disable auto retransmit +* @return (none) +*/ +void nRF905_setAutoRetransmit(nRF905_auto_retran_t val); + +/** +* Set low power receive +* +* @param [val] Enable/disable low power receive +* @return (none) +*/ +void nRF905_setLowRxPower(nRF905_low_rx_t val); + +/** +* Set output power +* +* @param [val] Output power level +* @return (none) +*/ +void nRF905_setTransmitPower(nRF905_pwr_t val); + +/** +* Set CRC +* +* @param [val] CRC Type +* @return (none) +*/ +void nRF905_setCRC(nRF905_crc_t val); + +/** +* Set clock output +* +* @param [val] Clock out frequency +* @return (none) +*/ +void nRF905_setClockOut(nRF905_outclk_t val); +#endif + +/** +* Payload size +* +* @param [size] Payload size (1 - 32) +* @return (none) +*/ +void nRF905_setPayloadSizes(uint8_t size); + +//** +//* Address size +//* +//* @param [size] Address size +//* @return (none) +//*/ +//void nRF905_setAddressSize(nRF905_addr_size_t size); + +/** +* Destination radio address +* +* @param [address] The address (usually a byte array of 1 or 4 bytes depending on NRF905_ADDR_SIZE) +* @return (none) +*/ +void nRF905_setTXAddress(uint8_t * address); + +/** +* Address of this radio +* +* @param [address] The address (usually a byte array of 1 or 4 bytes depending on NRF905_ADDR_SIZE) +* @return (none) +*/ +void nRF905_setRXAddress(uint8_t * address); + +/** +* Set payload data +* +* @param [data] Pointer to data +* @param [len] How many bytes to copy (max NRF905_MAX_PAYLOAD) +* @return false if the radio is currently transmitting something else, true otherwise +*/ +uint8_t nRF905_setData(uint8_t * data, uint8_t len); + +/** +* Send the payload. +* +* @return false if other transmissions are going on and collision detection is enabled or if the radio is currently transmitting, true if transmission has successfully began +*/ +uint8_t nRF905_send(void); + +// +//bool nRF905_sendPacket(nrf905_packet_s*); + +/** +* Get current radio state, transmitting etc. +* +* @return Radio state +*/ +nRF905_radio_state_t nRF905_getState(void); + +/** +* Receive mode. If the radio is currently transmitting then receive mode will be entered once it has finished. +* +* @return (none) +*/ +void nRF905_receive(void); + +/** +* Get received payload if available. +* +* @param [data] Pointer to buffer to place data +* @param [len] How many bytes to copy +* @return false if no data available, otherwise true +*/ +uint8_t nRF905_getData(uint8_t * data, uint8_t len); + +/** +* Wake up into standby mode. +* Will take 3ms to complete. +* +* @return (none) +*/ +void nRF905_powerUp(void); + +/** +* Sleep. +* +* @note Must call nRF905_powerUp() before transmitting or receiving again. +* @return (none) +*/ +void nRF905_powerDown(void); + +/** +* Enter standby mode. +* +* @return (none) +*/ +void nRF905_enterStandBy(void); + +/** +* Leave standby and go into receive mode (same as just calling nRF905_receive()). +* +* @return (none) +*/ +inline void nRF905_leaveStandBy(void) +{ + nRF905_receive(); +} + +/** +* blah +* +* @return blah +*/ +bool nRF905_receiveBusy(void); + +/** +* See if airway is busy (carrier detect pin high). +* +* @return true if other transmissions detected, otherwise false +*/ +inline bool nRF905_airwayBusy(void) +{ + return digitalRead(CD); +} + +/** +* Disable data ready interrupt. +* +* If NRF905_INTERRUPTS is enabled then this function must be called before doing SPI communications with any other device. +* +* @return (none) +*/ +inline void nRF905_interrupt_off(void) +{ +#if NRF905_INTERRUPTS + REG_EXTERNAL_INT &= ~_BV(BIT_EXTERNAL_INT); +#endif +} + +/** +* Enable data ready interrupt. +* +* If NRF905_INTERRUPTS is enabled then this function must be called once you have finished doing SPI communications with another device. +* +* @return (none) +*/ +inline void nRF905_interrupt_on(void) +{ +#if NRF905_INTERRUPTS + REG_EXTERNAL_INT |= _BV(BIT_EXTERNAL_INT); +#endif +} + +#endif /* NRF905_H_ */ \ No newline at end of file diff --git a/nRF905_Pluggit_AP300/nRF905_Pluggit_AP300.ino b/nRF905_Pluggit_AP300/nRF905_Pluggit_AP300.ino new file mode 100644 index 0000000..f744a8b --- /dev/null +++ b/nRF905_Pluggit_AP300/nRF905_Pluggit_AP300.ino @@ -0,0 +1,258 @@ +/* + * Project: nRF905 AVR/Arduino Library/Driver + * Author: Zak Kemble, contact@zakkemble.co.uk + * Copyright: (C) 2013 by Zak Kemble + * License: GNU GPL v3 (see License.txt) + * Web: http://blog.zakkemble.co.uk/nrf905-avrarduino-librarydriver/ + */ + +/* + * Time how long it takes to send some data and get a reply + * Should be around 14-16ms with default settings. + * + * 7 -> PWR == PWR_MODE + * 8 -> CE == TRX_EN + * 9 -> TXE == TX_EN + * 2 -> CD + * 3 -> DR - uses INT1 interrupt + * 10 -> CSN + * 12 -> SO + * 11 -> SI + * 13 -> SCK + */ + +#include +#include + +#define RXADDR {0x00, 0x00, 0x0A, 0x7A} // Address of this device (4 bytes) +#define TXADDR {0x00, 0x00, 0x0A, 0x7A} // Address of device to send to (4 bytes) + +#define TIMEOUT 1000 // 1 second ping timeout + +uint8_t payload[4][NRF905_MAX_PAYLOAD]; +uint8_t plCounter; +//#define DBG_PIN 5 +////////////////////////////////////////////////////////////////////////// +void nRF905_Config(void) +{ + // Set control register 0 - CHANNEL + nRF905_setConfigReg0(0x76); + // config reg 1 + nRF905_setConfigReg1(0x0E); + // config reg 2 + nRF905_setConfigReg2(0x44); + // Set payload sizes + nRF905_setPayloadSizes(0x20); + // set TX and Rx addresses + static byte buf1[] = TXADDR; + nRF905_setTXAddress(buf1); + // set Rx addres + static byte buf2[] = RXADDR; + nRF905_setRXAddress(buf2); + // read config register 9 - just to be conform with data detected by sniffing + nRF905_getConfigReg(9); + // set config register 9 + nRF905_setConfigReg9(0xDB); + // Clear DR by reading receive payload + nRF905_flushRecBuffer(); + // Set interrupts +// REG_EXTERNAL_INT_CTL |= BIT_EXTERNAL_INT_CTL; +// nRF905_interrupt_on(); +} +////////////////////////////////////////////////////////////////////////// +void nRF905_Initialise() +{ + pinMode(PWR_MODE, OUTPUT); + digitalWrite(PWR_MODE, LOW); // activate power down mode + pinMode(TRX_EN, OUTPUT); + digitalWrite(TRX_EN, LOW); // activate standby mode + pinMode(TX_EN, OUTPUT); + pinMode(CSN, OUTPUT); + pinMode(CD, INPUT); + pinMode(DR, INPUT); + digitalWrite(CSN, HIGH); +#ifdef DBG_PIN + pinMode(DBG_PIN, OUTPUT); +#endif + + SPI.begin(); + SPI.setClockDivider(SPI_CLOCK_DIV2); + + nRF905_Config(); + +#if NRF905_INTERRUPTS + // Set interrupts + REG_EXTERNAL_INT_CTL |= BIT_EXTERNAL_INT_CTL; + nRF905_interrupt_on(); +#endif + +Serial.println(F("nRF905 configured...")); +StatusPins(); +// leave config mode + nRF905_powerUp(); +Serial.println(F("nRF905 powered up...")); +StatusPins(); + // Put into receive mode +// nRF905_receive(); +} +////////////////////////////////////////////////////////////////// +void StatusPins(void) +{ +return; +/**/ + Serial.print(F("pins: ")); + Serial.print(digitalRead(CD)); + Serial.print(","); + Serial.print(digitalRead(DR)); + Serial.print(","); + Serial.print(digitalRead(PWR_MODE)); + Serial.print(","); + Serial.print(digitalRead(TRX_EN)); + Serial.print(","); + Serial.println(digitalRead(TX_EN)); +} +/////////////////////////////////////////////////////////////////// +void setup() +{ + Serial.begin(57600); + Serial.println(F("Client started")); + StatusPins(); + // Start up + nRF905_Initialise(); + StatusPins(); + Serial.println(F("nRF905 initialised")); + plCounter = 0; +} + +////////////////////////////////////////////////////// +nRF905_radio_state_t nRF905_getStatus(void) +{ + if (!digitalRead(PWR_MODE)) return NRF905_RADIO_STATE_POWER_DOWN; + else if (!digitalRead(TRX_EN)) return NRF905_RADIO_STATE_STANDBY; + else if (!digitalRead(TX_EN)) { + if (!digitalRead(DR)) return NRF905_RADIO_STATE_RX; + else return NRF905_RADIO_STATE_RX_END; + } else { + if (!digitalRead(DR)) return NRF905_RADIO_STATE_TX; + else return NRF905_RADIO_STATE_TX_END; + } +} + +///////////////////////////////////////////////////////////// +char wr1[] PROGMEM = {0x90, 0x80, 0x03, 0x04, 0x00, 0x00, 0x0C}; +char wr2[] PROGMEM = {0x90, 0x80, 0x03, 0x04, 0x0C, 0x00, 0x0C}; +static byte counter = 0; +static byte recOK = 0; +///////////////////////////////////////////////////////////// +void loop() +{ + byte ret; + + // Make data + strcpy_P((char*)payload, wr1); + counter++; + Serial.println(counter); + +#ifdef DBG_PIN + digitalWrite(DBG_PIN, 1); +#endif + unsigned long startTime = millis(); +/* // Set address of device to send to + byte addr[] = TXADDR; + nRF905_setTXAddress(addr); +*/ +#if 0 +//// SET DATA + StatusPins(); + Serial.println(F("setting data ...")); + // Set payload data + ret = nRF905_setData(payload, sizeof(wr1)); + if (ret) Serial.println(F("Error by setting data!")); + +//// SEND DATA + StatusPins(); + Serial.println(F("sending data ...")); + // Send payload (send fails if other transmissions are going on, keep trying until success) + while(1) { + ret = nRF905_send(); + if (ret==0) break; + else { + Serial.print(F("nRF905_send returned: ")); + Serial.println(ret); + delay(100); + } + StatusPins(); + }; +#endif +//// RECEIVE DATA +#ifdef DBG_PIN + digitalWrite(DBG_PIN, 0); + StatusPins(); + Serial.println(F("receiving data ...")); +#endif + // Put into receive mode + nRF905_receive(); + + // Make buffer for reply +// byte buffer[NRF905_MAX_PAYLOAD]; +#define buffer payload + +//// GETTING DATA +#ifdef DBG_PIN + StatusPins(); + Serial.println(F("getting data ...")); +#endif + // Wait for reply with timeout + unsigned long time0 = millis(); + while(1) + { + ret = nRF905_getData(&buffer[plCounter][0], NRF905_MAX_PAYLOAD); + if (ret==0) {plCounter++; recOK = true; break;} // Got data + else { +#ifdef DBG_PIN + Serial.print(F("getData returned: ")); + Serial.println(ret); +#endif + } +// StatusPins(); + // check timeout + if( millis() > (time0 + TIMEOUT) ) break; + } + +//// EVALUATE DATA +#ifdef DBG_PIN + StatusPins(); + Serial.println(F("evaluating data...")); +#endif + if(!ret) + { // data received. Do nothing, wait for time-out for display received data +#ifdef DBG_PIN + unsigned int totalTime = millis() - startTime; + Serial.print(F("Ping time: ")); + Serial.print(totalTime); + Serial.println(F("ms")); + // Printout ping contents + Serial.print(F("Replay from AP300: ")); +#endif + } + else if (recOK) { +// Serial.print(F("Replay from AP300: ")); + for (uint8_t y = 0; y=100) + while (1); // stop here +// delay(100); +*/ +} diff --git a/nRF905_Pluggit_AP300/nRF905_config.h b/nRF905_Pluggit_AP300/nRF905_config.h new file mode 100644 index 0000000..a15c2b2 --- /dev/null +++ b/nRF905_Pluggit_AP300/nRF905_config.h @@ -0,0 +1,164 @@ +/* + * Project: nRF905 AVR/Arduino Library/Driver + * Author: Zak Kemble, contact@zakkemble.co.uk + * Copyright: (C) 2013 by Zak Kemble + * License: GNU GPL v3 (see License.txt) + * Web: http://blog.zakkemble.co.uk/nrf905-avrarduino-librarydriver/ + */ + +#ifndef NRF905_CONFIG_H_ +#define NRF905_CONFIG_H_ + +#include "nRF905_defs.h" + +// Crystal frequency (the one the radio IC/module is using) +// NRF905_CLK_4MHZ +// NRF905_CLK_8MHZ +// NRF905_CLK_12MHZ +// NRF905_CLK_16MHZ +// NRF905_CLK_20MHZ +#define NRF905_CLK_FREQ NRF905_CLK_16MHZ + +// Use pin interrupt for data ready +// NOTE: If you have other devices connected that use the SPI bus then you will need to call nRF905_interrupt_off() before using SPI comms and then RF905_interrupt_on() once you've finished. +// Disabled for ESP32 - using polling mode +#define NRF905_INTERRUPTS 0 + +// Buffer count +// Only used if interrupts are used (see NRF905_INTERRUPTS) +// NOT YET IMPLEMENTED +//#define BUFFER_COUNT_RX 1 + +// Buffer count +// NOT YET IMPLEMENTED +//#define BUFFER_COUNT_TX 1 + +// +// NOT YET IMPLEMENTED +//#define NRF905_MAX_PACKET_SIZE 64 + +// Use software to get address match state instead of reading pin for high/low state +// Not used in this library yet +#define NRF905_AM_SW 0 + +// Use software to get data ready state instead of reading pin for high/low state +// Interrupts and software DR can not be enabled together +#define NRF905_DR_SW 1 + +// Don't transmit if airway is busy (other transmissions are going on) +#define NRF905_COLLISION_AVOID 0 + + +/////////////////// +// Pin stuff - ESP32 Configuration +/////////////////// + +// ESP32 GPIO pins for nRF905 +#define PWR_MODE 4 // Power mode pin (GPIO4) +#define TRX_EN 16 // Enable/standby pin (GPIO16) +#define TX_EN 17 // TX / RX mode pin (GPIO17) +#define CD 27 // Carrier detect pin (GPIO27) - optional +#define CSN 5 // SPI slave select pin (GPIO5) + +// Data ready pin +// If using interrupts (NRF905_INTERRUPTS 1) then this must be +// an external interrupt pin that matches the interrupt register settings below. +#define DR 26 // Data ready (GPIO26) - optional for interrupts + +// Address match pin (not used by library) +// blah +//#define AM 4 + + +/////////////////// +// Interrupt register stuff +// Only needed if NRF905_INTERRUPTS is 1 +/////////////////// + +// Interrupt number (INT0, INT1 etc) +// This must match the INT that is connected to DR +#define INTERRUPT_NUM 1 + +// ATmega48/88/168/328 +// INT0 = D2 (Arduino UNO pin 2) +// INT1 = D3 (Arduino UNO pin 3) + +// ATmega640/1280/1281/2560/2561 +// INT0 = D0 (Arduino MEGA pin 21) +// INT1 = D1 (Arduino MEGA pin 20) +// INT2 = D2 (Arduino MEGA pin 19) +// INT3 = D3 (Arduino MEGA pin 18) +// INT4 = E4 (Arduino MEGA pin 2) +// INT5 = E5 (Arduino MEGA pin 3) +// INT6 = E6 (Arduino MEGA N/A) +// INT7 = E7 (Arduino MEGA N/A) + +// Leave these commented out to let the library figure out what registers to use + +// Which interrupt to use for data ready (DR) +//#define REG_EXTERNAL_INT EIMSK +//#define BIT_EXTERNAL_INT INT1 +//#define INT_VECTOR INT1_vect + +// Set interrupt to trigger on rising edge +//#define REG_EXTERNAL_INT_CTL EICRA +//#define BIT_EXTERNAL_INT_CTL (_BV(ISC11)|_BV(ISC10)) + + +/////////////////// +// Default radio settings +/////////////////// + +// Frequency +#define NRF905_FREQ 868200000UL + +// Frequency band +// NRF905_BAND_433 +// NRF905_BAND_868 +// NRF905_BAND_915 +#define NRF905_BAND NRF905_BAND_868 + +// Output power +// n means negative, n10 = -10 +// NRF905_PWR_n10 (-10dBm = 100uW) +// NRF905_PWR_n2 (-2dBm = 631uW) +// NRF905_PWR_6 (6dBm = 4mW) +// NRF905_PWR_10 (10dBm = 10mW) +#define NRF905_PWR NRF905_PWR_10 + +// Save a few mA by reducing receive sensitivity +// NRF905_LOW_RX_DISABLE +// NRF905_LOW_RX_ENABLE +#define NRF905_LOW_RX NRF905_LOW_RX_DISABLE + +// Constantly retransmit payload while in transmit mode +// Can be useful in areas with lots of interference, but you'll need to make sure you can differentiate between re-transmitted packets and new packets (like an ID number). +// It will also block other transmissions if collision avoidance is enabled. +// NRF905_AUTO_RETRAN_DISABLE +// NRF905_AUTO_RETRAN_ENABLE +#define NRF905_AUTO_RETRAN NRF905_AUTO_RETRAN_DISABLE + +// Output a clock signal on pin 3 of IC +// NRF905_OUTCLK_DISABLE +// NRF905_OUTCLK_500KHZ +// NRF905_OUTCLK_1MHZ +// NRF905_OUTCLK_2MHZ +// NRF905_OUTCLK_4MHZ +#define NRF905_OUTCLK NRF905_OUTCLK_DISABLE + +// CRC checksum +// NRF905_CRC_DISABLE +// NRF905_CRC_8 +// NRF905_CRC_16 +#define NRF905_CRC NRF905_CRC_16 + +// Address size +// Number of bytes for address +// NRF905_ADDR_SIZE_1 +// NRF905_ADDR_SIZE_4 +#define NRF905_ADDR_SIZE NRF905_ADDR_SIZE_4 + +// Payload size (1 - 32) +#define NRF905_PAYLOAD_SIZE 32 //NRF905_MAX_PAYLOAD + +#endif /* NRF905_CONFIG_H_ */ \ No newline at end of file diff --git a/nRF905_Pluggit_AP300/nRF905_defs.h b/nRF905_Pluggit_AP300/nRF905_defs.h new file mode 100644 index 0000000..085fcb7 --- /dev/null +++ b/nRF905_Pluggit_AP300/nRF905_defs.h @@ -0,0 +1,121 @@ +/* + * Project: nRF905 AVR/Arduino Library/Driver + * Author: Zak Kemble, contact@zakkemble.co.uk + * Copyright: (C) 2013 by Zak Kemble + * License: GNU GPL v3 (see License.txt) + * Web: http://blog.zakkemble.co.uk/nrf905-avrarduino-librarydriver/ + */ + +#ifndef NRF905_DEFS_H_ +#define NRF905_DEFS_H_ + +#define AM_IS_USED_HW (!NRF905_AM_SW && defined(AM)) +#define POWER_UP() (digitalWrite(PWR_MODE, HIGH)) +#define POWER_DOWN() (digitalWrite(PWR_MODE, LOW)) +#define DISABLE_STANDBY_MODE() (digitalWrite(TRX_EN, HIGH)) +#define ENABLE_STANDBY_MODE() (digitalWrite(TRX_EN, LOW)) +#define SPI_SELECT() (digitalWrite(CSN, LOW)) +#define SPI_DESELECT() (digitalWrite(CSN, HIGH)) +#define RECEIVE_MODE() (digitalWrite(TX_EN, LOW)) +#define TRANSMIT_MODE() (digitalWrite(TX_EN, HIGH)) +#define spi_transfer(data) (SPI.transfer(data)) +//#define spi_transfer_nr(data) (SPI.transfer(data)) + +// Instructions +#define NRF905_CMD_NOP 0xFF +#define NRF905_CMD_W_CONFIG 0x00 +#define NRF905_CMD_R_CONFIG 0x10 +#define NRF905_CMD_W_TX_PAYLOAD 0x20 +#define NRF905_CMD_R_TX_PAYLOAD 0x21 +#define NRF905_CMD_W_TX_ADDRESS 0x22 +#define NRF905_CMD_R_TX_ADDRESS 0x23 +#define NRF905_CMD_R_RX_PAYLOAD 0x24 +#define NRF905_CMD_CHAN_CONFIG 0x80 + +// Registers +#define NRF905_REG_CHANNEL 0x00 +//#define NRF905_REG_AUTO_RETRAN 0x01 +//#define NRF905_REG_LOW_RX 0x01 +//#define NRF905_REG_PWR 0x01 +#define NRF905_REG_BAND 0x01 +#define NRF905_REG_CRC 0x09 +#define NRF905_REG_CLK 0x09 +#define NRF905_REG_OUTCLK 0x09 +#define NRF905_REG_OUTCLK_FREQ 0x09 +#define NRF905_REG_RX_ADDRESS 0x05 +#define NRF905_REG_RX_PAYLOAD_SIZE 0x03 +#define NRF905_REG_TX_PAYLOAD_SIZE 0x04 +#define NRF905_REG_ADDR_WIDTH 0x02 + +// Clock options +#define NRF905_CLK_4MHZ 0x00 +#define NRF905_CLK_8MHZ 0x08 +#define NRF905_CLK_12MHZ 0x10 +#define NRF905_CLK_16MHZ 0x18 +#define NRF905_CLK_20MHZ 0x20 + +// Register masks +#define NRF905_MASK_CHANNEL 0xFC +#define NRF905_MASK_AUTO_RETRAN ~(NRF905_AUTO_RETRAN_ENABLE | NRF905_AUTO_RETRAN_DISABLE) //0xDF +#define NRF905_MASK_LOW_RX ~(NRF905_LOW_RX_ENABLE | NRF905_LOW_RX_DISABLE) //0xEF +#define NRF905_MASK_PWR ~(NRF905_PWR_n10 | NRF905_PWR_n2 | NRF905_PWR_6 | NRF905_PWR_10) //0xF3 +#define NRF905_MASK_BAND ~(NRF905_BAND_433 | NRF905_BAND_868 | NRF905_BAND_915) //0xFD +#define NRF905_MASK_CRC (uint8_t)(~(NRF905_CRC_DISABLE | NRF905_CRC_8 | NRF905_CRC_16)) //0x3F // typecast to stop compiler moaning about large integer truncation +#define NRF905_MASK_CLK ~(NRF905_CLK_4MHZ | NRF905_CLK_8MHZ | NRF905_CLK_12MHZ | NRF905_CLK_16MHZ | NRF905_CLK_20MHZ) //0xC7 +#define NRF905_MASK_OUTCLK ~(NRF905_OUTCLK_DISABLE | NRF905_OUTCLK_4MHZ | NRF905_OUTCLK_2MHZ | NRF905_OUTCLK_1MHZ | NRF905_OUTCLK_500KHZ) // 0xF8 + +// Bit positions +#define NRF905_STATUS_DR 5 +#define NRF905_STATUS_AM 7 + +#include "nRF905_config.h" + +#if (NRF905_DR_SW && NRF905_INTERRUPTS) + #error "NRF905_INTERRUPTS and NRF905_DR_SW can not both be enabled" +#endif + +// Workout channel from frequency & band +#define NRF905_CALC_CHANNEL(f, b) ((((f) / (1 + (b>>1))) - 422400000UL) / 100000UL) + +#define CONCAT(a, b) a ## b +#define CONCAT2(a, b, c) a ## b ## c + +#define INTCONCAT(num) CONCAT(INT, num) +#define ISCCONCAT(num, bit) CONCAT2(ISC, num, bit) +#define INTVECTCONCAT(num) CONCAT2(INT, num, _vect) + +#ifndef REG_EXTERNAL_INT + #ifdef EIMSK + #define REG_EXTERNAL_INT EIMSK + #elif defined GICR + #define REG_EXTERNAL_INT GICR + #else + #define REG_EXTERNAL_INT GIMSK + #endif +#endif + +#ifndef REG_EXTERNAL_INT_CTL + #ifdef EICRA + #if INTERRUPT_NUM < 4 + #define REG_EXTERNAL_INT_CTL EICRA + #else + #define REG_EXTERNAL_INT_CTL EICRB + #endif + #else + #define REG_EXTERNAL_INT_CTL MCUCR + #endif +#endif + +#ifndef BIT_EXTERNAL_INT + #define BIT_EXTERNAL_INT INTCONCAT(INTERRUPT_NUM) +#endif + +#ifndef BIT_EXTERNAL_INT_CTL + #define BIT_EXTERNAL_INT_CTL (_BV(ISCCONCAT(INTERRUPT_NUM, 1))|_BV(ISCCONCAT(INTERRUPT_NUM, 0))) +#endif + +#ifndef INT_VECTOR + #define INT_VECTOR INTVECTCONCAT(INTERRUPT_NUM) +#endif + +#endif /* NRF905_DEFS_H_ */ \ No newline at end of file diff --git a/nRF905_Pluggit_AP300/nRF905_types.h b/nRF905_Pluggit_AP300/nRF905_types.h new file mode 100644 index 0000000..b13aec3 --- /dev/null +++ b/nRF905_Pluggit_AP300/nRF905_types.h @@ -0,0 +1,23 @@ +/* + * Project: nRF905 AVR/Arduino Library/Driver + * Author: Zak Kemble, contact@zakkemble.co.uk + * Copyright: (C) 2013 by Zak Kemble + * License: GNU GPL v3 (see License.txt) + * Web: http://blog.zakkemble.co.uk/nrf905-avrarduino-librarydriver/ + */ + +#ifndef NRF905_TYPES_H_ +#define NRF905_TYPES_H_ + +#ifndef ARDUINO +#include +#endif +#include "nRF905_config.h" +/* +typedef struct { + uint8_t len; + uint8_t dstAddress[NRF905_ADDR_SIZE]; + uint8_t buffer[64]; +} nrf905_packet_s; +*/ +#endif /* NRF905_TYPES_H_ */ diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..15f4813 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,20 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:upesy_wroom] +platform = espressif32 +board = upesy_wroom +framework = arduino +monitor_speed = 115200 +build_flags = + -I nRF905_Pluggit_AP300 +build_src_filter = + +<*> + +<../nRF905_Pluggit_AP300/*.cpp> diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..ea9e5f9 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,370 @@ +#include +#include +#include "../nRF905_Pluggit_AP300/nRF905.h" + +/* + * nRF905 Pin Configuration for ESP32 + * + * SPI Pins (Hardware SPI): + * - MOSI: GPIO23 + * - MISO: GPIO19 + * - SCK: GPIO18 + * - CSN: GPIO5 (Chip Select) + * + * Control Pins: + * - PWR_MODE: GPIO4 (Power control) + * - TRX_EN: GPIO16 (TX/RX Enable) + * - TX_EN: GPIO17 (TX/RX Mode select) + * + * Optional Pins (configured in nRF905_config.h): + * - DR: GPIO26 (Data Ready - for interrupts) + * - CD: GPIO27 (Carrier Detect - for collision avoidance) + */ + +// Statistics +uint32_t lastPacketTime = 0; +uint32_t packetCount = 0; +uint32_t pollCount = 0; +bool initialized = false; + +void setup() { + // Initialize Serial communication + Serial.begin(115200); + delay(1000); + + Serial.println("\n\n========================================"); + Serial.println(" nRF905 ESP32 Test & Receiver"); + Serial.println("========================================\n"); + + // Step 1: Initialize nRF905 + Serial.println("[1/4] Initializing nRF905..."); + Serial.println(" Pins configured:"); + Serial.println(" MOSI: GPIO23, MISO: GPIO19, SCK: GPIO18"); + Serial.println(" CSN: GPIO5"); + Serial.println(" PWR: GPIO4, CE: GPIO16, TXE: GPIO17"); + Serial.println(" DR: GPIO26 (Data Ready)"); + + // Configure GPIO pins BEFORE calling nRF905_init() + pinMode(4, OUTPUT); // PWR_MODE + pinMode(16, OUTPUT); // TRX_EN + pinMode(17, OUTPUT); // TX_EN + pinMode(5, OUTPUT); // CSN + pinMode(26, INPUT); // DR (Data Ready) + pinMode(27, INPUT); // CD (Carrier Detect) + digitalWrite(5, HIGH); // CSN high + + nRF905_init(); + delay(100); + Serial.println(" ✓ nRF905 initialized"); + + // Step 2: Test SPI communication by reading config registers + Serial.println("\n[2/4] Testing SPI communication..."); + bool spiOk = false; + + for (int reg = 0; reg < 10; reg++) { + uint8_t value = nRF905_getConfigReg(reg); + Serial.print(" Config Reg["); + Serial.print(reg); + Serial.print("]: 0x"); + if (value < 0x10) Serial.print("0"); + Serial.println(value, HEX); + + // Check if we're reading something (not all 0x00 or all 0xFF) + if (value != 0x00 && value != 0xFF) { + spiOk = true; + } + } + + if (spiOk) { + Serial.println(" ✓ SPI communication working!"); + initialized = true; + } else { + Serial.println(" ✗ SPI communication FAILED!"); + Serial.println(" Check wiring, especially:"); + Serial.println(" - MOSI, MISO, SCK, CSN connections"); + Serial.println(" - Power (3.3V) and Ground"); + Serial.println(" - PWR_MODE, TRX_EN, TX_EN control pins"); + } + + if (!initialized) { + Serial.println("\n*** INITIALIZATION FAILED ***"); + Serial.println("System halted. Check wiring and reset."); + while (true) delay(1000); + } + + // Step 3: Configure nRF905 for Pluggit AP300 (868 MHz) + // Using exact configuration from working AP300 code + Serial.println("\n[3/4] Configuring nRF905..."); + + // Set control register 0 - CHANNEL (0x76 = 868.4 MHz for 868 band) + nRF905_setConfigReg0(0x76); + Serial.println(" ✓ Channel: 0x76 (868.4 MHz)"); + + // Set control register 1 - Band, Power, Auto-retransmit, Low RX + // 0x0E = 868MHz band, 10dBm power, no auto-retransmit, normal RX + nRF905_setConfigReg1(0x0E); + Serial.println(" ✓ Config Reg1: 0x0E (868MHz, 10dBm)"); + + // Set control register 2 - Address width + // 0x44 = 4 bytes TX address, 4 bytes RX address + nRF905_setConfigReg2(0x44); + Serial.println(" ✓ Config Reg2: 0x44 (4-byte addresses)"); + + // Set payload size to 32 bytes (0x20) + nRF905_setPayloadSizes(0x20); + Serial.println(" ✓ Payload size: 32 bytes"); + + // Set RX and TX addresses (Pluggit AP300: 0x00, 0x00, 0x07, 0x7A) + uint8_t rxAddr[4] = {0x00, 0x00, 0x07, 0x7A}; + nRF905_setTXAddress(rxAddr); + nRF905_setRXAddress(rxAddr); + Serial.print(" ✓ RX/TX Address: "); + for (int i = 0; i < 4; i++) { + if (rxAddr[i] < 0x10) Serial.print("0"); + Serial.print(rxAddr[i], HEX); + if (i < 3) Serial.print(" "); + } + Serial.println(); + + // Set control register 9 - CRC and clock settings + // 0xDB = 16-bit CRC, 16MHz crystal, clock output disabled + nRF905_setConfigReg9(0xDB); + Serial.println(" ✓ Config Reg9: 0xDB (16-bit CRC, 16MHz XTAL)"); + + // Flush receive buffer to clear any old data + nRF905_flushRecBuffer(); + Serial.println(" ✓ RX buffer flushed"); + + // Verify configuration by reading back registers + Serial.println("\n Configuration verification:"); + Serial.print(" Reg0 (Channel): 0x"); + Serial.println(nRF905_getConfigReg(0), HEX); + Serial.print(" Reg1 (Band/Pwr): 0x"); + Serial.println(nRF905_getConfigReg(1), HEX); + Serial.print(" Reg9 (CRC/CLK): 0x"); + Serial.println(nRF905_getConfigReg(9), HEX); + + // Step 4: Enter receive mode + Serial.println("\n[4/4] Starting receive mode..."); + + // Show initial pin states + Serial.print(" Initial pins - PWR:"); + Serial.print(digitalRead(4)); + Serial.print(" CE:"); + Serial.print(digitalRead(16)); + Serial.print(" TXE:"); + Serial.print(digitalRead(17)); + Serial.print(" DR:"); + Serial.println(digitalRead(26)); + + // Power up the radio + nRF905_powerUp(); + delay(10); + Serial.println(" ✓ Radio powered up"); + + // Enter receive mode + nRF905_receive(); + delay(10); + Serial.println(" ✓ Receive mode active"); + + // Show pin states after entering receive mode + Serial.print(" RX mode pins - PWR:"); + Serial.print(digitalRead(4)); + Serial.print(" CE:"); + Serial.print(digitalRead(16)); + Serial.print(" TXE:"); + Serial.print(digitalRead(17)); + Serial.print(" DR:"); + Serial.println(digitalRead(26)); + + // Check radio state + nRF905_radio_state_t state = nRF905_getState(); + Serial.print(" Radio state: "); + switch(state) { + case NRF905_RADIO_STATE_POWER_DOWN: + Serial.println("POWER_DOWN"); + break; + case NRF905_RADIO_STATE_STANDBY: + Serial.println("STANDBY"); + break; + case NRF905_RADIO_STATE_RX: + Serial.println("RX (Receiving)"); + break; + case NRF905_RADIO_STATE_RX_END: + Serial.println("RX_END (Data Ready!)"); + break; + case NRF905_RADIO_STATE_TX: + Serial.println("TX (Transmitting)"); + break; + case NRF905_RADIO_STATE_TX_END: + Serial.println("TX_END"); + break; + default: + Serial.println("UNKNOWN"); + } + + Serial.println("\n========================================"); + Serial.println(" Listening for packets..."); + Serial.println(" Frequency: 868.4 MHz (Channel 0x76)"); + Serial.println(" Address: 0x00 0x00 0x07 0x7A"); + Serial.println("========================================\n"); +} + +void loop() { + if (!initialized) { + delay(1000); + return; + } + + // Get current time once per loop iteration + uint32_t now = millis(); + + // Poll for data with timeout (like the working examples) + static uint32_t lastPollTime = 0; + + // Try to get data every 50ms to avoid excessive polling + if (now - lastPollTime > 50) { + lastPollTime = now; + pollCount++; + + // Prepare buffer for received data + uint8_t rxData[NRF905_MAX_PAYLOAD]; + memset(rxData, 0, NRF905_MAX_PAYLOAD); + + // Try to read data (returns 0 on success, 1 if no data available) + uint8_t result = nRF905_getData(rxData, NRF905_MAX_PAYLOAD); + + if (result == 0) { + // Data received! + packetCount++; + uint32_t currentTime = millis(); + uint32_t timeSinceLastPacket = (lastPacketTime > 0) ? (currentTime - lastPacketTime) : 0; + lastPacketTime = currentTime; + // Print packet header + Serial.println("\n┌─────────────────────────────────────────────"); + Serial.print("│ ["); + Serial.print(currentTime); + Serial.print("ms] PACKET #"); + Serial.print(packetCount); + + if (timeSinceLastPacket > 0) { + Serial.print(" | Gap: "); + Serial.print(timeSinceLastPacket); + Serial.print("ms"); + } + Serial.println(); + + // Print HEX data + Serial.print("│ HEX: "); + for (int i = 0; i < NRF905_MAX_PAYLOAD; i++) { + if (rxData[i] < 0x10) Serial.print("0"); + Serial.print(rxData[i], HEX); + if (i < NRF905_MAX_PAYLOAD - 1) Serial.print(" "); + if ((i + 1) % 16 == 0 && i < NRF905_MAX_PAYLOAD - 1) { + Serial.println(); + Serial.print("│ "); + } + } + Serial.println(); + + // Try ASCII display (if any printable characters exist) + bool hasAscii = false; + for (int i = 0; i < NRF905_MAX_PAYLOAD; i++) { + if (rxData[i] >= 32 && rxData[i] <= 126) { + hasAscii = true; + break; + } + } + + if (hasAscii) { + Serial.print("│ ASCII: "); + for (int i = 0; i < NRF905_MAX_PAYLOAD; i++) { + if (rxData[i] >= 32 && rxData[i] <= 126) { + Serial.print((char)rxData[i]); + } else if (rxData[i] == 0) { + Serial.print("·"); // Middle dot for null + } else { + Serial.print("."); + } + } + Serial.println(); + } + + // Analyze data patterns + bool allZero = true; + bool allSame = true; + uint8_t firstByte = rxData[0]; + + for (int i = 0; i < NRF905_MAX_PAYLOAD; i++) { + if (rxData[i] != 0) allZero = false; + if (rxData[i] != firstByte) allSame = false; + } + + if (allZero) { + Serial.println("│ [INFO] All zeros - possible empty/idle packet"); + } else if (allSame) { + Serial.print("│ [INFO] All bytes same value: 0x"); + if (firstByte < 0x10) Serial.print("0"); + Serial.println(firstByte, HEX); + } + + Serial.println("└─────────────────────────────────────────────\n"); + + // Return to receive mode after reading data + nRF905_receive(); + } + } + + // Status update every 5 seconds + static uint32_t lastStatusTime = 0; + if (now - lastStatusTime > 5000) { + lastStatusTime = now; + + Serial.print("[STATUS] Uptime: "); + Serial.print(now / 1000); + Serial.print("s | Packets: "); + Serial.print(packetCount); + Serial.print(" | Polls: "); + Serial.print(pollCount); + + // Read pin states for debugging + Serial.print(" | Pins[PWR:"); + Serial.print(digitalRead(4)); + Serial.print(" CE:"); + Serial.print(digitalRead(16)); + Serial.print(" TXE:"); + Serial.print(digitalRead(17)); + Serial.print(" DR:"); + Serial.print(digitalRead(26)); + Serial.print("] | State: "); + + nRF905_radio_state_t currentState = nRF905_getStatus(); + switch(currentState) { + case NRF905_RADIO_STATE_POWER_DOWN: + Serial.println("POWER_DOWN"); + break; + case NRF905_RADIO_STATE_STANDBY: + Serial.println("STANDBY"); + break; + case NRF905_RADIO_STATE_RX: + Serial.println("RX (Listening)"); + break; + case NRF905_RADIO_STATE_RX_END: + Serial.println("RX_END (Data Ready!)"); + break; + case NRF905_RADIO_STATE_TX: + Serial.println("TX"); + break; + case NRF905_RADIO_STATE_TX_END: + Serial.println("TX_END"); + break; + default: + Serial.println("UNKNOWN"); + } + + pollCount = 0; + } + + // Small delay to prevent excessive CPU usage + delay(1); +} \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html