Added global scratchpace and put in template

--- Arduino/hardware/REV10/REV10SecureBHR/REV10SecureBHR.ino
+++ Arduino/hardware/REV10/REV10SecureBHR/REV10SecureBHR.ino
@@ -16,6 +16,17 @@
 Author(s) / Copyright (s): Damon Hart-Davis 2013--2017
                            Deniz Erbilgin 2015--2017
 */
+
+/******************************************************************************
+ * NOTES
+ *****************************************************************************/
+/**
+ * @brief   Template for building a V0p2 app.
+ * @TODO    Figure out how detailed this should be, e.g.
+ *          - Do we want a template for setup and loop functions?
+ *          - What generic functions should be included/assumed necessary?
+ *            e.g. pollIO, CLI stuff etc.
+ */

 /**
  *  DE20170901
@@ -38,75 +49,68 @@
 #undef OTSIM900LINK_SUBCYCLE_SEND_TIMEOUT_TEST
  */

-// GLOBAL flags that alter system build and behaviour.
-//#define DEBUG // If defined, do extra checks and serial logging.  Will take more code space and power.
-
-// Ensure that OpenTRV 'standard' UART speed is set unless explicitly overridden.
-#define BAUD 4800
-// Global flag for REV10 secure BHR
-#define CONFIG_REV10_SECURE_BHR // REV10: secure stats relay and boiler hub.
-
-// Get defaults for valve applications.
-#include <OTV0p2_valve_ENABLE_defaults.h>
-// REV8 + GSM Arduino shield + I2CEXT, see TODO-551.
-#include <OTV0p2_CONFIG_REV10.h>
+/******************************************************************************
+ * INCLUDES
+ *****************************************************************************/
+
+////// GLOBAL flags that alter system build and behaviour.
+
+// If defined, do extra checks and serial logging.  Will take more code space and power.
+#undef DEBUG
+
+// *** Global flag for REVx configuration here *** //
+// e.g.
+#define V0p2_REV 10
+
 // --------------------------------------------
-// Fixups to apply after loading the target config.
-#include <OTV0p2_valve_ENABLE_fixups.h>
-
-#include <OTV0p2_Board_IO_Config.h> // I/O pin allocation and setup: include ahead of I/O module headers.
+// I/O pin allocation and setup: include ahead of I/O module headers.
+#include <OTV0p2_Board_IO_Config.h>
+
+
+////// MAIN LIBRARIES

 #include <Arduino.h>
 #include <OTV0p2Base.h>
 #include <OTRadioLink.h>
+
+
+////// ADDITIONAL LIBRARIES/PERIPHERALS

 #define RFM23B_IRQ_CONTROL  // Enable RFM23B IRQ control code.
 #include <OTRFM23BLink.h>
 #include <OTSIM900Link.h>
 #include <OTAESGCM.h>

+
+////// ADDITIONAL USER HEADERS
+
 #include "secondaryRadioConfig.h"  // IP address in separate header to avoid accidentally committing.

-/////// RADIOS
-// Pick an appropriate radio config for RFM23 (if it is the primary radio).
-// Nodes talking on fast GFSK channel 0.
-static constexpr uint8_t nPrimaryRadioChannels = 1;
-static const OTRadioLink::OTRadioChannelConfig RFM23BConfigs[nPrimaryRadioChannels] =
-  {
-  // GFSK channel 0 full config, RX/TX, not in itself secure.
-  OTRadioLink::OTRadioChannelConfig(OTRFM23BLink::StandardRegSettingsGFSK57600, true),
-  };
-
-static const OTRadioLink::OTRadioChannelConfig SecondaryRadioConfig(&SIM900Config, true);
-
-// Brings in necessary radio libs.
-static constexpr uint8_t RFM23B_RX_QUEUE_SIZE = OTRFM23BLink::DEFAULT_RFM23B_RX_QUEUE_CAPACITY;
-static constexpr int8_t RFM23B_IRQ_PIN = PIN_RFM_NIRQ;
-static constexpr bool RFM23B_allowRX = true;
-OTRFM23BLink::OTRFM23BLink<OTV0P2BASE::V0p2_PIN_SPI_nSS, RFM23B_IRQ_PIN, RFM23B_RX_QUEUE_SIZE, RFM23B_allowRX> PrimaryRadio;
-OTSIM900Link::OTSIM900Link<8, 5, RADIO_POWER_PIN, OTV0P2BASE::getSecondsLT> SecondaryRadio;
-
-/////// SENSORS
-
-// Sensor for supply (eg battery) voltage in millivolts.
-OTV0P2BASE::SupplyVoltageCentiVolts Supply_cV;
-OTV0P2BASE::RoomTemperatureC16_TMP112 TemperatureC16;
-// Sense ambient lighting level.
-OTV0P2BASE::SensorAmbientLight AmbLight;
-
-/////// ACTUATORS
-static constexpr bool enableDefaultAlwaysRX = true;
-static constexpr bool enableRadioRX = true;
-static constexpr bool allowGetMinBoilerOnMFromEEPROM = false;
-OTRadValve::OTHubManager<enableDefaultAlwaysRX, enableRadioRX, allowGetMinBoilerOnMFromEEPROM> hubManager;
-OTRadValve::BoilerLogic::OnOffBoilerDriverLogic<decltype(hubManager), hubManager, OUT_HEATCALL> BoilerHub;
-
-//////// Constants and variables
+/******************************************************************************
+ * GENERAL CONSTANTS AND VARIABLES
+ * Core constants and variables required for V0p2 loop.
+ *****************************************************************************/
 // Controller's view of Least Significant Digits of the current (local) time, in this case whole seconds.
 // TIME_LSD ranges from 0 to TIME_CYCLE_S-1, also major cycle length.
 static constexpr uint_fast8_t TIME_CYCLE_S = 60;
 // Controller's notion/cache of seconds within major cycle.
 static uint_fast8_t TIME_LSD;
+
+// Send the underlying stats binary/text 'whitened' message.
+// This must be terminated with an 0xff (which is not sent),
+// and no longer than STATS_MSG_MAX_LEN bytes long in total (excluding the terminating 0xff).
+// This must not contain any 0xff and should not contain long runs of 0x00 bytes.
+// The message to be sent must be written at an offset of STATS_MSG_START_OFFSET from the start of the buffer.
+// This routine will alter the content of the buffer for transmission,
+// and the buffer should not be re-used as is.
+//   * doubleTX  double TX to increase chance of successful reception
+//   * RFM23BfriendlyPremable  if true then add an extra preamble
+//     to allow RFM23B-based receiver to RX this
+// This will use whichever transmission medium/carrier/etc is available.
+static constexpr uint8_t RFM22_PREAMBLE_BYTES = 5; // Recommended number of preamble bytes for reliable reception.
+static constexpr uint8_t RFM22_SYNC_MIN_BYTES = 3; // Minimum number of sync bytes.
+static constexpr uint8_t STATS_MSG_START_OFFSET = (RFM22_PREAMBLE_BYTES + RFM22_SYNC_MIN_BYTES);
+static constexpr uint8_t STATS_MSG_MAX_LEN = (64 - STATS_MSG_START_OFFSET);

 // 'Elapsed minutes' count of minute/major cycles; cheaper than accessing RTC and not tied to real time.
 // Starts at or just above zero (within the first 4-minute cycle) to help avoid collisions between units after mass power-up.
@@ -119,9 +123,154 @@
 // Mask for Port D input change interrupts.
 static constexpr uint8_t SERIALRX_INT_MASK = (1 << 0); // Serial RX

-//========================================
-// LOCAL FUNCTIONS
-//========================================
+////// SCRATCHSPACE
+
+// decode workspace
+constexpr size_t Decode_WorkspaceSize = OTAESGCM::OTAES128GCMGenericWithWorkspace<>::workspaceRequiredDec + 16 + 58;
+
+// Stats TX workspace
+/**
+ * The workspace consists of:
+ *   - Buffer to construct final message, size MSG_BUF_SIZE.
+ *     - buffer offset/preamble
+ *     - max binary length, or max JSON length + 1 for CRC + 1 to allow
+ *       detection of oversize message
+ *     - terminating 0xff
+ *     - Buffer need be no larger than leading length byte + typical
+ *       64-byte radio module TX buffer limit + optional terminator.
+ *   - Buffer for holding the JSON frame/plain text, size ptextBuflen.
+ *      - The plaintext buffer must hold the JSON frame plus the valvePC
+ *        and the "hasStats" indicator. As the plaintext must hold a copy
+ *        of the JSON frame, the JSON frame is constructed within it to
+ *        save on stack space and copying.
+ *   - Scratch space for the AESGCM decode function.
+ */
+constexpr uint8_t MSG_BUF_SIZE = 1 + 64 + 1;
+constexpr uint8_t bufJSONlen = OTRadioLink::ENC_BODY_SMALL_FIXED_PTEXT_MAX_SIZE + 1;  // 3 = '}' + 0x0 + ? FIXME whuut?
+constexpr uint8_t ptextBuflen = bufJSONlen + 2;  // 2 = valvePC + hasStats
+static_assert(ptextBuflen == 34, "ptextBuflen wrong");
+constexpr uint8_t scratchSpaceNeededHere = MSG_BUF_SIZE + ptextBuflen;  // This is the scratch space needed locally by bareStatsTX, excluding called functions.
+constexpr size_t StatsTX_WorkspaceSize = OTRadioLink::SimpleSecureFrame32or0BodyTXBase::generateSecureOFrameRawForTX_total_scratch_usage_OTAESGCM_2p0 + scratchSpaceNeededHere;
+static_assert(StatsTX_WorkspaceSize == 384, "StatsTX workspace size wrong!");  // Correct as of 20170704
+
+// CLI scratchspace
+static constexpr uint8_t MAXIMUM_CLI_RESPONSE_CHARS = 1 + OTV0P2BASE::CLI::MAX_TYPICAL_CLI_BUFFER;
+static constexpr uint8_t PollUI_WorkspaceSize = 1 + MAXIMUM_CLI_RESPONSE_CHARS;
+
+// Create workspace
+union GlobalWorkSpace {
+    uint8_t decode[Decode_WorkspaceSize];
+    uint8_t statsTX[StatsTX_WorkspaceSize];
+    uint8_t cli[PollUI_WorkspaceSize];
+};
+static GlobalWorkSpace globalWorkSpace;
+
+
+/******************************************************************************
+ * PERIPHERALS
+ * Peripheral drivers and config
+ *****************************************************************************/
+
+////// RADIOS
+
+// Pick an appropriate radio config for RFM23 (if it is the primary radio).
+// Nodes talking on fast GFSK channel 0.
+static constexpr uint8_t nPrimaryRadioChannels = 1;
+static const OTRadioLink::OTRadioChannelConfig RFM23BConfigs[nPrimaryRadioChannels] =
+  {
+  // GFSK channel 0 full config, RX/TX, not in itself secure.
+  OTRadioLink::OTRadioChannelConfig(OTRFM23BLink::StandardRegSettingsGFSK57600, true),
+  };
+static const OTRadioLink::OTRadioChannelConfig SecondaryRadioConfig(&SIM900Config, true);
+// Brings in necessary radio libs.
+static constexpr uint8_t RFM23B_RX_QUEUE_SIZE = OTRFM23BLink::DEFAULT_RFM23B_RX_QUEUE_CAPACITY;
+static constexpr int8_t RFM23B_IRQ_PIN = PIN_RFM_NIRQ;
+static constexpr bool RFM23B_allowRX = true;
+OTRFM23BLink::OTRFM23BLink<OTV0P2BASE::V0p2_PIN_SPI_nSS, RFM23B_IRQ_PIN, RFM23B_RX_QUEUE_SIZE, RFM23B_allowRX> PrimaryRadio;
+OTSIM900Link::OTSIM900Link<8, 5, RADIO_POWER_PIN, OTV0P2BASE::getSecondsLT> SecondaryRadio;
+
+////// SENSORS
+
+// Sensor for supply (eg battery) voltage in millivolts.
+OTV0P2BASE::SupplyVoltageCentiVolts Supply_cV;
+OTV0P2BASE::RoomTemperatureC16_TMP112 TemperatureC16;
+// Sense ambient lighting level.
+OTV0P2BASE::SensorAmbientLight AmbLight;
+
+////// ACTUATORS
+
+static constexpr bool enableDefaultAlwaysRX = true;
+static constexpr bool enableRadioRX = true;
+static constexpr bool allowGetMinBoilerOnMFromEEPROM = false;
+OTRadValve::OTHubManager<enableDefaultAlwaysRX, enableRadioRX, allowGetMinBoilerOnMFromEEPROM> hubManager;
+OTRadValve::BoilerLogic::OnOffBoilerDriverLogic<decltype(hubManager), hubManager, OUT_HEATCALL> BoilerHub;
+
+////// CONTROL
+
+
+////// MESSAGING
+// Managed JSON stats.
+// Number of JSON stats to TX:
+// Note: each stat statically allocates 6 bytes to RAM.
+// - Internal temp
+// - Boiler state
+// TODO: Consider removing entirely.
+constexpr uint8_t nTXStats = 2;
+static OTV0P2BASE::SimpleStatsRotation<nTXStats> ss1; // Configured for maximum different stats.
+
+
+/******************************************************************************
+ * INTERRUPT SERVICE ROUTINES
+ *****************************************************************************/
+
+// Controller's view of Least Significant Digits of the current (local) time, in this case whole seconds.
+// Previous state of port B pins to help detect changes.
+//
+// NOTE: PrimaryRadio may switch PCINT0 on and off during operation! This pin bank should not be relied
+//       upon for pin change interrupts!
+static volatile uint8_t prevStatePB;
+// Interrupt service routine for PB I/O port transition changes.
+ISR(PCINT0_vect)
+{
+    // Basic profiling info
+    OTV0P2BASE::MemoryChecks::recordPC();
+
+    const uint8_t pins = PINB;
+    const uint8_t changes = pins ^ prevStatePB;
+    prevStatePB = pins;
+
+    // RFM23B nIRQ falling edge is of interest.
+    // Handler routine not required/expected to 'clear' this interrupt.
+    if((changes & RFM23B_INT_MASK) && !(pins & RFM23B_INT_MASK))
+        { PrimaryRadio._handleInterruptNonVirtual(); }
+}
+
+// Previous state of port D pins to help detect changes.
+static volatile uint8_t prevStatePD;
+// Interrupt service routine for PD I/O port transition changes (including RX).
+// (DE20170810) Just does a store on an atomic_t. Low ram cost.
+ISR(PCINT2_vect)
+{
+    const uint8_t pins = PIND;
+    const uint8_t changes = pins ^ prevStatePD;
+    prevStatePD = pins;
+
+    // If an interrupt arrived from the serial RX then wake up the CLI.
+    // Use a nominally rising edge to avoid spurious trigger when other interrupts are handled.
+    // The will ensure that it is possible to wake the CLI subsystem with an extra CR or LF.
+    // It is OK to trigger this from other things such as button presses.
+    // TODO: ensure that resetCLIActiveTimer() is inlineable to minimise ISR prologue/epilogue time and space.
+    if((changes & SERIALRX_INT_MASK) && !(pins & SERIALRX_INT_MASK))
+    { OTV0P2BASE::CLI::resetCLIActiveTimer(); }
+}
+
+
+/******************************************************************************
+ * LOCAL FUNCTIONS
+ *****************************************************************************/
+
+////// PANIC
+
 // Indicate that the system is broken in an obvious way (distress flashing the main LED).
 // DOES NOT RETURN.
 // Tries to turn off most stuff safely that will benefit from doing so, but nothing too complex.
@@ -162,6 +311,9 @@
     panic();
 }

+
+////// DIAGNOSTICS
+
 /**
  * @brief   Force restart if SPAM/heap/stack likely corrupt.
  *          Complain and keep complaining when getting near stack overflow.
@@ -181,7 +333,7 @@
     OTV0P2BASE::serialPrintAndFlush(F(" prog: "));
     OTV0P2BASE::serialPrintAndFlush(progCounter, HEX);
     OTV0P2BASE::serialPrintlnAndFlush();
-    if (128 > minsp) panic(F("SH"));
+    if (64 > minsp) panic(F("SH"));
 //    OTV0P2BASE::MemoryChecks::forceResetIfStackOverflow();  // XXX
     OTV0P2BASE::MemoryChecks::resetMinSP();
 #else
@@ -189,6 +341,13 @@
     OTV0P2BASE::MemoryChecks::forceResetIfStackOverflow();
 #endif
 }
+
+
+////// SENSORS
+
+
+
+////// CONTROL

 // Call this to do an I/O poll if needed; returns true if something useful definitely happened.
 // This call should typically take << 1ms at 1MHz CPU.
@@ -218,6 +377,7 @@
   }

+////// MESSAGING
 /**
  * @brief   Wrapper function for secure frame decode/handle callback.
  * @param   msg: Raw RXed message. msgLen should be stored in the byte before
@@ -228,9 +388,7 @@
 inline bool decodeAndHandleSecureFrame(volatile const uint8_t * const msg)
 {
     // Create a workspace for large stack consuming items ahead of time, in order to improve stack usage visibility.
-    constexpr size_t workspaceSize = OTAESGCM::OTAES128GCMGenericWithWorkspace<>::workspaceRequiredDec + 16 + 58;
-    uint8_t workspace[workspaceSize];
-    OTV0P2BASE::ScratchSpaceL sW(workspace, sizeof(workspace));
+    OTV0P2BASE::ScratchSpaceL sW(globalWorkSpace.decode, sizeof(globalWorkSpace.decode));
     // Temporarily suspend PrimaryRadio interrupts to avoid stack collisions.
     PrimaryRadio.pauseInterrupts(true);
     const bool success = OTRadioLink::decodeAndHandleOTSecureOFrameWithWorkspace<
@@ -248,74 +406,7 @@
                                     decodeAndHandleSecureFrame, OTRadioLink::decodeAndHandleDummyFrame  // only interested in single frame type.
                                    > messageQueue;

-//========================================
-// INTERRUPT SERVICE ROUTINES
-//========================================
-// Controller's view of Least Significant Digits of the current (local) time, in this case whole seconds.
-// Previous state of port B pins to help detect changes.
-//
-// NOTE: PrimaryRadio may switch PCINT0 on and off during operation! This pin bank should not be relied
-//       upon for pin change interrupts!
-static volatile uint8_t prevStatePB;
-// Interrupt service routine for PB I/O port transition changes.
-ISR(PCINT0_vect)
-{
-    // Basic profiling info
-    OTV0P2BASE::MemoryChecks::recordPC();
-
-    const uint8_t pins = PINB;
-    const uint8_t changes = pins ^ prevStatePB;
-    prevStatePB = pins;
-
-    // RFM23B nIRQ falling edge is of interest.
-    // Handler routine not required/expected to 'clear' this interrupt.
-    if((changes & RFM23B_INT_MASK) && !(pins & RFM23B_INT_MASK))
-        { PrimaryRadio._handleInterruptNonVirtual(); }
-}
-
-// Previous state of port D pins to help detect changes.
-static volatile uint8_t prevStatePD;
-// Interrupt service routine for PD I/O port transition changes (including RX).
-// (DE20170810) Just does a store on an atomic_t. Low ram cost.
-ISR(PCINT2_vect)
-{
-    const uint8_t pins = PIND;
-    const uint8_t changes = pins ^ prevStatePD;
-    prevStatePD = pins;
-
-    // If an interrupt arrived from the serial RX then wake up the CLI.
-    // Use a nominally rising edge to avoid spurious trigger when other interrupts are handled.
-    // The will ensure that it is possible to wake the CLI subsystem with an extra CR or LF.
-    // It is OK to trigger this from other things such as button presses.
-    // TODO: ensure that resetCLIActiveTimer() is inlineable to minimise ISR prologue/epilogue time and space.
-    if((changes & SERIALRX_INT_MASK) && !(pins & SERIALRX_INT_MASK))
-    { OTV0P2BASE::CLI::resetCLIActiveTimer(); }
-}
-
-
-// Send the underlying stats binary/text 'whitened' message.
-// This must be terminated with an 0xff (which is not sent),
-// and no longer than STATS_MSG_MAX_LEN bytes long in total (excluding the terminating 0xff).
-// This must not contain any 0xff and should not contain long runs of 0x00 bytes.
-// The message to be sent must be written at an offset of STATS_MSG_START_OFFSET from the start of the buffer.
-// This routine will alter the content of the buffer for transmission,
-// and the buffer should not be re-used as is.
-//   * doubleTX  double TX to increase chance of successful reception
-//   * RFM23BfriendlyPremable  if true then add an extra preamble
-//     to allow RFM23B-based receiver to RX this
-// This will use whichever transmission medium/carrier/etc is available.
-static constexpr uint8_t RFM22_PREAMBLE_BYTES = 5; // Recommended number of preamble bytes for reliable reception.
-static constexpr uint8_t RFM22_SYNC_MIN_BYTES = 3; // Minimum number of sync bytes.
-static constexpr uint8_t STATS_MSG_START_OFFSET = (RFM22_PREAMBLE_BYTES + RFM22_SYNC_MIN_BYTES);
-static constexpr uint8_t STATS_MSG_MAX_LEN = (64 - STATS_MSG_START_OFFSET);
-// Managed JSON stats.
-// Number of JSON stats to TX:
-// Note: each stat statically allocates 6 bytes to RAM.
-// - Internal temp
-// - Boiler state
-// TODO: Consider removing entirely.
-constexpr uint8_t nTXStats = 2;
-static OTV0P2BASE::SimpleStatsRotation<nTXStats> ss1; // Configured for maximum different stats.
+
 // Do bare stats transmission.
 // Output should be filtered for items appropriate
 // to current channel security and sensitivity level.
@@ -325,7 +416,7 @@
 // Sends stats on primary radio channel 0 with possible duplicate to secondary channel.
 // If sending encrypted then ID/counter fields (eg @ and + for JSON) are omitted
 // as assumed supplied by security layer to remote recipent.
-__attribute__((noinline)) void bareStatsTX()
+void bareStatsTX()
 {
     // Note if radio/comms channel is itself framed.
     const bool neededWaking = OTV0P2BASE::powerUpSerialIfDisabled<>();
@@ -333,31 +424,7 @@
 static_assert(OTV0P2BASE::FullStatsMessageCore_MAX_BYTES_ON_WIRE <= STATS_MSG_MAX_LEN, "FullStatsMessageCore_MAX_BYTES_ON_WIRE too big");
 static_assert(OTV0P2BASE::MSG_JSON_MAX_LENGTH+1 <= STATS_MSG_MAX_LEN, "MSG_JSON_MAX_LENGTH too big"); // Allow 1 for trailing CRC.

-    /**
-     * The workspace consists of:
-     *   - Buffer to construct final message, size MSG_BUF_SIZE.
-     *     - buffer offset/preamble
-     *     - max binary length, or max JSON length + 1 for CRC + 1 to allow
-     *       detection of oversize message
-     *     - terminating 0xff
-     *     - Buffer need be no larger than leading length byte + typical
-     *       64-byte radio module TX buffer limit + optional terminator.
-     *   - Buffer for holding the JSON frame/plain text, size ptextBuflen.
-     *      - The plaintext buffer must hold the JSON frame plus the valvePC
-     *        and the "hasStats" indicator. As the plaintext must hold a copy
-     *        of the JSON frame, the JSON frame is constructed within it to
-     *        save on stack space and copying.
-     *   - Scratch space for the AESGCM decode function.
-     */
-    constexpr uint8_t MSG_BUF_SIZE = 1 + 64 + 1;
-    constexpr uint8_t bufJSONlen = OTRadioLink::ENC_BODY_SMALL_FIXED_PTEXT_MAX_SIZE + 1;  // 3 = '}' + 0x0 + ? FIXME whuut?
-    constexpr uint8_t ptextBuflen = bufJSONlen + 2;  // 2 = valvePC + hasStats
-    static_assert(ptextBuflen == 34, "ptextBuflen wrong");
-    constexpr uint8_t scratchSpaceNeededHere = MSG_BUF_SIZE + ptextBuflen;  // This is the scratch space needed locally by bareStatsTX, excluding called functions.
-    constexpr size_t workspaceSize = OTRadioLink::SimpleSecureFrame32or0BodyTXBase::generateSecureOFrameRawForTX_total_scratch_usage_OTAESGCM_2p0 + scratchSpaceNeededHere;
-    uint8_t workspace[workspaceSize];
-    static_assert(sizeof(workspace) == 384, "TX workspace size wrong!");  // Correct as of 20170704
-    OTV0P2BASE::ScratchSpaceL sW(workspace, sizeof(workspace));
+    OTV0P2BASE::ScratchSpaceL sW(globalWorkSpace.statsTX, sizeof(globalWorkSpace.statsTX));

     // Send binary *or* JSON on each attempt so as not to overwhelm the receiver.
     {
@@ -463,14 +530,14 @@
 }

+////// UI
+
 // Used to poll user side for CLI input until specified sub-cycle time.
 // Commands should be sent terminated by CR *or* LF; both may prevent 'E' (exit) from working properly.
 // A period of less than (say) 500ms will be difficult for direct human response on a raw terminal.
 // A period of less than (say) 100ms is not recommended to avoid possibility of overrun on long interactions.
 // Times itself out after at least a minute or two of inactivity.
 // NOT RENTRANT (eg uses static state for speed and code space).
-static constexpr uint8_t MAXIMUM_CLI_RESPONSE_CHARS = 1 + OTV0P2BASE::CLI::MAX_TYPICAL_CLI_BUFFER;
-static constexpr uint8_t BUFSIZ_pollUI = 1 + MAXIMUM_CLI_RESPONSE_CHARS;
 void pollCLI(const uint8_t maxSCT, const bool startOfMinute, const OTV0P2BASE::ScratchSpace &s)
 {
     // Perform any once-per-minute operations.
@@ -534,9 +601,10 @@
     if(neededWaking) { OTV0P2BASE::powerDownSerial(); }
 }

-//========================================
-// SETUP
-//========================================
+
+/******************************************************************************
+ * SETUP
+ *****************************************************************************/

 // Setup routine: runs once after reset.
 // Does some limited board self-test and will panic() if anything is obviously broken.
@@ -659,9 +727,11 @@
     TIME_LSD = OTV0P2BASE::getSecondsLT();
 }

-//========================================
-// MAIN LOOP
-//========================================
+
+/******************************************************************************
+ * MAIN LOOP
+ *****************************************************************************/
+
 void loop()
 {
     stackCheck();
@@ -832,8 +902,8 @@
     // and which should also allow some energy-saving sleep.
     if(OTV0P2BASE::CLI::isCLIActive()) {
         const uint8_t stopBy = nearOverrunThreshold - 1;
-        char buf[BUFSIZ_pollUI];
-        OTV0P2BASE::ScratchSpace s((uint8_t*)buf, sizeof(buf));
+        OTV0P2BASE::ScratchSpace s(globalWorkSpace.cli, sizeof(globalWorkSpace.cli));
         pollCLI(stopBy, 0 == TIME_LSD, s);
     }
 }
+


Update REV20Sensors.ino

Update REV20Sensors.ino

--- testsuite/REV20Sensors/REV20Sensors.ino
+++ testsuite/REV20Sensors/REV20Sensors.ino
@@ -125,8 +125,7 @@
 static constexpr bool binaryOnlyValveControl = false;
 static constexpr uint8_t m1 = MOTOR_DRIVE_ML;
 static constexpr uint8_t m2 = MOTOR_DRIVE_MR;
-typedef OTRadValve::ValveMotorDirectV1<m1, m2, MOTOR_DRIVE_MI_AIN, MOTOR_DRIVE_MC_AIN, decltype(Supply_cV), &Supply_cV, binaryOnlyValveControl> ValveDirect_t;
-// Singleton implementation/instance.
+OTRadValve::ValveMotorDirectV1HardwareDriver<m1, m2, MOTOR_DRIVE_MI_AIN, MOTOR_DRIVE_MC_AIN, motorNSleep> motorDriver;// Singleton implementation/instance.
 // Suppress unnecessary activity when room dark, eg to avoid disturbance if device crashes/restarts,
 // unless recent UI use because value is being fitted/adjusted.
 ValveDirect_t ValveDirect([](){return(AmbLight.isRoomDark());});


uso del controlador

uso del controlador

--- tcs230.ino
+++ tcs230.ino
@@ -1,78 +1,95 @@
-int s0=3, s1=4, s2=5, s3=6;
-int out=2;
-int flag=0;
+/**
+ *
+ * tcs230.ino
+ *
+ * @author Jose Patricio Hijuitl <patriciohc.0@gmail.com>
+ */

-byte counter=0;
-byte countR=0, countG=0, countB=0;
+#include <TimerOne.h>
+#include <LiquidCrystal.h>

-void setup()
-{
-	Serial.begin(115200);
-	pinMode(s0, OUTPUT);
-	pinMode(s1, OUTPUT);
-	pinMode(s2, OUTPUT);
-	pinMode(s3, OUTPUT);
+#include "ColorRecognition.h"
+#include "ColorRecognitionTCS230.h"
+#include "rgb_to_hsv.c"
+
+/*
+#define R 0
+#define G 1
+#define B 2
+*/
+int RGB[3] = {0,0,0};
+ColorRecognitionTCS230* tcs230;
+
+void setup() {
+	Serial.begin(9600);
+	tcs230 = ColorRecognitionTCS230::getInstance();
+	tcs230->initialize(2, 3, 4);
+	LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
+	LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
+	lcd.begin(16, 2);
+
+//debug
+/*	Serial.print("Ajust. blanco...");
+	Serial.print("Coloque blanco..");
+	Serial.print("Durante 5 sec.");
+*/
+	lcd.print("Ajust. white...");
+	lcd.setCursor(0, 1);
+	lcd.print("Show white..");
+	lcd.setCursor(0, 1);
+	lcd.print("During 5 sec.");
+	Show something white to it during 4 seconds.
+	tcs230->adjustWhiteBalance();
 }

-void TCS()
-{
-	flag=0;
-	digitalWrite(s1, HIGH);
-	digitalWrite(s0, HIGH);
-	digitalWrite(s2, LOW);
-	digitalWrite(s3, LOW);
-	attachInterrupt(0, ISR_INTO, LOW);
-	timer0_init();
+/*
+toma 10 lecturas de rgb y retorna el promedio
+*/
+void avg(){
+	RGB[RED]= 0;
+	RGB[GREEN]= 0;
+	RGB[BLUE]= 0;
+	delay(2000);
+	for(int i = 0; i<10; i++){
+		delay(500);
+		RGB[RED] += tcs230->getRed();
+		RGB[GREEN] += tcs230->getGreen();
+		RGB[BLUE] += tcs230->getBlue();
+	}
+	RGB[RED] /= 10;
+	RGB[GREEN] /= 10;
+	RGB[BLUE] /= 10;
 }

-void ISR_INTO()
-{
-	counter++;
+void loop() {
+	int H;
+	float S,V;
+	lcd.setCursor(0, 1);
+	delay(3000);
+	avg();
+	RGB_to_HSV(RGB, &H, &S, &V);
+	if (H < 65 && V > 70){
+		lcd.print("add solution");
+	}else if(H < 68 && V < 65){
+		lcd.print("perfect");
+	}else{
+		lcd.print("change solution")
+	}
+/*
+	Serial.print("H = ");
+	Serial.println(H);
+	Serial.print("S = ");
+	Serial.println(S);
+	Serial.print("V = ");
+	Serial.println(V);
+	Serial.println("-------------------");
+	Serial.print("Red: ");
+	Serial.println(tcs230->getRed());
+	Serial.print("Green: ");
+	Serial.println(tcs230->getGreen());
+	Serial.print("Blue ");
+	Serial.println(tcs230->getBlue());
+	Serial.println("-------------------");
+	delay(3000);*/
+
 }
-
-void timer0_init(void)
-{
-	TCCR2A = 0x00;
-	TCCR2B = 0x07; //the clock frequency source 1024 points
-	TCNT2 = 100;  //10 ms overflow again
-	TIMSK2 = 0x01; //allow interrupt
-}
-
-int i=0;
-
-/*the timer 2, 10ms interrupt overflow again. Internal overflow interrupt
-executive function*/
-ISR(TIMER2_OVF_vect)
-{
-	TCNT2=100;
-	flag++;
-	if (flag==1) {
-		countR=counter;
-		Serial.print("red=");
-		Serial.println(countR,DEC);
-		digitalWrite(s2,HIGH);
-		digitalWrite(s3,HIGH);
-	} else if (flag==2) {
-		countG=counter;
-		Serial.print("green=");
-		Serial.println(countG,DEC);
-		digitalWrite(s2,LOW);
-		digitalWrite(s3,HIGH);
-	} else if (flag==3) {
-		countB=counter; //Future Electronics Egypt Ltd. (Arduino Egypt).
-		Serial.print("blue=");
-		Serial.println(countB,DEC);
-		Serial.println("\n");
-		digitalWrite(s2,LOW);
-		digitalWrite(s3,LOW);
-	} else if (flag==4) {
-		flag=0;
-	}
-	counter=0;
-}
-
-void loop()
-{
-	TCS();
-	while (1);
-}


D and L commands also output something on Serial when done

D0# outputs D0#
L0# outputs L0#
this is useful when we have multiple controllers and we want to wait a
L0# before we start the next one (for instance we want to make sure that
we have locked the base motors before moving the hand)

--- jenny5-firmware/jenny5-firmware.ino
+++ jenny5-firmware/jenny5-firmware.ino
@@ -22,7 +22,7 @@

 char is_command_running;

-char firmware_version[] = "2015.12.26.3";// year.month.day.build number
+char firmware_version[] = "2015.12.27.0";// year.month.day.build number

 char current_buffer[65];

@@ -40,14 +40,14 @@
   Serial.write("Jenny 5 firmware version: ");
   Serial.write(firmware_version);
   Serial.write('\n');
-  Serial.write("##");// initialization is over; must check for ## string
+  Serial.write("#");// initialization is over; must check for # string

   /*
   Serial.write("Commands are:");
   Serial.println(F("T# // test connection. Returns T#."));
   Serial.println(F("Mx y# // Moves motor x with y steps. If y is negative the motor runs in the opposite direction. The motor remains locked at the end of the movement. Outputs Mx d# when motor rotation is over. If movement was complete, then d is 0, otherwise is the distance to go."));
-  Serial.println(F("Dx#  // Disables motor x."));
-  Serial.println(F("Lx#  // Lock motor x. Outputs Dx#"));
+  Serial.println(F("Dx#  // Disables motor x. Outputs Dx# when done."));
+  Serial.println(F("Lx#  // Lock motor x. Outputs Lx# when done."));
   Serial.println(F("SMx s a# // Sets speed of motor x to s and the acceleration to a."));
   Serial.println(F("SPx min max home# // Sets the parameters of a potentiometer. Min and max are the limits where it can move and home is from where we bring the robot when we start."));
   Serial.println(F("Ax n Py Bz ... # // Attach to motor x a list of n sensors (like Potentiometer y, Button z etc)."));
@@ -87,6 +87,9 @@
           int motor_index;
           sscanf(tmp_str + i + 1, "%d", &motor_index);
           motors_control.disable_motor(motor_index);
+          Serial.write("D");
+          Serial.print(m);
+          Serial.write('#');
           i++;
         }
         else
@@ -94,6 +97,9 @@
             int motor_index;
             sscanf(tmp_str + i + 1, "%d", &motor_index);
             motors_control.lock_motor(motor_index);
+            Serial.write("L");
+            Serial.print(m);
+            Serial.write('#');
             i++;
           }
         else
@@ -334,4 +340,4 @@
     }
   }
 }
-
+//------------------------------------------------------------------------------


Added all libraries, now in size problems!

--- BuggyTracker/BuggyTracker.ino
+++ BuggyTracker/BuggyTracker.ino
@@ -1,96 +1,139 @@
 #include <SPI.h>
 #include <boards.h>
 #include <RBL_nRF8001.h>
+#include <SD.h>
+#include <Wire.h>
+#include <RTClib.h>
+//#include <DS1307RTC.h>

-  /*
-  * a single revoluion of the wheel has this distance in mm (89,5 cm)
-   */
-  #define distance 895
+
+/*
+ * a single revoluion of the wheel has this distance in mm (89,5 cm)
+ */
+#define distance 895

 long curDistance = 0;
 int LED = 13;
 const int interupt = 3; // pin D1 on Leonardo!
+const int chipSelect = 10;
+File dataFile;
+RTC_DS1307 RTC;

 void setup()
 {
-    pinMode(LED, OUTPUT);
+  pinMode(LED, OUTPUT);

-    attachInterrupt(interupt, BtnDownCB, FALLING );
+  attachInterrupt(interupt, BtnDownCB, FALLING );

-    // Call the function to enable low power consumption
-    ble_low_power();
+  // Call the function to enable low power consumption
+  ble_low_power();

-    // If you are using the Blend, uncomment below
-    ble_set_pins(6, 7);
-    ble_set_name("Stroller");
+  // If you are using the Blend, uncomment below
+  ble_set_pins(6, 7);
+  ble_set_name("Stroller");

-    // Init. and start BLE library.
-    ble_begin();
+  // Init. and start BLE library.
+  ble_begin();
+
+  // prepare SD data logging!
+
+  if (!SD.begin(10, 11, 12, 13)) { // important: this is custom code for the leonardo, see https://learn.adafruit.com/adafruit-data-logger-shield/for-the-mega-and-leonardo
+//
+  }
+  else {
+
+    // Open up the file we're going to log to!
+    dataFile = SD.open("datalog.txt", FILE_WRITE);
+
+  }
+
 }

+
 volatile int hadRound = 0;
+

 void loop()
 {
   if (hadRound== 1) {
-     // compare the time of the last logged or the current logged value
-     // the actual calculation
-     curDistance = curDistance + distance;
-
-     hadRound=0;
-
+    // compare the time of the last logged or the current logged value
+    // the actual calculation
+      curDistance = curDistance + distance;
+      // write to SD card
+      long time = RTC.now().unixtime();
+
+
+
+      hadRound=0;
+
   }
-    if (ble_available() )
+  if (ble_available() )
+  {
+    uint8_t temp;
+    while ( ble_available() )
     {
-        uint8_t temp;
-        while ( ble_available() )
-        {
-          temp = ble_read();
-          if ('r' == temp) { // read comand from smartphone)
-            String output = "D: ";
-            output+=curDistance;
-            output+="\n";
-            int length= output.length()+1;
-            char charBuf[length];
-            output.toCharArray(charBuf,output.length()+1);
-            for (int i=0; i<length;i++) {
+      temp = ble_read();
+      if ('r' == temp) { // read comand from smartphone)
+//        int length = 4+sizeof(curDistance);
+        String output = "D:";
+        output+=curDistance;
+        output+="\n";
+        byte length= output.length()+1;
+
+        unsigned char charBuf[length];
+        charBuf[0]='D';
+        charBuf[1]=':';
+          ble_write('D');
+          ble_write(':');
+//           byte b[4];
+//           ble_write((int)curDistance>>24);
+//           ble_write((int)curDistance>>16);
+//           ble_write((int)curDistance>>8);
+//           ble_write((int)curDistance);
+//          IntegerToBytes(curDistance, b);
+          for (byte i=0; i<length; ++i) {
               ble_write(charBuf[i]);
-            }
-          } else if ( 'c' == temp ) { // aCcept or commit command from smartphone, later used for resetting
-            ble_write_bytes((unsigned char *)"not yet implemented", 19);
+
           }
-//            temp = ble_read();
-//            if('o' == temp)
-//            {
-//                temp = ble_read();
-//                if('n' == temp)
-//                {
-//
-//                    ble_write_bytes((unsigned char *)"LED on", 6);
-//                }
-//                else if('f' == temp && 'f' == ble_read())
-//                {
-//                    ble_write_bytes((unsigned char *)"LED off", 7);
-//                }
-//            }
-        }
+          ble_write('\n');
+      }
+      else if ( 'c' == temp ) { // aCcept or commit command from smartphone, later used for resetting
+        curDistance=0;
+        ble_write_bytes((unsigned char *)"reset", 5);
+      }
+      //            temp = ble_read();
+      //            if('o' == temp)
+      //            {
+      //                temp = ble_read();
+      //                if('n' == temp)
+      //                {
+      //
+      //                    ble_write_bytes((unsigned char *)"LED on", 6);
+      //                }
+      //                else if('f' == temp && 'f' == ble_read())
+      //                {
+      //                    ble_write_bytes((unsigned char *)"LED off", 7);
+      //                }
+      //            }
     }
-//    delay(100);
-    digitalWrite(LED,LOW);
-    ble_do_events();
+  }
+  //    delay(100);
+  digitalWrite(LED,LOW);
+  ble_do_events();
 }

 void BtnDownCB()
 {
-    PRR0 = 0x00;  // Power Reduction Register: open timer
-    PRR1 = 0x00;
+  PRR0 = 0x00;  // Power Reduction Register: open timer
+  PRR1 = 0x00;
   digitalWrite(LED,HIGH);
   hadRound = 1;
-//    delay(100);  //jitters elimination
-//    if(LOW == digitalRead(1))
-        if ( ble_connected() )
-        {
-            ble_write_bytes((unsigned char *)"Button down", 11);
-        }
+  //    delay(100);  //jitters elimination
+  //    if(LOW == digitalRead(1))
+  if ( ble_connected() )
+  {
+    ble_write_bytes((unsigned char *)"Button down", 11);
+  }

 }
+


Improve pitch mapping

Improve pitch mapping

Signed-off-by: Mark Knoop <f1b5a91d4d6ad523f2610114591c007e75d15084@markknoop.com>

--- src/sketch.ino
+++ src/sketch.ino
@@ -100,9 +100,9 @@

 int pitchToPulse(float pitch) {
     /* map MIDI pitch to motor pulse duration */
-    float i = ((71 - constrain(pitch, 36, 72)) * 71) / 33;
-    float p = 1 - log10(((72 - i) * 0.125) + 1);
-    return 500 + (3500 * p);
+    float i = pitch - 71;
+    float p = 1 - log10((i / 51.035) + 1);
+    return max(412, (pow(p, 4.8) * 700) - 260);
 }

 float pitchbyteToMidi(byte pitch) {


20150217.1109

--- cmdMULTIsens/src/sketch.ino
+++ cmdMULTIsens/src/sketch.ino
@@ -74,4 +74,5 @@
     Serial.println(" !");             // Signal end of telegram

     digitalWrite(ActivityLED, LOW);   // end of activity
+  }
 }


Arduinoコードを復旧

Arduinoコードを復旧

何故か古い方のコードをpushしてしまっていたので直した…

--- app/inTheDuck/LoverDuck.ino
+++ app/inTheDuck/LoverDuck.ino
@@ -1,20 +1,38 @@
+#include <Adafruit_NeoPixel.h>
+
 #include <Adafruit_Sensor.h>
 #include <Adafruit_LSM303.h>
 #include <Wire.h>
 #include <SoftwareSerial.h>
 SoftwareSerial BT(10,11);
 //RX/TX
+
+#define tonePin 2
+#define buttonPin 3
+#define ledPinA 6 //6 leds here
+#define ledNumA 6
+#define ledPinB 7 //4 leds here
+#define ledNumB 4
+
+Adafruit_NeoPixel pixelsA = Adafruit_NeoPixel(ledNumA, ledPinA, NEO_GRB + NEO_KHZ800);
+Adafruit_NeoPixel pixelsB = Adafruit_NeoPixel(ledNumB, ledPinB, NEO_GRB + NEO_KHZ800);
+int color[]={0,250,50};
+int startColor[]={0, 0, 250};
+int endColor[]={0, 250, 0};
+unsigned long mode1Duration=1*60*1000;
+
+
 Adafruit_LSM303 lsm;
-boolean isBT=false;
+boolean isBT=true;
 String idString="00";
-int tonePin=2;
-
-int buttonPin=3;
-boolean isON=false;
+
+int mode=1; //0 is off, 1 is on, 2 is warning
 int buttonState;
 int lastButtonState=HIGH;
 unsigned long lastDebounceTime=0;
 unsigned long debounceDelay=50;
+
+unsigned long startCurrentMode=0;

 void setup() {
   // put your setup code here, to run once:
@@ -28,33 +46,31 @@
     while(1);
   }
   pinMode(buttonPin, INPUT_PULLUP);
-  pinMode(LED_BUILTIN, OUTPUT);
+  pixelsA.begin();
+  pixelsB.begin();
 }

 void loop() {
   // toggle on/off states
   checkButton();
-
-  if(isON){
-    digitalWrite(LED_BUILTIN, HIGH);
-  }else{
-    digitalWrite(LED_BUILTIN, LOW);
-  }
+

   // send accelerometer data once every 100ms
   processData();

   if(comAvailable()>0){
     int data=comRead();
-    switch(data){
-      case 1:
-        warning();
-        break;
-      default:
-        //do nothing
-        break;
-    }
-  }
+//    switch(data){
+//      case 1:
+//        changeMode(2);
+//        break;
+//      default:
+//        //do nothing
+//        break;
+//    }
+  changeMode(2);
+  }
+  setColors();
 }

 //toggles on/off
@@ -68,7 +84,12 @@
       if(reading != buttonState){
         buttonState=reading;
         if(buttonState==LOW){
-          isON=!isON;
+          if(mode != 0){
+            changeMode(0);
+          }
+          else{
+            changeMode(1);
+          }
         }
       }
       }
@@ -76,7 +97,7 @@
 }

 unsigned long previousProcess=0;
-unsigned long sendInterval=100;
+unsigned long sendInterval=50;
 void processData(){
   if((millis()-previousProcess)>sendInterval){
     float data[6];
@@ -97,9 +118,7 @@
 }

 void sendLSMData(float data[]){
-  mySend("x"+(String)data[0]);
-  mySend("y"+(String)data[1]);
-  mySend("z"+(String)data[2]);
+  mySend((String)data[0]+" "+(String)data[1]+" "+(String)data[2]+" "+ (String)mode);
 }

 void comBegin(int speed){
@@ -114,7 +133,7 @@

 void mySend(String s){
   //add device ID
-  s=idString+s;
+  s=idString+" "+s;
   if(isBT){
     BT.println(s);
   }
@@ -126,7 +145,7 @@
 boolean comAvailable(){
   boolean value;
   if(isBT){
-    value=BT.available();
+    value=BT.available();
   }
   else{
     value=Serial.available();
@@ -145,13 +164,126 @@
   return value;
 }

-void warning(){
-  for(int i=0; i<4; i++){
-    tone(tonePin, 900);
-    delay(500);
-    tone(tonePin, 700);
-    delay(250);
-  }
-  noTone(tonePin);
-}
-
+//void warning(){
+//  for(int i=0; i<4; i++){
+//    tone(tonePin, 900);
+//    delay(500);
+//    tone(tonePin, 700);
+//    delay(250);
+//  }
+//  noTone(tonePin);
+//}
+
+int LEDangles[]={355, 5, 67, 77, 139, 149, 211, 221, 283, 293};
+void setLED(int i, int c[]){
+  for(int j ; j<3; j++){
+    if(c[j]<20){
+      c[j]=0;
+    }
+  }
+  if(i<6){
+    pixelsA.setPixelColor(5-i, pixelsA.Color(c[0], c[1], c[2]));
+    pixelsA.show();
+  }
+  else{
+    pixelsB.setPixelColor(i-6, pixelsA.Color(c[0], c[1], c[2]));
+    pixelsB.show();
+  }
+}
+void setColors(){
+  switch(mode){
+    case 1:{
+      float ratio= 0.7+ 0.3 * sin(((millis()/10)%360)*3.14/180);
+      int tmp[3];
+      for(int i=0; i<3; i++){
+        long a=(endColor[i]-startColor[i])*(millis()-startCurrentMode);
+        if(endColor[i]-startColor[i] <0){
+          a=-abs(a);
+        }
+        color[i]=(a/mode1Duration+startColor[i])%256;
+//        color[i]=startColor[i];
+        color[i]=(int)(color[i]*ratio);
+      }
+
+      if(millis()-startCurrentMode>mode1Duration){
+        changeMode(3);
+      }
+      break;}
+    case 2:
+      if((millis()-startCurrentMode)%1000<600){
+        color[0]=200;
+        color[1]=200;
+        color[2]=200;
+      }
+      else{
+        color[0]=0;
+        color[1]=0;
+        color[2]=0;
+      }
+      //possible drowning
+      break;
+    case 3:
+      //10 minutes have passed
+      if((millis()-startCurrentMode)%2000<1000){
+        color[0]=0;
+        color[1]=200;
+        color[2]=0;
+      }
+      else{
+        color[0]=0;
+        color[1]=0;
+        color[2]=0;
+      }
+      break;
+    case 0:
+        color[0]=0;
+        color[1]=0;
+        color[2]=0;
+        break;
+    default:
+      break;
+  }
+  for(int i=0; i<10; i++){
+    setLED(i, color);
+  }
+}
+
+void changeMode(int i){
+  switch(i){
+    case 1:
+      //normal mode
+      //tracks how much time has passed since start of mode1
+      break;
+    case 2:
+      //warning mode- possible drowning
+      break;
+    case 3:
+      //warning mode- 10minutes have passed
+      break;
+    default:
+      break;
+  }
+  startCurrentMode=millis();
+  mode=i;
+}
+
+//phi is angle of LED
+//theta is edge of current LED lgihting state
+float getRatio(float phi, float theta){
+  float width=100;
+  if(theta-width<0){
+    if(theta<phi || 360+theta-width < phi){
+      return 0.0;
+    }
+    else if(phi<=theta){
+      return (phi-theta+width)/width;
+    }
+    else{
+      return (phi-360.0-theta+width)/width;
+    }
+  }
+  else{
+    return (phi-theta+width)/width;
+  }
+  return 0.0;
+}


Changed thrust smoothing code to instantly drop to target thrust when that is a reduction in power.

--- arduino/OpenROV/OpenROV.ino
+++ arduino/OpenROV/OpenROV.ino
@@ -59,6 +59,23 @@
     readings[thisReading] = 0;
 }

+int smoothAdjustedServoPosition(int target, int current){
+  // if the MIDPOINT is betwen the change requested in velocity we want to go to MIDPOINT first, and right away.
+  if (((current < MIDPOINT) && (MIDPOINT < target)) || ((target < MIDPOINT) && (MIDPOINT < current))){
+    return MIDPOINT;
+  }
+  // if the change is moving us closer to MIDPOINT it is a reduction of power and we can move all the way to the target
+  // in one command
+  if (abs(MIDPOINT-target) < abs(MIDPOINT-current)){
+    return target;
+  }
+  // else, we need to smooth out amp spikes by making a series of incrimental changes in the motors, so only move part of
+  // the way to the target this time.
+  double x = target - current;
+  int sign = (x>0) - (x<0);
+  return(current + sign * (min(abs(target - current), smoothingIncriment)));
+}
+
 void loop(){

   if (Serial.available()) {
@@ -98,14 +115,10 @@
   //to their new positions in increments.  The incriment should eventually be adjustable from the cockpit so that
   //the pilot could have more aggressive response profiles for the ROV.
   if (controltime.elapsed (50)) {
-    if (p<new_p) new_p -= min(smoothingIncriment,new_p-p);
-    if (p>new_p) new_p += min(smoothingIncriment,p-new_p);
-    if (v<new_v) new_v -= min(smoothingIncriment,new_v-v);
-    if (v>new_v) new_v += min(smoothingIncriment,v-new_v);
-    if (s<new_s) new_s -= min(smoothingIncriment,new_s-s);
-    if (s>new_s) new_s += min(smoothingIncriment,s-new_s);
-    if (tilt_val<new_tilt) new_tilt -= min(smoothingIncriment,new_tilt-tilt_val);
-    if (tilt_val>new_tilt) new_tilt += min(smoothingIncriment,tilt_val-new_tilt);
+    new_p = smoothAdjustedServoPosition(p,new_p);
+    new_v = smoothAdjustedServoPosition(v,new_v);
+    new_s = smoothAdjustedServoPosition(s,new_s);
+    new_tilt = smoothAdjustedServoPosition(tilt_val,new_tilt);
     tilt.writeMicroseconds(new_tilt);
     motors.go(new_p, new_v, new_s);
   }


Minor PID Changes.

Minor PID Changes.


button buffer wip

button buffer wip

--- saymon_says/saymon_says.ino
+++ saymon_says/saymon_says.ino
@@ -31,10 +31,17 @@
 const int stateNewLevel = 3;
 const int statePressedOk = 4;

+const int buttonUnknow = 0;
+const int buttonDown = 1;
+const int buttonPressed = 3;
+
+
 int level;
 int state;
 int sequence[maxLength];
 int currentPlayingSeqIndex;
+int stateRedButton;
+int buttonStates[4] = { buttonUnknow, buttonUnknow, buttonUnknow, buttonUnknow };

 void setup() {
   Serial.begin(9600);
@@ -56,9 +63,16 @@
     sequence[i] = redButton;
   }

+  stateRedButton = 0;
+
 }

 void loop() {
+
+    computeButtonStates(0, redButton, redLed);
+    computeButtonStates(1, greenButton, greenLed);
+    computeButtonStates(2, yellowButton, yello);
+    computeButtonStates(3, blueButton);

   if (state == stateNewLevel) {
     level ++;
@@ -113,8 +127,21 @@
     displayWrite("ripeti");
     currentPlayingSeqIndex = 0;

-  }
-
+  }
+
+  if (state == statePlay) {
+
+
+
+
+  //    stateRedButton = analogRead(A0);
+//      stateRedButton = analogRead(A0);
+  //    stateRedButton = analogRead(A0);
+    //  stateRedButton = analogRead(A0);
+  }
+
+//  Serial.println(analogRead(A0));
+  /*
   if (pressed(redButton) && (state == statePlay)) {
     checkPressing(redLed, NOTE_C4, redButton);
   } else if (pressed(greenButton) && (state == statePlay)) {
@@ -124,7 +151,26 @@
   } else if (pressed(blueButton) && (state == statePlay)) {
     checkPressing(blueLed, NOTE_F4, blueButton);
   }
-
+  */
+
+}
+
+void computeButtonStates(int index, int button, int led) {
+      int tmpVal = analogRead(button);
+      delay(20);
+      if (tmpVal > 900) {
+        buttonStates[index] = buttonDown;
+        digitalWrite(led, HIGH);
+      } else {
+        if (buttonStates[index] == buttonDown) {
+          //Serial.print(index);
+          //Serial.println("pressed");
+          buttonStates[index] = buttonPressed;
+          digitalWrite(led, LOW);
+        }
+      }
+
+
 }

 void checkPressing(int led, unsigned int note, int button) {
@@ -142,7 +188,7 @@
          displayWrite("sbagliato");
          state = stateEnd;
        }
-                delay(1000);
+          delay(1000);
           noTone(tonePin);
           allLedOff();


No 'defensive programming'

No 'defensive programming'

--- arduino/MoonPhaseCalendar/MoonPhaseCalendar.ino
+++ arduino/MoonPhaseCalendar/MoonPhaseCalendar.ino
@@ -1,5 +1,7 @@
 // Moon Phase Calendar for Arduino, using Pro Trinket 3V/12MHz
 // Copyright 2015 by Mark Moene
+
+#include <assert.h>

 #define dimension_of( a ) ( sizeof(a) / sizeof(0[a]) )

@@ -76,7 +78,9 @@
     };
     static_assert( dimension_of(pattern) == phase_count, "expecting #pattern == pin_moon_count" );

-    const int code = pattern[ phase % phase_count ];
+    assert( 0 <= phase && phase < phase_count );
+
+    const int code = pattern[ phase ];

     for ( int i = 0; i < pin_moon_count; ++i )
     {


worked on the oszi example. im putting way too much effort in this XD

--- examples/STIXXXWT_Example_Oszi/STIXXXWT_Example_Oszi.ino
+++ examples/STIXXXWT_Example_Oszi/STIXXXWT_Example_Oszi.ino
@@ -21,36 +21,132 @@

 STIXXXWT display;

+float analogDivider = 1023.0;
+uint16_t currentX = 0;
+dynamicCurvePoint data;
+uint16_t resYm1,resX,resY;
+//color16 lineColor;
+
 void setup()
 {
-    display.connect(&Serial,19200);
-    display.sendHandshake(); //get infos
+    display.connect(&Serial1,115200);
+    for(int i = 0; i < 10; i++){
+        display.sendHandshake(); //get infos
+        delay(200);
+        display.checkSerial();
+        if(display.getResX() > 0){ //sometimes i had trouble getting the resolution from the display, thats why i do this loop
+            break;
+        }
+    } //if we didnt get res after 2 seonds we give up
     display.clearScreen();
+
+    //lineColor = color16(255,255,0);
+    data.color = color16(255,255,0);//set color beforehand because it wont change
+    resY = display.getResY();
+    resYm1 = display.getResY()-1;
+    resX = display.getResX();
+
+    #ifdef __SAM3X8E__ //due only
+    setupDue();
+    #endif
 }

-uint16_t currentX = 0;
+#define SAMPLES (320)
+uint16_t samples[SAMPLES];
 void loop()
 {
-    display.checkSerial(); //check if the display sent us something
-    delay(10);
-    float a = analogRead(0)/1023.0;
-    float b = analogRead(1)/1023.0;
-    float c = analogRead(2)/1023.0;
-    float d = analogRead(3)/1023.0;
-    dynamicCurvePoint data[4];
-    data[0].y = a*display.getResY();
-    data[0].color = color16(255,0,0);
-    data[1].y = b*display.getResY();
-    data[1].color = color16(0,255,0);
-    data[2].y = c*display.getResY();
-    data[2].color = color16(0,0,255);
-    data[3].y = d*display.getResY();
-    data[3].color = color16(255,255,0);
+    //display.checkSerial(); //optional check if the display sent us something. we dont expect anything from the display anymore so we just dont check
+    //delayMicroseconds(25); //4000 samples a second. have to test if the display can keep up
+    for(int i =0; i< SAMPLES;i++){
+        #ifdef __SAM3X8E__
+        samples[i] = customAnalogRead(0);
+        #else
+        samples[i] = analogRead(0);
+        #endif
+    }
+
+    int factor = SAMPLES / resX;
+    for(int i =0; i< resX;i++){
+      uint16_t tmp = 0;
+      for(int j = 0; j< factor;j++){
+        tmp += samples[i*factor+j];
+      }
+      tmp/=factor;
+      data.y = tmp/analogDivider * resY;
+      display.drawDynamicCurvePoint(i,0,resYm1,0,data);
+    }
+    //data.y = a*display.getResY();

-    display.drawDynamicCurvePoints(currentX,0,display.getResY()-1,0,data,4);

-    currentX++;
-    if(currentX >= display.getResX()){
-        currentX = 0;
+    //display.drawDynamicCurvePoint(currentX,0,resYm1,0,data);
+
+    //currentX++;
+    //if(currentX >= resX){
+    //    currentX = 0;
+    //}
+}
+
+#ifdef __SAM3X8E__
+void setupDue(){
+    //make analog read faster.
+    REG_ADC_MR = (REG_ADC_MR & ~ADC_MR_STARTUP_Msk) | ADC_MR_STARTUP_SUT0; // setting startup time to 0 ADC clock cycles
+    REG_ADC_MR = (REG_ADC_MR & ~ADC_MR_FREERUN) | ADC_MR_FREERUN_ON; //enable FREERUN mode
+    analogReadResolution(12);
+    analogDivider = 4096.0;
+}
+
+uint32_t customAnalogRead(uint8_t ulPin){
+    //this is basically a copy from wiring_analog.c but with minor differences (no clue if it really brings any speed, but lets give it a try)
+    uint32_t ulValue = 0;
+    uint32_t ulChannel;
+
+    if (ulPin < A0)
+    ulPin += A0;
+
+    ulChannel = g_APinDescription[ulPin].ulADCChannelNumber ;
+
+    static uint32_t latestSelectedChannel = -1;
+    switch ( g_APinDescription[ulPin].ulAnalogChannel )
+    {
+        // Handling ADC 12 bits channels
+        case ADC0 :
+        case ADC1 :
+        case ADC2 :
+        case ADC3 :
+        case ADC4 :
+        case ADC5 :
+        case ADC6 :
+        case ADC7 :
+        case ADC8 :
+        case ADC9 :
+        case ADC10 :
+        case ADC11 :
+            // Enable the corresponding channel
+            if (ulChannel != latestSelectedChannel) {
+                adc_enable_channel( ADC, static_cast<adc_channel_num_t>(ulChannel));
+                if ( latestSelectedChannel != (uint32_t)-1 )
+                    adc_disable_channel( ADC, static_cast<adc_channel_num_t>(latestSelectedChannel));
+                latestSelectedChannel = ulChannel;
+            }
+
+            // Start the ADC
+            adc_start( ADC );
+
+            // Wait for end of conversion
+            while ((adc_get_status(ADC) & ADC_ISR_DRDY) != ADC_ISR_DRDY)
+                ;
+
+            // Read the value
+            ulValue = adc_get_latest_value(ADC);
+            //ulValue = mapResolution(ulValue, ADC_RESOLUTION, _readResolution); //we dont need map resolution. we want the full 12 bit. yes i know that this will only shed a few instructions.
+
+            break;
+
+        // Compiler could yell because we don't handle DAC pins
+        default :
+            ulValue=0;
+            break;
     }
-}+    return ulValue;
+}
+#endif


Faster PACMAN operation

Faster PACMAN operation

--- PACMAN/arduino_firmware/ArduinoProMini/dusty_acorn/dusty_acorn.ino
+++ PACMAN/arduino_firmware/ArduinoProMini/dusty_acorn/dusty_acorn.ino
@@ -121,10 +121,8 @@
 }
 void loop(){
 	timer1 = millis();
-	if  ((timer1 - timer0) > 1000) {
+	if  ((timer1 - timer0) > 500) {
 		timer0 = timer1;
 		SendData();
-		if (dustport.available())
-			Serial.readBytes((char *)readbuffer,64);
 	}
 }


Add button press update

Add button press update

--- moteino/node_heater/node_heater.ino
+++ moteino/node_heater/node_heater.ino
@@ -72,6 +72,21 @@

 void updateHeater(char msg)
 {
+  bool powerToggle = ((msg & 0x1) == 0x1);
+  int delta = (msg >> 1) & 0x3f;
+  if ((msg & 0x80) != 0x0) {
+    delta *= -1;
+  }
+
+  if (powerToggle) {
+    power();
+  }
+
+  if (delta > 0) {
+    tempUp(delta);
+  } else if (delta < 0) {
+    tempDown(abs(delta));
+  }
 }

 void loop()
@@ -86,7 +101,7 @@

       DEBUG_PRINT("rx: %#x after %u ms\n", radio.DATA[0], millis() - requestTime);

-      // updateHeater(radio.DATA[0]);
+      updateHeater(radio.DATA[0]);

       listen = false;
     } else {
@@ -101,9 +116,9 @@
     radio.sleep();

     Serial.flush();
-    //for (int i = 0; i < 4; ++i) {
-      LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
-    //}
+    for (int i = 0; i < 2; ++i) {
+      LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
+    }

     if (request()) {
       listen = true;
@@ -132,6 +147,7 @@

 void press(byte button, int duration)
 {
+  DEBUG_PRINT("press %d\n", button);
   pinMode(button, OUTPUT);
   pinMode(LED, OUTPUT);
   digitalWrite(button, HIGH);
@@ -144,22 +160,25 @@

 void power()
 {
+  DEBUG_PRINT("switch power\n");
   press(BTN_POW, 1500);
 }

-void temp(byte button, int count)
+void changeTemp(byte button, int count)
 {
-  for (int i = 0; i < count + 1; i++) {
+  for (int i = 0; i < count + 1; i++) { // extra initial press to change temp
     press(button, 400);
   }
 }

 void tempUp(int count)
 {
-  temp(BTN_UP, count);
+  DEBUG_PRINT("temp up %d\n", count);
+  changeTemp(BTN_UP, count);
 }

 void tempDown(int count)
 {
-  temp(BTN_DOWN, count);
+  DEBUG_PRINT("temp down %d\n", count);
+  changeTemp(BTN_DOWN, count);
 }


Issue #32

Issue #32

* Fix bad line in ESP example

--- examples/esp/example.ino
+++ examples/esp/example.ino
@@ -145,7 +145,7 @@
     astrosunrise = sun.calcAstronomicalSunrise();
     astrosunset = sun.calcAstronomicalSunset();
     customsunrise = sun.calcCustomSunrise(90.0);
-    customsunset = sun.calcCustomSuset(90.0);
+    customsunset = sun.calcCustomSunset(90.0);

     Serial.print("Sunrise at ");
     Serial.print(sunrise/60);


added battery voltage msg pub

added battery voltage msg pub

--- turtlebot3_core/firmware/turtlebot3_core.ino
+++ turtlebot3_core/firmware/turtlebot3_core.ino
@@ -290,6 +290,9 @@
 *******************************************************************************/
 void publish_sensor_state_msg(void)
 {
+  sensor_state_msg.stamp = nh.now();
+  sensor_state_msg.battery = check_voltage();
+
   bool dxl_comm_result = false;

   dxl_comm_result = motor_driver.readEncoder(ADDR_XM_PRESENT_POSITION, 4, sensor_state_msg.left_encoder, sensor_state_msg.right_encoder);
@@ -546,4 +549,19 @@
   }
 }

+/*******************************************************************************
+* Check voltage
+*******************************************************************************/
+float check_voltage(void)
+{
+  int adc_value;
+  float vol_value;
+
+  adc_value = analogRead(BDPIN_BAT_PWR_ADC);
+  vol_value = map(adc_value, 0, 1023, 0, 330*57/10);
+  vol_value = vol_value/100;
+
+  return vol_value;
+}
+
 // EOF


I’ll never be happy with these colors

I’ll never be happy with these colors

--- statusbot.ino
+++ statusbot.ino
@@ -2,17 +2,17 @@
 #include "LiquidCrystal/LiquidCrystal.h"

 // Colors
-#define RGB_COLOR_RED   0xFF0000ul
+#define RGB_COLOR_RED     0xFF0000ul
 #define RGB_COLOR_GREEN   0x00FF00ul
 #define RGB_COLOR_BLUE    0x0000FFul
 #define RGB_COLOR_YELLOW  0xFFFF00ul
 #define RGB_COLOR_CYAN    0x00FFFFul
 #define RGB_COLOR_MAGENTA 0xFF00FFul
 #define RGB_COLOR_WHITE   0xFFFFFFul
-#define RGB_COLOR_ORANGE    0xFF6000ul
-#define WIZARD_ORANGE       0xc03f21ul
-#define WIZARD_BLUE         0x285166ul
-#define WIZARD_GRAY         0x515159ul
+#define RGB_COLOR_ORANGE  0xFF6000ul
+#define WIZARD_ORANGE     0xFF3f00ul
+#define WIZARD_BLUE       0x285166ul
+#define WIZARD_GRAY       0x515159ul

 // Pins for backlight
 #define R_PIN D0


Add correct pinout for all optional pins

--- steppercontrol/steppercontrol.ino
+++ steppercontrol/steppercontrol.ino
@@ -1,5 +1,22 @@
-int motorPin = 9;
-int switchPin = 7;
+int enablePin = 4;
+int MS1Pin = 5;
+int MS2Pin = 6;
+int MS3Pin = 7;
+int resetPin = 9;
+int sleepPin = 10;
+int motorPin = 11;
+int directionPin = 12;
+int switchPin = 13;
+
+// Stepping: Full, half, quarter, eigth, sixteenth
+int[] stepping = {
+  B000,
+  B100,
+  B010,
+  B110,
+  B111
+}
+
 int motorStep = 0;
 int maxStep = 200;
 int minimumStepDelay = 2;


Fixed a bug where connecting two input pins to an output pin, disabled other pins.

--- ServerSketch/ServerSketch.ino
+++ ServerSketch/ServerSketch.ino
@@ -808,37 +808,57 @@
 float getTotalPinAnalogValue(int _iPinNum)
 {
   float fPinValSum = 0;
+  int iConnCount = 1; // Pins are always connected to themselves

   for(int i=0; i<TOTAL_NUM_OF_PINS; i++)
   {
     // Checking what pins are connected to iPinNum
-    if(g_aPins[_iPinNum].connections[i])
-    {
-      fPinValSum += g_aPins[i].value;
-      Serial.print(i); Serial.print(" --> "); Serial.println(_iPinNum);
-      Serial.print("Value: "); Serial.println(fPinValSum);
-    }
-  }
+    if( _iPinNum != i) // Ignore the value set to the pin and only use connected pin values
+    {
+      if(g_aPins[_iPinNum].connections[i])
+      {
+        iConnCount++;
+        fPinValSum += g_aPins[i].value;
+        Serial.print(i); Serial.print(" --> "); Serial.print(_iPinNum);
+        Serial.print(" value: "); Serial.println(g_aPins[i].value);
+      }
+    }
+  }
+
+  if( 1 == iConnCount ) // No other connections found besides itself
+    fPinValSum = g_aPins[_iPinNum].value;

   if(fPinValSum > 1.0)
     fPinValSum = 1.0;

+  Serial.print("Total Value: "); Serial.println(fPinValSum);
+
   return fPinValSum;
 }

 int getTotalPinDigitalValue(int _iPinNum)
 {
+  int iRetValue = 0;
+  int iConnCount = 1; // Pins are always connected to themselves
+
   for(int i=0; i<TOTAL_NUM_OF_PINS; i++)
   {
     // Checking what pins are connected to iPinNum
-    if(g_aPins[_iPinNum].connections[i])
-    {
-      if(g_aPins[i].value == 1.0)
-        return 1.0;
-    }
+    if( _iPinNum != i) // Ignore the value set to the pin and only use connected pin values
+    {
+      if(g_aPins[_iPinNum].connections[i])
+      {
+        iConnCount++;
+        if(g_aPins[i].value == 1.0)
+          iRetValue = 1;
+      }
+    }
   }

-  return 0.0;
+  if( 1 == iConnCount ) // No other connections found besides itself
+    iRetValue = g_aPins[_iPinNum].value;
+
+  return iRetValue;
 }

 // Get the board state and return a JSON object
@@ -1247,7 +1267,7 @@
 //char g_acConnA0_TO_3[] = "{\"status\":\"OK\",\"connections\":[{\"source\":\"14\",\"target\":\"3\"},{\"source\":\"15\",\"target\":\"5\"}]}";

 char g_acPin13_On_3_Analog[] = "{\"status\":\"OK\",\"pins\":{ \"13\":{\"label\":\"Pin 13\",\"is_analog\":\"false\",\"is_input\":\"false\",\"value\":\"1\"}, \"3\":{\"label\":\"Pin 3\",\"is_analog\":\"true\",\"is_input\":\"false\",\"value\":\"0.0\"}  }}";
-char g_acConnA0_TO_3[] = "{\"status\":\"OK\",\"connections\":[{\"source\":\"14\",\"target\":\"3\"}]}";
+char g_acConnA0_TO_3[] = "{\"status\":\"OK\",\"connections\":[{\"source\":\"14\",\"target\":\"3\"},{\"source\":\"15\",\"target\":\"3\"}]}";
 int g_iDebugState = 0;

@@ -1285,14 +1305,12 @@
         snprintf(g_acMessage,sizeof(g_acMessage),g_acPin13_On_3_Analog);
         processMessage(g_acMessage);
         g_iDebugState = 1;
-        Serial.println("HERE 0");
       break;

       case 1:
         snprintf(g_acMessage,sizeof(g_acMessage),g_acConnA0_TO_3);
         processMessage(g_acMessage);
         g_iDebugState = 2;
-         Serial.println("HERE 1");
       break;

       default:


tinyTempNode: cleanup

tinyTempNode: cleanup

--- nodes/tinyTempNode/tinyTempNode.ino
+++ nodes/tinyTempNode/tinyTempNode.ino
@@ -53,9 +53,9 @@
 // and small change to OneWire library, see: http://arduino.cc/forum/index.php/topic,91491.msg687523.html#msg687523
 //----------------------------------------------------------------------------------------------------------------------

-#include <OneWire.h> // http://www.pjrc.com/teensy/arduino_libraries/OneWire.zip
+#include <OneWire.h>           // http://www.pjrc.com/teensy/arduino_libraries/OneWire.zip
 #include <DallasTemperature.h> // http://download.milesburton.com/Arduino/MaximTemperature/DallasTemperature_LATEST.zip
-#include <JeeLib.h> // https://github.com/jcw/jeelib
+#include <JeeLib.h>            // https://github.com/jcw/jeelib

 ISR(WDT_vect) { Sleepy::watchdogEvent(); } // interrupt handler for JeeLabs Sleepy power saving

@@ -75,63 +75,81 @@

 DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature

-//########################################################################################################################
-//Data Structure to be sent
-//########################################################################################################################
-
- typedef struct {
-      int temp; // Temperature reading
-      int supplyV;  // Supply voltage
- } Payload;
-
- Payload tinytx;
+
+// Data Structure to be sent
+typedef struct {
+  int temp;    // Temperature reading
+  int supplyV; // Supply voltage
+} Payload;
+
+Payload tinytx;
+
+
+#ifdef USE_ACK

 // Wait a few milliseconds for proper ACK
- #ifdef USE_ACK
-  static byte waitForAck() {
-   MilliTimer ackTimer;
-   while (!ackTimer.poll(ACK_TIME)) {
-     if (rf12_recvDone() && rf12_crc == 0 &&
-        rf12_hdr == (RF12_HDR_DST | RF12_HDR_CTL | myNodeID))
-        return 1;
-     }
-   return 0;
+static byte waitForAck() {
+  MilliTimer ackTimer;
+  while (!ackTimer.poll(ACK_TIME)) {
+    if (rf12_recvDone() && rf12_crc == 0 &&
+      rf12_hdr == (RF12_HDR_DST | RF12_HDR_CTL | myNodeID))
+      return 1;
+    }
+  return 0;
+}
+
+static void rfwrite(){
+  // tx and wait for ack up to RETRY_LIMIT times
+  for (byte i = 0; i <= RETRY_LIMIT; ++i) {
+    // Wake up RF module
+    rf12_sleep(-1);
+
+    while (!rf12_canSend())
+      rf12_recvDone();
+
+    rf12_sendStart(RF12_HDR_ACK, &tinytx, sizeof tinytx);
+
+    // Wait for RF to finish sending while in standby mode
+    rf12_sendWait(2);
+
+    // Wait for ACK
+    byte acked = waitForAck();
+
+    // Put RF module to sleep
+    rf12_sleep(0);
+
+    // Return if ACK received
+    if (acked) { return; }
+
+    // If no ack received wait and try again
+    Sleepy::loseSomeTime(RETRY_PERIOD * 1000);
   }
- #endif
-
-//--------------------------------------------------------------------------------------------------
-// Send payload data via RF
-//-------------------------------------------------------------------------------------------------
- static void rfwrite(){
-  #ifdef USE_ACK
-   for (byte i = 0; i <= RETRY_LIMIT; ++i) {  // tx and wait for ack up to RETRY_LIMIT times
-     rf12_sleep(-1);              // Wake up RF module
-      while (!rf12_canSend())
-      rf12_recvDone();
-      rf12_sendStart(RF12_HDR_ACK, &tinytx, sizeof tinytx);
-      rf12_sendWait(2);           // Wait for RF to finish sending while in standby mode
-      byte acked = waitForAck();  // Wait for ACK
-      rf12_sleep(0);              // Put RF module to sleep
-      if (acked) { return; }      // Return if ACK received
-
-   Sleepy::loseSomeTime(RETRY_PERIOD * 1000);     // If no ack received wait and try again
-   }
-  #else
-     rf12_sleep(-1);              // Wake up RF module
-     while (!rf12_canSend())
-     rf12_recvDone();
-     rf12_sendStart(0, &tinytx, sizeof tinytx);
-     rf12_sendWait(2);           // Wait for RF to finish sending while in standby mode
-     rf12_sleep(0);              // Put RF module to sleep
-     return;
-  #endif
- }
-
-
-
-//--------------------------------------------------------------------------------------------------
+}
+
+#else
+
+static void rfwrite(){
+  // Wake up RF module
+  rf12_sleep(-1);
+
+  while (!rf12_canSend())
+    rf12_recvDone();
+
+  rf12_sendStart(0, &tinytx, sizeof tinytx);
+
+  // Wait for RF to finish sending while in standby mode
+  rf12_sendWait(2);
+
+  // Put RF module to sleep
+  rf12_sleep(0);
+
+  return;
+}
+
+#endif
+
+
 // Read current supply voltage
-//--------------------------------------------------------------------------------------------------
  long readVcc() {
    bitClear(PRR, PRADC); ADCSRA |= bit(ADEN); // Enable the ADC
    long result;
@@ -150,39 +168,49 @@
    ADCSRA &= ~ bit(ADEN); bitSet(PRR, PRADC); // Disable the ADC to save power
    return result;
 }
-//########################################################################################################################

 void setup() {
-
-  rf12_initialize(myNodeID,freq,network); // Initialize RFM12 with settings defined above
-  rf12_sleep(0);                          // Put the RFM12 to sleep
-
-  pinMode(ONE_WIRE_POWER, OUTPUT); // set power pin for DS18B20 to output
-
-  PRR = bit(PRTIM1); // only keep timer 0 going
-
-  ADCSRA &= ~ bit(ADEN); bitSet(PRR, PRADC); // Disable the ADC to save power
-
+  // Initialize RFM12 with settings defined above
+  rf12_initialize(myNodeID, freq, network);
+
+  // Put the RFM12 to sleep
+  rf12_sleep(0);
+
+  // set power pin for DS18B20 to output
+  pinMode(ONE_WIRE_POWER, OUTPUT);
+
+  // only keep timer 0 going
+  PRR = bit(PRTIM1);
+
+  // Disable the ADC to save power
+  ADCSRA &= ~ bit(ADEN); bitSet(PRR, PRADC);
 }

 void loop() {
-
-  digitalWrite(ONE_WIRE_POWER, HIGH); // turn DS18B20 sensor on
+  // turn DS18B20 sensor on
+  digitalWrite(ONE_WIRE_POWER, HIGH);

   //Sleepy::loseSomeTime(5); // Allow 5ms for the sensor to be ready
   delay(5); // The above doesn't seem to work for everyone (why?)

-  sensors.begin(); //start up temp sensor
-  sensors.requestTemperatures(); // Get the temperature
-  tinytx.temp=(sensors.getTempCByIndex(0)*100); // Read first sensor and convert to integer, reversed at receiving end
-
-  digitalWrite(ONE_WIRE_POWER, LOW); // turn DS18B20 off
-
-  tinytx.supplyV = readVcc(); // Get supply voltage
-
-  rfwrite(); // Send data via RF
-
-  Sleepy::loseSomeTime(60000); //JeeLabs power save function: enter low power mode for 60 seconds (valid range 16-65000 ms)
-
-}
-
+  //start up temp sensor
+  sensors.begin();
+
+  // Get the temperature
+  sensors.requestTemperatures();
+
+  // Read first sensor and convert to integer, reversed at receiving end
+  tinytx.temp = (sensors.getTempCByIndex(0)*100);
+
+  // turn DS18B20 off
+  digitalWrite(ONE_WIRE_POWER, LOW);
+
+  // Get supply voltage
+  tinytx.supplyV = readVcc();
+
+  // Send data via RF
+  rfwrite();
+
+  // JeeLabs power save function: enter low power mode for 60 seconds (valid range 16-65000 ms)
+  Sleepy::loseSomeTime(60000);
+}


Removed systemic value change

Removed systemic value change

--- Firmware/R2-Quadcopter/R2-Quadcopter.ino
+++ Firmware/R2-Quadcopter/R2-Quadcopter.ino
@@ -15,7 +15,7 @@

 // PID variables
-bool auto_stabilisation_mode = false; //activer ou pas le mode auto-stabilisé: utiliser le switch de input 5 ou 6
+bool auto_stabilisation_mode = true; //activer ou pas le mode auto-stabilisé: utiliser le switch de input 5 ou 6
 int dt = 3;//notre dt est de 100 millisecondes
 double pid_roll_speed_in, pid_roll_angle_in,   pid_roll_out,   pid_roll_setpoint,  roll_error,  Integral_roll_error,  Derivative_roll_error,  last_roll_error, AS_roll_error, AS_Integral_roll_error, AS_Derivative_roll_error, AS_last_roll_error = 0;
 double pid_pitch_speed_in, pid_pitch_angle_in,  pid_pitch_out,  pid_pitch_setpoint, pitch_error, Integral_pitch_error, Derivative_pitch_error, last_pitch_error, AS_pitch_error, AS_Integral_pitch_error, AS_Derivative_pitch_error, AS_last_pitch_error = 0;
@@ -81,10 +81,10 @@
   mF = throttle + pid_pitch_out - pid_yaw_out;//////moteurs opposés/////
   mB = throttle - pid_pitch_out - pid_yaw_out;//////////////////////////

-  motor_right.writeMicroseconds(mR - 100);
-  motor_left.writeMicroseconds(mL - 100);
-  motor_front.writeMicroseconds(mF - 100);
-  motor_back.writeMicroseconds(mB - 100);
+  motor_right.writeMicroseconds(mR);
+  motor_left.writeMicroseconds(mL);
+  motor_front.writeMicroseconds(mF);
+  motor_back.writeMicroseconds(mB);
 }

 //fonction qui empeche les moteurs de tourner
@@ -126,32 +126,32 @@
   Serial.println(input[3]);
 }
 void print_pitch_and_roll() {
-  Serial.print(mR - 100);
-  Serial.print(", ");
-  Serial.print(mL - 100);
-  Serial.print(", ");
+  Serial.print(mR);
+  Serial.print(";");
+  Serial.print(mL);
+  Serial.print(";");
   Serial.print(roll_speed);
   Serial.print("     …     ");
-  Serial.print(mF - 100);
-  Serial.print(", ");
-  Serial.print(mB - 100);
-  Serial.print(", ");
+  Serial.print(mF);
+  Serial.print(";");
+  Serial.print(mB);
+  Serial.print(";");
   Serial.println(pitch_speed);
 }
 void print_yaw_and_motors() {
-  Serial.print(mR - 100);
-  Serial.print(", ");
-  Serial.print(mL - 100);
-  Serial.print(", ");
-  Serial.print(mF - 100);
-  Serial.print(", ");
-  Serial.print(mB - 100);
-  Serial.print(", ");
+  Serial.print(mR);
+  Serial.print(";");
+  Serial.print(mL);
+  Serial.print(";");
+  Serial.print(mF);
+  Serial.print(";");
+  Serial.print(mB);
+  Serial.print(";");
   Serial.println(yaw_speed);
 }
 void print_pid_values() {
   Serial.print(input[0]);
-  Serial.print(", ");
+  Serial.print(";");
   Serial.println(pid_roll_out);
 }


Refactor color lookup to function

Refactor color lookup to function

--- Valokepakko.ino
+++ Valokepakko.ino
@@ -58,6 +58,17 @@
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
 }

+// Returns the color from the palette. Return black if pixelindex is -1.
+uint32_t lookupColor(int pixelIndex) {
+  if (pixelIndex < 0) {
+    rgb = {0, 0, 0};
+  } else {
+    int colorIndex = pgm_read_byte_near(PIXELS + pixelIndex);
+    memcpy_PF(&rgb, (uint_farptr_t) &PALETTE[colorIndex], sizeof(RGB));
+  }
+  uint32_t c = strip.Color(rgb.r, rgb.g, rgb.b);
+}
+
 void loop() {
   /**********************/
   /* Accelerometer code */
@@ -83,18 +94,18 @@
     int deltaX = cos(angle) * h;
     int deltaY = sin(angle) * h;

-    // Lookup the pixel
+    /****************************/
+    /* Lookup the pixel's color */
+    /****************************/
     int x = int(originX + deltaX);
     int y = int(originY + deltaY);
+    int pixelIndex = x + y * IMAGE_WIDTH;
+    // If we are out of bounds set color to black
+    if (x < 0 || x > IMAGE_WIDTH - 1 || y < 0 || y > IMAGE_HEIGHT - 1) {
+      pixelindex = -1;
+    }
+    uint32_t c = lookupColor(pixelIndex);

-    if (x < 0 || x > IMAGE_WIDTH - 1 || y < 0 || y > IMAGE_HEIGHT - 1) {
-      rgb = {0, 0, 0};
-    } else {
-      int pixelIndex = x + y * IMAGE_WIDTH;
-      int colorIndex = pgm_read_byte_near(PIXELS + pixelIndex);
-      memcpy_PF(&rgb, (uint_farptr_t) &PALETTE[colorIndex], sizeof(RGB));
-    }
-    uint32_t c = strip.Color(rgb.r, rgb.g, rgb.b);
     strip.setPixelColor(led, c);
   }


SHT31と同じ修正

SHT31と同じ修正

--- 2_example/example09_hum_si7021/i2c_si7021.ino
+++ 2_example/example09_hum_si7021/i2c_si7021.ino
@@ -18,27 +18,27 @@
     _i2c_si7021_hum=-999.;
     Wire.beginTransmission(I2C_si7021);
     Wire.write(0xF5);
-    if( Wire.endTransmission() == 0){
-        delay(30);              // 15ms以上
-        Wire.requestFrom(I2C_si7021,2);
-        if(Wire.available()==0) return -999.;
-        hum = Wire.read();
-        hum <<= 8;
-        if(Wire.available()==0) return -999.;
-        hum += Wire.read();
-    }else return -999.;
+    if(Wire.endTransmission()) return -999.;
+
+    delay(30);                  // 15ms以上
+    Wire.requestFrom(I2C_si7021,2);
+    if(Wire.available()!=2) return -999.;
+    hum = Wire.read();
+    hum <<= 8;
+    hum += Wire.read();
+
     delay(18);                  // 15ms以上
     Wire.beginTransmission(I2C_si7021);
     Wire.write(0xE0);
-    if( Wire.endTransmission() == 0){
-        delay(30);              // 15ms以上
-        Wire.requestFrom(I2C_si7021,2);
-        if(Wire.available()==0) return -999.;
-        temp = Wire.read();
-        temp <<= 8;
-        if(Wire.available()==0) return -999.;
-        temp += Wire.read();
-    }else return -999.;
+    if(Wire.endTransmission()) return -989.;
+
+    delay(30);                  // 15ms以上
+    Wire.requestFrom(I2C_si7021,2);
+    if(Wire.available()!=2) return -999.;
+    temp = Wire.read();
+    temp <<= 8;
+    temp += Wire.read();
+
     _i2c_si7021_hum = (float)hum / 65536. * 125. - 6.;
     return (float)temp / 65535. * 175.72 - 46.85;
 }