From 51e820dc13c76c8164b6b4a3bf160ca4293c7137 Mon Sep 17 00:00:00 2001 From: Jon Szymaniak Date: Sat, 18 Jun 2016 21:54:52 -0400 Subject: [PATCH 1/4] Removed extraneous whitespace --- src/radio.h | 4 ++-- src/usb.c | 44 ++++++++++++++++++++++---------------------- src/usb_desc.c | 34 +++++++++++++++++----------------- src/usb_desc.h | 44 ++++++++++++++++++++++---------------------- 4 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/radio.h b/src/radio.h index 97845ee..a9b919e 100644 --- a/src/radio.h +++ b/src/radio.h @@ -100,7 +100,7 @@ __xdata static const uint8_t promiscuous_address[2] = { 0xAA, 0x00 }; // Radio mode enum radio_mode_t { - // ESB sniffer mode + // ESB sniffer mode sniffer = 0, // ESB promiscuous mode @@ -111,7 +111,7 @@ enum radio_mode_t }; // Radio mode -__xdata static uint8_t radio_mode; +__xdata static uint8_t radio_mode; // Promiscuous mode state __xdata static int pm_prefix_length; // Promixcuous mode address prefix length diff --git a/src/usb.c b/src/usb.c index a64a61c..d43db98 100644 --- a/src/usb.c +++ b/src/usb.c @@ -25,21 +25,21 @@ // xdata mapped USB request setup buffer __xdata struct usb_request_t * request = (__xdata void*)setupbuf; -// Initialize the USB configuraiton -bool init_usb() +// Initialize the USB configuration +bool init_usb() { - uint16_t ms_elapsed = 0; + uint16_t ms_elapsed = 0; configured = false; // Wakeup USB - usbcon = 0x40; + usbcon = 0x40; // Reset the USB bus usbcs |= 0x08; delay_us(50000); usbcs &= ~0x08; - // Set the default configuration + // Set the default configuration usb_reset_config(); // Wait for the USB controller to reach the configured state @@ -52,19 +52,19 @@ bool init_usb() // Reset the USB configuration void usb_reset_config() { - // Setup interrupts + // Setup interrupts usbien = 0x11; // USB reset and setup data valid in_ien = 0x00; // Disable EP IN interrupts out_ien = 0x02; // Enable EP1 OUT interrupt ien1 = 0x10; // Enable USB interrupt in_irq = 0x1F; // Clear IN IRQ flags out_irq = 0x1F; // Clear OUT IRQ flags - + // Enable bulk EP1, disable ISO EPs inbulkval = 0x02; outbulkval = 0x02; inisoval = 0x00; - outisoval = 0x00; + outisoval = 0x00; // Setup EP buffers bout1addr = 32; @@ -78,11 +78,11 @@ void usb_reset_config() // USB IRQ handler void usb_irq() __interrupt(12) __using(1) { - // Which IRQ? + // Which IRQ? // ref: nRF24LU1+ Product Spec, Section 7.8.3, Table 34 - switch (ivec) + switch (ivec) { - // Setup data available + // Setup data available case 0x00: handle_setup_request(); usbirq = 0x01; @@ -128,7 +128,7 @@ bool write_descriptor() memcpy(in0buf, &device_descriptor, desc_len); in0bc = desc_len; return true; - + // Configuration descriptor request case CONFIGURATION_DESCRIPTOR: if(desc_len > configuration_descriptor.wTotalLength) desc_len = configuration_descriptor.wTotalLength; @@ -140,20 +140,20 @@ bool write_descriptor() // - Language, Manufacturer, or Product case STRING_DESCRIPTOR: write_device_string(device_strings[setupbuf[2]]); - return true; - } + return true; + } // Not handled return false; } -// Handle a USB setup request +// Handle a USB setup request void handle_setup_request() { bool handled = false; switch(request->bRequest) { - // Return a descriptor + // Return a descriptor case GET_DESCRIPTOR: if(write_descriptor()) handled = true; break; @@ -164,7 +164,7 @@ void handle_setup_request() break; // Set the configuration state - case SET_CONFIGURATION: + case SET_CONFIGURATION: if (request->wValue == 0) configured = false; // Not configured, drop back to powered state else configured = true; // Configured handled = true; @@ -184,17 +184,17 @@ void handle_setup_request() if (request->bmRequestType == 0x82) { if ((setupbuf[4] & 0x80) == 0x80) in0buf[0] = in1cs; - else in0buf[0] = out1cs; + else in0buf[0] = out1cs; } - // Device / Interface status, always two 0 bytes because - // we're bus powered and don't support remote wakeup - else + // Device / Interface status, always two 0 bytes because + // we're bus powered and don't support remote wakeup + else { in0buf[0] = 0; in0buf[1] = 0; } - + in0bc = 2; handled = true; break; diff --git a/src/usb_desc.c b/src/usb_desc.c index 3ea5af5..43285d7 100644 --- a/src/usb_desc.c +++ b/src/usb_desc.c @@ -18,8 +18,8 @@ #include "usb_desc.h" -// Device descriptor -__code const device_descriptor_t device_descriptor = +// Device descriptor +__code const device_descriptor_t device_descriptor = { .bLength = 18, // Size of this struct .bDescriptorType = DEVICE_DESCRIPTOR, @@ -30,48 +30,48 @@ __code const device_descriptor_t device_descriptor = .bMaxPacketSize0 = 64, // EP0 max packet size .idVendor = 0x1915, // Nordic Semiconductor .idProduct = 0x0102, // Nordic bootloader product ID incremebted by 1 - .bcdDevice = 0x0001, // Device version number + .bcdDevice = 0x0001, // Device version number .iManufacturer = STRING_DESCRIPTOR_MANUFACTURER, .iProduct = STRING_DESCRIPTOR_PRODUCT, .iSerialNumber = 0, .bNumConfigurations = 1, // Configuration count }; -// Configuration descriptor -__code const configuration_descriptor_t configuration_descriptor = +// Configuration descriptor +__code const configuration_descriptor_t configuration_descriptor = { .bLength = 9, // Size of the configuration descriptor .bDescriptorType = CONFIGURATION_DESCRIPTOR, - .wTotalLength = 32, // Total size of the configuration descriptor and EP/interface descriptors + .wTotalLength = 32, // Total size of the configuration descriptor and EP/interface descriptors .bNumInterfaces = 1, // Interface count .bConfigurationValue = 1, // Configuration identifer .iConfiguration = 0, .bmAttributes = 0x80, // Bus powered - .bMaxPower = 100, // Max power of 100*2mA = 200mA - .interface_descriptor = + .bMaxPower = 100, // Max power of 100*2mA = 200mA + .interface_descriptor = { - .bLength = 9, // Size of the interface descriptor + .bLength = 9, // Size of the interface descriptor .bDescriptorType = INTERFACE_DESCRIPTOR, .bInterfaceNumber = 0, // Interface index - .bAlternateSetting = 0, + .bAlternateSetting = 0, .bNumEndpoints = 2, // 2 endpoints, EP1IN, EP1OUT .bInterfaceClass = 0xFF, // Vendor interface class .bInterfaceSubClass = 0xFF, // Vendor interface subclass .bInterfaceProtocol = 0xFF, .iInterface = 0, }, - .endpoint_1_in_descriptor = + .endpoint_1_in_descriptor = { - .bLength = 7, // Size of the endpoint descriptor + .bLength = 7, // Size of the endpoint descriptor .bDescriptorType = ENDPOINT_DESCRIPTOR, .bEndpointAddress = 0x81, // EP1 IN .bmAttributes = 0x02, // Bulk EP .wMaxPacketSize = 64, // 64 byte packet buffer - .bInterval = 0, + .bInterval = 0, }, - .endpoint_1_out_descriptor = + .endpoint_1_out_descriptor = { - .bLength = 7, // Size of the endpoint descriptor + .bLength = 7, // Size of the endpoint descriptor .bDescriptorType = ENDPOINT_DESCRIPTOR, .bEndpointAddress = 0x01, // EP1 OUT .bmAttributes = 0x02, // Bulk EP @@ -80,8 +80,8 @@ __code const configuration_descriptor_t configuration_descriptor = }, }; -// String descriptor values -__code char * device_strings[3] = +// String descriptor values +__code char * device_strings[3] = { "\x04\x09", // Language (EN-US) "RFStorm", // Manufacturer diff --git a/src/usb_desc.h b/src/usb_desc.h index b982ca1..2f97458 100644 --- a/src/usb_desc.h +++ b/src/usb_desc.h @@ -19,7 +19,7 @@ #include #include -// Descriptor types +// Descriptor types enum descriptor_type_t { DEVICE_DESCRIPTOR = 1, @@ -37,7 +37,7 @@ enum string_descriptor_indexes_t STRING_DESCRIPTOR_PRODUCT, }; -// Device descriptor +// Device descriptor typedef struct { uint8_t bLength; uint8_t bDescriptorType; @@ -55,49 +55,49 @@ typedef struct { uint8_t bNumConfigurations; } device_descriptor_t; -// Interface descriptor +// Interface descriptor typedef struct { uint8_t bLength; uint8_t bDescriptorType; uint8_t bInterfaceNumber; uint8_t bAlternateSetting; - uint8_t bNumEndpoints; - uint8_t bInterfaceClass; - uint8_t bInterfaceSubClass; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; uint8_t bInterfaceProtocol; - uint8_t iInterface; + uint8_t iInterface; } interface_descriptor_t; -// Endpoint descriptor +// Endpoint descriptor typedef struct { uint8_t bLength; uint8_t bDescriptorType; - uint8_t bEndpointAddress; - uint8_t bmAttributes; - uint16_t wMaxPacketSize; - uint8_t bInterval; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; } endpoint_descriptor_t; // Configuration descriptor, EP1 IN and EP1 OUT typedef struct { uint8_t bLength; uint8_t bDescriptorType; - uint16_t wTotalLength; + uint16_t wTotalLength; uint8_t bNumInterfaces; uint8_t bConfigurationValue; uint8_t iConfiguration; - uint8_t bmAttributes; - uint8_t bMaxPower; - interface_descriptor_t interface_descriptor; - endpoint_descriptor_t endpoint_1_in_descriptor; - endpoint_descriptor_t endpoint_1_out_descriptor; + uint8_t bmAttributes; + uint8_t bMaxPower; + interface_descriptor_t interface_descriptor; + endpoint_descriptor_t endpoint_1_in_descriptor; + endpoint_descriptor_t endpoint_1_out_descriptor; } configuration_descriptor_t; -// Device descriptor -extern __code const device_descriptor_t device_descriptor; +// Device descriptor +extern __code const device_descriptor_t device_descriptor; -// Configuration descriptor -extern __code const configuration_descriptor_t configuration_descriptor; +// Configuration descriptor +extern __code const configuration_descriptor_t configuration_descriptor; // Language, manufacturer, and product device strings extern __code char * device_strings[3]; From 800b937d6811b8ae2dfc84084695015c3a003077 Mon Sep 17 00:00:00 2001 From: Jon Szymaniak Date: Sat, 18 Jun 2016 22:27:23 -0400 Subject: [PATCH 2/4] firmware: Comment typo fix (SFR) --- src/nRF24LU1P.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nRF24LU1P.h b/src/nRF24LU1P.h index 85669df..c740e23 100644 --- a/src/nRF24LU1P.h +++ b/src/nRF24LU1P.h @@ -34,7 +34,7 @@ // Microsecond delay inline void delay_us(uint16_t us) { do nop_us(); while(--us); } -// Shift feedback registers +// Special Function Registers (SFR) __sfr __at (0xE6) rfctl; // ref: nRF24LU1+ Product Spec, Section 6.5.1, Table 20 __sfr __at (0x90) rfcon; // ref: nRF24LU1+ Product Spec, Section 6.5.1, Table 21 __sfr __at (0xA0) usbcon; // ref: nRF24LU1+ Product Spec, Section 7.3, Table 24 From 23c3f061768a4cc627ea1fce11b737b3426408d5 Mon Sep 17 00:00:00 2001 From: Jon Szymaniak Date: Mon, 13 Jun 2016 23:59:38 -0400 Subject: [PATCH 3/4] firmware: Added platform interface with builds for CRPA LED and MSPI support A simple platform abstraction interface has been introduced in platform.h. This is intended to decouple the details of platform-specific IO assignments (e.g. LED pins, LNA enable, SPI chip select) from other portions of the code. Three platforms variants are available: - CrazyRadio PA via `make CRPA=y`. Provides LED heartbeat and debug LED. - CrazyRadio PA modified for Master SPI support via `make CRPA_MSPI=y` - Generic platform with no external IO and P0DIR set to all inputs. Built when a `make` invocation does not specify one of the above. IMPORTANT: Do not run the CRPA_MSPI firmware on an unmodified platform! This firmware requires that U2 is depopulated and that the pads for U2 pins 2 and 4 are jumpered together. This allows CSN to be used as an output connected to P2, pin 10. --- Makefile | 17 +++++-- readme.md | 25 ++++++++++- src/common.h | 24 ++++++++++ src/main.c | 23 ++++++++++ src/nRF24LU1P.h | 4 ++ src/platform.h | 44 ++++++++++++++++++ src/platforms/crpa.c | 93 +++++++++++++++++++++++++++++++++++++++ src/platforms/crpa.h | 42 ++++++++++++++++++ src/platforms/crpa_mspi.c | 66 +++++++++++++++++++++++++++ src/platforms/generic.c | 33 ++++++++++++++ src/radio.c | 50 ++++++++++++++++++++- src/usb.h | 4 ++ 12 files changed, 419 insertions(+), 6 deletions(-) create mode 100644 src/common.h create mode 100644 src/platform.h create mode 100644 src/platforms/crpa.c create mode 100644 src/platforms/crpa.h create mode 100644 src/platforms/crpa_mspi.c create mode 100644 src/platforms/generic.c diff --git a/Makefile b/Makefile index 69caa10..1cba543 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,20 @@ SDCC ?= sdcc -CFLAGS = --model-large --std-c99 +CFLAGS = --model-large --std-c99 -Isrc LDFLAGS = --xram-loc 0x8000 --xram-size 2048 --model-large VPATH = src/ OBJS = main.rel usb.rel usb_desc.rel radio.rel +ifeq ($(CRPA),y) + OBJS += platforms/crpa.rel +else ifeq ($(CRPA_MSPI),y) + OBJS += platforms/crpa_mspi.rel +else + OBJS += platforms/generic.rel +endif + SDCC_VER := $(shell $(SDCC) -v | grep -Po "\d\.\d\.\d" | sed "s/\.//g") -all: sdcc bin/ dongle.bin +all: sdcc bin/ bin/platforms/ dongle.bin sdcc: @if test $(SDCC_VER) -lt 310; then echo "Please update SDCC to 3.1.0 or newer."; exit 2; fi @@ -21,7 +29,7 @@ dongle.bin: $(OBJS) $(SDCC) $(CFLAGS) -c $< -o bin/$@ clean: - rm -f bin/* + rm -rf bin/* install: ./prog/usb-flasher/usb-flash.py bin/dongle.bin @@ -34,3 +42,6 @@ logitech_install: bin/: mkdir -p bin + +bin/platforms/: + mkdir -p bin/platforms/ diff --git a/readme.md b/readme.md index 1de643a..1abcccc 100644 --- a/readme.md +++ b/readme.md @@ -31,10 +31,33 @@ The following hardware has been tested and is known to work. ## Build the firmware +To build generic firmware without external peripheral/IO support: + ``` make ``` +To build firmware targeting the Bitcraze Crazyradio PA: + +``` +make CRPA=y +``` + +To build firmware targeting a Bitcraze Crazyradio PA modified to be +used as an SPI master (e.g., to use as a programmer): + +``` +make CRPA_MSPI=y +``` + +The above `CRPA_MSPI` firmware requires that U2 has been removed, +and that pins 2 and 4 of the U2 footprint are connected. This allows +the CSN pin to be used as an output. + +**IMPORTANT:** Using the `CRPA_MSPI` firmware on an unmodified device +may damage U2 or U3 due to contention over the CSN signal. + + ## Flash over USB nRF24LU1+ chips come with a factory programmed bootloader occupying the topmost 2KB of flash memory. The CrazyRadio firmware and RFStorm research firmware support USB commands to enter the Nordic bootloader. @@ -194,4 +217,4 @@ Transmit a continuous tone at 2405MHz ``` ./nrf24-continuous-tone-test.py -c 5 -``` \ No newline at end of file +``` diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..4621e1f --- /dev/null +++ b/src/common.h @@ -0,0 +1,24 @@ +/* + Copyright (C) 2016 Jon Szymaniak + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef MOUSEJACK_COMMON_H_ +#define MOUSEJACK_COMMON_H_ + +// Mark variable intentionally unused to silence associated warnings +#define UNUSED_PARAMETER(x) ((void) (x)) + +#endif diff --git a/src/main.c b/src/main.c index 57c8e25..b69b8a3 100644 --- a/src/main.c +++ b/src/main.c @@ -15,18 +15,27 @@ along with this program. If not, see . */ +#include #include "usb.h" #include "radio.h" +#include "platform.h" // Program entry point void main() { + uint8_t heartbeat = 1; + uint16_t heartbeat_count = 0; + rfcon = 0x06; // enable RF clock rfctl = 0x10; // enable SPI ien0 = 0x80; // enable interrupts TICKDV = 0xFF; // set the tick divider + // Perform platform-specific initializations + platform_init(); + platform_led_off(PLATFORM_LED_HEARTBEAT | PLATFORM_LED_DEBUG); + // Initialise and connect the USB controller init_usb(); @@ -40,6 +49,20 @@ void main() REGXH = 0xFF; REGXL = 0xFF; REGXC = 0x08; + + // 1s, 50% duty cycle heatbeat. + // This will appear slow down when processor is being kept busy in ISRs + if (++heartbeat_count == 500) { + if (heartbeat) { + platform_led_on(PLATFORM_LED_HEARTBEAT); + } else { + platform_led_off(PLATFORM_LED_HEARTBEAT); + } + + heartbeat ^= 1; + heartbeat_count = 0; + } + delay_us(1000); } } diff --git a/src/nRF24LU1P.h b/src/nRF24LU1P.h index c740e23..47c5ccf 100644 --- a/src/nRF24LU1P.h +++ b/src/nRF24LU1P.h @@ -40,6 +40,8 @@ __sfr __at (0x90) rfcon; // ref: nRF24LU1+ Product Spec, Section 6.5.1, __sfr __at (0xA0) usbcon; // ref: nRF24LU1+ Product Spec, Section 7.3, Table 24 __sfr __at (0x80) P0; // ref: nRF24LU1+ Product Spec, Section 13.1, Table 94 __sfr __at (0x94) P0DIR; // ref: nRF24LU1+ Product Spec, Section 13.1, Table 95 +__sfr __at (0x95) P0ALT; // ref: nRF24LU1+ Product Spec, Section 13.1, Table 96 +__sfr __at (0xC9) P0EXP; // ref: nRF24LU1+ Product Spec, Section 13.1, Table 97 __sfr __at (0xE5) RFDAT; // ref: nRF24LU1+ Product Spec, Section 15.1.2, Table 108 __sfr __at (0xAB) TICKDV; // ref: nRF24LU1+ Product Spec, Section 19.3.2, Table 128 __sfr __at (0xAB) REGXH; // ref: nRF24LU1+ Product Spec, Section 19.3.6, Table 129 @@ -47,6 +49,8 @@ __sfr __at (0xAC) REGXL; // ref: nRF24LU1+ Product Spec, Section 19.3.6 __sfr __at (0xAD) REGXC; // ref: nRF24LU1+ Product Spec, Section 19.3.6, Table 129 __sfr __at (0xA8) ien0; // ref: nRF24LU1+ Product Spec, Section 22.4.1, Table 139 __sfr __at (0xB8) ien1; // ref: nRF24LU1+ Product Spec, Section 22.4.2, Table 140 +__sfr __at (0xB2) SMDAT; // ref: nrf24lu1+ product spec, Section 9.2 +__sfr __at (0xB3) SMCTRL; // ref: nrf24lu1+ product spec, Section 9.2 // SFR bits __sbit __at (0x90) rfce; // ref: nRF24LU1+ Product Spec, Section 6.5.1, Table 21 diff --git a/src/platform.h b/src/platform.h new file mode 100644 index 0000000..76f68bf --- /dev/null +++ b/src/platform.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2016 Jon Szymaniak + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef MOUSEJACK_PLATFORM_H_ +#define MOUSEJACK_PLATFORM_H_ + +#include + +#define PLATFORM_LED_HEARTBEAT (1 << 0) +#define PLATFORM_LED_DEBUG (1 << 1) + +// Initialize platform-specific settings and I/O +void platform_init(); + +// Enable (true) or disable (false) external LN:s +void platform_enable_lna(bool enable); + +// Set the state of LEDs on the platform. A `1` bit is ON, a `0` bit is OFF. +void platform_led(uint8_t led_state); + +// Turn on the LEDs associated with a `1` bit the specified mask. +void platform_led_on(uint8_t led_mask); + +// Turn off the LEDs associated with a `1` bit the specified mask. +void platform_led_off(uint8_t led_mask); + +// Assert SPI Master chip select +void platform_assert_spi_master_cs(bool assert_cs); + +#endif diff --git a/src/platforms/crpa.c b/src/platforms/crpa.c new file mode 100644 index 0000000..a0ed512 --- /dev/null +++ b/src/platforms/crpa.c @@ -0,0 +1,93 @@ +/* + * Bitcraze CrazyRadio PA - Unmodified platform with LED support + * + * Copyright (C) 2016 Jon Szymaniak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +#include "nRF24LU1P.h" +#include "platform.h" +#include "common.h" +#include "crpa.h" + +void platform_init() +{ + /* These pins must always be inputs because they're connected to the output + * of U2 (noninverting buffer). + */ + P0DIR = (CRPA_P0_CSN | CRPA_P0_5); + P0 = 0; +} + +void platform_enable_lna(bool enable) +{ + crpa_enable_lna(enable); +} + +void platform_led(uint8_t leds) +{ + uint8_t p0_state = P0; + + if (leds & PLATFORM_LED_DEBUG) { + p0_state |= CRPA_P0_RED_LED2; + } else { + p0_state &= ~CRPA_P0_RED_LED2; + } + + if (leds & PLATFORM_LED_HEARTBEAT) { + p0_state |= CRPA_P0_GRN_LED1; + } else { + p0_state &= ~CRPA_P0_GRN_LED1; + } + + P0 = p0_state; +} + +void platform_led_on(uint8_t led_mask) +{ + uint8_t p0_state = P0; + + if (led_mask & PLATFORM_LED_DEBUG) { + p0_state |= CRPA_P0_RED_LED2; + } + + if (led_mask & PLATFORM_LED_HEARTBEAT) { + p0_state |= CRPA_P0_GRN_LED1; + } + + P0 = p0_state; +} + +void platform_led_off(uint8_t led_mask) +{ + uint8_t p0_state = P0; + + if (led_mask & PLATFORM_LED_DEBUG) { + p0_state &= ~CRPA_P0_RED_LED2; + } + + if (led_mask & PLATFORM_LED_HEARTBEAT) { + p0_state &= ~CRPA_P0_GRN_LED1; + } + + P0 = p0_state; +} + +// No SPI master support available in this build +void platform_assert_spi_master_cs(bool assert_cs) +{ + UNUSED_PARAMETER(assert_cs); +} diff --git a/src/platforms/crpa.h b/src/platforms/crpa.h new file mode 100644 index 0000000..277937c --- /dev/null +++ b/src/platforms/crpa.h @@ -0,0 +1,42 @@ +/* + * Bitcraze CrazyRadio PA common definitions + * + * Copyright (C) 2016 Jon Szymaniak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef CRPA_H_ +#define CRPA_H_ + +// P0 mappning +#define CRPA_P0_SCK (1 << 0) +#define CRPA_P0_MOSI (1 << 1) +#define CRPA_P0_MISO (1 << 2) +#define CRPA_P0_CSN (1 << 3) +#define CRPA_P0_RXEN (1 << 4) +#define CRPA_P0_5 (1 << 5) + +// LEDs are on SPI pins +#define CRPA_P0_GRN_LED1 CRPA_P0_SCK +#define CRPA_P0_RED_LED2 CRPA_P0_MISO + +#define crpa_enable_lna(enable_) do { \ + if (enable_) { \ + P0 |= CRPA_P0_RXEN; \ + } else { \ + P0 &= ~CRPA_P0_RXEN; \ + } \ +} while (0) + +#endif diff --git a/src/platforms/crpa_mspi.c b/src/platforms/crpa_mspi.c new file mode 100644 index 0000000..4049409 --- /dev/null +++ b/src/platforms/crpa_mspi.c @@ -0,0 +1,66 @@ +/* + * Modified Bitcraze CrazyRadio PA with SPI Master support + * + * IMPORTANT: This implementation assumes that U2 has been depopulated, and + * U2 pins 2 & 4 have been connected. Running this firmware on an + * unmodified CRPA may damage U2 and U3 (due to contention over + * the CSN line). + * + * + * Copyright (C) 2016 Jon Szymaniak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "nRF24LU1P.h" +#include "platform.h" +#include "common.h" +#include "crpa.h" + +void platform_init() +{ + // Configure pins for SPI Master functionality via P0EXP[0:1] = 01 + uint8_t p0exp_val = P0EXP & ~0x3; + P0EXP = p0exp_val | 0x01; + + // Enable SPI master + SMCTRL |= (1 << 4); + + // Mark MISO as input, just for safe measure. This may be implicit + // in configuring the pin for use as an SPI master pin. + // + // P0_5 is unused - set this as an input for lack of any other use. + P0DIR = (CRPA_P0_MISO | CRPA_P0_5); + + platform_assert_spi_master_cs(false); +} + +void platform_enable_lna(bool enable) +{ + crpa_enable_lna(enable); +} + +void platform_assert_spi_master_cs(bool assert_cs) +{ + if (assert_cs) { + P0 &= ~CRPA_P0_CSN; + } else { + P0 |= CRPA_P0_CSN; + } +} + +// Dummies - the LED pins are not available +void platform_led(uint8_t leds) { UNUSED_PARAMETER(leds); } +void platform_led_on(uint8_t led_mask) { UNUSED_PARAMETER(led_mask); } +void platform_led_off(uint8_t led_mask) { UNUSED_PARAMETER(led_mask); } diff --git a/src/platforms/generic.c b/src/platforms/generic.c new file mode 100644 index 0000000..033efd9 --- /dev/null +++ b/src/platforms/generic.c @@ -0,0 +1,33 @@ +/* + Copyright (C) 2016 Jon Szymaniak + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "nRF24LU1P.h" +#include "platform.h" +#include "common.h" + +// Generic platform support - no IO support +void platform_init() +{ + // Default to all pins as inpus + P0DIR = 0xff; +} + +void platform_enable_lna(bool enable) { UNUSED_PARAMETER(enable); } +void platform_led(uint8_t leds) { UNUSED_PARAMETER(leds); } +void platform_led_on(uint8_t led_mask) { UNUSED_PARAMETER(led_mask); } +void platform_led_off(uint8_t led_mask) { UNUSED_PARAMETER(led_mask); } +void platform_assert_spi_master_cs(bool assert) { UNUSED_PARAMETER(assert); } diff --git a/src/radio.c b/src/radio.c index 5e82cc1..ef887e5 100644 --- a/src/radio.c +++ b/src/radio.c @@ -4,6 +4,7 @@ #include "usb.h" #include "radio.h" #include "nRF24LU1P.h" +#include "platform.h" // Enter ESB promiscuous mode void enter_promiscuous_mode(uint8_t * prefix, uint8_t prefix_length) @@ -180,8 +181,7 @@ void handle_radio_request(uint8_t request, uint8_t * data) // Enable the LNA (CrazyRadio PA) else if(request == ENABLE_LNA) { - P0DIR &= ~0x10; - P0 |= 0x10; + platform_enable_lna(true); in1bc = 0; return; } @@ -565,5 +565,51 @@ void handle_radio_request(uint8_t request, uint8_t * data) rfce = 1; in1bc = 1; } + + else if (request == SPI_TRANSACTION) { + const bool assert_csn = (data[0] & 0x80) != 0; + const bool deassert_csn = (data[0] & 0x40) != 0; + const uint8_t len = (data[0] & 0x1f); + uint8_t i = 0; + + if (assert_csn) { + platform_assert_spi_master_cs(true); + } + + if (len != 0) { + for (i = 0; i < len; i++) + { + // A delay is used here because this request handling is already + // executing in an IRQ context; the MSDONE IRQ cannot be used to + // determine when data is ready in MISO. This is admittedly sloppy, + // but fixing this would require that the handling of all USB + // requests be deferred into main() rather than done in the IRQ + // context. + // + // Section 10.2 of the nRF24LU1+ manual appears to indicate + // that IRCON.2 can be polled when operating the device + // as an SPI slave in non-interrupt mode. However, attempting + // to poll this in Master SPI mode does not appear to work. + // Even with INTEXP configured to enable MSDONE, no change in + // INTCON.2 is observed. The manual does not appear to provide any + // indication of whether or not INTCON.2 can be for polled MSPI. + // + // The duration of this delay was deemed to be sufficient using + // a Bitcraze CrazyRadio PA - this delay may need to be adjusted + // on a per-platform basis, depending on the speed of the + // system clock. + // + SMDAT = data[i+1]; + delay_us(10); + in1buf[i] = SMDAT; + } + } + + if (deassert_csn) { + platform_assert_spi_master_cs(false); + } + + in1bc = len; + } } diff --git a/src/usb.h b/src/usb.h index 523cf6f..a9c1c0e 100644 --- a/src/usb.h +++ b/src/usb.h @@ -60,6 +60,7 @@ enum usb_request_type_t SET_CONFIGURATION = 9, }; + //Vendor control messages and commands #define TRANSMIT_PAYLOAD 0x04 #define ENTER_SNIFFER_MODE 0x05 @@ -72,5 +73,8 @@ enum usb_request_type_t #define TRANSMIT_PAYLOAD_GENERIC 0x0C #define ENTER_PROMISCUOUS_MODE_GENERIC 0x0D #define RECEIVE_PACKET 0x12 + +#define SPI_TRANSACTION 0x20 + #define LAUNCH_BOOTLOADER 0xFF From 914ed87f128c0dc203d391524ff1131cc0a5e9d4 Mon Sep 17 00:00:00 2001 From: Jon Szymaniak Date: Sun, 26 Jun 2016 22:57:40 -0400 Subject: [PATCH 4/4] tools: lib: Added SPI transaction function --- tools/lib/nrf24.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/lib/nrf24.py b/tools/lib/nrf24.py index 9b7c06f..fc6db73 100644 --- a/tools/lib/nrf24.py +++ b/tools/lib/nrf24.py @@ -45,6 +45,7 @@ TRANSMIT_PAYLOAD_GENERIC = 0x0C ENTER_PROMISCUOUS_MODE_GENERIC = 0x0D RECEIVE_PAYLOAD = 0x12 +SPI_TRANSACTION = 0x20 # nRF24LU1+ registers RF_CH = 0x05 @@ -143,6 +144,24 @@ def enable_lna(self): self.send_usb_command(ENABLE_LNA_PA, []) self.dongle.read(0x81, 64, timeout=nrf24.usb_timeout) + # Perform an SPI transfer + def spi_transaction(self, mosi_data, assert_csn=True, deassert_csn=True): + if len(mosi_data) >= 32: + raise ValueError("Input data exceeds 31 byte maximum"); + + control = len(mosi_data) & 0x1f + + if assert_csn: + control |= 0x80 + + if deassert_csn: + control |= 0x40 + + data = [control] + map(ord, mosi_data) + + self.send_usb_command(SPI_TRANSACTION, data); + return self.dongle.read(0x81, 64, timeout=nrf24.usb_timeout) + # Send a USB command def send_usb_command(self, request, data): data = [request] + list(data)