summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2018-11-29 22:40:46 +0100
committerChristian Pointner <equinox@spreadspace.org>2018-11-29 22:40:46 +0100
commitb9860ad78b65ef0bae80041ac1d3e187b6f180d3 (patch)
treec12190e2f95f6414efe4321ef45e6652a273fec0
parentsome cleanups (diff)
parentadded feather32u4lora board (diff)
Merge branch 'radiohead'
-rw-r--r--.gitignore4
-rw-r--r--contrib/Makefile30
-rw-r--r--contrib/radiohead.patch305
-rw-r--r--defines.mk14
-rw-r--r--include.mk64
-rw-r--r--lib/Arduino-SPI.cpp201
-rw-r--r--lib/Arduino-SPI.h324
-rw-r--r--lib/Arduino.h27
-rw-r--r--lib/arduino-stub.cpp285
-rw-r--r--lib/led.c4
-rw-r--r--lib/stdc++-minimal.cpp53
-rw-r--r--radiohead.mk55
-rw-r--r--rweather-crypto.mk44
-rw-r--r--usb-crypto/Makefile51
-rwxr-xr-xusb-crypto/decrypt.py36
-rw-r--r--usb-crypto/usb-crypto.cpp157
-rw-r--r--usb-lora-crypto/Makefile52
-rw-r--r--usb-lora-crypto/usb-lora-crypto.cpp118
-rw-r--r--usb-lora/Makefile50
-rw-r--r--usb-lora/usb-lora.cpp112
20 files changed, 1976 insertions, 10 deletions
diff --git a/.gitignore b/.gitignore
index af8d6f1..69a5435 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,10 @@ contrib/FastLED-*
contrib/PJON-*
contrib/BMP180-*
contrib/vusb-*
+contrib/RadioHead-*
+contrib/RadioHead/
+contrib/.rweather-crypto.prepared
+contrib/rweather-crypto
contrib/.teensy-loader.prepared
contrib/teensy_loader_cli
contrib/.micronucleus.prepared
diff --git a/contrib/Makefile b/contrib/Makefile
index 05fe264..37eba4f 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -26,8 +26,10 @@ LUFA_VERSION := 151115
FASTLED_VERSION := 3.1.0
PJON_VERSION := 3.0
VUSB_VERSION := 20121206
+RADIOHEAD_VERSION := 1.89
-all: download-lufa download-fastled download-pjon download-vusb update-teensy-loader update-micronucleus
+all: download-lufa download-fastled download-pjon download-vusb download-radiohead clone-rweather-crypto clone-teensy-loader clone-micronucleus
+update-all: update-rweather-crypto update-teensy-loader update-micronucleus
download-lufa: LUFA-${LUFA_VERSION}.zip
@@ -35,6 +37,7 @@ LUFA-${LUFA_VERSION}.zip:
wget "http://www.github.com/abcminiuser/lufa/archive/$@" -O "$@"
unzip $@
+
download-fastled: FastLED-${FASTLED_VERSION}.zip
FastLED-${FASTLED_VERSION}.zip:
@@ -49,22 +52,47 @@ PJON-${PJON_VERSION}.zip:
wget "https://github.com/gioblu/PJON/archive/${PJON_VERSION}.zip" -O "$@"
unzip $@
+
download-vusb: vusb-${VUSB_VERSION}.zip
vusb-${VUSB_VERSION}.zip:
wget "https://www.obdev.at/downloads/vusb/vusb-${VUSB_VERSION}.zip" -O "$@"
unzip $@
+
+download-radiohead: RadioHead-${RADIOHEAD_VERSION}.zip
+
+RadioHead-${RADIOHEAD_VERSION}.zip:
+ wget "http://www.airspayce.com/mikem/arduino/RadioHead/$@" -O "$@"
+ unzip $@
+ cd RadioHead; patch -p1 < ../radiohead.patch
+
+
+.rweather-crypto.prepared:
+ git clone https://github.com/rweather/arduinolibs.git rweather-crypto
+ touch $@
+
+clone-rweather-crypto: .rweather-crypto.prepared
+
+update-rweather-crypto: .rweather-crypto.prepared
+ cd rweather-crypto; git pull
+
+
.teensy-loader.prepared:
git clone https://github.com/PaulStoffregen/teensy_loader_cli.git
touch $@
+clone-teensy-loader: .teensy-loader.prepared
+
update-teensy-loader: .teensy-loader.prepared
cd teensy_loader_cli; git pull; make
+
.micronucleus.prepared:
git clone https://github.com/micronucleus/micronucleus/
touch $@
+clone-micronucleus: .micronucleus.prepared
+
update-micronucleus: .micronucleus.prepared
cd micronucleus/commandline; git pull; make
diff --git a/contrib/radiohead.patch b/contrib/radiohead.patch
new file mode 100644
index 0000000..1636f91
--- /dev/null
+++ b/contrib/radiohead.patch
@@ -0,0 +1,305 @@
+diff -Nur RadioHead-orig/RadioHead.h RadioHead/RadioHead.h
+--- RadioHead-orig/RadioHead.h 2018-11-15 11:40:24.000000000 +0100
++++ RadioHead/RadioHead.h 2018-11-28 23:58:44.998151593 +0100
+@@ -317,8 +317,6 @@
+ cd /tmp
+ mkdir RadioHead
+ cd RadioHead
+-cp /usr/local/projects/arduino/libraries/RadioHead/*.h .
+-cp /usr/local/projects/arduino/libraries/RadioHead/*.cpp .
+ cp /usr/local/projects/arduino/libraries/RadioHead/examples/cc110/cc110_client/cc110_client.pde application.cpp
+ \endcode
+ - Edit application.cpp and comment out any \#include <SPI.h> so it looks like:
+@@ -1283,11 +1281,14 @@
+ #elif (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
+ #include <avr/io.h>
+ #include <avr/interrupt.h>
++ #include <avr/pgmspace.h>
+ #include <util/delay.h>
+ #include <string.h>
+ #include <stdbool.h>
+ #define RH_HAVE_HARDWARE_SPI
+- #include <SPI.h>
++ #include <Arduino.h>
++ #include <Arduino-SPI.h>
++ #define RH_ATTACHINTERRUPT_TAKES_PIN_NUMBER
+
+ // For Steve Childress port to ARM M4 w/CMSIS with STM's Hardware Abstraction lib.
+ // See ArduinoWorkarounds.h (not supplied)
+diff -Nur RadioHead-orig/RHAEADDriver.cpp RadioHead/RHAEADDriver.cpp
+--- RadioHead-orig/RHAEADDriver.cpp 1970-01-01 01:00:00.000000000 +0100
++++ RadioHead/RHAEADDriver.cpp 2018-11-28 23:59:30.373774012 +0100
+@@ -0,0 +1,48 @@
++// RHAEADDriver.cpp
++//
++// Author: Philippe.Rochat'at'gmail.com
++// Contributed to the RadioHead project by the author
++// $Id: RHAEADDriver.cpp,v 1.4 2018/09/23 23:54:01 mikem Exp $
++
++#include <RHAEADDriver.h>
++#ifdef RH_ENABLE_ENCRYPTION_MODULE
++
++RHAEADDriver::RHAEADDriver(RHGenericDriver& driver, AuthenticatedCipher& aead)
++ : _driver(driver),
++ _aead(aead)
++{
++ _buffer = (uint8_t *)calloc(_driver.maxMessageLength(), sizeof(uint8_t));
++}
++
++bool RHAEADDriver::recv(uint8_t* buf, uint8_t* len)
++{
++ bool status = _driver.recv(_buffer, len);
++ if (status && buf && len) {
++ // TODO: implement this
++ }
++ return status;
++}
++
++bool RHAEADDriver::send(const uint8_t* data, uint8_t len)
++{
++ if (len > maxMessageLength())
++ return false;
++
++ bool status = true;
++ if (len == 0) // PassThru
++ return _driver.send(data, len);
++
++ uint8_t out_len = 0;
++ // TODO: implement this
++ return _driver.send(_buffer, out_len);
++}
++
++uint8_t RHAEADDriver::maxMessageLength()
++{
++ int driver_len = _driver.maxMessageLength();
++ // IV?
++ driver_len -= _aead.tagSize();
++ return driver_len;
++}
++
++#endif
+diff -Nur RadioHead-orig/RHAEADDriver.h RadioHead/RHAEADDriver.h
+--- RadioHead-orig/RHAEADDriver.h 1970-01-01 01:00:00.000000000 +0100
++++ RadioHead/RHAEADDriver.h 2018-11-28 23:59:09.441948151 +0100
+@@ -0,0 +1,221 @@
++// RHAEADDriver.h
++
++// Generic encryption and authentication layer that could use any driver
++// But will encrypt and authenticate all data.
++// Requires the Arduinolibs/Crypto library:
++// https://github.com/rweather/arduinolibs
++//
++// Author: Christain Pointner equinox'at'spreadspace.org
++// Contributed to the RadioHead project by the author
++
++#ifndef RHAEADDriver_h
++#define RHAEADDriver_h
++
++#include <RHGenericDriver.h>
++#ifdef RH_ENABLE_ENCRYPTION_MODULE
++#include <AuthenticatedCipher.h>
++
++/////////////////////////////////////////////////////////////////////
++/// \class RHAEADDriver RHAEADDriver <RHAEADDriver.h>
++/// \brief Virtual Driver to encrypt and authenticate data. Can be used with any other RadioHead driver.
++///
++/// This driver acts as a wrapper for any other RadioHead driver, adding encryption and authentication of
++/// messages that are passed to and from the actual radio driver. Only the message payload is encrypted but
++/// the to/from address or flags is part of the authenticated portion. Any of the authenticated-ciphers
++/// supported by ArduinoLibs Cryptographic Library http://rweather.github.io/arduinolibs/crypto.html may be used.
++///
++/// For successful communications, both sender and receiver must use the same cipher and the same key.
++///
++/// In order to enable this module you must uncomment #define RH_ENABLE_AEAD_MODULE at the bottom of RadioHead.h
++/// But ensure you have installed the Crypto directory from arduinolibs first:
++/// http://rweather.github.io/arduinolibs/index.html
++
++class RHAEADDriver : public RHGenericDriver
++{
++public:
++ /// Constructor.
++ /// Adds a ciphering layer to messages sent and received by the actual transport driver.
++ /// \param[in] driver The RadioHead driver to use to transport messages.
++ /// \param[in] blockcipher The blockcipher (from arduinolibs) that crypt/decrypt data. Ensure that
++ /// the blockcipher has had its key set before sending or receiving messages.
++ RHAEADDriver(RHGenericDriver& driver, AuthenticatedCipher& aead);
++
++ /// Calls the real driver's init()
++ /// \return The value returned from the driver init() method;
++ virtual bool init() { return _driver.init();};
++
++ /// Tests whether a new message is available
++ /// from the Driver.
++ /// On most drivers, this will also put the Driver into RHModeRx mode until
++ /// a message is actually received by the transport, when it wil be returned to RHModeIdle.
++ /// This can be called multiple times in a timeout loop
++ /// \return true if a new, complete, error-free uncollected message is available to be retreived by recv()
++ virtual bool available() { return _driver.available();};
++
++ /// Turns the receiver on if it not already on.
++ /// If there is a valid message available, copy it to buf and return true
++ /// else return false.
++ /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
++ /// You should be sure to call this function frequently enough to not miss any messages
++ /// It is recommended that you call it in your main loop.
++ /// \param[in] buf Location to copy the received message
++ /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
++ /// \return true if a valid message was copied to buf
++ virtual bool recv(uint8_t* buf, uint8_t* len);
++
++ /// Waits until any previous transmit packet is finished being transmitted with waitPacketSent().
++ /// Then optionally waits for Channel Activity Detection (CAD)
++ /// to show the channnel is clear (if the radio supports CAD) by calling waitCAD().
++ /// Then loads a message into the transmitter and starts the transmitter. Note that a message length
++ /// of 0 is permitted.
++ /// \param[in] data Array of data to be sent
++ /// \param[in] len Number of bytes of data to send
++ /// specify the maximum time in ms to wait. If 0 (the default) do not wait for CAD before transmitting.
++ /// \return true if the message length was valid and it was correctly queued for transmit. Return false
++ /// if CAD was requested and the CAD timeout timed out before clear channel was detected.
++ virtual bool send(const uint8_t* data, uint8_t len);
++
++ /// Returns the maximum message length
++ /// available in this Driver, which depends on the maximum length supported by the underlying transport driver.
++ /// \return The maximum legal message length
++ virtual uint8_t maxMessageLength();
++
++ /// Blocks until the transmitter
++ /// is no longer transmitting.
++ virtual bool waitPacketSent() { return _driver.waitPacketSent();} ;
++
++ /// Blocks until the transmitter is no longer transmitting.
++ /// or until the timeout occuers, whichever happens first
++ /// \param[in] timeout Maximum time to wait in milliseconds.
++ /// \return true if the radio completed transmission within the timeout period. False if it timed out.
++ virtual bool waitPacketSent(uint16_t timeout) {return _driver.waitPacketSent(timeout);} ;
++
++ /// Starts the receiver and blocks until a received message is available or a timeout
++ /// \param[in] timeout Maximum time to wait in milliseconds.
++ /// \return true if a message is available
++ virtual bool waitAvailableTimeout(uint16_t timeout) {return _driver.waitAvailableTimeout(timeout);};
++
++ /// Calls the waitCAD method in the driver
++ /// \return The return value from teh drivers waitCAD() method
++ virtual bool waitCAD() { return _driver.waitCAD();};
++
++ /// Sets the Channel Activity Detection timeout in milliseconds to be used by waitCAD().
++ /// The default is 0, which means do not wait for CAD detection.
++ /// CAD detection depends on support for isChannelActive() by your particular radio.
++ void setCADTimeout(unsigned long cad_timeout) {_driver.setCADTimeout(cad_timeout);};
++
++ /// Determine if the currently selected radio channel is active.
++ /// This is expected to be subclassed by specific radios to implement their Channel Activity Detection
++ /// if supported. If the radio does not support CAD, returns true immediately. If a RadioHead radio
++ /// supports isChannelActive() it will be documented in the radio specific documentation.
++ /// This is called automatically by waitCAD().
++ /// \return true if the radio-specific CAD (as returned by override of isChannelActive()) shows the
++ /// current radio channel as active, else false. If there is no radio-specific CAD, returns false.
++ virtual bool isChannelActive() { return _driver.isChannelActive();};
++
++ /// Sets the address of this node. Defaults to 0xFF. Subclasses or the user may want to change this.
++ /// This will be used to test the adddress in incoming messages. In non-promiscuous mode,
++ /// only messages with a TO header the same as thisAddress or the broadcast addess (0xFF) will be accepted.
++ /// In promiscuous mode, all messages will be accepted regardless of the TO header.
++ /// In a conventional multinode system, all nodes will have a unique address
++ /// (which you could store in EEPROM).
++ /// You would normally set the header FROM address to be the same as thisAddress (though you dont have to,
++ /// allowing the possibilty of address spoofing).
++ /// \param[in] thisAddress The address of this node.
++ virtual void setThisAddress(uint8_t thisAddress) { _driver.setThisAddress(thisAddress);};
++
++ /// Sets the TO header to be sent in all subsequent messages
++ /// \param[in] to The new TO header value
++ virtual void setHeaderTo(uint8_t to){ _driver.setHeaderTo(to);};
++
++ /// Sets the FROM header to be sent in all subsequent messages
++ /// \param[in] from The new FROM header value
++ virtual void setHeaderFrom(uint8_t from){ _driver.setHeaderFrom(from);};
++
++ /// Sets the ID header to be sent in all subsequent messages
++ /// \param[in] id The new ID header value
++ virtual void setHeaderId(uint8_t id){ _driver.setHeaderId(id);};
++
++ /// Sets and clears bits in the FLAGS header to be sent in all subsequent messages
++ /// First it clears he FLAGS according to the clear argument, then sets the flags according to the
++ /// set argument. The default for clear always clears the application specific flags.
++ /// \param[in] set bitmask of bits to be set. Flags are cleared with the clear mask before being set.
++ /// \param[in] clear bitmask of flags to clear. Defaults to RH_FLAGS_APPLICATION_SPECIFIC
++ /// which clears the application specific flags, resulting in new application specific flags
++ /// identical to the set.
++ virtual void setHeaderFlags(uint8_t set, uint8_t clear = RH_FLAGS_APPLICATION_SPECIFIC) { _driver.setHeaderFlags(set, clear);};
++
++ /// Tells the receiver to accept messages with any TO address, not just messages
++ /// addressed to thisAddress or the broadcast address
++ /// \param[in] promiscuous true if you wish to receive messages with any TO address
++ virtual void setPromiscuous(bool promiscuous){ _driver.setPromiscuous(promiscuous);};
++
++ /// Returns the TO header of the last received message
++ /// \return The TO header
++ virtual uint8_t headerTo() { return _driver.headerTo();};
++
++ /// Returns the FROM header of the last received message
++ /// \return The FROM header
++ virtual uint8_t headerFrom() { return _driver.headerFrom();};
++
++ /// Returns the ID header of the last received message
++ /// \return The ID header
++ virtual uint8_t headerId() { return _driver.headerId();};
++
++ /// Returns the FLAGS header of the last received message
++ /// \return The FLAGS header
++ virtual uint8_t headerFlags() { return _driver.headerFlags();};
++
++ /// Returns the most recent RSSI (Receiver Signal Strength Indicator).
++ /// Usually it is the RSSI of the last received message, which is measured when the preamble is received.
++ /// If you called readRssi() more recently, it will return that more recent value.
++ /// \return The most recent RSSI measurement in dBm.
++ int16_t lastRssi() { return _driver.lastRssi();};
++
++ /// Returns the operating mode of the library.
++ /// \return the current mode, one of RF69_MODE_*
++ RHMode mode() { return _driver.mode();};
++
++ /// Sets the operating mode of the transport.
++ void setMode(RHMode mode) { _driver.setMode(mode);};
++
++ /// Sets the transport hardware into low-power sleep mode
++ /// (if supported). May be overridden by specific drivers to initialte sleep mode.
++ /// If successful, the transport will stay in sleep mode until woken by
++ /// changing mode it idle, transmit or receive (eg by calling send(), recv(), available() etc)
++ /// \return true if sleep mode is supported by transport hardware and the RadioHead driver, and if sleep mode
++ /// was successfully entered. If sleep mode is not suported, return false.
++ virtual bool sleep() { return _driver.sleep();};
++
++ /// Returns the count of the number of bad received packets (ie packets with bad lengths, checksum etc)
++ /// which were rejected and not delivered to the application.
++ /// Caution: not all drivers can correctly report this count. Some underlying hardware only report
++ /// good packets.
++ /// \return The number of bad packets received.
++ virtual uint16_t rxBad() { return _driver.rxBad();};
++
++ /// Returns the count of the number of
++ /// good received packets
++ /// \return The number of good packets received.
++ virtual uint16_t rxGood() { return _driver.rxGood();};
++
++ /// Returns the count of the number of
++ /// packets successfully transmitted (though not necessarily received by the destination)
++ /// \return The number of packets successfully transmitted
++ virtual uint16_t txGood() { return _driver.txGood();};
++
++private:
++ /// The underlying transport river we are to use
++ RHGenericDriver& _driver;
++
++ /// The AuthenticatedCipher we are to use for encrypting/decrypting
++ AuthenticatedCipher& _aead;
++
++ /// Buffer to store encrypted/decrypted message
++ uint8_t* _buffer;
++};
++
++
++
++#endif
++#endif
diff --git a/defines.mk b/defines.mk
index cec3dd5..f04496f 100644
--- a/defines.mk
+++ b/defines.mk
@@ -145,6 +145,19 @@ ifeq ($(BOARD_TYPE),feather32u4)
PROG_TYPE := avr109
AVRDUDE_PORT := /dev/ttyACM0
LUFA_BOARD = NONE
+ ARDUINO_PINS = leonardo
+endif
+ifeq ($(BOARD_TYPE),feather32u4lora)
+ MCU := atmega32u4
+ ARCH = AVR8
+ F_CPU := 8000000
+ F_USB = $(F_CPU)
+ PROG := avrdude
+ UPLOAD_RATE := 57600
+ PROG_TYPE := avr109
+ AVRDUDE_PORT := /dev/ttyACM0
+ LUFA_BOARD = NONE
+ ARDUINO_PINS = leonardo
endif
ifeq ($(BOARD_TYPE),elecrow32u4lora)
MCU := atmega32u4
@@ -285,7 +298,6 @@ COMMON += -funsigned-char
COMMON += -funsigned-bitfields
COMMON += -fdata-sections
COMMON += -ffunction-sections
-COMMON += -fpack-struct
COMMON += -fshort-enums
COMMON += -Wall
COMMON += -I$(LIB_DIR)
diff --git a/include.mk b/include.mk
index f624fcc..d0f526e 100644
--- a/include.mk
+++ b/include.mk
@@ -41,7 +41,7 @@ CXX_OBJ_LIB := $(CXX_LIBS:%=lib-%.o)
CXX_SRC_LIB := $(CXX_LIBS:%=$(LIB_DIR)/%.cpp)
CXX_DEP_LIB := $(CXX_LIBS:%=lib-%.d)
-.PHONY: prepare clean clean-external distclean clean-lufa clean-fastled clean-pjon clean-vusb program erase flash reset run
+.PHONY: prepare clean clean-external distclean clean-lufa clean-fastled clean-pjon clean-vusb clean-radiohead clean-rweather-crypto program erase flash reset run
ELFFILE := $(NAME).elf
HEXFILE := $(NAME).hex
@@ -82,6 +82,22 @@ CFLAGS += -DUSES_VUSB
CFLAGS += $(VUSB_OPTS)
endif
+ifdef RADIOHEAD_PATH
+CXXFLAGS += -I$(RADIOHEAD_PATH)
+CXXFLAGS += -DUSES_RADIOHEAD
+CXXFLAGS += -DRH_PLATFORM=RH_PLATFORM_GENERIC_AVR8
+ifdef RWEATHER_CRYPTO_PATH
+CXXFLAGS += -DRH_ENABLE_ENCRYPTION_MODULE
+endif
+CXXFLAGS += $(RADIOHEAD_OPTS)
+endif
+
+ifdef RWEATHER_CRYPTO_PATH
+CXXFLAGS += -I$(RWEATHER_CRYPTO_PATH)/libraries/Crypto
+CXXFLAGS += -DUSES_RWEATHER_CRYPTO
+CXXFLAGS += $(RWEATHER_CRYPTO_OPTS)
+endif
+
prepare: $(EXTERNAL_LIBS:%=build-%)
clean-external: $(EXTERNAL_LIBS:%=clean-%)
@@ -179,6 +195,52 @@ clean-vusb:
@echo "****************************************************"
+build-radiohead: libradiohead.a
+
+libradiohead.a: Makefile
+ @echo ""
+ @echo "****************************************************"
+ @echo "building external RadioHead lib ($(RADIOHEAD_PATH))"
+ @echo ""
+ make -f $(SPREADAVR_PATH)/radiohead.mk libradiohead.a
+ make -f $(SPREADAVR_PATH)/radiohead.mk clean
+ @echo ""
+ @echo "****************************************************"
+
+clean-radiohead:
+ @echo ""
+ @echo "****************************************************"
+ @echo "cleaning external RadioHead lib ($(RADIOHEAD_PATH))"
+ @echo ""
+ make -f $(SPREADAVR_PATH)/radiohead.mk clean
+ rm -f libradiohead.a
+ @echo ""
+ @echo "****************************************************"
+
+
+build-rweather-crypto: librweather-crypto.a
+
+librweather-crypto.a: Makefile
+ @echo ""
+ @echo "****************************************************"
+ @echo "building external rweather/crypto lib ($(RWEATHER_CRYPTO_PATH))"
+ @echo ""
+ make -f $(SPREADAVR_PATH)/rweather-crypto.mk librweather-crypto.a
+ make -f $(SPREADAVR_PATH)/rweather-crypto.mk clean
+ @echo ""
+ @echo "****************************************************"
+
+clean-rweather-crypto:
+ @echo ""
+ @echo "****************************************************"
+ @echo "cleaning external rweather/crypto lib ($(RWEATHER_CRYPTO_PATH))"
+ @echo ""
+ make -f $(SPREADAVR_PATH)/rweather-crypto.mk clean
+ rm -f librweather-crypto.a
+ @echo ""
+ @echo "****************************************************"
+
+
## project-specific objects
%.d: %.c Makefile
@set -e; rm -f $@; \
diff --git a/lib/Arduino-SPI.cpp b/lib/Arduino-SPI.cpp
new file mode 100644
index 0000000..0a7ac91
--- /dev/null
+++ b/lib/Arduino-SPI.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
+ * Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
+ * Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
+ * Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
+ * SPI Master library for arduino.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#include "Arduino-SPI.h"
+
+SPIClass SPI;
+
+uint8_t SPIClass::initialized = 0;
+uint8_t SPIClass::interruptMode = 0;
+uint8_t SPIClass::interruptMask = 0;
+uint8_t SPIClass::interruptSave = 0;
+#ifdef SPI_TRANSACTION_MISMATCH_LED
+uint8_t SPIClass::inTransactionFlag = 0;
+#endif
+
+void SPIClass::begin()
+{
+ uint8_t sreg = SREG;
+ noInterrupts(); // Protect from a scheduler and prevent transactionBegin
+ if (!initialized) {
+ // Set SS to high so a connected chip will be "deselected" by default
+ uint8_t port = digitalPinToPort(SS);
+ uint8_t bit = digitalPinToBitMask(SS);
+ volatile uint8_t *reg = portModeRegister(port);
+
+ // if the SS pin is not already configured as an output
+ // then set it high (to enable the internal pull-up resistor)
+ if(!(*reg & bit)){
+ digitalWrite(SS, HIGH);
+ }
+
+ // When the SS pin is set as OUTPUT, it can be used as
+ // a general purpose output port (it doesn't influence
+ // SPI operations).
+ pinMode(SS, OUTPUT);
+
+ // Warning: if the SS pin ever becomes a LOW INPUT then SPI
+ // automatically switches to Slave, so the data direction of
+ // the SS pin MUST be kept as OUTPUT.
+ SPCR |= _BV(MSTR);
+ SPCR |= _BV(SPE);
+
+ // Set direction register for SCK and MOSI pin.
+ // MISO pin automatically overrides to INPUT.
+ // By doing this AFTER enabling SPI, we avoid accidentally
+ // clocking in a single bit since the lines go directly
+ // from "input" to SPI control.
+ // http://code.google.com/p/arduino/issues/detail?id=888
+ pinMode(SCK, OUTPUT);
+ pinMode(MOSI, OUTPUT);
+ }
+ initialized++; // reference count
+ SREG = sreg;
+}
+
+void SPIClass::end() {
+ uint8_t sreg = SREG;
+ noInterrupts(); // Protect from a scheduler and prevent transactionBegin
+ // Decrease the reference counter
+ if (initialized)
+ initialized--;
+ // If there are no more references disable SPI
+ if (!initialized) {
+ SPCR &= ~_BV(SPE);
+ interruptMode = 0;
+ #ifdef SPI_TRANSACTION_MISMATCH_LED
+ inTransactionFlag = 0;
+ #endif
+ }
+ SREG = sreg;
+}
+
+// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
+#if defined(__AVR_ATmega32U4__)
+ #define SPI_INT0_MASK (1<<INT0)
+ #define SPI_INT1_MASK (1<<INT1)
+ #define SPI_INT2_MASK (1<<INT2)
+ #define SPI_INT3_MASK (1<<INT3)
+ #define SPI_INT4_MASK (1<<INT6)
+#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
+ #define SPI_INT0_MASK (1<<INT0)
+ #define SPI_INT1_MASK (1<<INT1)
+ #define SPI_INT2_MASK (1<<INT2)
+ #define SPI_INT3_MASK (1<<INT3)
+ #define SPI_INT4_MASK (1<<INT4)
+ #define SPI_INT5_MASK (1<<INT5)
+ #define SPI_INT6_MASK (1<<INT6)
+ #define SPI_INT7_MASK (1<<INT7)
+#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
+ #define SPI_INT0_MASK (1<<INT4)
+ #define SPI_INT1_MASK (1<<INT5)
+ #define SPI_INT2_MASK (1<<INT0)
+ #define SPI_INT3_MASK (1<<INT1)
+ #define SPI_INT4_MASK (1<<INT2)
+ #define SPI_INT5_MASK (1<<INT3)
+ #define SPI_INT6_MASK (1<<INT6)
+ #define SPI_INT7_MASK (1<<INT7)
+#else
+ #ifdef INT0
+ #define SPI_INT0_MASK (1<<INT0)
+ #endif
+ #ifdef INT1
+ #define SPI_INT1_MASK (1<<INT1)
+ #endif
+ #ifdef INT2
+ #define SPI_INT2_MASK (1<<INT2)
+ #endif
+#endif
+
+void SPIClass::usingInterrupt(uint8_t interruptNumber)
+{
+ uint8_t mask = 0;
+ uint8_t sreg = SREG;
+ noInterrupts(); // Protect from a scheduler and prevent transactionBegin
+ switch (interruptNumber) {
+ #ifdef SPI_INT0_MASK
+ case 0: mask = SPI_INT0_MASK; break;
+ #endif
+ #ifdef SPI_INT1_MASK
+ case 1: mask = SPI_INT1_MASK; break;
+ #endif
+ #ifdef SPI_INT2_MASK
+ case 2: mask = SPI_INT2_MASK; break;
+ #endif
+ #ifdef SPI_INT3_MASK
+ case 3: mask = SPI_INT3_MASK; break;
+ #endif
+ #ifdef SPI_INT4_MASK
+ case 4: mask = SPI_INT4_MASK; break;
+ #endif
+ #ifdef SPI_INT5_MASK
+ case 5: mask = SPI_INT5_MASK; break;
+ #endif
+ #ifdef SPI_INT6_MASK
+ case 6: mask = SPI_INT6_MASK; break;
+ #endif
+ #ifdef SPI_INT7_MASK
+ case 7: mask = SPI_INT7_MASK; break;
+ #endif
+ default:
+ interruptMode = 2;
+ break;
+ }
+ interruptMask |= mask;
+ if (!interruptMode)
+ interruptMode = 1;
+ SREG = sreg;
+}
+
+void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
+{
+ // Once in mode 2 we can't go back to 0 without a proper reference count
+ if (interruptMode == 2)
+ return;
+ uint8_t mask = 0;
+ uint8_t sreg = SREG;
+ noInterrupts(); // Protect from a scheduler and prevent transactionBegin
+ switch (interruptNumber) {
+ #ifdef SPI_INT0_MASK
+ case 0: mask = SPI_INT0_MASK; break;
+ #endif
+ #ifdef SPI_INT1_MASK
+ case 1: mask = SPI_INT1_MASK; break;
+ #endif
+ #ifdef SPI_INT2_MASK
+ case 2: mask = SPI_INT2_MASK; break;
+ #endif
+ #ifdef SPI_INT3_MASK
+ case 3: mask = SPI_INT3_MASK; break;
+ #endif
+ #ifdef SPI_INT4_MASK
+ case 4: mask = SPI_INT4_MASK; break;
+ #endif
+ #ifdef SPI_INT5_MASK
+ case 5: mask = SPI_INT5_MASK; break;
+ #endif
+ #ifdef SPI_INT6_MASK
+ case 6: mask = SPI_INT6_MASK; break;
+ #endif
+ #ifdef SPI_INT7_MASK
+ case 7: mask = SPI_INT7_MASK; break;
+ #endif
+ default:
+ break;
+ // this case can't be reached
+ }
+ interruptMask &= ~mask;
+ if (!interruptMask)
+ interruptMode = 0;
+ SREG = sreg;
+}
diff --git a/lib/Arduino-SPI.h b/lib/Arduino-SPI.h
new file mode 100644
index 0000000..5206a09
--- /dev/null
+++ b/lib/Arduino-SPI.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
+ * Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
+ * Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
+ * Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
+ * SPI Master library for arduino.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _SPI_H_INCLUDED
+#define _SPI_H_INCLUDED
+
+#include <Arduino.h>
+
+// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
+// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
+#define SPI_HAS_TRANSACTION 1
+
+// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method
+#define SPI_HAS_NOTUSINGINTERRUPT 1
+
+// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version.
+// This way when there is a bug fix you can check this define to alert users
+// of your code if it uses better version of this library.
+// This also implies everything that SPI_HAS_TRANSACTION as documented above is
+// available too.
+#define SPI_ATOMIC_VERSION 1
+
+// Uncomment this line to add detection of mismatched begin/end transactions.
+// A mismatch occurs if other libraries fail to use SPI.endTransaction() for
+// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn
+// on if any mismatch is ever detected.
+//#define SPI_TRANSACTION_MISMATCH_LED 5
+
+#ifndef LSBFIRST
+#define LSBFIRST 0
+#endif
+#ifndef MSBFIRST
+#define MSBFIRST 1
+#endif
+
+#define SPI_CLOCK_DIV4 0x00
+#define SPI_CLOCK_DIV16 0x01
+#define SPI_CLOCK_DIV64 0x02
+#define SPI_CLOCK_DIV128 0x03
+#define SPI_CLOCK_DIV2 0x04
+#define SPI_CLOCK_DIV8 0x05
+#define SPI_CLOCK_DIV32 0x06
+
+#define SPI_MODE0 0x00
+#define SPI_MODE1 0x04
+#define SPI_MODE2 0x08
+#define SPI_MODE3 0x0C
+
+#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
+#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
+#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
+
+// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
+#if defined(EIMSK)
+ #define SPI_AVR_EIMSK EIMSK
+#elif defined(GICR)
+ #define SPI_AVR_EIMSK GICR
+#elif defined(GIMSK)
+ #define SPI_AVR_EIMSK GIMSK
+#endif
+
+class SPISettings {
+public:
+ SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
+ if (__builtin_constant_p(clock)) {
+ init_AlwaysInline(clock, bitOrder, dataMode);
+ } else {
+ init_MightInline(clock, bitOrder, dataMode);
+ }
+ }
+ SPISettings() {
+ init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
+ }
+private:
+ void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
+ init_AlwaysInline(clock, bitOrder, dataMode);
+ }
+ void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
+ __attribute__((__always_inline__)) {
+ // Clock settings are defined as follows. Note that this shows SPI2X
+ // inverted, so the bits form increasing numbers. Also note that
+ // fosc/64 appears twice
+ // SPR1 SPR0 ~SPI2X Freq
+ // 0 0 0 fosc/2
+ // 0 0 1 fosc/4
+ // 0 1 0 fosc/8
+ // 0 1 1 fosc/16
+ // 1 0 0 fosc/32
+ // 1 0 1 fosc/64
+ // 1 1 0 fosc/64
+ // 1 1 1 fosc/128
+
+ // We find the fastest clock that is less than or equal to the
+ // given clock rate. The clock divider that results in clock_setting
+ // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
+ // slowest (128 == 2 ^^ 7, so clock_div = 6).
+ uint8_t clockDiv;
+
+ // When the clock is known at compiletime, use this if-then-else
+ // cascade, which the compiler knows how to completely optimize
+ // away. When clock is not known, use a loop instead, which generates
+ // shorter code.
+ if (__builtin_constant_p(clock)) {
+ if (clock >= F_CPU / 2) {
+ clockDiv = 0;
+ } else if (clock >= F_CPU / 4) {
+ clockDiv = 1;
+ } else if (clock >= F_CPU / 8) {
+ clockDiv = 2;
+ } else if (clock >= F_CPU / 16) {
+ clockDiv = 3;
+ } else if (clock >= F_CPU / 32) {
+ clockDiv = 4;
+ } else if (clock >= F_CPU / 64) {
+ clockDiv = 5;
+ } else {
+ clockDiv = 6;
+ }
+ } else {
+ uint32_t clockSetting = F_CPU / 2;
+ clockDiv = 0;
+ while (clockDiv < 6 && clock < clockSetting) {
+ clockSetting /= 2;
+ clockDiv++;
+ }
+ }
+
+ // Compensate for the duplicate fosc/64
+ if (clockDiv == 6)
+ clockDiv = 7;
+
+ // Invert the SPI2X bit
+ clockDiv ^= 0x1;
+
+ // Pack into the SPISettings class
+ spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
+ (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
+ spsr = clockDiv & SPI_2XCLOCK_MASK;
+ }
+ uint8_t spcr;
+ uint8_t spsr;
+ friend class SPIClass;
+};
+
+
+class SPIClass {
+public:
+ // Initialize the SPI library
+ static void begin();
+
+ // If SPI is used from within an interrupt, this function registers
+ // that interrupt with the SPI library, so beginTransaction() can
+ // prevent conflicts. The input interruptNumber is the number used
+ // with attachInterrupt. If SPI is used from a different interrupt
+ // (eg, a timer), interruptNumber should be 255.
+ static void usingInterrupt(uint8_t interruptNumber);
+ // And this does the opposite.
+ static void notUsingInterrupt(uint8_t interruptNumber);
+ // Note: the usingInterrupt and notUsingInterrupt functions should
+ // not to be called from ISR context or inside a transaction.
+ // For details see:
+ // https://github.com/arduino/Arduino/pull/2381
+ // https://github.com/arduino/Arduino/pull/2449
+
+ // Before using SPI.transfer() or asserting chip select pins,
+ // this function is used to gain exclusive access to the SPI bus
+ // and configure the correct settings.
+ inline static void beginTransaction(SPISettings settings) {
+ if (interruptMode > 0) {
+ uint8_t sreg = SREG;
+ noInterrupts();
+
+ #ifdef SPI_AVR_EIMSK
+ if (interruptMode == 1) {
+ interruptSave = SPI_AVR_EIMSK;
+ SPI_AVR_EIMSK &= ~interruptMask;
+ SREG = sreg;
+ } else
+ #endif
+ {
+ interruptSave = sreg;
+ }
+ }
+
+ #ifdef SPI_TRANSACTION_MISMATCH_LED
+ if (inTransactionFlag) {
+ pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
+ digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
+ }
+ inTransactionFlag = 1;
+ #endif
+
+ SPCR = settings.spcr;
+ SPSR = settings.spsr;
+ }
+
+ // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
+ inline static uint8_t transfer(uint8_t data) {
+ SPDR = data;
+ /*
+ * The following NOP introduces a small delay that can prevent the wait
+ * loop form iterating when running at the maximum speed. This gives
+ * about 10% more speed, even if it seems counter-intuitive. At lower
+ * speeds it is unnoticed.
+ */
+ asm volatile("nop");
+ while (!(SPSR & _BV(SPIF))) ; // wait
+ return SPDR;
+ }
+ inline static uint16_t transfer16(uint16_t data) {
+ union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
+ in.val = data;
+ if (!(SPCR & _BV(DORD))) {
+ SPDR = in.msb;
+ asm volatile("nop"); // See transfer(uint8_t) function
+ while (!(SPSR & _BV(SPIF))) ;
+ out.msb = SPDR;
+ SPDR = in.lsb;
+ asm volatile("nop");
+ while (!(SPSR & _BV(SPIF))) ;
+ out.lsb = SPDR;
+ } else {
+ SPDR = in.lsb;
+ asm volatile("nop");
+ while (!(SPSR & _BV(SPIF))) ;
+ out.lsb = SPDR;
+ SPDR = in.msb;
+ asm volatile("nop");
+ while (!(SPSR & _BV(SPIF))) ;
+ out.msb = SPDR;
+ }
+ return out.val;
+ }
+ inline static void transfer(void *buf, size_t count) {
+ if (count == 0) return;
+ uint8_t *p = (uint8_t *)buf;
+ SPDR = *p;
+ while (--count > 0) {
+ uint8_t out = *(p + 1);
+ while (!(SPSR & _BV(SPIF))) ;
+ uint8_t in = SPDR;
+ SPDR = out;
+ *p++ = in;
+ }
+ while (!(SPSR & _BV(SPIF))) ;
+ *p = SPDR;
+ }
+ // After performing a group of transfers and releasing the chip select
+ // signal, this function allows others to access the SPI bus
+ inline static void endTransaction(void) {
+ #ifdef SPI_TRANSACTION_MISMATCH_LED
+ if (!inTransactionFlag) {
+ pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
+ digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
+ }
+ inTransactionFlag = 0;
+ #endif
+
+ if (interruptMode > 0) {
+ #ifdef SPI_AVR_EIMSK
+ uint8_t sreg = SREG;
+ #endif
+ noInterrupts();
+ #ifdef SPI_AVR_EIMSK
+ if (interruptMode == 1) {
+ SPI_AVR_EIMSK = interruptSave;
+ SREG = sreg;
+ } else
+ #endif
+ {
+ SREG = interruptSave;
+ }
+ }
+ }
+
+ // Disable the SPI bus
+ static void end();
+
+ // This function is deprecated. New applications should use
+ // beginTransaction() to configure SPI settings.
+ inline static void setBitOrder(uint8_t bitOrder) {
+ if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
+ else SPCR &= ~(_BV(DORD));
+ }
+ // This function is deprecated. New applications should use
+ // beginTransaction() to configure SPI settings.
+ inline static void setDataMode(uint8_t dataMode) {
+ SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
+ }
+ // This function is deprecated. New applications should use
+ // beginTransaction() to configure SPI settings.
+ inline static void setClockDivider(uint8_t clockDiv) {
+ SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
+ SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
+ }
+ // These undocumented functions should not be used. SPI.transfer()
+ // polls the hardware flag which is automatically cleared as the
+ // AVR responds to SPI's interrupt
+ inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
+ inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
+
+private:
+ static uint8_t initialized;
+ static uint8_t interruptMode; // 0=none, 1=mask, 2=global
+ static uint8_t interruptMask; // which interrupts to mask
+ static uint8_t interruptSave; // temp storage, to restore state
+ #ifdef SPI_TRANSACTION_MISMATCH_LED
+ static uint8_t inTransactionFlag;
+ #endif
+};
+
+extern SPIClass SPI;
+
+#endif
diff --git a/lib/Arduino.h b/lib/Arduino.h
index 3698392..ac7031d 100644
--- a/lib/Arduino.h
+++ b/lib/Arduino.h
@@ -143,8 +143,8 @@ void delayMicroseconds(unsigned int us);
// void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
// uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
-// void attachInterrupt(uint8_t, void (*)(void), int mode);
-// void detachInterrupt(uint8_t);
+void attachInterrupt(uint8_t, void (*)(void), int mode);
+void detachInterrupt(uint8_t);
// Get the bit location within the hardware port of the given virtual pin.
// This comes from the pins_*.c file for the active board configuration.
@@ -215,6 +215,29 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
#define TIMER5B 17
#define TIMER5C 18
+
+#define EXTERNAL_INT_0 0
+#define EXTERNAL_INT_1 1
+#define EXTERNAL_INT_2 2
+#define EXTERNAL_INT_3 3
+#define EXTERNAL_INT_4 4
+#define EXTERNAL_INT_5 5
+#define EXTERNAL_INT_6 6
+#define EXTERNAL_INT_7 7
+
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega128RFA1__) || defined(__AVR_ATmega256RFR2__) || \
+ defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)
+#define EXTERNAL_NUM_INTERRUPTS 8
+#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
+#define EXTERNAL_NUM_INTERRUPTS 3
+#elif defined(__AVR_ATmega32U4__)
+#define EXTERNAL_NUM_INTERRUPTS 5
+#else
+#define EXTERNAL_NUM_INTERRUPTS 2
+#endif
+
+typedef void (*voidFuncPtr)(void);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/lib/arduino-stub.cpp b/lib/arduino-stub.cpp
index d848e8d..38bc168 100644
--- a/lib/arduino-stub.cpp
+++ b/lib/arduino-stub.cpp
@@ -329,7 +329,7 @@ void init()
* real cooperative scheduler.
*/
static void __empty() {
- // Empty
+ // Empty
}
void yield(void) __attribute__ ((weak, alias("__empty")));
@@ -762,6 +762,287 @@ void analogWrite(uint8_t pin, int val)
}
// ******************
+// this is from Arduino's WInterrupts.c
+
+static void nothing(void) {
+}
+
+static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = {
+#if EXTERNAL_NUM_INTERRUPTS > 8
+ #warning There are more than 8 external interrupts. Some callbacks may not be initialized.
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 7
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 6
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 5
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 4
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 3
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 2
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 1
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 0
+ nothing,
+#endif
+};
+// volatile static voidFuncPtr twiIntFunc;
+
+void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
+ if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
+ intFunc[interruptNum] = userFunc;
+
+ // Configure the interrupt mode (trigger on low input, any change, rising
+ // edge, or falling edge). The mode constants were chosen to correspond
+ // to the configuration bits in the hardware register, so we simply shift
+ // the mode into place.
+
+ // Enable the interrupt.
+
+ switch (interruptNum) {
+#if defined(__AVR_ATmega32U4__)
+ // I hate doing this, but the register assignment differs between the 1280/2560
+ // and the 32U4. Since avrlib defines registers PCMSK1 and PCMSK2 that aren't
+ // even present on the 32U4 this is the only way to distinguish between them.
+ case 0:
+ EICRA = (EICRA & ~((1<<ISC00) | (1<<ISC01))) | (mode << ISC00);
+ EIMSK |= (1<<INT0);
+ break;
+ case 1:
+ EICRA = (EICRA & ~((1<<ISC10) | (1<<ISC11))) | (mode << ISC10);
+ EIMSK |= (1<<INT1);
+ break;
+ case 2:
+ EICRA = (EICRA & ~((1<<ISC20) | (1<<ISC21))) | (mode << ISC20);
+ EIMSK |= (1<<INT2);
+ break;
+ case 3:
+ EICRA = (EICRA & ~((1<<ISC30) | (1<<ISC31))) | (mode << ISC30);
+ EIMSK |= (1<<INT3);
+ break;
+ case 4:
+ EICRB = (EICRB & ~((1<<ISC60) | (1<<ISC61))) | (mode << ISC60);
+ EIMSK |= (1<<INT6);
+ break;
+#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
+ case 2:
+ EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
+ EIMSK |= (1 << INT0);
+ break;
+ case 3:
+ EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
+ EIMSK |= (1 << INT1);
+ break;
+ case 4:
+ EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
+ EIMSK |= (1 << INT2);
+ break;
+ case 5:
+ EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
+ EIMSK |= (1 << INT3);
+ break;
+ case 0:
+ EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
+ EIMSK |= (1 << INT4);
+ break;
+ case 1:
+ EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
+ EIMSK |= (1 << INT5);
+ break;
+ case 6:
+ EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
+ EIMSK |= (1 << INT6);
+ break;
+ case 7:
+ EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
+ EIMSK |= (1 << INT7);
+ break;
+#else
+ case 0:
+ #if defined(EICRA) && defined(ISC00) && defined(EIMSK)
+ EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
+ EIMSK |= (1 << INT0);
+ #elif defined(MCUCR) && defined(ISC00) && defined(GICR)
+ MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
+ GICR |= (1 << INT0);
+ #elif defined(MCUCR) && defined(ISC00) && defined(GIMSK)
+ MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
+ GIMSK |= (1 << INT0);
+ #else
+ #error attachInterrupt not finished for this CPU (case 0)
+ #endif
+ break;
+
+ case 1:
+ #if defined(EICRA) && defined(ISC10) && defined(ISC11) && defined(EIMSK)
+ EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
+ EIMSK |= (1 << INT1);
+ #elif defined(MCUCR) && defined(ISC10) && defined(ISC11) && defined(GICR)
+ MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
+ GICR |= (1 << INT1);
+ #elif defined(MCUCR) && defined(ISC10) && defined(GIMSK) && defined(GIMSK)
+ MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
+ GIMSK |= (1 << INT1);
+ #else
+ #warning attachInterrupt may need some more work for this cpu (case 1)
+ #endif
+ break;
+
+ case 2:
+ #if defined(EICRA) && defined(ISC20) && defined(ISC21) && defined(EIMSK)
+ EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
+ EIMSK |= (1 << INT2);
+ #elif defined(MCUCR) && defined(ISC20) && defined(ISC21) && defined(GICR)
+ MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
+ GICR |= (1 << INT2);
+ #elif defined(MCUCR) && defined(ISC20) && defined(GIMSK) && defined(GIMSK)
+ MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
+ GIMSK |= (1 << INT2);
+ #endif
+ break;
+#endif
+ }
+ }
+}
+
+void detachInterrupt(uint8_t interruptNum) {
+ if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
+ // Disable the interrupt. (We can't assume that interruptNum is equal
+ // to the number of the EIMSK bit to clear, as this isn't true on the
+ // ATmega8. There, INT0 is 6 and INT1 is 7.)
+ switch (interruptNum) {
+#if defined(__AVR_ATmega32U4__)
+ case 0:
+ EIMSK &= ~(1<<INT0);
+ break;
+ case 1:
+ EIMSK &= ~(1<<INT1);
+ break;
+ case 2:
+ EIMSK &= ~(1<<INT2);
+ break;
+ case 3:
+ EIMSK &= ~(1<<INT3);
+ break;
+ case 4:
+ EIMSK &= ~(1<<INT6);
+ break;
+#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
+ case 2:
+ EIMSK &= ~(1 << INT0);
+ break;
+ case 3:
+ EIMSK &= ~(1 << INT1);
+ break;
+ case 4:
+ EIMSK &= ~(1 << INT2);
+ break;
+ case 5:
+ EIMSK &= ~(1 << INT3);
+ break;
+ case 0:
+ EIMSK &= ~(1 << INT4);
+ break;
+ case 1:
+ EIMSK &= ~(1 << INT5);
+ break;
+ case 6:
+ EIMSK &= ~(1 << INT6);
+ break;
+ case 7:
+ EIMSK &= ~(1 << INT7);
+ break;
+#else
+ case 0:
+ #if defined(EIMSK) && defined(INT0)
+ EIMSK &= ~(1 << INT0);
+ #elif defined(GICR) && defined(ISC00)
+ GICR &= ~(1 << INT0); // atmega32
+ #elif defined(GIMSK) && defined(INT0)
+ GIMSK &= ~(1 << INT0);
+ #else
+ #error detachInterrupt not finished for this cpu
+ #endif
+ break;
+
+ case 1:
+ #if defined(EIMSK) && defined(INT1)
+ EIMSK &= ~(1 << INT1);
+ #elif defined(GICR) && defined(INT1)
+ GICR &= ~(1 << INT1); // atmega32
+ #elif defined(GIMSK) && defined(INT1)
+ GIMSK &= ~(1 << INT1);
+ #else
+ #warning detachInterrupt may need some more work for this cpu (case 1)
+ #endif
+ break;
+
+ case 2:
+ #if defined(EIMSK) && defined(INT2)
+ EIMSK &= ~(1 << INT2);
+ #elif defined(GICR) && defined(INT2)
+ GICR &= ~(1 << INT2); // atmega32
+ #elif defined(GIMSK) && defined(INT2)
+ GIMSK &= ~(1 << INT2);
+ #elif defined(INT2)
+ #warning detachInterrupt may need some more work for this cpu (case 2)
+ #endif
+ break;
+#endif
+ }
+
+ intFunc[interruptNum] = nothing;
+ }
+}
+
+#define IMPLEMENT_ISR(vect, interrupt) \
+ ISR(vect) { \
+ intFunc[interrupt](); \
+ }
+
+#if defined(__AVR_ATmega32U4__)
+
+IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
+IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
+IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
+IMPLEMENT_ISR(INT3_vect, EXTERNAL_INT_3)
+IMPLEMENT_ISR(INT6_vect, EXTERNAL_INT_4)
+
+#elif defined(EICRA) && defined(EICRB)
+
+IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_2)
+IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_3)
+IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_4)
+IMPLEMENT_ISR(INT3_vect, EXTERNAL_INT_5)
+IMPLEMENT_ISR(INT4_vect, EXTERNAL_INT_0)
+IMPLEMENT_ISR(INT5_vect, EXTERNAL_INT_1)
+IMPLEMENT_ISR(INT6_vect, EXTERNAL_INT_6)
+IMPLEMENT_ISR(INT7_vect, EXTERNAL_INT_7)
+
+#else
+
+IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
+IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
+
+#if defined(EICRA) && defined(ISC20)
+IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
+#endif
+
+#endif
+
+
+// ******************
// this is from Arduino's WMath.cpp
void randomSeed(unsigned long seed)
@@ -795,5 +1076,3 @@ long map(long x, long in_min, long in_max, long out_min, long out_max)
unsigned int makeWord(unsigned int w) { return w; }
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }
-
-// end WMath.cpp
diff --git a/lib/led.c b/lib/led.c
index 192eb68..3949623 100644
--- a/lib/led.c
+++ b/lib/led.c
@@ -29,7 +29,7 @@
#define NUM_LEDS 2
#elif defined(__BOARD_teensy1__) || defined(__BOARD_teensy1pp__) || defined(__BOARD_teensy2__) || defined(__BOARD_teensy2pp__) || \
defined(__BOARD_arduinoNano__) || defined(__BOARD_arduinoNG__) || defined(__BOARD_arduino2009v2__) || defined(__BOARD_arduino2009__) || \
- defined(__BOARD_arduino10000__) || defined(__BOARD_arduinoUno__) || defined(__BOARD_feather32u4__) || \
+ defined(__BOARD_arduino10000__) || defined(__BOARD_arduinoUno__) || defined(__BOARD_feather32u4__) || defined(__BOARD_feather32u4lora__) || \
defined(__BOARD_hhd70dongle__) || defined(__BOARD_rda1846dongle__) || defined(__BOARD_culV3__) || \
defined(__BOARD_slowpandongle1__) || defined(__BOARD_slowpandongle2__) || defined(__BOARD_teenstep__) || \
defined(__BOARD_rhmixxx__) || defined(__BOARD_digispark__) || defined(__BOARD_robotdynMega2560__)
@@ -62,7 +62,7 @@
#define LED2_PINNUM 6
#endif
-#if defined(__BOARD_feather32u4__)
+#if defined(__BOARD_feather32u4__) || defined(__BOARD_feather32u4lora__)
#define LED_PORT PORTC
#define LED_DDR DDRC
#define LED_PINNUM 7
diff --git a/lib/stdc++-minimal.cpp b/lib/stdc++-minimal.cpp
new file mode 100644
index 0000000..982719b
--- /dev/null
+++ b/lib/stdc++-minimal.cpp
@@ -0,0 +1,53 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2014-2018 Christian Pointner <equinox@spreadspace.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils 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
+ * any later version.
+ *
+ * spreadspace avr utils 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 spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "stdlib.h"
+#include "stdio.h"
+
+extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__));
+extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__));
+
+void __cxa_pure_virtual(void) {
+ // this only works with serialio, it won't work with usbio
+ // because we would need to call usbio_task() ...
+ printf("PANIC: __cxa_pure_virtual() got called ...\r\n");
+ for(;;);
+}
+
+void __cxa_deleted_virtual(void) {
+ // this only works with serialio, it won't work with usbio
+ // because we would need to call usbio_task() ...
+ printf("PANIC: __cxa_deleted_virtual() got called ...\r\n");
+ for(;;);
+}
+
+void * operator new(size_t n)
+{
+ void * const p = malloc(n);
+ // handle p == 0
+ return p;
+}
+
+void operator delete(void * p) // or delete(void *, std::size_t)
+{
+ free(p);
+}
diff --git a/radiohead.mk b/radiohead.mk
new file mode 100644
index 0000000..55fe943
--- /dev/null
+++ b/radiohead.mk
@@ -0,0 +1,55 @@
+##
+## spreadspace avr utils
+##
+##
+## Copyright (C) 2013-2018 Christian Pointner <equinox@spreadspace.org>
+##
+## This file is part of spreadspace avr utils.
+##
+## spreadspace avr utils 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
+## any later version.
+##
+## spreadspace avr utils 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 spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+##
+
+include $(SPREADAVR_PATH)/defines.mk
+
+ # TODO: add other components dependent on driver...
+RADIOHEAD_COMPONENTS := RH_$(RADIOHEAD_DRIVER) RHSPIDriver RHGenericDriver RHGenericSPI RHHardwareSPI
+
+CXXFLAGS += -I$(RADIOHEAD_PATH)
+CXXFLAGS += -DRH_PLATFORM=RH_PLATFORM_GENERIC_AVR8
+CXXFLAGS += $(RADIOHEAD_OPTS)
+
+ifdef RWEATHER_CRYPTO_PATH
+CXXFLAGS += -DRH_ENABLE_ENCRYPTION_MODULE
+CXXFLAGS += -I$(RWEATHER_CRYPTO_PATH)/libraries/Crypto
+CXXFLAGS += $(RWEATHER_CRYPTO_OPTS)
+RADIOHEAD_COMPONENTS += RHAEADDriver # RHEncryptedDriver
+endif
+
+SRC:=$(foreach COMP,$(RADIOHEAD_COMPONENTS),$(RADIOHEAD_PATH)/$(COMP).cpp)
+DEPLIBS := Arduino-SPI arduino-stub stdc++-minimal
+
+OBJ = $(SRC:%.cpp=%.o)
+OBJ_DEPLIB = $(DEPLIBS:%=deplib-radiohead--%.o)
+
+libradiohead.a: $(OBJ) $(OBJ_DEPLIB)
+ $(AR) $@ $(OBJ) $(OBJ_DEPLIB)
+
+%.o: %.cpp
+ $(CXX) -c $(CXXFLAGS) $< -o $@
+
+deplib-radiohead--%.o: $(LIB_DIR)/%.cpp
+ $(CXX) $(CXXFLAGS) -c $< -o $@
+
+clean:
+ rm -f $(SRC:%.cpp=%.o) $(OBJ_DEPLIB)
diff --git a/rweather-crypto.mk b/rweather-crypto.mk
new file mode 100644
index 0000000..1d39ecc
--- /dev/null
+++ b/rweather-crypto.mk
@@ -0,0 +1,44 @@
+##
+## spreadspace avr utils
+##
+##
+## Copyright (C) 2013-2016 Christian Pointner <equinox@spreadspace.org>
+##
+## This file is part of spreadspace avr utils.
+##
+## spreadspace avr utils 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
+## any later version.
+##
+## spreadspace avr utils 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 spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+##
+
+include $(SPREADAVR_PATH)/defines.mk
+
+SRC:=$(wildcard $(RWEATHER_CRYPTO_PATH)/libraries/Crypto/*.cpp)
+DEPLIBS := stdc++-minimal
+
+CXXFLAGS += -I$(RWEATHER_CRYPTO_PATH)/libraries/Crypto
+CXXFLAGS += $(RWEATHER_CRYPTO_OPTS)
+
+OBJ = $(SRC:%.cpp=%.o)
+OBJ_DEPLIB = $(DEPLIBS:%=deplib-rweather-crypto--%.o)
+
+librweather-crypto.a: $(OBJ) $(OBJ_DEPLIB)
+ $(AR) $@ $(OBJ) $(OBJ_DEPLIB)
+
+%.o: %.cpp
+ $(CXX) -c $(CXXFLAGS) $< -o $@
+
+deplib-rweather-crypto--%.o: $(LIB_DIR)/%.cpp
+ $(CXX) $(CXXFLAGS) -c $< -o $@
+
+clean:
+ rm -f $(SRC:%.cpp=%.o) $(OBJ_DEPLIB)
diff --git a/usb-crypto/Makefile b/usb-crypto/Makefile
new file mode 100644
index 0000000..bae846a
--- /dev/null
+++ b/usb-crypto/Makefile
@@ -0,0 +1,51 @@
+##
+## spreadspace avr utils
+##
+##
+## Copyright (C) 2013-2016 Christian Pointner <equinox@spreadspace.org>
+##
+## This file is part of spreadspace avr utils.
+##
+## spreadspace avr utils 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
+## any later version.
+##
+## spreadspace avr utils 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 spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+##
+
+NAME := usb-crypto
+BOARD_TYPE := teensy2
+CXX_OBJ := $(NAME).o
+LIBS := util led lufa-descriptor-usbserial usbio
+EXTERNAL_LIBS := lufa rweather-crypto
+SPREADAVR_PATH := ..
+RESET_FUNC := $(SPREADAVR_PATH)/tools/reset_lufa_cdc
+RESET_PARAM := 'r'
+
+LUFA_PATH := $(SPREADAVR_PATH)/contrib/lufa-LUFA-151115
+LUFA_OPTS = -D USB_DEVICE_ONLY
+LUFA_OPTS += -D DEVICE_STATE_AS_GPIOR=0
+LUFA_OPTS += -D ORDERED_EP_CONFIG
+LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8
+LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1
+LUFA_OPTS += -D USE_FLASH_DESCRIPTORS
+LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
+LUFA_OPTS += -D INTERRUPT_CONTROL_ENDPOINT
+
+LUFA_OPTS += -D USB_MANUFACTURER="L\"equinox\""
+LUFA_OPTS += -D USB_PRODUCT="L\"spreadspace usb-crypto example\""
+
+LUFA_COMPONENTS := USB USBCLASS
+
+
+RWEATHER_CRYPTO_PATH := $(SPREADAVR_PATH)/contrib/rweather-crypto
+
+
+include $(SPREADAVR_PATH)/include.mk
diff --git a/usb-crypto/decrypt.py b/usb-crypto/decrypt.py
new file mode 100755
index 0000000..7f7151a
--- /dev/null
+++ b/usb-crypto/decrypt.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+#
+# spreadspace avr utils
+#
+#
+# Copyright (C) 2013-2016 Christian Pointner <equinox@spreadspace.org>
+#
+# This file is part of spreadspace avr utils.
+#
+# spreadspace avr utils 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
+# any later version.
+#
+# spreadspace avr utils 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 spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import binascii
+from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
+
+hdr = "hello world!"
+body_enc = binascii.unhexlify("5535BB923FB4BDCA401D3AE05C85FF314BD22423FE339CD00259551AECA534FABBEB16B39CC9AC14DF")
+
+key = binascii.unhexlify("7043b69bde20446661ba579e83fda0830e3e61c95b5ac8deeb79973ba0df02d8")
+iv = binascii.unhexlify("6fac1c6a94a5788761cf9ecd")
+
+cipher = ChaCha20Poly1305(key)
+msg = cipher.decrypt(iv, body_enc, hdr)
+
+print(str(msg))
diff --git a/usb-crypto/usb-crypto.cpp b/usb-crypto/usb-crypto.cpp
new file mode 100644
index 0000000..0f7a9be
--- /dev/null
+++ b/usb-crypto/usb-crypto.cpp
@@ -0,0 +1,157 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013-2016 Christian Pointner <equinox@spreadspace.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils 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
+ * any later version.
+ *
+ * spreadspace avr utils 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 spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/io.h>
+#include <avr/wdt.h>
+#include <avr/interrupt.h>
+#include <avr/power.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "util.h"
+#include "led.h"
+#include "usbio.h"
+
+#include <Crypto.h>
+#include <ChaChaPoly.h>
+
+ChaChaPoly cipher;
+
+void print_hex_dump(const uint8_t* data, size_t len) {
+ for(size_t i=0; i<len; ++i) {
+ printf(" 0x%02X", data[i]);
+ if((i+1)%8 == 0) printf("\r\n");
+ }
+ printf("\r\n");
+}
+
+void run_crypto()
+{
+ printf("running encrypt/decrypt test using ChaCha20Poly1305:\r\n");
+
+ printf("\r\nencrypting...\r\n");
+ uint8_t hdr[] = "hello world!";
+ size_t hdr_len = sizeof(hdr)-1;
+ uint8_t body[] = "this is a secret message.";
+ size_t body_len = sizeof(body)-1;
+
+ uint8_t key[] = {0x70, 0x43, 0xb6, 0x9b, 0xde, 0x20, 0x44, 0x66,
+ 0x61, 0xba, 0x57, 0x9e, 0x83, 0xfd, 0xa0, 0x83,
+ 0x0e, 0x3e, 0x61, 0xc9, 0x5b, 0x5a, 0xc8, 0xde,
+ 0xeb, 0x79, 0x97, 0x3b, 0xa0, 0xdf, 0x02, 0xd8};
+
+ uint8_t iv[] = {0x6f, 0xac, 0x1c, 0x6a, 0x94, 0xa5, 0x78, 0x87,
+ 0x61, 0xcf, 0x9e, 0xcd};
+
+ uint8_t buf[256];
+ uint8_t tag[16];
+ memset(buf, 0, sizeof(buf));
+ memset(tag, 0, sizeof(tag));
+
+ led_on();
+ cipher.clear();
+ if(!cipher.setKey(key, sizeof(key))) {
+ printf("failed to set key\r\n");
+ return;
+ }
+ if(!cipher.setIV(iv, sizeof(iv))) {
+ printf("failed to set iv\r\n");
+ return;
+ }
+ led_off();
+
+ led_on();
+ cipher.addAuthData(hdr, hdr_len);
+ cipher.encrypt(buf, body, body_len);
+ cipher.computeTag(tag, sizeof(tag));
+ led_off();
+
+ printf("encrypted data (%d bytes):\r\n", body_len);
+ print_hex_dump(buf, body_len);
+ printf("\r\n");
+ printf("auth tag (%d bytes):\r\n", sizeof(tag));
+ print_hex_dump(tag, sizeof(tag));
+
+ printf("\r\ndecrypting...\r\n");
+ memcpy(body, buf, body_len);
+ memset(buf, 0, sizeof(buf));
+
+ led_on();
+ cipher.clear();
+ if(!cipher.setKey(key, sizeof(key))) {
+ printf("failed to set key\r\n");
+ return;
+ }
+ if(!cipher.setIV(iv, sizeof(iv))) {
+ printf("failed to set iv\r\n");
+ return;
+ }
+ led_off();
+
+ led_on();
+ cipher.addAuthData(hdr, hdr_len);
+ cipher.decrypt(buf, body, body_len);
+ bool ct = cipher.checkTag(tag, sizeof(tag));
+ led_off();
+
+ if(!ct) {
+ printf("auth tag mismatch!\r\n");
+ return;
+ } else {
+ printf("auth tag correct!\r\n");
+ }
+ printf("decrypted body: '%s'\r\n", buf);
+}
+
+void handle_cmd(uint8_t cmd)
+{
+ switch(cmd) {
+ case 'c': run_crypto(); break;
+ case 'r': reset2bootloader(); break;
+ default: printf("unknown command"); break;
+ }
+ printf("\r\n");
+}
+
+int main(void)
+{
+ MCUSR &= ~(1 << WDRF);
+ wdt_disable();
+
+ cpu_init();
+ led_init();
+ usbio_init();
+ sei();
+
+ for(;;) {
+ int16_t BytesReceived = usbio_bytes_received();
+ while(BytesReceived > 0) {
+ int ReceivedByte = fgetc(stdin);
+ if(ReceivedByte != EOF) {
+ handle_cmd(ReceivedByte);
+ }
+ BytesReceived--;
+ }
+
+ usbio_task();
+ }
+}
diff --git a/usb-lora-crypto/Makefile b/usb-lora-crypto/Makefile
new file mode 100644
index 0000000..0b61c94
--- /dev/null
+++ b/usb-lora-crypto/Makefile
@@ -0,0 +1,52 @@
+##
+## spreadspace avr utils
+##
+##
+## Copyright (C) 2013-2018 Christian Pointner <equinox@spreadspace.org>
+##
+## This file is part of spreadspace avr utils.
+##
+## spreadspace avr utils 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
+## any later version.
+##
+## spreadspace avr utils 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 spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+##
+
+NAME := usb-lora-crypto
+BOARD_TYPE := elecrow32u4lora
+CXX_OBJ := $(NAME).o
+LIBS := util led lufa-descriptor-usbserial usbio
+EXTERNAL_LIBS := lufa radiohead rweather-crypto
+SPREADAVR_PATH := ..
+
+LUFA_PATH := $(SPREADAVR_PATH)/contrib/lufa-LUFA-151115
+LUFA_OPTS = -D USB_DEVICE_ONLY
+LUFA_OPTS += -D DEVICE_STATE_AS_GPIOR=0
+LUFA_OPTS += -D ORDERED_EP_CONFIG
+LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8
+LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1
+LUFA_OPTS += -D USE_FLASH_DESCRIPTORS
+LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
+LUFA_OPTS += -D INTERRUPT_CONTROL_ENDPOINT
+
+LUFA_OPTS += -D USB_MANUFACTURER="L\"equinox\""
+LUFA_OPTS += -D USB_PRODUCT="L\"spreadspace usb-lora-crypto example\""
+
+LUFA_COMPONENTS := USB USBCLASS
+
+
+RADIOHEAD_PATH := $(SPREADAVR_PATH)/contrib/RadioHead
+
+RADIOHEAD_DRIVER := RF95
+
+RWEATHER_CRYPTO_PATH := $(SPREADAVR_PATH)/contrib/rweather-crypto
+
+include $(SPREADAVR_PATH)/include.mk
diff --git a/usb-lora-crypto/usb-lora-crypto.cpp b/usb-lora-crypto/usb-lora-crypto.cpp
new file mode 100644
index 0000000..3af1dcb
--- /dev/null
+++ b/usb-lora-crypto/usb-lora-crypto.cpp
@@ -0,0 +1,118 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013-2016 Christian Pointner <equinox@spreadspace.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils 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
+ * any later version.
+ *
+ * spreadspace avr utils 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 spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/io.h>
+#include <avr/wdt.h>
+#include <avr/interrupt.h>
+#include <avr/power.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "led.h"
+#include "usbio.h"
+
+#include "RadioHead.h"
+#include "RH_RF95.h"
+#include <Crypto.h>
+#include <ChaChaPoly.h>
+#include "RHAEADDriver.h"
+
+ChaChaPoly cipher;
+RH_RF95 lora;
+RHAEADDriver aead(lora, cipher);
+
+void recv_aead_msg()
+{
+ uint8_t buf[RH_RF95_MAX_MESSAGE_LEN+1];
+ uint8_t len = sizeof(buf)-1;
+
+ led2_on();
+ if(!aead.recv(buf, &len)) {
+ printf("aead.recv(): failed\r\n");
+ led2_off();
+ return;
+ }
+ buf[len] = 0;
+
+ printf("aead.recv() got message: RSSI = %d, data = ", aead.lastRssi());
+ for(uint8_t i = 0; i < len; ++i) printf("%s0x%02X", (i==0) ? "" : " ", buf[i]);
+ printf("\r\n");
+ // printf("aead.recv() got message: RSSI = %d, data = %s\r\n", aead.lastRssi(), buf);
+ led2_off();
+}
+
+void send_aead_msg()
+{
+ uint8_t data[] = "spreadspace.org/avr-utils usb-aead test using radiohead library";
+ printf("aead: sending message with %d bytes\r\n", sizeof(data));
+
+ led_on();
+ if(!aead.send(data, sizeof(data))) {
+ printf("aead.send(): failed\r\n");
+ led_off();
+ return;
+ }
+ aead.waitPacketSent();
+ printf("aead.send(): success\r\n");
+ led_off();
+}
+
+void handle_cmd(uint8_t cmd)
+{
+ switch(cmd) {
+ case 's': send_aead_msg(); break;
+ default: printf("error\r\n"); return;
+ }
+}
+
+int main(void)
+{
+ MCUSR &= ~(1 << WDRF);
+ wdt_disable();
+
+ cpu_init();
+ led_init();
+ usbio_init();
+ arduino_init();
+ sei();
+
+ lora.init();
+ lora.setFrequency(868.0);
+ aead.init();
+
+ for(;;) {
+ if(aead.available()) {
+ recv_aead_msg();
+ }
+
+ int16_t BytesReceived = usbio_bytes_received();
+ while(BytesReceived > 0) {
+ int ReceivedByte = fgetc(stdin);
+ if(ReceivedByte != EOF) {
+ handle_cmd(ReceivedByte);
+ }
+ BytesReceived--;
+ }
+
+ usbio_task();
+ }
+}
diff --git a/usb-lora/Makefile b/usb-lora/Makefile
new file mode 100644
index 0000000..8e2c751
--- /dev/null
+++ b/usb-lora/Makefile
@@ -0,0 +1,50 @@
+##
+## spreadspace avr utils
+##
+##
+## Copyright (C) 2013-2018 Christian Pointner <equinox@spreadspace.org>
+##
+## This file is part of spreadspace avr utils.
+##
+## spreadspace avr utils 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
+## any later version.
+##
+## spreadspace avr utils 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 spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+##
+
+NAME := usb-lora
+BOARD_TYPE := feather32u4lora
+CXX_OBJ := $(NAME).o
+LIBS := util led lufa-descriptor-usbserial usbio
+EXTERNAL_LIBS := lufa radiohead
+SPREADAVR_PATH := ..
+
+LUFA_PATH := $(SPREADAVR_PATH)/contrib/lufa-LUFA-151115
+LUFA_OPTS = -D USB_DEVICE_ONLY
+LUFA_OPTS += -D DEVICE_STATE_AS_GPIOR=0
+LUFA_OPTS += -D ORDERED_EP_CONFIG
+LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8
+LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1
+LUFA_OPTS += -D USE_FLASH_DESCRIPTORS
+LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
+LUFA_OPTS += -D INTERRUPT_CONTROL_ENDPOINT
+
+LUFA_OPTS += -D USB_MANUFACTURER="L\"equinox\""
+LUFA_OPTS += -D USB_PRODUCT="L\"spreadspace usb-lora example\""
+
+LUFA_COMPONENTS := USB USBCLASS
+
+
+RADIOHEAD_PATH := $(SPREADAVR_PATH)/contrib/RadioHead
+
+RADIOHEAD_DRIVER := RF95
+
+include $(SPREADAVR_PATH)/include.mk
diff --git a/usb-lora/usb-lora.cpp b/usb-lora/usb-lora.cpp
new file mode 100644
index 0000000..561f543
--- /dev/null
+++ b/usb-lora/usb-lora.cpp
@@ -0,0 +1,112 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2013-2016 Christian Pointner <equinox@spreadspace.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils 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
+ * any later version.
+ *
+ * spreadspace avr utils 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 spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/io.h>
+#include <avr/wdt.h>
+#include <avr/interrupt.h>
+#include <avr/power.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "led.h"
+#include "usbio.h"
+
+#include "RadioHead.h"
+#include "RH_RF95.h"
+
+RH_RF95 lora;
+
+void recv_lora_msg()
+{
+ uint8_t buf[RH_RF95_MAX_MESSAGE_LEN+1];
+ uint8_t len = sizeof(buf)-1;
+
+ led2_on();
+ if(!lora.recv(buf, &len)) {
+ printf("lora.recv(): failed\r\n");
+ led2_off();
+ return;
+ }
+ buf[len] = 0;
+
+ // printf("lora.recv() got message: SNR = %d, data = ", lora.lastSNR());
+ // for(uint8_t i = 0; i < len; ++i) printf("%s0x%02X", (i==0) ? "" : " ", buf[i]);
+ // printf("\r\n");
+ printf("lora.recv() got message: SNR = %d, data = %s\r\n", lora.lastSNR(), buf);
+ led2_off();
+}
+
+void send_lora_msg()
+{
+ uint8_t data[] = "spreadspace.org/avr-utils usb-lora test using radiohead library";
+ printf("lora: sending message with %d bytes\r\n", sizeof(data));
+
+ led_on();
+ if(!lora.send(data, sizeof(data))) {
+ printf("lora.send(): failed\r\n");
+ led_off();
+ return;
+ }
+ lora.waitPacketSent();
+ printf("lora.send(): success\r\n");
+ led_off();
+}
+
+void handle_cmd(uint8_t cmd)
+{
+ switch(cmd) {
+ case 's': send_lora_msg(); break;
+ default: printf("error\r\n"); return;
+ }
+}
+
+int main(void)
+{
+ MCUSR &= ~(1 << WDRF);
+ wdt_disable();
+
+ cpu_init();
+ led_init();
+ usbio_init();
+ arduino_init();
+ sei();
+
+ lora.init();
+ lora.setFrequency(868.0);
+
+ for(;;) {
+ if(lora.available()) {
+ recv_lora_msg();
+ }
+
+ int16_t BytesReceived = usbio_bytes_received();
+ while(BytesReceived > 0) {
+ int ReceivedByte = fgetc(stdin);
+ if(ReceivedByte != EOF) {
+ handle_cmd(ReceivedByte);
+ }
+ BytesReceived--;
+ }
+
+ usbio_task();
+ }
+}