diff --git a/.clang-format b/.clang-format deleted file mode 100644 index ae467aa..0000000 --- a/.clang-format +++ /dev/null @@ -1,6 +0,0 @@ ---- -# To see the actual lint settings that are being set by this file, run: -# clang-format -dump-config -Language: Cpp -BasedOnStyle: Google -... diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 6aed45a..0000000 --- a/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -* text=auto -*.c text -*.h text -*.cpp text diff --git a/.gitmodules b/.gitmodules index 7c7835e..03df9b8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "hardware/bean/avr/cores/bean/applicationMessageHeaders"] path = hardware/bean/avr/cores/bean/applicationMessageHeaders - url = https://bitbucket.org/punchthroughdesign/bean-application-message-definitions.git + url = git@bitbucket.org:punchthroughdesign/bean-application-message-definitions.git +[submodule "hardware/bean/avr/libraries/PinChangeInt"] + path = hardware/bean/avr/libraries/PinChangeInt + url = https://github.com/PunchThrough/PinChangeInt.git diff --git a/CPPLINT.cfg b/CPPLINT.cfg deleted file mode 100644 index 32c9161..0000000 --- a/CPPLINT.cfg +++ /dev/null @@ -1 +0,0 @@ -filter=-build/header_guard,-legal/copyright,-runtime/int,-readability/casting,-build/include \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index 967c29d..0000000 --- a/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -install: - brew install clang-format - pip install cpplint - -show: - tests/lint_all.py --show - -reformat: - tests/lint_all.py --reformat - -lint: - tests/lint_all.py --lint diff --git a/README.md b/README.md index 5a26cbf..fc13102 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,29 @@ -# [LightBlue Bean](https://punchthrough.com/bean) Arduino Library +Bean - A BLE Arduino By Punch Through Design +============================================= + +Repo Overview +------------- This repo contains the Arduino firmware and installation files used in the LightBlue Bean project. The firmware files are based off of the Arduino firmware release version 1.0.5 and have been modified to work on the LightBlue Bean, a system that has on it a few other features, a BLE radio an accelerometer and a multicolor LED. -# Reading and Setting Atmega Fuses with avrdude +### TODO: + +* Add note to this doc regarding FUSES (!! BOD) +* Fix Serial.println so, like Serial.print, extra radio messages arn't sent for the newline +* Add proper doxygen comments to relelvent parts, especially the API +* Add features to emulator to provide better, more useful testing +* Add more and better examples + +### Reading and Setting Atmega Fuses with avrdude + +We're going to need to set some fuses for our part in the factory. The fuse settings we need are going to set our part to basically should +match the Arduino Pro defaults with brownout disabled. + +At the time of writing, I don't have a programmer at my disposal. However the steps taken should be the +We write the fuse settings here: XX XX XX + +Steps: -We're going to need to set some fuses for our part in the factory. The fuse settings we need are going to set our part to basically should match the Arduino Pro defaults with brownout disabled. 1. Install avrdude. I used [http://www.obdev.at/products/crosspack/index.html](CrossPack) to do this. 1. Read the fuses from an off the shelf ArduinoPro. Use this command after avrdude is in your path: `avrdude -p atmega328p -c usbtiny -U lfuse:r:-:h -U hfuse:r:-:h -U efuse:r:-:h -U lock:r:-:h` @@ -13,21 +32,20 @@ We're going to need to set some fuses for our part in the factory. The fuse set 1. Calculate the new state of the fuses using the website, note for future (so no one else has to do these silly instructions) 1. Use avrdude to write and test your new fuse settings. The command line will look something like this (except, these are guessed values: `avrdude -p atmega328p -c usbtiny -U lfuse:w:0xee:m -U hfuse:w:0xdc:m -U efuse:w:0xff:m`) -# Key Files -## Everything in the `hardware` directory -The contents of the hardware directory should be copied into the Arduino program resources hardware directory on install. This directory contains the firmware for the LightBlue Bean, as well as the files needed for the Arduino IDE to recognize the board allow users to program it. +### Key Files: -## Everything in the `examples` directory +#### Everything in the `hardware` directory +The contents of the hardware directory should be copied into the Arduino program resources hardware directory on install. This directory contains the firmware for the LightBlue Bean, as well as the files needed for the Arduino IDE to recognize the board allow users to program it. +#### Everything in the `examples` directory The contents of the examples directory should be copied separately on install to the examples resources in the Arduino IDE. -## Everything in the `beanModuleEmulator` directory - +#### Everything in the `beanModuleEmulator` directory This directory contains an Emulator of the 'non-Arduino' parts of the bean. This acts as a test jig for the Arduino code, and allows us to verify that things operate as expected. You can run `python BeanModuleEmulator.py` from within the beanModuleEmulator directory. -# Dependencies +##### Dependencies There are a few python library dependencies you'll need to make the emulator work: @@ -38,86 +56,19 @@ There are a few python library dependencies you'll need to make the emulator wor The emulator has been tested with python 2.7.6 installed by Homebrew on OSX -# Development - +### Development: During development, it is recommended to use soft links from inside your Arduino IDE resources to your repository. It will make it easier to test your work. -# Repo Setup - -This repository uses git submodules and requires a few extra steps for cloning and pulling. - -## Clone - -``` -$ git clone REPO_URL --recursive -``` - -## Initialize Submodules - -(This is unnecessary if the recursive clone works) - -``` -$ git submodule update --init --recursive -``` - -## Pull - -``` -$ git pull -$ git submodule update --recursive -``` - -# Code Style and Quality +### Repo Setup: +This repository uses git submodules and requires a few extra steps for cloning and pulling. +#### Clone + git clone REPO_URL --recursive -Code in this repo should adhere to the [Google C++ Style Guide](https://google-styleguide.googlecode.com/svn/trunk/cppguide.html). +#### Initialize Submodules +######(This is unnecessary if the recursive clone works) + git submodule update --init --recursive -This repo comes with tools to ensure your code meets Punch Through C++ style guidelines. - -If code you submit for review does not fit our style guide, your pull request will fail our automated tests. Lint your code before submitting it to avoid this. - -## Installing Tools - -If you're running the reformatter or linter for the first time, run this first to install the tools: - -```sh -make install -``` - -## Auto-Reformat - -clang-format is set up to use the Google style guide. Reformatting your code will clean up many of the lint errors you might make. - -To reformat Bean files in this project: - -```sh -make reformat -``` - -clang-format uses the `.clang-format` file to set formatting style. See the [clang-format docs](http://clang.llvm.org/docs/ClangFormat.html) for more info. - -## Linting - -Our continuous integration server lints all code when it's submitted to a pull request. You can run the linter on your machine to make sure your code is up to this repo's standards. - -To lint Bean files for errors before committing: - -```sh -make lint -``` - -cpplint is configured in `CPPLINT.cfg`. See the [cpplint.py source](https://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py) for more info on configuration options and linter filters. - -## View List of Linted Files - -To see which files will be linted or reformatted: - -```sh -make show -``` - -# TODO - -* Fix Serial.println so, like Serial.print, extra radio messages aren't sent for the newline -* Add proper doxygen comments to relelvent parts, especially the API -* Add features to emulator to provide better, more useful testing -* Add more and better examples \ No newline at end of file +#### Pull + git pull + git submodule update --recursive + diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 6d754a7..0000000 --- a/circle.yml +++ /dev/null @@ -1,27 +0,0 @@ -machine: - python: - version: 2.7.10 - environment: - PLATFORMIO_CI_SRC: tests/resources/to_compile.ino - -checkout: - post: - - git submodule sync - - git submodule update --init - -dependencies: - cache_directories: - - ~/.platformio - override: - - pip install cpplint - # Installing PlatformIO with pip is kind of broken. Just use their install script. - - python -c "$(curl -fsSL https://raw.githubusercontent.com/platformio/platformio/master/scripts/get-platformio.py)" - - platformio platforms install atmelavr - - mkdir -p ~/.platformio/boards # -p: no error if cached /boards already exists - - cp tests/resources/platformio/boards/punchthrough.json ~/.platformio/boards/ - - cp -rvf hardware/bean/avr/* ~/.platformio/packages/framework-arduinoavr/ - -test: - override: - - tests/lint_all.py --lint - - platformio ci --board=lightblue-bean diff --git a/examples/LightBlueBean/01.Basics/AccelerometerEvent/AccelerometerEvent.ino b/examples/LightBlueBean/01.Basics/AccelerometerEvent/AccelerometerEvent.ino deleted file mode 100644 index 5da6cd9..0000000 --- a/examples/LightBlueBean/01.Basics/AccelerometerEvent/AccelerometerEvent.ino +++ /dev/null @@ -1,69 +0,0 @@ -/* - This sketch demonstrates the Bean's ability to detect motion events. - - In this demo we assign a unique LED color with each motion event. - The Bean's active LED color indicates what motion event it's waiting to detect. - After detecting the event, the sketch will cycle to the next color and wait for the next event. - - We start by waiting for "double tap" indicated by a red LED color - - - Double tap (Red) - - Single tap (Green) - - Any motion detected (Blue) - - Orientation change (Orange) - - High-g motion (Purple) - - Low-g (freefall) (Turquoise) - - Flat orientation (Off) - - Notes: - - This is not a low-power sketch because we are using the LED extensively. - Without LED use, this sketch is considered low-power. - - Bean.sleep() is interrupted by the action of an enabled event. - - Calling checkMotionEvent(someEvent) will return 'true' only if "someEvent" was - detected in the time since checkMotionEvent(someEvent) was last called. - - This example code is in the public domain. -*/ - -typedef struct{ - uint8_t event; - uint8_t red; - uint8_t green; - uint8_t blue; -}MotionEventState; - -int index = 0; -MotionEventState states[] = { - {DOUBLE_TAP_EVENT, 128, 0, 0 }, // Red - {SINGLE_TAP_EVENT, 0, 128, 0 }, // Green - {ANY_MOTION_EVENT, 0, 0, 128 }, // Blue - {ORIENT_EVENT, 64, 64, 0 }, // Orange - {HIGH_G_EVENT, 64, 0, 64 }, // Purple - {LOW_G_EVENT, 0, 64, 64 }, // Turquoise - {FLAT_EVENT, 0, 0, 0 } // Off -}; - - -void setup() { -} - -void loop() { - // Listen for this event - Bean.enableMotionEvent( states[index].event ); - - // Set the LED state to indicate which event the Bean is waiting for - Bean.setLed(states[index].red, states[index].green, states[index].blue); - - // Wait for the motion event in a low-power mode - while( Bean.checkMotionEvent( states[index].event ) == false ) - { - // Bean.sleep is interrupted by an enabled acclerometer event - Bean.sleep(10000); - } - - // Disable this event - Bean.disableMotionEvents(); - - // Move on to the next event - index = (index + 1) % 7; -} diff --git a/examples/LightBlueBean/01.Basics/AccelerometerLEDDemo/AccelerometerLEDDemo.ino b/examples/LightBlueBean/01.Basics/AccelerometerLEDDemo/AccelerometerLEDDemo.ino deleted file mode 100644 index a85b95a..0000000 --- a/examples/LightBlueBean/01.Basics/AccelerometerLEDDemo/AccelerometerLEDDemo.ino +++ /dev/null @@ -1,54 +0,0 @@ -#include "bma250.h" - -#define POLL_RATE 3000 -#define SUPAH_COUNTDOWN 5 - -uint16_t count; -uint16_t supah_sleep; - -void setup() { - // put your setup code here, to run once: - Serial.begin(); - Bean.accelerometerConfig(ENABLE_DOUBLE_TAP_INT | ENABLE_LOW_G_INT | ENABLE_ANY_MOTION_INT, VALUE_LOW_POWER_10MS); - Bean.enableWakeOnAccelerometer(WAKE_LOW_G_INT | WAKE_DOUBLE_TAP_INT); - count = 0; - supah_sleep = 10; -} - -void loop() { - // put your main code here, to run repeatedly: - Bean.sleep(POLL_RATE); - uint8_t status = Bean.checkAccelInterrupts(); - if (status > 0) { - supah_sleep = SUPAH_COUNTDOWN; - Bean.enableAdvertising(true); - } - if (status & CHECK_DOUBLE_TAP_INT) { - Bean.setLed(0xFF, 0x00, 0x00); - count = 3000 / POLL_RATE; // Hold for 5 seconds - } - else if (status & CHECK_LOW_G_INT) { - Bean.setLed(0x00, 0xFF, 0x00); - count = 3000 / POLL_RATE; // Hold for 5 seconds - } - else if ((status & CHECK_ANY_MOTION_INT) && (count == 0)) { - Bean.setLed(0x00, 0x00, 0xFF); - } - else if (count == 0) { - if (supah_sleep == 0) { - Bean.enableAdvertising(false); // Disable advertising - Bean.setLed(0xFF, 0xFF, 0xFF); // Flash the crowd - Bean.sleep(500); - Bean.setLed(0x00, 0x00, 0x00); - Bean.sleep(60000); // Sleep for a minute - } - else { - supah_sleep--; - Bean.setLed(0x00, 0x00, 0x00); - } - } - else if (count > 0) { - count--; - } -} - diff --git a/examples/LightBlueBean/01.Basics/ChangeInterrupts/ChangeInterrupts.ino b/examples/LightBlueBean/01.Basics/ChangeInterrupts/ChangeInterrupts.ino new file mode 100644 index 0000000..0c032ee --- /dev/null +++ b/examples/LightBlueBean/01.Basics/ChangeInterrupts/ChangeInterrupts.ino @@ -0,0 +1,70 @@ +#include + +/* + This sketch uses the Bean library to trigger interrupts when changes are detected on pins 0, 1, and 2. + + Notes: + - This is not a low-power sketch + - A Bean with a low battery might show a faint blue and green LED color + + This example code is in the public domain. +*/ + +volatile uint8_t red = 0; +volatile uint8_t green = 0; +volatile uint8_t blue = 0; + +// Interrupts are meant to be fast, avoid doing Bean.* operations directly within ISRs +// Set a flag and perform the desired operation within the superloop +void zeroChangeDetected( void ) +{ + red += 16; +} + +void oneChangeDetected( void ) +{ + green += 16; +} + +void twoChangeDetected( void ) +{ + blue += 16; +} + +void threeChangeDetected( void ) +{ + red = 0; +} + +void fourChangeDetected( void ) +{ + green = 0; +} + +void fiveChangeDetected( void ) +{ + blue = 0; +} + +void setup() { + pinMode(0, INPUT); + pinMode(1, INPUT); + pinMode(2, INPUT); + pinMode(3, INPUT); + pinMode(4, INPUT); + pinMode(5, INPUT); + attachPinChangeInterrupt(0, zeroChangeDetected, CHANGE); + attachPinChangeInterrupt(1, oneChangeDetected, CHANGE); + attachPinChangeInterrupt(2, twoChangeDetected, CHANGE); + attachPinChangeInterrupt(3, threeChangeDetected, CHANGE); + attachPinChangeInterrupt(4, fourChangeDetected, CHANGE); + attachPinChangeInterrupt(5, fiveChangeDetected, CHANGE); + Bean.setLed(0xFF, 0xFF, 0xFF); // Flash to show the sketch is running + Bean.sleep(250); +} + +void loop() { + // Set the Bean's LED based upon RGBs changed by interrupts + Bean.setLed(red, green, blue); + Bean.sleep(100); +} diff --git a/hardware/bean/avr/boards.txt b/hardware/bean/avr/boards.txt index b2eb504..95c9324 100644 --- a/hardware/bean/avr/boards.txt +++ b/hardware/bean/avr/boards.txt @@ -1,23 +1,11 @@ -bean.name=LightBlue Bean -bean.upload.tool=beanupload -bean.upload.protocol=ptdble -bean.upload.maximum_size=32256 -bean.upload.speed=57600 -bean.upload.params.verbose= -bean.build.mcu=atmega328p -bean.build.f_cpu=8000000L -bean.build.core=bean -bean.build.variant=bean -bean.build.board=AVR_UNO - -beanplus.name=LightBlue Bean+ -beanplus.upload.tool=beanupload -beanplus.upload.protocol=ptdble -beanplus.upload.maximum_size=32256 -beanplus.upload.speed=57600 -beanplus.upload.params.verbose= -beanplus.build.mcu=atmega328p -beanplus.build.f_cpu=16000000L -beanplus.build.core=bean -beanplus.build.variant=bean+ -beanplus.build.board=AVR_UNO +lightblue-bean.name=LightBlue Bean +lightblue-bean.upload.tool=beanupload +lightblue-bean.upload.protocol=ptdble +lightblue-bean.upload.maximum_size=32256 +lightblue-bean.upload.speed=57600 +lightblue-bean.upload.params.verbose= +lightblue-bean.build.mcu=atmega328p +lightblue-bean.build.f_cpu=8000000L +lightblue-bean.build.core=bean +lightblue-bean.build.variant=bean +lightblue-bean.build.board=AVR_UNO diff --git a/hardware/bean/avr/cores/bean/.gitignore b/hardware/bean/avr/cores/bean/.gitignore deleted file mode 100644 index 5e08acd..0000000 --- a/hardware/bean/avr/cores/bean/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea/ -CMakeLists.txt diff --git a/hardware/bean/avr/cores/bean/Bean.cpp b/hardware/bean/avr/cores/bean/Bean.cpp index 6346efe..c49c44a 100644 --- a/hardware/bean/avr/cores/bean/Bean.cpp +++ b/hardware/bean/avr/cores/bean/Bean.cpp @@ -1,388 +1,310 @@ #include "Bean.h" -#include "BeanHID.h" #include "Arduino.h" #include #include #include #include -#include #include "wiring_private.h" -#include "bma250.h" - -#ifndef sleep_bod_disable() // not included in Arduino AVR toolset -#define sleep_bod_disable() \ - do { \ - uint8_t tempreg; \ - __asm__ __volatile__( \ - "in %[tempreg], %[mcucr]" \ - "\n\t" \ - "ori %[tempreg], %[bods_bodse]" \ - "\n\t" \ - "out %[mcucr], %[tempreg]" \ - "\n\t" \ - "andi %[tempreg], %[not_bodse]" \ - "\n\t" \ - "out %[mcucr], %[tempreg]" \ - : [tempreg] "=&d"(tempreg) \ - : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ - [bods_bodse] "i"(_BV(BODS) | _BV(BODSE)), \ - [not_bodse] "i"(~_BV(BODSE))); \ - } while (0) + +#ifndef sleep_bod_disable() // not included in Arduino AVR toolset +#define sleep_bod_disable() \ +do { \ + uint8_t tempreg; \ + __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ + "ori %[tempreg], %[bods_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" "\n\t" \ + "andi %[tempreg], %[not_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" \ + : [tempreg] "=&d" (tempreg) \ + : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ + [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ + [not_bodse] "i" (~_BV(BODSE))); \ +} while (0) #endif #define MAX_SCRATCH_SIZE (20) #define NUM_BEAN_PINS 7 -static volatile voidFuncPtr intFunc; - -// midi access definitions -#define MIDI_BUFFER_SIZE 20 -#define BLE_PACKET_SIZE 20 - -typedef struct { - uint32_t timestamp; - uint8_t status; - uint8_t byte1; - uint8_t byte2; -} midiMessage; - -static midiMessage midiMessages[MIDI_BUFFER_SIZE]; -uint8_t midiPacket[BLE_PACKET_SIZE]; -uint8_t midiWriteOffset = 0; -uint8_t midiReadOffset = 0; - -// Pin change interrupt vectors - -// D0 -#ifndef PCINT2_vect -ISR(PCINT2_vect) { - if (intFunc) { - intFunc(); - } -} -#endif - -// Analog 0, Analog 1 -#ifndef PCINT1_vect -ISR(PCINT1_vect) { - if (intFunc) { - intFunc(); - } -} -#endif + BeanClass Bean; -// D1-D5 -#ifndef PCINT0_vect -ISR(PCINT0_vect) { - if (intFunc) { - intFunc(); + static void wakeUp(void){ + // Do nothing. + // This function is called as an interrupt purely to wake + // us up. + return; } -} -#endif - -BeanClass Bean; - -static void wakeUp(void) { - // Do nothing. - // This function is called as an interrupt purely to wake - // us up. - return; -} -#define MAX_SLEEP_POLL (30) -#define MAX_DELAY (30000) -#define MIN_SLEEP_TIME (10) + #define MAX_SLEEP_POLL (30) + #define MAX_DELAY (30000) + #define MIN_SLEEP_TIME (10) -void BeanClass::keepAwake(bool enable) { - lastStatus = 0; - midiTimeStampDiff = 0; - midiPacketBegin = true; - if (enable) { - Serial.BTConfigUartSleep(UART_SLEEP_NEVER); - } else { - Serial.BTConfigUartSleep(UART_SLEEP_NORMAL); + void BeanClass::keepAwake(bool enable) + { + if ( enable ) + { + Serial.BTConfigUartSleep(UART_SLEEP_NEVER); + } + else + { + Serial.BTConfigUartSleep(UART_SLEEP_NORMAL); + } } -} -bool BeanClass::attemptSleep(uint32_t duration_ms) { - // ensure that our interrupt line is an input - DDRD &= ~(_BV(3)); + bool BeanClass::attemptSleep( uint32_t duration_ms ) + { + // ensure that our interrupt line is an input + DDRD &= ~(_BV(3)); - bool sleepLineSet = false; - uint8_t pollCount = 0; + bool sleepLineSet = false; + uint8_t pollCount = 0; - // Send the sleep message to the TI and wait for it to - // finish sending. - Serial.sleep(duration_ms); - Serial.flush(); + // Send the sleep message to the TI and wait for it to + // finish sending. + Serial.sleep(duration_ms); + Serial.flush(); - while (sleepLineSet == false && pollCount++ < MAX_SLEEP_POLL) { - delay(1); - if ((PIND & _BV(3)) > 0) { - sleepLineSet = true; + while ( sleepLineSet == false && pollCount++ < MAX_SLEEP_POLL) + { + delay(1); + if ( ( PIND & _BV(3) ) > 0 ) + { + sleepLineSet = true; + } } + + return sleepLineSet; } - return sleepLineSet; -} + void BeanClass::enableConfigSave( bool enableSave ) + { + Serial.BTSetEnableConfigSave( enableSave ); + } -void BeanClass::enableConfigSave(bool enableSave) { - Serial.BTSetEnableConfigSave(enableSave); -} + void BeanClass::sleep(uint32_t duration_ms){ + // ensure that our interrupt line is an input + DDRD &= ~(_BV(3)); -void BeanClass::sleep(uint32_t duration_ms) { - // ensure that our interrupt line is an input - DDRD &= ~(_BV(3)); + Serial.BTConfigUartSleep(UART_SLEEP_NORMAL); - Serial.BTConfigUartSleep(UART_SLEEP_NORMAL); + // There's no point in sleeping if the duration is <= 10ms + if ( duration_ms < MIN_SLEEP_TIME ) + { + delay( duration_ms ); + return; + } - // There's no point in sleeping if the duration is <= 10ms - if (duration_ms < MIN_SLEEP_TIME) { - delay(duration_ms); - return; - } + // poll and wait for interrupt line to go HIGH (sleep) - // poll and wait for interrupt line to go HIGH (sleep) + // attempt sleep, if it fails, waited a total of 10ms + bool sleeping = false; - // attempt sleep, if it fails, waited a total of 10ms - bool sleeping = false; + sleeping = attemptSleep( duration_ms ); - sleeping = attemptSleep(duration_ms); + if ( !sleeping && duration_ms > MAX_DELAY ) + { + // keep trying until the end of delay period + while( duration_ms > 0 && false == sleeping ) + { + duration_ms = ( duration_ms >= MAX_SLEEP_POLL ) ? duration_ms - MAX_SLEEP_POLL : 0; + sleeping = attemptSleep( duration_ms ); + } + } + else if ( !sleeping && duration_ms > MAX_SLEEP_POLL ) + { + // take out the time we've already delayed + delay( duration_ms - MAX_SLEEP_POLL ); + sleeping = false; + } - if (!sleeping && duration_ms > MAX_DELAY) { - // keep trying until the end of delay period - while (duration_ms > 0 && false == sleeping) { - duration_ms = - (duration_ms >= MAX_SLEEP_POLL) ? duration_ms - MAX_SLEEP_POLL : 0; - sleeping = attemptSleep(duration_ms); + // if we never slept, don't set interrupts + if ( sleeping == false ) + { + return; } - } else if (!sleeping && duration_ms > MAX_SLEEP_POLL) { - // take out the time we've already delayed - delay(duration_ms - MAX_SLEEP_POLL); - sleeping = false; - } - // if we never slept, don't set interrupts - if (sleeping == false) { - return; - } + // set our interrupt pin to input: + const int interruptNum = 1; - // set our interrupt pin to input: - const int interruptNum = 1; + bool adc_was_set = bit_is_set(ADCSRA, ADEN); + if(adc_was_set){ + // disable ADC + ADCSRA &= ~(_BV(ADEN)); + } - bool adc_was_set = bit_is_set(ADCSRA, ADEN); - if (adc_was_set) { - // disable ADC - ADCSRA &= ~(_BV(ADEN)); - } + bool ac_was_set = bit_is_set(ACSR, ACD); + if(ac_was_set){ + // disable ADC + ACSR &= ~(_BV(ACD)); + } - bool ac_was_set = bit_is_set(ACSR, ACD); - if (ac_was_set) { - // disable ADC - ACSR &= ~(_BV(ACD)); - } - // Details on how to manage sleep mode with AVR gotten from the avr-libc - // manual, found here: - // http://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html - // (block quote below) - - // Note that unless your purpose is to completely lock the CPU (until a - // hardware reset), interrupts need to be enabled before going to sleep. - - // As the sleep_mode() macro might cause race conditions in some situations, - // the individual steps of manipulating the sleep enable (SE) bit, and - // actually issuing the SLEEP instruction, are provided in the macros - // sleep_enable(), sleep_disable(), and sleep_cpu(). This also allows for - // test-and-sleep scenarios that take care of not missing the interrupt - // that will awake the device from sleep. - - // Example: - - // #include - // #include - - // ... - // set_sleep_mode(); - // cli(); - // if (some_condition) - // { - // sleep_enable(); - // sei(); - // sleep_cpu(); - // sleep_disable(); - // } - // sei(); - // This sequence ensures an atomic test of some_condition with interrupts - // being disabled. If the condition is met, sleep mode will be prepared, - // and the SLEEP instruction will be scheduled immediately after an SEI - // instruction. As the intruction right after the SEI is guaranteed to be - // executed before an interrupt could trigger, it is sure the device will - // really be put to sleep. - - // Some devices have the ability to disable the Brown Out Detector (BOD) - // before going to sleep. This will also reduce power while sleeping. - // If the specific AVR device has this ability then an additional macro - // is defined: sleep_bod_disable(). This macro generates inlined assembly - // code that will correctly implement the timed sequence for disabling the - // BOD before sleeping. However, there is a limited number of cycles after - // the BOD has been disabled that the device can be put into sleep mode, - // otherwise the BOD will not truly be disabled. Recommended practice is - // to disable the BOD (sleep_bod_disable()), set the interrupts (sei()), - // and then put the device to sleep (sleep_cpu()), like so: - - // #include - // #include - - // ... - // set_sleep_mode(); - // cli(); - // if (some_condition) - // { - // sleep_enable(); - // sleep_bod_disable(); - // sei(); - // sleep_cpu(); - // sleep_disable(); - // } - // sei(); - - /* In the function call attachInterrupt(A, B, C) - * A can be either 0 or 1 for interrupts on pin 2 or 3. - * - * B Name of a function you want to execute at interrupt for A. - * - * C Trigger mode of the interrupt pin. can be: - * LOW a low level triggers - * CHANGE a change in level triggers - * RISING a rising edge of a level triggers - * FALLING a falling edge of a level triggers - * - * In all but the IDLE sleep modes only LOW can be used. - */ - attachInterrupt(interruptNum, wakeUp, LOW); - set_sleep_mode(SLEEP_MODE_PWR_DOWN); - cli(); - if (bit_is_set(PIND, 3)) { - sleep_enable(); - sleep_bod_disable(); + // Details on how to manage sleep mode with AVR gotten from the avr-libc + // manual, found here: http://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html + // (block quote below) + + // Note that unless your purpose is to completely lock the CPU (until a + // hardware reset), interrupts need to be enabled before going to sleep. + + // As the sleep_mode() macro might cause race conditions in some situations, + // the individual steps of manipulating the sleep enable (SE) bit, and + // actually issuing the SLEEP instruction, are provided in the macros + // sleep_enable(), sleep_disable(), and sleep_cpu(). This also allows for + // test-and-sleep scenarios that take care of not missing the interrupt + // that will awake the device from sleep. + + // Example: + + // #include + // #include + + // ... + // set_sleep_mode(); + // cli(); + // if (some_condition) + // { + // sleep_enable(); + // sei(); + // sleep_cpu(); + // sleep_disable(); + // } + // sei(); + // This sequence ensures an atomic test of some_condition with interrupts + // being disabled. If the condition is met, sleep mode will be prepared, + // and the SLEEP instruction will be scheduled immediately after an SEI + // instruction. As the intruction right after the SEI is guaranteed to be + // executed before an interrupt could trigger, it is sure the device will + // really be put to sleep. + + // Some devices have the ability to disable the Brown Out Detector (BOD) + // before going to sleep. This will also reduce power while sleeping. + // If the specific AVR device has this ability then an additional macro + // is defined: sleep_bod_disable(). This macro generates inlined assembly + // code that will correctly implement the timed sequence for disabling the + // BOD before sleeping. However, there is a limited number of cycles after + // the BOD has been disabled that the device can be put into sleep mode, + // otherwise the BOD will not truly be disabled. Recommended practice is + // to disable the BOD (sleep_bod_disable()), set the interrupts (sei()), + // and then put the device to sleep (sleep_cpu()), like so: + + // #include + // #include + + // ... + // set_sleep_mode(); + // cli(); + // if (some_condition) + // { + // sleep_enable(); + // sleep_bod_disable(); + // sei(); + // sleep_cpu(); + // sleep_disable(); + // } + // sei(); + + + /* In the function call attachInterrupt(A, B, C) + * A can be either 0 or 1 for interrupts on pin 2 or 3. + * + * B Name of a function you want to execute at interrupt for A. + * + * C Trigger mode of the interrupt pin. can be: + * LOW a low level triggers + * CHANGE a change in level triggers + * RISING a rising edge of a level triggers + * FALLING a falling edge of a level triggers + * + * In all but the IDLE sleep modes only LOW can be used. + */ + attachInterrupt(interruptNum,wakeUp, LOW); + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + cli(); + if (bit_is_set(PIND, 3)) + { + sleep_enable(); + sleep_bod_disable(); + sei(); + sleep_cpu(); + sleep_disable(); + } sei(); - sleep_cpu(); - sleep_disable(); - } - sei(); - detachInterrupt(interruptNum); + detachInterrupt(interruptNum); - if (adc_was_set) { - // re-enable adc - ADCSRA |= _BV(ADEN); - } + if(adc_was_set){ + //re-enable adc + ADCSRA |= _BV(ADEN); + } - if (ac_was_set) { - // re-enable analog compareter - ACSR |= _BV(ACD); - } + if(ac_was_set){ + //re-enable analog compareter + ACSR |= _BV(ACD); + } } -void BeanClass::attachChangeInterrupt(uint8_t pin, void (*userFunc)(void)) { - switch (pin) { - case 0: - PCICR |= _BV(PCIE2); - PCMSK2 |= _BV(PCINT22); - break; - case 1: - PCICR |= _BV(PCIE0); - PCMSK0 |= _BV(PCINT1); - break; - case 2: - PCICR |= _BV(PCIE0); - PCMSK0 |= _BV(PCINT2); - break; - case 3: - PCICR |= _BV(PCIE0); - PCMSK0 |= _BV(PCINT3); - break; - case 4: - PCICR |= _BV(PCIE0); - PCMSK0 |= _BV(PCINT4); - break; - case 5: - PCICR |= _BV(PCIE0); - PCMSK0 |= _BV(PCINT5); - break; - - default: - break; - } + uint16_t BeanClass::getAccelerationX(void){ + ACC_READING_T reading; + if(Serial.accelRead(&reading) == 0){ + return reading.xAxis; + } - intFunc = userFunc; -} + // TODO + // this is an error state. Is it worth a few retries? + return 0; + } -void BeanClass::detachChangeInterrupt(uint8_t pin) { - switch (pin) { - case 0: - PCICR &= ~_BV(PCIE2); - PCMSK2 &= ~_BV(PCINT22); - break; - case 1: - PCICR &= ~_BV(PCIE0); - PCMSK0 &= ~_BV(PCINT1); - break; - case 2: - PCICR &= ~_BV(PCIE0); - PCMSK0 &= ~_BV(PCINT2); - break; - case 3: - PCICR &= ~_BV(PCIE0); - PCMSK0 &= ~_BV(PCINT3); - break; - case 4: - PCICR &= ~_BV(PCIE0); - PCMSK0 &= ~_BV(PCINT4); - break; - case 5: - PCICR &= ~_BV(PCIE0); - PCMSK0 &= ~_BV(PCINT5); - break; - - default: - break; + uint8_t BeanClass::getAccelerationRange( void ) + { + uint8_t range = 0; + if (Serial.accelRangeRead(&range) == 0) + { + return range; + } } - intFunc = NULL; -} + void BeanClass::setAccelerationRange( uint8_t range ) + { + Serial.accelRangeSet( range ); + } -void BeanClass::setAdvertisingInterval(uint16_t interval_ms) { - Serial.BTSetAdvertisingInterval(interval_ms); +void BeanClass::setAdvertisingInterval( uint16_t interval_ms ) +{ + Serial.BTSetAdvertisingInterval( interval_ms ); } -void BeanClass::enableAdvertising(bool enable, uint32_t timer) { - Serial.BTSetAdvertisingOnOff(enable, timer); +void BeanClass::enableAdvertising( bool enable, uint32_t timer ) +{ + Serial.BTSetAdvertisingOnOff( enable, timer ); } -void BeanClass::enableAdvertising(bool enable) { - Serial.BTSetAdvertisingOnOff(enable, 0); +void BeanClass::enableAdvertising( bool enable ) +{ + Serial.BTSetAdvertisingOnOff( enable, 0 ); } -bool BeanClass::getConnectionState(void) { +bool BeanClass::getConnectionState( void ) +{ BT_STATES_T btStates; - if (Serial.BTGetStates(&btStates) == 0) { - return (bool)btStates.conn_state; - } + if(Serial.BTGetStates(&btStates)== 0) + { + return (bool)btStates.conn_state; + } return 0; } -bool BeanClass::getAdvertisingState(void) { +bool BeanClass::getAdvertisingState( void ) +{ BT_STATES_T btStates; - if (Serial.BTGetStates(&btStates) == 0) { - return (bool)btStates.adv_state; - } + if(Serial.BTGetStates(&btStates)== 0) + { + return (bool)btStates.adv_state; + } return 0; } -int8_t BeanClass::getTemperature(void) { +int8_t BeanClass::getTemperature(void) +{ int8_t temp = 0; Serial.temperatureRead(&temp); @@ -390,7 +312,8 @@ int8_t BeanClass::getTemperature(void) { return temp; } -uint8_t BeanClass::getBatteryLevel(void) { +uint8_t BeanClass::getBatteryLevel(void) +{ uint8_t level = 0; Serial.batteryRead(&level); @@ -398,7 +321,8 @@ uint8_t BeanClass::getBatteryLevel(void) { return level; } -uint16_t BeanClass::getBatteryVoltage(void) { +uint16_t BeanClass::getBatteryVoltage(void) +{ uint32_t actualVoltage = 0; uint8_t level = 0; @@ -408,546 +332,232 @@ uint16_t BeanClass::getBatteryVoltage(void) { // The conversion function from voltage to level is as follows: // f(x) = x * (63.53) - 124.26 // - // solve for voltage and you get the function below, including fixed-point - // scaling + // solve for voltage and you get the function below, including fixed-point scaling // with two decimal points of precision - actualVoltage = - (((uint32_t)100 * (uint32_t)level + (uint32_t)12426) * (uint32_t)100) / - 6353; + actualVoltage = (((uint32_t)100 * (uint32_t)level + (uint32_t)12426 ) * (uint32_t)100 ) / 6353; return (uint16_t)actualVoltage; } -void BeanClass::accelRegisterWrite(uint8_t reg, uint8_t value) { - Serial.accelRegisterWrite(reg, value); -} - -int BeanClass::accelRegisterRead(uint8_t reg, uint8_t length, uint8_t *value) { - return Serial.accelRegisterRead(reg, length, value); -} - -void BeanClass::setAccelerometerPowerMode(uint8_t mode) { - Serial.accelRegisterWrite(REG_POWER_MODE_X11, mode); -} - -uint8_t BeanClass::getAccelerometerPowerMode() { - uint8_t value; - Serial.accelRegisterRead(REG_POWER_MODE_X11, 1, &value); - return value; -} - -void BeanClass::enableWakeOnAccelerometer(uint8_t sources) { - Serial.accelRegisterWrite(REG_LATCH_CFG_X21, VALUE_TEMPORARY_250MS); - Serial.accelRegisterWrite(REG_INT_MAPPING_X19, sources); - Serial.wakeOnAccel(1); -} - -uint8_t BeanClass::getAccelerationRange(void) { - uint8_t value; - Serial.accelRegisterRead(REG_G_SETTING, 1, &value); - return value; -} - -void BeanClass::setAccelerationRange(uint8_t range) { - Serial.accelRegisterWrite(REG_G_SETTING, range); -} + uint16_t BeanClass::getAccelerationY(void){ + ACC_READING_T reading; + if(Serial.accelRead(&reading) == 0){ + return reading.yAxis; + } -int16_t BeanClass::getAccelerationX(void) { - ACC_READING_T reading; - Serial.accelRead(&reading); - return reading.xAxis; -} + // TODO + // this is an error state. Is it worth a few retries? + return 0; + } -int16_t BeanClass::getAccelerationY(void) { - ACC_READING_T reading; - Serial.accelRead(&reading); - return reading.yAxis; -} -int16_t BeanClass::getAccelerationZ(void) { - ACC_READING_T reading; - Serial.accelRead(&reading); - return reading.zAxis; -} + uint16_t BeanClass::getAccelerationZ(void){ + ACC_READING_T reading; + if(Serial.accelRead(&reading) == 0){ + return reading.zAxis; + } -ACC_READING_T BeanClass::getAcceleration(void) { - ACC_READING_T reading; - Serial.accelRead(&reading); - return reading; -} + // TODO + // this is an error state. Is it worth a few retries? + return 0; + } -static uint8_t enabledEvents = 0x00; -static uint8_t triggeredEvents = 0x00; -void BeanClass::enableMotionEvent(uint8_t events) { - uint16_t enableRegister = 0x0000; - uint8_t wakeRegister = 0x00; - enabledEvents |= events; + ACC_READING_T BeanClass::getAcceleration(void){ + ACC_READING_T reading; + if(Serial.accelRead(&reading) == 0){ + return reading; + } - if (enabledEvents & FLAT_EVENT) { - enableRegister |= ENABLE_FLAT_INT; - wakeRegister |= WAKE_FLAT_INT; + // TODO + // this is an error state. Is it worth a few retries? + memset(&reading, 0, sizeof(reading)); + return reading; } - if (enabledEvents & ORIENT_EVENT) { - enableRegister |= ENABLE_ORIENT_INT; - wakeRegister |= WAKE_ORIENT_INT; - } + void BeanClass::setLedRed(uint8_t intensity){ + LED_IND_SETTING_T setting; + setting.color = (uint8_t) LED_RED; + setting.intensity = intensity; - if (enabledEvents & SINGLE_TAP_EVENT) { - enableRegister |= ENABLE_SINGLE_TAP_INT; - wakeRegister |= WAKE_SINGLE_TAP_INT; + Serial.ledSetSingle(setting); } - if (enabledEvents & DOUBLE_TAP_EVENT) { - enableRegister |= ENABLE_DOUBLE_TAP_INT; - wakeRegister |= WAKE_DOUBLE_TAP_INT; - } + void BeanClass::setLedGreen(uint8_t intensity){ + LED_IND_SETTING_T setting; + setting.color = (uint8_t) LED_GREEN; + setting.intensity = intensity; - if (enabledEvents & ANY_MOTION_EVENT) { - enableRegister |= ENABLE_ANY_MOTION_INT; - wakeRegister |= WAKE_ANY_MOTION_INT; + Serial.ledSetSingle(setting); } + void BeanClass::setLedBlue(uint8_t intensity){ + LED_IND_SETTING_T setting; + setting.color = (uint8_t) LED_BLUE; + setting.intensity = intensity; - if (enabledEvents & HIGH_G_EVENT) { - enableRegister |= - (ENABLE_HIGH_G_Z_INT | ENABLE_HIGH_G_Y_INT | ENABLE_HIGH_G_X_INT); - wakeRegister |= WAKE_HIGH_G_INT; + Serial.ledSetSingle(setting); } - if (enabledEvents & LOW_G_EVENT) { - enableRegister |= ENABLE_LOW_G_INT; - wakeRegister |= WAKE_LOW_G_INT; + void BeanClass::setLed(uint8_t red, uint8_t green, uint8_t blue){ + LED_SETTING_T setting = {red, green, blue}; + Serial.ledSet(setting); } - // Clear triggered event flags for newly enabled events - triggeredEvents &= ~events; - accelerometerConfig(enableRegister, VALUE_LOW_POWER_10MS); - enableWakeOnAccelerometer(wakeRegister); -} - -void BeanClass::disableMotionEvents() { - enabledEvents = 0; - accelerometerConfig(0, VALUE_LOW_POWER_1S); -} - -// This function returns true if any one of the "events" param had been -// triggered -// It clears all corresponding "events" flags -bool BeanClass::checkMotionEvent(uint8_t events) { - triggeredEvents |= checkAccelInterrupts(); + uint8_t BeanClass::getLedRed(void){ + LED_SETTING_T reading; - bool eventOccurred = (triggeredEvents & events) ? true : false; - triggeredEvents &= ~events; - - return eventOccurred; -} - -void BeanClass::accelerometerConfig(uint16_t interrupts, uint8_t power_mode) { - Serial.accelRegisterWrite(REG_POWER_MODE_X11, power_mode); - Serial.accelRegisterWrite(REG_LATCH_CFG_X21, VALUE_LATCHED); - Serial.accelRegisterWrite(REG_INT_SETTING_X16, (uint8_t)(interrupts >> 8)); - Serial.accelRegisterWrite(REG_INT_SETTING_X17, (uint8_t)(interrupts & 0xFF)); -} - -uint8_t BeanClass::checkAccelInterrupts() { - uint8_t value; - uint8_t latch_cfg; - Serial.accelRegisterRead(REG_INT_STATUS_X09, 2, &value); - Serial.accelRegisterRead(REG_LATCH_CFG_X21, 1, &latch_cfg); - latch_cfg |= MASK_RESET_INT_LATCH; - Serial.accelRegisterWrite(REG_LATCH_CFG_X21, latch_cfg); - return value; -} - -void BeanClass::setLedRed(uint8_t intensity) { - LED_IND_SETTING_T setting; - setting.color = (uint8_t)LED_RED; - setting.intensity = intensity; - - Serial.ledSetSingle(setting); -} - -void BeanClass::setLedGreen(uint8_t intensity) { - LED_IND_SETTING_T setting; - setting.color = (uint8_t)LED_GREEN; - setting.intensity = intensity; - - Serial.ledSetSingle(setting); -} - -void BeanClass::setLedBlue(uint8_t intensity) { - LED_IND_SETTING_T setting; - setting.color = (uint8_t)LED_BLUE; - setting.intensity = intensity; - - Serial.ledSetSingle(setting); -} - -void BeanClass::setLed(uint8_t red, uint8_t green, uint8_t blue) { - LED_SETTING_T setting = {red, green, blue}; - Serial.ledSet(setting); -} - -uint8_t BeanClass::getLedRed(void) { - LED_SETTING_T reading; + if(Serial.ledRead(&reading) == 0) { + return reading.red; + } - if (Serial.ledRead(&reading) == 0) { - return reading.red; + // TODO: This is an error state. + // Should we retry? + return 0; } - return 0; -} + uint8_t BeanClass::getLedGreen(void){ + LED_SETTING_T reading; -uint8_t BeanClass::getLedGreen(void) { - LED_SETTING_T reading; + if(Serial.ledRead(&reading) == 0) { + return reading.green; + } - if (Serial.ledRead(&reading) == 0) { - return reading.green; + // TODO: This is an error state. + // Should we retry? + return 0; } - return 0; -} + uint8_t BeanClass::getLedBlue(void){ + LED_SETTING_T reading; -uint8_t BeanClass::getLedBlue(void) { - LED_SETTING_T reading; + if(Serial.ledRead(&reading) == 0) { + return reading.blue; + } - if (Serial.ledRead(&reading) == 0) { - return reading.blue; + // TODO: This is an error state. + // Should we retry? + return 0; } - return 0; -} - -LED_SETTING_T BeanClass::getLed(void) { - LED_SETTING_T reading; - if (Serial.ledRead(&reading) == 0) { - return reading; - } + LED_SETTING_T BeanClass::getLed(void){ + LED_SETTING_T reading; - memset(&reading, 0, sizeof(reading)); - return reading; -} + if(Serial.ledRead(&reading) == 0){ + return reading; + } -ADV_SWITCH_ENABLED_T BeanClass::getServices(void) { - ADV_SWITCH_ENABLED_T services; - if (Serial.readGATT(&services) == 0) { - return services; + memset(&reading, 0, sizeof(reading)); + return reading; } - memset(&services, 0, sizeof(ADV_SWITCH_ENABLED_T)); - return services; -} - -void BeanClass::resetServices(void) { - ADV_SWITCH_ENABLED_T services; - memset(&services, 0, sizeof(ADV_SWITCH_ENABLED_T)); - services.standard = 1; - setServices(services); -} - -void BeanClass::setServices(ADV_SWITCH_ENABLED_T services) { - Serial.writeGATT(services); -} - -void BeanClass::enableHID(void) { - ADV_SWITCH_ENABLED_T curServices = getServices(); - curServices.hid = 1; - setServices(curServices); -} - -void BeanClass::enableMidi(void) { - ADV_SWITCH_ENABLED_T curServices = getServices(); - curServices.midi = 1; - setServices(curServices); -} - -void BeanClass::enableANCS(void) { - ADV_SWITCH_ENABLED_T curServices = getServices(); - curServices.ancs = 1; - setServices(curServices); -} - -void BeanClass::enableCustom(void) { - ADV_SWITCH_ENABLED_T curServices = getServices(); - curServices.custom = 1; - setServices(curServices); -} - -void BeanClass::setCustomAdvertisement(uint8_t *buf, int len) { - Serial.setCustomAdvertisement(buf, len); -} - -void BeanClass::startObserver(void) { Serial.startObserver(); } - -void BeanClass::stopObserver(void) { Serial.stopObserver(); } + bool BeanClass::setScratchData(uint8_t bank, const uint8_t* data, uint8_t dataLength) + { + bool errorRtn = true; -int BeanClass::getObserverMessage(ObseverAdvertisementInfo *message, - unsigned long timeout) { - return Serial.getObserverMessage(message, timeout); -} - -void BeanClass::enableiBeacon(void) { - ADV_SWITCH_ENABLED_T curServices = getServices(); - curServices.ibeacon = 1; - setServices(curServices); -} - -int BeanClass::midiSend(uint8_t status, uint8_t byte1, uint8_t byte2) { - if ((midiWriteOffset + 1) % MIDI_BUFFER_SIZE == midiReadOffset) return 1; - uint32_t millisec = millis(); - midiMessages[midiWriteOffset].status = status; - midiMessages[midiWriteOffset].byte1 = byte1; - midiMessages[midiWriteOffset].byte2 = byte2; - midiMessages[midiWriteOffset].timestamp = millisec; - midiWriteOffset++; - midiWriteOffset = midiWriteOffset % MIDI_BUFFER_SIZE; - return 0; -} - -int BeanClass::midiPacketSend() { - if (midiReadOffset == midiWriteOffset) return 0; - uint8_t byteOffset = 0; - // send a 20 byte message - uint32_t millisec = midiMessages[midiReadOffset].timestamp; - // first the header - uint8_t head_ts = millisec >> 7; - head_ts |= 1 << 7; // set the 7th bit to 1 - head_ts &= ~(1 << 6); // set the 6th bit to zero - midiPacket[byteOffset++] = head_ts; - // now some messages - int lastStatus = -1; - int lastTime = -1; - while (midiReadOffset != midiWriteOffset) { - if (lastStatus == midiMessages[midiReadOffset].status && - lastTime == midiMessages[midiReadOffset].timestamp) { - midiPacket[byteOffset++] = midiMessages[midiReadOffset].byte1; - midiPacket[byteOffset++] = midiMessages[midiReadOffset].byte2; - } else { - uint8_t msg_ts = midiMessages[midiReadOffset].timestamp; - msg_ts |= 1 << 7; // set the 7th bit to 1. - midiPacket[byteOffset++] = msg_ts; - midiPacket[byteOffset++] = midiMessages[midiReadOffset].status; - midiPacket[byteOffset++] = midiMessages[midiReadOffset].byte1; - midiPacket[byteOffset++] = midiMessages[midiReadOffset].byte2; + if ( dataLength <= MAX_SCRATCH_SIZE ) + { + BT_SCRATCH_T scratch; + scratch.number = bank; + memcpy( (void*)scratch.scratch, (void*)data, dataLength); + // magic: +1 due to bank byte + Serial.BTSetScratchChar(&scratch, (uint8_t)(dataLength+1)); } - midiReadOffset++; - midiReadOffset = midiReadOffset % MIDI_BUFFER_SIZE; - if (byteOffset + 4 > - BLE_PACKET_SIZE) // can we handle another midi message in this packet - break; - } - Serial.write_message(MSG_ID_MIDI_WRITE, midiPacket, byteOffset); - return byteOffset; -} - -int BeanClass::midiRead(uint8_t *status, uint8_t *byte1, uint8_t *byte2) { - uint8_t buffer[8]; - if (midiPacketBegin) { - if (Serial.midiAvailable() > 4) { - Serial.readMidi(buffer, 1); // header - midiPacketBegin = false; // we are now in the body + else + { + errorRtn = false; } - } - if (!midiPacketBegin) { - // read the first byte, check if its a status byte - if (Serial.midiAvailable() > 0) { - uint8_t peek = 0; - peek = Serial.peekMidi(); - if (peek & 1 << 7) { - // is status/timestamp byte. we are looking at a 4 byte message - if (Serial.midiAvailable() >= 4) { - Serial.readMidi(buffer, 4); - uint8_t timestamp = buffer[0]; - *status = buffer[1]; - lastStatus = *status; - *byte1 = buffer[2]; - *byte2 = buffer[3]; - if (timestamp == 0xFF && - *status == 0xFF && - *byte1 == 0xFF && - *byte2 == 0xFF) { - // end of packet - midiPacketBegin = true; - return 0; - } else { - return peek; - } - } - } else { // running status - if (Serial.midiAvailable() >= 2) { - Serial.readMidi(buffer, 2); - *status = lastStatus; - *byte1 = buffer[0]; - *byte2 = buffer[1]; - return peek; - } - } - } - } - return 0; -} - -int BeanClass::HIDPressKey(uint8_t k) { return BeanKeyboard.press(k); } - -int BeanClass::HIDReleaseKey(uint8_t k) { return BeanKeyboard.release(k); } - -int BeanClass::HIDWriteKey(uint8_t k) { return BeanKeyboard.write(k); } -int BeanClass::HIDWrite(String s) { - int status = 0; - int maxIndex = s.length() - 1; - for (int i = 0; i < maxIndex; i++) { - status |= BeanKeyboard.write(s.charAt(i)); + return errorRtn; } - return status; -} - -void BeanClass::HIDMoveMouse(signed char x, signed char y, signed char wheel) { - BeanMouse.move(x, y, wheel); -} - -void BeanClass::HIDClickMouse(uint8_t b) { BeanMouse.click(b); } - -void BeanClass::HIDSendConsumerControl(unsigned char command) { - BeanKeyboard.sendCC(command); -} - -int BeanClass::ancsAvailable() { return Serial.ancsAvailable(); } - -int BeanClass::readAncs(uint8_t *buffer, size_t max_length) { - return Serial.readAncs(buffer, max_length); -} - -int BeanClass::parseAncs(ANCS_SOURCE_MSG_T *buffer, size_t max_length) { - int numMsgs = Serial.ancsAvailable(); - Serial.readAncs((uint8_t *)buffer, max_length * 8); - - return numMsgs; -} - -int BeanClass::requestAncsNotiDetails(NOTI_ATTR_ID_T type, size_t len, - uint32_t ID) { - if (8 + len > SERIAL_BUFFER_SIZE) { - len = SERIAL_BUFFER_SIZE - 8; - } - uint8_t reqBuf[8]; - reqBuf[0] = 0; - memcpy((void *)&reqBuf[1], &ID, 4); - reqBuf[5] = type; - reqBuf[6] = len; - reqBuf[7] = 0; - Serial.getAncsNotiDetails(reqBuf, 8); -} - -void BeanClass::performAncsAction(uint32_t ID, uint8_t actionID) { - uint8_t reqBuf[6]; - reqBuf[0] = 2; // command ID perform notifcation action - memcpy((void *)&reqBuf[1], &ID, sizeof(uint32_t)); - reqBuf[5] = actionID; - Serial.getAncsNotiDetails(reqBuf, sizeof(reqBuf)); -} - -int BeanClass::readAncsNotiDetails(uint8_t *buf, size_t max_length) { - return Serial.readAncsMessage(buf, max_length); -} - -bool BeanClass::setScratchData(uint8_t bank, const uint8_t *data, - uint8_t dataLength) { - bool errorRtn = true; - - if (dataLength <= MAX_SCRATCH_SIZE) { + bool BeanClass::setScratchNumber(uint8_t bank, uint32_t data) + { + bool errorRtn = true; BT_SCRATCH_T scratch; scratch.number = bank; - memcpy((void *)scratch.scratch, (void *)data, dataLength); - // magic: +1 due to bank byte - Serial.BTSetScratchChar(&scratch, (uint8_t)(dataLength + 1)); - } else { - errorRtn = false; - } - return errorRtn; -} + scratch.scratch[0] = data & 0xFF; + scratch.scratch[1] = data >> 8UL; + scratch.scratch[2] = data >> 16UL; + scratch.scratch[3] = data >> 24UL; -bool BeanClass::setScratchNumber(uint8_t bank, uint32_t data) { - bool errorRtn = true; - BT_SCRATCH_T scratch; - scratch.number = bank; + // magic: 4 for data, 1 for scratch bank + Serial.BTSetScratchChar(&scratch, 4+1); - scratch.scratch[0] = data & 0xFF; - scratch.scratch[1] = data >> 8UL; - scratch.scratch[2] = data >> 16UL; - scratch.scratch[3] = data >> 24UL; + return errorRtn; + } - // magic: 4 for data, 1 for scratch bank - Serial.BTSetScratchChar(&scratch, 4 + 1); + ScratchData BeanClass::readScratchData(uint8_t bank) + { + ScratchData scratchTempBuffer; - return errorRtn; -} + memset( scratchTempBuffer.data, 0, 20); + Serial.BTGetScratchChar( bank, &scratchTempBuffer ); -ScratchData BeanClass::readScratchData(uint8_t bank) { - ScratchData scratchTempBuffer; + return scratchTempBuffer; + } - memset(scratchTempBuffer.data, 0, 20); - Serial.BTGetScratchChar(bank, &scratchTempBuffer); + long BeanClass::readScratchNumber(uint8_t bank) + { + long returnNum = 0; + static ScratchData scratchNumBuffer; - return scratchTempBuffer; -} + memset( scratchNumBuffer.data, 0, 20); + Serial.BTGetScratchChar( bank, &scratchNumBuffer ); -long BeanClass::readScratchNumber(uint8_t bank) { - long returnNum = 0; - static ScratchData scratchNumBuffer; + returnNum |= (long)scratchNumBuffer.data[0] & 0xFF; + returnNum |= (long)scratchNumBuffer.data[1] << 8UL; + returnNum |= (long)scratchNumBuffer.data[2] << 16UL; + returnNum |= (long)scratchNumBuffer.data[3] << 24UL; - memset(scratchNumBuffer.data, 0, 20); - Serial.BTGetScratchChar(bank, &scratchNumBuffer); + return returnNum; + } - returnNum |= (long)scratchNumBuffer.data[0] & 0xFF; - returnNum |= (long)scratchNumBuffer.data[1] << 8UL; - returnNum |= (long)scratchNumBuffer.data[2] << 16UL; - returnNum |= (long)scratchNumBuffer.data[3] << 24UL; + void BeanClass::setBeanName( const String &s ) + { + Serial.BTSetLocalName( (const char*)s.c_str() ); + } - return returnNum; -} + const char * BeanClass::getBeanName(void) + { + BT_RADIOCONFIG_T config; + static char myChar[MAX_LOCAL_NAME_SIZE]; -void BeanClass::setBeanName(const String &s) { - Serial.BTSetLocalName((const char *)s.c_str()); -} + int nameSize = MAX_LOCAL_NAME_SIZE; -const char *BeanClass::getBeanName(void) { - BT_RADIOCONFIG_T config; - static char myChar[MAX_LOCAL_NAME_SIZE]; + if ( -1 != Serial.BTGetConfig(&config) ) + { + nameSize = ( config.local_name_size < MAX_LOCAL_NAME_SIZE ) ? config.local_name_size : MAX_LOCAL_NAME_SIZE; - int nameSize = MAX_LOCAL_NAME_SIZE; + memcpy( (void*)myChar, (void*)config.local_name, nameSize ); + } - if (-1 != Serial.BTGetConfig(&config)) { - nameSize = (config.local_name_size < MAX_LOCAL_NAME_SIZE) - ? config.local_name_size - : MAX_LOCAL_NAME_SIZE; + // Null-terminate + for ( int i = nameSize; i < MAX_LOCAL_NAME_SIZE; i++ ) + { + myChar[i] = 0; + } - memcpy((void *)myChar, (void *)config.local_name, nameSize); + return myChar; } - // Null-terminate - for (int i = nameSize; i < MAX_LOCAL_NAME_SIZE; i++) { - myChar[i] = 0; + void BeanClass::setBeaconParameters( uint16_t uuid, uint16_t major_id, uint16_t minor_id ) + { + Serial.BTSetBeaconParams( uuid, major_id, minor_id ); } - return myChar; -} - -void BeanClass::setBeaconParameters(uint16_t uuid, uint16_t major_id, - uint16_t minor_id) { - Serial.BTSetBeaconParams(uuid, major_id, minor_id); -} - -void BeanClass::setBeaconEnable(bool beaconEnable) { - Serial.BTBeaconModeEnable(beaconEnable); -} + void BeanClass::setBeaconEnable( bool beaconEnable ) + { + Serial.BTBeaconModeEnable( beaconEnable ); + } -void BeanClass::enableWakeOnConnect(bool enable) { - Serial.enableWakeOnConnect(enable); -} + void BeanClass::enableWakeOnConnect( bool enable ) + { + Serial.enableWakeOnConnect( enable ); + } -void BeanClass::disconnect(void) { Serial.BTDisconnect(); } + void BeanClass::disconnect(void) + { + Serial.BTDisconnect(); + } diff --git a/hardware/bean/avr/cores/bean/Bean.h b/hardware/bean/avr/cores/bean/Bean.h index 11cb01a..ae7c57b 100644 --- a/hardware/bean/avr/cores/bean/Bean.h +++ b/hardware/bean/avr/cores/bean/Bean.h @@ -1,127 +1,494 @@ #ifndef BEAN_BEAN_BEAN_H #define BEAN_BEAN_BEAN_H #include "BeanSerialTransport.h" -#include "BeanHID.h" - -// Accel Events. -#define FLAT_EVENT 0x80 -#define ORIENT_EVENT 0x40 -#define SINGLE_TAP_EVENT 0x20 -#define DOUBLE_TAP_EVENT 0x10 -#define ANY_MOTION_EVENT 0x04 -#define HIGH_G_EVENT 0x02 -#define LOW_G_EVENT 0x01 +/** + * An acceleration reading from the Bean accelerometer, the BMA250 (datasheet). Also includes the current sensitivity setting. + * + * The accelerometer has 10-bit resolution. Readings are returned raw in the range of -512 to 511. These readings need to be converted to g (g-force). + * + * The accelerometer has configurable sensitivity. When using the accelerometer at the default sensitivity of ±2g, a value of +1 corresponds to +3.91 mg. + * + * The accelerometer sensitivity is ±2g, ±4g, ±8g, or ±16g. These are represented by the values 2, 4, 8, or 16. + */ typedef ACC_READING_T AccelerationReading; -typedef LED_SETTING_T LedReading; -typedef ADV_SWITCH_ENABLED_T BluetoothServices; -typedef ANCS_SOURCE_MSG_T AncsNotification; -typedef NOTI_ATTR_ID_T AncsNotificationAttribute; -typedef OBSERVER_INFO_MESSAGE_T ObseverAdvertisementInfo; +/** + * Intensity values for the color channels of the Bean RGB LED. 0 is off and 255 is on. + */ +typedef LED_SETTING_T LedReading; class BeanClass { public: - void enableMotionEvent(uint8_t events); - void disableMotionEvents(); - bool checkMotionEvent(uint8_t events); + /****************************************************************************/ + /** @name Accelerometer + * Read acceleration values and configure the accelerometer's sensitivity. + */ + ///@{ + + /** + * Get the current value of the Bean accelerometer X axis. + * + * @return a 10-bit value corresponding to the current X axis acceleration + */ + uint16_t getAccelerationX(void); - int16_t getAccelerationX(void); - int16_t getAccelerationY(void); - int16_t getAccelerationZ(void); + /** + * Get the current value of the Bean accelerometer Y axis. + * + * @return a 10-bit value corresponding to the current Y axis acceleration + */ + uint16_t getAccelerationY(void); + + /** + * Get the current value of the Bean accelerometer Z axis. + * + * @return a 10-bit value corresponding to the current Z axis acceleration + */ + uint16_t getAccelerationZ(void); + + /** + * Get the current value of all axes and the current sensitivity setting from the Bean accelerometer. + * + * @return an AccelerationReading object containing current acceleration and sensitivity + */ AccelerationReading getAcceleration(void); - void accelRegisterWrite(uint8_t reg, uint8_t value); - int accelRegisterRead(uint8_t reg, uint8_t length, uint8_t* value); + + /** + * Get the current sensitivity setting of the Bean accelerometer. + * + * @return 2, 4, 8, or 16, corresponding to ±2g, ±4g, ±8g, or ±16g + */ uint8_t getAccelerationRange(void); + + /** + * Configure the sensitivity of the Bean accelerometer. + * + * @param range 2, 4, 8, or 16, corresponding to ±2g, ±4g, ±8g, or ±16g + */ void setAccelerationRange(uint8_t range); - void setAccelerometerPowerMode(uint8_t mode); - uint8_t getAccelerometerPowerMode(); + ///@} - int8_t getTemperature(void); - uint8_t getBatteryLevel(void); - uint16_t getBatteryVoltage(void); - void enableConfigSave(bool enableSave); + /****************************************************************************/ + /** @name LED + * Set the RGB LED color and check what it's currently showing. + */ + ///@{ + + /** + * Set intensity values for the color channels of the Bean RGB LED. 0 is off and 255 is on. + * + * # Examples + * + * This example sets the LED to white (all channels on, full intensity): + * @include led/setLed.ino + */ void setLed(uint8_t red, uint8_t green, uint8_t blue); + + /** + * Get current intensity values for the color channels of the Bean RGB LED. + * + * @return `LedReading` struct that contains an integer representation of each color. + * + * # Examples + * + * This example shows the usage of the getLed() function and how to interperet the return value. + * @include led/getLed.ino + */ LedReading getLed(void); + + /** + * Get intensity of the red channel of the Bean RGB LED. 0 is off and 255 is on. + */ uint8_t getLedRed(void); + + /** + * Get intensity of the green channel of the Bean RGB LED. 0 is off and 255 is on. + */ uint8_t getLedGreen(void); + + /** + * Get intensity of the blue channel of the Bean RGB LED. 0 is off and 255 is on. + */ uint8_t getLedBlue(void); + + /** + * Set intensity of the red channel of the Bean RGB LED. 0 is off and 255 is on. + */ void setLedRed(uint8_t intensity); + + /** + * Set intensity of the green channel of the Bean RGB LED. 0 is off and 255 is on. + */ void setLedGreen(uint8_t intensity); + + /** + * Set intensity of the blue channel of the Bean RGB LED. 0 is off and 255 is on. + */ void setLedBlue(uint8_t intensity); + ///@} - BluetoothServices getServices(void); - void setServices(BluetoothServices services); - void resetServices(void); - void enableHID(void); - void enableMidi(void); - void enableANCS(void); - void enableiBeacon(void); - void enableCustom(void); - void setCustomAdvertisement(uint8_t *buf, int len); - - int midiPacketSend(); - int midiSend(uint8_t *buff, uint8_t numBytes); - int midiSend(uint8_t status, uint8_t byte1, uint8_t byte2); - int midiRead(uint8_t *status, uint8_t *byte1, uint8_t *byte2); - - int HIDPressKey(uint8_t k); - int HIDReleaseKey(uint8_t k); - int HIDWriteKey(uint8_t k); - int HIDWrite(String s); - void HIDMoveMouse(signed char x, signed char y, signed char wheel = 0); - void HIDClickMouse(uint8_t b = MOUSE_LEFT); - void HIDSendConsumerControl(unsigned char command); - - int ancsAvailable(); - int readAncs(uint8_t *buffer, size_t max_length); - int parseAncs(ANCS_SOURCE_MSG_T *buffer, size_t max_length); - int requestAncsNotiDetails(NOTI_ATTR_ID_T type, size_t len, uint32_t ID); - int readAncsNotiDetails(uint8_t *buf, size_t max_length); - void performAncsAction(uint32_t ID, uint8_t actionID); - - void startObserver(void); - void stopObserver(void); - int getObserverMessage(ObseverAdvertisementInfo *message, - unsigned long timeout); - - bool setScratchData(uint8_t bank, const uint8_t* data, uint8_t dataLength); + + /****************************************************************************/ + /** @name Scratch + * Read and write arbitrary data using pre-defined BLE characteristics. + * + * Scratch characteristics are Bluetooth Low Energy characteristics that Bean provides for arbitrary use by developers. Each characteristic can hold up to 20 bytes due to BLE restrictions. + * + * Scratch characteristics will trigger Notify events on BLE Central clients when they are changed by Bean's Arduino sketch. Bean sketches must poll to find out when a client changes scratch characteristic data. + * + * Bean and Bean+ have five scratch characteristics. All scratch chars are contained in a single BLE service. + * + * * **Scratch Service UUID:** `a495ff20-c5b1-4b44-b512-1370f02d74de` + * * **Scratch Characteristic UUIDs:** + * 1. `a495ff21-c5b1-4b44-b512-1370f02d74de` + * 2. `a495ff22-c5b1-4b44-b512-1370f02d74de` + * 3. `a495ff23-c5b1-4b44-b512-1370f02d74de` + * 4. `a495ff24-c5b1-4b44-b512-1370f02d74de` + * 5. `a495ff25-c5b1-4b44-b512-1370f02d74de` + * + * In the below methods, behavior is undefined when the `bank` parameter is not `1`, `2`, `3`, `4`, or `5`. + * + */ + ///@{ + + /** + * Set the data in a scratch characteristic. Triggers a BLE Notify event for connected clients. + * + * @param bank The index of the destination scratch char: `1`, `2`, `3`, `4`, or `5` + * @param data An array of `byte`s or `uint8_t`s to be copied into the scratch char + * @param dataLength The number of bytes to copy from `data` + * + * @return Success: false if `dataLength` is greater than 20, true otherwise + * + * # Examples + * + * This example reads two of Bean's analog pins and writes the values to two scratch characteristics: + * @include scratchChars/setScratchData.ino + */ + bool setScratchData(uint8_t bank, const uint8_t *data, uint8_t dataLength); + + /** + * Write a 32-bit (four-byte) value into a scratch characteristic. Triggers a BLE Notify event for connected clients. + * + * @param bank The index of the destination scratch char: `1`, `2`, `3`, `4`, or `5` + * @param data The 32-bit value to be written into the scratch char + * + * @return Success: always returns true, since all 32-bit numbers are under 20 bytes in length + * + * # Examples + * + * This example writes a value to and reads a value from a scratch characteristic: + * @include scratchChars/setScratchNumber.ino + */ bool setScratchNumber(uint8_t bank, uint32_t data); + + /** + * Read the data from a scratch characteristic. + * + * @param bank The index of the source scratch char: `1`, `2`, `3`, `4`, or `5` + * + * @return The contents of the scratch characteristic + * + * # Examples + * + * This example polls a scratch characteristic and blinks Bean's LED if the value changes: + * @include scratchChars/readScratchData.ino + */ ScratchData readScratchData(uint8_t bank); + + /** + * Read a 32-bit (four-byte) value from a scratch characteristic. + * + * @param bank The index of the source scratch char: `1`, `2`, `3`, `4`, or `5` + * + * # Examples + * + * This example writes a value to and reads a value from a scratch characteristic: + * @include scratchChars/setScratchNumber.ino + */ long readScratchNumber(uint8_t bank); + ///@} + + /****************************************************************************/ + /** @name Sleep + * Bean power management functions to help save battery life. + */ + ///@{ + + /** + * Sleep for a period of time. + * + * This method puts the ATmega chip to sleep until it is woken by the LBM313 at the requested time. + * + * Bean can be woken from sleep by the following: + * + * * The requested sleep time elapses + * * A serial message is received from a connected client + * * A client connects to Bean while wake on connect is enabled + * * A pin change interrupt occurs + * + * `Bean.sleep()` is more power-efficient than Arduino `sleep()` because it puts the ATmega into a low-power mode known as "power-down". This disables the ATmega's internal timers, so functions like `millis()` will not track time elapsed during `Bean.sleep()`. + * + * The ATmega can take up to 7 ms to wake from `Bean.sleep()`. If you are looking for more precise timings, please consider using [delay()](https://www.arduino.cc/en/Reference/Delay) or [delayMicroseconds()](https://www.arduino.cc/en/Reference/DelayMicroseconds). + * + * For more information on low-power mode on the ATmega328, check out this [Sparkfun tutorial](https://www.sparkfun.com/tutorials/309). + * + * @param duration_ms The duration to sleep for, in milliseconds + * + * # Examples + * + * This example turns on Bean's LED, sleeps for one second, turns off Bean's LED and sleeps for four more seconds, then repeats: + * + * @include sleep/sleep.ino + */ void sleep(uint32_t duration_ms); + + /** + * Enable or disable keep-awake mode. + * + * By default, the Bean radio sleeps frequently to conserve power. Enabling keep-awake forces the LBM into wake mode and decreases latency between the LBM313 and the ATmega. + * + * This may be useful if you are having trouble with latency between an event and a Bluetooth transmission: for example, to decrease the time between Bean reading a pin change event and sending a Bluetooth message. + * + * Enabling keep-awake may signficantly decrease battery life. Use with caution. + * + * @param true to enable keep-awake, false to disable + */ void keepAwake(bool enable); - void attachChangeInterrupt(uint8_t pin, void (*userFunc)(void)); - void detachChangeInterrupt(uint8_t pin); + /** + * Enable or disable wake on connect. By default, Bean does not wake up when a BLE client connects. + * + * @param enable true to enable wake on connect, false to disable + * + * # Examples + * + * This example wakes Bean when a client connects, waits for the client to disconnect, and sleeps on disconnect: + * + * @include sleep/enableWakeOnConnect.ino + */ + void enableWakeOnConnect(bool enable); + ///@} + + + /****************************************************************************/ + /** @name Advertising + * Set and verify the Bean BLE advertising configuration. + * + * Bean makes itself visible to BLE Central devices by broadcasting BLE advertising packets. If advertising is disabled, Central devices will not be able to find or connect to Bean. + * + * Advertising is automatically enabled when Bean is powered on or resets. However, uploading a sketch that disables advertising indefinitely may make it impossible to connect to Bean. If this happens to you, see [this guide (TODO: ADD GUIDE + LINK)](#) to clear the sketch stored on Bean. + */ + ///@{ + + /** + * Set the advertising name of the Bean. BLE advertising names are truncated at 20 bytes. + * + * @param s The name to be advertised + * + * # Examples + * + * This example changes Bean's name based on its temperature: + * + * @include advertising/setBeanName.ino + */ + void setBeanName(const String &s); + + /** + * Read the currently-advertised name of the Bean. + * + * @return The Bean name as a char array, null-terminated + * + * # Examples + * + * This example prints Bean's name to Virtual Serial every two seconds: + * + * @include examples/getBeanName.ino + */ + const char *getBeanName(void); + + /** + * Needs docs + */ void setAdvertisingInterval(uint16_t interval_ms); + + /** + * Enable or disable BLE advertising for a specific duration. + * + * Advertising is automatically enabled when Bean is powered on or resets. Configuration changes made by calling this method are **not** stored in non-volatile memory. + * + * @param enable true to enable advertising, false to disable + * @param timer the duration to enable/disable advertising, in milliseconds + * + * # Examples + * + * This example disables advertising for 10 seconds when digital pin 0 is pulled low: + * + * @include advertising/enableAdvertisingInterval.ino + */ void enableAdvertising(bool enable, uint32_t timer); + + /** + * Enable or disable BLE advertising. + * + * Advertising is automatically enabled when Bean is powered on or resets. Configuration changes made by calling this method are **not** stored in non-volatile memory. + * + * @param enable true to enable advertising, false to disable + * + * # Examples + * + * This example disables advertising when digital pin 0 is pulled low and enables it otherwise: + * + * @include advertising/enableAdvertising.ino + */ void enableAdvertising(bool enable); - bool getConnectionState(void); + + /** + * Check whether the Bean is currently advertising. + * + * @return true if Bean is advertising, false if Bean is not advertising + * + * # Examples + * + * This example toggles Bean's advertising every 15 seconds and indicates the current advertising status with the LED: + * + * @include advertising/getAdvertisingState.ino + * + */ bool getAdvertisingState(void); - void setBeanName(const String& s); - const char* getBeanName(void); + ///@} + + + /****************************************************************************/ + /** @name iBeacon + * Let your Bean act as an iBeacon, a way to convey real-world location to iOS devices. + * + * Bean supports a limited subset of UUIDs available to iBeacon devices. A Bean iBeacon UUID is made up of 16 user-configurable bits and 112 preconfigured bits, where `xx` represents a user-configurable byte: + * + * `A495xxxx-C5B1-4B44-B512-1370F02D74DE` + * + * Using iBeacon features will, by default, write to Bean's NVRAM. The NVRAM has a limited number of writes. Use `enableConfigSave` to store settings temporarily and conserve NVRAM writes. + */ + ///@{ + + /** + * Configure Bean's iBeacon UUID, major ID, and minor ID. Each of these parameters, **including UUID**, takes 16-bit unsigned values. For more information on UUID, major, and minor values, see [this iBeacon FAQ](https://support.kontakt.io/hc/en-gb/articles/201620741-iBeacon-Parameters-UUID-Major-and-Minor). + * + * @param uuid The 16-bit value used to set part of the iBeacon UUID. For example: Passing `0xABCD` to `uuid` will set the Bean's UUID to `A495ABCD-C5B1-4B44-B512-1370F02D74DE`. + * @param major_id The major ID of the iBeacon + * @param major_id The minor ID of the iBeacon + */ void setBeaconParameters(uint16_t uuid, uint16_t major_id, uint16_t minor_id); + + /** + * Enable or disable iBeacon functionality. + * + * @param beaconEnable true to enable iBeacon, false to disable + */ void setBeaconEnable(bool beaconEnable); - void enableWakeOnConnect(bool enable); + ///@} + + + /****************************************************************************/ + /** @name Battery + * Read the Bean's battery level. + */ + ///@{ + + /** + * Get the current battery level, in percent. + * + * @return a value in the range 0 to 100: 0 = 1.95 V, 100 = 3.53 V + */ + uint8_t getBatteryLevel(void); + + /** + * Get the current battery voltage, in volts. + * + * Accuracy is ±0.01 V. + * + * @return a value in the range 195 to 353: 195 = 1.95 V, 353 = 3.53 V + */ + uint16_t getBatteryVoltage(void); + ///@} + + + /****************************************************************************/ + /** @name Temperature + * Read the ambient temperature of the Bean. + */ + ///@{ + + /** + * Get the current temperature of the Bean, in degrees Celsius. The Bean uses the BMA250 (datasheet) for temperature readings. + * + * @return temperature, between -40 and 88 degrees Celsius + */ + int8_t getTemperature(void); + ///@} + + + /****************************************************************************/ + /** @name Connection + * Work with active BLE Central devices that connect to Bean. + */ + ///@{ + + /** + * Terminate the connection between Bean and the connected BLE Central + * device. If no Central device is connected, this method does nothing. + */ void disconnect(void); + /** + * Check if any BLE Central devices are currently connected to Bean. + * + * @return true if a device is connected, false otherwise + */ + bool getConnectionState(void); + ///@} + + + /***************************************************************************/ + /** @name Other + * Functions that don't belong in any of the other categories. + */ + ///@{ + + /** + * Allows temporary storage of BLE configuration settings, as opposed to permanent storage in non-volatile memory (NVRAM). + * + * Bean can only write to NVRAM a maximum of 20,000 times. If your sketch changes its advertising configuration frequently, it will quickly use up all of your Bean NVRAM's writes. To prevent this, disable saving to NVRAM first. + * + * Configurations written while NVRAM saving is disabled will persist until the Bean is power cycled. + * + * When the Bean is power cycled, saving to NVRAM is re-enabled. + * + * @param enableSave true to disable saving to NVRAM, false to enable + */ + void enableConfigSave(bool enableSave); + ///@} + + BeanClass() {} private: + /** + * Send a message from the ATmega to the CC2540 asking it to wake up the ATmega at a given time. The CC2540 might not receive the message, so it's important to check the return value of this method. + * + * @param duration_ms The duration to sleep for, in milliseconds + * + * @return true if the message was acknowledged by the CC2540 successfully, false if the message was not acknowledged and should be sent again + */ bool attemptSleep(uint32_t duration_ms); - int16_t convertAcceleration(uint8_t high_byte, uint8_t low_byte); - void accelerometerConfig(uint16_t interrupts, uint8_t power_mode); - void enableWakeOnAccelerometer(uint8_t sources); - uint8_t checkAccelInterrupts(); - - uint8_t lastStatus; - long midiTimeStampDiff; - bool midiPacketBegin; }; +/** + * Needs docs + */ extern BeanClass Bean; #endif diff --git a/hardware/bean/avr/cores/bean/BeanHID.cpp b/hardware/bean/avr/cores/bean/BeanHID.cpp deleted file mode 100644 index da674d6..0000000 --- a/hardware/bean/avr/cores/bean/BeanHID.cpp +++ /dev/null @@ -1,572 +0,0 @@ - - -/* Copyright (c) 2011, Peter Barrett -** -** Permission to use, copy, modify, and/or distribute this software for -** any purpose with or without fee is hereby granted, provided that the -** above copyright notice and this permission notice appear in all copies. -** -** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR -** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES -** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -** SOFTWARE. -*/ - -#include -#include "BeanHID.h" - -// Singletons for BeanKeyboard and BeanMouse - -BeanKeyboard_ BeanKeyboard; -BeanMouse_ BeanMouse; - -#define HID_DEV_DATA_LEN 8 - -// HID keyboard input report length -#define HID_KEYBOARD_IN_RPT_LEN 8 -#define HID_MOUSE_IN_RPT_LEN 4 -#define HID_CC_IN_RPT_LEN 2 - -typedef struct { - uint8_t id; - uint8_t type; - uint8_t len; - uint8_t data[HID_DEV_DATA_LEN]; -} hidDevReport_t; - -//============================================================================== -//============================================================================== - -// HID report descriptor - -#define LSB(_x) ((_x)&0xFF) -#define MSB(_x) ((_x) >> 8) - -#define RAWHID_USAGE_PAGE 0xFFC0 -#define RAWHID_USAGE 0x0C00 -#define RAWHID_TX_SIZE 64 -#define RAWHID_RX_SIZE 64 - -extern const uint8_t _hidReportDescriptor[] PROGMEM; -const uint8_t _hidReportDescriptor[] = { - // BeanMouse - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 - 0x09, 0x02, // USAGE (BeanMouse) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x01, // USAGE (Pointer) - 0xa1, 0x00, // COLLECTION (Physical) - 0x85, 0x01, // REPORT_ID (1) - 0x05, 0x09, // USAGE_PAGE (Button) - 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x03, // USAGE_MAXIMUM (Button 3) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x95, 0x03, // REPORT_COUNT (3) - 0x75, 0x01, // REPORT_SIZE (1) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x05, // REPORT_SIZE (5) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x30, // USAGE (X) - 0x09, 0x31, // USAGE (Y) - 0x09, 0x38, // USAGE (Wheel) - 0x15, 0x81, // LOGICAL_MINIMUM (-127) - 0x25, 0x7f, // LOGICAL_MAXIMUM (127) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x03, // REPORT_COUNT (3) - 0x81, 0x06, // INPUT (Data,Var,Rel) - 0xc0, // END_COLLECTION - 0xc0, // END_COLLECTION - - // Keyboard - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 - 0x09, 0x06, // USAGE (Keyboard) - 0xa1, 0x01, // COLLECTION (Application) - 0x85, 0x02, // REPORT_ID (2) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - - 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) - 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x75, 0x01, // REPORT_SIZE (1) - - 0x95, 0x08, // REPORT_COUNT (8) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x08, // REPORT_SIZE (8) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - - 0x95, 0x06, // REPORT_COUNT (6) - 0x75, 0x08, // REPORT_SIZE (8) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x65, // LOGICAL_MAXIMUM (101) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - - 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) - 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) - 0x81, 0x00, // INPUT (Data,Ary,Abs) - 0xc0, // END_COLLECTION - -#if RAWHID_ENABLED - // RAW HID - 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 - 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), - - 0xA1, 0x01, // Collection 0x01 - 0x85, 0x03, // REPORT_ID (3) - 0x75, 0x08, // report size = 8 bits - 0x15, 0x00, // logical minimum = 0 - 0x26, 0xFF, 0x00, // logical maximum = 255 - - 0x95, 64, // report count TX - 0x09, 0x01, // usage - 0x81, 0x02, // Input (array) - - 0x95, 64, // report count RX - 0x09, 0x02, // usage - 0x91, 0x02, // Output (array) - 0xC0 // end collection -#endif -}; - -#define HID_RPT_ID_KEY_IN 2 // Keyboard input report ID -#define HID_RPT_ID_MOUSE_IN 1 // Mouse input report ID -#define HID_RPT_ID_CC_IN 3 // Consumer Control input report ID - -#define HID_RPT_ID_LED_OUT 0 // LED output report ID -#define HID_RPT_ID_FEATURE 0 // Feature report ID - -#define HID_REPORT_TYPE_INPUT 1 -#define HID_REPORT_TYPE_OUTPUT 2 -#define HID_REPORT_TYPE_FEATURE 3 - -//============================================================================== -//============================================================================== -// Driver - -uint8_t _hid_idle = 1; - -//============================================================================== -//============================================================================== -// BeanMouse - -BeanMouse_::BeanMouse_(void) : _buttons(0) {} - -void BeanMouse_::begin(void) {} - -void BeanMouse_::end(void) {} - -void BeanMouse_::click(uint8_t b) { - _buttons = b; - move(0, 0, 0); - _buttons = 0; - move(0, 0, 0); -} - -void BeanMouse_::move(signed char x, signed char y, signed char wheel) { - BeanMouseReport m; - m.mouse[0] = _buttons; - m.mouse[1] = x; - m.mouse[2] = y; - m.mouse[3] = wheel; - sendReport(&m); -} - -void BeanMouse_::buttons(uint8_t b) { - if (b != _buttons) { - _buttons = b; - move(0, 0, 0); - } -} - -void BeanMouse_::press(uint8_t b) { buttons(_buttons | b); } - -void BeanMouse_::release(uint8_t b) { buttons(_buttons & ~b); } - -bool BeanMouse_::isPressed(uint8_t b) { - if ((b & _buttons) > 0) return true; - return false; -} - -void BeanMouse_::sendReport(BeanMouseReport *commands) { - hidDevReport_t report; - report.type = HID_REPORT_TYPE_INPUT; - report.id = HID_RPT_ID_MOUSE_IN; - report.len = HID_MOUSE_IN_RPT_LEN; - - if (report.len <= HID_DEV_DATA_LEN) { - memcpy((void *)report.data, (void *)commands, sizeof(BeanMouseReport)); - Serial.write_message(MSG_ID_HID_SEND_REPORT, (uint8_t *)&report, - sizeof(hidDevReport_t)); - } -} - -//============================================================================== -//============================================================================== -// Keyboard - -BeanKeyboard_::BeanKeyboard_(void) {} - -void BeanKeyboard_::begin(void) {} - -// Macros for the HID Consumer Control 2-byte report -#define HID_CC_RPT_SET_NUMERIC(s, x) \ - (s)[0] &= HID_CC_RPT_NUMERIC_BITS; \ - (s)[0] = (x) -#define HID_CC_RPT_SET_CHANNEL(s, x) \ - (s)[0] &= HID_CC_RPT_CHANNEL_BITS; \ - (s)[0] |= ((x)&0x03) << 4 -#define HID_CC_RPT_SET_VOLUME_UP(s) \ - (s)[0] &= HID_CC_RPT_VOLUME_BITS; \ - (s)[0] |= 0x40 -#define HID_CC_RPT_SET_VOLUME_DOWN(s) \ - (s)[0] &= HID_CC_RPT_VOLUME_BITS; \ - (s)[0] |= 0x80 -#define HID_CC_RPT_SET_BUTTON(s, x) \ - (s)[1] &= HID_CC_RPT_BUTTON_BITS; \ - (s)[1] |= (x) -#define HID_CC_RPT_SET_SELECTION(s, x) \ - (s)[1] &= HID_CC_RPT_SELECTION_BITS; \ - (s)[1] |= ((x)&0x03) << 4 - -static void hidCCBuildReport(uint8_t *pBuf, uint8_t cmd) { - switch (cmd) { - case HID_CONSUMER_CHANNEL_UP: - HID_CC_RPT_SET_CHANNEL(pBuf, HID_CC_RPT_CHANNEL_UP); - break; - - case HID_CONSUMER_CHANNEL_DOWN: - HID_CC_RPT_SET_CHANNEL(pBuf, HID_CC_RPT_CHANNEL_DOWN); - break; - - case HID_CONSUMER_VOLUME_UP: - HID_CC_RPT_SET_VOLUME_UP(pBuf); - break; - - case HID_CONSUMER_VOLUME_DOWN: - HID_CC_RPT_SET_VOLUME_DOWN(pBuf); - break; - - case HID_CONSUMER_MUTE: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_MUTE); - break; - - case HID_CONSUMER_POWER: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_POWER); - break; - - case HID_CONSUMER_RECALL_LAST: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_LAST); - break; - - case HID_CONSUMER_ASSIGN_SEL: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_ASSIGN_SEL); - break; - - case HID_CONSUMER_PLAY: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_PLAY); - break; - - case HID_CONSUMER_PAUSE: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_PAUSE); - break; - - case HID_CONSUMER_RECORD: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_RECORD); - break; - - case HID_CONSUMER_FAST_FORWARD: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_FAST_FWD); - break; - - case HID_CONSUMER_REWIND: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_REWIND); - break; - - case HID_CONSUMER_SCAN_NEXT_TRK: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_SCAN_NEXT_TRK); - break; - - case HID_CONSUMER_SCAN_PREV_TRK: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_SCAN_PREV_TRK); - break; - - case HID_CONSUMER_STOP: - HID_CC_RPT_SET_BUTTON(pBuf, HID_CC_RPT_STOP); - break; - - default: - if ((cmd >= HID_KEYBOARD_1) && (cmd <= HID_KEYBOARD_0)) { - HID_CC_RPT_SET_BUTTON(pBuf, (cmd - HID_KEYBOARD_1 + 1) % 10); - } - break; - } -} - -void BeanKeyboard_::sendCC(uint8_t command) { - hidDevReport_t report; - report.type = HID_REPORT_TYPE_INPUT; - report.id = HID_RPT_ID_CC_IN; - report.len = HID_CC_IN_RPT_LEN; - - uint8_t buf[HID_CC_IN_RPT_LEN] = {0, 0}; - - hidCCBuildReport(buf, command); - - memcpy((void *)report.data, buf, HID_CC_IN_RPT_LEN); - Serial.write_message(MSG_ID_HID_SEND_REPORT, (uint8_t *)&report, - sizeof(hidDevReport_t)); -} - -void BeanKeyboard_::end(void) {} - -void BeanKeyboard_::sendReport(BeanKeyReport *keys) { - hidDevReport_t report; - report.type = HID_REPORT_TYPE_INPUT; - report.id = HID_RPT_ID_KEY_IN; - report.len = HID_KEYBOARD_IN_RPT_LEN; - - if (report.len <= HID_DEV_DATA_LEN) { - memcpy((void *)report.data, (void *)keys, sizeof(BeanKeyReport)); - Serial.write_message(MSG_ID_HID_SEND_REPORT, (uint8_t *)&report, - sizeof(hidDevReport_t)); - } -} - -extern const uint8_t _asciimap[128] PROGMEM; - -#define SHIFT 0x80 -const uint8_t _asciimap[128] = { - 0x00, // NUL - 0x00, // SOH - 0x00, // STX - 0x00, // ETX - 0x00, // EOT - 0x00, // ENQ - 0x00, // ACK - 0x00, // BEL - 0x2a, // BS Backspace - 0x2b, // TAB Tab - 0x28, // LF Enter - 0x00, // VT - 0x00, // FF - 0x00, // CR - 0x00, // SO - 0x00, // SI - 0x00, // DEL - 0x00, // DC1 - 0x00, // DC2 - 0x00, // DC3 - 0x00, // DC4 - 0x00, // NAK - 0x00, // SYN - 0x00, // ETB - 0x00, // CAN - 0x00, // EM - 0x00, // SUB - 0x00, // ESC - 0x00, // FS - 0x00, // GS - 0x00, // RS - 0x00, // US - - 0x2c, // ' ' - 0x1e | SHIFT, // ! - 0x34 | SHIFT, // " - 0x20 | SHIFT, // # - 0x21 | SHIFT, // $ - 0x22 | SHIFT, // % - 0x24 | SHIFT, // & - 0x34, // ' - 0x26 | SHIFT, // ( - 0x27 | SHIFT, // ) - 0x25 | SHIFT, // * - 0x2e | SHIFT, // + - 0x36, // , - 0x2d, // - - 0x37, // . - 0x38, // / - 0x27, // 0 - 0x1e, // 1 - 0x1f, // 2 - 0x20, // 3 - 0x21, // 4 - 0x22, // 5 - 0x23, // 6 - 0x24, // 7 - 0x25, // 8 - 0x26, // 9 - 0x33 | SHIFT, // : - 0x33, // ; - 0x36 | SHIFT, // < - 0x2e, // = - 0x37 | SHIFT, // > - 0x38 | SHIFT, // ? - 0x1f | SHIFT, // @ - 0x04 | SHIFT, // A - 0x05 | SHIFT, // B - 0x06 | SHIFT, // C - 0x07 | SHIFT, // D - 0x08 | SHIFT, // E - 0x09 | SHIFT, // F - 0x0a | SHIFT, // G - 0x0b | SHIFT, // H - 0x0c | SHIFT, // I - 0x0d | SHIFT, // J - 0x0e | SHIFT, // K - 0x0f | SHIFT, // L - 0x10 | SHIFT, // M - 0x11 | SHIFT, // N - 0x12 | SHIFT, // O - 0x13 | SHIFT, // P - 0x14 | SHIFT, // Q - 0x15 | SHIFT, // R - 0x16 | SHIFT, // S - 0x17 | SHIFT, // T - 0x18 | SHIFT, // U - 0x19 | SHIFT, // V - 0x1a | SHIFT, // W - 0x1b | SHIFT, // X - 0x1c | SHIFT, // Y - 0x1d | SHIFT, // Z - 0x2f, // [ - 0x31, // bslash - 0x30, // ] - 0x23 | SHIFT, // ^ - 0x2d | SHIFT, // _ - 0x35, // ` - 0x04, // a - 0x05, // b - 0x06, // c - 0x07, // d - 0x08, // e - 0x09, // f - 0x0a, // g - 0x0b, // h - 0x0c, // i - 0x0d, // j - 0x0e, // k - 0x0f, // l - 0x10, // m - 0x11, // n - 0x12, // o - 0x13, // p - 0x14, // q - 0x15, // r - 0x16, // s - 0x17, // t - 0x18, // u - 0x19, // v - 0x1a, // w - 0x1b, // x - 0x1c, // y - 0x1d, // z - 0x2f | SHIFT, // - 0x31 | SHIFT, // | - 0x30 | SHIFT, // } - 0x35 | SHIFT, // ~ - 0 // DEL -}; - -// press() adds the specified key (printing, non-printing, or modifier) -// to the persistent key report and sends the report. Because of the way -// USB HID works, the host acts like the key remains pressed until we -// call release(), releaseAll(), or otherwise clear the report and resend. -size_t BeanKeyboard_::press(uint8_t k) { - uint8_t i; - if (k >= 136) { // it's a non-printing key (not a modifier) - k = k - 136; - } else if (k >= 128) { // it's a modifier key - _keyReport.modifiers |= (1 << (k - 128)); - k = 0; - } else { // it's a printing key - k = pgm_read_byte(_asciimap + k); - if (!k) { - setWriteError(); - return 0; - } - if (k & - 0x80) { // it's a capital letter or other character reached with shift - _keyReport.modifiers |= 0x02; // the left shift modifier - k &= 0x7F; - } - } - - // Add k to the key report only if it's not already present - // and if there is an empty slot. - if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && - _keyReport.keys[2] != k && _keyReport.keys[3] != k && - _keyReport.keys[4] != k && _keyReport.keys[5] != k) { - for (i = 0; i < 6; i++) { - if (_keyReport.keys[i] == 0x00) { - _keyReport.keys[i] = k; - break; - } - } - if (i == 6) { - setWriteError(); - return 0; - } - } - sendReport(&_keyReport); - return 1; -} - -// release() takes the specified key out of the persistent key report and -// sends the report. This tells the OS the key is no longer pressed and that -// it shouldn't be repeated any more. -size_t BeanKeyboard_::release(uint8_t k) { - uint8_t i; - if (k >= 136) { // it's a non-printing key (not a modifier) - k = k - 136; - } else if (k >= 128) { // it's a modifier key - _keyReport.modifiers &= ~(1 << (k - 128)); - k = 0; - } else { // it's a printing key - k = pgm_read_byte(_asciimap + k); - if (!k) { - return 0; - } - if (k & - 0x80) { // it's a capital letter or other character reached with shift - _keyReport.modifiers &= ~(0x02); // the left shift modifier - k &= 0x7F; - } - } - - // Test the key report to see if k is present. Clear it if it exists. - // Check all positions in case the key is present more than once (which it - // shouldn't be) - for (i = 0; i < 6; i++) { - if (0 != k && _keyReport.keys[i] == k) { - _keyReport.keys[i] = 0x00; - } - } - - sendReport(&_keyReport); - return 1; -} - -void BeanKeyboard_::releaseAll(void) { - _keyReport.keys[0] = 0; - _keyReport.keys[1] = 0; - _keyReport.keys[2] = 0; - _keyReport.keys[3] = 0; - _keyReport.keys[4] = 0; - _keyReport.keys[5] = 0; - _keyReport.modifiers = 0; - sendReport(&_keyReport); -} - -size_t BeanKeyboard_::write(uint8_t c) { - uint8_t p = press(c); // Keydown - uint8_t r = release(c); // Keyup - return (p); // just return the result of press() since release() almost - // always returns 1 -} diff --git a/hardware/bean/avr/cores/bean/BeanHID.h b/hardware/bean/avr/cores/bean/BeanHID.h deleted file mode 100644 index fa0b7f9..0000000 --- a/hardware/bean/avr/cores/bean/BeanHID.h +++ /dev/null @@ -1,184 +0,0 @@ - - -#ifndef __BEANHID__ -#define __BEANHID__ - -//============================================================================== -//============================================================================== -// Mouse - -#define MOUSE_LEFT 1 -#define MOUSE_RIGHT 2 -#define MOUSE_MIDDLE 4 -#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE) - -typedef struct { uint8_t mouse[5]; } BeanMouseReport; - -class BeanMouse_ { - private: - uint8_t _buttons; - void buttons(uint8_t b); - void sendReport(BeanMouseReport* commands); - - public: - BeanMouse_(void); - void begin(void); - void end(void); - void click(uint8_t b = MOUSE_LEFT); - void move(signed char x, signed char y, signed char wheel = 0); - void press(uint8_t b = MOUSE_LEFT); // press LEFT by default - void release(uint8_t b = MOUSE_LEFT); // release LEFT by default - bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default -}; -extern BeanMouse_ BeanMouse; - -//============================================================================== -//============================================================================== -// Keyboard - -#define KEY_LEFT_CTRL 0x80 -#define KEY_LEFT_SHIFT 0x81 -#define KEY_LEFT_ALT 0x82 -#define KEY_LEFT_GUI 0x83 -#define KEY_RIGHT_CTRL 0x84 -#define KEY_RIGHT_SHIFT 0x85 -#define KEY_RIGHT_ALT 0x86 -#define KEY_RIGHT_GUI 0x87 - -#define KEY_UP_ARROW 0xDA -#define KEY_DOWN_ARROW 0xD9 -#define KEY_LEFT_ARROW 0xD8 -#define KEY_RIGHT_ARROW 0xD7 -#define KEY_BACKSPACE 0xB2 -#define KEY_TAB 0xB3 -#define KEY_RETURN 0xB0 -#define KEY_ESC 0xB1 -#define KEY_INSERT 0xD1 -#define KEY_DELETE 0xD4 -#define KEY_PAGE_UP 0xD3 -#define KEY_PAGE_DOWN 0xD6 -#define KEY_HOME 0xD2 -#define KEY_END 0xD5 -#define KEY_CAPS_LOCK 0xC1 -#define KEY_F1 0xC2 -#define KEY_F2 0xC3 -#define KEY_F3 0xC4 -#define KEY_F4 0xC5 -#define KEY_F5 0xC6 -#define KEY_F6 0xC7 -#define KEY_F7 0xC8 -#define KEY_F8 0xC9 -#define KEY_F9 0xCA -#define KEY_F10 0xCB -#define KEY_F11 0xCC -#define KEY_F12 0xCD - -// HID Consumer Usage IDs (subset of the codes available in the USB HID Usage -// Tables spec) -#define HID_CONSUMER_POWER 48 // 0x30 - Power -#define HID_CONSUMER_RESET 49 // 0x31 - Reset -#define HID_CONSUMER_SLEEP 50 // 0x32 - Sleep - -#define HID_CONSUMER_MENU 64 // 0x40 - Menu -#define HID_CONSUMER_SELECTION 128 // 0x80 - Selection -#define HID_CONSUMER_ASSIGN_SEL 129 // 0x81 - Assign Selection -#define HID_CONSUMER_MODE_STEP 130 // 0x82 - Mode Step -#define HID_CONSUMER_RECALL_LAST 131 // 0x83 - Recall Last -#define HID_CONSUMER_QUIT 148 // 0x94 - Quit -#define HID_CONSUMER_HELP 149 // 0x95 - Help -#define HID_CONSUMER_CHANNEL_UP 156 // 0x9C - Channel Increment -#define HID_CONSUMER_CHANNEL_DOWN 157 // 0x9D - Channel Decrement - -#define HID_CONSUMER_PLAY 176 // 0xB0 - Play -#define HID_CONSUMER_PAUSE 177 // 0xB1 - Pause -#define HID_CONSUMER_RECORD 178 // 0xB2 - Record -#define HID_CONSUMER_FAST_FORWARD 179 // 0xB3 - Fast Forward -#define HID_CONSUMER_REWIND 180 // 0xB4 - Rewind -#define HID_CONSUMER_SCAN_NEXT_TRK 181 // 0xB5 - Scan Next Track -#define HID_CONSUMER_SCAN_PREV_TRK 182 // 0xB6 - Scan Previous Track -#define HID_CONSUMER_STOP 183 // 0xB7 - Stop -#define HID_CONSUMER_EJECT 184 // 0xB8 - Eject -#define HID_CONSUMER_RANDOM_PLAY 185 // 0xB9 - Random Play -#define HID_CONSUMER_SELECT_DISC 186 // 0xBA - Select Disk -#define HID_CONSUMER_ENTER_DISC 187 // 0xBB - Enter Disc -#define HID_CONSUMER_REPEAT 188 // 0xBC - Repeat -#define HID_CONSUMER_STOP_EJECT 204 // 0xCC - Stop/Eject -#define HID_CONSUMER_PLAY_PAUSE 205 // 0xCD - Play/Pause -#define HID_CONSUMER_PLAY_SKIP 206 // 0xCE - Play/Skip - -#define HID_CONSUMER_VOLUME 224 // 0xE0 - Volume -#define HID_CONSUMER_BALANCE 225 // 0xE1 - Balance -#define HID_CONSUMER_MUTE 226 // 0xE2 - Mute -#define HID_CONSUMER_BASS 227 // 0xE3 - Bass -#define HID_CONSUMER_VOLUME_UP 233 // 0xE9 - Volume Increment -#define HID_CONSUMER_VOLUME_DOWN 234 // 0xEA - Volume Decrement - -// HID Consumer Control keycodes (based on the HID Report Map characteristic -// value) -#define HID_CC_RPT_MUTE 1 -#define HID_CC_RPT_POWER 2 -#define HID_CC_RPT_LAST 3 -#define HID_CC_RPT_ASSIGN_SEL 4 -#define HID_CC_RPT_PLAY 5 -#define HID_CC_RPT_PAUSE 6 -#define HID_CC_RPT_RECORD 7 -#define HID_CC_RPT_FAST_FWD 8 -#define HID_CC_RPT_REWIND 9 -#define HID_CC_RPT_SCAN_NEXT_TRK 10 -#define HID_CC_RPT_SCAN_PREV_TRK 11 -#define HID_CC_RPT_STOP 12 - -#define HID_CC_RPT_CHANNEL_UP 0x01 -#define HID_CC_RPT_CHANNEL_DOWN 0x03 -#define HID_CC_RPT_VOLUME_UP 0x40 -#define HID_CC_RPT_VOLUME_DOWN 0x80 - -// HID Consumer Control report bitmasks -#define HID_CC_RPT_NUMERIC_BITS 0xF0 -#define HID_CC_RPT_CHANNEL_BITS 0xCF -#define HID_CC_RPT_VOLUME_BITS 0x3F -#define HID_CC_RPT_BUTTON_BITS 0xF0 -#define HID_CC_RPT_SELECTION_BITS 0xCF - -#define HID_KEYBOARD_1 30 // 0x1E - Keyboard 1 and ! -#define HID_KEYBOARD_0 39 // 0x27 - Keyboard 0 and ) - -// Low level key report: up to 6 keys and shift, ctrl etc at once -typedef struct { - uint8_t modifiers; - uint8_t reserved; - uint8_t keys[6]; -} BeanKeyReport; - -class BeanKeyboard_ : public Print { - private: - BeanKeyReport _keyReport; - void sendReport(BeanKeyReport* keys); - - public: - BeanKeyboard_(void); - void begin(void); - void end(void); - void sendCC(uint8_t command); - - virtual size_t write(uint8_t k); - virtual size_t press(uint8_t k); - virtual size_t release(uint8_t k); - virtual void releaseAll(void); -}; -extern BeanKeyboard_ BeanKeyboard; - -//============================================================================== -//============================================================================== -// Low level API - -typedef struct { - uint8_t bmRequestType; - uint8_t bRequest; - uint8_t wValueL; - uint8_t wValueH; - uint16_t wIndex; - uint16_t wLength; -} Setup; - -#endif /* if defined(BeanHID) */ diff --git a/hardware/bean/avr/cores/bean/BeanSerialTransport.cpp b/hardware/bean/avr/cores/bean/BeanSerialTransport.cpp index 26f0ef4..01fc663 100644 --- a/hardware/bean/avr/cores/bean/BeanSerialTransport.cpp +++ b/hardware/bean/avr/cores/bean/BeanSerialTransport.cpp @@ -6,19 +6,20 @@ #include "BeanSerialTransport.h" + // There is a compiler or hardware bug(?) that causes // HardwareSerial::write() to lock the Serial Port unless // it is explicitely called with a uint8_t. // I've copied the #defines into uint8_t types to ensure that // HardwareSerial::write() isn't called with a #define by mistake. -const uint8_t BEAN_SOF = UT_CHAR_START; -const uint8_t BEAN_EOF = UT_CHAR_END; -const uint8_t BEAN_ESCAPE = UT_CHAR_ESC; -const uint8_t BEAN_ESCAPE_XOR = HDLC_ESCAPE_XOR; +const uint8_t BEAN_SOF = UT_CHAR_START; +const uint8_t BEAN_EOF = UT_CHAR_END; +const uint8_t BEAN_ESCAPE = UT_CHAR_ESC; +const uint8_t BEAN_ESCAPE_XOR = HDLC_ESCAPE_XOR; static uint8_t m_ccSleepPinVal = LOW; -static const uint16_t BEAN_MIN_ADVERTISING_INT_MS = 20; // ms -static const uint16_t BEAN_MAX_ADVERTISING_INT_MS = 1285; // ms +static const uint16_t BEAN_MIN_ADVERTISING_INT_MS = 20; // ms +static const uint16_t BEAN_MAX_ADVERTISING_INT_MS = 1285; // ms #define MAX_BODY_LENGTH (APP_MSG_MAX_LENGTH - 2) @@ -37,21 +38,16 @@ static const uint16_t BEAN_MAX_ADVERTISING_INT_MS = 1285; // ms #endif #endif -ring_buffer midi_buffer = {{0}, 0, 0}; -ring_buffer ancs_buffer = {{0}, 0, 0}; -ring_buffer ancs_message_buffer = {{0}, 0, 0}; -ring_buffer observer_message = {{0}, 0, 0}; -ring_buffer rx_buffer = {{0}, 0, 0}; -ring_buffer tx_buffer = {{0}, 0, 0}; -ring_buffer reply_buffer = {{0}, 0, 0}; + +ring_buffer rx_buffer = { { 0 }, 0, 0}; +ring_buffer tx_buffer = { { 0 }, 0, 0}; +ring_buffer reply_buffer = { { 0 }, 0, 0}; static volatile bool tx_buffer_flushed = true; static volatile bool serial_message_complete = false; -static volatile bool observer_message_sending = false; -static volatile int observer_msg_len = 0; -static inline void store_char(unsigned char c, ring_buffer *buffer) { +static inline void store_char(unsigned char c, ring_buffer *buffer){ unsigned int i = (buffer->head + 1) % SERIAL_BUFFER_SIZE; // if we should be storing the received character into the location @@ -64,7 +60,8 @@ static inline void store_char(unsigned char c, ring_buffer *buffer) { } } -static bool rx_char(uint8_t *c) { + +static bool rx_char(uint8_t *c){ #if defined(UDR0) if (bit_is_clear(UCSR0A, UPE0)) { *c = UDR0; @@ -72,7 +69,7 @@ static bool rx_char(uint8_t *c) { } else { *c = UDR0; return false; - } + }; #elif defined(UDR) if (bit_is_clear(UCSRA, PE)) { *c = UDR; @@ -80,179 +77,172 @@ static bool rx_char(uint8_t *c) { } else { *c = UDR; return false; - } + }; #else -#error UDR not defined + #error UDR not defined #endif } + #if !defined(USART0_RX_vect) && defined(USART1_RX_vect) // do nothing - on the 32u4 the first USART is USART1 #else #if !defined(USART_RX_vect) && !defined(USART0_RX_vect) && \ !defined(USART_RXC_vect) -#error "Don't know what the Data Received vector is called for the first UART" + #error "Don't know what the Data Received vector is called for the first UART" #else -void serialEvent() __attribute__((weak)); -void serialEvent() {} -#define serialEvent_implemented + void serialEvent() __attribute__((weak)); + void serialEvent() {} + #define serialEvent_implemented #if defined(USART_RX_vect) -ISR(USART_RX_vect) + ISR(USART_RX_vect) #elif defined(USART0_RX_vect) -ISR(USART0_RX_vect) + ISR(USART0_RX_vect) #elif defined(USART_RXC_vect) -ISR(USART_RXC_vect) // ATmega8 + ISR(USART_RXC_vect) // ATmega8 #endif -{ - // DECLARATIONS - static enum { - WAITING_FOR_SOF, - GETTING_LENGTH, - GETTING_MESSAGE_ID_1, - GETTING_MESSAGE_ID_2, - GETTING_MESSAGE_BODY, - GETTING_EOF - } bean_transport_state = WAITING_FOR_SOF; - - static bool escaping = false; - static uint16_t messageType = MSG_ID_SERIAL_DATA; - static uint8_t messageRemaining = 0; - static uint8_t messageCur = 0; - - // buffer - static ring_buffer *buffer = NULL; - - uint8_t next; - if (!rx_char(&next)) { - return; - } - - // only handle escape char in message - if (bean_transport_state != WAITING_FOR_SOF) { - if (escaping == true) { - next ^= BEAN_ESCAPE_XOR; - } else if (escaping == false && next == BEAN_ESCAPE) { - escaping = true; + { + + // DECLARATIONS + static enum { + WAITING_FOR_SOF, + GETTING_LENGTH, + GETTING_MESSAGE_ID_1, + GETTING_MESSAGE_ID_2, + GETTING_MESSAGE_BODY, + GETTING_EOF + } bean_transport_state = WAITING_FOR_SOF; + + static bool escaping = false; + static uint16_t messageType = MSG_ID_SERIAL_DATA; + static uint8_t messageRemaining = 0; + static uint8_t messageCur = 0; + + // buffer + static ring_buffer* buffer = NULL; + + uint8_t next; + if(!rx_char(&next)){ return; } - } - if (escaping == false) { - if ((next == BEAN_SOF && bean_transport_state != WAITING_FOR_SOF) || - (next == BEAN_EOF && bean_transport_state != GETTING_EOF) || - next == BEAN_ESCAPE) { - // RESET STATE - escaping = false; - messageType = WAITING_FOR_SOF; - messageRemaining = 0; - messageCur = 0; - buffer = NULL; - serial_message_complete = false; - return; + // only handle escape char in message + if(bean_transport_state != WAITING_FOR_SOF){ + if(escaping == true){ + next ^= BEAN_ESCAPE_XOR; + } + else if(escaping == false && next == BEAN_ESCAPE){ + escaping = true; + return; + } } - } - escaping = false; + if(escaping == false){ + if((next == BEAN_SOF && bean_transport_state != WAITING_FOR_SOF) || + ( next == BEAN_EOF && bean_transport_state != GETTING_EOF) || + next == BEAN_ESCAPE){ + + // TODO: How to Signal Error? + // assert(1); - switch (bean_transport_state) { - case WAITING_FOR_SOF: - if (next == BEAN_SOF) { - bean_transport_state = GETTING_LENGTH; + // RESET STATE + escaping = false; + messageType = WAITING_FOR_SOF; + messageRemaining = 0; + messageCur = 0; + buffer = NULL; serial_message_complete = false; + + + return; } + } - break; + escaping = false; - case GETTING_LENGTH: - messageRemaining = next; - bean_transport_state = GETTING_MESSAGE_ID_1; - observer_msg_len = next; // we don't have message type yet, but save the - // length for later - break; + switch(bean_transport_state){ + case WAITING_FOR_SOF: + if(next == BEAN_SOF){ + bean_transport_state = GETTING_LENGTH; + serial_message_complete = false; + } - case GETTING_MESSAGE_ID_1: - messageType = ((unsigned int)next) << 8; - messageRemaining--; - bean_transport_state = GETTING_MESSAGE_ID_2; - break; + break; - case GETTING_MESSAGE_ID_2: - messageType |= next; - messageRemaining--; - - if (messageType == MSG_ID_MIDI_READ) { - buffer = &midi_buffer; - } else if (messageType == MSG_ID_ANCS_READ) { - buffer = &ancs_buffer; - } else if (messageType == MSG_ID_ANCS_GET_NOTI) { - buffer = &ancs_message_buffer; - } else if (messageType == MSG_ID_OBSERVER_READ) { - buffer = &observer_message; - observer_message_sending = true; - observer_message.head = observer_message.tail = - 0; // if the user missed a previous message drop it - } else { - buffer = - (messageType == MSG_ID_SERIAL_DATA) ? &rx_buffer : &reply_buffer; - } + case GETTING_LENGTH: + messageRemaining = next; + bean_transport_state = GETTING_MESSAGE_ID_1; + break; - if (messageRemaining > 0) { - bean_transport_state = GETTING_MESSAGE_BODY; - } else { - bean_transport_state = GETTING_EOF; - } - break; + case GETTING_MESSAGE_ID_1: + messageType = ((unsigned int) next) << 8; + messageRemaining--; + bean_transport_state = GETTING_MESSAGE_ID_2; + break; - case GETTING_MESSAGE_BODY: - if (buffer) { - store_char(next, buffer); + case GETTING_MESSAGE_ID_2: + messageType |= next; messageRemaining--; - } - if (messageRemaining == 0) { - bean_transport_state = GETTING_EOF; - } - break; + buffer = (messageType == MSG_ID_SERIAL_DATA) ? &rx_buffer : &reply_buffer; - case GETTING_EOF: - // RESET STATE - if (messageType == MSG_ID_MIDI_READ) { - for (int i = 0; i < 3; i++) - store_char( - 0, buffer); // null message to specify the end of a btle packet - } - if (messageType == MSG_ID_OBSERVER_READ) { - observer_message_sending = false; - } - serial_message_complete = true; - bean_transport_state = WAITING_FOR_SOF; - messageType = MSG_ID_SERIAL_DATA; - messageRemaining = 0; - messageCur = 0; - buffer = NULL; + if(messageRemaining > 0){ + bean_transport_state = GETTING_MESSAGE_BODY; + } + else { + bean_transport_state = GETTING_EOF; + } + + break; + + + case GETTING_MESSAGE_BODY: + if(buffer){ + store_char(next, buffer); + messageRemaining--; + } + + if(messageRemaining == 0){ + bean_transport_state = GETTING_EOF; + } break; + + case GETTING_EOF: + // TODO: How to Signal Error? + // if(next != BEAN_EOF){ + // assert(1); + // } + // RESET STATE + serial_message_complete = true; + bean_transport_state = WAITING_FOR_SOF; + messageType = MSG_ID_SERIAL_DATA; + messageRemaining = 0; + messageCur = 0; + buffer = NULL; + break; + } } -} #endif #endif + + // The Original HWSerial version of this function // relies on the TX Vector flag to tell when tx_buffer_flushed. // we need that flag to fire the interrupt (auto-clears, and cannot be manually -// set) pin for the CC, so for BeanSerial we use 'tx_buffer_flushed' bool -// instead. -void BeanSerialTransport::flush() { +// set) pin for the CC, so for BeanSerial we use 'tx_buffer_flushed' bool instead. +void BeanSerialTransport::flush() +{ // logic is handled in writes and interrupts - while (tx_buffer_flushed == false) - {} + while (tx_buffer_flushed == false); // this is a holdover from HWSerial. transmitting = false; } // This interrupt fires after the send has completed -ISR(USART_TX_vect) { +ISR(USART_TX_vect){ // lower interrupt line that wakes The CC if (tx_buffer.head == tx_buffer.tail) { digitalWrite(CC_INTERRUPT_PIN, m_ccSleepPinVal); @@ -263,7 +253,8 @@ ISR(USART_TX_vect) { // This interrupt fires after the send register as offloaded the data // to the send hardware. -ISR(USART_UDRE_vect) { +ISR(USART_UDRE_vect) +{ if (tx_buffer.head == tx_buffer.tail) { // Buffer empty, so disable interrupts cbi(UCSR0B, UDRIE0); @@ -271,41 +262,41 @@ ISR(USART_UDRE_vect) { // enable the tx sent interrupt so we can disable the // CC interrupt pin sbi(UCSR0B, TXCIE0); - } else { + } + else { // There is more data in the output buffer. Send the next byte unsigned char c = tx_buffer.buffer[tx_buffer.tail]; tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE; -#if defined(UDR0) + #if defined(UDR0) UDR0 = c; -#elif defined(UDR) + #elif defined(UDR) UDR = c; -#else -#error UDR not defined -#endif + #else + #error UDR not defined + #endif } } // Called in main, before setup, to enable things such as setting the LED // color during setup. -void BeanSerialTransport::begin(void) { +void BeanSerialTransport::begin(void){ HardwareSerial::begin(38400); pinMode(CC_INTERRUPT_PIN, OUTPUT); - digitalWrite(CC_INTERRUPT_PIN, LOW); m_enableSave = true; - if (tx_buffer.head == tx_buffer.tail) { + if (tx_buffer.head == tx_buffer.tail){ tx_buffer_flushed = true; digitalWrite(CC_INTERRUPT_PIN, m_ccSleepPinVal); } } -inline void BeanSerialTransport::insert_escaped_char(uint8_t input) { +inline void BeanSerialTransport::insert_escaped_char(uint8_t input){ // It's crucial that HardwareSerial::write is only called // with excplicit uint8_t types otherwise weird overloading // happens, and things you don't expect result - switch (input) { + switch(input){ case BEAN_SOF: // fallthrough case BEAN_EOF: // fallthrough case BEAN_ESCAPE: @@ -320,23 +311,29 @@ inline void BeanSerialTransport::insert_escaped_char(uint8_t input) { } } -void BeanSerialTransport::BTConfigUartSleep(UART_SLEEP_MODE_T mode) { - if (UART_SLEEP_NORMAL == mode) { - m_wakeDelay = UART_DEFAULT_WAKE_WAIT; - m_enforcedDelay = UART_DEFAULT_SEND_WAIT; - m_ccSleepPinVal = LOW; - } else if (UART_SLEEP_NEVER == mode) { - m_wakeDelay = 0; - m_enforcedDelay = 0; - m_ccSleepPinVal = HIGH; - digitalWrite(CC_INTERRUPT_PIN, HIGH); - } +void BeanSerialTransport::BTConfigUartSleep(UART_SLEEP_MODE_T mode) +{ + if ( UART_SLEEP_NORMAL == mode ) + { + m_wakeDelay = UART_DEFAULT_WAKE_WAIT; + m_enforcedDelay = UART_DEFAULT_SEND_WAIT; + m_ccSleepPinVal = LOW; + } + else if ( UART_SLEEP_NEVER == mode ) + { + m_wakeDelay = 0; + m_enforcedDelay = 0; + m_ccSleepPinVal = HIGH; + digitalWrite(CC_INTERRUPT_PIN, HIGH); + } } size_t BeanSerialTransport::write_message(uint16_t messageId, const uint8_t *body, - size_t body_length) { - if (body_length > MAX_BODY_LENGTH) { + size_t body_length){ + if(body_length > MAX_BODY_LENGTH){ + // TODO: do we want to throw an error, or somehow + // note why we were forced to drop the message? return -1; } @@ -348,28 +345,35 @@ size_t BeanSerialTransport::write_message(uint16_t messageId, if (tx_buffer.head == tx_buffer.tail && m_wakeDelay > 0) { delay(m_wakeDelay); } + HardwareSerial::write(BEAN_SOF); - // body_length + "2" for message type. + //body_length + "2" for message type. insert_escaped_char(body_length + 2); insert_escaped_char((uint8_t)(messageId >> 8)); insert_escaped_char((uint8_t)(messageId & 0xFF)); - for (uint8_t i = 0; i < body_length; i++) { + for(uint8_t i = 0; i < body_length; i++){ insert_escaped_char(body[i]); } HardwareSerial::write(BEAN_EOF); + // throttle the transfer speed - if (m_enforcedDelay > 0) { + if ( m_enforcedDelay > 0 ) + { delay(m_enforcedDelay); } return body_length; } -int BeanSerialTransport::call_and_response( - MSG_ID_T messageId, const uint8_t *body, size_t body_length, - uint8_t *response, size_t *response_length, unsigned long timeout_ms) { + +int BeanSerialTransport::call_and_response(MSG_ID_T messageId, + const uint8_t *body, + size_t body_length, + uint8_t * response, + size_t * response_length, + unsigned long timeout_ms){ noInterrupts(); // clear our rx buffer to ensure that we don't read some old message out of it _reply_buffer->head = _reply_buffer->tail = 0; @@ -378,14 +382,12 @@ int BeanSerialTransport::call_and_response( // send our message write_message(messageId, body, body_length); - // wait for RX to hold an EOF, and then return the data + //wait for RX to hold an EOF, and then return the data _startMillis = millis(); - do { - } while (*_message_complete == false && - (millis() - _startMillis < timeout_ms)); + do {} while (*_message_complete == false && (millis() - _startMillis < timeout_ms)); - if (*_message_complete) { + if(*_message_complete){ // copy the message body into out memcpy(response, _reply_buffer->buffer, min(_reply_buffer->head, *response_length)); @@ -397,432 +399,269 @@ int BeanSerialTransport::call_and_response( return -1; } + ///////// /// Radio ///////// -void BeanSerialTransport::BTSetAdvertisingOnOff(const bool setting, - uint32_t timer) { - BT_ADV_ONOFF_T advOnOff; - advOnOff.adv_timer = timer; - advOnOff.adv_onOff = setting ? 1 : 0; - write_message(MSG_ID_BT_ADV_ONOFF, (const uint8_t *)&advOnOff, - sizeof(advOnOff)); -} + void BeanSerialTransport::BTSetAdvertisingOnOff(const bool setting, uint32_t timer){ + BT_ADV_ONOFF_T advOnOff; + advOnOff.adv_timer = timer; + advOnOff.adv_onOff = setting ? 1 : 0; + write_message(MSG_ID_BT_ADV_ONOFF, (const uint8_t*)&advOnOff, sizeof(advOnOff)); + }; + + void BeanSerialTransport::BTSetLocalName(const char* name){ + if(name == NULL) + name = ""; + + size_t length = strlen(name); + if ( length > 20 ) + { + length = 20; + } -void BeanSerialTransport::BTSetLocalName(const char *name) { - if (name == NULL) name = ""; + BT_RADIOCONFIG_T radioConfig; + size_t size = sizeof(BT_RADIOCONFIG_T); + int response = call_and_response(MSG_ID_BT_GET_CONFIG, NULL, 0, (uint8_t *)&radioConfig, &size ); - size_t length = strlen(name); - if (length > 20) { - length = 20; - } + if ( 0 == response ) + { + memcpy( (void*)radioConfig.local_name, (void*)name, length ); + radioConfig.local_name_size = length; - BT_RADIOCONFIG_T radioConfig; - size_t size = sizeof(BT_RADIOCONFIG_T); - int response = call_and_response(MSG_ID_BT_GET_CONFIG, NULL, 0, - (uint8_t *)&radioConfig, &size); + uint16_t msgId = ( m_enableSave ? MSG_ID_BT_SET_CONFIG: MSG_ID_BT_SET_CONFIG_NOSAVE ); - if (0 == response) { - memcpy((void *)radioConfig.local_name, (void *)name, length); - radioConfig.local_name_size = length; + write_message(msgId, (const uint8_t*)&radioConfig, size); + } - uint16_t msgId = - (m_enableSave ? MSG_ID_BT_SET_CONFIG : MSG_ID_BT_SET_CONFIG_NOSAVE); + }; - write_message(msgId, (const uint8_t *)&radioConfig, size); + int BeanSerialTransport::BTGetStates(BT_STATES_T * btStates ) + { + size_t length = sizeof(BT_STATES_T); + return call_and_response(MSG_ID_BT_GET_STATES, NULL, + (size_t)0, (uint8_t*)btStates, &length); } -} -int BeanSerialTransport::BTGetStates(BT_STATES_T *btStates) { - size_t length = sizeof(BT_STATES_T); - return call_and_response(MSG_ID_BT_GET_STATES, NULL, (size_t)0, - (uint8_t *)btStates, &length); -} + void BeanSerialTransport::BTSetPairingPin(const uint16_t pin){ + write_message(MSG_ID_BT_SET_PIN, (const uint8_t*)&pin, sizeof(pin)); + }; + -void BeanSerialTransport::BTSetPairingPin(const uint16_t pin) { - write_message(MSG_ID_BT_SET_PIN, (const uint8_t *)&pin, sizeof(pin)); -} -void BeanSerialTransport::BTSetAdvertisingInterval(uint16_t interval_ms) { - if (interval_ms < BEAN_MIN_ADVERTISING_INT_MS) { +void BeanSerialTransport::BTSetAdvertisingInterval( uint16_t interval_ms){ + if(interval_ms < BEAN_MIN_ADVERTISING_INT_MS) + { interval_ms = BEAN_MIN_ADVERTISING_INT_MS; - } else if (interval_ms > BEAN_MAX_ADVERTISING_INT_MS) { + } + else if(interval_ms > BEAN_MAX_ADVERTISING_INT_MS) + { interval_ms = BEAN_MAX_ADVERTISING_INT_MS; } - BT_RADIOCONFIG_T radioConfig; - size_t size = sizeof(BT_RADIOCONFIG_T); - int response = call_and_response(MSG_ID_BT_GET_CONFIG, NULL, 0, - (uint8_t *)&radioConfig, &size); + BT_RADIOCONFIG_T radioConfig; + size_t size = sizeof(BT_RADIOCONFIG_T); + int response = call_and_response(MSG_ID_BT_GET_CONFIG, NULL, 0, (uint8_t *)&radioConfig, &size ); - if (0 == response) { - radioConfig.adv_int = (uint16_t)interval_ms; + if ( 0 == response ) + { + radioConfig.adv_int = (uint16_t)interval_ms; - uint16_t msgId = - (m_enableSave ? MSG_ID_BT_SET_CONFIG : MSG_ID_BT_SET_CONFIG_NOSAVE); + uint16_t msgId = ( m_enableSave ? MSG_ID_BT_SET_CONFIG: MSG_ID_BT_SET_CONFIG_NOSAVE ); - write_message(msgId, (const uint8_t *)&radioConfig, size); - } + write_message(msgId, (const uint8_t*)&radioConfig, size); + } } -void BeanSerialTransport::BTSetConnectionInterval(const int interval_ms) { - write_message(MSG_ID_BT_SET_CONN, (const uint8_t *)&interval_ms, sizeof(int)); -} -void BeanSerialTransport::BTSetTxPower(const BT_TXPOWER_DB_T &power) { - write_message(MSG_ID_BT_SET_TX_PWR, (const uint8_t *)&power, - sizeof(BT_TXPOWER_DB_T)); +void BeanSerialTransport::BTSetConnectionInterval(const int interval_ms){ + write_message(MSG_ID_BT_SET_CONN, (const uint8_t*)&interval_ms, sizeof(int)); } -void BeanSerialTransport::BTSetScratchChar(BT_SCRATCH_T *setting, - uint8_t length) { - write_message(MSG_ID_BT_SET_SCRATCH, (uint8_t *)setting, (size_t)length); + +void BeanSerialTransport::BTSetTxPower(const BT_TXPOWER_DB_T& power){ + write_message(MSG_ID_BT_SET_TX_PWR, (const uint8_t*)&power, sizeof(BT_TXPOWER_DB_T)); } -int BeanSerialTransport::BTGetScratchChar(uint8_t scratchNum, - ScratchData *scratchData) { +void BeanSerialTransport::BTSetScratchChar(BT_SCRATCH_T* setting, uint8_t length){ + write_message(MSG_ID_BT_SET_SCRATCH, (uint8_t*)setting, (size_t)length); +}; + +int BeanSerialTransport::BTGetScratchChar(uint8_t scratchNum, ScratchData * scratchData){ int rtnVal; size_t lengthSt = sizeof(BT_SCRATCH_T); uint8_t buffer[1] = {scratchNum}; - rtnVal = call_and_response(MSG_ID_BT_GET_SCRATCH, buffer, (size_t)1, - (uint8_t *)scratchData, &lengthSt); + rtnVal = call_and_response(MSG_ID_BT_GET_SCRATCH, buffer, + (size_t)1, (uint8_t*)scratchData, &lengthSt); // magic: -1 for length byte scratchData->length = (uint8_t)lengthSt - 1; return rtnVal; -} +}; -int BeanSerialTransport::BTGetConfig(BT_RADIOCONFIG_T *config) { +int BeanSerialTransport::BTGetConfig(BT_RADIOCONFIG_T *config){ size_t size = sizeof(BT_RADIOCONFIG_T); - return call_and_response(MSG_ID_BT_GET_CONFIG, NULL, 0, (uint8_t *)config, - &size); -} + return call_and_response(MSG_ID_BT_GET_CONFIG, NULL, + 0, (uint8_t *) config, &size); +}; -void BeanSerialTransport::BTBeaconModeEnable(bool beaconEnable) { +void BeanSerialTransport::BTBeaconModeEnable( bool beaconEnable ) +{ BT_RADIOCONFIG_T radioConfig; size_t size = sizeof(BT_RADIOCONFIG_T); - int response = call_and_response(MSG_ID_BT_GET_CONFIG, NULL, 0, - (uint8_t *)&radioConfig, &size); + int response = call_and_response(MSG_ID_BT_GET_CONFIG, NULL, 0, (uint8_t *)&radioConfig, &size ); - if (0 == response) { - radioConfig.adv_mode = (beaconEnable ? ADV_IBEACON : ADV_STANDARD); - uint16_t msgId = - (m_enableSave ? MSG_ID_BT_SET_CONFIG : MSG_ID_BT_SET_CONFIG_NOSAVE); + if ( 0 == response ) + { + radioConfig.adv_mode = ( beaconEnable ? ADV_IBEACON : ADV_STANDARD); + uint16_t msgId = ( m_enableSave ? MSG_ID_BT_SET_CONFIG : MSG_ID_BT_SET_CONFIG_NOSAVE ); - write_message(msgId, (const uint8_t *)&radioConfig, size); + write_message(msgId, (const uint8_t*)&radioConfig, + size); } } -void BeanSerialTransport::BTSetBeaconParams(uint16_t uuid, uint16_t majorid, - uint16_t minorid) { +void BeanSerialTransport::BTSetBeaconParams(uint16_t uuid, uint16_t majorid, uint16_t minorid ) +{ BT_RADIOCONFIG_T radioConfig; size_t size = sizeof(BT_RADIOCONFIG_T); - int response = call_and_response(MSG_ID_BT_GET_CONFIG, NULL, 0, - (uint8_t *)&radioConfig, &size); + int response = call_and_response(MSG_ID_BT_GET_CONFIG, NULL, 0, (uint8_t *)&radioConfig, &size ); - if (0 == response) { + if ( 0 == response ) + { radioConfig.ibeacon_uuid = uuid; radioConfig.ibeacon_major = majorid; radioConfig.ibeacon_minor = minorid; - uint16_t msgId = - (m_enableSave ? MSG_ID_BT_SET_CONFIG : MSG_ID_BT_SET_CONFIG_NOSAVE); + uint16_t msgId = ( m_enableSave ? MSG_ID_BT_SET_CONFIG : MSG_ID_BT_SET_CONFIG_NOSAVE ); - write_message(msgId, (const uint8_t *)&radioConfig, size); + write_message(msgId, (const uint8_t*)&radioConfig, + size); } + } //////// // LED //////// -void BeanSerialTransport::ledSetSingle(const LED_IND_SETTING_T &setting) { - write_message(MSG_ID_CC_LED_WRITE, (const uint8_t *)&setting, - sizeof(setting)); +void BeanSerialTransport::ledSetSingle(const LED_IND_SETTING_T &setting){ + write_message(MSG_ID_CC_LED_WRITE, (const uint8_t *)&setting, sizeof(setting)); } -void BeanSerialTransport::ledSet(const LED_SETTING_T &setting) { - write_message(MSG_ID_CC_LED_WRITE_ALL, (const uint8_t *)&setting, - sizeof(setting)); +void BeanSerialTransport::ledSet(const LED_SETTING_T &setting){ + write_message(MSG_ID_CC_LED_WRITE_ALL, (const uint8_t *)&setting, sizeof(setting)); } -int BeanSerialTransport::ledRead(LED_SETTING_T *reading) { +int BeanSerialTransport::ledRead(LED_SETTING_T* reading){ size_t size = sizeof(LED_SETTING_T); - return call_and_response(MSG_ID_CC_LED_READ_ALL, NULL, 0, (uint8_t *)reading, - &size); -} - -////// -/// GATT manager -////// - -int BeanSerialTransport::readGATT(ADV_SWITCH_ENABLED_T *reading) { - size_t size = sizeof(ADV_SWITCH_ENABLED_T); - return call_and_response(MSG_ID_GATT_GET_GATT, NULL, 0, (uint8_t *)reading, - &size); -} - -int BeanSerialTransport::writeGATT(ADV_SWITCH_ENABLED_T services) { - write_message(MSG_ID_GATT_SET_GATT, (const uint8_t *)&services, - sizeof(services)); -} - -int BeanSerialTransport::setCustomAdvertisement(uint8_t *buf, int len) { - if (len > 31) { - return -1; - } - uint8_t sendBuf[32]; - sendBuf[0] = len; - memcpy((void *)&sendBuf[1], buf, len); - write_message(MSG_ID_GATT_SET_CUSTOM, sendBuf, len + 1); - return 0; + return call_and_response(MSG_ID_CC_LED_READ_ALL, NULL, + 0, (uint8_t *) reading, &size); } -//////// -/// MIDI -//////// - -char BeanSerialTransport::peekMidi() { - return midi_buffer.buffer[midi_buffer.tail]; -} -size_t BeanSerialTransport::midiAvailable() { - if (midi_buffer.head == midi_buffer.tail) return 0; - if (midi_buffer.head > midi_buffer.tail) - return midi_buffer.head - midi_buffer.tail; - else - return midi_buffer.head + (SERIAL_BUFFER_SIZE - midi_buffer.tail); -} -size_t BeanSerialTransport::readMidi(uint8_t *buffer, size_t max_length) { - size_t bytes_written = 0; - while (midi_buffer.tail != midi_buffer.head) { - if (bytes_written >= max_length) break; - buffer[bytes_written] = midi_buffer.buffer[midi_buffer.tail]; - midi_buffer.tail++; - midi_buffer.tail %= SERIAL_BUFFER_SIZE; - bytes_written++; - } - return bytes_written; -} - -void BeanSerialTransport::midiSend(uint8_t status, uint8_t byte1, - uint8_t byte2) { - uint8_t midi[3]; - midi[0] = status; - midi[1] = byte1; - midi[2] = byte2; - write_message(MSG_ID_MIDI_WRITE, (const uint8_t *)midi, 3); -} - -//////// -// ANCS -//////// - -int BeanSerialTransport::ancsAvailable() { - if (ancs_buffer.head == ancs_buffer.tail) return 0; - if (ancs_buffer.head > ancs_buffer.tail) - return (ancs_buffer.head - ancs_buffer.tail) / 8; - else - return (ancs_buffer.head + (SERIAL_BUFFER_SIZE - ancs_buffer.tail)) / 8; -} - -int BeanSerialTransport::readAncs(uint8_t *buffer, size_t max_length) { - size_t bytes_written = 0; - while (ancs_buffer.tail != ancs_buffer.head) { - if (bytes_written >= max_length) break; - buffer[bytes_written] = ancs_buffer.buffer[ancs_buffer.tail]; - ancs_buffer.tail++; - ancs_buffer.tail %= SERIAL_BUFFER_SIZE; - bytes_written++; - } - return bytes_written; -} - -int BeanSerialTransport::getAncsNotiDetails(uint8_t *buffer, size_t length) { - write_message(MSG_ID_ANCS_GET_NOTI, (const uint8_t *)buffer, length); -} - -int BeanSerialTransport::ancsNotiDetailsAvailable() { - if (ancs_message_buffer.head == ancs_message_buffer.tail) return 0; - if (ancs_message_buffer.head > ancs_message_buffer.tail) - return (ancs_message_buffer.head - ancs_message_buffer.tail) / 8; - else - return (ancs_message_buffer.head + - (SERIAL_BUFFER_SIZE - ancs_message_buffer.tail)) / - 8; -} - -int BeanSerialTransport::readAncsMessage(uint8_t *buffer, size_t max_length) { - size_t bytes_written = 0; - while (ancs_message_buffer.tail != ancs_message_buffer.head) { - if (bytes_written >= max_length) break; - buffer[bytes_written] = - ancs_message_buffer.buffer[ancs_message_buffer.tail]; - ancs_message_buffer.tail++; - ancs_message_buffer.tail %= SERIAL_BUFFER_SIZE; - bytes_written++; - } - return bytes_written; -} - -/////// -// Observer -/////// -int BeanSerialTransport::startObserver() { - write_message(MSG_ID_OBSERVER_START, NULL, 0); -} - -int BeanSerialTransport::stopObserver() { - write_message(MSG_ID_OBSERVER_STOP, NULL, 0); -} - -int BeanSerialTransport::getObserverMessage(OBSERVER_INFO_MESSAGE_T *message, - unsigned long timeout) { - memset(message, 0, sizeof(OBSERVER_INFO_MESSAGE_T)); - - unsigned long startMillis = millis(); - do { - if ((millis() - startMillis > timeout)) return -1; - } while (observer_message_sending == false && - abs(observer_message.head - observer_message.tail) == - 0); // block until advertisement is observed - do { - if ((millis() - startMillis > timeout)) return -1; - } while (observer_message_sending == true); // block until data is sent - - observer_message.head = observer_message.tail = 0; - - // copy the message body into out - memcpy(message, observer_message.buffer, - min(observer_msg_len, sizeof(OBSERVER_INFO_MESSAGE_T))); - return 0; -} //////// // Accelerometer //////// -int BeanSerialTransport::accelRead(ACC_READING_T *reading) { +int BeanSerialTransport::accelRead(ACC_READING_T* reading){ size_t size = sizeof(ACC_READING_T); - return call_and_response(MSG_ID_CC_ACCEL_READ, NULL, (size_t)0, - (uint8_t *)reading, &size); -} - -int BeanSerialTransport::accelRangeRead(uint8_t *range) { - size_t size = sizeof(uint8_t); - return call_and_response(MSG_ID_CC_ACCEL_GET_RANGE, NULL, (size_t)0, - (uint8_t *)range, &size); + return call_and_response(MSG_ID_CC_ACCEL_READ, NULL, + (size_t) 0, (uint8_t *) reading, &size); } -void BeanSerialTransport::accelRangeSet(uint8_t range) { - write_message(MSG_ID_CC_ACCEL_SET_RANGE, (const uint8_t *)&range, - sizeof(range)); -} - -int BeanSerialTransport::accelRegisterRead(uint8_t reg, uint8_t length, - uint8_t *value) { +int BeanSerialTransport::accelRangeRead( uint8_t *range) +{ size_t size = sizeof(uint8_t); - uint8_t payload[2]; - payload[0] = reg; - payload[1] = length; - return call_and_response(MSG_ID_CC_ACCEL_READ_REG, payload, sizeof(payload), - value, &size); + return call_and_response(MSG_ID_CC_ACCEL_GET_RANGE, NULL, + (size_t) 0, (uint8_t *)range, &size); } -void BeanSerialTransport::accelRegisterWrite(uint8_t reg, uint8_t value) { - uint8_t payload[2]; - payload[0] = reg; - payload[1] = value; - write_message(MSG_ID_CC_ACCEL_WRITE_REG, (const uint8_t *)&payload, - sizeof(payload)); -} - -// Bit zero is INT1 pin from Accelerometer, Bit one is INT2 pin from -// Accelerometer (if available) -void BeanSerialTransport::wakeOnAccel(uint8_t int_enable) { - uint8_t payload; - payload = int_enable; - write_message(MSG_ID_CC_WAKE_ON_ACCEL, (const uint8_t *)&payload, - sizeof(payload)); +void BeanSerialTransport::accelRangeSet( uint8_t range ) +{ + write_message(MSG_ID_CC_ACCEL_SET_RANGE, (const uint8_t *)&range, sizeof(range)); } - ///////// // Temperature ///////// -int BeanSerialTransport::temperatureRead(int8_t *tempRead) { +int BeanSerialTransport::temperatureRead( int8_t* tempRead ) +{ size_t size = 1; - return call_and_response(MSG_ID_CC_TEMP_READ, NULL, (size_t)0, - (uint8_t *)tempRead, &size); + return call_and_response( MSG_ID_CC_TEMP_READ, NULL, + (size_t) 0, (uint8_t *) tempRead, &size); } ///////// // Battery Level ///////// -int BeanSerialTransport::batteryRead(uint8_t *level) { +int BeanSerialTransport::batteryRead( uint8_t* level ) +{ size_t size = 1; - return call_and_response(MSG_ID_CC_BATT_READ, NULL, (size_t)0, - (uint8_t *)level, &size); + return call_and_response( MSG_ID_CC_BATT_READ, NULL, + (size_t) 0, (uint8_t *)level, &size ); + } + //////// // Sleep //////// -void BeanSerialTransport::sleep(uint32_t duration_ms) { - write_message(MSG_ID_AR_SLEEP, (const uint8_t *)&duration_ms, - sizeof(duration_ms)); +void BeanSerialTransport::sleep(uint32_t duration_ms){ + write_message(MSG_ID_AR_SLEEP, (const uint8_t *)&duration_ms, sizeof(duration_ms)); } -void BeanSerialTransport::enableWakeOnConnect(bool enable) { - uint8_t enableBuff = (enable == true) ? 1 : 0; +void BeanSerialTransport::enableWakeOnConnect( bool enable ) +{ + uint8_t enableBuff = (enable == true ) ? 1 : 0; - write_message(MSG_ID_AR_WAKE_ON_CONNECT, (const uint8_t *)&enableBuff, - sizeof(enableBuff)); + write_message(MSG_ID_AR_WAKE_ON_CONNECT, (const uint8_t *)&enableBuff, sizeof(enableBuff)); } -// Debug +//Debug bool BeanSerialTransport::debugLoopbackVerify(const uint8_t *message, - const size_t size) { - uint8_t res[size]; // NOLINT(runtime/arrays) - size_t res_size = size; - if (call_and_response(MSG_ID_DB_LOOPBACK, message, size, res, &res_size) != - 0) { + const size_t size){ + uint8_t res[size]; + size_t res_size = size; + if(call_and_response(MSG_ID_DB_LOOPBACK, message, size, res, &res_size) != 0){ return false; } - for (unsigned int i = 0; i < size; i++) { - if (message[i] != res[i]) return false; + for(unsigned int i = 0; i < size; i++){ + if(message[i] != res[i]) + return false; } return true; -} +}; bool BeanSerialTransport::debugEndToEndLoopbackVerify(const uint8_t *message, - const size_t size) { - uint8_t res[size]; // NOLINT(runtime/arrays) - size_t res_size = size; + const size_t size){ + uint8_t res[size]; + size_t res_size = size; // note that we've set the timeout to 250 here and not the default 100ms as // this is going to the phone and back. - if (call_and_response(MSG_ID_DB_E2E_LOOPBACK, message, size, res, &res_size, - 250) != 0) { + if(call_and_response(MSG_ID_DB_E2E_LOOPBACK, message, size, res, &res_size, 250) != 0){ return false; } - for (unsigned int i = 0; i < size; i++) { - if (message[i] != res[i]) return false; + for(unsigned int i = 0; i < size; i++){ + if(message[i] != res[i]) + return false; } return true; -} +}; + -int BeanSerialTransport::debugGetDebugCounter(int *counter) { +int BeanSerialTransport::debugGetDebugCounter(int* counter){ size_t return_size; - return call_and_response(MSG_ID_DB_COUNTER, NULL, 0, (uint8_t *)counter, - &return_size); -} + return call_and_response(MSG_ID_DB_COUNTER, NULL, 0, (uint8_t*)counter, &return_size); +}; -void BeanSerialTransport::debugWritePtm(const uint8_t *message, - const size_t size) { +void BeanSerialTransport::debugWritePtm( const uint8_t *message, const size_t size ) +{ write_message(MSG_ID_DB_PTM, message, size); } @@ -830,46 +669,53 @@ void BeanSerialTransport::debugWritePtm(const uint8_t *message, ///////////////////// ///////////////////// // This is the public write function that is used all the time -size_t BeanSerialTransport::write(uint8_t c) { +size_t BeanSerialTransport::write(uint8_t c) +{ write_message(MSG_ID_SERIAL_DATA, &c, 1); - return 1; + return 1; } -size_t BeanSerialTransport::write(const uint8_t *buffer, size_t size) { - if (buffer == NULL || size == 0) return 0; +size_t BeanSerialTransport::write(const uint8_t *buffer, size_t size) +{ + if(buffer == NULL || size == 0) + return 0; - if (size > MAX_BODY_LENGTH) { + if(size > MAX_BODY_LENGTH){ size_t end = MAX_BODY_LENGTH - 1; size_t start = 0; - while (end <= size) { + while(end <= size){ write_message(MSG_ID_SERIAL_DATA, buffer + start, end - start); - if (end == size) break; + if(end == size) + break; start = end; end = min(end + MAX_BODY_LENGTH, size); } return size; - } else { - return write_message(MSG_ID_SERIAL_DATA, buffer, size); } + else + return write_message(MSG_ID_SERIAL_DATA, buffer, size); } -size_t BeanSerialTransport::print(const String &s) { - return write((uint8_t *)s.c_str(), (size_t)s.length()); +size_t BeanSerialTransport::print(const String &s) +{ + return write((uint8_t*)s.c_str(), (size_t)s.length()); } -size_t BeanSerialTransport::print(const __FlashStringHelper *ifsh) { +size_t BeanSerialTransport::print(const __FlashStringHelper *ifsh) +{ uint8_t buffer[MAX_BODY_LENGTH]; const char PROGMEM *p = (const char PROGMEM *)ifsh; size_t n = 0; - if (ifsh == NULL) return 0; + if(ifsh == NULL) + return 0; while (1) { unsigned char c = pgm_read_byte(p++); if (c == 0) break; buffer[n++] = c; - if (n == MAX_BODY_LENGTH) { + if(n == MAX_BODY_LENGTH){ write_message(MSG_ID_SERIAL_DATA, buffer, n); n = 0; } @@ -878,44 +724,47 @@ size_t BeanSerialTransport::print(const __FlashStringHelper *ifsh) { return n; } -void BeanSerialTransport::debugLoopBackFullSerialMessages() { + +void BeanSerialTransport::debugLoopBackFullSerialMessages(){ setTimeout(0); char buffer[APP_MSG_MAX_LENGTH + 1]; - while (1) { + while(1){ *_message_complete = false; - // wait for RX to hold an EOF, and then return the data - while (*_message_complete == false) { + //wait for RX to hold an EOF, and then return the data + while(*_message_complete == false){ // BLOCK UNTIL WE GET THE ENTIRE RESPONSE + // TODO -- Timeout this? } size_t length = APP_MSG_MAX_LENGTH + 1; length = readBytes(buffer, length); - write((uint8_t *)buffer, length); + write((uint8_t*)buffer, length); } } -void BeanSerialTransport::BTSetEnableConfigSave(bool enableSave) { +void BeanSerialTransport::BTSetEnableConfigSave(bool enableSave) +{ m_enableSave = enableSave; } -void BeanSerialTransport::BTDisconnect(void) { - write_message(MSG_ID_BT_DISCONNECT, NULL, 0); +void BeanSerialTransport::BTDisconnect(void) +{ + write_message(MSG_ID_BT_DISCONNECT, NULL, 0); } -// Preinstantiate Objects ////////////////////////////////////////////////////// +//Preinstantiate Objects ////////////////////////////////////////////////////// #if defined(UBRRH) && defined(UBRRL) -BeanSerialTransport Serial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, - &UCSRB, &UCSRC, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X, - &reply_buffer, &serial_message_complete); + BeanSerialTransport Serial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, + &UCSRB, &UCSRC, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X, &reply_buffer, + &serial_message_complete); #elif defined(UBRR0H) && defined(UBRR0L) -BeanSerialTransport Serial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, - &UCSR0B, &UCSR0C, &UDR0, RXEN0, TXEN0, RXCIE0, - UDRIE0, U2X0, &reply_buffer, - &serial_message_complete); + BeanSerialTransport Serial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, + &UCSR0B, &UCSR0C, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0, &reply_buffer, + &serial_message_complete); #elif defined(USBCON) -// do nothing - Serial object and buffers are initialized in CDC code + // do nothing - Serial object and buffers are initialized in CDC code #else -#error no serial port defined, port 0 + #error no serial port defined (port 0) #endif diff --git a/hardware/bean/avr/cores/bean/BeanSerialTransport.h b/hardware/bean/avr/cores/bean/BeanSerialTransport.h index 1f9124c..c7e5f05 100644 --- a/hardware/bean/avr/cores/bean/BeanSerialTransport.h +++ b/hardware/bean/avr/cores/bean/BeanSerialTransport.h @@ -11,116 +11,99 @@ struct ScratchData { uint8_t data[20]; }; -typedef enum { UART_SLEEP_NORMAL, UART_SLEEP_NEVER } UART_SLEEP_MODE_T; +typedef enum +{ + UART_SLEEP_NORMAL, + UART_SLEEP_NEVER +} UART_SLEEP_MODE_T; // Used for waking the CC out of deep sleep mode. +#define CC_INTERRUPT_PIN (13) #define UART_DEFAULT_WAKE_WAIT (7) #define UART_DEFAULT_SEND_WAIT (13) -class BeanSerialTransport : public HardwareSerial { - friend class BeanClass; - friend class BeanKeyboard_; - friend class BeanMouse_; - private: - uint32_t m_wakeDelay; - uint32_t m_enforcedDelay; +class BeanSerialTransport : public HardwareSerial +{ + friend class BeanClass; - protected: +private: + uint32_t m_wakeDelay; + uint32_t m_enforcedDelay; + +protected: ring_buffer *_reply_buffer; void insert_escaped_char(uint8_t input); - volatile bool *_message_complete; + volatile bool* _message_complete; + - size_t write_message(uint16_t messageId, const uint8_t *body, - size_t body_length); + size_t write_message(uint16_t messageId, const uint8_t* body, size_t body_length); - int call_and_response(MSG_ID_T messageId, const uint8_t *body, - size_t body_length, uint8_t *response, - size_t *response_length, - unsigned long timeout_ms = 100); + int call_and_response(MSG_ID_T messageId, + const uint8_t *body, + size_t body_length, + uint8_t * response, + size_t * response_length, unsigned long timeout_ms=100); - // API Control - // BT + +// API Control + //BT void BTSetAdvertisingOnOff(const bool setting, uint32_t timer); void BTSetEnableConfigSave(bool enableSave); void BTSetAdvertisingInterval(uint16_t interval_ms); void BTSetConnectionInterval(const int interval_ms); - void BTSetLocalName(const char *name); + void BTSetLocalName(const char* name); void BTSetPairingPin(const uint16_t pin); - void BTSetTxPower(const BT_TXPOWER_DB_T &power); + void BTSetTxPower(const BT_TXPOWER_DB_T& power); void BTSetScratchChar(BT_SCRATCH_T *setting, uint8_t length); - int BTGetScratchChar(uint8_t scratchNum, ScratchData *scratchData); - int BTGetConfig(BT_RADIOCONFIG_T *config); - int BTGetStates(BT_STATES_T *btStates); - void BTSetBeaconParams(uint16_t uuid, uint16_t majorid, uint16_t minorid); - void BTBeaconModeEnable(bool beaconEnable); + int BTGetScratchChar(uint8_t scratchNum, ScratchData * scratchData); + int BTGetConfig(BT_RADIOCONFIG_T *config); + int BTGetStates(BT_STATES_T * btStates ); + void BTSetBeaconParams(uint16_t uuid, uint16_t majorid, uint16_t minorid ); + void BTBeaconModeEnable( bool beaconEnable ); void BTConfigUartSleep(UART_SLEEP_MODE_T mode); void BTDisconnect(void); + - // LED Control + //LED Control void ledSet(const LED_SETTING_T &setting); void ledSetSingle(const LED_IND_SETTING_T &setting); int ledRead(LED_SETTING_T *reading); - // GATT Control - int readGATT(ADV_SWITCH_ENABLED_T *reading); - int writeGATT(ADV_SWITCH_ENABLED_T services); - int setCustomAdvertisement(uint8_t *buf, int len); - - // Midi - char peekMidi(); - size_t midiAvailable(); - size_t readMidi(uint8_t *buffer, size_t max_length); - void midiSend(uint8_t status, uint8_t byte1, uint8_t byte2); - - // ANCS - int ancsAvailable(); - int readAncs(uint8_t *buffer, size_t max_length); - int getAncsNotiDetails(uint8_t *buffer, size_t length); - int ancsNotiDetailsAvailable(); - int readAncsMessage(uint8_t *buffer, size_t max_length); - - // Observer - int startObserver(void); - int stopObserver(void); - int getObserverMessage(OBSERVER_INFO_MESSAGE_T *message, - unsigned long timeout); - - // Accelerometer - int accelRead(ACC_READING_T *reading); - int accelRangeRead(uint8_t *range); - void accelRangeSet(uint8_t range); - int accelRegisterRead(uint8_t reg, uint8_t length, uint8_t *value); - void accelRegisterWrite(uint8_t reg, uint8_t value); - void wakeOnAccel(uint8_t int_enable); - - // temperature - int temperatureRead(int8_t *tempRead); - - // battery - int batteryRead(uint8_t *level); - - // Arduino Sleep + //Accelerometer + int accelRead(ACC_READING_T* reading); + int accelRangeRead( uint8_t *range); + void accelRangeSet( uint8_t range ); + + //temperature + int temperatureRead( int8_t* tempRead ); + + //battery + int batteryRead( uint8_t* level ); + + //Arduino Sleep void sleep(uint32_t duration_ms); - void enableWakeOnConnect(bool enable); + void enableWakeOnConnect( bool enable ); bool m_enableSave; - public: + + +public: // To work on bean, the serial must be initialized // at 57600 with standard settings, and cannot be disabled // or all control messaging will break. We've overidden begin() and end() // functions to not do a whole heck of a lot as a result. void begin(void); - virtual void begin(unsigned long ignored) { + virtual void begin(unsigned long ignored){ // Do nothing. // We're overiding what users can do here. } - virtual void begin(unsigned long ignored, uint8_t also_ignored) { + virtual void begin(unsigned long ignored, uint8_t also_ignored){ // Do nothing. // We're overiding what users can do here. } - virtual void end() { + virtual void end(){ // Do nothing. Users ending serial would break our control messaging // so we're removing this ability. } @@ -130,42 +113,46 @@ class BeanSerialTransport : public HardwareSerial { virtual size_t write(uint8_t); size_t write(const uint8_t *buffer, size_t size); - using HardwareSerial::write; // pull in write(str) and write(buf, size) from - // Print + using HardwareSerial::write; // pull in write(str) and write(buf, size) from Print virtual size_t print(const String &s); size_t print(const __FlashStringHelper *ifsh); using Print::print; - // Debug + //Debug bool debugLoopbackVerify(const uint8_t *message, const size_t size); bool debugEndToEndLoopbackVerify(const uint8_t *message, const size_t size); int debugGetDebugCounter(int *counter); - void debugWrite(const char c) { HardwareSerial::write((uint8_t)c); } + void debugWrite(const char c){ HardwareSerial::write((uint8_t)c);}; void debugLoopBackFullSerialMessages(void); void debugWritePtm(const uint8_t *message, const size_t size); + // constructor - BeanSerialTransport(ring_buffer *rx_buffer, ring_buffer *tx_buffer, - volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, - volatile uint8_t *ucsra, volatile uint8_t *ucsrb, - volatile uint8_t *ucsrc, volatile uint8_t *udr, - uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, - uint8_t u2x, ring_buffer *reply_buffer, - volatile bool *message_complete) - : HardwareSerial(rx_buffer, tx_buffer, ubrrh, ubrrl, ucsra, ucsrb, ucsrc, - udr, rxen, txen, rxcie, udrie, u2x) { + BeanSerialTransport(ring_buffer *rx_buffer, ring_buffer *tx_buffer, + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *ucsrc, volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, + uint8_t udrie, uint8_t u2x, ring_buffer* reply_buffer, + volatile bool* message_complete) + : HardwareSerial(rx_buffer, tx_buffer, ubrrh, ubrrl, + ucsra, ucsrb, ucsrc, udr, rxen, txen, + rxcie, udrie, u2x) + { _reply_buffer = reply_buffer; _message_complete = message_complete; *message_complete = false; m_wakeDelay = UART_DEFAULT_WAKE_WAIT; m_enforcedDelay = UART_DEFAULT_SEND_WAIT; - } // End constructor -}; // End BeanSerialTransport + }; // End constructor + +}; // End BeanSerialTransport #if defined(UBRRH) || defined(UBRR0H) -extern BeanSerialTransport Serial; + extern BeanSerialTransport Serial; #elif defined(USBCON) -#include "USBAPI.h" + #include "USBAPI.h" +// extern HardwareSerial Serial_; #endif -#endif +#endif \ No newline at end of file diff --git a/hardware/bean/avr/cores/bean/applicationMessageHeaders b/hardware/bean/avr/cores/bean/applicationMessageHeaders index 840fd78..2ae9773 160000 --- a/hardware/bean/avr/cores/bean/applicationMessageHeaders +++ b/hardware/bean/avr/cores/bean/applicationMessageHeaders @@ -1 +1 @@ -Subproject commit 840fd78b775fb1c303ad4be239cdad61fe5a803c +Subproject commit 2ae9773e378ecc3ff9e0fc73157bc165c2afdcd5 diff --git a/hardware/bean/avr/cores/bean/bma250.h b/hardware/bean/avr/cores/bean/bma250.h deleted file mode 100644 index 6674d7d..0000000 --- a/hardware/bean/avr/cores/bean/bma250.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef BEAN_BMA250_H -#define BEAN_BMA250_H - -#define REG_X_ACCEL_LSB 0x02 -#define REG_Y_ACCEL_LSB 0x04 -#define REG_Z_ACCEL_LSB 0x06 - -#define REG_G_SETTING 0x0F -#define VALUE_2G 0x03 -#define VALUE_4G 0x05 -#define VALUE_8G 0x08 -#define VALUE_16G 0x0C - -// Normal mode: 0x00 (~140uA) -// Suspend mode: 0x80 (~0.5uA) -// Low Power 10ms: 0x54 (~16.4uA) -// Low Power 100ms: 0x5A (~2.3uA) -// Low Power 1s: 0x5E (~0.7uA) -#define REG_POWER_MODE_X11 0x11 -#define VALUE_NORMAL_MODE 0x00 -#define VALUE_SUSPEND_MODE 0x80 -#define VALUE_LOW_POWER_10MS 0x54 -#define VALUE_LOW_POWER_100MS 0x5A -#define VALUE_LOW_POWER_1S 0x5E - -#define REG_INT_STATUS_X09 0x09 -#define CHECK_FLAT_INT 0x80 -#define CHECK_ORIENT_INT 0x40 -#define CHECK_SINGLE_TAP_INT 0x20 -#define CHECK_DOUBLE_TAP_INT 0x10 -#define CHECK_ANY_MOTION_INT 0x04 -#define CHECK_HIGH_G_INT 0x02 -#define CHECK_LOW_G_INT 0x01 - -#define REG_INT_SETTING_X16 0x16 -#define ENABLE_FLAT_INT 0x8000 -#define ENABLE_ORIENT_INT 0x4000 -#define ENABLE_SINGLE_TAP_INT 0x2000 -#define ENABLE_DOUBLE_TAP_INT 0x1000 -#define ENABLE_SLOPE_Z_INT 0x0400 -#define ENABLE_SLOPE_Y_INT 0x0200 -#define ENABLE_SLOPE_X_INT 0x0100 -#define ENABLE_ANY_MOTION_INT 0x0700 - -#define REG_INT_SETTING_X17 0x17 -#define ENABLE_NEW_DATA_INT 0x0010 -#define ENABLE_LOW_G_INT 0x0008 -#define ENABLE_HIGH_G_Z_INT 0x0004 -#define ENABLE_HIGH_G_Y_INT 0x0002 -#define ENABLE_HIGH_G_X_INT 0x0001 - -#define REG_INT_MAPPING_X19 0x19 -#define MASK_X19_ALL_INT1 0xF7 -#define WAKE_FLAT_INT 0x80 -#define WAKE_ORIENT_INT 0x40 -#define WAKE_SINGLE_TAP_INT 0x20 -#define WAKE_DOUBLE_TAP_INT 0x10 -#define WAKE_ANY_MOTION_INT 0x04 -#define WAKE_HIGH_G_INT 0x02 -#define WAKE_LOW_G_INT 0x01 - - -#define REG_INT_MAPPING_X1A 0x1A -#define MASK_X1A_ALL_INT1 0x81 - -#define REG_LATCH_CFG_X21 0x21 -#define VALUE_LATCHED 0x07 -#define VALUE_TEMPORARY_250MS 0x01 -#define MASK_RESET_INT_LATCH 0x80 - -#endif //BEAN_BMA250_H diff --git a/hardware/bean/avr/cores/bean/wiring_analog.c b/hardware/bean/avr/cores/bean/wiring_analog.c index 8879572..0bea9ad 100644 --- a/hardware/bean/avr/cores/bean/wiring_analog.c +++ b/hardware/bean/avr/cores/bean/wiring_analog.c @@ -57,7 +57,7 @@ int analogRead(uint8_t pin) #elif defined(analogPinToChannel) && (defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)) pin = analogPinToChannel(pin); #else - if (pin >= NUM_DIGITAL_PINS) pin -= NUM_DIGITAL_PINS; // allow for channel or pin numbers + if (pin >= 14) pin -= 14; // allow for channel or pin numbers #endif #if defined(__AVR_ATmega32U4__) diff --git a/hardware/bean/avr/libraries/PinChangeInt b/hardware/bean/avr/libraries/PinChangeInt new file mode 160000 index 0000000..ec745f8 --- /dev/null +++ b/hardware/bean/avr/libraries/PinChangeInt @@ -0,0 +1 @@ +Subproject commit ec745f854b2b807640341cf479f540bb8bb3fc2f diff --git a/hardware/bean/avr/libraries/SoftwareSerial/SoftwareSerial.cpp b/hardware/bean/avr/libraries/SoftwareSerial/SoftwareSerial.cpp index b4e4529..527f3f9 100644 --- a/hardware/bean/avr/libraries/SoftwareSerial/SoftwareSerial.cpp +++ b/hardware/bean/avr/libraries/SoftwareSerial/SoftwareSerial.cpp @@ -1,490 +1,490 @@ -/* -SoftwareSerial.cpp (formerly NewSoftSerial.cpp) - -Multi-instance software serial library for Arduino/Wiring --- Interrupt-driven receive and other improvements by ladyada - (http://ladyada.net) --- Tuning, circular buffer, derivation from class Print/Stream, - multi-instance support, porting to 8MHz processors, - various optimizations, PROGMEM delay tables, inverse logic and - direct port writing by Mikal Hart (http://www.arduiniana.org) --- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) --- 20MHz processor support by Garrett Mace (http://www.macetech.com) --- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -The latest version of this library can always be found at -http://arduiniana.org. -*/ - -// When set, _DEBUG co-opts pins 11 and 13 for debugging with an -// oscilloscope or logic analyzer. Beware: it also slightly modifies -// the bit times, so don't rely on it too much at high baud rates -#define _DEBUG 0 -#define _DEBUG_PIN1 11 -#define _DEBUG_PIN2 13 -// -// Includes -// -#include -#include -#include -#include -#include - -// -// Statics -// -SoftwareSerial *SoftwareSerial::active_object = 0; -char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; -volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0; -volatile uint8_t SoftwareSerial::_receive_buffer_head = 0; - -// -// Debugging -// -// This function generates a brief pulse -// for debugging or measuring on an oscilloscope. -inline void DebugPulse(uint8_t pin, uint8_t count) -{ -#if _DEBUG - volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin)); - - uint8_t val = *pport; - while (count--) - { - *pport = val | digitalPinToBitMask(pin); - *pport = val; - } -#endif -} - -// -// Private methods -// - -/* static */ -inline void SoftwareSerial::tunedDelay(uint16_t delay) { - _delay_loop_2(delay); -} - -// This function sets the current object as the "listening" -// one and returns true if it replaces another -bool SoftwareSerial::listen() -{ - if (!_rx_delay_stopbit) - return false; - - if (active_object != this) - { - if (active_object) - active_object->stopListening(); - - _buffer_overflow = false; - _receive_buffer_head = _receive_buffer_tail = 0; - active_object = this; - - setRxIntMsk(true); - return true; - } - - return false; -} - -// Stop listening. Returns true if we were actually listening. -bool SoftwareSerial::stopListening() -{ - if (active_object == this) - { - setRxIntMsk(false); - active_object = NULL; - return true; - } - return false; -} - -// -// The receive routine called by the interrupt handler -// -void SoftwareSerial::recv() -{ - -#if GCC_VERSION < 40302 -// Work-around for avr-gcc 4.3.0 OSX version bug -// Preserve the registers that the compiler misses -// (courtesy of Arduino forum user *etracer*) - asm volatile( - "push r18 \n\t" - "push r19 \n\t" - "push r20 \n\t" - "push r21 \n\t" - "push r22 \n\t" - "push r23 \n\t" - "push r26 \n\t" - "push r27 \n\t" - ::); -#endif - - uint8_t d = 0; - - // If RX line is high, then we don't see any start bit - // so interrupt is probably not for us - if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) - { - // Disable further interrupts during reception, this prevents - // triggering another interrupt directly after we return, which can - // cause problems at higher baudrates. - setRxIntMsk(false); - - // Wait approximately 1/2 of a bit width to "center" the sample - tunedDelay(_rx_delay_centering); - DebugPulse(_DEBUG_PIN2, 1); - - // Read each of the 8 bits - for (uint8_t i=8; i > 0; --i) - { - tunedDelay(_rx_delay_intrabit); - d >>= 1; - DebugPulse(_DEBUG_PIN2, 1); - if (rx_pin_read()) - d |= 0x80; - } - - if (_inverse_logic) - d = ~d; - - // if buffer full, set the overflow flag and return - uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; - if (next != _receive_buffer_head) - { - // save new data in buffer: tail points to where byte goes - _receive_buffer[_receive_buffer_tail] = d; // save new byte - _receive_buffer_tail = next; - } - else - { - DebugPulse(_DEBUG_PIN1, 1); - _buffer_overflow = true; - } - - // skip the stop bit - tunedDelay(_rx_delay_stopbit); - DebugPulse(_DEBUG_PIN1, 1); - - // Re-enable interrupts when we're sure to be inside the stop bit - setRxIntMsk(true); - - } - -#if GCC_VERSION < 40302 -// Work-around for avr-gcc 4.3.0 OSX version bug -// Restore the registers that the compiler misses - asm volatile( - "pop r27 \n\t" - "pop r26 \n\t" - "pop r23 \n\t" - "pop r22 \n\t" - "pop r21 \n\t" - "pop r20 \n\t" - "pop r19 \n\t" - "pop r18 \n\t" - ::); -#endif -} - -uint8_t SoftwareSerial::rx_pin_read() -{ - return *_receivePortRegister & _receiveBitMask; -} - -// -// Interrupt handling -// - -/* static */ -inline void SoftwareSerial::handle_interrupt() -{ - if (active_object) - { - active_object->recv(); - } -} - -#if defined(PCINT0_vect) -ISR(PCINT0_vect) -{ - SoftwareSerial::handle_interrupt(); -} -#endif - -#if defined(PCINT1_vect) -ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect)); -#endif - -#if defined(PCINT2_vect) -ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect)); -#endif - -#if defined(PCINT3_vect) -ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect)); -#endif - -// -// Constructor -// -SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : - _rx_delay_centering(0), - _rx_delay_intrabit(0), - _rx_delay_stopbit(0), - _tx_delay(0), - _buffer_overflow(false), - _inverse_logic(inverse_logic) -{ - setTX(transmitPin); - setRX(receivePin); -} - -// -// Destructor -// -SoftwareSerial::~SoftwareSerial() -{ - end(); -} - -void SoftwareSerial::setTX(uint8_t tx) -{ - // First write, then set output. If we do this the other way around, - // the pin would be output low for a short while before switching to - // output hihg. Now, it is input with pullup for a short while, which - // is fine. With inverse logic, either order is fine. - digitalWrite(tx, _inverse_logic ? LOW : HIGH); - pinMode(tx, OUTPUT); - _transmitBitMask = digitalPinToBitMask(tx); - uint8_t port = digitalPinToPort(tx); - _transmitPortRegister = portOutputRegister(port); -} - -void SoftwareSerial::setRX(uint8_t rx) -{ - pinMode(rx, INPUT); - if (!_inverse_logic) - digitalWrite(rx, HIGH); // pullup for normal logic! - _receivePin = rx; - _receiveBitMask = digitalPinToBitMask(rx); - uint8_t port = digitalPinToPort(rx); - _receivePortRegister = portInputRegister(port); -} - -uint16_t SoftwareSerial::subtract_cap(uint16_t num, uint16_t sub) { - if (num > sub) - return num - sub; - else - return 1; -} - -// -// Public methods -// - -void SoftwareSerial::begin(long speed) -{ - _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0; - - // Precalculate the various delays, in number of 4-cycle delays - uint16_t bit_delay = (F_CPU / speed) / 4; - - // 12 (gcc 4.8.2) or 13 (gcc 4.3.2) cycles from start bit to first bit, - // 15 (gcc 4.8.2) or 16 (gcc 4.3.2) cycles between bits, - // 12 (gcc 4.8.2) or 14 (gcc 4.3.2) cycles from last bit to stop bit - // These are all close enough to just use 15 cycles, since the inter-bit - // timings are the most critical (deviations stack 8 times) - _tx_delay = subtract_cap(bit_delay, 15 / 4); - - // Only setup rx when we have a valid PCINT for this pin - if (digitalPinToPCICR(_receivePin)) { - #if GCC_VERSION > 40800 - // Timings counted from gcc 4.8.2 output. This works up to 115200 on - // 16Mhz and 57600 on 8Mhz. - // - // When the start bit occurs, there are 3 or 4 cycles before the - // interrupt flag is set, 4 cycles before the PC is set to the right - // interrupt vector address and the old PC is pushed on the stack, - // and then 75 cycles of instructions (including the RJMP in the - // ISR vector table) until the first delay. After the delay, there - // are 17 more cycles until the pin value is read (excluding the - // delay in the loop). - // We want to have a total delay of 1.5 bit time. Inside the loop, - // we already wait for 1 bit time - 23 cycles, so here we wait for - // 0.5 bit time - (71 + 18 - 22) cycles. - _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 75 + 17 - 23) / 4); - - // There are 23 cycles in each loop iteration (excluding the delay) - _rx_delay_intrabit = subtract_cap(bit_delay, 23 / 4); - - // There are 37 cycles from the last bit read to the start of - // stopbit delay and 11 cycles from the delay until the interrupt - // mask is enabled again (which _must_ happen during the stopbit). - // This delay aims at 3/4 of a bit time, meaning the end of the - // delay will be at 1/4th of the stopbit. This allows some extra - // time for ISR cleanup, which makes 115200 baud at 16Mhz work more - // reliably - _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (37 + 11) / 4); - #else // Timings counted from gcc 4.3.2 output - // Note that this code is a _lot_ slower, mostly due to bad register - // allocation choices of gcc. This works up to 57600 on 16Mhz and - // 38400 on 8Mhz. - _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 97 + 29 - 11) / 4); - _rx_delay_intrabit = subtract_cap(bit_delay, 11 / 4); - _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (44 + 17) / 4); - #endif - - - // Enable the PCINT for the entire port here, but never disable it - // (others might also need it, so we disable the interrupt by using - // the per-pin PCMSK register). - *digitalPinToPCICR(_receivePin) |= _BV(digitalPinToPCICRbit(_receivePin)); - // Precalculate the pcint mask register and value, so setRxIntMask - // can be used inside the ISR without costing too much time. - _pcint_maskreg = digitalPinToPCMSK(_receivePin); - _pcint_maskvalue = _BV(digitalPinToPCMSKbit(_receivePin)); - - tunedDelay(_tx_delay); // if we were low this establishes the end - } - -#if _DEBUG - pinMode(_DEBUG_PIN1, OUTPUT); - pinMode(_DEBUG_PIN2, OUTPUT); -#endif - - listen(); -} - -void SoftwareSerial::setRxIntMsk(bool enable) -{ - if (enable) - *_pcint_maskreg |= _pcint_maskvalue; - else - *_pcint_maskreg &= ~_pcint_maskvalue; -} - -void SoftwareSerial::end() -{ - stopListening(); -} - - -// Read data from buffer -int SoftwareSerial::read() -{ - if (!isListening()) - return -1; - - // Empty buffer? - if (_receive_buffer_head == _receive_buffer_tail) - return -1; - - // Read from "head" - uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte - _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF; - return d; -} - -int SoftwareSerial::available() -{ - if (!isListening()) - return 0; - - return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF; -} - -size_t SoftwareSerial::write(uint8_t b) -{ - if (_tx_delay == 0) { - setWriteError(); - return 0; - } - - // By declaring these as local variables, the compiler will put them - // in registers _before_ disabling interrupts and entering the - // critical timing sections below, which makes it a lot easier to - // verify the cycle timings - volatile uint8_t *reg = _transmitPortRegister; - uint8_t reg_mask = _transmitBitMask; - uint8_t inv_mask = ~_transmitBitMask; - uint8_t oldSREG = SREG; - bool inv = _inverse_logic; - uint16_t delay = _tx_delay; - - if (inv) - b = ~b; - - cli(); // turn off interrupts for a clean txmit - - // Write the start bit - if (inv) - *reg |= reg_mask; - else - *reg &= inv_mask; - - tunedDelay(delay); - - // Write each of the 8 bits - for (uint8_t i = 8; i > 0; --i) - { - if (b & 1) // choose bit - *reg |= reg_mask; // send 1 - else - *reg &= inv_mask; // send 0 - - tunedDelay(delay); - b >>= 1; - } - - // restore pin to natural state - if (inv) - *reg &= inv_mask; - else - *reg |= reg_mask; - - SREG = oldSREG; // turn interrupts back on - tunedDelay(_tx_delay); - - return 1; -} - -void SoftwareSerial::flush() -{ - if (!isListening()) - return; - - uint8_t oldSREG = SREG; - cli(); - _receive_buffer_head = _receive_buffer_tail = 0; - SREG = oldSREG; -} - -int SoftwareSerial::peek() -{ - if (!isListening()) - return -1; - - // Empty buffer? - if (_receive_buffer_head == _receive_buffer_tail) - return -1; - - // Read from "head" - return _receive_buffer[_receive_buffer_head]; -} +/* +SoftwareSerial.cpp (formerly NewSoftSerial.cpp) - +Multi-instance software serial library for Arduino/Wiring +-- Interrupt-driven receive and other improvements by ladyada + (http://ladyada.net) +-- Tuning, circular buffer, derivation from class Print/Stream, + multi-instance support, porting to 8MHz processors, + various optimizations, PROGMEM delay tables, inverse logic and + direct port writing by Mikal Hart (http://www.arduiniana.org) +-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) +-- 20MHz processor support by Garrett Mace (http://www.macetech.com) +-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +http://arduiniana.org. +*/ + +// When set, _DEBUG co-opts pins 11 and 13 for debugging with an +// oscilloscope or logic analyzer. Beware: it also slightly modifies +// the bit times, so don't rely on it too much at high baud rates +#define _DEBUG 0 +#define _DEBUG_PIN1 11 +#define _DEBUG_PIN2 13 +// +// Includes +// +#include +#include +#include +#include +#include + +// +// Statics +// +SoftwareSerial *SoftwareSerial::active_object = 0; +char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; +volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0; +volatile uint8_t SoftwareSerial::_receive_buffer_head = 0; + +// +// Debugging +// +// This function generates a brief pulse +// for debugging or measuring on an oscilloscope. +inline void DebugPulse(uint8_t pin, uint8_t count) +{ +#if _DEBUG + volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin)); + + uint8_t val = *pport; + while (count--) + { + *pport = val | digitalPinToBitMask(pin); + *pport = val; + } +#endif +} + +// +// Private methods +// + +/* static */ +inline void SoftwareSerial::tunedDelay(uint16_t delay) { + _delay_loop_2(delay); +} + +// This function sets the current object as the "listening" +// one and returns true if it replaces another +bool SoftwareSerial::listen() +{ + if (!_rx_delay_stopbit) + return false; + + if (active_object != this) + { + if (active_object) + active_object->stopListening(); + + _buffer_overflow = false; + _receive_buffer_head = _receive_buffer_tail = 0; + active_object = this; + + setRxIntMsk(true); + return true; + } + + return false; +} + +// Stop listening. Returns true if we were actually listening. +bool SoftwareSerial::stopListening() +{ + if (active_object == this) + { + setRxIntMsk(false); + active_object = NULL; + return true; + } + return false; +} + +// +// The receive routine called by the interrupt handler +// +void SoftwareSerial::recv() +{ + +#if GCC_VERSION < 40302 +// Work-around for avr-gcc 4.3.0 OSX version bug +// Preserve the registers that the compiler misses +// (courtesy of Arduino forum user *etracer*) + asm volatile( + "push r18 \n\t" + "push r19 \n\t" + "push r20 \n\t" + "push r21 \n\t" + "push r22 \n\t" + "push r23 \n\t" + "push r26 \n\t" + "push r27 \n\t" + ::); +#endif + + uint8_t d = 0; + + // If RX line is high, then we don't see any start bit + // so interrupt is probably not for us + if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) + { + // Disable further interrupts during reception, this prevents + // triggering another interrupt directly after we return, which can + // cause problems at higher baudrates. + setRxIntMsk(false); + + // Wait approximately 1/2 of a bit width to "center" the sample + tunedDelay(_rx_delay_centering); + DebugPulse(_DEBUG_PIN2, 1); + + // Read each of the 8 bits + for (uint8_t i=8; i > 0; --i) + { + tunedDelay(_rx_delay_intrabit); + d >>= 1; + DebugPulse(_DEBUG_PIN2, 1); + if (rx_pin_read()) + d |= 0x80; + } + + if (_inverse_logic) + d = ~d; + + // if buffer full, set the overflow flag and return + uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; + if (next != _receive_buffer_head) + { + // save new data in buffer: tail points to where byte goes + _receive_buffer[_receive_buffer_tail] = d; // save new byte + _receive_buffer_tail = next; + } + else + { + DebugPulse(_DEBUG_PIN1, 1); + _buffer_overflow = true; + } + + // skip the stop bit + tunedDelay(_rx_delay_stopbit); + DebugPulse(_DEBUG_PIN1, 1); + + // Re-enable interrupts when we're sure to be inside the stop bit + setRxIntMsk(true); + + } + +#if GCC_VERSION < 40302 +// Work-around for avr-gcc 4.3.0 OSX version bug +// Restore the registers that the compiler misses + asm volatile( + "pop r27 \n\t" + "pop r26 \n\t" + "pop r23 \n\t" + "pop r22 \n\t" + "pop r21 \n\t" + "pop r20 \n\t" + "pop r19 \n\t" + "pop r18 \n\t" + ::); +#endif +} + +uint8_t SoftwareSerial::rx_pin_read() +{ + return *_receivePortRegister & _receiveBitMask; +} + +// +// Interrupt handling +// + +/* static */ +inline void SoftwareSerial::handle_interrupt() +{ + if (active_object) + { + active_object->recv(); + } +} + +#if defined(PCINT0_vect) +ISR(PCINT0_vect) +{ + SoftwareSerial::handle_interrupt(); +} +#endif + +#if defined(PCINT1_vect) +ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +#if defined(PCINT2_vect) +ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +#if defined(PCINT3_vect) +ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +// +// Constructor +// +SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : + _rx_delay_centering(0), + _rx_delay_intrabit(0), + _rx_delay_stopbit(0), + _tx_delay(0), + _buffer_overflow(false), + _inverse_logic(inverse_logic) +{ + setTX(transmitPin); + setRX(receivePin); +} + +// +// Destructor +// +SoftwareSerial::~SoftwareSerial() +{ + end(); +} + +void SoftwareSerial::setTX(uint8_t tx) +{ + // First write, then set output. If we do this the other way around, + // the pin would be output low for a short while before switching to + // output hihg. Now, it is input with pullup for a short while, which + // is fine. With inverse logic, either order is fine. + digitalWrite(tx, _inverse_logic ? LOW : HIGH); + pinMode(tx, OUTPUT); + _transmitBitMask = digitalPinToBitMask(tx); + uint8_t port = digitalPinToPort(tx); + _transmitPortRegister = portOutputRegister(port); +} + +void SoftwareSerial::setRX(uint8_t rx) +{ + pinMode(rx, INPUT); + if (!_inverse_logic) + digitalWrite(rx, HIGH); // pullup for normal logic! + _receivePin = rx; + _receiveBitMask = digitalPinToBitMask(rx); + uint8_t port = digitalPinToPort(rx); + _receivePortRegister = portInputRegister(port); +} + +uint16_t SoftwareSerial::subtract_cap(uint16_t num, uint16_t sub) { + if (num > sub) + return num - sub; + else + return 1; +} + +// +// Public methods +// + +void SoftwareSerial::begin(long speed) +{ + _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0; + + // Precalculate the various delays, in number of 4-cycle delays + uint16_t bit_delay = (F_CPU / speed) / 4; + + // 12 (gcc 4.8.2) or 13 (gcc 4.3.2) cycles from start bit to first bit, + // 15 (gcc 4.8.2) or 16 (gcc 4.3.2) cycles between bits, + // 12 (gcc 4.8.2) or 14 (gcc 4.3.2) cycles from last bit to stop bit + // These are all close enough to just use 15 cycles, since the inter-bit + // timings are the most critical (deviations stack 8 times) + _tx_delay = subtract_cap(bit_delay, 15 / 4); + + // Only setup rx when we have a valid PCINT for this pin + if (digitalPinToPCICR(_receivePin)) { + #if GCC_VERSION > 40800 + // Timings counted from gcc 4.8.2 output. This works up to 115200 on + // 16Mhz and 57600 on 8Mhz. + // + // When the start bit occurs, there are 3 or 4 cycles before the + // interrupt flag is set, 4 cycles before the PC is set to the right + // interrupt vector address and the old PC is pushed on the stack, + // and then 75 cycles of instructions (including the RJMP in the + // ISR vector table) until the first delay. After the delay, there + // are 17 more cycles until the pin value is read (excluding the + // delay in the loop). + // We want to have a total delay of 1.5 bit time. Inside the loop, + // we already wait for 1 bit time - 23 cycles, so here we wait for + // 0.5 bit time - (71 + 18 - 22) cycles. + _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 75 + 17 - 23) / 4); + + // There are 23 cycles in each loop iteration (excluding the delay) + _rx_delay_intrabit = subtract_cap(bit_delay, 23 / 4); + + // There are 37 cycles from the last bit read to the start of + // stopbit delay and 11 cycles from the delay until the interrupt + // mask is enabled again (which _must_ happen during the stopbit). + // This delay aims at 3/4 of a bit time, meaning the end of the + // delay will be at 1/4th of the stopbit. This allows some extra + // time for ISR cleanup, which makes 115200 baud at 16Mhz work more + // reliably + _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (37 + 11) / 4); + #else // Timings counted from gcc 4.3.2 output + // Note that this code is a _lot_ slower, mostly due to bad register + // allocation choices of gcc. This works up to 57600 on 16Mhz and + // 38400 on 8Mhz. + _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 97 + 29 - 11) / 4); + _rx_delay_intrabit = subtract_cap(bit_delay, 11 / 4); + _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (44 + 17) / 4); + #endif + + + // Enable the PCINT for the entire port here, but never disable it + // (others might also need it, so we disable the interrupt by using + // the per-pin PCMSK register). + *digitalPinToPCICR(_receivePin) |= _BV(digitalPinToPCICRbit(_receivePin)); + // Precalculate the pcint mask register and value, so setRxIntMask + // can be used inside the ISR without costing too much time. + _pcint_maskreg = digitalPinToPCMSK(_receivePin); + _pcint_maskvalue = _BV(digitalPinToPCMSKbit(_receivePin)); + + tunedDelay(_tx_delay); // if we were low this establishes the end + } + +#if _DEBUG + pinMode(_DEBUG_PIN1, OUTPUT); + pinMode(_DEBUG_PIN2, OUTPUT); +#endif + + listen(); +} + +void SoftwareSerial::setRxIntMsk(bool enable) +{ + if (enable) + *_pcint_maskreg |= _pcint_maskvalue; + else + *_pcint_maskreg &= ~_pcint_maskvalue; +} + +void SoftwareSerial::end() +{ + stopListening(); +} + + +// Read data from buffer +int SoftwareSerial::read() +{ + if (!isListening()) + return -1; + + // Empty buffer? + if (_receive_buffer_head == _receive_buffer_tail) + return -1; + + // Read from "head" + uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte + _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF; + return d; +} + +int SoftwareSerial::available() +{ + if (!isListening()) + return 0; + + return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF; +} + +size_t SoftwareSerial::write(uint8_t b) +{ + if (_tx_delay == 0) { + setWriteError(); + return 0; + } + + // By declaring these as local variables, the compiler will put them + // in registers _before_ disabling interrupts and entering the + // critical timing sections below, which makes it a lot easier to + // verify the cycle timings + volatile uint8_t *reg = _transmitPortRegister; + uint8_t reg_mask = _transmitBitMask; + uint8_t inv_mask = ~_transmitBitMask; + uint8_t oldSREG = SREG; + bool inv = _inverse_logic; + uint16_t delay = _tx_delay; + + if (inv) + b = ~b; + + cli(); // turn off interrupts for a clean txmit + + // Write the start bit + if (inv) + *reg |= reg_mask; + else + *reg &= inv_mask; + + tunedDelay(delay); + + // Write each of the 8 bits + for (uint8_t i = 8; i > 0; --i) + { + if (b & 1) // choose bit + *reg |= reg_mask; // send 1 + else + *reg &= inv_mask; // send 0 + + tunedDelay(delay); + b >>= 1; + } + + // restore pin to natural state + if (inv) + *reg &= inv_mask; + else + *reg |= reg_mask; + + SREG = oldSREG; // turn interrupts back on + tunedDelay(_tx_delay); + + return 1; +} + +void SoftwareSerial::flush() +{ + if (!isListening()) + return; + + uint8_t oldSREG = SREG; + cli(); + _receive_buffer_head = _receive_buffer_tail = 0; + SREG = oldSREG; +} + +int SoftwareSerial::peek() +{ + if (!isListening()) + return -1; + + // Empty buffer? + if (_receive_buffer_head == _receive_buffer_tail) + return -1; + + // Read from "head" + return _receive_buffer[_receive_buffer_head]; +} diff --git a/hardware/bean/avr/libraries/SoftwareSerial/SoftwareSerial.h b/hardware/bean/avr/libraries/SoftwareSerial/SoftwareSerial.h index 680e40d..274f3df 100644 --- a/hardware/bean/avr/libraries/SoftwareSerial/SoftwareSerial.h +++ b/hardware/bean/avr/libraries/SoftwareSerial/SoftwareSerial.h @@ -1,121 +1,121 @@ -/* -SoftwareSerial.h (formerly NewSoftSerial.h) - -Multi-instance software serial library for Arduino/Wiring --- Interrupt-driven receive and other improvements by ladyada - (http://ladyada.net) --- Tuning, circular buffer, derivation from class Print/Stream, - multi-instance support, porting to 8MHz processors, - various optimizations, PROGMEM delay tables, inverse logic and - direct port writing by Mikal Hart (http://www.arduiniana.org) --- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) --- 20MHz processor support by Garrett Mace (http://www.macetech.com) --- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -The latest version of this library can always be found at -http://arduiniana.org. -*/ - -#ifndef SoftwareSerial_h -#define SoftwareSerial_h - -#include -#include - -/****************************************************************************** -* Definitions -******************************************************************************/ - -#define _SS_MAX_RX_BUFF 64 // RX buffer size -#ifndef GCC_VERSION -#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#endif - -class SoftwareSerial : public Stream -{ -private: - // per object data - uint8_t _receivePin; - uint8_t _receiveBitMask; - volatile uint8_t *_receivePortRegister; - uint8_t _transmitBitMask; - volatile uint8_t *_transmitPortRegister; - volatile uint8_t *_pcint_maskreg; - uint8_t _pcint_maskvalue; - - // Expressed as 4-cycle delays (must never be 0!) - uint16_t _rx_delay_centering; - uint16_t _rx_delay_intrabit; - uint16_t _rx_delay_stopbit; - uint16_t _tx_delay; - - uint16_t _buffer_overflow:1; - uint16_t _inverse_logic:1; - - // static data - static char _receive_buffer[_SS_MAX_RX_BUFF]; - static volatile uint8_t _receive_buffer_tail; - static volatile uint8_t _receive_buffer_head; - static SoftwareSerial *active_object; - - // private methods - void recv() __attribute__((__always_inline__)); - uint8_t rx_pin_read(); - void tx_pin_write(uint8_t pin_state) __attribute__((__always_inline__)); - void setTX(uint8_t transmitPin); - void setRX(uint8_t receivePin); - void setRxIntMsk(bool enable) __attribute__((__always_inline__)); - - // Return num - sub, or 1 if the result would be < 1 - static uint16_t subtract_cap(uint16_t num, uint16_t sub); - - // private static method for timing - static inline void tunedDelay(uint16_t delay); - -public: - // public methods - SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); - ~SoftwareSerial(); - void begin(long speed); - bool listen(); - void end(); - bool isListening() { return this == active_object; } - bool stopListening(); - bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; } - int peek(); - - virtual size_t write(uint8_t byte); - virtual int read(); - virtual int available(); - virtual void flush(); - operator bool() { return true; } - - using Print::write; - - // public only for easy access by interrupt handlers - static inline void handle_interrupt() __attribute__((__always_inline__)); -}; - -// Arduino 0012 workaround -#undef int -#undef char -#undef long -#undef byte -#undef float -#undef abs -#undef round - -#endif +/* +SoftwareSerial.h (formerly NewSoftSerial.h) - +Multi-instance software serial library for Arduino/Wiring +-- Interrupt-driven receive and other improvements by ladyada + (http://ladyada.net) +-- Tuning, circular buffer, derivation from class Print/Stream, + multi-instance support, porting to 8MHz processors, + various optimizations, PROGMEM delay tables, inverse logic and + direct port writing by Mikal Hart (http://www.arduiniana.org) +-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) +-- 20MHz processor support by Garrett Mace (http://www.macetech.com) +-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +http://arduiniana.org. +*/ + +#ifndef SoftwareSerial_h +#define SoftwareSerial_h + +#include +#include + +/****************************************************************************** +* Definitions +******************************************************************************/ + +#define _SS_MAX_RX_BUFF 64 // RX buffer size +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +class SoftwareSerial : public Stream +{ +private: + // per object data + uint8_t _receivePin; + uint8_t _receiveBitMask; + volatile uint8_t *_receivePortRegister; + uint8_t _transmitBitMask; + volatile uint8_t *_transmitPortRegister; + volatile uint8_t *_pcint_maskreg; + uint8_t _pcint_maskvalue; + + // Expressed as 4-cycle delays (must never be 0!) + uint16_t _rx_delay_centering; + uint16_t _rx_delay_intrabit; + uint16_t _rx_delay_stopbit; + uint16_t _tx_delay; + + uint16_t _buffer_overflow:1; + uint16_t _inverse_logic:1; + + // static data + static char _receive_buffer[_SS_MAX_RX_BUFF]; + static volatile uint8_t _receive_buffer_tail; + static volatile uint8_t _receive_buffer_head; + static SoftwareSerial *active_object; + + // private methods + void recv() __attribute__((__always_inline__)); + uint8_t rx_pin_read(); + void tx_pin_write(uint8_t pin_state) __attribute__((__always_inline__)); + void setTX(uint8_t transmitPin); + void setRX(uint8_t receivePin); + void setRxIntMsk(bool enable) __attribute__((__always_inline__)); + + // Return num - sub, or 1 if the result would be < 1 + static uint16_t subtract_cap(uint16_t num, uint16_t sub); + + // private static method for timing + static inline void tunedDelay(uint16_t delay); + +public: + // public methods + SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); + ~SoftwareSerial(); + void begin(long speed); + bool listen(); + void end(); + bool isListening() { return this == active_object; } + bool stopListening(); + bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; } + int peek(); + + virtual size_t write(uint8_t byte); + virtual int read(); + virtual int available(); + virtual void flush(); + operator bool() { return true; } + + using Print::write; + + // public only for easy access by interrupt handlers + static inline void handle_interrupt() __attribute__((__always_inline__)); +}; + +// Arduino 0012 workaround +#undef int +#undef char +#undef long +#undef byte +#undef float +#undef abs +#undef round + +#endif diff --git a/hardware/bean/avr/variants/bean+/pins_arduino.h b/hardware/bean/avr/variants/bean+/pins_arduino.h deleted file mode 100644 index f718cf6..0000000 --- a/hardware/bean/avr/variants/bean+/pins_arduino.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - pins_arduino.h - Pin definition functions for Arduino - Part of Arduino - http://www.arduino.cc/ - - Copyright (c) 2007 David A. Mellis - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ -*/ - -#ifndef Pins_Arduino_h -#define Pins_Arduino_h - -#include - -#define NUM_DIGITAL_PINS 10 -#define NUM_ANALOG_INPUTS 6 -#define analogInputToDigitalPin(p) ((p < NUM_DIGITAL_PINS) ? (p) + NUM_DIGITAL_PINS : -1) - -#define digitalPinHasPWM(p) ((p) == 2 || (p) == 5 || (p) == 6 || (p) == 7) - -static const uint8_t SS = 6; -static const uint8_t MOSI = 7; -static const uint8_t MISO = 8; -static const uint8_t SCK = 9; - -static const uint8_t SDA = 14; -static const uint8_t SCL = 15; -//static const uint8_t LED_BUILTIN = 13; - -static const uint8_t A0 = 10; -static const uint8_t A1 = 11; -static const uint8_t A2 = 12; -static const uint8_t A3 = 13; -static const uint8_t A4 = 14; -static const uint8_t A5 = 15; - -static const uint8_t CC_INTERRUPT_PIN = 16; - -// TODO - I don't know what this stuff is -#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0)) -#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1)) -#define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0)))) -#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14))) - -#ifdef ARDUINO_MAIN - -// On the Arduino board, digital pins are also used -// for the analog output (software PWM). Analog input -// pins are a separate set. - -// ATMEL ATMEGA8 & 168 / ARDUINO -// -// +-\/-+ -// PC6 1| |28 PC5 (AI 5) -// (D 0) PD0 2| |27 PC4 (AI 4) -// (D 1) PD1 3| |26 PC3 (AI 3) -// (D 2) PD2 4| |25 PC2 (AI 2) -// PWM+ (D 3) PD3 5| |24 PC1 (AI 1) -// (D 4) PD4 6| |23 PC0 (AI 0) -// VCC 7| |22 GND -// GND 8| |21 AREF -// PB6 9| |20 AVCC -// PB7 10| |19 PB5 (D 13) -// PWM+ (D 5) PD5 11| |18 PB4 (D 12) -// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM -// (D 7) PD7 13| |16 PB2 (D 10) PWM -// (D 8) PB0 14| |15 PB1 (D 9) PWM -// +----+ -// -// (PWM+ indicates the additional PWM pins on the ATmega168.) - -// ATMEL ATMEGA1280 / ARDUINO -// -// 0-7 PE0-PE7 works -// 8-13 PB0-PB5 works -// 14-21 PA0-PA7 works -// 22-29 PH0-PH7 works -// 30-35 PG5-PG0 works -// 36-43 PC7-PC0 works -// 44-51 PJ7-PJ0 works -// 52-59 PL7-PL0 works -// 60-67 PD7-PD0 works -// A0-A7 PF0-PF7 -// A8-A15 PK0-PK7 - - -// these arrays map port names (e.g. port B) to the -// appropriate addresses for various functions (e.g. reading -// and writing) -const uint16_t PROGMEM port_to_mode_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - (uint16_t) &DDRB, - (uint16_t) &DDRC, - (uint16_t) &DDRD, -}; - -const uint16_t PROGMEM port_to_output_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - (uint16_t) &PORTB, - (uint16_t) &PORTC, - (uint16_t) &PORTD, -}; - -const uint16_t PROGMEM port_to_input_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - (uint16_t) &PINB, - (uint16_t) &PINC, - (uint16_t) &PIND, -}; - -const uint8_t PROGMEM digital_pin_to_port_PGM[] = { - PD, // D0 - PD, // D1 - PD, // D2 PWM - PD, // D3 - PB, // D4 - PB, // D5 PWM - PB, // D6 PWM - PB, // D7 PWM - PB, // D8 - PB, // D9 - PC, // A0 - PC, // A1 - PC, // A2 - PC, // A3 - PC, // A4 - PC, // A5 - PD, // CC_INTERRUPT -}; - -const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { - _BV(2), // D0 - _BV(4), // D1 - _BV(6), // D2 PWM - _BV(7), // D3 - _BV(0), // D4 - _BV(1), // D5 PWM - _BV(2), // D6 PWM - _BV(3), // D7 PWM - _BV(4), // D8 - _BV(5), // D9 - _BV(0), // A0 - _BV(1), // A1 - _BV(2), // A2 - _BV(3), // A3 - _BV(4), // A4 - _BV(5), // A5 - _BV(5), // D5 -}; - -const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { - NOT_ON_TIMER, // D0 - NOT_ON_TIMER, // D1 - TIMER0A, // D2 PWM - NOT_ON_TIMER, // D3 - NOT_ON_TIMER, // D4 - TIMER1A, // D5 PWM - TIMER1B, // D6 PWM - TIMER2A, // D7 PWM - NOT_ON_TIMER, // D8 - NOT_ON_TIMER, // D9 - NOT_ON_TIMER, // A0 - NOT_ON_TIMER, // A1 - NOT_ON_TIMER, // A2 - NOT_ON_TIMER, // A3 - NOT_ON_TIMER, // A4 - NOT_ON_TIMER, // A5 - NOT_ON_TIMER, // CC_INTERRUPT -}; - -#endif // ARDUINO_MAIN -#endif // Pins_Arduino_h - diff --git a/hardware/bean/avr/variants/bean/pins_arduino.h b/hardware/bean/avr/variants/bean/pins_arduino.h index 4addcbe..e999f0b 100644 --- a/hardware/bean/avr/variants/bean/pins_arduino.h +++ b/hardware/bean/avr/variants/bean/pins_arduino.h @@ -57,8 +57,6 @@ static const uint8_t A5 = 15; // remapped for Bean (swapped with A1) static const uint8_t A6 = 20; static const uint8_t A7 = 21; -static const uint8_t CC_INTERRUPT_PIN = 13; - #define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0)) #define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1)) #define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0)))) diff --git a/tests/lint_all.py b/tests/lint_all.py deleted file mode 100755 index e39f838..0000000 --- a/tests/lint_all.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python -from os import walk -from os.path import join -from sys import argv, exit -import re -import subprocess - -usage = """Usage: - {script} --show: list all files that are linted - {script} --reformat: reformat Bean files according to style guide - {script} --lint: lint Bean files using style guide""" - -formatter = ['clang-format', '-i'] -linter = ['cpplint'] - -bean_files = r"Bean.*\.(h|cpp)" - -bean_files_regex = re.compile(bean_files) - -to_process = [] -for root, dirnames, filenames in walk('.'): - for filename in filenames: - if bean_files_regex.match(filename): - path = join(root, filename) - to_process.append(path) - -show = False -reformat = False -lint = False -for arg in argv[1:]: - if arg == '--show': - show = True - if arg == '--reformat': - reformat = True - if arg == '--lint': - lint = True - -if not (show or lint or reformat): - print(usage.format(script=argv[0])) - exit(1) - -format_cmd = formatter + to_process -lint_cmd = linter + to_process - -if show: - print('Files to be linted:') - for fn in to_process: - print(' ', fn) - -if reformat: - reformat_code = subprocess.call(format_cmd) - if lint: - if reformat_code: # We only get one exit code, use it for the linter - print('Reformatter exited with error code', reformat_code) - else: - exit(reformat_code) - -if lint: - lint_code = subprocess.call(lint_cmd) - exit(lint_code) diff --git a/tests/resources/platformio/boards/punchthrough.json b/tests/resources/platformio/boards/punchthrough.json deleted file mode 100644 index bf6fc85..0000000 --- a/tests/resources/platformio/boards/punchthrough.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "lightblue-bean": { - "name": "LightBlue Bean", - "vendor": "Punch Through Design", - "url": "https://punchthrough.com/bean", - - "platform": "atmelavr", - "frameworks": ["arduino"], - - "build": { - "core": "bean", - "variant": "bean", - "extra_flags": "-DARDUINO_ARCH_AVR", - "mcu": "atmega328p", - "f_cpu": "8000000L" - }, - "upload": { - "maximum_size": 32256, - "maximum_ram_size": 2048 - } - } -} diff --git a/tests/resources/to_compile.ino b/tests/resources/to_compile.ino deleted file mode 100644 index 3f7bc60..0000000 --- a/tests/resources/to_compile.ino +++ /dev/null @@ -1,7 +0,0 @@ -void setup() { - Serial.begin(57600); -} - -void loop() { - Bean.sleep(1000); -}