diff --git a/.gitignore b/.gitignore
index a423023..aa4052a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,4 +17,7 @@
applet/
*~
*.orig
-*.rej
\ No newline at end of file
+*.rej
+.project
+
+
diff --git a/Minnow/.cproject b/Minnow/.cproject
new file mode 100644
index 0000000..69ba7ec
--- /dev/null
+++ b/Minnow/.cproject
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Minnow/.gitignore b/Minnow/.gitignore
new file mode 100644
index 0000000..d027396
--- /dev/null
+++ b/Minnow/.gitignore
@@ -0,0 +1 @@
+/.settings/
diff --git a/Minnow/.settings/language.settings.xml b/Minnow/.settings/language.settings.xml
new file mode 100644
index 0000000..589c487
--- /dev/null
+++ b/Minnow/.settings/language.settings.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Minnow/Arduino.h b/Minnow/Arduino.h
new file mode 100644
index 0000000..f1da68d
--- /dev/null
+++ b/Minnow/Arduino.h
@@ -0,0 +1,251 @@
+/*
+ Arduino.h - Main include file for the Arduino SDK
+ Copyright (c) 2005-2013 Arduino Team. All right reserved.
+
+ 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
+*/
+
+#ifndef Arduino_h
+#define Arduino_h
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "binary.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+void yield(void);
+
+#define HIGH 0x1
+#define LOW 0x0
+
+#define INPUT 0x0
+#define OUTPUT 0x1
+#define INPUT_PULLUP 0x2
+
+#define PI 3.1415926535897932384626433832795
+#define HALF_PI 1.5707963267948966192313216916398
+#define TWO_PI 6.283185307179586476925286766559
+#define DEG_TO_RAD 0.017453292519943295769236907684886
+#define RAD_TO_DEG 57.295779513082320876798154814105
+#define EULER 2.718281828459045235360287471352
+
+#define SERIAL 0x0
+#define DISPLAY 0x1
+
+#define LSBFIRST 0
+#define MSBFIRST 1
+
+#define CHANGE 1
+#define FALLING 2
+#define RISING 3
+
+#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
+#define DEFAULT 0
+#define EXTERNAL 1
+#define INTERNAL 2
+#else
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
+#define INTERNAL1V1 2
+#define INTERNAL2V56 3
+#else
+#define INTERNAL 3
+#endif
+#define DEFAULT 1
+#define EXTERNAL 0
+#endif
+
+// undefine stdlib's abs if encountered
+#ifdef abs
+#undef abs
+#endif
+
+#define min(a,b) ((a)<(b)?(a):(b))
+#define max(a,b) ((a)>(b)?(a):(b))
+#define abs(x) ((x)>0?(x):-(x))
+#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
+#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
+#define radians(deg) ((deg)*DEG_TO_RAD)
+#define degrees(rad) ((rad)*RAD_TO_DEG)
+#define sq(x) ((x)*(x))
+
+#define interrupts() sei()
+#define noInterrupts() cli()
+
+#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
+#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
+#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
+
+#define lowByte(w) ((uint8_t) ((w) & 0xff))
+#define highByte(w) ((uint8_t) ((w) >> 8))
+
+#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
+#define bitSet(value, bit) ((value) |= (1UL << (bit)))
+#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
+#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
+
+// avr-libc defines _NOP() since 1.6.2
+#ifndef _NOP
+#define _NOP() do { __asm__ volatile ("nop"); } while (0)
+#endif
+
+typedef unsigned int word;
+
+#define bit(b) (1UL << (b))
+
+typedef bool boolean;
+typedef uint8_t byte;
+
+void init(void);
+void initVariant(void);
+
+int atexit(void (*func)()) __attribute__((weak));
+
+void pinMode(uint8_t, uint8_t);
+void digitalWrite(uint8_t, uint8_t);
+int digitalRead(uint8_t);
+int analogRead(uint8_t);
+void analogReference(uint8_t mode);
+void analogWrite(uint8_t, int);
+
+unsigned long millis(void);
+unsigned long micros(void);
+void delay(unsigned long);
+void delayMicroseconds(unsigned int us);
+unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
+unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout);
+
+void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
+uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
+
+void attachInterrupt(uint8_t, void (*)(void), int mode);
+void detachInterrupt(uint8_t);
+
+void setup(void);
+void loop(void);
+
+// Get the bit location within the hardware port of the given virtual pin.
+// This comes from the pins_*.c file for the active board configuration.
+
+#define analogInPinToBit(P) (P)
+
+// On the ATmega1280, the addresses of some of the port registers are
+// greater than 255, so we can't store them in uint8_t's.
+extern const uint16_t PROGMEM port_to_mode_PGM[];
+extern const uint16_t PROGMEM port_to_input_PGM[];
+extern const uint16_t PROGMEM port_to_output_PGM[];
+
+extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
+// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
+extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
+extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
+
+// Get the bit location within the hardware port of the given virtual pin.
+// This comes from the pins_*.c file for the active board configuration.
+//
+// These perform slightly better as macros compared to inline functions
+//
+#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
+#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
+#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
+#define analogInPinToBit(P) (P)
+#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
+#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
+#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
+
+#define NOT_A_PIN 0
+#define NOT_A_PORT 0
+
+#define NOT_AN_INTERRUPT -1
+
+#ifdef ARDUINO_MAIN
+#define PA 1
+#define PB 2
+#define PC 3
+#define PD 4
+#define PE 5
+#define PF 6
+#define PG 7
+#define PH 8
+#define PJ 10
+#define PK 11
+#define PL 12
+#endif
+
+#define NOT_ON_TIMER 0
+#define TIMER0A 1
+#define TIMER0B 2
+#define TIMER1A 3
+#define TIMER1B 4
+#define TIMER1C 5
+#define TIMER2 6
+#define TIMER2A 7
+#define TIMER2B 8
+
+#define TIMER3A 9
+#define TIMER3B 10
+#define TIMER3C 11
+#define TIMER4A 12
+#define TIMER4B 13
+#define TIMER4C 14
+#define TIMER4D 15
+#define TIMER5A 16
+#define TIMER5B 17
+#define TIMER5C 18
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#ifdef __cplusplus
+#include "WCharacter.h"
+#include "WString.h"
+#include "HardwareSerial.h"
+#include "USBAPI.h"
+#if defined(HAVE_HWSERIAL0) && defined(HAVE_CDCSERIAL)
+#error "Targets with both UART0 and CDC serial not supported"
+#endif
+
+uint16_t makeWord(uint16_t w);
+uint16_t makeWord(byte h, byte l);
+
+#define word(...) makeWord(__VA_ARGS__)
+
+unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
+unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
+
+void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
+void noTone(uint8_t _pin);
+
+// WMath prototypes
+long random(long);
+long random(long, long);
+void randomSeed(unsigned long);
+long map(long, long, long, long, long);
+
+#endif
+
+#include "pins_arduino.h"
+
+#endif
diff --git a/Minnow/AxisInfo.h b/Minnow/AxisInfo.h
index b39a000..962acaf 100644
--- a/Minnow/AxisInfo.h
+++ b/Minnow/AxisInfo.h
@@ -57,7 +57,7 @@ struct AxisInfoInternal
uint32_t underrun_accel_rate;
// used by ISR
- int16_t step_event_counter;
+ int32_t step_event_counter;
};
//
@@ -229,4 +229,4 @@ class AxisInfo
#endif
-
\ No newline at end of file
+
diff --git a/Minnow/ConfigTreeNode.cpp b/Minnow/ConfigTreeNode.cpp
index b600d2e..9e8e096 100644
--- a/Minnow/ConfigTreeNode.cpp
+++ b/Minnow/ConfigTreeNode.cpp
@@ -1,6 +1,6 @@
/*
Minnow Pacemaker client firmware.
-
+
Copyright (C) 2013 Robert Fairlie-Cuninghame
This program is free software: you can redistribute it and/or modify
@@ -18,9 +18,9 @@
*/
//
-// Implementation of ConfigurationTreeNode class for navigating the
-// configuration tree.
-
+// Implementation of ConfigurationTreeNode class for navigating the
+// configuration tree.
+
#include "ConfigTreeNode.h"
#include "Minnow.h"
@@ -48,7 +48,7 @@ struct ConfigNodeInfo
uint8_t instance_child_type;
uint8_t (*num_children)(); // stores either a functor (for instance node) or the raw count (for group nodes)
uint8_t leaf_node_class;
- uint8_t leaf_operations;
+ uint8_t leaf_operations;
uint8_t leaf_datatype; // the datatype is only needed for writable leaf nodes, or the device_type for non-leaf nodes.
};
@@ -162,7 +162,7 @@ PROGMEM static const char name_of_NODE_TYPE_CONFIG_LEAF_STEPPER_STEP_INVERT[] =
#define name_of_NODE_TYPE_CONFIG_LEAF_STEPPER_FRIENDLY_NAME pstr_NAME
// Arrays of named children
-PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_ROOT[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_ROOT[] =
{
NODE_TYPE_GROUP_SYSTEM,
NODE_TYPE_GROUP_DEVICES,
@@ -170,7 +170,7 @@ PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_ROOT[] =
NODE_TYPE_GROUP_DEBUG
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_GROUP_SYSTEM[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_GROUP_SYSTEM[] =
{
NODE_TYPE_CONFIG_LEAF_SYSTEM_HARDWARE_NAME,
NODE_TYPE_CONFIG_LEAF_SYSTEM_HARDWARE_TYPE,
@@ -186,7 +186,7 @@ PROGMEM static const uint8_t children_of_NODE_TYPE_GROUP_SYSTEM[] =
NODE_TYPE_CONFIG_LEAF_SYSTEM_NUM_STEPPERS,
NODE_TYPE_OPERATION_LEAF_RESET_EEPROM
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_GROUP_DEVICES[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_GROUP_DEVICES[] =
{
NODE_TYPE_CONFIG_DEVICE_INPUT_SWITCHES,
NODE_TYPE_CONFIG_DEVICE_OUTPUT_SWITCHES,
@@ -196,48 +196,48 @@ PROGMEM static const uint8_t children_of_NODE_TYPE_GROUP_DEVICES[] =
NODE_TYPE_CONFIG_DEVICE_HEATERS,
NODE_TYPE_CONFIG_DEVICE_STEPPERS
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_GROUP_STATISTICS[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_GROUP_STATISTICS[] =
{
NODE_TYPE_STATS_LEAF_RX_PACKET_COUNT,
NODE_TYPE_STATS_LEAF_RX_ERROR_COUNT,
NODE_TYPE_STATS_LEAF_QUEUE_MEMORY
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_GROUP_DEBUG[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_GROUP_DEBUG[] =
{
NODE_TYPE_DEBUG_LEAF_STACK_MEMORY,
NODE_TYPE_DEBUG_LEAF_STACK_LOW_WATER_MARK
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_INPUT_SWITCH[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_INPUT_SWITCH[] =
{
NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_FRIENDLY_NAME,
NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_PIN,
NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_TRIGGER_LEVEL,
NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_ENABLE_PULLUP
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_OUTPUT_SWITCH[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_OUTPUT_SWITCH[] =
{
NODE_TYPE_CONFIG_LEAF_OUTPUT_SWITCH_FRIENDLY_NAME,
NODE_TYPE_CONFIG_LEAF_OUTPUT_SWITCH_PIN,
NODE_TYPE_CONFIG_LEAF_OUTPUT_SWITCH_INITIAL_STATE
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_PWM_OUTPUT[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_PWM_OUTPUT[] =
{
NODE_TYPE_CONFIG_LEAF_PWM_OUTPUT_FRIENDLY_NAME,
NODE_TYPE_CONFIG_LEAF_PWM_OUTPUT_PIN,
NODE_TYPE_CONFIG_LEAF_PWM_OUTPUT_USE_SOFT_PWM
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_BUZZER[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_BUZZER[] =
{
NODE_TYPE_CONFIG_LEAF_BUZZER_FRIENDLY_NAME,
NODE_TYPE_CONFIG_LEAF_BUZZER_PIN
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_TEMP_SENSOR[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_TEMP_SENSOR[] =
{
NODE_TYPE_CONFIG_LEAF_TEMP_SENSOR_FRIENDLY_NAME,
NODE_TYPE_CONFIG_LEAF_TEMP_SENSOR_PIN,
NODE_TYPE_CONFIG_LEAF_TEMP_SENSOR_TYPE,
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_HEATER[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_HEATER[] =
{
NODE_TYPE_CONFIG_LEAF_HEATER_FRIENDLY_NAME,
NODE_TYPE_CONFIG_LEAF_HEATER_PIN,
@@ -252,9 +252,9 @@ PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_HEATER
NODE_TYPE_CONFIG_LEAF_HEATER_PID_KP,
NODE_TYPE_CONFIG_LEAF_HEATER_PID_KI,
NODE_TYPE_CONFIG_LEAF_HEATER_PID_KD,
- NODE_TYPE_CONFIG_LEAF_HEATER_PID_DO_AUTOTUNE,
+ NODE_TYPE_CONFIG_LEAF_HEATER_PID_DO_AUTOTUNE,
};
-PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_STEPPER[] =
+PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_STEPPER[] =
{
NODE_TYPE_CONFIG_LEAF_STEPPER_FRIENDLY_NAME,
NODE_TYPE_CONFIG_LEAF_STEPPER_ENABLE_PIN,
@@ -267,7 +267,7 @@ PROGMEM static const uint8_t children_of_NODE_TYPE_CONFIG_DEVICE_INSTANCE_STEPPE
//
// Configuration Tree Definition
//
-PROGMEM static const ConfigNodeInfo node_info_array[] =
+PROGMEM static const ConfigNodeInfo node_info_array[] =
{
//
// Config Related Nodes
@@ -280,30 +280,30 @@ PROGMEM static const ConfigNodeInfo node_info_array[] =
GROUP_NODE(NODE_TYPE_GROUP_DEVICES),
GROUP_NODE(NODE_TYPE_GROUP_STATISTICS),
GROUP_NODE(NODE_TYPE_GROUP_DEBUG),
-
+
// Device Type Nodes
- INSTANCE_PARENT_NODE(NODE_TYPE_CONFIG_DEVICE_INPUT_SWITCHES,
- NODE_TYPE_CONFIG_DEVICE_INSTANCE_INPUT_SWITCH,
- Device_InputSwitch::GetNumDevices),
+ INSTANCE_PARENT_NODE(NODE_TYPE_CONFIG_DEVICE_INPUT_SWITCHES,
+ NODE_TYPE_CONFIG_DEVICE_INSTANCE_INPUT_SWITCH,
+ Device_InputSwitch::GetNumDevices),
INSTANCE_PARENT_NODE(NODE_TYPE_CONFIG_DEVICE_OUTPUT_SWITCHES,
- NODE_TYPE_CONFIG_DEVICE_INSTANCE_OUTPUT_SWITCH,
- Device_OutputSwitch::GetNumDevices),
+ NODE_TYPE_CONFIG_DEVICE_INSTANCE_OUTPUT_SWITCH,
+ Device_OutputSwitch::GetNumDevices),
INSTANCE_PARENT_NODE(NODE_TYPE_CONFIG_DEVICE_PWM_OUTPUTS,
- NODE_TYPE_CONFIG_DEVICE_INSTANCE_PWM_OUTPUT,
- Device_PwmOutput::GetNumDevices),
+ NODE_TYPE_CONFIG_DEVICE_INSTANCE_PWM_OUTPUT,
+ Device_PwmOutput::GetNumDevices),
INSTANCE_PARENT_NODE(NODE_TYPE_CONFIG_DEVICE_BUZZERS,
- NODE_TYPE_CONFIG_DEVICE_INSTANCE_BUZZER,
- Device_Buzzer::GetNumDevices),
+ NODE_TYPE_CONFIG_DEVICE_INSTANCE_BUZZER,
+ Device_Buzzer::GetNumDevices),
INSTANCE_PARENT_NODE(NODE_TYPE_CONFIG_DEVICE_TEMP_SENSORS,
- NODE_TYPE_CONFIG_DEVICE_INSTANCE_TEMP_SENSOR,
- Device_TemperatureSensor::GetNumDevices),
+ NODE_TYPE_CONFIG_DEVICE_INSTANCE_TEMP_SENSOR,
+ Device_TemperatureSensor::GetNumDevices),
INSTANCE_PARENT_NODE(NODE_TYPE_CONFIG_DEVICE_HEATERS,
- NODE_TYPE_CONFIG_DEVICE_INSTANCE_HEATER,
- Device_Heater::GetNumDevices),
+ NODE_TYPE_CONFIG_DEVICE_INSTANCE_HEATER,
+ Device_Heater::GetNumDevices),
INSTANCE_PARENT_NODE(NODE_TYPE_CONFIG_DEVICE_STEPPERS,
- NODE_TYPE_CONFIG_DEVICE_INSTANCE_STEPPER,
- Device_Stepper::GetNumDevices),
-
+ NODE_TYPE_CONFIG_DEVICE_INSTANCE_STEPPER,
+ Device_Stepper::GetNumDevices),
+
// Device Type Instance Nodes
UNNAMED_GROUP_NODE(NODE_TYPE_CONFIG_DEVICE_INSTANCE_INPUT_SWITCH, PM_DEVICE_TYPE_SWITCH_INPUT),
UNNAMED_GROUP_NODE(NODE_TYPE_CONFIG_DEVICE_INSTANCE_OUTPUT_SWITCH, PM_DEVICE_TYPE_SWITCH_OUTPUT),
@@ -312,12 +312,12 @@ PROGMEM static const ConfigNodeInfo node_info_array[] =
UNNAMED_GROUP_NODE(NODE_TYPE_CONFIG_DEVICE_INSTANCE_TEMP_SENSOR, PM_DEVICE_TYPE_TEMP_SENSOR),
UNNAMED_GROUP_NODE(NODE_TYPE_CONFIG_DEVICE_INSTANCE_HEATER, PM_DEVICE_TYPE_HEATER),
UNNAMED_GROUP_NODE(NODE_TYPE_CONFIG_DEVICE_INSTANCE_STEPPER, PM_DEVICE_TYPE_STEPPER),
-
+
// Device related leaf nodes
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_FRIENDLY_NAME,
FIRMWARE_CONFIG_TYPE_NONVOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_STRING),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_PIN,
- FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_UINT8),
+ FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_PIN),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_TRIGGER_LEVEL,
FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_BOOL),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_ENABLE_PULLUP,
@@ -325,30 +325,30 @@ PROGMEM static const ConfigNodeInfo node_info_array[] =
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_OUTPUT_SWITCH_FRIENDLY_NAME,
FIRMWARE_CONFIG_TYPE_NONVOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_STRING),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_OUTPUT_SWITCH_PIN,
- FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_UINT8),
+ FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_PIN),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_OUTPUT_SWITCH_INITIAL_STATE,
FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_STRING),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_PWM_OUTPUT_FRIENDLY_NAME,
FIRMWARE_CONFIG_TYPE_NONVOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_STRING),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_PWM_OUTPUT_PIN,
- FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_UINT8),
+ FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_PIN),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_PWM_OUTPUT_USE_SOFT_PWM,
FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_BOOL),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_BUZZER_FRIENDLY_NAME,
FIRMWARE_CONFIG_TYPE_NONVOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_STRING),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_BUZZER_PIN,
- FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_UINT8),
+ FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_PIN),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_TEMP_SENSOR_FRIENDLY_NAME,
FIRMWARE_CONFIG_TYPE_NONVOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_STRING),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_TEMP_SENSOR_PIN,
- FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_UINT8),
- LEAF_NODE(NODE_TYPE_CONFIG_LEAF_TEMP_SENSOR_TYPE,
+ FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_PIN),
+ LEAF_NODE(NODE_TYPE_CONFIG_LEAF_TEMP_SENSOR_TYPE,
FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_INT16),
-
+
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_HEATER_FRIENDLY_NAME,
FIRMWARE_CONFIG_TYPE_NONVOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_STRING),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_HEATER_PIN,
- FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_UINT8),
+ FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_PIN),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_HEATER_POWER_ON_LEVEL,
FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_UINT8),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_HEATER_USE_SOFT_PWM,
@@ -373,22 +373,22 @@ PROGMEM static const ConfigNodeInfo node_info_array[] =
FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_FLOAT),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_HEATER_PID_DO_AUTOTUNE,
FIRMWARE_CONFIG_TYPE_OPERATION, FIRMWARE_CONFIG_OPS_WRITEABLE, LEAF_SET_DATATYPE_STRING),
-
+
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_STEPPER_FRIENDLY_NAME,
FIRMWARE_CONFIG_TYPE_NONVOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_STRING),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_STEPPER_ENABLE_PIN,
- FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_UINT8),
+ FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_PIN),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_STEPPER_ENABLE_INVERT,
FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_BOOL),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_STEPPER_DIRECTION_PIN,
- FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_UINT8),
+ FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_PIN),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_STEPPER_DIRECTION_INVERT,
FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_BOOL),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_STEPPER_STEP_PIN,
- FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_UINT8),
+ FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_PIN),
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_STEPPER_STEP_INVERT,
FIRMWARE_CONFIG_TYPE_VOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_BOOL),
-
+
// System config related leaf nodes
LEAF_NODE(NODE_TYPE_CONFIG_LEAF_SYSTEM_HARDWARE_NAME,
FIRMWARE_CONFIG_TYPE_NONVOLATILE_CONFIG, LEAF_OPERATIONS_READWRITEABLE, LEAF_SET_DATATYPE_STRING),
@@ -426,13 +426,13 @@ PROGMEM static const ConfigNodeInfo node_info_array[] =
FIRMWARE_CONFIG_TYPE_STATUS, FIRMWARE_CONFIG_OPS_READABLE, LEAF_SET_DATATYPE_INVALID),
LEAF_NODE(NODE_TYPE_DEBUG_LEAF_STACK_LOW_WATER_MARK,
FIRMWARE_CONFIG_TYPE_STATUS, FIRMWARE_CONFIG_OPS_READABLE, LEAF_SET_DATATYPE_INVALID),
-
+
// Operation nodes
LEAF_NODE(NODE_TYPE_OPERATION_LEAF_RESET_EEPROM,
FIRMWARE_CONFIG_TYPE_OPERATION, FIRMWARE_CONFIG_OPS_WRITEABLE, LEAF_SET_DATATYPE_STRING)
-
+
// Diagnostics related leaf nodes
-
+
};
//
@@ -443,7 +443,7 @@ uint8_t ConfigurationTreeNode::GetName(char *buffer, uint8_t buffer_length) cons
{
const char *name_string;
uint8_t cnt = 0;
-
+
if (!IsInstanceNode())
{
if (node_info_index == INVALID_NODE_INFO_INDEX)
@@ -489,7 +489,7 @@ int8_t ConfigurationTreeNode::CompareName(const char *str) const
const char *name_string;
char ch;
int8_t cnt = 0;
-
+
if (!IsInstanceNode())
{
if (node_info_index == INVALID_NODE_INFO_INDEX)
@@ -530,7 +530,7 @@ int8_t ConfigurationTreeNode::CompareName(const char *str) const
return -1;
}
-uint8_t
+uint8_t
ConfigurationTreeNode::GetLeafClass() const
{
if (node_info_index == INVALID_NODE_INFO_INDEX)
@@ -538,7 +538,7 @@ ConfigurationTreeNode::GetLeafClass() const
return pgm_read_byte(&node_info_array[node_info_index].leaf_node_class);
}
-uint8_t
+uint8_t
ConfigurationTreeNode::GetLeafOperations() const
{
if (node_info_index == INVALID_NODE_INFO_INDEX)
@@ -546,21 +546,21 @@ ConfigurationTreeNode::GetLeafOperations() const
return pgm_read_byte(&node_info_array[node_info_index].leaf_operations);
}
-uint8_t
+uint8_t
ConfigurationTreeNode::GetLeafSetDataType() const
{
if (node_info_index == INVALID_NODE_INFO_INDEX)
return false;
return pgm_read_byte(&node_info_array[node_info_index].leaf_datatype);
}
-
+
///////////////////////////////////////////////////////////////////////////////
//
-// Private Functions
+// Private Functions
//
-void
+void
ConfigurationTreeNode::Clear()
{
node_type = NODE_TYPE_INVALID;
@@ -568,15 +568,15 @@ ConfigurationTreeNode::Clear()
instance_id = INVALID_INSTANCE_ID;
}
-void
-ConfigurationTreeNode::SetAsRootNode()
-{
+void
+ConfigurationTreeNode::SetAsRootNode()
+{
Clear();
- node_type = NODE_TYPE_CONFIG_ROOT;
+ node_type = NODE_TYPE_CONFIG_ROOT;
node_info_index = FindNodeInfoIndex(NODE_TYPE_CONFIG_ROOT);
}
-uint8_t
+uint8_t
ConfigurationTreeNode::FindNodeInfoIndex(uint8_t type) const
{
for (uint8_t i=0; inum_children) :
(num_children_functor_type)pgm_read_dword(&node_info->num_children);
-
+
if (!IsLeafNode())
{
if (instance_child_type != NODE_TYPE_INVALID)
@@ -626,7 +626,7 @@ ConfigurationTreeNode::InitializeNextChild(ConfigurationTreeNode &child) const
return true;
}
// the functor pointer is acually storing a raw value in this case
- const uint8_t num_children = (uint8_t)(uint32_t)num_children_functor;
+ const uint8_t num_children = (uint8_t)(uint32_t)num_children_functor;
for (uint8_t i=0; inamed_child_types) == 2) ?
diff --git a/Minnow/ConfigTreeNode.h b/Minnow/ConfigTreeNode.h
index cf04635..c393438 100644
--- a/Minnow/ConfigTreeNode.h
+++ b/Minnow/ConfigTreeNode.h
@@ -1,6 +1,6 @@
/*
Minnow Pacemaker client firmware.
-
+
Copyright (C) 2013 Robert Fairlie-Cuninghame
This program is free software: you can redistribute it and/or modify
@@ -17,9 +17,9 @@
along with this program. If not, see .
*/
-#ifndef CONFIG_TREE_NODE_H
+#ifndef CONFIG_TREE_NODE_H
#define CONFIG_TREE_NODE_H
-
+
#include
//
@@ -104,7 +104,7 @@ class ConfigurationTreeNode
#define NODE_TYPE_CONFIG_LEAF_STEPPER_STEP_PIN 95
#define NODE_TYPE_CONFIG_LEAF_STEPPER_STEP_INVERT 96
-// System configuration
+// System configuration
#define NODE_TYPE_CONFIG_LEAF_SYSTEM_HARDWARE_NAME 180
#define NODE_TYPE_CONFIG_LEAF_SYSTEM_HARDWARE_TYPE 181
#define NODE_TYPE_CONFIG_LEAF_SYSTEM_HARDWARE_REV 182
@@ -151,15 +151,16 @@ class ConfigurationTreeNode
#define LEAF_SET_DATATYPE_BOOL 3
#define LEAF_SET_DATATYPE_STRING 4
#define LEAF_SET_DATATYPE_FLOAT 5
+#define LEAF_SET_DATATYPE_PIN 6
uint8_t GetName(char *buffer, uint8_t buffer_length) const;
int8_t CompareName(const char *str) const;
-
+
uint8_t GetNodeType() const { return node_type; };
uint8_t GetInstanceId() const { return instance_id; };
-
+
bool IsValid() const { return (node_info_index != INVALID_NODE_INFO_INDEX); };
bool IsInstanceNode() const { return (instance_id != INVALID_INSTANCE_ID); };
bool IsLeafNode() const { return GetLeafClass() != LEAF_CLASS_INVALID; };
@@ -167,7 +168,7 @@ class ConfigurationTreeNode
uint8_t GetLeafClass() const;
uint8_t GetLeafOperations() const;
uint8_t GetLeafSetDataType() const;
-
+
private:
friend class ConfigurationTree;
@@ -176,13 +177,13 @@ class ConfigurationTreeNode
bool InitializeNextChild(ConfigurationTreeNode &child) const;
- void SetAsRootNode();
+ void SetAsRootNode();
void Clear();
uint8_t FindNodeInfoIndex(uint8_t) const;
uint8_t node_type;
- uint8_t node_info_index;
- uint8_t instance_id;
+ uint8_t node_info_index;
+ uint8_t instance_id;
};
-#endif
\ No newline at end of file
+#endif
diff --git a/Minnow/Device_TemperatureSensor.cpp b/Minnow/Device_TemperatureSensor.cpp
index 99bb32e..2e895c2 100644
--- a/Minnow/Device_TemperatureSensor.cpp
+++ b/Minnow/Device_TemperatureSensor.cpp
@@ -1,6 +1,6 @@
/*
Minnow Pacemaker client firmware.
-
+
Copyright (C) 2013 Robert Fairlie-Cuninghame
This program is free software: you can redistribute it and/or modify
@@ -18,14 +18,14 @@
*/
#include "Minnow.h"
-
+
#include "Device_TemperatureSensor.h"
#include "response.h"
#include "thermistortables.h"
-// Most of the Device_TemperatureSensor statics are placed in the movement.cpp compilation unit to
-// allow potentiall better optimization in the ISR
+// Most of the Device_TemperatureSensor statics are placed in the movement.cpp compilation unit to
+// allow potentially better optimization in the ISR
float *Device_TemperatureSensor::temperature_sensor_current_temps;
@@ -36,7 +36,7 @@ extern volatile bool temp_meas_ready;
//
//
-// Set the raw measurement limits for detecting a open-circuit/short-circuit
+// Set the raw measurement limits for detecting a open-circuit/short-circuit
//
#define THERMOCOUPLE_RAW_HI_TEMP (16383-ADC_OCSC_FAULT_MARGIN) // this is opposite to a thermistor
#define THERMOCOUPLE_RAW_LO_TEMP (0+ADC_OCSC_FAULT_MARGIN)
@@ -47,7 +47,7 @@ FORCE_INLINE static float convert_raw_temp_value(int8_t type, uint16_t raw_value
{
const int16_t (*tt)[2];
uint8_t tt_len;
-
+
switch (type)
{
case 1: tt = TT_NAME(1); tt_len = NUM_ARRAY_ELEMENTS(TT_NAME(1)); break;
@@ -63,16 +63,19 @@ FORCE_INLINE static float convert_raw_temp_value(int8_t type, uint16_t raw_value
case 51: tt = TT_NAME(51); tt_len = NUM_ARRAY_ELEMENTS(TT_NAME(51)); break;
case 52: tt = TT_NAME(52); tt_len = NUM_ARRAY_ELEMENTS(TT_NAME(52)); break;
case 55: tt = TT_NAME(55); tt_len = NUM_ARRAY_ELEMENTS(TT_NAME(55)); break;
+ case 57: tt = TT_NAME(57); tt_len = NUM_ARRAY_ELEMENTS(TT_NAME(57)); break;
+ case 58: tt = TT_NAME(58); tt_len = NUM_ARRAY_ELEMENTS(TT_NAME(58)); break;
case 60: tt = TT_NAME(60); tt_len = NUM_ARRAY_ELEMENTS(TT_NAME(60)); break;
case 71: tt = TT_NAME(71); tt_len = NUM_ARRAY_ELEMENTS(TT_NAME(71)); break;
+
default:
return SENSOR_TEMPERATURE_INVALID;
}
-
+
// remember raw values are inverse of temperatures for thermistors.
- if (raw_value < THERMISTOR_RAW_HI_TEMP || raw_value > THERMISTOR_RAW_LO_TEMP)
+ if (raw_value < THERMISTOR_RAW_HI_TEMP || raw_value > THERMISTOR_RAW_LO_TEMP)
return SENSOR_TEMPERATURE_INVALID;
-
+
#define PGM_RD_W(x) (int16_t)pgm_read_word(&x)
// Derived from RepRap FiveD extruder::getTemperature()
// For hot end temperature measurement.
@@ -84,8 +87,8 @@ FORCE_INLINE static float convert_raw_temp_value(int8_t type, uint16_t raw_value
{
if (PGM_RD_W(tt[i][0]) > (int16_t)raw_value)
{
- celsius = PGM_RD_W(tt[i-1][1]) +
- (raw_value - PGM_RD_W(tt[i-1][0])) *
+ celsius = PGM_RD_W(tt[i-1][1]) +
+ (raw_value - PGM_RD_W(tt[i-1][0])) *
(float)(PGM_RD_W(tt[i][1]) - PGM_RD_W(tt[i-1][1])) /
(float)(PGM_RD_W(tt[i][0]) - PGM_RD_W(tt[i-1][0]));
return celsius;
@@ -101,7 +104,7 @@ FORCE_INLINE static float convert_raw_temp_value(int8_t type, uint16_t raw_value
if (raw_value > THERMOCOUPLE_RAW_HI_TEMP || raw_value < THERMOCOUPLE_RAW_LO_TEMP)
return SENSOR_TEMPERATURE_INVALID;
- return ((raw_value * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN)
+ return ((raw_value * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN)
+ TEMP_SENSOR_AD595_OFFSET;
}
else
@@ -122,7 +125,7 @@ uint8_t Device_TemperatureSensor::Init(uint8_t num_devices)
}
uint8_t *memory = (uint8_t *)malloc(num_devices *
- (sizeof(*temperature_sensor_pins) + sizeof(*temperature_sensor_types)
+ (sizeof(*temperature_sensor_pins) + sizeof(*temperature_sensor_types)
+ sizeof(*temperature_sensor_current_temps)
+ sizeof(*temperature_sensor_isr_raw_values) + sizeof(*temperature_sensor_raw_values)));
@@ -137,7 +140,7 @@ uint8_t Device_TemperatureSensor::Init(uint8_t num_devices)
temperature_sensor_isr_raw_values = (uint16_t *)(temperature_sensor_types + num_devices);
temperature_sensor_raw_values = temperature_sensor_isr_raw_values + num_devices;
temperature_sensor_current_temps = (float *)(temperature_sensor_raw_values + num_devices);
-
+
memset(temperature_sensor_pins, 0xFF, num_devices * sizeof(*temperature_sensor_pins));
memset(temperature_sensor_types, TEMP_SENSOR_TYPE_INVALID, num_devices * sizeof(*temperature_sensor_types));
memset(temperature_sensor_raw_values, 0, num_devices * sizeof(*temperature_sensor_raw_values));
@@ -154,9 +157,9 @@ uint8_t Device_TemperatureSensor::Init(uint8_t num_devices)
#ifdef DIDR2
DIDR2 = 0;
#endif
-
+
num_temperature_sensors = num_devices;
-
+
return APP_ERROR_TYPE_SUCCESS;
}
@@ -164,7 +167,7 @@ uint8_t Device_TemperatureSensor::SetPin(uint8_t device_number, uint8_t pin)
{
if (device_number >= num_temperature_sensors)
return PARAM_APP_ERROR_TYPE_INVALID_DEVICE_NUMBER;
-
+
temperature_sensor_pins[device_number] = pin;
return APP_ERROR_TYPE_SUCCESS;
@@ -174,13 +177,13 @@ uint8_t Device_TemperatureSensor::SetType(uint8_t device_number, int16_t type)
{
if (device_number >= num_temperature_sensors)
return PARAM_APP_ERROR_TYPE_INVALID_DEVICE_NUMBER;
-
+
if (type == 0)
{
temperature_sensor_types[device_number] = type;
return APP_ERROR_TYPE_SUCCESS;
}
-
+
if (type >= FIRST_THERMISTOR_SENSOR_TYPE && type <= LAST_THERMISTOR_SENSOR_TYPE)
{
// for now, do conversion as simple way of checking type validity
@@ -204,7 +207,7 @@ uint8_t Device_TemperatureSensor::SetType(uint8_t device_number, int16_t type)
generate_response_msg_addPGM(PMSG(MSG_ERR_UNKNOWN_VALUE));
return PARAM_APP_ERROR_TYPE_BAD_PARAMETER_VALUE;
}
-
+
if (temperature_sensor_pins[device_number] == 0xFF)
{
generate_response_msg_addPGM(PMSG(ERR_MSG_INVALID_PIN_NUMBER));
@@ -217,18 +220,18 @@ uint8_t Device_TemperatureSensor::SetType(uint8_t device_number, int16_t type)
pinMode(pin, INPUT);
if (pin < 8)
{
- DIDR0 |= 1 << pin;
+ DIDR0 |= 1 << pin;
}
else
{
#ifdef DIDR2
- DIDR2 |= 1<<(pin - 8);
-#else
+ DIDR2 |= 1<<(pin - 8);
+#else
generate_response_msg_addPGM(PMSG(ERR_MSG_INVALID_PIN_NUMBER));
return PARAM_APP_ERROR_TYPE_FAILED;
-#endif
+#endif
}
-
+
temperature_sensor_types[device_number] = type;
return APP_ERROR_TYPE_SUCCESS;
diff --git a/Minnow/HardwareSerial.cpp b/Minnow/HardwareSerial.cpp
new file mode 100644
index 0000000..5cd89e5
--- /dev/null
+++ b/Minnow/HardwareSerial.cpp
@@ -0,0 +1,250 @@
+/*
+ HardwareSerial.cpp - Hardware serial library for Wiring
+ Copyright (c) 2006 Nicholas Zambetti. All right reserved.
+
+ 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
+
+ Modified 23 November 2006 by David A. Mellis
+ Modified 28 September 2010 by Mark Sproul
+ Modified 14 August 2012 by Alarus
+ Modified 3 December 2013 by Matthijs Kooijman
+*/
+
+#include
+#include
+#include
+#include
+#include "Arduino.h"
+
+#include "HardwareSerial.h"
+#include "HardwareSerial_private.h"
+
+// this next line disables the entire HardwareSerial.cpp,
+// this is so I can support Attiny series and any other chip without a uart
+#if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3)
+
+// SerialEvent functions are weak, so when the user doesn't define them,
+// the linker just sets their address to 0 (which is checked below).
+// The Serialx_available is just a wrapper around Serialx.available(),
+// but we can refer to it weakly so we don't pull in the entire
+// HardwareSerial instance if the user doesn't also refer to it.
+#if defined(HAVE_HWSERIAL0)
+ void serialEvent() __attribute__((weak));
+ bool Serial0_available() __attribute__((weak));
+#endif
+
+#if defined(HAVE_HWSERIAL1)
+ void serialEvent1() __attribute__((weak));
+ bool Serial1_available() __attribute__((weak));
+#endif
+
+#if defined(HAVE_HWSERIAL2)
+ void serialEvent2() __attribute__((weak));
+ bool Serial2_available() __attribute__((weak));
+#endif
+
+#if defined(HAVE_HWSERIAL3)
+ void serialEvent3() __attribute__((weak));
+ bool Serial3_available() __attribute__((weak));
+#endif
+
+void serialEventRun(void)
+{
+#if defined(HAVE_HWSERIAL0)
+ if (Serial0_available && serialEvent && Serial0_available()) serialEvent();
+#endif
+#if defined(HAVE_HWSERIAL1)
+ if (Serial1_available && serialEvent1 && Serial1_available()) serialEvent1();
+#endif
+#if defined(HAVE_HWSERIAL2)
+ if (Serial2_available && serialEvent2 && Serial2_available()) serialEvent2();
+#endif
+#if defined(HAVE_HWSERIAL3)
+ if (Serial3_available && serialEvent3 && Serial3_available()) serialEvent3();
+#endif
+}
+
+// Actual interrupt handlers //////////////////////////////////////////////////////////////
+
+void HardwareSerial::_tx_udr_empty_irq(void)
+{
+ // If interrupts are enabled, there must be more data in the output
+ // buffer. Send the next byte
+ unsigned char c = _tx_buffer[_tx_buffer_tail];
+ _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE;
+
+ *_udr = c;
+
+ // clear the TXC bit -- "can be cleared by writing a one to its bit
+ // location". This makes sure flush() won't return until the bytes
+ // actually got written
+ sbi(*_ucsra, TXC0);
+
+ if (_tx_buffer_head == _tx_buffer_tail) {
+ // Buffer empty, so disable interrupts
+ cbi(*_ucsrb, UDRIE0);
+ }
+}
+
+// Public Methods //////////////////////////////////////////////////////////////
+
+void HardwareSerial::begin(unsigned long baud, byte config)
+{
+ // Try u2x mode first
+ uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
+ *_ucsra = 1 << U2X0;
+
+ // hardcoded exception for 57600 for compatibility with the bootloader
+ // shipped with the Duemilanove and previous boards and the firmware
+ // on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot
+ // be > 4095, so switch back to non-u2x mode if the baud rate is too
+ // low.
+ if (((F_CPU == 16000000UL) && (baud == 57600)) || (baud_setting >4095))
+ {
+ *_ucsra = 0;
+ baud_setting = (F_CPU / 8 / baud - 1) / 2;
+ }
+
+ // assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register)
+ *_ubrrh = baud_setting >> 8;
+ *_ubrrl = baud_setting;
+
+ _written = false;
+
+ //set the data bits, parity, and stop bits
+#if defined(__AVR_ATmega8__)
+ config |= 0x80; // select UCSRC register (shared with UBRRH)
+#endif
+ *_ucsrc = config;
+
+ sbi(*_ucsrb, RXEN0);
+ sbi(*_ucsrb, TXEN0);
+ sbi(*_ucsrb, RXCIE0);
+ cbi(*_ucsrb, UDRIE0);
+}
+
+void HardwareSerial::end()
+{
+ // wait for transmission of outgoing data
+ flush();
+
+ cbi(*_ucsrb, RXEN0);
+ cbi(*_ucsrb, TXEN0);
+ cbi(*_ucsrb, RXCIE0);
+ cbi(*_ucsrb, UDRIE0);
+
+ // clear any received data
+ _rx_buffer_head = _rx_buffer_tail;
+}
+
+int HardwareSerial::available(void)
+{
+ return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
+}
+
+int HardwareSerial::peek(void)
+{
+ if (_rx_buffer_head == _rx_buffer_tail) {
+ return -1;
+ } else {
+ return _rx_buffer[_rx_buffer_tail];
+ }
+}
+
+int HardwareSerial::read(void)
+{
+ // if the head isn't ahead of the tail, we don't have any characters
+ if (_rx_buffer_head == _rx_buffer_tail) {
+ return -1;
+ } else {
+ unsigned char c = _rx_buffer[_rx_buffer_tail];
+ _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
+ return c;
+ }
+}
+
+int HardwareSerial::availableForWrite(void)
+{
+#if (SERIAL_TX_BUFFER_SIZE>256)
+ uint8_t oldSREG = SREG;
+ cli();
+#endif
+ tx_buffer_index_t head = _tx_buffer_head;
+ tx_buffer_index_t tail = _tx_buffer_tail;
+#if (SERIAL_TX_BUFFER_SIZE>256)
+ SREG = oldSREG;
+#endif
+ if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail;
+ return tail - head - 1;
+}
+
+void HardwareSerial::flush()
+{
+ // If we have never written a byte, no need to flush. This special
+ // case is needed since there is no way to force the TXC (transmit
+ // complete) bit to 1 during initialization
+ if (!_written)
+ return;
+
+ while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) {
+ if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0))
+ // Interrupts are globally disabled, but the DR empty
+ // interrupt should be enabled, so poll the DR empty flag to
+ // prevent deadlock
+ if (bit_is_set(*_ucsra, UDRE0))
+ _tx_udr_empty_irq();
+ }
+ // If we get here, nothing is queued anymore (DRIE is disabled) and
+ // the hardware finished tranmission (TXC is set).
+}
+
+size_t HardwareSerial::write(uint8_t c)
+{
+ _written = true;
+ // If the buffer and the data register is empty, just write the byte
+ // to the data register and be done. This shortcut helps
+ // significantly improve the effective datarate at high (>
+ // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
+ if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) {
+ *_udr = c;
+ sbi(*_ucsra, TXC0);
+ return 1;
+ }
+ tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE;
+
+ // If the output buffer is full, there's nothing for it other than to
+ // wait for the interrupt handler to empty it a bit
+ while (i == _tx_buffer_tail) {
+ if (bit_is_clear(SREG, SREG_I)) {
+ // Interrupts are disabled, so we'll have to poll the data
+ // register empty flag ourselves. If it is set, pretend an
+ // interrupt has happened and call the handler to free up
+ // space for us.
+ if(bit_is_set(*_ucsra, UDRE0))
+ _tx_udr_empty_irq();
+ } else {
+ // nop, the interrupt handler will free up space for us
+ }
+ }
+
+ _tx_buffer[_tx_buffer_head] = c;
+ _tx_buffer_head = i;
+
+ sbi(*_ucsrb, UDRIE0);
+
+ return 1;
+}
+
+#endif // whole file
diff --git a/Minnow/HardwareSerial.h b/Minnow/HardwareSerial.h
new file mode 100644
index 0000000..1beafc5
--- /dev/null
+++ b/Minnow/HardwareSerial.h
@@ -0,0 +1,161 @@
+/*
+ HardwareSerial.h - Hardware serial library for Wiring
+ Copyright (c) 2006 Nicholas Zambetti. All right reserved.
+
+ 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
+
+ Modified 28 September 2010 by Mark Sproul
+ Modified 14 August 2012 by Alarus
+ Modified 3 December 2013 by Matthijs Kooijman
+*/
+
+#ifndef HardwareSerial_h
+#define HardwareSerial_h
+
+#include
+
+#include "Stream.h"
+
+// Define constants and variables for buffering incoming serial data. We're
+// using a ring buffer (I think), in which head is the index of the location
+// to which to write the next incoming character and tail is the index of the
+// location from which to read.
+// NOTE: a "power of 2" buffer size is reccomended to dramatically
+// optimize all the modulo operations for ring buffers.
+// WARNING: When buffer sizes are increased to > 256, the buffer index
+// variables are automatically increased in size, but the extra
+// atomicity guards needed for that are not implemented. This will
+// often work, but occasionally a race condition can occur that makes
+// Serial behave erratically. See https://github.com/arduino/Arduino/issues/2405
+#if !defined(SERIAL_TX_BUFFER_SIZE)
+#if (RAMEND < 1000)
+#define SERIAL_TX_BUFFER_SIZE 16
+#else
+#define SERIAL_TX_BUFFER_SIZE 64
+#endif
+#endif
+#if !defined(SERIAL_RX_BUFFER_SIZE)
+#if (RAMEND < 1000)
+#define SERIAL_RX_BUFFER_SIZE 16
+#else
+#define SERIAL_RX_BUFFER_SIZE 64
+#endif
+#endif
+#if (SERIAL_TX_BUFFER_SIZE>256)
+typedef uint16_t tx_buffer_index_t;
+#else
+typedef uint8_t tx_buffer_index_t;
+#endif
+#if (SERIAL_RX_BUFFER_SIZE>256)
+typedef uint16_t rx_buffer_index_t;
+#else
+typedef uint8_t rx_buffer_index_t;
+#endif
+
+// Define config for Serial.begin(baud, config);
+#define SERIAL_5N1 0x00
+#define SERIAL_6N1 0x02
+#define SERIAL_7N1 0x04
+#define SERIAL_8N1 0x06
+#define SERIAL_5N2 0x08
+#define SERIAL_6N2 0x0A
+#define SERIAL_7N2 0x0C
+#define SERIAL_8N2 0x0E
+#define SERIAL_5E1 0x20
+#define SERIAL_6E1 0x22
+#define SERIAL_7E1 0x24
+#define SERIAL_8E1 0x26
+#define SERIAL_5E2 0x28
+#define SERIAL_6E2 0x2A
+#define SERIAL_7E2 0x2C
+#define SERIAL_8E2 0x2E
+#define SERIAL_5O1 0x30
+#define SERIAL_6O1 0x32
+#define SERIAL_7O1 0x34
+#define SERIAL_8O1 0x36
+#define SERIAL_5O2 0x38
+#define SERIAL_6O2 0x3A
+#define SERIAL_7O2 0x3C
+#define SERIAL_8O2 0x3E
+
+class HardwareSerial : public Stream
+{
+ protected:
+ volatile uint8_t * const _ubrrh;
+ volatile uint8_t * const _ubrrl;
+ volatile uint8_t * const _ucsra;
+ volatile uint8_t * const _ucsrb;
+ volatile uint8_t * const _ucsrc;
+ volatile uint8_t * const _udr;
+ // Has any byte been written to the UART since begin()
+ bool _written;
+
+ volatile rx_buffer_index_t _rx_buffer_head;
+ volatile rx_buffer_index_t _rx_buffer_tail;
+ volatile tx_buffer_index_t _tx_buffer_head;
+ volatile tx_buffer_index_t _tx_buffer_tail;
+
+ // Don't put any members after these buffers, since only the first
+ // 32 bytes of this struct can be accessed quickly using the ldd
+ // instruction.
+ unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE];
+ unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE];
+
+ public:
+ inline HardwareSerial(
+ volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
+ volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
+ volatile uint8_t *ucsrc, volatile uint8_t *udr);
+ void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
+ void begin(unsigned long, uint8_t);
+ void end();
+ virtual int available(void);
+ virtual int peek(void);
+ virtual int read(void);
+ int availableForWrite(void);
+ virtual void flush(void);
+ virtual size_t write(uint8_t);
+ inline size_t write(unsigned long n) { return write((uint8_t)n); }
+ inline size_t write(long n) { return write((uint8_t)n); }
+ inline size_t write(unsigned int n) { return write((uint8_t)n); }
+ inline size_t write(int n) { return write((uint8_t)n); }
+ using Print::write; // pull in write(str) and write(buf, size) from Print
+ operator bool() { return true; }
+
+ // Interrupt handlers - Not intended to be called externally
+ inline void _rx_complete_irq(void);
+ void _tx_udr_empty_irq(void);
+};
+
+#if defined(UBRRH) || defined(UBRR0H)
+ extern HardwareSerial Serial;
+ #define HAVE_HWSERIAL0
+#endif
+#if defined(UBRR1H)
+ extern HardwareSerial Serial1;
+ #define HAVE_HWSERIAL1
+#endif
+#if defined(UBRR2H)
+ extern HardwareSerial Serial2;
+ #define HAVE_HWSERIAL2
+#endif
+#if defined(UBRR3H)
+ extern HardwareSerial Serial3;
+ #define HAVE_HWSERIAL3
+#endif
+
+extern void serialEventRun(void) __attribute__((weak));
+
+#endif
diff --git a/Minnow/HardwareSerial_private.h b/Minnow/HardwareSerial_private.h
new file mode 100644
index 0000000..761a5e5
--- /dev/null
+++ b/Minnow/HardwareSerial_private.h
@@ -0,0 +1,123 @@
+/*
+ HardwareSerial_private.h - Hardware serial library for Wiring
+ Copyright (c) 2006 Nicholas Zambetti. All right reserved.
+
+ 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
+
+ Modified 23 November 2006 by David A. Mellis
+ Modified 28 September 2010 by Mark Sproul
+ Modified 14 August 2012 by Alarus
+*/
+
+#include "wiring_private.h"
+
+// this next line disables the entire HardwareSerial.cpp,
+// this is so I can support Attiny series and any other chip without a uart
+#if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3)
+
+// Ensure that the various bit positions we use are available with a 0
+// postfix, so we can always use the values for UART0 for all UARTs. The
+// alternative, passing the various values for each UART to the
+// HardwareSerial constructor also works, but makes the code bigger and
+// slower.
+#if !defined(TXC0)
+#if defined(TXC)
+// Some chips like ATmega8 don't have UPE, only PE. The other bits are
+// named as expected.
+#if !defined(UPE) && defined(PE)
+#define UPE PE
+#endif
+// On ATmega8, the uart and its bits are not numbered, so there is no TXC0 etc.
+#define TXC0 TXC
+#define RXEN0 RXEN
+#define TXEN0 TXEN
+#define RXCIE0 RXCIE
+#define UDRIE0 UDRIE
+#define U2X0 U2X
+#define UPE0 UPE
+#define UDRE0 UDRE
+#elif defined(TXC1)
+// Some devices have uart1 but no uart0
+#define TXC0 TXC1
+#define RXEN0 RXEN1
+#define TXEN0 TXEN1
+#define RXCIE0 RXCIE1
+#define UDRIE0 UDRIE1
+#define U2X0 U2X1
+#define UPE0 UPE1
+#define UDRE0 UDRE1
+#else
+#error No UART found in HardwareSerial.cpp
+#endif
+#endif // !defined TXC0
+
+// Check at compiletime that it is really ok to use the bit positions of
+// UART0 for the other UARTs as well, in case these values ever get
+// changed for future hardware.
+#if defined(TXC1) && (TXC1 != TXC0 || RXEN1 != RXEN0 || RXCIE1 != RXCIE0 || \
+ UDRIE1 != UDRIE0 || U2X1 != U2X0 || UPE1 != UPE0 || \
+ UDRE1 != UDRE0)
+#error "Not all bit positions for UART1 are the same as for UART0"
+#endif
+#if defined(TXC2) && (TXC2 != TXC0 || RXEN2 != RXEN0 || RXCIE2 != RXCIE0 || \
+ UDRIE2 != UDRIE0 || U2X2 != U2X0 || UPE2 != UPE0 || \
+ UDRE2 != UDRE0)
+#error "Not all bit positions for UART2 are the same as for UART0"
+#endif
+#if defined(TXC3) && (TXC3 != TXC0 || RXEN3 != RXEN0 || RXCIE3 != RXCIE0 || \
+ UDRIE3 != UDRIE0 || U3X3 != U3X0 || UPE3 != UPE0 || \
+ UDRE3 != UDRE0)
+#error "Not all bit positions for UART3 are the same as for UART0"
+#endif
+
+// Constructors ////////////////////////////////////////////////////////////////
+
+HardwareSerial::HardwareSerial(
+ volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
+ volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
+ volatile uint8_t *ucsrc, volatile uint8_t *udr) :
+ _ubrrh(ubrrh), _ubrrl(ubrrl),
+ _ucsra(ucsra), _ucsrb(ucsrb), _ucsrc(ucsrc),
+ _udr(udr),
+ _rx_buffer_head(0), _rx_buffer_tail(0),
+ _tx_buffer_head(0), _tx_buffer_tail(0)
+{
+}
+
+// Actual interrupt handlers //////////////////////////////////////////////////////////////
+
+void HardwareSerial::_rx_complete_irq(void)
+{
+ if (bit_is_clear(*_ucsra, UPE0)) {
+ // No Parity error, read byte and store it in the buffer if there is
+ // room
+ unsigned char c = *_udr;
+ rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
+
+ // if we should be storing the received character into the location
+ // just before the tail (meaning that the head would advance to the
+ // current location of the tail), we're about to overflow the buffer
+ // and so we don't write the character or advance the head.
+ if (i != _rx_buffer_tail) {
+ _rx_buffer[_rx_buffer_head] = c;
+ _rx_buffer_head = i;
+ }
+ } else {
+ // Parity error, read byte but discard it
+ *_udr;
+ };
+}
+
+#endif // whole file
diff --git a/Minnow/Makefile b/Minnow/Makefile
new file mode 100644
index 0000000..99ceae8
--- /dev/null
+++ b/Minnow/Makefile
@@ -0,0 +1,258 @@
+PROGRAMMER=wiring
+#auskommentieren für automatische Wahl
+PORT=-P/dev/ttyACM0
+BAUD=-b115200
+
+# Microcontroller Type
+MCU = atmega2560
+
+# Target file name (without extension).
+TARGET = Minnow_main
+
+OPT = s
+
+FORMAT = ihex
+
+CPP_SRC = Minnow_main.cpp
+CPP_SRC += AxisInfo.cpp
+CPP_SRC += CommandQueue.cpp
+CPP_SRC += ConfigTree.cpp
+CPP_SRC += ConfigTreeNode.cpp
+CPP_SRC += crc8.cpp
+CPP_SRC += debug.cpp
+CPP_SRC += Device_Buzzer.cpp
+CPP_SRC += Device_Heater.cpp
+CPP_SRC += Device_InputSwitch.cpp
+CPP_SRC += Device_OutputSwitch.cpp
+CPP_SRC += Device_PwmOutput.cpp
+CPP_SRC += Device_Stepper.cpp
+CPP_SRC += Device_TemperatureSensor.cpp
+CPP_SRC += enqueue_command.cpp
+CPP_SRC += firmware_configuration.cpp
+CPP_SRC += HwSerial.cpp
+CPP_SRC += initial_pin_state.cpp
+CPP_SRC += language.cpp
+CPP_SRC += movement_ISR.cpp
+CPP_SRC += NVConfigStore.cpp
+CPP_SRC += order_handlers.cpp
+CPP_SRC += order_helpers.cpp
+CPP_SRC += response.cpp
+CPP_SRC += SoftPwmState.cpp
+CPP_SRC += temperature_ISR.cpp
+CPP_SRC += Tone.cpp
+CPP_SRC += main.cpp
+C_SRC += wiring.c
+C_SRC += wiring_analog.c
+C_SRC += wiring_digital.c
+C_SRC += hooks.c
+
+SRC = $(CPP_SRC) $(C_SRC)
+
+CFLAGS = -g -O$(OPT) \
+-mmcu=$(MCU) -I. \
+-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \
+-Wall \
+-DF_CPU=16000000 \
+-Wa,-adhlns=$(<:.c=.lst) \
+$(patsubst %,-I%,$(EXTRAINCDIRS))
+
+CPP_FLAGS = -g -O$(OPT) \
+-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \
+-Wall \
+-DF_CPU=16000000 \
+-std=c++03 \
+-Wa,-adhlns=$(<:.cpp=.lst) \
+$(patsubst %,-I%,$(EXTRAINCDIRS))
+
+ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
+LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
+
+CC = avr-g++
+
+OBJCOPY = avr-objcopy
+OBJDUMP = avr-objdump
+SIZE = avr-size
+
+
+REMOVE = rm -f
+COPY = cp
+
+HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
+ELFSIZE = $(SIZE) -A $(TARGET).elf
+
+
+
+# Define Messages
+# English
+MSG_ERRORS_NONE = Errors: none
+MSG_BEGIN = -------- begin --------
+MSG_END = -------- end --------
+MSG_SIZE_BEFORE = Size before:
+MSG_SIZE_AFTER = Size after:
+MSG_COFF = Converting to AVR COFF:
+MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
+MSG_FLASH = Creating load file for Flash:
+MSG_EEPROM = Creating load file for EEPROM:
+MSG_EXTENDED_LISTING = Creating Extended Listing:
+MSG_SYMBOL_TABLE = Creating Symbol Table:
+MSG_LINKING = Linking:
+MSG_COMPILING = Compiling:
+MSG_ASSEMBLING = Assembling:
+MSG_CLEANING = Cleaning project:
+
+
+
+
+# Define all object files.
+OBJ = $(CPP_SRC:.cpp=.o) $(C_SRC:.c=.o) $(ASRC:.S=.o)
+
+# Define all listing files.
+LST = $(ASRC:.S=.lst) $(CPP_SRC:.cpp=.lst) $(C_SRC:.c=.lst)
+
+# Combine all necessary flags and optional flags.
+# Add target processor to flags.
+ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
+ALL_CPP_FLAGS = -mmcu=$(MCU) -I. $(CPP_FLAGS)
+ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
+
+# Default target: make program!
+all: begin gccversion sizebefore $(TARGET).elf $(TARGET).hex $(TARGET).eep \
+ $(TARGET).lss $(TARGET).sym sizeafter finished end
+
+begin:
+ @echo
+ @echo $(MSG_BEGIN)
+
+finished:
+ @echo $(MSG_ERRORS_NONE)
+
+end:
+ @echo $(MSG_END)
+ @echo
+
+
+# Display size of file.
+sizebefore:
+ @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); echo; fi
+
+sizeafter:
+ @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi
+
+
+
+# Display compiler version information.
+gccversion :
+ @$(CC) --version
+
+
+
+
+# Convert ELF to COFF for use in debugging / simulating in
+# AVR Studio or VMLAB.
+COFFCONVERT=$(OBJCOPY) --debugging \
+ --change-section-address .data-0x800000 \
+ --change-section-address .bss-0x800000 \
+ --change-section-address .noinit-0x800000 \
+ --change-section-address .eeprom-0x810000
+
+
+coff: $(TARGET).elf
+ @echo
+ @echo $(MSG_COFF) $(TARGET).cof
+ $(COFFCONVERT) -O coff-avr $< $(TARGET).cof
+
+
+extcoff: $(TARGET).elf
+ @echo
+ @echo $(MSG_EXTENDED_COFF) $(TARGET).cof
+ $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
+
+
+
+
+# Create final output files (.hex, .eep) from ELF output file.
+%.hex: %.elf
+ @echo
+ @echo $(MSG_FLASH) $@
+ $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
+
+%.eep: %.elf
+ @echo
+ @echo $(MSG_EEPROM) $@
+ -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
+ --change-section-lma .eeprom=0 -O $(FORMAT) $< $@
+
+# Create extended listing file from ELF output file.
+%.lss: %.elf
+ @echo
+ @echo $(MSG_EXTENDED_LISTING) $@
+ $(OBJDUMP) -h -S $< > $@
+
+# Create a symbol table from ELF output file.
+%.sym: %.elf
+ @echo
+ @echo $(MSG_SYMBOL_TABLE) $@
+ avr-nm -n $< > $@
+
+
+
+# Link: create ELF output file from object files.
+.SECONDARY : $(TARGET).elf
+.PRECIOUS : $(OBJ)
+%.elf: $(OBJ)
+ @echo
+ @echo $(MSG_LINKING) $@
+ $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
+
+
+# Compile: create object files from C++ source files.
+%.o : %.cpp
+ @echo
+ @echo $(MSG_COMPILING) $<
+ $(CC) -c $(ALL_CPP_FLAGS) $< -o $@
+
+# Compile: create assembler files from C source files.
+%.s : %.c
+ @echo
+ @echo $(MSG_COMPILING) $<
+ $(CC) -S $(ALL_CFLAGS) $< -o $@
+
+
+# Assemble: create object files from assembler source files.
+%.o : %.S
+ @echo
+ @echo $(MSG_ASSEMBLING) $<
+ $(CC) -c $(ALL_ASFLAGS) $< -o $@
+
+# Target: clean project.
+clean: begin clean_list finished end
+
+clean_list :
+ @echo
+ @echo $(MSG_CLEANING)
+ $(REMOVE) $(TARGET).hex
+ $(REMOVE) $(TARGET).eep
+ $(REMOVE) $(TARGET).obj
+ $(REMOVE) $(TARGET).cof
+ $(REMOVE) $(TARGET).elf
+ $(REMOVE) $(TARGET).map
+ $(REMOVE) $(TARGET).obj
+ $(REMOVE) $(TARGET).a90
+ $(REMOVE) $(TARGET).sym
+ $(REMOVE) $(TARGET).lnk
+ $(REMOVE) $(TARGET).lss
+ $(REMOVE) $(OBJ)
+ $(REMOVE) $(LST)
+ $(REMOVE) $(CPP_SRC:.cpp=.s)
+ $(REMOVE) $(C_SRC:.c=.s)
+ $(REMOVE) $(CPP_SRC:.cpp=.d)
+ $(REMOVE) $(C_SRC:.c=.d)
+ $(REMOVE) *~
+
+program:
+ avrdude -p$(MCU) $(PORT) $(BAUD) -c$(PROGRAMMER) -D -Uflash:w:$(TARGET).hex:i
+
+# Listing of phony targets.
+.PHONY : all begin finish end sizebefore sizeafter gccversion coff extcoff \
+ clean clean_list program
+
diff --git a/Minnow/Print.cpp b/Minnow/Print.cpp
new file mode 100644
index 0000000..bc97c85
--- /dev/null
+++ b/Minnow/Print.cpp
@@ -0,0 +1,265 @@
+/*
+ Print.cpp - Base class that provides print() and println()
+ Copyright (c) 2008 David A. Mellis. All right reserved.
+
+ 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
+
+ Modified 23 November 2006 by David A. Mellis
+ Modified 03 August 2015 by Chuck Todd
+ */
+
+#include
+#include
+#include
+#include
+#include "Arduino.h"
+
+#include "Print.h"
+
+// Public Methods //////////////////////////////////////////////////////////////
+
+/* default implementation: may be overridden */
+size_t Print::write(const uint8_t *buffer, size_t size)
+{
+ size_t n = 0;
+ while (size--) {
+ if (write(*buffer++)) n++;
+ else break;
+ }
+ return n;
+}
+
+size_t Print::print(const __FlashStringHelper *ifsh)
+{
+ PGM_P p = reinterpret_cast(ifsh);
+ size_t n = 0;
+ while (1) {
+ unsigned char c = pgm_read_byte(p++);
+ if (c == 0) break;
+ if (write(c)) n++;
+ else break;
+ }
+ return n;
+}
+
+size_t Print::print(const String &s)
+{
+ return write(s.c_str(), s.length());
+}
+
+size_t Print::print(const char str[])
+{
+ return write(str);
+}
+
+size_t Print::print(char c)
+{
+ return write(c);
+}
+
+size_t Print::print(unsigned char b, int base)
+{
+ return print((unsigned long) b, base);
+}
+
+size_t Print::print(int n, int base)
+{
+ return print((long) n, base);
+}
+
+size_t Print::print(unsigned int n, int base)
+{
+ return print((unsigned long) n, base);
+}
+
+size_t Print::print(long n, int base)
+{
+ if (base == 0) {
+ return write(n);
+ } else if (base == 10) {
+ if (n < 0) {
+ int t = print('-');
+ n = -n;
+ return printNumber(n, 10) + t;
+ }
+ return printNumber(n, 10);
+ } else {
+ return printNumber(n, base);
+ }
+}
+
+size_t Print::print(unsigned long n, int base)
+{
+ if (base == 0) return write(n);
+ else return printNumber(n, base);
+}
+
+size_t Print::print(double n, int digits)
+{
+ return printFloat(n, digits);
+}
+
+size_t Print::println(const __FlashStringHelper *ifsh)
+{
+ size_t n = print(ifsh);
+ n += println();
+ return n;
+}
+
+size_t Print::print(const Printable& x)
+{
+ return x.printTo(*this);
+}
+
+size_t Print::println(void)
+{
+ return write("\r\n");
+}
+
+size_t Print::println(const String &s)
+{
+ size_t n = print(s);
+ n += println();
+ return n;
+}
+
+size_t Print::println(const char c[])
+{
+ size_t n = print(c);
+ n += println();
+ return n;
+}
+
+size_t Print::println(char c)
+{
+ size_t n = print(c);
+ n += println();
+ return n;
+}
+
+size_t Print::println(unsigned char b, int base)
+{
+ size_t n = print(b, base);
+ n += println();
+ return n;
+}
+
+size_t Print::println(int num, int base)
+{
+ size_t n = print(num, base);
+ n += println();
+ return n;
+}
+
+size_t Print::println(unsigned int num, int base)
+{
+ size_t n = print(num, base);
+ n += println();
+ return n;
+}
+
+size_t Print::println(long num, int base)
+{
+ size_t n = print(num, base);
+ n += println();
+ return n;
+}
+
+size_t Print::println(unsigned long num, int base)
+{
+ size_t n = print(num, base);
+ n += println();
+ return n;
+}
+
+size_t Print::println(double num, int digits)
+{
+ size_t n = print(num, digits);
+ n += println();
+ return n;
+}
+
+size_t Print::println(const Printable& x)
+{
+ size_t n = print(x);
+ n += println();
+ return n;
+}
+
+// Private Methods /////////////////////////////////////////////////////////////
+
+size_t Print::printNumber(unsigned long n, uint8_t base) {
+ char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
+ char *str = &buf[sizeof(buf) - 1];
+
+ *str = '\0';
+
+ // prevent crash if called with base == 1
+ if (base < 2) base = 10;
+
+ do {
+ unsigned long m = n;
+ n /= base;
+ char c = m - base * n;
+ *--str = c < 10 ? c + '0' : c + 'A' - 10;
+ } while(n);
+
+ return write(str);
+}
+
+size_t Print::printFloat(double number, uint8_t digits)
+{
+ size_t n = 0;
+
+ if (isnan(number)) return print("nan");
+ if (isinf(number)) return print("inf");
+ if (number > 4294967040.0) return print ("ovf"); // constant determined empirically
+ if (number <-4294967040.0) return print ("ovf"); // constant determined empirically
+
+ // Handle negative numbers
+ if (number < 0.0)
+ {
+ n += print('-');
+ number = -number;
+ }
+
+ // Round correctly so that print(1.999, 2) prints as "2.00"
+ double rounding = 0.5;
+ for (uint8_t i=0; i 0) {
+ n += print(".");
+ }
+
+ // Extract digits from the remainder one at a time
+ while (digits-- > 0)
+ {
+ remainder *= 10.0;
+ int toPrint = int(remainder);
+ n += print(toPrint);
+ remainder -= toPrint;
+ }
+
+ return n;
+}
diff --git a/Minnow/Print.h b/Minnow/Print.h
new file mode 100644
index 0000000..7b53aa4
--- /dev/null
+++ b/Minnow/Print.h
@@ -0,0 +1,84 @@
+/*
+ Print.h - Base class that provides print() and println()
+ Copyright (c) 2008 David A. Mellis. All right reserved.
+
+ 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
+*/
+
+#ifndef Print_h
+#define Print_h
+
+#include
+#include // for size_t
+
+#include "WString.h"
+#include "Printable.h"
+
+#define DEC 10
+#define HEX 16
+#define OCT 8
+#define BIN 2
+
+class Print
+{
+ private:
+ int write_error;
+ size_t printNumber(unsigned long, uint8_t);
+ size_t printFloat(double, uint8_t);
+ protected:
+ void setWriteError(int err = 1) { write_error = err; }
+ public:
+ Print() : write_error(0) {}
+
+ int getWriteError() { return write_error; }
+ void clearWriteError() { setWriteError(0); }
+
+ virtual size_t write(uint8_t) = 0;
+ size_t write(const char *str) {
+ if (str == NULL) return 0;
+ return write((const uint8_t *)str, strlen(str));
+ }
+ virtual size_t write(const uint8_t *buffer, size_t size);
+ size_t write(const char *buffer, size_t size) {
+ return write((const uint8_t *)buffer, size);
+ }
+
+ size_t print(const __FlashStringHelper *);
+ size_t print(const String &);
+ size_t print(const char[]);
+ size_t print(char);
+ size_t print(unsigned char, int = DEC);
+ size_t print(int, int = DEC);
+ size_t print(unsigned int, int = DEC);
+ size_t print(long, int = DEC);
+ size_t print(unsigned long, int = DEC);
+ size_t print(double, int = 2);
+ size_t print(const Printable&);
+
+ size_t println(const __FlashStringHelper *);
+ size_t println(const String &s);
+ size_t println(const char[]);
+ size_t println(char);
+ size_t println(unsigned char, int = DEC);
+ size_t println(int, int = DEC);
+ size_t println(unsigned int, int = DEC);
+ size_t println(long, int = DEC);
+ size_t println(unsigned long, int = DEC);
+ size_t println(double, int = 2);
+ size_t println(const Printable&);
+ size_t println(void);
+};
+
+#endif
diff --git a/Minnow/Printable.h b/Minnow/Printable.h
new file mode 100644
index 0000000..2a1b2e9
--- /dev/null
+++ b/Minnow/Printable.h
@@ -0,0 +1,40 @@
+/*
+ Printable.h - Interface class that allows printing of complex types
+ Copyright (c) 2011 Adrian McEwen. All right reserved.
+
+ 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
+*/
+
+#ifndef Printable_h
+#define Printable_h
+
+#include
+
+class Print;
+
+/** The Printable class provides a way for new classes to allow themselves to be printed.
+ By deriving from Printable and implementing the printTo method, it will then be possible
+ for users to print out instances of this class by passing them into the usual
+ Print::print and Print::println methods.
+*/
+
+class Printable
+{
+ public:
+ virtual size_t printTo(Print& p) const = 0;
+};
+
+#endif
+
diff --git a/Minnow/Stream.cpp b/Minnow/Stream.cpp
new file mode 100644
index 0000000..b31942f
--- /dev/null
+++ b/Minnow/Stream.cpp
@@ -0,0 +1,317 @@
+/*
+ Stream.cpp - adds parsing methods to Stream class
+ Copyright (c) 2008 David A. Mellis. All right reserved.
+
+ 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
+
+ Created July 2011
+ parsing functions based on TextFinder library by Michael Margolis
+
+ findMulti/findUntil routines written by Jim Leonard/Xuth
+ */
+
+#include "Arduino.h"
+#include "Stream.h"
+
+#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
+#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
+
+// private method to read stream with timeout
+int Stream::timedRead()
+{
+ int c;
+ _startMillis = millis();
+ do {
+ c = read();
+ if (c >= 0) return c;
+ } while(millis() - _startMillis < _timeout);
+ return -1; // -1 indicates timeout
+}
+
+// private method to peek stream with timeout
+int Stream::timedPeek()
+{
+ int c;
+ _startMillis = millis();
+ do {
+ c = peek();
+ if (c >= 0) return c;
+ } while(millis() - _startMillis < _timeout);
+ return -1; // -1 indicates timeout
+}
+
+// returns peek of the next digit in the stream or -1 if timeout
+// discards non-numeric characters
+int Stream::peekNextDigit()
+{
+ int c;
+ while (1) {
+ c = timedPeek();
+ if (c < 0) return c; // timeout
+ if (c == '-') return c;
+ if (c >= '0' && c <= '9') return c;
+ read(); // discard non-numeric
+ }
+}
+
+// Public Methods
+//////////////////////////////////////////////////////////////
+
+void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
+{
+ _timeout = timeout;
+}
+
+ // find returns true if the target string is found
+bool Stream::find(char *target)
+{
+ return findUntil(target, strlen(target), NULL, 0);
+}
+
+// reads data from the stream until the target string of given length is found
+// returns true if target string is found, false if timed out
+bool Stream::find(char *target, size_t length)
+{
+ return findUntil(target, length, NULL, 0);
+}
+
+// as find but search ends if the terminator string is found
+bool Stream::findUntil(char *target, char *terminator)
+{
+ return findUntil(target, strlen(target), terminator, strlen(terminator));
+}
+
+// reads data from the stream until the target string of the given length is found
+// search terminated if the terminator string is found
+// returns true if target string is found, false if terminated or timed out
+bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
+{
+ if (terminator == NULL) {
+ MultiTarget t[1] = {{target, targetLen, 0}};
+ return findMulti(t, 1) == 0 ? true : false;
+ } else {
+ MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
+ return findMulti(t, 2) == 0 ? true : false;
+ }
+}
+
+
+// returns the first valid (long) integer value from the current position.
+// initial characters that are not digits (or the minus sign) are skipped
+// function is terminated by the first character that is not a digit.
+long Stream::parseInt()
+{
+ return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
+}
+
+// as above but a given skipChar is ignored
+// this allows format characters (typically commas) in values to be ignored
+long Stream::parseInt(char skipChar)
+{
+ bool isNegative = false;
+ long value = 0;
+ int c;
+
+ c = peekNextDigit();
+ // ignore non numeric leading characters
+ if(c < 0)
+ return 0; // zero returned if timeout
+
+ do{
+ if(c == skipChar)
+ ; // ignore this charactor
+ else if(c == '-')
+ isNegative = true;
+ else if(c >= '0' && c <= '9') // is c a digit?
+ value = value * 10 + c - '0';
+ read(); // consume the character we got with peek
+ c = timedPeek();
+ }
+ while( (c >= '0' && c <= '9') || c == skipChar );
+
+ if(isNegative)
+ value = -value;
+ return value;
+}
+
+
+// as parseInt but returns a floating point value
+float Stream::parseFloat()
+{
+ return parseFloat(NO_SKIP_CHAR);
+}
+
+// as above but the given skipChar is ignored
+// this allows format characters (typically commas) in values to be ignored
+float Stream::parseFloat(char skipChar){
+ bool isNegative = false;
+ bool isFraction = false;
+ long value = 0;
+ char c;
+ float fraction = 1.0;
+
+ c = peekNextDigit();
+ // ignore non numeric leading characters
+ if(c < 0)
+ return 0; // zero returned if timeout
+
+ do{
+ if(c == skipChar)
+ ; // ignore
+ else if(c == '-')
+ isNegative = true;
+ else if (c == '.')
+ isFraction = true;
+ else if(c >= '0' && c <= '9') { // is c a digit?
+ value = value * 10 + c - '0';
+ if(isFraction)
+ fraction *= 0.1;
+ }
+ read(); // consume the character we got with peek
+ c = timedPeek();
+ }
+ while( (c >= '0' && c <= '9') || c == '.' || c == skipChar );
+
+ if(isNegative)
+ value = -value;
+ if(isFraction)
+ return value * fraction;
+ else
+ return value;
+}
+
+// read characters from stream into buffer
+// terminates if length characters have been read, or timeout (see setTimeout)
+// returns the number of characters placed in the buffer
+// the buffer is NOT null terminated.
+//
+size_t Stream::readBytes(char *buffer, size_t length)
+{
+ size_t count = 0;
+ while (count < length) {
+ int c = timedRead();
+ if (c < 0) break;
+ *buffer++ = (char)c;
+ count++;
+ }
+ return count;
+}
+
+
+// as readBytes with terminator character
+// terminates if length characters have been read, timeout, or if the terminator character detected
+// returns the number of characters placed in the buffer (0 means no valid data found)
+
+size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
+{
+ if (length < 1) return 0;
+ size_t index = 0;
+ while (index < length) {
+ int c = timedRead();
+ if (c < 0 || c == terminator) break;
+ *buffer++ = (char)c;
+ index++;
+ }
+ return index; // return number of characters, not including null terminator
+}
+
+String Stream::readString()
+{
+ String ret;
+ int c = timedRead();
+ while (c >= 0)
+ {
+ ret += (char)c;
+ c = timedRead();
+ }
+ return ret;
+}
+
+String Stream::readStringUntil(char terminator)
+{
+ String ret;
+ int c = timedRead();
+ while (c >= 0 && c != terminator)
+ {
+ ret += (char)c;
+ c = timedRead();
+ }
+ return ret;
+}
+
+int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
+ // any zero length target string automatically matches and would make
+ // a mess of the rest of the algorithm.
+ for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
+ if (t->len <= 0)
+ return t - targets;
+ }
+
+ while (1) {
+ int c = timedRead();
+ if (c < 0)
+ return -1;
+
+ for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
+ // the simple case is if we match, deal with that first.
+ if (c == t->str[t->index]) {
+ if (++t->index == t->len)
+ return t - targets;
+ else
+ continue;
+ }
+
+ // if not we need to walk back and see if we could have matched further
+ // down the stream (ie '1112' doesn't match the first position in '11112'
+ // but it will match the second position so we can't just reset the current
+ // index to 0 when we find a mismatch.
+ if (t->index == 0)
+ continue;
+
+ int origIndex = t->index;
+ do {
+ --t->index;
+ // first check if current char works against the new current index
+ if (c != t->str[t->index])
+ continue;
+
+ // if it's the only char then we're good, nothing more to check
+ if (t->index == 0) {
+ t->index++;
+ break;
+ }
+
+ // otherwise we need to check the rest of the found string
+ int diff = origIndex - t->index;
+ size_t i;
+ for (i = 0; i < t->index; ++i) {
+ if (t->str[i] != t->str[i + diff])
+ break;
+ }
+
+ // if we successfully got through the previous loop then our current
+ // index is good.
+ if (i == t->index) {
+ t->index++;
+ break;
+ }
+
+ // otherwise we just try the next index
+ } while (t->index);
+ }
+ }
+ // unreachable
+ return -1;
+}
diff --git a/Minnow/Stream.h b/Minnow/Stream.h
new file mode 100644
index 0000000..15f6761
--- /dev/null
+++ b/Minnow/Stream.h
@@ -0,0 +1,115 @@
+/*
+ Stream.h - base class for character-based streams.
+ Copyright (c) 2010 David A. Mellis. All right reserved.
+
+ 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
+
+ parsing functions based on TextFinder library by Michael Margolis
+*/
+
+#ifndef Stream_h
+#define Stream_h
+
+#include
+#include "Print.h"
+
+// compatability macros for testing
+/*
+#define getInt() parseInt()
+#define getInt(skipChar) parseInt(skipchar)
+#define getFloat() parseFloat()
+#define getFloat(skipChar) parseFloat(skipChar)
+#define getString( pre_string, post_string, buffer, length)
+readBytesBetween( pre_string, terminator, buffer, length)
+*/
+
+class Stream : public Print
+{
+ protected:
+ unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
+ unsigned long _startMillis; // used for timeout measurement
+ int timedRead(); // private method to read stream with timeout
+ int timedPeek(); // private method to peek stream with timeout
+ int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
+
+ public:
+ virtual int available() = 0;
+ virtual int read() = 0;
+ virtual int peek() = 0;
+ virtual void flush() = 0;
+
+ Stream() {_timeout=1000;}
+
+// parsing methods
+
+ void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
+
+ bool find(char *target); // reads data from the stream until the target string is found
+ bool find(uint8_t *target) { return find ((char *)target); }
+ // returns true if target string is found, false if timed out (see setTimeout)
+
+ bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found
+ bool find(uint8_t *target, size_t length) { return find ((char *)target, length); }
+ // returns true if target string is found, false if timed out
+
+ bool find(char target) { return find (&target, 1); }
+
+ bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found
+ bool findUntil(uint8_t *target, char *terminator) { return findUntil((char *)target, terminator); }
+
+ bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found
+ bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); }
+
+
+ long parseInt(); // returns the first valid (long) integer value from the current position.
+ // initial characters that are not digits (or the minus sign) are skipped
+ // integer is terminated by the first character that is not a digit.
+
+ float parseFloat(); // float version of parseInt
+
+ size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer
+ size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); }
+ // terminates if length characters have been read or timeout (see setTimeout)
+ // returns the number of characters placed in the buffer (0 means no valid data found)
+
+ size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character
+ size_t readBytesUntil( char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); }
+ // terminates if length characters have been read, timeout, or if the terminator character detected
+ // returns the number of characters placed in the buffer (0 means no valid data found)
+
+ // Arduino String functions to be added here
+ String readString();
+ String readStringUntil(char terminator);
+
+ protected:
+ long parseInt(char skipChar); // as above but the given skipChar is ignored
+ // as above but the given skipChar is ignored
+ // this allows format characters (typically commas) in values to be ignored
+
+ float parseFloat(char skipChar); // as above but the given skipChar is ignored
+
+ struct MultiTarget {
+ const char *str; // string you're searching for
+ size_t len; // length of string you're searching for
+ size_t index; // index used by the search routine.
+ };
+
+ // This allows you to search for an arbitrary number of strings.
+ // Returns index of the target that is found first or -1 if timeout occurs.
+ int findMulti(struct MultiTarget *targets, int tCount);
+};
+
+
+#endif
diff --git a/Minnow/Tone.cpp b/Minnow/Tone.cpp
new file mode 100644
index 0000000..4e058cd
--- /dev/null
+++ b/Minnow/Tone.cpp
@@ -0,0 +1,619 @@
+/* Tone.cpp
+
+ A Tone Generator Library
+
+ Written by Brett Hagman
+
+ 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
+
+Version Modified By Date Comments
+------- ----------- -------- --------
+0001 B Hagman 09/08/02 Initial coding
+0002 B Hagman 09/08/18 Multiple pins
+0003 B Hagman 09/08/18 Moved initialization from constructor to begin()
+0004 B Hagman 09/09/26 Fixed problems with ATmega8
+0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers
+ 09/11/25 Changed pin toggle method to XOR
+ 09/11/25 Fixed timer0 from being excluded
+0006 D Mellis 09/12/29 Replaced objects with functions
+0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register
+0008 S Kanemoto 12/06/22 Fixed for Leonardo by @maris_HY
+0009 J Reucker 15/04/10 Issue #292 Fixed problems with ATmega8 (thanks to Pete62)
+0010 jipp 15/04/13 added additional define check #2923
+*************************************************/
+
+#include
+#include
+#include "Arduino.h"
+#include "pins_arduino.h"
+
+#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
+#define TCCR2A TCCR2
+#define TCCR2B TCCR2
+#define COM2A1 COM21
+#define COM2A0 COM20
+#define OCR2A OCR2
+#define TIMSK2 TIMSK
+#define OCIE2A OCIE2
+#define TIMER2_COMPA_vect TIMER2_COMP_vect
+#define TIMSK1 TIMSK
+#endif
+
+// timerx_toggle_count:
+// > 0 - duration specified
+// = 0 - stopped
+// < 0 - infinitely (until stop() method called, or new play() called)
+
+#if !defined(__AVR_ATmega8__)
+volatile long timer0_toggle_count;
+volatile uint8_t *timer0_pin_port;
+volatile uint8_t timer0_pin_mask;
+#endif
+
+volatile long timer1_toggle_count;
+volatile uint8_t *timer1_pin_port;
+volatile uint8_t timer1_pin_mask;
+volatile long timer2_toggle_count;
+volatile uint8_t *timer2_pin_port;
+volatile uint8_t timer2_pin_mask;
+
+#if defined(TIMSK3)
+volatile long timer3_toggle_count;
+volatile uint8_t *timer3_pin_port;
+volatile uint8_t timer3_pin_mask;
+#endif
+
+#if defined(TIMSK4)
+volatile long timer4_toggle_count;
+volatile uint8_t *timer4_pin_port;
+volatile uint8_t timer4_pin_mask;
+#endif
+
+#if defined(TIMSK5)
+volatile long timer5_toggle_count;
+volatile uint8_t *timer5_pin_port;
+volatile uint8_t timer5_pin_mask;
+#endif
+
+
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+
+#define AVAILABLE_TONE_PINS 1
+#define USE_TIMER2
+
+const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ };
+static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ };
+
+#elif defined(__AVR_ATmega8__)
+
+#define AVAILABLE_TONE_PINS 1
+#define USE_TIMER2
+
+const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ };
+static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
+
+#elif defined(__AVR_ATmega32U4__)
+
+#define AVAILABLE_TONE_PINS 1
+#define USE_TIMER3
+
+const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 3 /*, 1 */ };
+static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
+
+#else
+
+#define AVAILABLE_TONE_PINS 1
+#define USE_TIMER2
+
+// Leave timer 0 to last.
+const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ };
+static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ };
+
+#endif
+
+
+
+static int8_t toneBegin(uint8_t _pin)
+{
+ int8_t _timer = -1;
+
+ // if we're already using the pin, the timer should be configured.
+ for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
+ if (tone_pins[i] == _pin) {
+ return pgm_read_byte(tone_pin_to_timer_PGM + i);
+ }
+ }
+
+ // search for an unused timer.
+ for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
+ if (tone_pins[i] == 255) {
+ tone_pins[i] = _pin;
+ _timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
+ break;
+ }
+ }
+
+ if (_timer != -1)
+ {
+ // Set timer specific stuff
+ // All timers in CTC mode
+ // 8 bit timers will require changing prescalar values,
+ // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
+ switch (_timer)
+ {
+ #if defined(TCCR0A) && defined(TCCR0B) && defined(WGM01)
+ case 0:
+ // 8 bit timer
+ TCCR0A = 0;
+ TCCR0B = 0;
+ bitWrite(TCCR0A, WGM01, 1);
+ bitWrite(TCCR0B, CS00, 1);
+ timer0_pin_port = portOutputRegister(digitalPinToPort(_pin));
+ timer0_pin_mask = digitalPinToBitMask(_pin);
+ break;
+ #endif
+
+ #if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)
+ case 1:
+ // 16 bit timer
+ TCCR1A = 0;
+ TCCR1B = 0;
+ bitWrite(TCCR1B, WGM12, 1);
+ bitWrite(TCCR1B, CS10, 1);
+ timer1_pin_port = portOutputRegister(digitalPinToPort(_pin));
+ timer1_pin_mask = digitalPinToBitMask(_pin);
+ break;
+ #endif
+
+ #if defined(TCCR2A) && defined(TCCR2B)
+ case 2:
+ // 8 bit timer
+ TCCR2A = 0;
+ TCCR2B = 0;
+ bitWrite(TCCR2A, WGM21, 1);
+ bitWrite(TCCR2B, CS20, 1);
+ timer2_pin_port = portOutputRegister(digitalPinToPort(_pin));
+ timer2_pin_mask = digitalPinToBitMask(_pin);
+ break;
+ #endif
+
+ #if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3)
+ case 3:
+ // 16 bit timer
+ TCCR3A = 0;
+ TCCR3B = 0;
+ bitWrite(TCCR3B, WGM32, 1);
+ bitWrite(TCCR3B, CS30, 1);
+ timer3_pin_port = portOutputRegister(digitalPinToPort(_pin));
+ timer3_pin_mask = digitalPinToBitMask(_pin);
+ break;
+ #endif
+
+ #if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4)
+ case 4:
+ // 16 bit timer
+ TCCR4A = 0;
+ TCCR4B = 0;
+ #if defined(WGM42)
+ bitWrite(TCCR4B, WGM42, 1);
+ #elif defined(CS43)
+ #warning this may not be correct
+ // atmega32u4
+ bitWrite(TCCR4B, CS43, 1);
+ #endif
+ bitWrite(TCCR4B, CS40, 1);
+ timer4_pin_port = portOutputRegister(digitalPinToPort(_pin));
+ timer4_pin_mask = digitalPinToBitMask(_pin);
+ break;
+ #endif
+
+ #if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5)
+ case 5:
+ // 16 bit timer
+ TCCR5A = 0;
+ TCCR5B = 0;
+ bitWrite(TCCR5B, WGM52, 1);
+ bitWrite(TCCR5B, CS50, 1);
+ timer5_pin_port = portOutputRegister(digitalPinToPort(_pin));
+ timer5_pin_mask = digitalPinToBitMask(_pin);
+ break;
+ #endif
+ }
+ }
+
+ return _timer;
+}
+
+
+
+// frequency (in hertz) and duration (in milliseconds).
+
+void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
+{
+ uint8_t prescalarbits = 0b001;
+ long toggle_count = 0;
+ uint32_t ocr = 0;
+ int8_t _timer;
+
+ _timer = toneBegin(_pin);
+
+ if (_timer >= 0)
+ {
+ // Set the pinMode as OUTPUT
+ pinMode(_pin, OUTPUT);
+
+ // if we are using an 8 bit timer, scan through prescalars to find the best fit
+ if (_timer == 0 || _timer == 2)
+ {
+ ocr = F_CPU / frequency / 2 - 1;
+ prescalarbits = 0b001; // ck/1: same for both timers
+ if (ocr > 255)
+ {
+ ocr = F_CPU / frequency / 2 / 8 - 1;
+ prescalarbits = 0b010; // ck/8: same for both timers
+
+ if (_timer == 2 && ocr > 255)
+ {
+ ocr = F_CPU / frequency / 2 / 32 - 1;
+ prescalarbits = 0b011;
+ }
+
+ if (ocr > 255)
+ {
+ ocr = F_CPU / frequency / 2 / 64 - 1;
+ prescalarbits = _timer == 0 ? 0b011 : 0b100;
+
+ if (_timer == 2 && ocr > 255)
+ {
+ ocr = F_CPU / frequency / 2 / 128 - 1;
+ prescalarbits = 0b101;
+ }
+
+ if (ocr > 255)
+ {
+ ocr = F_CPU / frequency / 2 / 256 - 1;
+ prescalarbits = _timer == 0 ? 0b100 : 0b110;
+ if (ocr > 255)
+ {
+ // can't do any better than /1024
+ ocr = F_CPU / frequency / 2 / 1024 - 1;
+ prescalarbits = _timer == 0 ? 0b101 : 0b111;
+ }
+ }
+ }
+ }
+
+#if defined(TCCR0B)
+ if (_timer == 0)
+ {
+ TCCR0B = (TCCR0B & 0b11111000) | prescalarbits;
+ }
+ else
+#endif
+#if defined(TCCR2B)
+ {
+ TCCR2B = (TCCR2B & 0b11111000) | prescalarbits;
+ }
+#else
+ {
+ // dummy place holder to make the above ifdefs work
+ }
+#endif
+ }
+ else
+ {
+ // two choices for the 16 bit timers: ck/1 or ck/64
+ ocr = F_CPU / frequency / 2 - 1;
+
+ prescalarbits = 0b001;
+ if (ocr > 0xffff)
+ {
+ ocr = F_CPU / frequency / 2 / 64 - 1;
+ prescalarbits = 0b011;
+ }
+
+ if (_timer == 1)
+ {
+#if defined(TCCR1B)
+ TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
+#endif
+ }
+#if defined(TCCR3B)
+ else if (_timer == 3)
+ TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;
+#endif
+#if defined(TCCR4B)
+ else if (_timer == 4)
+ TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
+#endif
+#if defined(TCCR5B)
+ else if (_timer == 5)
+ TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;
+#endif
+
+ }
+
+
+ // Calculate the toggle count
+ if (duration > 0)
+ {
+ toggle_count = 2 * frequency * duration / 1000;
+ }
+ else
+ {
+ toggle_count = -1;
+ }
+
+ // Set the OCR for the given timer,
+ // set the toggle count,
+ // then turn on the interrupts
+ switch (_timer)
+ {
+
+#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A)
+ case 0:
+ OCR0A = ocr;
+ timer0_toggle_count = toggle_count;
+ bitWrite(TIMSK0, OCIE0A, 1);
+ break;
+#endif
+
+ case 1:
+#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
+ OCR1A = ocr;
+ timer1_toggle_count = toggle_count;
+ bitWrite(TIMSK1, OCIE1A, 1);
+#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
+ // this combination is for at least the ATmega32
+ OCR1A = ocr;
+ timer1_toggle_count = toggle_count;
+ bitWrite(TIMSK, OCIE1A, 1);
+#endif
+ break;
+
+#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
+ case 2:
+ OCR2A = ocr;
+ timer2_toggle_count = toggle_count;
+ bitWrite(TIMSK2, OCIE2A, 1);
+ break;
+#endif
+
+#if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A)
+ case 3:
+ OCR3A = ocr;
+ timer3_toggle_count = toggle_count;
+ bitWrite(TIMSK3, OCIE3A, 1);
+ break;
+#endif
+
+#if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A)
+ case 4:
+ OCR4A = ocr;
+ timer4_toggle_count = toggle_count;
+ bitWrite(TIMSK4, OCIE4A, 1);
+ break;
+#endif
+
+#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
+ case 5:
+ OCR5A = ocr;
+ timer5_toggle_count = toggle_count;
+ bitWrite(TIMSK5, OCIE5A, 1);
+ break;
+#endif
+
+ }
+ }
+}
+
+
+// XXX: this function only works properly for timer 2 (the only one we use
+// currently). for the others, it should end the tone, but won't restore
+// proper PWM functionality for the timer.
+void disableTimer(uint8_t _timer)
+{
+ switch (_timer)
+ {
+ case 0:
+ #if defined(TIMSK0)
+ TIMSK0 = 0;
+ #elif defined(TIMSK)
+ TIMSK = 0; // atmega32
+ #endif
+ break;
+
+#if defined(TIMSK1) && defined(OCIE1A)
+ case 1:
+ bitWrite(TIMSK1, OCIE1A, 0);
+ break;
+#endif
+
+ case 2:
+ #if defined(TIMSK2) && defined(OCIE2A)
+ bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt
+ #endif
+ #if defined(TCCR2A) && defined(WGM20)
+ TCCR2A = (1 << WGM20);
+ #endif
+ #if defined(TCCR2B) && defined(CS22)
+ TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22);
+ #endif
+ #if defined(OCR2A)
+ OCR2A = 0;
+ #endif
+ break;
+
+#if defined(TIMSK3) && defined(OCIE3A)
+ case 3:
+ bitWrite(TIMSK3, OCIE3A, 0);
+ break;
+#endif
+
+#if defined(TIMSK4) && defined(OCIE4A)
+ case 4:
+ bitWrite(TIMSK4, OCIE4A, 0);
+ break;
+#endif
+
+#if defined(TIMSK5) && defined(OCIE5A)
+ case 5:
+ bitWrite(TIMSK5, OCIE5A, 0);
+ break;
+#endif
+ }
+}
+
+
+void noTone(uint8_t _pin)
+{
+ int8_t _timer = -1;
+
+ for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
+ if (tone_pins[i] == _pin) {
+ _timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
+ tone_pins[i] = 255;
+ break;
+ }
+ }
+
+ disableTimer(_timer);
+
+ digitalWrite(_pin, 0);
+}
+
+#ifdef USE_TIMER0
+ISR(TIMER0_COMPA_vect)
+{
+ if (timer0_toggle_count != 0)
+ {
+ // toggle the pin
+ *timer0_pin_port ^= timer0_pin_mask;
+
+ if (timer0_toggle_count > 0)
+ timer0_toggle_count--;
+ }
+ else
+ {
+ disableTimer(0);
+ *timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop
+ }
+}
+#endif
+
+
+#ifdef USE_TIMER1
+ISR(TIMER1_COMPA_vect)
+{
+ if (timer1_toggle_count != 0)
+ {
+ // toggle the pin
+ *timer1_pin_port ^= timer1_pin_mask;
+
+ if (timer1_toggle_count > 0)
+ timer1_toggle_count--;
+ }
+ else
+ {
+ disableTimer(1);
+ *timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop
+ }
+}
+#endif
+
+
+#ifdef USE_TIMER2
+ISR(TIMER2_COMPA_vect)
+{
+
+ if (timer2_toggle_count != 0)
+ {
+ // toggle the pin
+ *timer2_pin_port ^= timer2_pin_mask;
+
+ if (timer2_toggle_count > 0)
+ timer2_toggle_count--;
+ }
+ else
+ {
+ // need to call noTone() so that the tone_pins[] entry is reset, so the
+ // timer gets initialized next time we call tone().
+ // XXX: this assumes timer 2 is always the first one used.
+ noTone(tone_pins[0]);
+// disableTimer(2);
+// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop
+ }
+}
+#endif
+
+
+#ifdef USE_TIMER3
+ISR(TIMER3_COMPA_vect)
+{
+ if (timer3_toggle_count != 0)
+ {
+ // toggle the pin
+ *timer3_pin_port ^= timer3_pin_mask;
+
+ if (timer3_toggle_count > 0)
+ timer3_toggle_count--;
+ }
+ else
+ {
+ disableTimer(3);
+ *timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop
+ }
+}
+#endif
+
+
+#ifdef USE_TIMER4
+ISR(TIMER4_COMPA_vect)
+{
+ if (timer4_toggle_count != 0)
+ {
+ // toggle the pin
+ *timer4_pin_port ^= timer4_pin_mask;
+
+ if (timer4_toggle_count > 0)
+ timer4_toggle_count--;
+ }
+ else
+ {
+ disableTimer(4);
+ *timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop
+ }
+}
+#endif
+
+
+#ifdef USE_TIMER5
+ISR(TIMER5_COMPA_vect)
+{
+ if (timer5_toggle_count != 0)
+ {
+ // toggle the pin
+ *timer5_pin_port ^= timer5_pin_mask;
+
+ if (timer5_toggle_count > 0)
+ timer5_toggle_count--;
+ }
+ else
+ {
+ disableTimer(5);
+ *timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop
+ }
+}
+#endif
diff --git a/Minnow/USBAPI.h b/Minnow/USBAPI.h
new file mode 100644
index 0000000..4072772
--- /dev/null
+++ b/Minnow/USBAPI.h
@@ -0,0 +1,206 @@
+/*
+ USBAPI.h
+ Copyright (c) 2005-2014 Arduino. All right reserved.
+
+ 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
+*/
+
+#ifndef __USBAPI__
+#define __USBAPI__
+
+#include
+#include
+#include
+#include
+#include
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+#include "Arduino.h"
+
+// This definitions is usefull if you want to reduce the EP_SIZE to 16
+// at the moment only 64 and 16 as EP_SIZE for all EPs are supported except the control endpoint
+#ifndef USB_EP_SIZE
+#define USB_EP_SIZE 64
+#endif
+
+#if defined(USBCON)
+
+#include "USBDesc.h"
+#include "USBCore.h"
+
+//================================================================================
+//================================================================================
+// USB
+
+#define EP_TYPE_CONTROL (0x00)
+#define EP_TYPE_BULK_IN ((1<256)
+#error Please lower the CDC Buffer size
+#endif
+
+class Serial_ : public Stream
+{
+private:
+ int peek_buffer;
+public:
+ Serial_() { peek_buffer = -1; };
+ void begin(unsigned long);
+ void begin(unsigned long, uint8_t);
+ void end(void);
+
+ virtual int available(void);
+ virtual int peek(void);
+ virtual int read(void);
+ int availableForWrite(void);
+ virtual void flush(void);
+ virtual size_t write(uint8_t);
+ virtual size_t write(const uint8_t*, size_t);
+ using Print::write; // pull in write(str) and write(buf, size) from Print
+ operator bool();
+
+ volatile uint8_t _rx_buffer_head;
+ volatile uint8_t _rx_buffer_tail;
+ unsigned char _rx_buffer[SERIAL_BUFFER_SIZE];
+
+ // This method allows processing "SEND_BREAK" requests sent by
+ // the USB host. Those requests indicate that the host wants to
+ // send a BREAK signal and are accompanied by a single uint16_t
+ // value, specifying the duration of the break. The value 0
+ // means to end any current break, while the value 0xffff means
+ // to start an indefinite break.
+ // readBreak() will return the value of the most recent break
+ // request, but will return it at most once, returning -1 when
+ // readBreak() is called again (until another break request is
+ // received, which is again returned once).
+ // This also mean that if two break requests are received
+ // without readBreak() being called in between, the value of the
+ // first request is lost.
+ // Note that the value returned is a long, so it can return
+ // 0-0xffff as well as -1.
+ int32_t readBreak();
+
+ // These return the settings specified by the USB host for the
+ // serial port. These aren't really used, but are offered here
+ // in case a sketch wants to act on these settings.
+ uint32_t baud();
+ uint8_t stopbits();
+ uint8_t paritytype();
+ uint8_t numbits();
+ bool dtr();
+ bool rts();
+ enum {
+ ONE_STOP_BIT = 0,
+ ONE_AND_HALF_STOP_BIT = 1,
+ TWO_STOP_BITS = 2,
+ };
+ enum {
+ NO_PARITY = 0,
+ ODD_PARITY = 1,
+ EVEN_PARITY = 2,
+ MARK_PARITY = 3,
+ SPACE_PARITY = 4,
+ };
+
+};
+extern Serial_ Serial;
+
+#define HAVE_CDCSERIAL
+
+//================================================================================
+//================================================================================
+// Low level API
+
+typedef struct
+{
+ uint8_t bmRequestType;
+ uint8_t bRequest;
+ uint8_t wValueL;
+ uint8_t wValueH;
+ uint16_t wIndex;
+ uint16_t wLength;
+} USBSetup;
+
+//================================================================================
+//================================================================================
+// MSC 'Driver'
+
+int MSC_GetInterface(uint8_t* interfaceNum);
+int MSC_GetDescriptor(int i);
+bool MSC_Setup(USBSetup& setup);
+bool MSC_Data(uint8_t rx,uint8_t tx);
+
+//================================================================================
+//================================================================================
+// CSC 'Driver'
+
+int CDC_GetInterface(uint8_t* interfaceNum);
+int CDC_GetDescriptor(int i);
+bool CDC_Setup(USBSetup& setup);
+
+//================================================================================
+//================================================================================
+
+#define TRANSFER_PGM 0x80
+#define TRANSFER_RELEASE 0x40
+#define TRANSFER_ZERO 0x20
+
+int USB_SendControl(uint8_t flags, const void* d, int len);
+int USB_RecvControl(void* d, int len);
+
+uint8_t USB_Available(uint8_t ep);
+uint8_t USB_SendSpace(uint8_t ep);
+int USB_Send(uint8_t ep, const void* data, int len); // blocking
+int USB_Recv(uint8_t ep, void* data, int len); // non-blocking
+int USB_Recv(uint8_t ep); // non-blocking
+void USB_Flush(uint8_t ep);
+
+#endif
+
+#endif /* if defined(USBCON) */
diff --git a/Minnow/WCharacter.h b/Minnow/WCharacter.h
new file mode 100644
index 0000000..79733b5
--- /dev/null
+++ b/Minnow/WCharacter.h
@@ -0,0 +1,168 @@
+/*
+ WCharacter.h - Character utility functions for Wiring & Arduino
+ Copyright (c) 2010 Hernando Barragan. All right reserved.
+
+ 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
+ */
+
+#ifndef Character_h
+#define Character_h
+
+#include
+
+// WCharacter.h prototypes
+inline boolean isAlphaNumeric(int c) __attribute__((always_inline));
+inline boolean isAlpha(int c) __attribute__((always_inline));
+inline boolean isAscii(int c) __attribute__((always_inline));
+inline boolean isWhitespace(int c) __attribute__((always_inline));
+inline boolean isControl(int c) __attribute__((always_inline));
+inline boolean isDigit(int c) __attribute__((always_inline));
+inline boolean isGraph(int c) __attribute__((always_inline));
+inline boolean isLowerCase(int c) __attribute__((always_inline));
+inline boolean isPrintable(int c) __attribute__((always_inline));
+inline boolean isPunct(int c) __attribute__((always_inline));
+inline boolean isSpace(int c) __attribute__((always_inline));
+inline boolean isUpperCase(int c) __attribute__((always_inline));
+inline boolean isHexadecimalDigit(int c) __attribute__((always_inline));
+inline int toAscii(int c) __attribute__((always_inline));
+inline int toLowerCase(int c) __attribute__((always_inline));
+inline int toUpperCase(int c)__attribute__((always_inline));
+
+
+// Checks for an alphanumeric character.
+// It is equivalent to (isalpha(c) || isdigit(c)).
+inline boolean isAlphaNumeric(int c)
+{
+ return ( isalnum(c) == 0 ? false : true);
+}
+
+
+// Checks for an alphabetic character.
+// It is equivalent to (isupper(c) || islower(c)).
+inline boolean isAlpha(int c)
+{
+ return ( isalpha(c) == 0 ? false : true);
+}
+
+
+// Checks whether c is a 7-bit unsigned char value
+// that fits into the ASCII character set.
+inline boolean isAscii(int c)
+{
+ return ( isascii (c) == 0 ? false : true);
+}
+
+
+// Checks for a blank character, that is, a space or a tab.
+inline boolean isWhitespace(int c)
+{
+ return ( isblank (c) == 0 ? false : true);
+}
+
+
+// Checks for a control character.
+inline boolean isControl(int c)
+{
+ return ( iscntrl (c) == 0 ? false : true);
+}
+
+
+// Checks for a digit (0 through 9).
+inline boolean isDigit(int c)
+{
+ return ( isdigit (c) == 0 ? false : true);
+}
+
+
+// Checks for any printable character except space.
+inline boolean isGraph(int c)
+{
+ return ( isgraph (c) == 0 ? false : true);
+}
+
+
+// Checks for a lower-case character.
+inline boolean isLowerCase(int c)
+{
+ return (islower (c) == 0 ? false : true);
+}
+
+
+// Checks for any printable character including space.
+inline boolean isPrintable(int c)
+{
+ return ( isprint (c) == 0 ? false : true);
+}
+
+
+// Checks for any printable character which is not a space
+// or an alphanumeric character.
+inline boolean isPunct(int c)
+{
+ return ( ispunct (c) == 0 ? false : true);
+}
+
+
+// Checks for white-space characters. For the avr-libc library,
+// these are: space, formfeed ('\f'), newline ('\n'), carriage
+// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
+inline boolean isSpace(int c)
+{
+ return ( isspace (c) == 0 ? false : true);
+}
+
+
+// Checks for an uppercase letter.
+inline boolean isUpperCase(int c)
+{
+ return ( isupper (c) == 0 ? false : true);
+}
+
+
+// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
+// 8 9 a b c d e f A B C D E F.
+inline boolean isHexadecimalDigit(int c)
+{
+ return ( isxdigit (c) == 0 ? false : true);
+}
+
+
+// Converts c to a 7-bit unsigned char value that fits into the
+// ASCII character set, by clearing the high-order bits.
+inline int toAscii(int c)
+{
+ return toascii (c);
+}
+
+
+// Warning:
+// Many people will be unhappy if you use this function.
+// This function will convert accented letters into random
+// characters.
+
+// Converts the letter c to lower case, if possible.
+inline int toLowerCase(int c)
+{
+ return tolower (c);
+}
+
+
+// Converts the letter c to upper case, if possible.
+inline int toUpperCase(int c)
+{
+ return toupper (c);
+}
+
+#endif
\ No newline at end of file
diff --git a/Minnow/WString.cpp b/Minnow/WString.cpp
new file mode 100644
index 0000000..cd3e0e8
--- /dev/null
+++ b/Minnow/WString.cpp
@@ -0,0 +1,745 @@
+/*
+ WString.cpp - String library for Wiring & Arduino
+ ...mostly rewritten by Paul Stoffregen...
+ Copyright (c) 2009-10 Hernando Barragan. All rights reserved.
+ Copyright 2011, Paul Stoffregen, paul@pjrc.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
+*/
+
+#include "WString.h"
+
+/*********************************************/
+/* Constructors */
+/*********************************************/
+
+String::String(const char *cstr)
+{
+ init();
+ if (cstr) copy(cstr, strlen(cstr));
+}
+
+String::String(const String &value)
+{
+ init();
+ *this = value;
+}
+
+String::String(const __FlashStringHelper *pstr)
+{
+ init();
+ *this = pstr;
+}
+
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+String::String(String &&rval)
+{
+ init();
+ move(rval);
+}
+String::String(StringSumHelper &&rval)
+{
+ init();
+ move(rval);
+}
+#endif
+
+String::String(char c)
+{
+ init();
+ char buf[2];
+ buf[0] = c;
+ buf[1] = 0;
+ *this = buf;
+}
+
+String::String(unsigned char value, unsigned char base)
+{
+ init();
+ char buf[1 + 8 * sizeof(unsigned char)];
+ utoa(value, buf, base);
+ *this = buf;
+}
+
+String::String(int value, unsigned char base)
+{
+ init();
+ char buf[2 + 8 * sizeof(int)];
+ itoa(value, buf, base);
+ *this = buf;
+}
+
+String::String(unsigned int value, unsigned char base)
+{
+ init();
+ char buf[1 + 8 * sizeof(unsigned int)];
+ utoa(value, buf, base);
+ *this = buf;
+}
+
+String::String(long value, unsigned char base)
+{
+ init();
+ char buf[2 + 8 * sizeof(long)];
+ ltoa(value, buf, base);
+ *this = buf;
+}
+
+String::String(unsigned long value, unsigned char base)
+{
+ init();
+ char buf[1 + 8 * sizeof(unsigned long)];
+ ultoa(value, buf, base);
+ *this = buf;
+}
+
+String::String(float value, unsigned char decimalPlaces)
+{
+ init();
+ char buf[33];
+ *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
+}
+
+String::String(double value, unsigned char decimalPlaces)
+{
+ init();
+ char buf[33];
+ *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
+}
+
+String::~String()
+{
+ free(buffer);
+}
+
+/*********************************************/
+/* Memory Management */
+/*********************************************/
+
+inline void String::init(void)
+{
+ buffer = NULL;
+ capacity = 0;
+ len = 0;
+}
+
+void String::invalidate(void)
+{
+ if (buffer) free(buffer);
+ buffer = NULL;
+ capacity = len = 0;
+}
+
+unsigned char String::reserve(unsigned int size)
+{
+ if (buffer && capacity >= size) return 1;
+ if (changeBuffer(size)) {
+ if (len == 0) buffer[0] = 0;
+ return 1;
+ }
+ return 0;
+}
+
+unsigned char String::changeBuffer(unsigned int maxStrLen)
+{
+ char *newbuffer = (char *)realloc(buffer, maxStrLen + 1);
+ if (newbuffer) {
+ buffer = newbuffer;
+ capacity = maxStrLen;
+ return 1;
+ }
+ return 0;
+}
+
+/*********************************************/
+/* Copy and Move */
+/*********************************************/
+
+String & String::copy(const char *cstr, unsigned int length)
+{
+ if (!reserve(length)) {
+ invalidate();
+ return *this;
+ }
+ len = length;
+ strcpy(buffer, cstr);
+ return *this;
+}
+
+String & String::copy(const __FlashStringHelper *pstr, unsigned int length)
+{
+ if (!reserve(length)) {
+ invalidate();
+ return *this;
+ }
+ len = length;
+ strcpy_P(buffer, (PGM_P)pstr);
+ return *this;
+}
+
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+void String::move(String &rhs)
+{
+ if (buffer) {
+ if (capacity >= rhs.len) {
+ strcpy(buffer, rhs.buffer);
+ len = rhs.len;
+ rhs.len = 0;
+ return;
+ } else {
+ free(buffer);
+ }
+ }
+ buffer = rhs.buffer;
+ capacity = rhs.capacity;
+ len = rhs.len;
+ rhs.buffer = NULL;
+ rhs.capacity = 0;
+ rhs.len = 0;
+}
+#endif
+
+String & String::operator = (const String &rhs)
+{
+ if (this == &rhs) return *this;
+
+ if (rhs.buffer) copy(rhs.buffer, rhs.len);
+ else invalidate();
+
+ return *this;
+}
+
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+String & String::operator = (String &&rval)
+{
+ if (this != &rval) move(rval);
+ return *this;
+}
+
+String & String::operator = (StringSumHelper &&rval)
+{
+ if (this != &rval) move(rval);
+ return *this;
+}
+#endif
+
+String & String::operator = (const char *cstr)
+{
+ if (cstr) copy(cstr, strlen(cstr));
+ else invalidate();
+
+ return *this;
+}
+
+String & String::operator = (const __FlashStringHelper *pstr)
+{
+ if (pstr) copy(pstr, strlen_P((PGM_P)pstr));
+ else invalidate();
+
+ return *this;
+}
+
+/*********************************************/
+/* concat */
+/*********************************************/
+
+unsigned char String::concat(const String &s)
+{
+ return concat(s.buffer, s.len);
+}
+
+unsigned char String::concat(const char *cstr, unsigned int length)
+{
+ unsigned int newlen = len + length;
+ if (!cstr) return 0;
+ if (length == 0) return 1;
+ if (!reserve(newlen)) return 0;
+ strcpy(buffer + len, cstr);
+ len = newlen;
+ return 1;
+}
+
+unsigned char String::concat(const char *cstr)
+{
+ if (!cstr) return 0;
+ return concat(cstr, strlen(cstr));
+}
+
+unsigned char String::concat(char c)
+{
+ char buf[2];
+ buf[0] = c;
+ buf[1] = 0;
+ return concat(buf, 1);
+}
+
+unsigned char String::concat(unsigned char num)
+{
+ char buf[1 + 3 * sizeof(unsigned char)];
+ itoa(num, buf, 10);
+ return concat(buf, strlen(buf));
+}
+
+unsigned char String::concat(int num)
+{
+ char buf[2 + 3 * sizeof(int)];
+ itoa(num, buf, 10);
+ return concat(buf, strlen(buf));
+}
+
+unsigned char String::concat(unsigned int num)
+{
+ char buf[1 + 3 * sizeof(unsigned int)];
+ utoa(num, buf, 10);
+ return concat(buf, strlen(buf));
+}
+
+unsigned char String::concat(long num)
+{
+ char buf[2 + 3 * sizeof(long)];
+ ltoa(num, buf, 10);
+ return concat(buf, strlen(buf));
+}
+
+unsigned char String::concat(unsigned long num)
+{
+ char buf[1 + 3 * sizeof(unsigned long)];
+ ultoa(num, buf, 10);
+ return concat(buf, strlen(buf));
+}
+
+unsigned char String::concat(float num)
+{
+ char buf[20];
+ char* string = dtostrf(num, 4, 2, buf);
+ return concat(string, strlen(string));
+}
+
+unsigned char String::concat(double num)
+{
+ char buf[20];
+ char* string = dtostrf(num, 4, 2, buf);
+ return concat(string, strlen(string));
+}
+
+unsigned char String::concat(const __FlashStringHelper * str)
+{
+ if (!str) return 0;
+ int length = strlen_P((const char *) str);
+ if (length == 0) return 1;
+ unsigned int newlen = len + length;
+ if (!reserve(newlen)) return 0;
+ strcpy_P(buffer + len, (const char *) str);
+ len = newlen;
+ return 1;
+}
+
+/*********************************************/
+/* Concatenate */
+/*********************************************/
+
+StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!a.concat(rhs.buffer, rhs.len)) a.invalidate();
+ return a;
+}
+
+StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate();
+ return a;
+}
+
+StringSumHelper & operator + (const StringSumHelper &lhs, char c)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!a.concat(c)) a.invalidate();
+ return a;
+}
+
+StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!a.concat(num)) a.invalidate();
+ return a;
+}
+
+StringSumHelper & operator + (const StringSumHelper &lhs, int num)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!a.concat(num)) a.invalidate();
+ return a;
+}
+
+StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!a.concat(num)) a.invalidate();
+ return a;
+}
+
+StringSumHelper & operator + (const StringSumHelper &lhs, long num)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!a.concat(num)) a.invalidate();
+ return a;
+}
+
+StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!a.concat(num)) a.invalidate();
+ return a;
+}
+
+StringSumHelper & operator + (const StringSumHelper &lhs, float num)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!a.concat(num)) a.invalidate();
+ return a;
+}
+
+StringSumHelper & operator + (const StringSumHelper &lhs, double num)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!a.concat(num)) a.invalidate();
+ return a;
+}
+
+StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)
+{
+ StringSumHelper &a = const_cast(lhs);
+ if (!a.concat(rhs)) a.invalidate();
+ return a;
+}
+
+/*********************************************/
+/* Comparison */
+/*********************************************/
+
+int String::compareTo(const String &s) const
+{
+ if (!buffer || !s.buffer) {
+ if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer;
+ if (buffer && len > 0) return *(unsigned char *)buffer;
+ return 0;
+ }
+ return strcmp(buffer, s.buffer);
+}
+
+unsigned char String::equals(const String &s2) const
+{
+ return (len == s2.len && compareTo(s2) == 0);
+}
+
+unsigned char String::equals(const char *cstr) const
+{
+ if (len == 0) return (cstr == NULL || *cstr == 0);
+ if (cstr == NULL) return buffer[0] == 0;
+ return strcmp(buffer, cstr) == 0;
+}
+
+unsigned char String::operator<(const String &rhs) const
+{
+ return compareTo(rhs) < 0;
+}
+
+unsigned char String::operator>(const String &rhs) const
+{
+ return compareTo(rhs) > 0;
+}
+
+unsigned char String::operator<=(const String &rhs) const
+{
+ return compareTo(rhs) <= 0;
+}
+
+unsigned char String::operator>=(const String &rhs) const
+{
+ return compareTo(rhs) >= 0;
+}
+
+unsigned char String::equalsIgnoreCase( const String &s2 ) const
+{
+ if (this == &s2) return 1;
+ if (len != s2.len) return 0;
+ if (len == 0) return 1;
+ const char *p1 = buffer;
+ const char *p2 = s2.buffer;
+ while (*p1) {
+ if (tolower(*p1++) != tolower(*p2++)) return 0;
+ }
+ return 1;
+}
+
+unsigned char String::startsWith( const String &s2 ) const
+{
+ if (len < s2.len) return 0;
+ return startsWith(s2, 0);
+}
+
+unsigned char String::startsWith( const String &s2, unsigned int offset ) const
+{
+ if (offset > len - s2.len || !buffer || !s2.buffer) return 0;
+ return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0;
+}
+
+unsigned char String::endsWith( const String &s2 ) const
+{
+ if ( len < s2.len || !buffer || !s2.buffer) return 0;
+ return strcmp(&buffer[len - s2.len], s2.buffer) == 0;
+}
+
+/*********************************************/
+/* Character Access */
+/*********************************************/
+
+char String::charAt(unsigned int loc) const
+{
+ return operator[](loc);
+}
+
+void String::setCharAt(unsigned int loc, char c)
+{
+ if (loc < len) buffer[loc] = c;
+}
+
+char & String::operator[](unsigned int index)
+{
+ static char dummy_writable_char;
+ if (index >= len || !buffer) {
+ dummy_writable_char = 0;
+ return dummy_writable_char;
+ }
+ return buffer[index];
+}
+
+char String::operator[]( unsigned int index ) const
+{
+ if (index >= len || !buffer) return 0;
+ return buffer[index];
+}
+
+void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const
+{
+ if (!bufsize || !buf) return;
+ if (index >= len) {
+ buf[0] = 0;
+ return;
+ }
+ unsigned int n = bufsize - 1;
+ if (n > len - index) n = len - index;
+ strncpy((char *)buf, buffer + index, n);
+ buf[n] = 0;
+}
+
+/*********************************************/
+/* Search */
+/*********************************************/
+
+int String::indexOf(char c) const
+{
+ return indexOf(c, 0);
+}
+
+int String::indexOf( char ch, unsigned int fromIndex ) const
+{
+ if (fromIndex >= len) return -1;
+ const char* temp = strchr(buffer + fromIndex, ch);
+ if (temp == NULL) return -1;
+ return temp - buffer;
+}
+
+int String::indexOf(const String &s2) const
+{
+ return indexOf(s2, 0);
+}
+
+int String::indexOf(const String &s2, unsigned int fromIndex) const
+{
+ if (fromIndex >= len) return -1;
+ const char *found = strstr(buffer + fromIndex, s2.buffer);
+ if (found == NULL) return -1;
+ return found - buffer;
+}
+
+int String::lastIndexOf( char theChar ) const
+{
+ return lastIndexOf(theChar, len - 1);
+}
+
+int String::lastIndexOf(char ch, unsigned int fromIndex) const
+{
+ if (fromIndex >= len) return -1;
+ char tempchar = buffer[fromIndex + 1];
+ buffer[fromIndex + 1] = '\0';
+ char* temp = strrchr( buffer, ch );
+ buffer[fromIndex + 1] = tempchar;
+ if (temp == NULL) return -1;
+ return temp - buffer;
+}
+
+int String::lastIndexOf(const String &s2) const
+{
+ return lastIndexOf(s2, len - s2.len);
+}
+
+int String::lastIndexOf(const String &s2, unsigned int fromIndex) const
+{
+ if (s2.len == 0 || len == 0 || s2.len > len) return -1;
+ if (fromIndex >= len) fromIndex = len - 1;
+ int found = -1;
+ for (char *p = buffer; p <= buffer + fromIndex; p++) {
+ p = strstr(p, s2.buffer);
+ if (!p) break;
+ if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer;
+ }
+ return found;
+}
+
+String String::substring(unsigned int left, unsigned int right) const
+{
+ if (left > right) {
+ unsigned int temp = right;
+ right = left;
+ left = temp;
+ }
+ String out;
+ if (left >= len) return out;
+ if (right > len) right = len;
+ char temp = buffer[right]; // save the replaced character
+ buffer[right] = '\0';
+ out = buffer + left; // pointer arithmetic
+ buffer[right] = temp; //restore character
+ return out;
+}
+
+/*********************************************/
+/* Modification */
+/*********************************************/
+
+void String::replace(char find, char replace)
+{
+ if (!buffer) return;
+ for (char *p = buffer; *p; p++) {
+ if (*p == find) *p = replace;
+ }
+}
+
+void String::replace(const String& find, const String& replace)
+{
+ if (len == 0 || find.len == 0) return;
+ int diff = replace.len - find.len;
+ char *readFrom = buffer;
+ char *foundAt;
+ if (diff == 0) {
+ while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
+ memcpy(foundAt, replace.buffer, replace.len);
+ readFrom = foundAt + replace.len;
+ }
+ } else if (diff < 0) {
+ char *writeTo = buffer;
+ while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
+ unsigned int n = foundAt - readFrom;
+ memcpy(writeTo, readFrom, n);
+ writeTo += n;
+ memcpy(writeTo, replace.buffer, replace.len);
+ writeTo += replace.len;
+ readFrom = foundAt + find.len;
+ len += diff;
+ }
+ strcpy(writeTo, readFrom);
+ } else {
+ unsigned int size = len; // compute size needed for result
+ while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
+ readFrom = foundAt + find.len;
+ size += diff;
+ }
+ if (size == len) return;
+ if (size > capacity && !changeBuffer(size)) return; // XXX: tell user!
+ int index = len - 1;
+ while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
+ readFrom = buffer + index + find.len;
+ memmove(readFrom + diff, readFrom, len - (readFrom - buffer));
+ len += diff;
+ buffer[len] = 0;
+ memcpy(buffer + index, replace.buffer, replace.len);
+ index--;
+ }
+ }
+}
+
+void String::remove(unsigned int index){
+ // Pass the biggest integer as the count. The remove method
+ // below will take care of truncating it at the end of the
+ // string.
+ remove(index, (unsigned int)-1);
+}
+
+void String::remove(unsigned int index, unsigned int count){
+ if (index >= len) { return; }
+ if (count <= 0) { return; }
+ if (count > len - index) { count = len - index; }
+ char *writeTo = buffer + index;
+ len = len - count;
+ strncpy(writeTo, buffer + index + count,len - index);
+ buffer[len] = 0;
+}
+
+void String::toLowerCase(void)
+{
+ if (!buffer) return;
+ for (char *p = buffer; *p; p++) {
+ *p = tolower(*p);
+ }
+}
+
+void String::toUpperCase(void)
+{
+ if (!buffer) return;
+ for (char *p = buffer; *p; p++) {
+ *p = toupper(*p);
+ }
+}
+
+void String::trim(void)
+{
+ if (!buffer || len == 0) return;
+ char *begin = buffer;
+ while (isspace(*begin)) begin++;
+ char *end = buffer + len - 1;
+ while (isspace(*end) && end >= begin) end--;
+ len = end + 1 - begin;
+ if (begin > buffer) memcpy(buffer, begin, len);
+ buffer[len] = 0;
+}
+
+/*********************************************/
+/* Parsing / Conversion */
+/*********************************************/
+
+long String::toInt(void) const
+{
+ if (buffer) return atol(buffer);
+ return 0;
+}
+
+float String::toFloat(void) const
+{
+ if (buffer) return float(atof(buffer));
+ return 0;
+}
diff --git a/Minnow/WString.h b/Minnow/WString.h
new file mode 100644
index 0000000..b047980
--- /dev/null
+++ b/Minnow/WString.h
@@ -0,0 +1,224 @@
+/*
+ WString.h - String library for Wiring & Arduino
+ ...mostly rewritten by Paul Stoffregen...
+ Copyright (c) 2009-10 Hernando Barragan. All right reserved.
+ Copyright 2011, Paul Stoffregen, paul@pjrc.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
+*/
+
+#ifndef String_class_h
+#define String_class_h
+#ifdef __cplusplus
+
+#include
+#include
+#include
+#include
+
+// When compiling programs with this class, the following gcc parameters
+// dramatically increase performance and memory (RAM) efficiency, typically
+// with little or no increase in code size.
+// -felide-constructors
+// -std=c++0x
+
+class __FlashStringHelper;
+#define F(string_literal) (reinterpret_cast(PSTR(string_literal)))
+
+// An inherited class for holding the result of a concatenation. These
+// result objects are assumed to be writable by subsequent concatenations.
+class StringSumHelper;
+
+// The string class
+class String
+{
+ // use a function pointer to allow for "if (s)" without the
+ // complications of an operator bool(). for more information, see:
+ // http://www.artima.com/cppsource/safebool.html
+ typedef void (String::*StringIfHelperType)() const;
+ void StringIfHelper() const {}
+
+public:
+ // constructors
+ // creates a copy of the initial value.
+ // if the initial value is null or invalid, or if memory allocation
+ // fails, the string will be marked as invalid (i.e. "if (s)" will
+ // be false).
+ String(const char *cstr = "");
+ String(const String &str);
+ String(const __FlashStringHelper *str);
+ #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+ String(String &&rval);
+ String(StringSumHelper &&rval);
+ #endif
+ explicit String(char c);
+ explicit String(unsigned char, unsigned char base=10);
+ explicit String(int, unsigned char base=10);
+ explicit String(unsigned int, unsigned char base=10);
+ explicit String(long, unsigned char base=10);
+ explicit String(unsigned long, unsigned char base=10);
+ explicit String(float, unsigned char decimalPlaces=2);
+ explicit String(double, unsigned char decimalPlaces=2);
+ ~String(void);
+
+ // memory management
+ // return true on success, false on failure (in which case, the string
+ // is left unchanged). reserve(0), if successful, will validate an
+ // invalid string (i.e., "if (s)" will be true afterwards)
+ unsigned char reserve(unsigned int size);
+ inline unsigned int length(void) const {return len;}
+
+ // creates a copy of the assigned value. if the value is null or
+ // invalid, or if the memory allocation fails, the string will be
+ // marked as invalid ("if (s)" will be false).
+ String & operator = (const String &rhs);
+ String & operator = (const char *cstr);
+ String & operator = (const __FlashStringHelper *str);
+ #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+ String & operator = (String &&rval);
+ String & operator = (StringSumHelper &&rval);
+ #endif
+
+ // concatenate (works w/ built-in types)
+
+ // returns true on success, false on failure (in which case, the string
+ // is left unchanged). if the argument is null or invalid, the
+ // concatenation is considered unsucessful.
+ unsigned char concat(const String &str);
+ unsigned char concat(const char *cstr);
+ unsigned char concat(char c);
+ unsigned char concat(unsigned char c);
+ unsigned char concat(int num);
+ unsigned char concat(unsigned int num);
+ unsigned char concat(long num);
+ unsigned char concat(unsigned long num);
+ unsigned char concat(float num);
+ unsigned char concat(double num);
+ unsigned char concat(const __FlashStringHelper * str);
+
+ // if there's not enough memory for the concatenated value, the string
+ // will be left unchanged (but this isn't signalled in any way)
+ String & operator += (const String &rhs) {concat(rhs); return (*this);}
+ String & operator += (const char *cstr) {concat(cstr); return (*this);}
+ String & operator += (char c) {concat(c); return (*this);}
+ String & operator += (unsigned char num) {concat(num); return (*this);}
+ String & operator += (int num) {concat(num); return (*this);}
+ String & operator += (unsigned int num) {concat(num); return (*this);}
+ String & operator += (long num) {concat(num); return (*this);}
+ String & operator += (unsigned long num) {concat(num); return (*this);}
+ String & operator += (float num) {concat(num); return (*this);}
+ String & operator += (double num) {concat(num); return (*this);}
+ String & operator += (const __FlashStringHelper *str){concat(str); return (*this);}
+
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, char c);
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num);
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, int num);
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, long num);
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, float num);
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);
+ friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs);
+
+ // comparison (only works w/ Strings and "strings")
+ operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; }
+ int compareTo(const String &s) const;
+ unsigned char equals(const String &s) const;
+ unsigned char equals(const char *cstr) const;
+ unsigned char operator == (const String &rhs) const {return equals(rhs);}
+ unsigned char operator == (const char *cstr) const {return equals(cstr);}
+ unsigned char operator != (const String &rhs) const {return !equals(rhs);}
+ unsigned char operator != (const char *cstr) const {return !equals(cstr);}
+ unsigned char operator < (const String &rhs) const;
+ unsigned char operator > (const String &rhs) const;
+ unsigned char operator <= (const String &rhs) const;
+ unsigned char operator >= (const String &rhs) const;
+ unsigned char equalsIgnoreCase(const String &s) const;
+ unsigned char startsWith( const String &prefix) const;
+ unsigned char startsWith(const String &prefix, unsigned int offset) const;
+ unsigned char endsWith(const String &suffix) const;
+
+ // character acccess
+ char charAt(unsigned int index) const;
+ void setCharAt(unsigned int index, char c);
+ char operator [] (unsigned int index) const;
+ char& operator [] (unsigned int index);
+ void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const;
+ void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const
+ {getBytes((unsigned char *)buf, bufsize, index);}
+ const char * c_str() const { return buffer; }
+
+ // search
+ int indexOf( char ch ) const;
+ int indexOf( char ch, unsigned int fromIndex ) const;
+ int indexOf( const String &str ) const;
+ int indexOf( const String &str, unsigned int fromIndex ) const;
+ int lastIndexOf( char ch ) const;
+ int lastIndexOf( char ch, unsigned int fromIndex ) const;
+ int lastIndexOf( const String &str ) const;
+ int lastIndexOf( const String &str, unsigned int fromIndex ) const;
+ String substring( unsigned int beginIndex ) const { return substring(beginIndex, len); };
+ String substring( unsigned int beginIndex, unsigned int endIndex ) const;
+
+ // modification
+ void replace(char find, char replace);
+ void replace(const String& find, const String& replace);
+ void remove(unsigned int index);
+ void remove(unsigned int index, unsigned int count);
+ void toLowerCase(void);
+ void toUpperCase(void);
+ void trim(void);
+
+ // parsing/conversion
+ long toInt(void) const;
+ float toFloat(void) const;
+
+protected:
+ char *buffer; // the actual char array
+ unsigned int capacity; // the array length minus one (for the '\0')
+ unsigned int len; // the String length (not counting the '\0')
+protected:
+ void init(void);
+ void invalidate(void);
+ unsigned char changeBuffer(unsigned int maxStrLen);
+ unsigned char concat(const char *cstr, unsigned int length);
+
+ // copy and move
+ String & copy(const char *cstr, unsigned int length);
+ String & copy(const __FlashStringHelper *pstr, unsigned int length);
+ #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+ void move(String &rhs);
+ #endif
+};
+
+class StringSumHelper : public String
+{
+public:
+ StringSumHelper(const String &s) : String(s) {}
+ StringSumHelper(const char *p) : String(p) {}
+ StringSumHelper(char c) : String(c) {}
+ StringSumHelper(unsigned char num) : String(num) {}
+ StringSumHelper(int num) : String(num) {}
+ StringSumHelper(unsigned int num) : String(num) {}
+ StringSumHelper(long num) : String(num) {}
+ StringSumHelper(unsigned long num) : String(num) {}
+ StringSumHelper(float num) : String(num) {}
+ StringSumHelper(double num) : String(num) {}
+};
+
+#endif // __cplusplus
+#endif // String_class_h
diff --git a/Minnow/backup_makefile b/Minnow/backup_makefile
new file mode 100644
index 0000000..aff1497
--- /dev/null
+++ b/Minnow/backup_makefile
@@ -0,0 +1,411 @@
+# WinAVR Sample makefile written by Eric B. Weddington, Jörg Wunsch, et al.
+# Modified (bringing often-changed options to the top) by Elliot Williams
+
+# make all = Make software and program
+# make clean = Clean out built project files.
+# make program = Download the hex file to the device, using avrdude. Please
+# customize the avrdude settings below first!
+
+# Microcontroller Type
+MCU = atmega2560
+# MCU = attiny13
+# MCU = attiny2313
+# MCU = atmega8
+# MCU = attiny45
+
+# Target file name (without extension).
+TARGET = Minnow_main
+
+# Programming hardware: type avrdude -c ?
+# to get a full listing.
+# AVRDUDE_PROGRAMMER = dapa
+# AVRDUDE_PROGRAMMER = usbtiny
+# AVRDUDE_PROGRAMMER = dt006
+AVRDUDE_PROGRAMMER = arduino
+
+AVRDUDE_PORT = /dev/usb # not really needed for usb
+#AVRDUDE_PORT = /dev/parport0 # linux
+# AVRDUDE_PORT = lpt1 # windows
+
+############# Don't need to change below here for most purposes (Elliot)
+
+# Optimization level, can be [0, 1, 2, 3, s]. 0 turns off optimization.
+# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
+OPT = s
+
+# Output format. (can be srec, ihex, binary)
+FORMAT = ihex
+
+# List C source files here. (C dependencies are automatically generated.)
+SRC = $(wildcard ./*.cpp)
+#SRC = Minnow_main.cpp
+#SRC = AxisInfo.cpp
+#SRC += CommandQueue.cpp
+#SRC += ConfigTree.cpp
+#SRC += ConfigTreeNode.cpp
+#SRC += crc8.cpp
+#SRC += debug.cpp
+#SRC += Device_Buzzer.cpp
+#SRC += Device_Heater.cpp
+#SRC += Device_InputSwitch.cpp
+#SRC += Device_OutputSwitch.cpp
+#SRC += Device_PwmOutput.cpp
+#SRC += Device_Stepper.cpp
+#SRC += Device_TemperatureSensor.cpp
+#SRC += enqueue_command.cpp
+#SRC += firmware_configuration.cpp
+#SRC += HwSerial.cpp
+#SRC += initial_pin_state.cpp
+#SRC += language.cpp
+#SRC += movement_ISR.cpp
+#SRC += NVConfigStore.cpp
+#SRC += order_handlers.cpp
+#SRC += order_helpers.cpp
+#SRC += response.cpp
+#SRC += SoftPwmState.cpp
+#SRC += temperature_ISR.cpp
+
+
+# List Assembler source files here.
+# Make them always end in a capital .S. Files ending in a lowercase .s
+# will not be considered source files but generated files (assembler
+# output from the compiler), and will be deleted upon "make clean"!
+# Even though the DOS/Win* filesystem matches both .s and .S the same,
+# it will preserve the spelling of the filenames, and gcc itself does
+# care about how the name is spelled on its command-line.
+ASRC =
+
+
+# List any extra directories to look for include files here.
+# Each directory must be seperated by a space.
+EXTRAINCDIRS =
+
+
+# Optional compiler flags.
+# -g: generate debugging information (for GDB, or for COFF conversion)
+# -O*: optimization level
+# -f...: tuning, see gcc manual and avr-libc documentation
+# -Wall...: warning level
+# -Wa,...: tell GCC to pass this to the assembler.
+# -ahlms: create assembler listing
+CFLAGS = -g -O$(OPT) \
+-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \
+-Wall -Wstrict-prototypes \
+-Wa,-adhlns=$(<:.c=.lst) \
+$(patsubst %,-I%,$(EXTRAINCDIRS))
+
+
+# Set a "language standard" compiler flag.
+# Unremark just one line below to set the language standard to use.
+# gnu99 = C99 + GNU extensions. See GCC manual for more information.
+#CFLAGS += -std=c89
+#CFLAGS += -std=gnu89
+#CFLAGS += -std=c99
+#CFLAGS += -std=gnu99
+CFLAGS += -std=c++03
+
+
+# Optional assembler flags.
+# -Wa,...: tell GCC to pass this to the assembler.
+# -ahlms: create listing
+# -gstabs: have the assembler create line number information; note that
+# for use in COFF files, additional information about filenames
+# and function names needs to be present in the assembler source
+# files -- see avr-libc docs [FIXME: not yet described there]
+ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
+
+
+
+# Optional linker flags.
+# -Wl,...: tell GCC to pass this to linker.
+# -Map: create map file
+# --cref: add cross reference to map file
+LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
+
+
+
+# Additional libraries
+
+# Minimalistic printf version
+#LDFLAGS += -Wl,-u,vfprintf -lprintf_min
+
+# Floating point printf version (requires -lm below)
+#LDFLAGS += -Wl,-u,vfprintf -lprintf_flt
+
+# -lm = math library
+LDFLAGS += -lm
+
+
+# Programming support using avrdude. Settings and variables.
+
+
+AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
+#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
+
+AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
+
+# Uncomment the following if you want avrdude's erase cycle counter.
+# Note that this counter needs to be initialized first using -Yn,
+# see avrdude manual.
+#AVRDUDE_ERASE += -y
+
+# Uncomment the following if you do /not/ wish a verification to be
+# performed after programming the device.
+#AVRDUDE_FLAGS += -V
+
+# Increase verbosity level. Please use this when submitting bug
+# reports about avrdude. See
+# to submit bug reports.
+#AVRDUDE_FLAGS += -v -v
+
+#Run while cable attached or don't
+AVRDUDE_FLAGS += -E reset #keep chip disabled while cable attached
+#AVRDUDE_FLAGS += -E noreset
+
+#AVRDUDE_WRITE_FLASH = -U lfuse:w:0x04:m #run with 8 Mhz clock
+
+#AVRDUDE_WRITE_FLASH = -U lfuse:w:0x21:m #run with 1 Mhz clock #default clock mode
+
+#AVRDUDE_WRITE_FLASH = -U lfuse:w:0x01:m #run with 1 Mhz clock no start up time
+
+# ---------------------------------------------------------------------------
+
+# Define directories, if needed.
+DIRAVR = c:/winavr
+DIRAVRBIN = $(DIRAVR)/bin
+DIRAVRUTILS = $(DIRAVR)/utils/bin
+DIRINC = .
+DIRLIB = $(DIRAVR)/avr/lib
+
+
+# Define programs and commands.
+SHELL = sh
+
+CC = avr-g++
+
+OBJCOPY = avr-objcopy
+OBJDUMP = avr-objdump
+SIZE = avr-size
+
+
+# Programming support using avrdude.
+AVRDUDE = avrdude
+
+
+REMOVE = rm -f
+COPY = cp
+
+HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
+ELFSIZE = $(SIZE) -A $(TARGET).elf
+
+
+
+# Define Messages
+# English
+MSG_ERRORS_NONE = Errors: none
+MSG_BEGIN = -------- begin --------
+MSG_END = -------- end --------
+MSG_SIZE_BEFORE = Size before:
+MSG_SIZE_AFTER = Size after:
+MSG_COFF = Converting to AVR COFF:
+MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
+MSG_FLASH = Creating load file for Flash:
+MSG_EEPROM = Creating load file for EEPROM:
+MSG_EXTENDED_LISTING = Creating Extended Listing:
+MSG_SYMBOL_TABLE = Creating Symbol Table:
+MSG_LINKING = Linking:
+MSG_COMPILING = Compiling:
+MSG_ASSEMBLING = Assembling:
+MSG_CLEANING = Cleaning project:
+
+
+
+
+# Define all object files.
+OBJ = $(SRC:.cpp=.o) $(ASRC:.S=.o)
+
+# Define all listing files.
+LST = $(ASRC:.S=.lst) $(SRC:.cpp=.lst)
+
+# Combine all necessary flags and optional flags.
+# Add target processor to flags.
+ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
+ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
+
+
+
+# Default target: make program!
+all: begin gccversion sizebefore $(TARGET).elf $(TARGET).hex $(TARGET).eep \
+ $(TARGET).lss $(TARGET).sym sizeafter finished end
+# $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
+
+# Eye candy.
+# AVR Studio 3.x does not check make's exit code but relies on
+# the following magic strings to be generated by the compile job.
+begin:
+ @echo
+ @echo $(MSG_BEGIN)
+
+finished:
+ @echo $(MSG_ERRORS_NONE)
+
+end:
+ @echo $(MSG_END)
+ @echo
+
+
+# Display size of file.
+sizebefore:
+ @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); echo; fi
+
+sizeafter:
+ @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi
+
+
+
+# Display compiler version information.
+gccversion :
+ @$(CC) --version
+
+
+
+
+# Convert ELF to COFF for use in debugging / simulating in
+# AVR Studio or VMLAB.
+COFFCONVERT=$(OBJCOPY) --debugging \
+ --change-section-address .data-0x800000 \
+ --change-section-address .bss-0x800000 \
+ --change-section-address .noinit-0x800000 \
+ --change-section-address .eeprom-0x810000
+
+
+coff: $(TARGET).elf
+ @echo
+ @echo $(MSG_COFF) $(TARGET).cof
+ $(COFFCONVERT) -O coff-avr $< $(TARGET).cof
+
+
+extcoff: $(TARGET).elf
+ @echo
+ @echo $(MSG_EXTENDED_COFF) $(TARGET).cof
+ $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
+
+
+
+
+# Program the device.
+program: $(TARGET).hex $(TARGET).eep
+ $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
+
+
+
+
+# Create final output files (.hex, .eep) from ELF output file.
+%.hex: %.elf
+ @echo
+ @echo $(MSG_FLASH) $@
+ $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
+
+%.eep: %.elf
+ @echo
+ @echo $(MSG_EEPROM) $@
+ -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
+ --change-section-lma .eeprom=0 -O $(FORMAT) $< $@
+
+# Create extended listing file from ELF output file.
+%.lss: %.elf
+ @echo
+ @echo $(MSG_EXTENDED_LISTING) $@
+ $(OBJDUMP) -h -S $< > $@
+
+# Create a symbol table from ELF output file.
+%.sym: %.elf
+ @echo
+ @echo $(MSG_SYMBOL_TABLE) $@
+ avr-nm -n $< > $@
+
+
+
+# Link: create ELF output file from object files.
+.SECONDARY : $(TARGET).elf
+.PRECIOUS : $(OBJ)
+%.elf: $(OBJ)
+ @echo
+ @echo $(MSG_LINKING) $@
+ $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
+
+
+# Compile: create object files from C source files.
+%.o : %.c
+ @echo
+ @echo $(MSG_COMPILING) $<
+ $(CC) -c $(ALL_CFLAGS) $< -o $@
+
+# Compile: create object files from C++ source files.
+%.o : %.cpp
+ @echo
+ @echo $(MSG_COMPILING) $<
+ $(CC) -c $(ALL_CFLAGS) $< -o $@
+
+# Compile: create assembler files from C source files.
+%.s : %.c
+ $(CC) -S $(ALL_CFLAGS) $< -o $@
+
+
+# Assemble: create object files from assembler source files.
+%.o : %.S
+ @echo
+ @echo $(MSG_ASSEMBLING) $<
+ $(CC) -c $(ALL_ASFLAGS) $< -o $@
+
+
+
+
+
+
+# Target: clean project.
+clean: begin clean_list finished end
+
+clean_list :
+ @echo
+ @echo $(MSG_CLEANING)
+ $(REMOVE) $(TARGET).hex
+ $(REMOVE) $(TARGET).eep
+ $(REMOVE) $(TARGET).obj
+ $(REMOVE) $(TARGET).cof
+ $(REMOVE) $(TARGET).elf
+ $(REMOVE) $(TARGET).map
+ $(REMOVE) $(TARGET).obj
+ $(REMOVE) $(TARGET).a90
+ $(REMOVE) $(TARGET).sym
+ $(REMOVE) $(TARGET).lnk
+ $(REMOVE) $(TARGET).lss
+ $(REMOVE) $(OBJ)
+ $(REMOVE) $(LST)
+ $(REMOVE) $(SRC:.c=.s)
+ $(REMOVE) $(SRC:.c=.d)
+ $(REMOVE) *~
+
+# Automatically generate C source code dependencies.
+# (Code originally taken from the GNU make user manual and modified
+# (See README.txt Credits).)
+#
+# Note that this will work with sh (bash) and sed that is shipped with WinAVR
+# (see the SHELL variable defined above).
+# This may not work with other shells or other seds.
+#
+%.d: %.c
+ set -e; $(CC) -MM $(ALL_CFLAGS) $< \
+ | sed 's,\(.*\)\.o[ :]*,\1.o \1.d : ,g' > $@; \
+ [ -s $@ ] || rm -f $@
+
+
+# Remove the '-' if you want to see the dependency files generated.
+-include $(SRC:.c=.d)
+
+
+
+# Listing of phony targets.
+.PHONY : all begin finish end sizebefore sizeafter gccversion coff extcoff \
+ clean clean_list program
+
diff --git a/Minnow/binary.h b/Minnow/binary.h
new file mode 100644
index 0000000..aec4c73
--- /dev/null
+++ b/Minnow/binary.h
@@ -0,0 +1,534 @@
+/*
+ binary.h - Definitions for binary constants
+ Copyright (c) 2006 David A. Mellis. All right reserved.
+
+ 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
+*/
+
+#ifndef Binary_h
+#define Binary_h
+
+#define B0 0
+#define B00 0
+#define B000 0
+#define B0000 0
+#define B00000 0
+#define B000000 0
+#define B0000000 0
+#define B00000000 0
+#define B1 1
+#define B01 1
+#define B001 1
+#define B0001 1
+#define B00001 1
+#define B000001 1
+#define B0000001 1
+#define B00000001 1
+#define B10 2
+#define B010 2
+#define B0010 2
+#define B00010 2
+#define B000010 2
+#define B0000010 2
+#define B00000010 2
+#define B11 3
+#define B011 3
+#define B0011 3
+#define B00011 3
+#define B000011 3
+#define B0000011 3
+#define B00000011 3
+#define B100 4
+#define B0100 4
+#define B00100 4
+#define B000100 4
+#define B0000100 4
+#define B00000100 4
+#define B101 5
+#define B0101 5
+#define B00101 5
+#define B000101 5
+#define B0000101 5
+#define B00000101 5
+#define B110 6
+#define B0110 6
+#define B00110 6
+#define B000110 6
+#define B0000110 6
+#define B00000110 6
+#define B111 7
+#define B0111 7
+#define B00111 7
+#define B000111 7
+#define B0000111 7
+#define B00000111 7
+#define B1000 8
+#define B01000 8
+#define B001000 8
+#define B0001000 8
+#define B00001000 8
+#define B1001 9
+#define B01001 9
+#define B001001 9
+#define B0001001 9
+#define B00001001 9
+#define B1010 10
+#define B01010 10
+#define B001010 10
+#define B0001010 10
+#define B00001010 10
+#define B1011 11
+#define B01011 11
+#define B001011 11
+#define B0001011 11
+#define B00001011 11
+#define B1100 12
+#define B01100 12
+#define B001100 12
+#define B0001100 12
+#define B00001100 12
+#define B1101 13
+#define B01101 13
+#define B001101 13
+#define B0001101 13
+#define B00001101 13
+#define B1110 14
+#define B01110 14
+#define B001110 14
+#define B0001110 14
+#define B00001110 14
+#define B1111 15
+#define B01111 15
+#define B001111 15
+#define B0001111 15
+#define B00001111 15
+#define B10000 16
+#define B010000 16
+#define B0010000 16
+#define B00010000 16
+#define B10001 17
+#define B010001 17
+#define B0010001 17
+#define B00010001 17
+#define B10010 18
+#define B010010 18
+#define B0010010 18
+#define B00010010 18
+#define B10011 19
+#define B010011 19
+#define B0010011 19
+#define B00010011 19
+#define B10100 20
+#define B010100 20
+#define B0010100 20
+#define B00010100 20
+#define B10101 21
+#define B010101 21
+#define B0010101 21
+#define B00010101 21
+#define B10110 22
+#define B010110 22
+#define B0010110 22
+#define B00010110 22
+#define B10111 23
+#define B010111 23
+#define B0010111 23
+#define B00010111 23
+#define B11000 24
+#define B011000 24
+#define B0011000 24
+#define B00011000 24
+#define B11001 25
+#define B011001 25
+#define B0011001 25
+#define B00011001 25
+#define B11010 26
+#define B011010 26
+#define B0011010 26
+#define B00011010 26
+#define B11011 27
+#define B011011 27
+#define B0011011 27
+#define B00011011 27
+#define B11100 28
+#define B011100 28
+#define B0011100 28
+#define B00011100 28
+#define B11101 29
+#define B011101 29
+#define B0011101 29
+#define B00011101 29
+#define B11110 30
+#define B011110 30
+#define B0011110 30
+#define B00011110 30
+#define B11111 31
+#define B011111 31
+#define B0011111 31
+#define B00011111 31
+#define B100000 32
+#define B0100000 32
+#define B00100000 32
+#define B100001 33
+#define B0100001 33
+#define B00100001 33
+#define B100010 34
+#define B0100010 34
+#define B00100010 34
+#define B100011 35
+#define B0100011 35
+#define B00100011 35
+#define B100100 36
+#define B0100100 36
+#define B00100100 36
+#define B100101 37
+#define B0100101 37
+#define B00100101 37
+#define B100110 38
+#define B0100110 38
+#define B00100110 38
+#define B100111 39
+#define B0100111 39
+#define B00100111 39
+#define B101000 40
+#define B0101000 40
+#define B00101000 40
+#define B101001 41
+#define B0101001 41
+#define B00101001 41
+#define B101010 42
+#define B0101010 42
+#define B00101010 42
+#define B101011 43
+#define B0101011 43
+#define B00101011 43
+#define B101100 44
+#define B0101100 44
+#define B00101100 44
+#define B101101 45
+#define B0101101 45
+#define B00101101 45
+#define B101110 46
+#define B0101110 46
+#define B00101110 46
+#define B101111 47
+#define B0101111 47
+#define B00101111 47
+#define B110000 48
+#define B0110000 48
+#define B00110000 48
+#define B110001 49
+#define B0110001 49
+#define B00110001 49
+#define B110010 50
+#define B0110010 50
+#define B00110010 50
+#define B110011 51
+#define B0110011 51
+#define B00110011 51
+#define B110100 52
+#define B0110100 52
+#define B00110100 52
+#define B110101 53
+#define B0110101 53
+#define B00110101 53
+#define B110110 54
+#define B0110110 54
+#define B00110110 54
+#define B110111 55
+#define B0110111 55
+#define B00110111 55
+#define B111000 56
+#define B0111000 56
+#define B00111000 56
+#define B111001 57
+#define B0111001 57
+#define B00111001 57
+#define B111010 58
+#define B0111010 58
+#define B00111010 58
+#define B111011 59
+#define B0111011 59
+#define B00111011 59
+#define B111100 60
+#define B0111100 60
+#define B00111100 60
+#define B111101 61
+#define B0111101 61
+#define B00111101 61
+#define B111110 62
+#define B0111110 62
+#define B00111110 62
+#define B111111 63
+#define B0111111 63
+#define B00111111 63
+#define B1000000 64
+#define B01000000 64
+#define B1000001 65
+#define B01000001 65
+#define B1000010 66
+#define B01000010 66
+#define B1000011 67
+#define B01000011 67
+#define B1000100 68
+#define B01000100 68
+#define B1000101 69
+#define B01000101 69
+#define B1000110 70
+#define B01000110 70
+#define B1000111 71
+#define B01000111 71
+#define B1001000 72
+#define B01001000 72
+#define B1001001 73
+#define B01001001 73
+#define B1001010 74
+#define B01001010 74
+#define B1001011 75
+#define B01001011 75
+#define B1001100 76
+#define B01001100 76
+#define B1001101 77
+#define B01001101 77
+#define B1001110 78
+#define B01001110 78
+#define B1001111 79
+#define B01001111 79
+#define B1010000 80
+#define B01010000 80
+#define B1010001 81
+#define B01010001 81
+#define B1010010 82
+#define B01010010 82
+#define B1010011 83
+#define B01010011 83
+#define B1010100 84
+#define B01010100 84
+#define B1010101 85
+#define B01010101 85
+#define B1010110 86
+#define B01010110 86
+#define B1010111 87
+#define B01010111 87
+#define B1011000 88
+#define B01011000 88
+#define B1011001 89
+#define B01011001 89
+#define B1011010 90
+#define B01011010 90
+#define B1011011 91
+#define B01011011 91
+#define B1011100 92
+#define B01011100 92
+#define B1011101 93
+#define B01011101 93
+#define B1011110 94
+#define B01011110 94
+#define B1011111 95
+#define B01011111 95
+#define B1100000 96
+#define B01100000 96
+#define B1100001 97
+#define B01100001 97
+#define B1100010 98
+#define B01100010 98
+#define B1100011 99
+#define B01100011 99
+#define B1100100 100
+#define B01100100 100
+#define B1100101 101
+#define B01100101 101
+#define B1100110 102
+#define B01100110 102
+#define B1100111 103
+#define B01100111 103
+#define B1101000 104
+#define B01101000 104
+#define B1101001 105
+#define B01101001 105
+#define B1101010 106
+#define B01101010 106
+#define B1101011 107
+#define B01101011 107
+#define B1101100 108
+#define B01101100 108
+#define B1101101 109
+#define B01101101 109
+#define B1101110 110
+#define B01101110 110
+#define B1101111 111
+#define B01101111 111
+#define B1110000 112
+#define B01110000 112
+#define B1110001 113
+#define B01110001 113
+#define B1110010 114
+#define B01110010 114
+#define B1110011 115
+#define B01110011 115
+#define B1110100 116
+#define B01110100 116
+#define B1110101 117
+#define B01110101 117
+#define B1110110 118
+#define B01110110 118
+#define B1110111 119
+#define B01110111 119
+#define B1111000 120
+#define B01111000 120
+#define B1111001 121
+#define B01111001 121
+#define B1111010 122
+#define B01111010 122
+#define B1111011 123
+#define B01111011 123
+#define B1111100 124
+#define B01111100 124
+#define B1111101 125
+#define B01111101 125
+#define B1111110 126
+#define B01111110 126
+#define B1111111 127
+#define B01111111 127
+#define B10000000 128
+#define B10000001 129
+#define B10000010 130
+#define B10000011 131
+#define B10000100 132
+#define B10000101 133
+#define B10000110 134
+#define B10000111 135
+#define B10001000 136
+#define B10001001 137
+#define B10001010 138
+#define B10001011 139
+#define B10001100 140
+#define B10001101 141
+#define B10001110 142
+#define B10001111 143
+#define B10010000 144
+#define B10010001 145
+#define B10010010 146
+#define B10010011 147
+#define B10010100 148
+#define B10010101 149
+#define B10010110 150
+#define B10010111 151
+#define B10011000 152
+#define B10011001 153
+#define B10011010 154
+#define B10011011 155
+#define B10011100 156
+#define B10011101 157
+#define B10011110 158
+#define B10011111 159
+#define B10100000 160
+#define B10100001 161
+#define B10100010 162
+#define B10100011 163
+#define B10100100 164
+#define B10100101 165
+#define B10100110 166
+#define B10100111 167
+#define B10101000 168
+#define B10101001 169
+#define B10101010 170
+#define B10101011 171
+#define B10101100 172
+#define B10101101 173
+#define B10101110 174
+#define B10101111 175
+#define B10110000 176
+#define B10110001 177
+#define B10110010 178
+#define B10110011 179
+#define B10110100 180
+#define B10110101 181
+#define B10110110 182
+#define B10110111 183
+#define B10111000 184
+#define B10111001 185
+#define B10111010 186
+#define B10111011 187
+#define B10111100 188
+#define B10111101 189
+#define B10111110 190
+#define B10111111 191
+#define B11000000 192
+#define B11000001 193
+#define B11000010 194
+#define B11000011 195
+#define B11000100 196
+#define B11000101 197
+#define B11000110 198
+#define B11000111 199
+#define B11001000 200
+#define B11001001 201
+#define B11001010 202
+#define B11001011 203
+#define B11001100 204
+#define B11001101 205
+#define B11001110 206
+#define B11001111 207
+#define B11010000 208
+#define B11010001 209
+#define B11010010 210
+#define B11010011 211
+#define B11010100 212
+#define B11010101 213
+#define B11010110 214
+#define B11010111 215
+#define B11011000 216
+#define B11011001 217
+#define B11011010 218
+#define B11011011 219
+#define B11011100 220
+#define B11011101 221
+#define B11011110 222
+#define B11011111 223
+#define B11100000 224
+#define B11100001 225
+#define B11100010 226
+#define B11100011 227
+#define B11100100 228
+#define B11100101 229
+#define B11100110 230
+#define B11100111 231
+#define B11101000 232
+#define B11101001 233
+#define B11101010 234
+#define B11101011 235
+#define B11101100 236
+#define B11101101 237
+#define B11101110 238
+#define B11101111 239
+#define B11110000 240
+#define B11110001 241
+#define B11110010 242
+#define B11110011 243
+#define B11110100 244
+#define B11110101 245
+#define B11110110 246
+#define B11110111 247
+#define B11111000 248
+#define B11111001 249
+#define B11111010 250
+#define B11111011 251
+#define B11111100 252
+#define B11111101 253
+#define B11111110 254
+#define B11111111 255
+
+#endif
diff --git a/Minnow/enqueue_command.cpp b/Minnow/enqueue_command.cpp
index 50d7f22..ba320fb 100644
--- a/Minnow/enqueue_command.cpp
+++ b/Minnow/enqueue_command.cpp
@@ -1,6 +1,6 @@
/*
Minnow Pacemaker client firmware.
-
+
Copyright (C) 2013 Robert Fairlie-Cuninghame
This program is free software: you can redistribute it and/or modify
@@ -62,19 +62,19 @@ void enqueue_command()
{
if (!allocate_command_queue_memory())
{
- send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
+ send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
PMSG(MSG_ERR_INSUFFICIENT_MEMORY));
return;
}
- }
-
+ }
+
generate_response_start(RSP_ORDER_SPECIFIC_ERROR, QUEUE_ERROR_MSG_OFFSET);
-
+
while (ptr < parameter_value + parameter_length)
{
const uint8_t length = *ptr++;
const uint8_t cmd = ptr[0];
-
+
if (length < 1 || ptr + length > parameter_value + parameter_length
|| (cmd == QUEUE_COMMAND_ORDER_WRAPPER && length < 2))
{
@@ -83,22 +83,22 @@ void enqueue_command()
send_enqueue_error(QUEUE_COMMAND_ERROR_TYPE_MALFORMED_BLOCK, index);
return;
}
-
+
uint8_t retval;
switch (cmd)
{
case QUEUE_COMMAND_LINEAR_MOVE:
retval = enqueue_linear_move_command(ptr+1, length-1);
break;
-
+
case QUEUE_COMMAND_MOVEMENT_CHECKPOINT:
retval = enqueue_move_checkpoint_command(ptr+1, length-1);
break;
-
+
case QUEUE_COMMAND_DELAY:
retval = enqueue_delay_command(ptr+1, length-1);
break;
-
+
case QUEUE_COMMAND_ORDER_WRAPPER:
switch (ptr[1])
{
@@ -127,7 +127,7 @@ void enqueue_command()
return;
}
break;
-
+
default:
send_enqueue_error(QUEUE_COMMAND_ERROR_TYPE_UNKNOWN_COMMAND_BLOCK, index);
return;
@@ -140,26 +140,26 @@ void enqueue_command()
ptr += length;
index += 1;
}
-
+
uint16_t remaining_slots;
uint16_t current_command_count;
uint16_t total_command_count;
CommandQueue::GetQueueInfo(remaining_slots, current_command_count, total_command_count);
-
+
generate_response_start(RSP_OK);
generate_response_data_add(remaining_slots);
generate_response_data_add(current_command_count);
generate_response_data_add(total_command_count);
- generate_response_send();
+ generate_response_send();
}
-
+
void send_enqueue_error(uint8_t error_type, uint8_t block_index, uint8_t error_code)
{
uint16_t remaining_slots;
uint16_t current_command_count;
uint16_t total_command_count;
CommandQueue::GetQueueInfo(remaining_slots, current_command_count, total_command_count);
-
+
generate_response_data_addbyte(error_type);
generate_response_data_addbyte(block_index);
generate_response_data_add(remaining_slots);
@@ -167,7 +167,7 @@ void send_enqueue_error(uint8_t error_type, uint8_t block_index, uint8_t error_c
generate_response_data_add(total_command_count);
generate_response_data_addbyte(error_code);
generate_response_send();
-}
+}
uint8_t generate_enqueue_insufficient_bytes_error(uint8_t expected_num_bytes, uint8_t rcvd_num_bytes)
{
@@ -176,26 +176,26 @@ uint8_t generate_enqueue_insufficient_bytes_error(uint8_t expected_num_bytes, ui
generate_response_msg_addPGM(PSTR(", "));
generate_response_msg_addPGM(PMSG(MSG_EXPECTING));
generate_response_msg_add_ascii_number(expected_num_bytes);
- return PARAM_APP_ERROR_TYPE_BAD_PARAMETER_FORMAT;
+ return PARAM_APP_ERROR_TYPE_BAD_PARAMETER_FORMAT;
}
-
+
FORCE_INLINE uint8_t enqueue_delay_command(const uint8_t *queue_command, uint8_t queue_command_length)
{
if (queue_command_length != sizeof(uint16_t))
return generate_enqueue_insufficient_bytes_error(sizeof(uint16_t), queue_command_length);
uint8_t *insertion_point = CommandQueue::GetCommandInsertionPoint(sizeof(DelayQueueCommand));
-
+
if (insertion_point == 0)
return ENQUEUE_ERROR_QUEUE_FULL;
-
+
DelayQueueCommand *cmd = (DelayQueueCommand *)insertion_point;
-
+
cmd->command_type = QUEUE_COMMAND_STRUCTS_TYPE_DELAY;
-
+
uint16_t delay = (queue_command[0] << 8) | queue_command[1];
- cmd->delay = delay * 10UL; // use us for delay
-
+ cmd->delay = delay * 10UL; // use us for delay
+
CommandQueue::EnqueueCommand(sizeof(DelayQueueCommand));
return ENQUEUE_SUCCESS;
}
@@ -206,26 +206,26 @@ FORCE_INLINE uint8_t enqueue_set_output_switch_state_command(const uint8_t *queu
if ((number_of_switches * 3) != queue_command_length)
return generate_enqueue_insufficient_bytes_error(3*(number_of_switches+1), queue_command_length);
-
- const uint8_t length = sizeof(SetOutputSwitchStateQueueCommand) +
+
+ const uint8_t length = sizeof(SetOutputSwitchStateQueueCommand) +
((number_of_switches - 1) * sizeof(DeviceBitState));
uint8_t *insertion_point = CommandQueue::GetCommandInsertionPoint(length);
-
+
if (insertion_point == 0)
return ENQUEUE_ERROR_QUEUE_FULL;
-
+
SetOutputSwitchStateQueueCommand *cmd = (SetOutputSwitchStateQueueCommand *)insertion_point;
-
+
cmd->command_type = QUEUE_COMMAND_STRUCTS_TYPE_SET_OUTPUT_SWITCH_STATE;
cmd->num_bits = number_of_switches;
-
+
uint8_t device_number, device_state;
for (uint8_t i = 0; i < queue_command_length; i+=3)
{
device_number = queue_command[i+1];
device_state = queue_command[i+2];
-
+
switch(queue_command[i])
{
case PM_DEVICE_TYPE_SWITCH_OUTPUT:
@@ -235,9 +235,9 @@ FORCE_INLINE uint8_t enqueue_set_output_switch_state_command(const uint8_t *queu
// assume that Device_OutputSwitch::SetPin checks that pin maps to valid port
const uint8_t pin = Device_OutputSwitch::GetPin(device_number);
-
+
DeviceBitState *output_state = (DeviceBitState *)cmd->output_bit_info + i;
-
+
// could further optimize this by including the actual address of the output/mode register
// but this is sufficient for now
output_state->device_number = device_number;
@@ -245,12 +245,12 @@ FORCE_INLINE uint8_t enqueue_set_output_switch_state_command(const uint8_t *queu
output_state->device_bit = digitalPinToBitMask(pin);
output_state->device_state = device_state;
break;
- }
+ }
default:
return PARAM_APP_ERROR_TYPE_INVALID_DEVICE_TYPE;
}
- }
-
+ }
+
CommandQueue::EnqueueCommand(length);
return ENQUEUE_SUCCESS;
}
@@ -259,14 +259,14 @@ FORCE_INLINE uint8_t enqueue_set_pwm_output_state_command(const uint8_t *queue_c
{
if (queue_command_length < 4)
return generate_enqueue_insufficient_bytes_error(4, queue_command_length);
-
+
uint8_t *insertion_point = CommandQueue::GetCommandInsertionPoint(sizeof(SetPwmOutputStateQueueCommand));
-
+
if (insertion_point == 0)
return ENQUEUE_ERROR_QUEUE_FULL;
-
+
const uint8_t device_number = queue_command[1];
-
+
switch(queue_command[0])
{
case PM_DEVICE_TYPE_PWM_OUTPUT:
@@ -280,24 +280,24 @@ FORCE_INLINE uint8_t enqueue_set_pwm_output_state_command(const uint8_t *queue_c
cmd->value = queue_command[2]; // the LSB is ignored
CommandQueue::EnqueueCommand(sizeof(SetPwmOutputStateQueueCommand));
return ENQUEUE_SUCCESS;
- }
+ }
default:
return PARAM_APP_ERROR_TYPE_INVALID_DEVICE_TYPE;
- }
+ }
}
FORCE_INLINE uint8_t enqueue_set_output_tone_command(const uint8_t *queue_command, uint8_t queue_command_length)
{
if (queue_command_length < 4)
return generate_enqueue_insufficient_bytes_error(4, queue_command_length);
-
+
uint8_t *insertion_point = CommandQueue::GetCommandInsertionPoint(sizeof(SetBuzzerStateQueueCommand));
-
+
if (insertion_point == 0)
return ENQUEUE_ERROR_QUEUE_FULL;
-
+
const uint8_t device_number = queue_command[1];
-
+
switch(queue_command[0])
{
case PM_DEVICE_TYPE_BUZZER:
@@ -311,26 +311,26 @@ FORCE_INLINE uint8_t enqueue_set_output_tone_command(const uint8_t *queue_comman
cmd->value = queue_command[2]; // the LSB is ignored
CommandQueue::EnqueueCommand(sizeof(SetBuzzerStateQueueCommand));
return ENQUEUE_SUCCESS;
- }
+ }
default:
return PARAM_APP_ERROR_TYPE_INVALID_DEVICE_TYPE;
- }
+ }
}
FORCE_INLINE uint8_t enqueue_set_heater_target_temperature_command(const uint8_t *queue_command, uint8_t queue_command_length)
{
if (queue_command_length < 3)
return generate_enqueue_insufficient_bytes_error(3, queue_command_length);
-
+
uint8_t *insertion_point = CommandQueue::GetCommandInsertionPoint(sizeof(SetHeaterTargetTempCommand));
-
+
if (insertion_point == 0)
return ENQUEUE_ERROR_QUEUE_FULL;
-
+
uint8_t heater_number = queue_command[0];
int16_t target_temp = (queue_command[1] << 8) | queue_command[2];
float target_ftemp = (float)target_temp / 10;
-
+
uint8_t retval = Device_Heater::ValidateTargetTemperature(heater_number, target_ftemp);
if (retval != APP_ERROR_TYPE_SUCCESS)
return retval;
@@ -340,7 +340,7 @@ FORCE_INLINE uint8_t enqueue_set_heater_target_temperature_command(const uint8_t
generate_response_msg_addPGM(PMSG(MSG_ERR_CANNOT_ACTIVATE_DEVICE_WHEN_STOPPED));
return PARAM_APP_ERROR_TYPE_DEVICE_UNAVAILABLE;
}
-
+
SetHeaterTargetTempCommand *cmd = (SetHeaterTargetTempCommand *)insertion_point;
cmd->command_type = QUEUE_COMMAND_STRUCTS_TYPE_SET_HEATER_TARGET_TEMP;
cmd->heater_number = queue_command[0];
@@ -354,14 +354,14 @@ FORCE_INLINE uint8_t enqueue_set_stepper_enable_state_command(const uint8_t *que
{
if (queue_command_length != 0 && queue_command_length != 2)
return generate_enqueue_insufficient_bytes_error(2, queue_command_length);
-
+
uint8_t *insertion_point = CommandQueue::GetCommandInsertionPoint(sizeof(SetStepperEnableStateQueueCommand));
-
+
if (insertion_point == 0)
return ENQUEUE_ERROR_QUEUE_FULL;
-
+
SetStepperEnableStateQueueCommand *cmd = (SetStepperEnableStateQueueCommand *)insertion_point;
-
+
cmd->command_type = QUEUE_COMMAND_STRUCTS_TYPE_SET_STEPPER_ENABLE_STATE;
if (queue_command_length == 0)
{
@@ -391,22 +391,22 @@ FORCE_INLINE static uint8_t enqueue_set_endstop_enable_state_command(const uint8
{
if ((queue_command_length & 1) != 0)
return generate_enqueue_insufficient_bytes_error(queue_command_length+1, queue_command_length);
-
+
uint8_t *insertion_point = CommandQueue::GetCommandInsertionPoint(sizeof(SetEndstopEnableStateQueueCommand));
-
+
SetEndstopEnableStateQueueCommand *cmd = (SetEndstopEnableStateQueueCommand *)insertion_point;
-
+
cmd->command_type = QUEUE_COMMAND_STRUCTS_TYPE_SET_ENDSTOP_ENABLE_STATE;
cmd->endstops_to_change = 0;
cmd->endstop_enable_state = 0;
-
+
uint8_t device_number, device_state;
for (uint8_t i=0; i < queue_command_length; i+=2)
{
device_number = queue_command[i];
device_state = queue_command[i+1];
-
+
if (!Device_InputSwitch::IsInUse(device_number) || device_number >= MAX_ENDSTOPS)
return PARAM_APP_ERROR_TYPE_INVALID_DEVICE_NUMBER;
@@ -414,7 +414,7 @@ FORCE_INLINE static uint8_t enqueue_set_endstop_enable_state_command(const uint8
if (device_state)
cmd->endstop_enable_state |= (1 << device_number);
}
-
+
CommandQueue::EnqueueCommand(sizeof(SetEndstopEnableStateQueueCommand));
return ENQUEUE_SUCCESS;
}
@@ -422,17 +422,17 @@ FORCE_INLINE static uint8_t enqueue_set_endstop_enable_state_command(const uint8
uint8_t validate_linear_move(const uint8_t *queue_command, uint8_t queue_command_length)
{
uint8_t expected_length = 7; // minimum short header size
-
+
uint16_t axes_selected = 0;
uint16_t directions = 0;
bool use_long_counts = false;
bool use_long_axis_mask = queue_command[0] & 0x80;
-
+
if (use_long_axis_mask)
{
expected_length += 2;
- axes_selected = ((queue_command[0] & ~0x80) << 8) | queue_command[1];
- directions = ((queue_command[2] & ~0x80) << 8) | queue_command[3];
+ axes_selected = ((uint16_t)(queue_command[0] & ~0x80) << 8) | queue_command[1];
+ directions = ((uint16_t)(queue_command[2] & ~0x80) << 8) | queue_command[3];
use_long_counts = queue_command[2] & 0x80;
queue_command += 4;
}
@@ -448,11 +448,11 @@ uint8_t validate_linear_move(const uint8_t *queue_command, uint8_t queue_command
if (queue_command_length < expected_length)
return generate_enqueue_insufficient_bytes_error(expected_length, queue_command_length);
-
+
uint8_t primary_axis = *queue_command++ & 0x0F; // (don't need homing bit for validation)
uint8_t nominal_speed_fraction = *queue_command++;
uint8_t final_speed_fraction = *queue_command++;
-
+
uint16_t accel_count;
uint16_t decel_count;
if (!use_long_counts)
@@ -462,11 +462,11 @@ uint8_t validate_linear_move(const uint8_t *queue_command, uint8_t queue_command
}
else
{
- accel_count = (queue_command[0] << 8) | queue_command[1];
- decel_count = (queue_command[2] << 8) | queue_command[3];
+ accel_count = ((uint16_t)(queue_command[0]) << 8) | queue_command[1];
+ decel_count = ((uint16_t)(queue_command[2]) << 8) | queue_command[3];
queue_command += 4;
}
-
+
uint8_t num_axes = 0;
uint8_t tmp_axes = axes_selected;
uint8_t axis_number = 0;
@@ -498,7 +498,7 @@ uint8_t validate_linear_move(const uint8_t *queue_command, uint8_t queue_command
}
primary_axis_index = index;
}
-
+
index += 1;
}
tmp_axes >>= 1;
@@ -510,20 +510,20 @@ uint8_t validate_linear_move(const uint8_t *queue_command, uint8_t queue_command
generate_response_msg_addPGM(PSTR("No axis selected")); // TODO: Language-ify
return PARAM_APP_ERROR_TYPE_BAD_PARAMETER_VALUE;
}
-
+
if (primary_axis_index < 0)
{
generate_response_msg_addPGM(PSTR("Invalid primary axis specified")); // TODO: Language-ify
return PARAM_APP_ERROR_TYPE_BAD_PARAMETER_VALUE;
}
-
+
if (nominal_speed_fraction < final_speed_fraction)
{
generate_response_msg_addPGM(PSTR("Nominal < Final Speed")); // TODO: Language-ify
return PARAM_APP_ERROR_TYPE_BAD_PARAMETER_VALUE;
}
- uint16_t nominal_speed = (uint32_t)AxisInfo::GetAxisMaxRate(primary_axis) * nominal_speed_fraction / 255;
+ uint16_t nominal_speed = (uint32_t)AxisInfo::GetAxisMaxRate(primary_axis) * nominal_speed_fraction / 255;
uint16_t initial_speed= last_enqueued_final_speed;
if (nominal_speed < initial_speed)
@@ -548,7 +548,7 @@ uint8_t validate_linear_move(const uint8_t *queue_command, uint8_t queue_command
if (!use_long_counts)
primary_axis_count = queue_command[primary_axis_index];
else
- primary_axis_count = (queue_command[2*primary_axis_index] << 8) | queue_command[(2*primary_axis_index) + 1];
+ primary_axis_count = ( (uint16_t)(queue_command[2*primary_axis_index]) << 8) | queue_command[(2*primary_axis_index) + 1];
if (accel_count > primary_axis_count)
{
@@ -561,33 +561,33 @@ uint8_t validate_linear_move(const uint8_t *queue_command, uint8_t queue_command
generate_response_msg_addPGM(PSTR("Invalid deceleration count")); // TODO: Language-ify
return PARAM_APP_ERROR_TYPE_BAD_PARAMETER_VALUE;
}
-
+
if (accel_count + decel_count > primary_axis_count)
{
generate_response_msg_addPGM(PSTR("Overlapped acceleration counts")); // TODO: Language-ify
return PARAM_APP_ERROR_TYPE_BAD_PARAMETER_VALUE;
}
-
+
return APP_ERROR_TYPE_SUCCESS;
}
uint8_t enqueue_linear_move_command(const uint8_t *queue_command, uint8_t queue_command_length)
{
- // validation code is separated so that it makes it easier to split
+ // validation code is separated so that it makes it easier to split
// the expansion to a secondary queue.
uint8_t retval = validate_linear_move(queue_command, queue_command_length);
if (retval != APP_ERROR_TYPE_SUCCESS)
return retval;
-
+
uint16_t axes_selected;
uint16_t directions;
bool use_long_counts;
bool use_long_axis_mask = queue_command[0] & 0x80;
-
+
if (use_long_axis_mask)
{
- axes_selected = ((queue_command[0] & ~0x80) << 8) | queue_command[1];
- directions = ((queue_command[2] & ~0x80) << 8) | queue_command[3];
+ axes_selected = ((uint16_t)(queue_command[0] & ~0x80) << 8) | queue_command[1];
+ directions = ((uint16_t)(queue_command[2] & ~0x80) << 8) | queue_command[3];
use_long_counts = queue_command[2] & 0x80;
queue_command += 4;
}
@@ -598,12 +598,12 @@ uint8_t enqueue_linear_move_command(const uint8_t *queue_command, uint8_t queue_
use_long_counts = queue_command[1] & 0x80;
queue_command += 2;
}
-
+
uint8_t primary_axis = *queue_command & 0x0F;
bool homing_bit = *queue_command++ & 0x10;
uint8_t nominal_speed_fraction = *queue_command++;
uint8_t final_speed_fraction = *queue_command++;
-
+
uint16_t accel_count;
uint16_t decel_count;
if (!use_long_counts)
@@ -613,11 +613,11 @@ uint8_t enqueue_linear_move_command(const uint8_t *queue_command, uint8_t queue_
}
else
{
- accel_count = (queue_command[0] << 8) | queue_command[1];
- decel_count = (queue_command[2] << 8) | queue_command[3];
+ accel_count = ((uint16_t)(queue_command[0]) << 8) | queue_command[1];
+ decel_count = ((uint16_t)(queue_command[2]) << 8) | queue_command[3];
queue_command += 4;
}
-
+
uint8_t num_axes = 0;
uint8_t tmp_axes = axes_selected;
while (tmp_axes != 0)
@@ -628,13 +628,13 @@ uint8_t enqueue_linear_move_command(const uint8_t *queue_command, uint8_t queue_
}
uint8_t expected_output_length = sizeof(LinearMoveCommand) + ((num_axes-1)*sizeof(AxisMoveInfo));
-
+
uint8_t *insertion_point = CommandQueue::GetCommandInsertionPoint(expected_output_length);
if (insertion_point == 0)
return ENQUEUE_ERROR_QUEUE_FULL;
LinearMoveCommand *cmd = (LinearMoveCommand *)insertion_point;
-
+
cmd->command_type = QUEUE_COMMAND_STRUCTS_TYPE_LINEAR_MOVE;
cmd->num_axes = num_axes;
@@ -653,7 +653,7 @@ uint8_t enqueue_linear_move_command(const uint8_t *queue_command, uint8_t queue_
{
AxisMoveInfo *axis_move_info = &cmd->axis_move_info[index];
if (use_long_counts)
- axis_move_info->step_count = (queue_command[2*index] << 8) | queue_command[(2*index)+1];
+ axis_move_info->step_count = ((uint16_t)(queue_command[2*index]) << 8) | queue_command[(2*index)+1];
else
axis_move_info->step_count = queue_command[index];
@@ -665,9 +665,11 @@ uint8_t enqueue_linear_move_command(const uint8_t *queue_command, uint8_t queue_
cmd->primary_axis = index;
primary_axis_steps = axis_move_info->step_count;
}
-
+
axis_move_info->axis_info = &AxisInfo::axis_info_array[axis_number];
-
+
+ // after homing one end Switch is triggered, but we still want the stepper to move away from it.
+ // -> we can only check the end switch in direction of movement.
if (directions & (1 << axis_number))
{
cmd->directions |= (1 << index);
@@ -677,7 +679,7 @@ uint8_t enqueue_linear_move_command(const uint8_t *queue_command, uint8_t queue_
{
cmd->endstops_of_interest |= AxisInfo::GetAxisMinEndstops(axis_number);
}
-
+
index += 1;
}
tmp_axes >>= 1;
@@ -698,22 +700,22 @@ uint8_t enqueue_linear_move_command(const uint8_t *queue_command, uint8_t queue_
cmd->steps_phase_2 = max_steps - ((uint32_t)max_steps * accel_count / primary_axis_steps);
cmd->steps_phase_3 = (uint32_t)max_steps * decel_count / primary_axis_steps;
}
-
+
uint16_t initial_speed = last_enqueued_final_speed;
-
+
// a = (v^2 - u^2) / (2*distance)
if (cmd->steps_phase_2 != max_steps)
- cmd->acceleration_rate = ((((uint32_t)cmd->nominal_rate * cmd->nominal_rate) - ((uint32_t)initial_speed * initial_speed))
+ cmd->acceleration_rate = ((((uint32_t)cmd->nominal_rate * cmd->nominal_rate) - ((uint32_t)initial_speed * initial_speed))
/ (max_steps - cmd->steps_phase_2)) / 2;
else
cmd->acceleration_rate = 0;
-
+
if (cmd->steps_phase_3 != 0)
- cmd->deceleration_rate = ((((uint32_t)cmd->nominal_rate * cmd->nominal_rate) - ((uint32_t)cmd->final_rate * cmd->final_rate))
+ cmd->deceleration_rate = ((((uint32_t)cmd->nominal_rate * cmd->nominal_rate) - ((uint32_t)cmd->final_rate * cmd->final_rate))
/ cmd->steps_phase_3) / 2;
else
cmd->deceleration_rate = 0;
-
+
// t = (v - u) / a and t = d / v
// TODO - work through again
uint32_t nominal_block_time = 0;
@@ -727,21 +729,21 @@ uint8_t enqueue_linear_move_command(const uint8_t *queue_command, uint8_t queue_
cmd->nominal_block_time = nominal_block_time;
else
cmd->nominal_block_time = 0xFFFF;
-
+
cmd->homing_bit = homing_bit;
-
+
uint16_t underrun_rate = min(cmd->nominal_rate,AxisInfo::GetUnderrunRate(primary_axis));
-
+
// d = (v^2 - u^2) / (2*a)
if (underrun_rate > cmd->final_rate)
- cmd->steps_to_final_speed_from_underrun_rate = ((uint32_t)underrun_rate*underrun_rate) - ((uint32_t)cmd->final_rate*cmd->final_rate)
+ cmd->steps_to_final_speed_from_underrun_rate = ((uint32_t)underrun_rate*underrun_rate) - ((uint32_t)cmd->final_rate*cmd->final_rate)
/ (2 * AxisInfo::GetUnderrunAccelRate(primary_axis));
else
cmd->steps_to_final_speed_from_underrun_rate = 0;
-
+
is_checkpoint_last = false;
-
- // TODO safely increment
+
+ // TODO safely increment
// queued_microseconds_remaining -= nominal_block_time;
// queued_steps_remaining -= total_step_events;
@@ -753,4 +755,4 @@ uint8_t enqueue_move_checkpoint_command(const uint8_t *queue_command, uint8_t qu
{
is_checkpoint_last = true;
return ENQUEUE_SUCCESS;
-}
\ No newline at end of file
+}
diff --git a/Minnow/firmware_configuration.cpp b/Minnow/firmware_configuration.cpp
index e1eb585..cce7931 100644
--- a/Minnow/firmware_configuration.cpp
+++ b/Minnow/firmware_configuration.cpp
@@ -1,6 +1,6 @@
/*
Minnow Pacemaker client firmware.
-
+
Copyright (C) 2013 Robert Fairlie-Cuninghame
This program is free software: you can redistribute it and/or modify
@@ -18,7 +18,7 @@
*/
//
-// Firmware Configuration
+// Firmware Configuration
//
#define __STDC_LIMIT_MACROS
@@ -39,6 +39,7 @@
#include "Device_Heater.h"
#include "Device_Stepper.h"
#include "Device_TemperatureSensor.h"
+#include "pins_arduino.h"
FORCE_INLINE static void generate_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t instance_id);
FORCE_INLINE static bool set_uint8_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t instance_id, uint8_t value);
@@ -49,6 +50,7 @@ FORCE_INLINE static bool set_float_value(uint8_t node_type, uint8_t parent_insta
FORCE_INLINE static bool setPin(uint8_t node_type, uint8_t device_number, uint8_t pin);
static bool read_number(long &number, const char *value);
+static bool read_pin(long &number, const char *value);
void handle_firmware_configuration_value_properties(const char *name)
{
@@ -60,7 +62,7 @@ void handle_firmware_configuration_value_properties(const char *name)
PMSG(ERR_MSG_CONFIG_NODE_NOT_FOUND));
return;
}
-
+
ConfigurationTreeNode *node = tree.FindNode(name);
if (node == 0)
{
@@ -75,7 +77,7 @@ void handle_firmware_configuration_value_properties(const char *name)
PMSG(ERR_MSG_CONFIG_NODE_NOT_COMPLETE), name);
return;
}
-
+
generate_response_start(RSP_OK, 2);
generate_response_data_addbyte(node->GetLeafClass());
generate_response_data_addbyte(node->GetLeafOperations());
@@ -88,7 +90,7 @@ void handle_firmware_configuration_value_properties(const char *name)
uint8_t device_number = 0;
while ((node = tree.GetParentNode(node)) != 0)
{
- if (node->IsInstanceNode()
+ if (node->IsInstanceNode()
&& node->GetLeafSetDataType() != PM_DEVICE_TYPE_INVALID)
{
device_type = node->GetLeafSetDataType();
@@ -97,9 +99,9 @@ void handle_firmware_configuration_value_properties(const char *name)
}
generate_response_data_addbyte(device_type);
generate_response_data_addbyte(device_number);
-
+
generate_response_send();
-}
+}
void handle_firmware_configuration_traversal(const char *name)
{
@@ -122,10 +124,10 @@ void handle_firmware_configuration_traversal(const char *name)
// currently only return nodes for devices which are in use
node = tree.FindNextLeafNode(tree.GetRootNode());
}
-
+
if (node == 0)
{
- send_OK_response();
+ send_OK_response();
return;
}
@@ -143,18 +145,18 @@ void handle_firmware_configuration_traversal(const char *name)
{
send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR, 0);
return;
- }
+ }
generate_response_send();
}
void handle_firmware_configuration_request(const char *name, const char* value)
{
ConfigurationTree tree;
-
+
if (*name == '\0')
{
send_app_error_response(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_FORMAT, 0);
- return;
+ return;
}
ConfigurationTreeNode *node = tree.FindNode(name);
@@ -192,16 +194,35 @@ void handle_firmware_configuration_request(const char *name, const char* value)
PMSG(ERR_MSG_CONFIG_NODE_NOT_WRITEABLE));
return;
}
-
+
generate_response_start(RSP_APPLICATION_ERROR, 1);
// ensure value has correct format and then attempt to set
switch (node->GetLeafSetDataType())
{
+ case LEAF_SET_DATATYPE_PIN:
+ {
+ long number;
+ if (!read_pin(number, value)
+ || number < 0 || number > UINT8_MAX)
+ {
+ send_app_error_response(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_FORMAT,
+ PMSG(ERR_MSG_INVALID_PIN_NUMBER), number);
+ return;
+ }
+
+ if (!set_uint8_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
+ node->GetInstanceId(), number))
+ {
+ return; // assume that set function has generated an error response
+ }
+ break;
+ }
+
case LEAF_SET_DATATYPE_UINT8:
{
long number;
- if (!read_number(number, value)
+ if (!read_number(number, value)
|| number < 0 || number > UINT8_MAX)
{
send_app_error_response(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_FORMAT,
@@ -209,14 +230,14 @@ void handle_firmware_configuration_request(const char *name, const char* value)
return;
}
- if (!set_uint8_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
+ if (!set_uint8_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
node->GetInstanceId(), number))
{
return; // assume that set function has generated an error response
}
break;
}
-
+
case LEAF_SET_DATATYPE_INT16:
{
long number;
@@ -227,14 +248,14 @@ void handle_firmware_configuration_request(const char *name, const char* value)
return;
}
- if (!set_int16_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
+ if (!set_int16_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
node->GetInstanceId(), number))
{
return; // assume that set function has generated an error response
}
break;
- }
-
+ }
+
case LEAF_SET_DATATYPE_BOOL:
{
bool val;
@@ -252,25 +273,25 @@ void handle_firmware_configuration_request(const char *name, const char* value)
PMSG(ERR_MSG_EXPECTED_BOOL_VALUE));
return;
}
-
- if (!set_bool_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
+
+ if (!set_bool_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
node->GetInstanceId(), val))
{
return; // assume that set function has generated an error response
}
break;
}
-
+
case LEAF_SET_DATATYPE_STRING:
{
- if (!set_string_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
+ if (!set_string_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
node->GetInstanceId(), value))
{
return; // assume that set function has generated an error response
}
break;
}
-
+
case LEAF_SET_DATATYPE_FLOAT:
{
char *end;
@@ -282,14 +303,14 @@ void handle_firmware_configuration_request(const char *name, const char* value)
return;
}
- if (!set_float_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
+ if (!set_float_value(node->GetNodeType(), tree.GetParentNode(node)->GetInstanceId(),
node->GetInstanceId(), val))
{
return; // assume that set function has generated an error response
}
break;
}
-
+
default:
send_app_error_response(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_FORMAT,
PMSG(MSG_ERR_CANNOT_HANDLE_FIRMWARE_CONFIG_REQUEST), __LINE__);
@@ -324,7 +345,7 @@ void generate_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t inst
case NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_ENABLE_PULLUP:
generate_response_data_addbyte(Device_InputSwitch::GetEnablePullup(parent_instance_id) ? '1' : '0');
break;
-
+
case NODE_TYPE_CONFIG_LEAF_OUTPUT_SWITCH_FRIENDLY_NAME:
if ((length = NVConfigStore::GetDeviceName(PM_DEVICE_TYPE_SWITCH_OUTPUT, instance_id, response_data_buf, response_data_buf_len)) > 0)
generate_response_data_addlen(length);
@@ -338,7 +359,7 @@ void generate_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t inst
strncpy_P(response_data_buf, stringify_initial_pin_state_value(value), response_data_buf_len);
generate_response_data_addlen(strlen(response_data_buf));
break;
-
+
case NODE_TYPE_CONFIG_LEAF_PWM_OUTPUT_FRIENDLY_NAME:
if ((length = NVConfigStore::GetDeviceName(PM_DEVICE_TYPE_PWM_OUTPUT, instance_id, response_data_buf, response_data_buf_len)) > 0)
generate_response_data_addlen(length);
@@ -350,8 +371,8 @@ void generate_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t inst
case NODE_TYPE_CONFIG_LEAF_PWM_OUTPUT_USE_SOFT_PWM:
generate_response_data_addbyte(Device_PwmOutput::GetSoftPwmState(parent_instance_id) ? '1' : '0');
break;
-
-
+
+
case NODE_TYPE_CONFIG_LEAF_BUZZER_FRIENDLY_NAME:
if ((length = NVConfigStore::GetDeviceName(PM_DEVICE_TYPE_BUZZER, instance_id, response_data_buf, response_data_buf_len)) > 0)
generate_response_data_addlen(length);
@@ -360,7 +381,7 @@ void generate_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t inst
utoa(Device_Buzzer::GetPin(parent_instance_id), response_data_buf, 10);
generate_response_data_addlen(strlen(response_data_buf));
break;
-
+
case NODE_TYPE_CONFIG_LEAF_HEATER_FRIENDLY_NAME:
if ((length = NVConfigStore::GetDeviceName(PM_DEVICE_TYPE_HEATER, instance_id, response_data_buf, response_data_buf_len)) > 0)
generate_response_data_addlen(length);
@@ -389,7 +410,7 @@ void generate_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t inst
generate_response_data_addbyte(Device_Heater::GetPidFunctionalRange(parent_instance_id));
break;
// TODO add other heater config
-
+
// Statistics Related
case NODE_TYPE_STATS_LEAF_RX_PACKET_COUNT:
{
@@ -431,14 +452,14 @@ void generate_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t inst
send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
PMSG(MSG_ERR_CANNOT_HANDLE_FIRMWARE_CONFIG_REQUEST), __LINE__);
return;
- }
+ }
generate_response_send();
}
-
+
bool set_uint8_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t instance_id, uint8_t value)
-{
+{
uint8_t retval;
switch (node_type)
{
@@ -459,7 +480,7 @@ bool set_uint8_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t ins
case NODE_TYPE_CONFIG_LEAF_SYSTEM_HARDWARE_REV:
retval = NVConfigStore::SetHardwareRevision(value);
break;
-
+
case NODE_TYPE_CONFIG_LEAF_SYSTEM_NUM_INPUT_SWITCHES:
retval = Device_InputSwitch::Init(value);
break;
@@ -481,7 +502,7 @@ bool set_uint8_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t ins
case NODE_TYPE_CONFIG_LEAF_SYSTEM_NUM_STEPPERS:
retval = Device_Stepper::Init(value);
break;
-
+
case NODE_TYPE_CONFIG_LEAF_OUTPUT_SWITCH_INITIAL_STATE:
retval = Device_OutputSwitch::SetInitialState(parent_instance_id, value);
break;
@@ -499,22 +520,22 @@ bool set_uint8_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t ins
retval = Device_Heater::SetPidFunctionalRange(parent_instance_id, value);
break;
- default:
+ default:
send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
PMSG(MSG_ERR_CANNOT_HANDLE_FIRMWARE_CONFIG_REQUEST), __LINE__);
return false;
}
-
+
if (retval == APP_ERROR_TYPE_SUCCESS)
return true;
-
+
generate_response_data_addbyte(retval);
generate_response_send();
return false;
}
bool set_int16_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t instance_id, int16_t value)
-{
+{
uint8_t retval;
switch (node_type)
@@ -526,23 +547,23 @@ bool set_int16_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t ins
case NODE_TYPE_CONFIG_LEAF_TEMP_SENSOR_TYPE:
retval = Device_TemperatureSensor::SetType(parent_instance_id, value);
break;
-
- default:
+
+ default:
send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
PMSG(MSG_ERR_CANNOT_HANDLE_FIRMWARE_CONFIG_REQUEST), __LINE__);
return false;
}
-
+
if (retval == APP_ERROR_TYPE_SUCCESS)
return true;
-
+
generate_response_data_addbyte(retval);
generate_response_send();
return false;
}
bool set_bool_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t instance_id, bool value)
-{
+{
uint8_t retval;
switch (node_type)
@@ -553,7 +574,7 @@ bool set_bool_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t inst
case NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_ENABLE_PULLUP:
retval = Device_InputSwitch::SetEnablePullup(parent_instance_id, value);
break;
-
+
case NODE_TYPE_CONFIG_LEAF_PWM_OUTPUT_USE_SOFT_PWM:
retval = Device_PwmOutput::EnableSoftPwm(parent_instance_id, value);
break;
@@ -573,7 +594,7 @@ bool set_bool_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t inst
else
retval = APP_ERROR_TYPE_SUCCESS;
break;
-
+
case NODE_TYPE_CONFIG_LEAF_STEPPER_ENABLE_INVERT:
retval = Device_Stepper::SetEnableInvert(parent_instance_id, value);
break;
@@ -584,26 +605,26 @@ bool set_bool_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t inst
retval = Device_Stepper::SetStepInvert(parent_instance_id, value);
break;
- default:
+ default:
send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
PMSG(MSG_ERR_CANNOT_HANDLE_FIRMWARE_CONFIG_REQUEST), __LINE__);
return false;
}
-
+
if (retval == APP_ERROR_TYPE_SUCCESS)
return true;
-
+
generate_response_data_addbyte(retval);
generate_response_send();
return false;
}
bool set_string_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t instance_id, const char *value)
-{
+{
uint8_t retval;
generate_response_start(RSP_APPLICATION_ERROR, 1);
-
+
switch (node_type)
{
case NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_FRIENDLY_NAME:
@@ -650,12 +671,12 @@ bool set_string_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t in
case NODE_TYPE_CONFIG_LEAF_SYSTEM_BOARD_SERIAL_NUM:
retval = NVConfigStore::SetBoardSerialNumber(value);
break;
-
+
case NODE_TYPE_CONFIG_LEAF_HEATER_PID_DO_AUTOTUNE:
{
char *end;
long temp, cycles;
- if ((temp = strtol(value, &end, 10)) == 0 || *end != ',' ||
+ if ((temp = strtol(value, &end, 10)) == 0 || *end != ',' ||
(cycles = strtol(end+1, &end, 10)) == 0 || *end != '\0')
{
generate_response_data_addbyte(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_FORMAT);
@@ -674,27 +695,27 @@ bool set_string_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t in
send_OK_response(); // send response now as it takes a while to complete
Device_Heater::DoPidAutotune(parent_instance_id, temp, cycles);
return false;
- }
+ }
case NODE_TYPE_OPERATION_LEAF_RESET_EEPROM:
NVConfigStore::WriteDefaults(true);
retval = APP_ERROR_TYPE_SUCCESS;
break;
- default:
+ default:
send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
PMSG(MSG_ERR_CANNOT_HANDLE_FIRMWARE_CONFIG_REQUEST), __LINE__);
return false;
}
-
+
if (retval == APP_ERROR_TYPE_SUCCESS)
return true;
-
+
generate_response_data_addbyte(retval);
generate_response_send();
return false;
}
bool set_float_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t instance_id, float value)
-{
+{
uint8_t retval;
switch (node_type)
@@ -709,15 +730,15 @@ bool set_float_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t ins
retval = Device_Heater::SetPidDefaultKd(parent_instance_id, value);
break;
- default:
+ default:
send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
PMSG(MSG_ERR_CANNOT_HANDLE_FIRMWARE_CONFIG_REQUEST), __LINE__);
return false;
}
-
+
if (retval == APP_ERROR_TYPE_SUCCESS)
return true;
-
+
generate_response_data_addbyte(retval);
generate_response_send();
return false;
@@ -726,29 +747,29 @@ bool set_float_value(uint8_t node_type, uint8_t parent_instance_id, uint8_t ins
bool setPin(uint8_t node_type, uint8_t device_number, uint8_t pin)
{
uint8_t retval = false;
-
+
switch (node_type)
{
case NODE_TYPE_CONFIG_LEAF_INPUT_SWITCH_PIN:
retval = Device_InputSwitch::SetPin(device_number, pin);
break;
-
+
case NODE_TYPE_CONFIG_LEAF_OUTPUT_SWITCH_PIN:
retval = Device_OutputSwitch::SetPin(device_number, pin);
break;
-
+
case NODE_TYPE_CONFIG_LEAF_PWM_OUTPUT_PIN:
retval = Device_PwmOutput::SetPin(device_number, pin);
break;
-
+
case NODE_TYPE_CONFIG_LEAF_BUZZER_PIN:
retval = Device_Buzzer::SetPin(device_number, pin);
break;
-
+
case NODE_TYPE_CONFIG_LEAF_TEMP_SENSOR_PIN:
retval = Device_TemperatureSensor::SetPin(device_number, pin);
break;
-
+
case NODE_TYPE_CONFIG_LEAF_HEATER_PIN:
retval = Device_Heater::SetHeaterPin(device_number, pin);
break;
@@ -765,12 +786,12 @@ bool setPin(uint8_t node_type, uint8_t device_number, uint8_t pin)
retval = Device_Stepper::SetStepPin(device_number, pin);
break;
- default:
+ default:
send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
PMSG(MSG_ERR_CANNOT_HANDLE_FIRMWARE_CONFIG_REQUEST), __LINE__);
return false;
- }
-
+ }
+
if (retval == APP_ERROR_TYPE_SUCCESS)
return true;
@@ -783,7 +804,7 @@ bool setPin(uint8_t node_type, uint8_t device_number, uint8_t pin)
void update_firmware_configuration(bool final)
{
uint8_t i;
-
+
// For the steppers, we delay pin initialization to allow the invert state
// to be set.
for (i = 0; i < Device_Stepper::GetNumDevices(); i++)
@@ -806,16 +827,16 @@ void apply_initial_configuration()
#ifdef START_MINNOW_INITIAL_CONFIGURATION
const char *pstr = boot_configuration_string;
const char *pstr_end = boot_configuration_string + sizeof(boot_configuration_string);
-
+
while (pstr < pstr_end)
{
// there are multiple substrings within the whole boot_configuration_string/.
// find the length of the next command.
apply_firmware_configuration_string_P(pstr);
-
+
pstr += strlen_P(pstr) + 1;
}
-#endif
+#endif
}
void apply_firmware_configuration_string_P(const char *pstr)
@@ -823,42 +844,42 @@ void apply_firmware_configuration_string_P(const char *pstr)
extern uint16_t recv_buf_len;
extern uint8_t recv_buf[MAX_RECV_BUF_LEN];
- // Note: this function overwrites recv_buf contents so it is primarily intended for
+ // Note: this function overwrites recv_buf contents so it is primarily intended for
// development & boot time usage
- char * const buf_start = (char *)&recv_buf[PM_PARAMETER_OFFSET]; // just to preserve header information
+ char * const buf_start = (char *)&recv_buf[PM_PARAMETER_OFFSET]; // just to preserve header information
recv_buf_len = 0;
// copy next command into recv_buf
// (we use one less than the size so that the last byte of recv_buf buffer always remains zero)
- strncpy_P(buf_start, pstr, sizeof(recv_buf) - PM_PARAMETER_OFFSET - 1);
-
+ strncpy_P(buf_start, pstr, sizeof(recv_buf) - PM_PARAMETER_OFFSET - 1);
+
const char *value = 0;
char *ptr = buf_start;
char ch;
-
+
// find end of name
- while ((ch = *ptr) != '\0' && ch != ' ' && ch != '=')
+ while ((ch = *ptr) != '\0' && ch != ' ' && ch != '=')
ptr += 1;
if (ptr == buf_start || buf_start[0] == '#')
return; // comment or blank line.
-
+
// find end of name/value separator
if (ch != '\0')
{
*ptr = '\0'; // make name null terminated
-
+
ptr += 1;
- while ((ch = *ptr) == '\0' || ch == ' ' || ch == '=')
+ while ((ch = *ptr) == '\0' || ch == ' ' || ch == '=')
ptr += 1;
- }
-
+ }
+
value = ptr;
-
+
// find end of value
- while (*ptr != '\0')
+ while (*ptr != '\0')
ptr += 1;
-
+
DEBUGPGM("Applying firmware configuration: ");
DEBUG(buf_start);
DEBUG_CH('=');
@@ -874,15 +895,15 @@ void apply_firmware_configuration_string_P(const char *pstr)
handle_firmware_configuration_request(buf_start, value);
if (reply_header[PM_ORDER_BYTE_OFFSET] == RSP_OK)
{
- DEBUGLNPGM("ok");
+ DEBUGLNPGM("ok");
}
else
{
- DEBUGPGM("failed (code=");
+ DEBUGPGM("failed (code=");
DEBUG((int)reply_buf[0]);
if (reply_msg_len > 0)
{
- DEBUGPGM(" ,reason=");
+ DEBUGPGM(" ,reason=");
reply_buf[reply_msg_len + 1] = '\0';
DEBUG((char *)&reply_buf[1]);
}
@@ -890,7 +911,7 @@ void apply_firmware_configuration_string_P(const char *pstr)
DEBUG_EOL();
}
response_squelch = false;
-
+
}
@@ -901,8 +922,57 @@ void apply_firmware_configuration_string_P(const char *pstr)
bool read_number(long &number, const char *value)
{
char *end;
- number = strtol(value, &end, 10);
+ number = strtol(value, &end, 10);
if (end == value || *end != '\0')
return false;
return true;
}
+
+bool read_pin(long &number, const char *value)
+{
+ // Analog pins are defined as A0 to A15 in pins_arduino.h
+ char *end;
+ if(('A' == *value) || ('a' == *value))
+ {
+ // analog pin (A0 to A15)
+ switch(*(value +1))
+ {
+ case '0': number = A0; return true;
+ case '1':
+ switch(*(value +2))
+ {
+ case '\0' : number = A1; return true;
+ case '0': number = A10; return true;
+ case '1': number = A11; return true;
+ case '2': number = A12; return true;
+ case '3': number = A13; return true;
+ case '4': number = A14; return true;
+ case '5': number = A15; return true;
+ default : number = 502; return false;
+ }
+ case '2': number = A2; return true;
+ case '3': number = A3; return true;
+ case '4': number = A4; return true;
+ case '5': number = A5; return true;
+ case '6': number = A6; return true;
+ case '7': number = A7; return true;
+ case '8': number = A8; return true;
+ case '9': number = A9; return true;
+ default : number = 501; return false;
+ }
+ }
+ else
+ {
+ // digital Pin
+ number = strtol(value, &end, 10);
+ if (end == value || *end != '\0')
+ {
+ number = 500;
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+}
diff --git a/Minnow/hooks.c b/Minnow/hooks.c
new file mode 100644
index 0000000..460ef8c
--- /dev/null
+++ b/Minnow/hooks.c
@@ -0,0 +1,36 @@
+/*
+ Copyright (c) 2012 Arduino. All right reserved.
+
+ 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
+*/
+
+#include "hooks.h"
+
+/**
+ * Empty yield() hook.
+ *
+ * This function is intended to be used by library writers to build
+ * libraries or sketches that supports cooperative threads.
+ *
+ * Its defined as a weak symbol and it can be redefined to implement a
+ * real cooperative scheduler.
+ */
+static void __empty() {
+ // Empty
+}
+
+void yield(void)
+{
+}
diff --git a/Minnow/hooks.h b/Minnow/hooks.h
new file mode 100644
index 0000000..e536333
--- /dev/null
+++ b/Minnow/hooks.h
@@ -0,0 +1,15 @@
+/*
+ * hooks.h
+ *
+ * Created on: 05.09.2015
+ * Author: lars
+ */
+
+#ifndef HOOKS_H_
+#define HOOKS_H_
+
+void yield(void) __attribute__ ((weak));
+
+
+
+#endif /* HOOKS_H_ */
diff --git a/Minnow/main.cpp b/Minnow/main.cpp
new file mode 100644
index 0000000..434cd40
--- /dev/null
+++ b/Minnow/main.cpp
@@ -0,0 +1,52 @@
+/*
+ main.cpp - Main loop for Arduino sketches
+ Copyright (c) 2005-2013 Arduino Team. All right reserved.
+
+ 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
+*/
+
+#include
+
+// Declared weak in Arduino.h to allow user redefinitions.
+int atexit(void (* /*func*/ )()) { return 0; }
+
+// Weak empty variant initialization function.
+// May be redefined by variant files.
+void initVariant() __attribute__((weak));
+void initVariant() { }
+
+void setupUSB() __attribute__((weak));
+void setupUSB() { }
+
+int main(void)
+{
+ init();
+
+ initVariant();
+
+#if defined(USBCON)
+ USBDevice.attach();
+#endif
+
+ setup();
+
+ for (;;) {
+ loop();
+ if (serialEventRun) serialEventRun();
+ }
+
+ return 0;
+}
+
diff --git a/Minnow/movement_ISR.cpp b/Minnow/movement_ISR.cpp
index 2329232..c5baaed 100644
--- a/Minnow/movement_ISR.cpp
+++ b/Minnow/movement_ISR.cpp
@@ -20,7 +20,7 @@
// Movement Design Description
//
-// Like Marlin or Grbl, Minnow uses trapezoid speed curves to drive the steppers
+// Like Marlin or Grbl, Minnow uses trapezoid speed curves to drive the steppers
//
// __________________________
// /| |\ _________________ ^
@@ -30,7 +30,7 @@
// / | | | | | \ e
// +-----+------------------------+---+--+---------------+----+ e
// |Phase1 Phase2 Phase3| | d
-// | BLOCK 1 | BLOCK 2 |
+// | BLOCK 1 | BLOCK 2 |
// time ----->
//
// The trapezoid is the shape the speed curve over time. It starts at initial_rate, accelerates
@@ -39,31 +39,31 @@
//
// Minnow does not hardcode the number of axes or stepper pins and therefore the inner step loop
// uses slightly more instructions to complete however this is mitigated because:
-// - it can still support 40000 steps per second (as per Marlin/Grbl).
-// - all step inputs and output registers are precalculated to minimize execution time (so
+// - it can still support 40000 steps per second (as per Marlin/Grbl).
+// - all step inputs and output registers are precalculated to minimize execution time (so
// it is fairly close to hard-coded output times anyway)
// - efficient block transmission and queuing means that high rates of small step blocks can be
-// maintained without motion-planning becoming the bottle-neck (especially a problem with
+// maintained without motion-planning becoming the bottle-neck (especially a problem with
// non-cartesian co-ordinate systems).
-// - speed calculation is only done once per ISR invocaton as normal (i.e., regardless of number
+// - speed calculation is only done once per ISR invocaton as normal (i.e., regardless of number
// of axes) and is very similar to Marlin/Grbl.
-// - step spacing consistency is maximized because the current movement steps are output
+// - step spacing consistency is maximized because the current movement steps are output
// before the step interval is recalculated for the next step (and therefore the effect
// of any differences in recalculation time are minimized).
-// - far less non-movement ISR CPU time is needed as there is no motion planning required
-// - the underrun avoidance algorithm also avoids lengthy calculations and the extra logic is
-// only used in abnormal operating cases when the system needs to be slowed down due
+// - far less non-movement ISR CPU time is needed as there is no motion planning required
+// - the underrun avoidance algorithm also avoids lengthy calculations and the extra logic is
+// only used in abnormal operating cases when the system needs to be slowed down due
// to a lack of input data anyway.
//
// Underrun Avoidance Algorithm Description
// ----------------------------------------
//
-// The Underrun Avoidance Algorithm will slow the movement down to lesser of the nominal underrun
-// rate for the primary axis and the requested nominal rate.
+// The Underrun Avoidance Algorithm will slow the movement down to lesser of the nominal underrun
+// rate for the primary axis and the requested nominal rate.
// The movement is changed to always accelerate up/down to this speed until the system approaches
-// the end of the movement block. The LinearMoveCommand block includes a precalculated
+// the end of the movement block. The LinearMoveCommand block includes a precalculated
// step count required to decelerate from the expected underrun rate to the final speed (when that
-// is less than the nominal rate).
+// is less than the nominal rate).
//
// The underrun avoidance algorithm must also ensure that system comes to a complete stop if the
// block has a non-zero final speed but there are no more movement blocks. This is again accomplished
@@ -73,16 +73,16 @@
// When the underrun condition is cleared, the system will accelerate to the normal nominal rate.
// Once achieved, it will exit underrun mode. The trickiest part is working out when to start
// decelerating if the nominal speed is not reached before approaching the end of the block.
-// If the system does not reach the nominal rate before phase 3, it will begin decelerating to the
-// nominal underrun rate. From that speed the system knows when it must decelerate to reach the
-// final rate (again using the precalculated step count).
+// If the system does not reach the nominal rate before phase 3, it will begin decelerating to the
+// nominal underrun rate. From that speed the system knows when it must decelerate to reach the
+// final rate (again using the precalculated step count).
//
-// The corner case here is if the system hasn't reached the nominal underrun rate and the remaining
+// The corner case here is if the system hasn't reached the nominal underrun rate and the remaining
// steps are less than that which is required to decelerate from the underrun rate to the final rate.
-// In this (rare) case, the system will simply decelerate to the final rate. If the final rate is
+// In this (rare) case, the system will simply decelerate to the final rate. If the final rate is
// reached before the end of the block then the system will "hop" to the end by accelerating for half
-// the remaining steps and then decelerating again for the second half of the remaining steps -
-// thereby reaching the end of the block at the required exit speed. The system will then exit
+// the remaining steps and then decelerating again for the second half of the remaining steps -
+// thereby reaching the end of the block at the required exit speed. The system will then exit
// underrun mode for the next block.
#include
@@ -110,7 +110,7 @@
// queue statics placed in this compilation unit to allow better optimization
uint8_t *CommandQueue::queue_buffer = 0;
uint16_t CommandQueue::queue_buffer_length = 0;
-
+
volatile uint8_t *CommandQueue::queue_head = 0;
volatile uint8_t *CommandQueue::queue_tail = 0; // ISR will never change this value
@@ -126,8 +126,8 @@ bool is_checkpoint_last; // is last movement command in queue a checkpoint?
// Function declarations
FORCE_INLINE void movement_ISR(); // needs to be non-static due to friend usage elsewhere
FORCE_INLINE bool handle_queue_command(); // needs to be non-static due to friend usage elsewhere
-FORCE_INLINE bool handle_linear_move();
-FORCE_INLINE bool handle_delay_command();
+FORCE_INLINE bool handle_linear_move();
+FORCE_INLINE bool handle_delay_command();
FORCE_INLINE void setup_new_move();
FORCE_INLINE void update_directions_and_initial_counts();
FORCE_INLINE bool check_endstops();
@@ -169,10 +169,10 @@ static uint8_t nominal_rate_step_loops;
static uint16_t initial_rate;
static uint16_t final_rate;
-static uint16_t nominal_block_time;
+static uint16_t nominal_block_time;
// queue counts(not including current block)
-static uint32_t queued_microseconds_remaining;
+static uint32_t queued_microseconds_remaining;
static uint32_t queued_steps_remaining;
// Underrun avoidance state
@@ -189,7 +189,6 @@ static uint32_t underrun_acceleration_rate; // underrun acceleration rate for cu
// Endstop State
static BITMASK(MAX_ENDSTOPS) endstops_to_check;
-static BITMASK(MAX_ENDSTOPS) endstop_hit;
static BITMASK(MAX_ENDSTOPS) stopped_axes;
// General state
@@ -214,7 +213,7 @@ uint32_t isr_elasped_time; // accumulative elapsed time when movement is being p
// Routines
//
-void movement_ISR_init()
+void movement_ISR_init()
{
// waveform generation = 0100 = CTC
TCCR1B &= ~(1<= CommandQueue::queue_buffer + CommandQueue::queue_buffer_length)
+ if (queue_head >= CommandQueue::queue_buffer + CommandQueue::queue_buffer_length)
{
#if QUEUE_DEBUG
if (CommandQueue::queue_head > CommandQueue::queue_buffer + CommandQueue::queue_buffer_length)
ERRORLNPGM("queue ran off the end");
- #endif
+ #endif
queue_head = CommandQueue::queue_buffer;
CommandQueue::queue_head = queue_head;
}
@@ -373,11 +372,11 @@ FORCE_INLINE void movement_ISR()
// get the length of the next command
length = *queue_head;
CommandQueue::in_progress_length = length;
-
+
if (length == 0)
{
// this is a skip marker
-
+
// anything left in queue after the skip marker?
if (queue_tail > queue_head)
{
@@ -385,19 +384,19 @@ FORCE_INLINE void movement_ISR()
#if QUEUE_DEBUG
if (queue_tail != CommandQueue::queue_buffer + CommandQueue::queue_buffer_length)
ERRORLNPGM("unexpected tail position");
- #endif
+ #endif
queue_head = queue_tail;
- CommandQueue::queue_head = queue_head;
+ CommandQueue::queue_head = queue_head;
}
else
{
// next command is at start of buffer
queue_head = CommandQueue::queue_buffer;
- CommandQueue::queue_head = queue_head;
+ CommandQueue::queue_head = queue_head;
}
continue;
}
-
+
// we have the next command to execute.
CommandQueue::total_attempted_queue_command_count += 1;
cmd_start_cnt += 1;
@@ -416,27 +415,27 @@ FORCE_INLINE void movement_ISR()
DEBUG(CommandQueue::current_queue_command_count);
DEBUGPGM(" tcc=");
DEBUGLN(CommandQueue::total_attempted_queue_command_count);
- #endif
-
+ #endif
+
// this is a bit ugly but saves on a massive duplication of inline code
- goto do_handle_queue_command;
+ goto do_handle_queue_command;
}
}
FORCE_INLINE bool handle_queue_command()
{
int8_t i;
-
+
// start command processing
switch (*command_in_progress)
{
case QUEUE_COMMAND_STRUCTS_TYPE_DELAY:
{
if (!continuing)
- {
+ {
const DelayQueueCommand *cmd = (const DelayQueueCommand*)command_in_progress;
- tmp_uint32 = micros() + cmd->delay;
+ tmp_uint32 = micros() + cmd->delay;
}
return handle_delay_command();
}
@@ -451,19 +450,19 @@ FORCE_INLINE bool handle_queue_command()
if (Device_OutputSwitch::output_switch_disabled[device_info->device_number])
{
// expect enabling/disabling a pin is not a common operation - so this not currently optimized
- pinMode(Device_OutputSwitch::output_switch_pins[device_info->device_number],OUTPUT);
+ pinMode(Device_OutputSwitch::output_switch_pins[device_info->device_number],OUTPUT);
Device_OutputSwitch::output_switch_disabled[device_info->device_number] = false;
}
volatile uint8_t *output_reg = device_info->device_reg;
if (device_info->device_state == OUTPUT_SWITCH_STATE_LOW)
- *output_reg &= ~device_info->device_bit;
+ *output_reg &= ~device_info->device_bit;
else
*output_reg |= device_info->device_bit;
}
else
{
// expect enabling/disabling a pin is not a common operation - so this not currently optimized
- pinMode(Device_OutputSwitch::output_switch_pins[device_info->device_number],INPUT);
+ pinMode(Device_OutputSwitch::output_switch_pins[device_info->device_number],INPUT);
Device_OutputSwitch::output_switch_disabled[device_info->device_number] = true;
}
device_info += 1;
@@ -550,7 +549,7 @@ FORCE_INLINE bool handle_queue_command()
if (command_in_progress[2] != CommandQueue::in_progress_length - 3)
ERRORLNPGM("Incorrect payload length in long queue test");
return false;
-#endif
+#endif
default:
ERRORPGM("Unknown cmd in ISR: cmd=");
ERRORLN((int)*command_in_progress);
@@ -568,13 +567,13 @@ FORCE_INLINE bool handle_delay_command()
else
{
if (delay > IDLE_INTERRUPT_RATE / 2) // assumes 2Mhz counter frequency
- OCR1A = IDLE_INTERRUPT_RATE;
+ OCR1A = IDLE_INTERRUPT_RATE;
else
OCR1A = max(delay * 2, 10L);
return true;
}
}
-
+
FORCE_INLINE bool handle_linear_move()
{
if (!continuing)
@@ -582,18 +581,15 @@ FORCE_INLINE bool handle_linear_move()
setup_new_move();
update_directions_and_initial_counts();
}
- else
+ else
{
if (step_events_remaining == 0)
return false; // finished
}
-
- if (endstops_to_check != 0)
- {
- if (!check_endstops())
- return false; // finished
- }
-
+
+ if (!check_endstops())
+ return false; // finished
+
for(int8_t i=0; i < step_loops; i++) // Take multiple steps per interrupt (For high speed moves)
{
#ifndef AT90USB
@@ -601,22 +597,22 @@ FORCE_INLINE bool handle_linear_move()
#endif
write_steps();
-
+
if (--step_events_remaining == 0)
- break;
+ return false; // finished
}
-
+
// recalculation is done after outputting the current steps to achieve greatest step consistency
- // (the counter is already running, what we are doing here is calculating the
+ // (the counter is already running, what we are doing here is calculating the
// point at which it next triggers an interrupt and resets)
recalculate_speed();
return true;
-}
-
+}
+
FORCE_INLINE void setup_new_move()
{
const LinearMoveCommand *cmd = (LinearMoveCommand *)command_in_progress;
-
+
num_axes = cmd->num_axes;
total_step_events = cmd->total_steps;
step_events_remaining = total_step_events;
@@ -624,7 +620,7 @@ FORCE_INLINE void setup_new_move()
in_phase_1 = true;
in_phase_2 = false;
in_phase_3 = false;
- initial_rate = final_rate;
+ initial_rate = final_rate;
final_rate = cmd->final_rate;
nominal_rate = cmd->nominal_rate;
nominal_block_time = cmd->nominal_block_time;
@@ -632,13 +628,21 @@ FORCE_INLINE void setup_new_move()
accel_start_rate = initial_rate;
start_axis_move_info = cmd->axis_move_info;
stopped_axes = 0;
- endstops_to_check = cmd->endstops_of_interest & AxisInfo::endstop_enable_state;
+ if(cmd->homing_bit)
+ {
+ // during homing all end stops are enabled !
+ endstops_to_check = cmd->endstops_of_interest;
+ }
+ else
+ {
+ endstops_to_check = cmd->endstops_of_interest & AxisInfo::endstop_enable_state;
+ }
queued_microseconds_remaining -= nominal_block_time;
queued_steps_remaining -= total_step_events;
-
+
// currently only check for underrun condition at the start of the block
- // (although underrun_condition might be cleared during block if more
+ // (although underrun_condition might be cleared during block if more
// movement blocks are enqueued).
underrun_condition = check_underrun_condition();
if (!underrun_active && !underrun_condition)
@@ -648,9 +652,9 @@ FORCE_INLINE void setup_new_move()
}
else
{
- if (!underrun_condition &&
- (int16_t)(step_rate - initial_rate) <= ALLOWED_SPEED_DIFF &&
- (int16_t)(step_rate - initial_rate) >= -ALLOWED_SPEED_DIFF)
+ if (!underrun_condition &&
+ (int16_t)(step_rate - initial_rate) <= ALLOWED_SPEED_DIFF &&
+ (int16_t)(step_rate - initial_rate) >= -ALLOWED_SPEED_DIFF)
{
// can exit underrun mode immediately.
underrun_active = false;
@@ -659,12 +663,12 @@ FORCE_INLINE void setup_new_move()
}
else
{
- // leave step_rate and step_loops unchanged but recalculate underrun rates and reset
+ // leave step_rate and step_loops unchanged but recalculate underrun rates and reset
// necessary state for block
setup_underrun_mode();
}
}
-
+
#if TRACE_MOVEMENT
// Emitting debug in the ISR is less than ideal - it can cause CRC errors
DEBUGPGM("New ISR move: axes:");
@@ -692,7 +696,6 @@ FORCE_INLINE void setup_new_move()
DEBUGPGM("/");
DEBUG_F(AxisInfo::endstop_enable_state,HEX);
DEBUGPGM("/");
- DEBUG_F(endstop_hit,HEX);
DEBUGPGM(", dirs:");
DEBUG_F(cmd->directions,HEX);
DEBUGPGM(", loops:");
@@ -710,7 +713,7 @@ FORCE_INLINE void setup_new_move()
DEBUGPGM(", stop?:");
DEBUG(come_to_stop_and_flush_queue);
DEBUG_EOL();
-#endif //TRACE_MOVEMENT
+#endif //TRACE_MOVEMENT
}
FORCE_INLINE void update_directions_and_initial_counts()
@@ -722,7 +725,7 @@ FORCE_INLINE void update_directions_and_initial_counts()
{
AxisInfoInternal *axis_info = axis_move_info->axis_info;
BITMASK(MAX_STEPPERS) axis_bit = (1 << axis_info->stepper_number);
-
+
#if TRACE_MOVEMENT
DEBUGPGM(" AMI[");
DEBUG(num_axes - cnt);
@@ -733,7 +736,7 @@ FORCE_INLINE void update_directions_and_initial_counts()
if (cnt == 1)
DEBUG_EOL();
#endif
-
+
// enable stepper if not already enabled
if ((AxisInfo::stepper_enable_state & axis_bit) == 0)
{
@@ -743,9 +746,9 @@ FORCE_INLINE void update_directions_and_initial_counts()
*((volatile uint8_t *)axis_info->stepper_enable_reg) &= ~(axis_info->stepper_enable_bit);
AxisInfo::stepper_enable_state |= axis_bit;
}
-
+
// set starting count (the extra -1 prevents rollover in the 0xFFFF step count case)
- axis_info->step_event_counter = -(total_step_events >> 1) - 1;
+ axis_info->step_event_counter = -(total_step_events >> 1) - 1;
// update directions
if (((uint8_t)directions & 1) != 0)
@@ -777,15 +780,14 @@ FORCE_INLINE void update_directions_and_initial_counts()
axis_move_info++;
directions >>= 1;
}
-}
-
+}
+
FORCE_INLINE bool check_endstops()
{
const LinearMoveCommand *cmd = (LinearMoveCommand *)command_in_progress;
uint8_t index = 0;
- uint16_t directions = cmd->directions;
BITMASK(MAX_ENDSTOPS) local_endstops_to_check = endstops_to_check;
-
+ // DEBUGLN(endstops_to_check);
while (local_endstops_to_check != 0)
{
while (((uint8_t)local_endstops_to_check & 1) == 0)
@@ -793,10 +795,10 @@ FORCE_INLINE bool check_endstops()
local_endstops_to_check >>= 1;
index++;
}
-
+
BITMASK(MAX_ENDSTOPS) endstop_bit = 1 << index;
bool new_endstop_hit = Device_InputSwitch::ReadState(index);
- if (new_endstop_hit && (endstop_hit & endstop_bit))
+ if (new_endstop_hit)
{
if (cmd->homing_bit)
{
@@ -806,31 +808,25 @@ FORCE_INLINE bool check_endstops()
while (true)
{
AxisInfoInternal *axis_info = axis_move_info->axis_info;
- if ((directions & (1<stepper_number)) == 0)
+ if ((axis_info->min_endstops_configured & endstop_bit) != 0)
{
- if ((axis_info->min_endstops_configured & endstop_bit) != 0)
- {
- // stop this axis - keep others going
- if (axis_move_info->step_count != 0)
- stopped_axes += 1;
- ((AxisMoveInfo *)axis_move_info)->step_count = 0;
- axis_info->step_event_counter = -1;
- if (stopped_axes == num_axes)
- return false;
- }
+ // stop this axis - keep others going
+ if (axis_move_info->step_count != 0)
+ stopped_axes += 1;
+ ((AxisMoveInfo *)axis_move_info)->step_count = 0;
+ axis_info->step_event_counter = -1;
+ if (stopped_axes == num_axes)
+ return false;
}
- else
+ if ((axis_info->max_endstops_configured & endstop_bit) != 0)
{
- if ((axis_info->max_endstops_configured & endstop_bit) != 0)
- {
- // stop this axis - keep others going
- if (axis_move_info->step_count != 0)
- stopped_axes += 1;
- ((AxisMoveInfo *)axis_move_info)->step_count = 0;
- axis_info->step_event_counter = -1;
- if (stopped_axes == num_axes)
- return false;
- }
+ // stop this axis - keep others going
+ if (axis_move_info->step_count != 0)
+ stopped_axes += 1;
+ ((AxisMoveInfo *)axis_move_info)->step_count = 0;
+ axis_info->step_event_counter = -1;
+ if (stopped_axes == num_axes)
+ return false;
}
if (--cnt == 0)
break;
@@ -846,11 +842,6 @@ FORCE_INLINE bool check_endstops()
return false;
}
}
- if (new_endstop_hit)
- endstop_hit |= endstop_bit;
- else
- endstop_hit &= ~endstop_bit;
-
local_endstops_to_check >>= 1;
index++;
}
@@ -866,7 +857,7 @@ FORCE_INLINE void write_steps()
{
axis_info = axis_move_info->axis_info;
axis_info->step_event_counter += axis_move_info->step_count;
- if (axis_info->step_event_counter >= 0)
+ if (axis_info->step_event_counter >= 0)
{
volatile uint8_t *step_reg = axis_info->stepper_step_reg;
if (!axis_info->stepper_step_invert)
@@ -884,25 +875,25 @@ FORCE_INLINE void write_steps()
// (which should be long enough)
axis_info->step_event_counter -= total_step_events;
*step_reg |= axis_info->stepper_step_bit;
- }
+ }
}
if (--cnt == 0)
break;
axis_move_info++;
}
-}
+}
FORCE_INLINE void recalculate_speed()
-{
+{
const LinearMoveCommand *cmd = (const LinearMoveCommand *)command_in_progress;
-
+
if (underrun_active || come_to_stop_and_flush_queue)
{
// do underrun avoidance handling
handle_underrun_condition();
return;
}
-
+
// check if we need to move to the next movement phase
if (in_phase_1 && step_events_remaining <= step_events_next_phase
&& step_events_remaining > cmd->steps_phase_3)
@@ -915,13 +906,13 @@ FORCE_INLINE void recalculate_speed()
}
else if (!in_phase_3 && step_events_remaining <= step_events_next_phase)
{ // this also handles the case where there is no phase 2.
- in_phase_1 = false;
+ in_phase_1 = false;
in_phase_2 = false;
in_phase_3 = true;
acceleration_time = 0;
accel_start_rate = step_rate;
}
-
+
// normal system operation
if (in_phase_1)
{
@@ -931,7 +922,7 @@ FORCE_INLINE void recalculate_speed()
acceleration_time = timer;
accel_start_rate = step_rate;
}
-
+
// phase 1: accelerate from initial_rate to nominal_rate
MultiU24X24toH16(step_rate, acceleration_time, cmd->acceleration_rate);
step_rate += accel_start_rate;
@@ -953,15 +944,15 @@ FORCE_INLINE void recalculate_speed()
acceleration_time = timer;
accel_start_rate = step_rate;
}
-
+
// phase 3: decelerate from nominal_rate to final_rate
MultiU24X24toH16(step_rate, acceleration_time, cmd->deceleration_rate);
- if(step_rate > accel_start_rate)
+ if(step_rate > accel_start_rate)
{ // Check step_rate stays positive
step_rate = final_rate;
}
- else
+ else
{
step_rate = accel_start_rate - step_rate; // Decelerate from aceleration end point.
}
@@ -975,7 +966,7 @@ FORCE_INLINE void recalculate_speed()
OCR1A = timer;
acceleration_time += timer;
}
- else
+ else
{
// phase 2: maintain nominal_rate
OCR1A = nominal_rate_timer;
@@ -995,28 +986,28 @@ FORCE_INLINE bool check_underrun_condition()
if ((queue_count < AxisInfo::underrun_queue_low_level && queued_time < AxisInfo::underrun_queue_high_time)
|| queued_time < AxisInfo::underrun_queue_low_time)
return true;
-#endif
- return false;
+#endif
+ return false;
}
FORCE_INLINE void setup_underrun_mode()
{
const LinearMoveCommand *cmd = (LinearMoveCommand *)command_in_progress;
-
+
const AxisInfoInternal *primary_axis_info = start_axis_move_info[cmd->primary_axis].axis_info;
underrun_acceleration_rate = max(max(cmd->acceleration_rate, cmd->deceleration_rate),
primary_axis_info->underrun_accel_rate);
underrun_max_rate = primary_axis_info->underrun_max_rate;
steps_to_final_speed_from_underrun_rate = cmd->steps_to_final_speed_from_underrun_rate;
- steps_for_underrun_hop_to_end = 0;
+ steps_for_underrun_hop_to_end = 0;
current_underrun_accel_sign = 0;
underrun_active = true;
}
-
+
// underrun avoidance algorithm handling
//
-// there are a few different cases to cover here but none of them involve
+// there are a few different cases to cover here but none of them involve
// complex calculations
//
// remember also that the system will be operating at lower speeds normally
@@ -1025,7 +1016,7 @@ FORCE_INLINE void handle_underrun_condition()
{
uint16_t target_rate;
bool is_final_rate = false;
-
+
// is the underrun condition persisting?
if (underrun_condition)
{
@@ -1036,7 +1027,7 @@ FORCE_INLINE void handle_underrun_condition()
}
// to minimise checking in high speed cases we always decel to underrun rate first
- if (step_rate > underrun_max_rate)
+ if (step_rate > underrun_max_rate)
{
target_rate = underrun_max_rate;
}
@@ -1060,10 +1051,10 @@ FORCE_INLINE void handle_underrun_condition()
}
else
{
- target_rate = underrun_max_rate;
+ target_rate = underrun_max_rate;
}
}
- else
+ else
{
// underrun condition has cleared - time to attempt to resume normal movement
if (step_events_remaining <= steps_to_final_speed_from_underrun_rate)
@@ -1075,7 +1066,7 @@ FORCE_INLINE void handle_underrun_condition()
{
target_rate = max(final_rate, underrun_max_rate);
}
- else
+ else
{
// we aren't near the end of the block - so speed up to nominal again.
target_rate = nominal_rate;
@@ -1124,7 +1115,7 @@ FORCE_INLINE void accelerate_to_underrun_target_rate(uint16_t target_rate, bool
}
}
else if (step_rate > target_rate)
- {
+ {
if (current_underrun_accel_sign != 1)
{
// we've reach the target plateau speed from below
@@ -1168,11 +1159,11 @@ FORCE_INLINE void accelerate_to_underrun_target_rate(uint16_t target_rate, bool
{
current_underrun_accel_sign = 0;
}
-
- if (is_final_rate
+
+ if (is_final_rate
&& current_underrun_accel_sign == 0 // i.e., step_rate == target_rate
&& step_rate < underrun_max_rate // (if its higher than this rate, we'll just wait until we reach the end)
- && step_events_remaining > (uint8_t)(step_loops << 1))
+ && step_events_remaining > (uint8_t)(step_loops << 1))
{
// this is a corner case. we've reached the target speed too early and it
// is a very low speed - potentially even 0.
@@ -1243,18 +1234,18 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
timer = (unsigned short)pgm_read_word_near(table_address);
timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3);
}
- if(timer < 100)
+ if(timer < 100)
{
- timer = 100;
+ timer = 100;
#if MOVEMENT_DEBUG //(100 = 20kHz so this should never happen)
- ERROR("Stepper too high:"); ERRORLN(step_rate);
+ ERROR("Stepper too high:"); ERRORLN(step_rate);
#endif
}
return timer;
}
// this is a subset which just calcs the step_loops value
-uint8_t calc_step_loops(uint16_t my_step_rate)
+uint8_t calc_step_loops(uint16_t my_step_rate)
{
if(my_step_rate > MAX_STEP_FREQUENCY) my_step_rate = MAX_STEP_FREQUENCY;
@@ -1299,8 +1290,8 @@ void print_movement_ISR_state()
DEBUGPGM(", urun:");
DEBUG(underrun_active);
DEBUG_EOL();
-
-#if 0
+
+#if 0
if (continuing)
{
const AxisMoveInfo *axis_move_info = start_axis_move_info;
@@ -1308,7 +1299,7 @@ void print_movement_ISR_state()
while (cnt > 0)
{
AxisInfoInternal *axis_info = axis_move_info->axis_info;
-
+
DEBUGPGM(" AMI[");
DEBUG(num_axes - cnt);
DEBUGPGM("]: index:");
@@ -1320,10 +1311,10 @@ void print_movement_ISR_state()
cnt -= 1;
axis_move_info++;
}
- DEBUG_EOL();
+ DEBUG_EOL();
}
#endif
-
+
#endif //TRACE_MOVEMENT
}
@@ -1332,15 +1323,15 @@ void run_queue_test()
{
uint8_t buffer[50];
CommandQueue::Init(buffer, sizeof(buffer));
-
+
uint16_t remaining_slots;
uint16_t current_command_count;
uint16_t total_command_count;
uint8_t *ptr;
int i;
- DEBUGLNPGM("Begin test");
-
+ DEBUGLNPGM("Begin test");
+
for (i = 0; i < 1000; i++)
{
while ((ptr = CommandQueue::GetCommandInsertionPoint(1)) == 0)
@@ -1348,7 +1339,7 @@ void run_queue_test()
*ptr = QUEUE_TEST_SHORT;
if (!CommandQueue::EnqueueCommand(1))
ERRORLNPGM("Failed to short enqueue");
-
+
if (i % 59 == 0)
{
while ((ptr = CommandQueue::GetCommandInsertionPoint(5)) == 0)
@@ -1400,7 +1391,7 @@ void run_queue_test()
ERRORLNPGM("Failed to short enqueue delay");
}
}
-
+
CommandQueue::GetQueueInfo(remaining_slots, current_command_count, total_command_count);
DEBUGPGM("Info2a: slots=");
DEBUG(remaining_slots);
@@ -1441,7 +1432,7 @@ void run_queue_test()
ERRORLNPGM("Failed to short enqueue delay");
}
}
-
+
CommandQueue::GetQueueInfo(remaining_slots, current_command_count, total_command_count);
DEBUGPGM("Info3a: slots=");
DEBUG(remaining_slots);
@@ -1459,6 +1450,6 @@ void run_queue_test()
DEBUG((int)current_command_count);
DEBUGPGM(" tcc=");
DEBUGLN(total_command_count);
-#endif
+#endif
}
-#endif //if QUEUE_TEST
\ No newline at end of file
+#endif //if QUEUE_TEST
diff --git a/Minnow/order_handlers.cpp b/Minnow/order_handlers.cpp
index 4e60eaf..8031b9d 100644
--- a/Minnow/order_handlers.cpp
+++ b/Minnow/order_handlers.cpp
@@ -1,6 +1,6 @@
/*
Minnow Pacemaker client firmware.
-
+
Copyright (C) 2013 Robert Fairlie-Cuninghame
This program is free software: you can redistribute it and/or modify
@@ -19,24 +19,24 @@
//
// This file handles each of the Pacemaker Orders
-//
-
-#include "order_handlers.h"
-#include "order_helpers.h"
-#include "Minnow.h"
+//
+
+#include "order_handlers.h"
+#include "order_helpers.h"
+#include "Minnow.h"
#include "protocol.h"
#include "response.h"
#include "firmware_configuration.h"
#include "Device_InputSwitch.h"
#include "Device_OutputSwitch.h"
-#include "Device_PwmOutput.h"
-#include "Device_Heater.h"
-#include "Device_Buzzer.h"
-#include "Device_Stepper.h"
+#include "Device_PwmOutput.h"
+#include "Device_Heater.h"
+#include "Device_Buzzer.h"
+#include "Device_Stepper.h"
#include "AxisInfo.h"
-#include "NVConfigStore.h"
+#include "NVConfigStore.h"
#include "enqueue_command.h"
#include "CommandQueue.h"
@@ -103,12 +103,12 @@ void process_command()
// device.stepper.0.enable_pin=48
// device.stepper.0.enable_invert=1
// ...
- // will only result in the stepper configuration being applied when all
+ // will only result in the stepper configuration being applied when all
// attributes have been applied.
if (firmware_configuration_change_made || !final_firmware_configuration_update_done)
{
if (!final_firmware_configuration_update_done
- && (order_code == ORDER_SET_HEATER_TARGET_TEMP
+ && (order_code == ORDER_SET_HEATER_TARGET_TEMP
|| order_code == ORDER_SET_OUTPUT_SWITCH_STATE
|| order_code == ORDER_SET_PWM_OUTPUT_STATE
|| order_code == ORDER_SET_OUTPUT_TONE
@@ -131,7 +131,7 @@ void process_command()
update_firmware_configuration(false);
}
}
-
+
switch (order_code)
{
case ORDER_RESET:
@@ -225,19 +225,19 @@ void process_command()
send_app_error_response(PARAM_APP_ERROR_TYPE_UNKNOWN_ORDER, 0);
break;
}
-
+
}
-
+
void handle_resume_order()
{
if (parameter_length < 1)
{
send_insufficient_bytes_error_response(1);
- return;
+ return;
}
-
+
const uint8_t resume_type = parameter_value[0];
-
+
if (resume_type == PARAM_RESUME_TYPE_ACKNOWLEDGE)
{
stopped_is_acknowledged = true;
@@ -249,100 +249,100 @@ void handle_resume_order()
if (stopped_type == PARAM_STOPPED_TYPE_ONE_TIME_OR_CLEARED)
is_stopped = false;
-
- send_stopped_response();
+
+ send_stopped_response();
}
else
{
send_app_error_response(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_VALUE,0);
}
}
-
+
void handle_request_information_order()
{
if (parameter_length < 1)
{
send_insufficient_bytes_error_response(1);
- return;
+ return;
}
const uint8_t request_type = parameter_value[0];
-
+
generate_response_start(RSP_OK);
char *response_data_buf = (char *)generate_response_data_ptr();
uint8_t response_data_buf_len = generate_response_data_len();
int8_t length;
uint8_t value;
-
+
switch(request_type)
{
case PARAM_REQUEST_INFO_FIRMWARE_NAME:
generate_response_data_addPGM(PSTR(MINNOW_FIRMWARE_NAME));
break;
-
+
case PARAM_REQUEST_INFO_BOARD_SERIAL_NUMBER:
if ((length = NVConfigStore::GetBoardSerialNumber(response_data_buf, response_data_buf_len)) > 0)
generate_response_data_addlen(length);
break;
-
+
case PARAM_REQUEST_INFO_BOARD_NAME:
if ((length = NVConfigStore::GetHardwareName(response_data_buf, response_data_buf_len)) > 0)
generate_response_data_addlen(length);
break;
-
+
case PARAM_REQUEST_INFO_GIVEN_NAME:
if ((length = NVConfigStore::GetBoardIdentity(response_data_buf, response_data_buf_len)) > 0)
generate_response_data_addlen(length);
break;
-
+
case PARAM_REQUEST_INFO_PROTO_VERSION_MAJOR:
generate_response_data_addbyte(PM_PROTCOL_VERSION_MAJOR);
break;
-
+
case PARAM_REQUEST_INFO_PROTO_VERSION_MINOR:
generate_response_data_addbyte(PM_PROTCOL_VERSION_MINOR);
break;
-
+
case PARAM_REQUEST_INFO_SUPPORTED_EXTENSIONS:
generate_response_data_addbyte(PM_EXTENSION_STEPPER_CONTROL);
generate_response_data_addbyte(PM_EXTENSION_QUEUED_CMD);
generate_response_data_addbyte(PM_EXTENSION_BASIC_MOVE);
break;
-
+
case PARAM_REQUEST_INFO_FIRMWARE_TYPE:
generate_response_data_addbyte(PM_FIRMWARE_TYPE_MINNOW);
break;
-
+
case PARAM_REQUEST_INFO_FIRMWARE_VERSION_MAJOR:
generate_response_data_addbyte(MINNOW_FIRMWARE_VERSION_MAJOR);
break;
-
+
case PARAM_REQUEST_INFO_FIRMWARE_VERSION_MINOR:
generate_response_data_addbyte(MINNOW_FIRMWARE_VERSION_MINOR);
break;
-
+
case PARAM_REQUEST_INFO_HARDWARE_TYPE:
generate_response_data_addbyte(NVConfigStore::GetHardwareType());
break;
-
+
case PARAM_REQUEST_INFO_HARDWARE_REVISION:
if ((value = NVConfigStore::GetHardwareRevision()) != 0xFF)
generate_response_data_addbyte(value);
break;
-
+
case PARAM_REQUEST_INFO_MAXIMUM_STEP_RATE:
generate_response_data_add(MAX_STEP_FREQUENCY);
break;
-
+
case PARAM_REQUEST_INFO_HOST_TIMEOUT:
generate_response_data_addbyte(HOST_TIMEOUT_SECS);
break;
-
+
default:
send_app_error_response(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_VALUE,0);
return;
}
- generate_response_send();
+ generate_response_send();
}
void handle_device_count_order()
@@ -350,7 +350,7 @@ void handle_device_count_order()
if (parameter_length < 1)
{
send_insufficient_bytes_error_response(1);
- return;
+ return;
}
const uint8_t device_type = parameter_value[0];
@@ -361,18 +361,18 @@ void handle_device_count_order()
send_app_error_response(PARAM_APP_ERROR_TYPE_INVALID_DEVICE_TYPE,0);
return;
}
-
+
generate_response_start(RSP_OK,1);
generate_response_data_addbyte(num_devices);
generate_response_send();
}
-
+
void handle_device_name_order()
{
if (parameter_length < 2)
{
send_insufficient_bytes_error_response(2);
- return;
+ return;
}
const uint8_t device_type = parameter_value[0];
@@ -387,7 +387,7 @@ void handle_device_name_order()
send_app_error_response(PARAM_APP_ERROR_TYPE_INVALID_DEVICE_NUMBER,0);
return;
}
-
+
generate_response_start(RSP_OK);
char *response_data_buf = (char *)generate_response_data_ptr();
uint8_t response_data_buf_len = generate_response_data_len();
@@ -403,12 +403,12 @@ void handle_device_status_order()
if (parameter_length < 2)
{
send_insufficient_bytes_error_response(2);
- return;
+ return;
}
const uint8_t device_type = parameter_value[0];
const uint8_t device_number = parameter_value[1];
-
+
uint8_t num_devices = get_num_devices(device_type);
if (device_number >= num_devices)
{
@@ -418,7 +418,7 @@ void handle_device_status_order()
send_app_error_response(PARAM_APP_ERROR_TYPE_INVALID_DEVICE_NUMBER,0);
return;
}
-
+
generate_response_start(RSP_OK, 1);
switch(device_type)
@@ -433,7 +433,7 @@ void handle_device_status_order()
if (!Device_OutputSwitch::IsInUse(device_number))
generate_response_data_addbyte(DEVICE_STATUS_CONFIG_ERROR);
else if (!Device_OutputSwitch::GetEnableState(device_number))
- generate_response_data_addbyte(DEVICE_STATUS_DISABLED);
+ generate_response_data_addbyte(DEVICE_STATUS_DISABLED);
// TODO handle inactive state
else
generate_response_data_addbyte(DEVICE_STATUS_ACTIVE);
@@ -486,29 +486,29 @@ void handle_device_status_order()
}
generate_response_send();
}
-
+
void handle_request_temperature_reading_order()
{
if (parameter_length < 2)
{
send_insufficient_bytes_error_response(2);
- return;
+ return;
}
if ((parameter_length & 1) == 1)
{
send_app_error_response(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_FORMAT, 0);
- return;
+ return;
}
generate_response_start(RSP_OK,parameter_length*2);
-
+
for (int i = 0; i < parameter_length; i+=2)
{
const uint8_t device_type = parameter_value[i];
const uint8_t device_number = parameter_value[i+1];
float ftemp;
int16_t temp;
-
+
switch(device_type)
{
case PM_DEVICE_TYPE_HEATER:
@@ -521,7 +521,7 @@ void handle_request_temperature_reading_order()
ftemp = Device_Heater::ReadCurrentTemperature(device_number);
break;
}
- case PM_DEVICE_TYPE_TEMP_SENSOR:
+ case PM_DEVICE_TYPE_TEMP_SENSOR:
{
if (!Device_TemperatureSensor::IsInUse(device_number))
{
@@ -541,19 +541,19 @@ void handle_request_temperature_reading_order()
temp = PM_TEMPERATURE_INVALID;
generate_response_data_addbyte(highByte(temp));
generate_response_data_addbyte(lowByte(temp));
- }
-
+ }
+
generate_response_send();
}
-
+
void handle_get_heater_configuration_order()
{
if (parameter_length < 1)
{
send_insufficient_bytes_error_response(1);
- return;
+ return;
}
-
+
const uint8_t heater_number = parameter_value[0];
if (Device_Heater::GetHeaterPin(heater_number) == 0xFF)
@@ -565,21 +565,21 @@ void handle_get_heater_configuration_order()
generate_response_start(RSP_OK);
generate_response_data_addbyte(PARAM_HEATER_CONFIG_HOST_SENSOR_CONFIG);
generate_response_data_addbyte(Device_Heater::GetTempSensor(heater_number));
- generate_response_send();
+ generate_response_send();
}
-
+
void handle_configure_heater_order()
{
if (parameter_length < 2)
{
send_insufficient_bytes_error_response(2);
- return;
+ return;
}
-
+
const uint8_t heater_number = parameter_value[0];
const uint8_t temp_sensor = parameter_value[1];
const uint8_t current_temp_sensor = Device_Heater::GetTempSensor(heater_number);
-
+
if (current_temp_sensor != 0xFF)
{
if (current_temp_sensor != temp_sensor)
@@ -594,7 +594,7 @@ void handle_configure_heater_order()
}
return;
}
-
+
generate_response_start(RSP_APPLICATION_ERROR, 1);
uint8_t retval = Device_Heater::SetTempSensor(heater_number, temp_sensor);
if (retval != APP_ERROR_TYPE_SUCCESS)
@@ -607,13 +607,13 @@ void handle_configure_heater_order()
send_OK_response();
}
}
-
+
void handle_set_heater_target_temperature_order()
{
if (parameter_length < 3)
{
send_insufficient_bytes_error_response(3);
- return;
+ return;
}
const uint8_t heater_number = parameter_value[0];
@@ -637,8 +637,8 @@ void handle_set_heater_target_temperature_order()
}
Device_Heater::SetTargetTemperature(heater_number, ftemp);
send_OK_response();
-}
-
+}
+
void handle_get_input_switch_state_order()
{
uint8_t device_type, device_number;
@@ -646,21 +646,21 @@ void handle_get_input_switch_state_order()
if (parameter_length < 2)
{
send_insufficient_bytes_error_response(2);
- return;
+ return;
}
if ((parameter_length & 1) == 1)
{
send_app_error_response(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_FORMAT, 0);
- return;
+ return;
}
generate_response_start(RSP_OK,parameter_length/2);
-
+
for (int i = 0; i < parameter_length; i+=2)
{
device_type = parameter_value[i];
device_number = parameter_value[i+1];
-
+
switch(device_type)
{
case PM_DEVICE_TYPE_SWITCH_INPUT:
@@ -677,11 +677,11 @@ void handle_get_input_switch_state_order()
send_app_error_at_offset_response(PARAM_APP_ERROR_TYPE_INVALID_DEVICE_TYPE, i);
return;
}
- }
-
+ }
+
generate_response_send();
}
-
+
void handle_set_output_switch_state_order()
{
uint8_t device_type, device_number, device_state;
@@ -689,7 +689,7 @@ void handle_set_output_switch_state_order()
if (parameter_length < 3)
{
send_insufficient_bytes_error_response(3);
- return;
+ return;
}
for (uint8_t i = 0; i < parameter_length; i+=3)
@@ -697,12 +697,12 @@ void handle_set_output_switch_state_order()
if (i + 3 > parameter_length)
{
send_app_error_at_offset_response(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_FORMAT,parameter_length);
- return;
+ return;
}
-
+
device_type = parameter_value[i];
device_number = parameter_value[i+1];
-
+
switch(device_type)
{
case PM_DEVICE_TYPE_SWITCH_OUTPUT:
@@ -718,7 +718,7 @@ void handle_set_output_switch_state_order()
send_app_error_at_offset_response(PARAM_APP_ERROR_TYPE_INVALID_DEVICE_TYPE,i);
return;
}
- }
+ }
// we only write the switches if all are valid
for (uint8_t i = 0; i < parameter_length; i+=3)
@@ -726,7 +726,7 @@ void handle_set_output_switch_state_order()
device_type = parameter_value[i];
device_number = parameter_value[i+1];
device_state = parameter_value[i+2];
-
+
switch(device_type)
{
case PM_DEVICE_TYPE_SWITCH_OUTPUT:
@@ -734,25 +734,25 @@ void handle_set_output_switch_state_order()
break;
}
}
-
+
send_OK_response();
}
-
+
void handle_set_pwm_output_state_order()
{
uint8_t device_type, device_number;
uint16_t device_state;
-
+
if (parameter_length < 4)
{
send_insufficient_bytes_error_response(4);
- return;
+ return;
}
device_type = parameter_value[0];
device_number = parameter_value[1];
device_state = (parameter_value[2]<<8) | parameter_value[3];
-
+
switch(device_type)
{
case PM_DEVICE_TYPE_PWM_OUTPUT:
@@ -769,25 +769,25 @@ void handle_set_pwm_output_state_order()
send_app_error_at_offset_response(PARAM_APP_ERROR_TYPE_INVALID_DEVICE_TYPE,0);
return;
}
-
+
send_OK_response();
}
-
+
void handle_set_output_tone_order()
{
uint8_t device_type, device_number;
uint16_t device_state;
-
+
if (parameter_length < 4)
{
send_insufficient_bytes_error_response(4);
- return;
+ return;
}
device_type = parameter_value[0];
device_number = parameter_value[1];
device_state = (parameter_value[2]<<8) | parameter_value[3];
-
+
switch(device_type)
{
case PM_DEVICE_TYPE_BUZZER:
@@ -811,11 +811,11 @@ void handle_set_output_tone_order()
void handle_write_firmware_configuration_value_order()
{
const uint8_t name_length = parameter_value[0];
-
+
if (parameter_length < name_length + 1)
{
send_insufficient_bytes_error_response(name_length + 1);
- return;
+ return;
}
// make name null terminated
@@ -825,17 +825,17 @@ void handle_write_firmware_configuration_value_order()
// this function will handle response generation
// note: get_command() already makes the end of the command (ie. value) null-terminated
handle_firmware_configuration_request((const char *)¶meter_value[0], (const char *)¶meter_value[name_length+1]);
-}
+}
void handle_activate_stepper_control_order()
{
if (parameter_length < 1)
{
send_insufficient_bytes_error_response(1);
- return;
+ return;
}
- // Currently Minnow does not supported disabling on stepper control. This is
+ // Currently Minnow does not supported disabling on stepper control. This is
// primarily only necessary for SPI controlled stepper modules which are not
// supported by Minnow and would complicate the initial_pin_state logic.
if (!parameter_value[0])
@@ -853,7 +853,7 @@ void handle_enable_disable_steppers_order()
send_insufficient_bytes_error_response(1);
return;
}
-
+
if (parameter_length == 0)
{
for (uint8_t i=0; i MAX_STEP_FREQUENCY)
{
send_app_error_at_offset_response(PARAM_APP_ERROR_TYPE_BAD_PARAMETER_VALUE,1);
return;
}
-
+
uint8_t retval = AxisInfo::SetAxisMaxRate(device_number, (uint16_t)max_rate);
if (retval != APP_ERROR_TYPE_SUCCESS)
{
send_app_error_response(retval, 0);
return;
}
- send_OK_response();
+ send_OK_response();
}
void handle_configure_underrun_params_order()
@@ -987,7 +987,7 @@ void handle_configure_underrun_params_order()
send_insufficient_bytes_error_response(9);
return;
}
-
+
uint8_t device_number = parameter_value[0];
if (!Device_Stepper::IsInUse(device_number))
@@ -996,8 +996,8 @@ void handle_configure_underrun_params_order()
return;
}
- uint32_t underrun_rate = ((uint32_t)parameter_value[1] << 24) | ((uint32_t)parameter_value[2] << 16) | (parameter_value[3] << 8) | parameter_value[4];
- uint32_t underrun_accel_rate = ((uint32_t)parameter_value[5] << 24) | ((uint32_t)parameter_value[6] << 16) | (parameter_value[7] << 8) | parameter_value[8];
+ uint32_t underrun_rate = ((uint32_t)parameter_value[1] << 24) | ((uint32_t)parameter_value[2] << 16) | ((uint32_t)parameter_value[3] << 8) | parameter_value[4];
+ uint32_t underrun_accel_rate = ((uint32_t)parameter_value[5] << 24) | ((uint32_t)parameter_value[6] << 16) | ((uint32_t)parameter_value[7] << 8) | parameter_value[8];
if (underrun_rate > MAX_STEP_FREQUENCY)
{
@@ -1007,34 +1007,34 @@ void handle_configure_underrun_params_order()
AxisInfo::SetUnderrunRate(device_number, underrun_rate);
AxisInfo::SetUnderrunAccelRate(device_number, underrun_accel_rate);
- send_OK_response();
+ send_OK_response();
}
void handle_clear_command_queue_order()
{
generate_response_start(RSP_APPLICATION_ERROR, 1);
-
+
if (CommandQueue::GetQueueBufferLength() == 0)
- {
+ {
if (!allocate_command_queue_memory())
{
- send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
+ send_app_error_response(PARAM_APP_ERROR_TYPE_FIRMWARE_ERROR,
PMSG(MSG_ERR_INSUFFICIENT_MEMORY));
return;
}
}
CommandQueue::FlushQueuedCommands();
-
+
uint16_t remaining_slots;
uint16_t current_command_count;
uint16_t total_command_count;
CommandQueue::GetQueueInfo(remaining_slots, current_command_count, total_command_count);
-
+
generate_response_start(RSP_OK);
generate_response_data_add(remaining_slots);
generate_response_data_add(current_command_count);
generate_response_data_add(total_command_count);
- generate_response_send();
-}
+ generate_response_send();
+}
diff --git a/Minnow/pins_arduino.h b/Minnow/pins_arduino.h
new file mode 100644
index 0000000..7d330fa
--- /dev/null
+++ b/Minnow/pins_arduino.h
@@ -0,0 +1,387 @@
+/*
+ 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
+*/
+
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include
+
+#define NUM_DIGITAL_PINS 70
+#define NUM_ANALOG_INPUTS 16
+#define analogInputToDigitalPin(p) ((p < 16) ? (p) + 54 : -1)
+#define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 13) || ((p) >= 44 && (p)<= 46))
+
+static const uint8_t SS = 53;
+static const uint8_t MOSI = 51;
+static const uint8_t MISO = 50;
+static const uint8_t SCK = 52;
+
+static const uint8_t SDA = 20;
+static const uint8_t SCL = 21;
+#define LED_BUILTIN 13
+
+static const uint8_t A0 = 54;
+static const uint8_t A1 = 55;
+static const uint8_t A2 = 56;
+static const uint8_t A3 = 57;
+static const uint8_t A4 = 58;
+static const uint8_t A5 = 59;
+static const uint8_t A6 = 60;
+static const uint8_t A7 = 61;
+static const uint8_t A8 = 62;
+static const uint8_t A9 = 63;
+static const uint8_t A10 = 64;
+static const uint8_t A11 = 65;
+static const uint8_t A12 = 66;
+static const uint8_t A13 = 67;
+static const uint8_t A14 = 68;
+static const uint8_t A15 = 69;
+
+// A majority of the pins are NOT PCINTs, SO BE WARNED (i.e. you cannot use them as receive pins)
+// Only pins available for RECEIVE (TRANSMIT can be on any pin):
+// (I've deliberately left out pin mapping to the Hardware USARTs - seems senseless to me)
+// Pins: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69
+
+#define digitalPinToPCICR(p) ( (((p) >= 10) && ((p) <= 13)) || \
+ (((p) >= 50) && ((p) <= 53)) || \
+ (((p) >= 62) && ((p) <= 69)) ? (&PCICR) : ((uint8_t *)0) )
+
+#define digitalPinToPCICRbit(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? 0 : \
+ ( (((p) >= 62) && ((p) <= 69)) ? 2 : \
+ 0 ) )
+
+#define digitalPinToPCMSK(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? (&PCMSK0) : \
+ ( (((p) >= 62) && ((p) <= 69)) ? (&PCMSK2) : \
+ ((uint8_t *)0) ) )
+
+#define digitalPinToPCMSKbit(p) ( (((p) >= 10) && ((p) <= 13)) ? ((p) - 6) : \
+ ( ((p) == 50) ? 3 : \
+ ( ((p) == 51) ? 2 : \
+ ( ((p) == 52) ? 1 : \
+ ( ((p) == 53) ? 0 : \
+ ( (((p) >= 62) && ((p) <= 69)) ? ((p) - 62) : \
+ 0 ) ) ) ) ) )
+
+#define digitalPinToInterrupt(p) ((p) == 2 ? 0 : ((p) == 3 ? 1 : ((p) >= 18 && (p) <= 21 ? 23 - (p) : NOT_AN_INTERRUPT)))
+
+#ifdef ARDUINO_MAIN
+
+const uint16_t PROGMEM port_to_mode_PGM[] = {
+ NOT_A_PORT,
+ (uint16_t) &DDRA,
+ (uint16_t) &DDRB,
+ (uint16_t) &DDRC,
+ (uint16_t) &DDRD,
+ (uint16_t) &DDRE,
+ (uint16_t) &DDRF,
+ (uint16_t) &DDRG,
+ (uint16_t) &DDRH,
+ NOT_A_PORT,
+ (uint16_t) &DDRJ,
+ (uint16_t) &DDRK,
+ (uint16_t) &DDRL,
+};
+
+const uint16_t PROGMEM port_to_output_PGM[] = {
+ NOT_A_PORT,
+ (uint16_t) &PORTA,
+ (uint16_t) &PORTB,
+ (uint16_t) &PORTC,
+ (uint16_t) &PORTD,
+ (uint16_t) &PORTE,
+ (uint16_t) &PORTF,
+ (uint16_t) &PORTG,
+ (uint16_t) &PORTH,
+ NOT_A_PORT,
+ (uint16_t) &PORTJ,
+ (uint16_t) &PORTK,
+ (uint16_t) &PORTL,
+};
+
+const uint16_t PROGMEM port_to_input_PGM[] = {
+ NOT_A_PIN,
+ (uint16_t) &PINA,
+ (uint16_t) &PINB,
+ (uint16_t) &PINC,
+ (uint16_t) &PIND,
+ (uint16_t) &PINE,
+ (uint16_t) &PINF,
+ (uint16_t) &PING,
+ (uint16_t) &PINH,
+ NOT_A_PIN,
+ (uint16_t) &PINJ,
+ (uint16_t) &PINK,
+ (uint16_t) &PINL,
+};
+
+const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
+ // PORTLIST
+ // -------------------------------------------
+ PE , // PE 0 ** 0 ** USART0_RX
+ PE , // PE 1 ** 1 ** USART0_TX
+ PE , // PE 4 ** 2 ** PWM2
+ PE , // PE 5 ** 3 ** PWM3
+ PG , // PG 5 ** 4 ** PWM4
+ PE , // PE 3 ** 5 ** PWM5
+ PH , // PH 3 ** 6 ** PWM6
+ PH , // PH 4 ** 7 ** PWM7
+ PH , // PH 5 ** 8 ** PWM8
+ PH , // PH 6 ** 9 ** PWM9
+ PB , // PB 4 ** 10 ** PWM10
+ PB , // PB 5 ** 11 ** PWM11
+ PB , // PB 6 ** 12 ** PWM12
+ PB , // PB 7 ** 13 ** PWM13
+ PJ , // PJ 1 ** 14 ** USART3_TX
+ PJ , // PJ 0 ** 15 ** USART3_RX
+ PH , // PH 1 ** 16 ** USART2_TX
+ PH , // PH 0 ** 17 ** USART2_RX
+ PD , // PD 3 ** 18 ** USART1_TX
+ PD , // PD 2 ** 19 ** USART1_RX
+ PD , // PD 1 ** 20 ** I2C_SDA
+ PD , // PD 0 ** 21 ** I2C_SCL
+ PA , // PA 0 ** 22 ** D22
+ PA , // PA 1 ** 23 ** D23
+ PA , // PA 2 ** 24 ** D24
+ PA , // PA 3 ** 25 ** D25
+ PA , // PA 4 ** 26 ** D26
+ PA , // PA 5 ** 27 ** D27
+ PA , // PA 6 ** 28 ** D28
+ PA , // PA 7 ** 29 ** D29
+ PC , // PC 7 ** 30 ** D30
+ PC , // PC 6 ** 31 ** D31
+ PC , // PC 5 ** 32 ** D32
+ PC , // PC 4 ** 33 ** D33
+ PC , // PC 3 ** 34 ** D34
+ PC , // PC 2 ** 35 ** D35
+ PC , // PC 1 ** 36 ** D36
+ PC , // PC 0 ** 37 ** D37
+ PD , // PD 7 ** 38 ** D38
+ PG , // PG 2 ** 39 ** D39
+ PG , // PG 1 ** 40 ** D40
+ PG , // PG 0 ** 41 ** D41
+ PL , // PL 7 ** 42 ** D42
+ PL , // PL 6 ** 43 ** D43
+ PL , // PL 5 ** 44 ** D44
+ PL , // PL 4 ** 45 ** D45
+ PL , // PL 3 ** 46 ** D46
+ PL , // PL 2 ** 47 ** D47
+ PL , // PL 1 ** 48 ** D48
+ PL , // PL 0 ** 49 ** D49
+ PB , // PB 3 ** 50 ** SPI_MISO
+ PB , // PB 2 ** 51 ** SPI_MOSI
+ PB , // PB 1 ** 52 ** SPI_SCK
+ PB , // PB 0 ** 53 ** SPI_SS
+ PF , // PF 0 ** 54 ** A0
+ PF , // PF 1 ** 55 ** A1
+ PF , // PF 2 ** 56 ** A2
+ PF , // PF 3 ** 57 ** A3
+ PF , // PF 4 ** 58 ** A4
+ PF , // PF 5 ** 59 ** A5
+ PF , // PF 6 ** 60 ** A6
+ PF , // PF 7 ** 61 ** A7
+ PK , // PK 0 ** 62 ** A8
+ PK , // PK 1 ** 63 ** A9
+ PK , // PK 2 ** 64 ** A10
+ PK , // PK 3 ** 65 ** A11
+ PK , // PK 4 ** 66 ** A12
+ PK , // PK 5 ** 67 ** A13
+ PK , // PK 6 ** 68 ** A14
+ PK , // PK 7 ** 69 ** A15
+};
+
+const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
+ // PIN IN PORT
+ // -------------------------------------------
+ _BV( 0 ) , // PE 0 ** 0 ** USART0_RX
+ _BV( 1 ) , // PE 1 ** 1 ** USART0_TX
+ _BV( 4 ) , // PE 4 ** 2 ** PWM2
+ _BV( 5 ) , // PE 5 ** 3 ** PWM3
+ _BV( 5 ) , // PG 5 ** 4 ** PWM4
+ _BV( 3 ) , // PE 3 ** 5 ** PWM5
+ _BV( 3 ) , // PH 3 ** 6 ** PWM6
+ _BV( 4 ) , // PH 4 ** 7 ** PWM7
+ _BV( 5 ) , // PH 5 ** 8 ** PWM8
+ _BV( 6 ) , // PH 6 ** 9 ** PWM9
+ _BV( 4 ) , // PB 4 ** 10 ** PWM10
+ _BV( 5 ) , // PB 5 ** 11 ** PWM11
+ _BV( 6 ) , // PB 6 ** 12 ** PWM12
+ _BV( 7 ) , // PB 7 ** 13 ** PWM13
+ _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX
+ _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX
+ _BV( 1 ) , // PH 1 ** 16 ** USART2_TX
+ _BV( 0 ) , // PH 0 ** 17 ** USART2_RX
+ _BV( 3 ) , // PD 3 ** 18 ** USART1_TX
+ _BV( 2 ) , // PD 2 ** 19 ** USART1_RX
+ _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA
+ _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL
+ _BV( 0 ) , // PA 0 ** 22 ** D22
+ _BV( 1 ) , // PA 1 ** 23 ** D23
+ _BV( 2 ) , // PA 2 ** 24 ** D24
+ _BV( 3 ) , // PA 3 ** 25 ** D25
+ _BV( 4 ) , // PA 4 ** 26 ** D26
+ _BV( 5 ) , // PA 5 ** 27 ** D27
+ _BV( 6 ) , // PA 6 ** 28 ** D28
+ _BV( 7 ) , // PA 7 ** 29 ** D29
+ _BV( 7 ) , // PC 7 ** 30 ** D30
+ _BV( 6 ) , // PC 6 ** 31 ** D31
+ _BV( 5 ) , // PC 5 ** 32 ** D32
+ _BV( 4 ) , // PC 4 ** 33 ** D33
+ _BV( 3 ) , // PC 3 ** 34 ** D34
+ _BV( 2 ) , // PC 2 ** 35 ** D35
+ _BV( 1 ) , // PC 1 ** 36 ** D36
+ _BV( 0 ) , // PC 0 ** 37 ** D37
+ _BV( 7 ) , // PD 7 ** 38 ** D38
+ _BV( 2 ) , // PG 2 ** 39 ** D39
+ _BV( 1 ) , // PG 1 ** 40 ** D40
+ _BV( 0 ) , // PG 0 ** 41 ** D41
+ _BV( 7 ) , // PL 7 ** 42 ** D42
+ _BV( 6 ) , // PL 6 ** 43 ** D43
+ _BV( 5 ) , // PL 5 ** 44 ** D44
+ _BV( 4 ) , // PL 4 ** 45 ** D45
+ _BV( 3 ) , // PL 3 ** 46 ** D46
+ _BV( 2 ) , // PL 2 ** 47 ** D47
+ _BV( 1 ) , // PL 1 ** 48 ** D48
+ _BV( 0 ) , // PL 0 ** 49 ** D49
+ _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO
+ _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI
+ _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK
+ _BV( 0 ) , // PB 0 ** 53 ** SPI_SS
+ _BV( 0 ) , // PF 0 ** 54 ** A0
+ _BV( 1 ) , // PF 1 ** 55 ** A1
+ _BV( 2 ) , // PF 2 ** 56 ** A2
+ _BV( 3 ) , // PF 3 ** 57 ** A3
+ _BV( 4 ) , // PF 4 ** 58 ** A4
+ _BV( 5 ) , // PF 5 ** 59 ** A5
+ _BV( 6 ) , // PF 6 ** 60 ** A6
+ _BV( 7 ) , // PF 7 ** 61 ** A7
+ _BV( 0 ) , // PK 0 ** 62 ** A8
+ _BV( 1 ) , // PK 1 ** 63 ** A9
+ _BV( 2 ) , // PK 2 ** 64 ** A10
+ _BV( 3 ) , // PK 3 ** 65 ** A11
+ _BV( 4 ) , // PK 4 ** 66 ** A12
+ _BV( 5 ) , // PK 5 ** 67 ** A13
+ _BV( 6 ) , // PK 6 ** 68 ** A14
+ _BV( 7 ) , // PK 7 ** 69 ** A15
+};
+
+const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
+ // TIMERS
+ // -------------------------------------------
+ NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX
+ NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX
+ TIMER3B , // PE 4 ** 2 ** PWM2
+ TIMER3C , // PE 5 ** 3 ** PWM3
+ TIMER0B , // PG 5 ** 4 ** PWM4
+ TIMER3A , // PE 3 ** 5 ** PWM5
+ TIMER4A , // PH 3 ** 6 ** PWM6
+ TIMER4B , // PH 4 ** 7 ** PWM7
+ TIMER4C , // PH 5 ** 8 ** PWM8
+ TIMER2B , // PH 6 ** 9 ** PWM9
+ TIMER2A , // PB 4 ** 10 ** PWM10
+ TIMER1A , // PB 5 ** 11 ** PWM11
+ TIMER1B , // PB 6 ** 12 ** PWM12
+ TIMER0A , // PB 7 ** 13 ** PWM13
+ NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX
+ NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX
+ NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX
+ NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX
+ NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX
+ NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX
+ NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA
+ NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL
+ NOT_ON_TIMER , // PA 0 ** 22 ** D22
+ NOT_ON_TIMER , // PA 1 ** 23 ** D23
+ NOT_ON_TIMER , // PA 2 ** 24 ** D24
+ NOT_ON_TIMER , // PA 3 ** 25 ** D25
+ NOT_ON_TIMER , // PA 4 ** 26 ** D26
+ NOT_ON_TIMER , // PA 5 ** 27 ** D27
+ NOT_ON_TIMER , // PA 6 ** 28 ** D28
+ NOT_ON_TIMER , // PA 7 ** 29 ** D29
+ NOT_ON_TIMER , // PC 7 ** 30 ** D30
+ NOT_ON_TIMER , // PC 6 ** 31 ** D31
+ NOT_ON_TIMER , // PC 5 ** 32 ** D32
+ NOT_ON_TIMER , // PC 4 ** 33 ** D33
+ NOT_ON_TIMER , // PC 3 ** 34 ** D34
+ NOT_ON_TIMER , // PC 2 ** 35 ** D35
+ NOT_ON_TIMER , // PC 1 ** 36 ** D36
+ NOT_ON_TIMER , // PC 0 ** 37 ** D37
+ NOT_ON_TIMER , // PD 7 ** 38 ** D38
+ NOT_ON_TIMER , // PG 2 ** 39 ** D39
+ NOT_ON_TIMER , // PG 1 ** 40 ** D40
+ NOT_ON_TIMER , // PG 0 ** 41 ** D41
+ NOT_ON_TIMER , // PL 7 ** 42 ** D42
+ NOT_ON_TIMER , // PL 6 ** 43 ** D43
+ TIMER5C , // PL 5 ** 44 ** D44
+ TIMER5B , // PL 4 ** 45 ** D45
+ TIMER5A , // PL 3 ** 46 ** D46
+ NOT_ON_TIMER , // PL 2 ** 47 ** D47
+ NOT_ON_TIMER , // PL 1 ** 48 ** D48
+ NOT_ON_TIMER , // PL 0 ** 49 ** D49
+ NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO
+ NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI
+ NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK
+ NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS
+ NOT_ON_TIMER , // PF 0 ** 54 ** A0
+ NOT_ON_TIMER , // PF 1 ** 55 ** A1
+ NOT_ON_TIMER , // PF 2 ** 56 ** A2
+ NOT_ON_TIMER , // PF 3 ** 57 ** A3
+ NOT_ON_TIMER , // PF 4 ** 58 ** A4
+ NOT_ON_TIMER , // PF 5 ** 59 ** A5
+ NOT_ON_TIMER , // PF 6 ** 60 ** A6
+ NOT_ON_TIMER , // PF 7 ** 61 ** A7
+ NOT_ON_TIMER , // PK 0 ** 62 ** A8
+ NOT_ON_TIMER , // PK 1 ** 63 ** A9
+ NOT_ON_TIMER , // PK 2 ** 64 ** A10
+ NOT_ON_TIMER , // PK 3 ** 65 ** A11
+ NOT_ON_TIMER , // PK 4 ** 66 ** A12
+ NOT_ON_TIMER , // PK 5 ** 67 ** A13
+ NOT_ON_TIMER , // PK 6 ** 68 ** A14
+ NOT_ON_TIMER , // PK 7 ** 69 ** A15
+};
+
+#endif
+
+// These serial port names are intended to allow libraries and architecture-neutral
+// sketches to automatically default to the correct port name for a particular type
+// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
+// the first hardware serial port whose RX/TX pins are not dedicated to another use.
+//
+// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor
+//
+// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial
+//
+// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library
+//
+// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins.
+//
+// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX
+// pins are NOT connected to anything by default.
+#define SERIAL_PORT_MONITOR Serial
+#define SERIAL_PORT_HARDWARE Serial
+#define SERIAL_PORT_HARDWARE1 Serial1
+#define SERIAL_PORT_HARDWARE2 Serial2
+#define SERIAL_PORT_HARDWARE3 Serial3
+#define SERIAL_PORT_HARDWARE_OPEN Serial1
+#define SERIAL_PORT_HARDWARE_OPEN1 Serial2
+#define SERIAL_PORT_HARDWARE_OPEN2 Serial3
+
+#endif
diff --git a/Minnow/response.h b/Minnow/response.h
index 4ca6a1a..913632b 100644
--- a/Minnow/response.h
+++ b/Minnow/response.h
@@ -1,6 +1,6 @@
/*
Minnow Pacemaker client firmware.
-
+
Copyright (C) 2013 Robert Fairlie-Cuninghame
This program is free software: you can redistribute it and/or modify
@@ -27,11 +27,11 @@
#include
//
-// Setup a new response buffer.
+// Setup a new response buffer.
//
-// The expected_length_excluding_msg argument indicates the offset where an optional
-// trailing UTF8 string message can be built. This argument has no effect if none of the
-// generate_response_msg_add functions are called.
+// The expected_length_excluding_msg argument indicates the offset where an optional
+// trailing UTF8 string message can be built. This argument has no effect if none of the
+// generate_response_msg_add functions are called.
//
// A value of 0xFF for expected_length_excluding_msg indicates that no message is expected
//
@@ -39,7 +39,7 @@ void generate_response_start(uint8_t response_code, uint8_t expected_length_excl
void generate_response_transport_error_start(uint8_t transport_error, uint8_t control_byte);
//
-// These method append data to the reponse Parameter.
+// These method append data to the response Parameter.
//
void generate_response_data_addbyte(uint8_t value);
void generate_response_data_add(uint8_t value);
@@ -58,7 +58,7 @@ uint8_t generate_response_data_len();
//
// The following methods allow for a trailing UTF8 string to be appended
-// after the expected data length (expected_length_excluding_msg) in the
+// after the expected data length (expected_length_excluding_msg) in the
// response Parameter buffer.
//
void generate_response_msg_addbyte(uint8_t value);
@@ -96,4 +96,4 @@ void send_app_error_response(uint8_t error_type, const char *msg_pstr, const cha
void send_failed_response(const char* reason);
void send_stopped_response();
-#endif
\ No newline at end of file
+#endif
diff --git a/Minnow/thermistortables.h b/Minnow/thermistortables.h
index fa3f36d..6518829 100644
--- a/Minnow/thermistortables.h
+++ b/Minnow/thermistortables.h
@@ -1,6 +1,6 @@
/*
Minnow Pacemaker client firmware.
-
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -60,6 +60,8 @@
#define ENABLE_THERMISTOR_TYPE_51 1
#define ENABLE_THERMISTOR_TYPE_52 1
#define ENABLE_THERMISTOR_TYPE_55 1
+#define ENABLE_THERMISTOR_TYPE_57 1
+#define ENABLE_THERMISTOR_TYPE_58 1
#define TT_NAME(_N) _TT_NAME(_N)
#define _TT_NAME(_N) temptable_ ## _N
@@ -378,7 +380,7 @@ const int16_t temptable_7[][2] PROGMEM = {
{991*OVERSAMPLENR, 17},
{1009*OVERSAMPLENR, 1},
{1023*OVERSAMPLENR, 0} //to allow internal 0 degrees C
-};
+};
#endif//ENABLE_THERMISTOR_TYPE_7
#if ENABLE_THERMISTOR_TYPE_71 // 100k Honeywell 135-104LAF-J01
@@ -558,37 +560,37 @@ const int16_t temptable_8[][2] PROGMEM = {
#endif //ENABLE_THERMISTOR_TYPE_8
#if ENABLE_THERMISTOR_TYPE_9 // 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup)
const int16_t temptable_9[][2] PROGMEM = {
- {1*OVERSAMPLENR, 936},
- {36*OVERSAMPLENR, 300},
- {71*OVERSAMPLENR, 246},
- {106*OVERSAMPLENR, 218},
- {141*OVERSAMPLENR, 199},
- {176*OVERSAMPLENR, 185},
- {211*OVERSAMPLENR, 173},
- {246*OVERSAMPLENR, 163},
- {281*OVERSAMPLENR, 155},
- {316*OVERSAMPLENR, 147},
- {351*OVERSAMPLENR, 140},
- {386*OVERSAMPLENR, 134},
- {421*OVERSAMPLENR, 128},
- {456*OVERSAMPLENR, 122},
- {491*OVERSAMPLENR, 117},
- {526*OVERSAMPLENR, 112},
- {561*OVERSAMPLENR, 107},
- {596*OVERSAMPLENR, 102},
- {631*OVERSAMPLENR, 97},
- {666*OVERSAMPLENR, 92},
- {701*OVERSAMPLENR, 87},
- {736*OVERSAMPLENR, 81},
- {771*OVERSAMPLENR, 76},
- {806*OVERSAMPLENR, 70},
- {841*OVERSAMPLENR, 63},
- {876*OVERSAMPLENR, 56},
- {911*OVERSAMPLENR, 48},
- {946*OVERSAMPLENR, 38},
- {981*OVERSAMPLENR, 23},
- {1005*OVERSAMPLENR, 5},
- {1016*OVERSAMPLENR, 0}
+ {1*OVERSAMPLENR, 936},
+ {36*OVERSAMPLENR, 300},
+ {71*OVERSAMPLENR, 246},
+ {106*OVERSAMPLENR, 218},
+ {141*OVERSAMPLENR, 199},
+ {176*OVERSAMPLENR, 185},
+ {211*OVERSAMPLENR, 173},
+ {246*OVERSAMPLENR, 163},
+ {281*OVERSAMPLENR, 155},
+ {316*OVERSAMPLENR, 147},
+ {351*OVERSAMPLENR, 140},
+ {386*OVERSAMPLENR, 134},
+ {421*OVERSAMPLENR, 128},
+ {456*OVERSAMPLENR, 122},
+ {491*OVERSAMPLENR, 117},
+ {526*OVERSAMPLENR, 112},
+ {561*OVERSAMPLENR, 107},
+ {596*OVERSAMPLENR, 102},
+ {631*OVERSAMPLENR, 97},
+ {666*OVERSAMPLENR, 92},
+ {701*OVERSAMPLENR, 87},
+ {736*OVERSAMPLENR, 81},
+ {771*OVERSAMPLENR, 76},
+ {806*OVERSAMPLENR, 70},
+ {841*OVERSAMPLENR, 63},
+ {876*OVERSAMPLENR, 56},
+ {911*OVERSAMPLENR, 48},
+ {946*OVERSAMPLENR, 38},
+ {981*OVERSAMPLENR, 23},
+ {1005*OVERSAMPLENR, 5},
+ {1016*OVERSAMPLENR, 0}
};
#endif //ENABLE_THERMISTOR_TYPE_9
@@ -772,6 +774,161 @@ const int16_t temptable_55[][2] PROGMEM = {
};
#endif //ENABLE_THERMISTOR_TYPE_55
+
+#if ENABLE_THERMISTOR_TYPE_57
+// ./createTemperatureLookupMarlin.py --rp=4680 --t1=21.4:106300 --t2=187:1023 --t3=248:281 --num-temps=72
+// thermistor table for extruder i3Berlin
+const int16_t temptable_57[][2] PROGMEM = {
+{159, 340},
+{172, 335},
+{186, 330},
+{202, 325},
+{219, 320},
+{238, 315},
+{258, 310},
+{281, 305},
+{306, 300},
+{333, 295},
+{363, 209},
+{396, 285},
+{432, 280},
+{472, 275},
+{516, 270},
+{565, 265},
+{618, 260},
+{677, 255},
+{742, 240},
+{814, 245},
+{894, 240},
+{981, 235},
+{1078, 230},
+{1184, 225},
+{1302, 220},
+{1432, 215},
+{1574, 210},
+{1732, 205},
+{1904, 200},
+{2094, 195},
+{2302, 190},
+{2530, 185},
+{2779, 180},
+{3050, 175},
+{3344, 170},
+{3662, 165},
+{4006, 160},
+{4375, 155},
+{4770, 150},
+{5190, 145},
+{5634, 140},
+{6101, 135},
+{6589, 130},
+{7095, 125},
+{7617, 120},
+{8149, 115},
+{8689, 110},
+{9230, 105},
+{9770, 100},
+{10302, 95},
+{11810, 90},
+{12271, 85},
+{12705, 80},
+{13111, 75},
+{13487, 70},
+{13833, 65},
+{14149, 60},
+{14435, 55},
+{14693, 50},
+{14923, 45},
+{15127, 40},
+{15308, 35},
+{15466, 30},
+{15604, 25},
+{15725, 20},
+{15828, 15},
+{15918, 10},
+{15994, 5},
+{16060, 0}
+};
+#endif // ENABLE_THERMISTOR_TYPE_57
+
+#if ENABLE_THERMISTOR_TYPE_58
+// ./createTemperatureLookup.py --rp=4670 --t1=21.7:110700.0 --t2=190.0:623.0 --t3=259.0:192.0 --num-temps=72
+// thermistor table for heatbed i3Berlin
+const int16_t temptable_58[][2] PROGMEM = {
+{198, 350},
+{210, 345},
+{223, 340},
+{236, 335},
+{251, 330},
+{267, 325},
+{284, 320},
+{303, 315},
+{323, 310},
+{345, 305},
+{369, 300},
+{395, 295},
+{423, 290},
+{453, 285},
+{486, 280},
+{522, 275},
+{562, 270},
+{605, 265},
+{652, 260},
+{704, 255},
+{760, 250},
+{822, 245},
+{890, 240},
+{964, 235},
+{1046, 230},
+{1136, 225},
+{1235, 220},
+{1344, 215},
+{1464, 210},
+{1597, 205},
+{1743, 200},
+{1903, 195},
+{2080, 190},
+{2275, 185},
+{2489, 180},
+{2725, 175},
+{2983, 170},
+{3267, 165},
+{3576, 160},
+{3913, 155},
+{4280, 150},
+{4676, 145},
+{5104, 140},
+{5561, 135},
+{6049, 130},
+{6565, 125},
+{7108, 120},
+{7673, 115},
+{8256, 110},
+{8852, 105},
+{9455, 100},
+{10058, 95},
+{10654, 90},
+{11237, 85},
+{11799, 80},
+{12334, 75},
+{12838, 70},
+{13306, 65},
+{13734, 60},
+{14123, 55},
+{14471, 50},
+{14779, 45},
+{15048, 40},
+{15282, 35},
+{15481, 30},
+{15651, 25},
+{15793, 20},
+{15912, 15},
+{16010, 10},
+{16090, 5},
+{16154, 0}
+};
+#endif // ENABLE_THERMISTOR_TYPE_58
+
#if ENABLE_THERMISTOR_TYPE_60 // Maker's Tool Works Kapton Bed Thermister
const int16_t temptable_60[][2] PROGMEM = {
{51*OVERSAMPLENR, 272},
diff --git a/Minnow/wiring.c b/Minnow/wiring.c
new file mode 100644
index 0000000..f725b10
--- /dev/null
+++ b/Minnow/wiring.c
@@ -0,0 +1,395 @@
+/*
+ wiring.c - Partial implementation of the Wiring API for the ATmega8.
+ Part of Arduino - http://www.arduino.cc/
+
+ Copyright (c) 2005-2006 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
+*/
+
+#include "wiring_private.h"
+#include "hooks.h"
+
+// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
+// the overflow handler is called every 256 ticks.
+#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
+
+// the whole number of milliseconds per timer0 overflow
+#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
+
+// the fractional number of milliseconds per timer0 overflow. we shift right
+// by three to fit these numbers into a byte. (for the clock speeds we care
+// about - 8 and 16 MHz - this doesn't lose precision.)
+#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
+#define FRACT_MAX (1000 >> 3)
+
+volatile unsigned long timer0_overflow_count = 0;
+volatile unsigned long timer0_millis = 0;
+static unsigned char timer0_fract = 0;
+
+#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
+ISR(TIM0_OVF_vect)
+#else
+ISR(TIMER0_OVF_vect)
+#endif
+{
+ // copy these to local variables so they can be stored in registers
+ // (volatile variables must be read from memory on every access)
+ unsigned long m = timer0_millis;
+ unsigned char f = timer0_fract;
+
+ m += MILLIS_INC;
+ f += FRACT_INC;
+ if (f >= FRACT_MAX) {
+ f -= FRACT_MAX;
+ m += 1;
+ }
+
+ timer0_fract = f;
+ timer0_millis = m;
+ timer0_overflow_count++;
+}
+
+unsigned long millis()
+{
+ unsigned long m;
+ uint8_t oldSREG = SREG;
+
+ // disable interrupts while we read timer0_millis or we might get an
+ // inconsistent value (e.g. in the middle of a write to timer0_millis)
+ cli();
+ m = timer0_millis;
+ SREG = oldSREG;
+
+ return m;
+}
+
+unsigned long micros() {
+ unsigned long m;
+ uint8_t oldSREG = SREG, t;
+
+ cli();
+ m = timer0_overflow_count;
+#if defined(TCNT0)
+ t = TCNT0;
+#elif defined(TCNT0L)
+ t = TCNT0L;
+#else
+ #error TIMER 0 not defined
+#endif
+
+#ifdef TIFR0
+ if ((TIFR0 & _BV(TOV0)) && (t < 255))
+ m++;
+#else
+ if ((TIFR & _BV(TOV0)) && (t < 255))
+ m++;
+#endif
+
+ SREG = oldSREG;
+
+ return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
+}
+
+void delay(unsigned long ms)
+{
+ uint16_t start = (uint16_t)micros();
+
+ while (ms > 0) {
+ yield();
+ if (((uint16_t)micros() - start) >= 1000) {
+ ms--;
+ start += 1000;
+ }
+ }
+}
+
+/* Delay for the given number of microseconds. Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */
+void delayMicroseconds(unsigned int us)
+{
+ // call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable)
+
+ // calling avrlib's delay_us() function with low values (e.g. 1 or
+ // 2 microseconds) gives delays longer than desired.
+ //delay_us(us);
+#if F_CPU >= 24000000L
+ // for the 24 MHz clock for the aventurous ones, trying to overclock
+
+ // zero delay fix
+ if (!us) return; // = 3 cycles, (4 when true)
+
+ // the following loop takes a 1/6 of a microsecond (4 cycles)
+ // per iteration, so execute it six times for each microsecond of
+ // delay requested.
+ us *= 6; // x6 us, = 7 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 22 (24) cycles above, remove 5, (5*4=20)
+ // us is at least 6 so we can substract 5
+ us -= 5; //=2 cycles
+
+#elif F_CPU >= 20000000L
+ // for the 20 MHz clock on rare Arduino boards
+
+ // for a one-microsecond delay, simply return. the overhead
+ // of the function call takes 18 (20) cycles, which is 1us
+ __asm__ __volatile__ (
+ "nop" "\n\t"
+ "nop" "\n\t"
+ "nop" "\n\t"
+ "nop"); //just waiting 4 cycles
+ if (us <= 1) return; // = 3 cycles, (4 when true)
+
+ // the following loop takes a 1/5 of a microsecond (4 cycles)
+ // per iteration, so execute it five times for each microsecond of
+ // delay requested.
+ us = (us << 2) + us; // x5 us, = 7 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 26 (28) cycles above, remove 7, (7*4=28)
+ // us is at least 10 so we can substract 7
+ us -= 7; // 2 cycles
+
+#elif F_CPU >= 16000000L
+ // for the 16 MHz clock on most Arduino boards
+
+ // for a one-microsecond delay, simply return. the overhead
+ // of the function call takes 14 (16) cycles, which is 1us
+ if (us <= 1) return; // = 3 cycles, (4 when true)
+
+ // the following loop takes 1/4 of a microsecond (4 cycles)
+ // per iteration, so execute it four times for each microsecond of
+ // delay requested.
+ us <<= 2; // x4 us, = 4 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 19 (21) cycles above, remove 5, (5*4=20)
+ // us is at least 8 so we can substract 5
+ us -= 5; // = 2 cycles,
+
+#elif F_CPU >= 12000000L
+ // for the 12 MHz clock if somebody is working with USB
+
+ // for a 1 microsecond delay, simply return. the overhead
+ // of the function call takes 14 (16) cycles, which is 1.5us
+ if (us <= 1) return; // = 3 cycles, (4 when true)
+
+ // the following loop takes 1/3 of a microsecond (4 cycles)
+ // per iteration, so execute it three times for each microsecond of
+ // delay requested.
+ us = (us << 1) + us; // x3 us, = 5 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 20 (22) cycles above, remove 5, (5*4=20)
+ // us is at least 6 so we can substract 5
+ us -= 5; //2 cycles
+
+#elif F_CPU >= 8000000L
+ // for the 8 MHz internal clock
+
+ // for a 1 and 2 microsecond delay, simply return. the overhead
+ // of the function call takes 14 (16) cycles, which is 2us
+ if (us <= 2) return; // = 3 cycles, (4 when true)
+
+ // the following loop takes 1/2 of a microsecond (4 cycles)
+ // per iteration, so execute it twice for each microsecond of
+ // delay requested.
+ us <<= 1; //x2 us, = 2 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 17 (19) cycles above, remove 4, (4*4=16)
+ // us is at least 6 so we can substract 4
+ us -= 4; // = 2 cycles
+
+#else
+ // for the 1 MHz internal clock (default settings for common Atmega microcontrollers)
+
+ // the overhead of the function calls is 14 (16) cycles
+ if (us <= 16) return; //= 3 cycles, (4 when true)
+ if (us <= 25) return; //= 3 cycles, (4 when true), (must be at least 25 if we want to substract 22)
+
+ // compensate for the time taken by the preceeding and next commands (about 22 cycles)
+ us -= 22; // = 2 cycles
+ // the following loop takes 4 microseconds (4 cycles)
+ // per iteration, so execute it us/4 times
+ // us is at least 4, divided by 4 gives us 1 (no zero delay bug)
+ us >>= 2; // us div 4, = 4 cycles
+
+
+#endif
+
+ // busy wait
+ __asm__ __volatile__ (
+ "1: sbiw %0,1" "\n\t" // 2 cycles
+ "brne 1b" : "=w" (us) : "0" (us) // 2 cycles
+ );
+ // return = 4 cycles
+}
+
+void init()
+{
+ // this needs to be called before setup() or some functions won't
+ // work there
+ sei();
+
+ // on the ATmega168, timer 0 is also used for fast hardware pwm
+ // (using phase-correct PWM would mean that timer 0 overflowed half as often
+ // resulting in different millis() behavior on the ATmega8 and ATmega168)
+#if defined(TCCR0A) && defined(WGM01)
+ sbi(TCCR0A, WGM01);
+ sbi(TCCR0A, WGM00);
+#endif
+
+ // set timer 0 prescale factor to 64
+#if defined(__AVR_ATmega128__)
+ // CPU specific: different values for the ATmega128
+ sbi(TCCR0, CS02);
+#elif defined(TCCR0) && defined(CS01) && defined(CS00)
+ // this combination is for the standard atmega8
+ sbi(TCCR0, CS01);
+ sbi(TCCR0, CS00);
+#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
+ // this combination is for the standard 168/328/1280/2560
+ sbi(TCCR0B, CS01);
+ sbi(TCCR0B, CS00);
+#elif defined(TCCR0A) && defined(CS01) && defined(CS00)
+ // this combination is for the __AVR_ATmega645__ series
+ sbi(TCCR0A, CS01);
+ sbi(TCCR0A, CS00);
+#else
+ #error Timer 0 prescale factor 64 not set correctly
+#endif
+
+ // enable timer 0 overflow interrupt
+#if defined(TIMSK) && defined(TOIE0)
+ sbi(TIMSK, TOIE0);
+#elif defined(TIMSK0) && defined(TOIE0)
+ sbi(TIMSK0, TOIE0);
+#else
+ #error Timer 0 overflow interrupt not set correctly
+#endif
+
+ // timers 1 and 2 are used for phase-correct hardware pwm
+ // this is better for motors as it ensures an even waveform
+ // note, however, that fast pwm mode can achieve a frequency of up
+ // 8 MHz (with a 16 MHz clock) at 50% duty cycle
+
+#if defined(TCCR1B) && defined(CS11) && defined(CS10)
+ TCCR1B = 0;
+
+ // set timer 1 prescale factor to 64
+ sbi(TCCR1B, CS11);
+#if F_CPU >= 8000000L
+ sbi(TCCR1B, CS10);
+#endif
+#elif defined(TCCR1) && defined(CS11) && defined(CS10)
+ sbi(TCCR1, CS11);
+#if F_CPU >= 8000000L
+ sbi(TCCR1, CS10);
+#endif
+#endif
+ // put timer 1 in 8-bit phase correct pwm mode
+#if defined(TCCR1A) && defined(WGM10)
+ sbi(TCCR1A, WGM10);
+#elif defined(TCCR1)
+ #warning this needs to be finished
+#endif
+
+ // set timer 2 prescale factor to 64
+#if defined(TCCR2) && defined(CS22)
+ sbi(TCCR2, CS22);
+#elif defined(TCCR2B) && defined(CS22)
+ sbi(TCCR2B, CS22);
+#else
+ #warning Timer 2 not finished (may not be present on this CPU)
+#endif
+
+ // configure timer 2 for phase correct pwm (8-bit)
+#if defined(TCCR2) && defined(WGM20)
+ sbi(TCCR2, WGM20);
+#elif defined(TCCR2A) && defined(WGM20)
+ sbi(TCCR2A, WGM20);
+#else
+ #warning Timer 2 not finished (may not be present on this CPU)
+#endif
+
+#if defined(TCCR3B) && defined(CS31) && defined(WGM30)
+ sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64
+ sbi(TCCR3B, CS30);
+ sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode
+#endif
+
+#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */
+ sbi(TCCR4B, CS42); // set timer4 prescale factor to 64
+ sbi(TCCR4B, CS41);
+ sbi(TCCR4B, CS40);
+ sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode
+ sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A
+ sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D
+#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */
+#if defined(TCCR4B) && defined(CS41) && defined(WGM40)
+ sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64
+ sbi(TCCR4B, CS40);
+ sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode
+#endif
+#endif /* end timer4 block for ATMEGA1280/2560 and similar */
+
+#if defined(TCCR5B) && defined(CS51) && defined(WGM50)
+ sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64
+ sbi(TCCR5B, CS50);
+ sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode
+#endif
+
+#if defined(ADCSRA)
+ // set a2d prescaler so we are inside the desired 50-200 KHz range.
+ #if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ sbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 8000000 // 8 MHz / 64 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ sbi(ADCSRA, ADPS1);
+ cbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 4000000 // 4 MHz / 32 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ cbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 2000000 // 2 MHz / 16 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ cbi(ADCSRA, ADPS1);
+ cbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 1000000 // 1 MHz / 8 = 125 KHz
+ cbi(ADCSRA, ADPS2);
+ sbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #else // 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2
+ cbi(ADCSRA, ADPS2);
+ cbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #endif
+ // enable a2d conversions
+ sbi(ADCSRA, ADEN);
+#endif
+
+ // the bootloader connects pins 0 and 1 to the USART; disconnect them
+ // here so they can be used as normal digital i/o; they will be
+ // reconnected in Serial.begin()
+#if defined(UCSRB)
+ UCSRB = 0;
+#elif defined(UCSR0B)
+ UCSR0B = 0;
+#endif
+}
diff --git a/Minnow/wiring_analog.c b/Minnow/wiring_analog.c
new file mode 100644
index 0000000..1a4701a
--- /dev/null
+++ b/Minnow/wiring_analog.c
@@ -0,0 +1,290 @@
+/*
+ wiring_analog.c - analog input and output
+ Part of Arduino - http://www.arduino.cc/
+
+ Copyright (c) 2005-2006 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
+
+ Modified 28 September 2010 by Mark Sproul
+*/
+
+#include "wiring_private.h"
+#include "pins_arduino.h"
+
+uint8_t analog_reference = DEFAULT;
+
+void analogReference(uint8_t mode)
+{
+ // can't actually set the register here because the default setting
+ // will connect AVCC and the AREF pin, which would cause a short if
+ // there's something connected to AREF.
+ analog_reference = mode;
+}
+
+int analogRead(uint8_t pin)
+{
+ uint8_t low, high;
+
+#if defined(analogPinToChannel)
+#if defined(__AVR_ATmega32U4__)
+ if (pin >= 18) pin -= 18; // allow for channel or pin numbers
+#endif
+ pin = analogPinToChannel(pin);
+#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+ if (pin >= 54) pin -= 54; // allow for channel or pin numbers
+#elif defined(__AVR_ATmega32U4__)
+ if (pin >= 18) pin -= 18; // allow for channel or pin numbers
+#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
+ if (pin >= 24) pin -= 24; // allow for channel or pin numbers
+#else
+ if (pin >= 14) pin -= 14; // allow for channel or pin numbers
+#endif
+
+#if defined(ADCSRB) && defined(MUX5)
+ // the MUX5 bit of ADCSRB selects whether we're reading from channels
+ // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
+ ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
+#endif
+
+ // set the analog reference (high two bits of ADMUX) and select the
+ // channel (low 4 bits). this also sets ADLAR (left-adjust result)
+ // to 0 (the default).
+#if defined(ADMUX)
+ ADMUX = (analog_reference << 6) | (pin & 0x07);
+#endif
+
+ // without a delay, we seem to read from the wrong channel
+ //delay(1);
+
+#if defined(ADCSRA) && defined(ADCL)
+ // start the conversion
+ sbi(ADCSRA, ADSC);
+
+ // ADSC is cleared when the conversion finishes
+ while (bit_is_set(ADCSRA, ADSC));
+
+ // we have to read ADCL first; doing so locks both ADCL
+ // and ADCH until ADCH is read. reading ADCL second would
+ // cause the results of each conversion to be discarded,
+ // as ADCL and ADCH would be locked when it completed.
+ low = ADCL;
+ high = ADCH;
+#else
+ // we dont have an ADC, return 0
+ low = 0;
+ high = 0;
+#endif
+
+ // combine the two bytes
+ return (high << 8) | low;
+}
+
+// Right now, PWM output only works on the pins with
+// hardware support. These are defined in the appropriate
+// pins_*.c file. For the rest of the pins, we default
+// to digital output.
+void analogWrite(uint8_t pin, int val)
+{
+ // We need to make sure the PWM output is enabled for those pins
+ // that support it, as we turn it off when digitally reading or
+ // writing with them. Also, make sure the pin is in output mode
+ // for consistenty with Wiring, which doesn't require a pinMode
+ // call for the analog output pins.
+ pinMode(pin, OUTPUT);
+ if (val == 0)
+ {
+ digitalWrite(pin, LOW);
+ }
+ else if (val == 255)
+ {
+ digitalWrite(pin, HIGH);
+ }
+ else
+ {
+ switch(digitalPinToTimer(pin))
+ {
+ // XXX fix needed for atmega8
+ #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
+ case TIMER0A:
+ // connect pwm to pin on timer 0
+ sbi(TCCR0, COM00);
+ OCR0 = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR0A) && defined(COM0A1)
+ case TIMER0A:
+ // connect pwm to pin on timer 0, channel A
+ sbi(TCCR0A, COM0A1);
+ OCR0A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR0A) && defined(COM0B1)
+ case TIMER0B:
+ // connect pwm to pin on timer 0, channel B
+ sbi(TCCR0A, COM0B1);
+ OCR0B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR1A) && defined(COM1A1)
+ case TIMER1A:
+ // connect pwm to pin on timer 1, channel A
+ sbi(TCCR1A, COM1A1);
+ OCR1A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR1A) && defined(COM1B1)
+ case TIMER1B:
+ // connect pwm to pin on timer 1, channel B
+ sbi(TCCR1A, COM1B1);
+ OCR1B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR1A) && defined(COM1C1)
+ case TIMER1C:
+ // connect pwm to pin on timer 1, channel B
+ sbi(TCCR1A, COM1C1);
+ OCR1C = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR2) && defined(COM21)
+ case TIMER2:
+ // connect pwm to pin on timer 2
+ sbi(TCCR2, COM21);
+ OCR2 = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR2A) && defined(COM2A1)
+ case TIMER2A:
+ // connect pwm to pin on timer 2, channel A
+ sbi(TCCR2A, COM2A1);
+ OCR2A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR2A) && defined(COM2B1)
+ case TIMER2B:
+ // connect pwm to pin on timer 2, channel B
+ sbi(TCCR2A, COM2B1);
+ OCR2B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR3A) && defined(COM3A1)
+ case TIMER3A:
+ // connect pwm to pin on timer 3, channel A
+ sbi(TCCR3A, COM3A1);
+ OCR3A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR3A) && defined(COM3B1)
+ case TIMER3B:
+ // connect pwm to pin on timer 3, channel B
+ sbi(TCCR3A, COM3B1);
+ OCR3B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR3A) && defined(COM3C1)
+ case TIMER3C:
+ // connect pwm to pin on timer 3, channel C
+ sbi(TCCR3A, COM3C1);
+ OCR3C = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR4A)
+ case TIMER4A:
+ //connect pwm to pin on timer 4, channel A
+ sbi(TCCR4A, COM4A1);
+ #if defined(COM4A0) // only used on 32U4
+ cbi(TCCR4A, COM4A0);
+ #endif
+ OCR4A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR4A) && defined(COM4B1)
+ case TIMER4B:
+ // connect pwm to pin on timer 4, channel B
+ sbi(TCCR4A, COM4B1);
+ OCR4B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR4A) && defined(COM4C1)
+ case TIMER4C:
+ // connect pwm to pin on timer 4, channel C
+ sbi(TCCR4A, COM4C1);
+ OCR4C = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR4C) && defined(COM4D1)
+ case TIMER4D:
+ // connect pwm to pin on timer 4, channel D
+ sbi(TCCR4C, COM4D1);
+ #if defined(COM4D0) // only used on 32U4
+ cbi(TCCR4C, COM4D0);
+ #endif
+ OCR4D = val; // set pwm duty
+ break;
+ #endif
+
+
+ #if defined(TCCR5A) && defined(COM5A1)
+ case TIMER5A:
+ // connect pwm to pin on timer 5, channel A
+ sbi(TCCR5A, COM5A1);
+ OCR5A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR5A) && defined(COM5B1)
+ case TIMER5B:
+ // connect pwm to pin on timer 5, channel B
+ sbi(TCCR5A, COM5B1);
+ OCR5B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR5A) && defined(COM5C1)
+ case TIMER5C:
+ // connect pwm to pin on timer 5, channel C
+ sbi(TCCR5A, COM5C1);
+ OCR5C = val; // set pwm duty
+ break;
+ #endif
+
+ case NOT_ON_TIMER:
+ default:
+ if (val < 128) {
+ digitalWrite(pin, LOW);
+ } else {
+ digitalWrite(pin, HIGH);
+ }
+ }
+ }
+}
+
diff --git a/Minnow/wiring_digital.c b/Minnow/wiring_digital.c
new file mode 100644
index 0000000..51adb2c
--- /dev/null
+++ b/Minnow/wiring_digital.c
@@ -0,0 +1,179 @@
+/*
+ wiring_digital.c - digital input and output functions
+ Part of Arduino - http://www.arduino.cc/
+
+ Copyright (c) 2005-2006 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
+
+ Modified 28 September 2010 by Mark Sproul
+*/
+
+#define ARDUINO_MAIN
+#include "wiring_private.h"
+#include "pins_arduino.h"
+
+void pinMode(uint8_t pin, uint8_t mode)
+{
+ uint8_t bit = digitalPinToBitMask(pin);
+ uint8_t port = digitalPinToPort(pin);
+ volatile uint8_t *reg, *out;
+
+ if (port == NOT_A_PIN) return;
+
+ // JWS: can I let the optimizer do this?
+ reg = portModeRegister(port);
+ out = portOutputRegister(port);
+
+ if (mode == INPUT) {
+ uint8_t oldSREG = SREG;
+ cli();
+ *reg &= ~bit;
+ *out &= ~bit;
+ SREG = oldSREG;
+ } else if (mode == INPUT_PULLUP) {
+ uint8_t oldSREG = SREG;
+ cli();
+ *reg &= ~bit;
+ *out |= bit;
+ SREG = oldSREG;
+ } else {
+ uint8_t oldSREG = SREG;
+ cli();
+ *reg |= bit;
+ SREG = oldSREG;
+ }
+}
+
+// Forcing this inline keeps the callers from having to push their own stuff
+// on the stack. It is a good performance win and only takes 1 more byte per
+// user than calling. (It will take more bytes on the 168.)
+//
+// But shouldn't this be moved into pinMode? Seems silly to check and do on
+// each digitalread or write.
+//
+// Mark Sproul:
+// - Removed inline. Save 170 bytes on atmega1280
+// - changed to a switch statment; added 32 bytes but much easier to read and maintain.
+// - Added more #ifdefs, now compiles for atmega645
+//
+//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
+//static inline void turnOffPWM(uint8_t timer)
+static void turnOffPWM(uint8_t timer)
+{
+ switch (timer)
+ {
+ #if defined(TCCR1A) && defined(COM1A1)
+ case TIMER1A: cbi(TCCR1A, COM1A1); break;
+ #endif
+ #if defined(TCCR1A) && defined(COM1B1)
+ case TIMER1B: cbi(TCCR1A, COM1B1); break;
+ #endif
+ #if defined(TCCR1A) && defined(COM1C1)
+ case TIMER1C: cbi(TCCR1A, COM1C1); break;
+ #endif
+
+ #if defined(TCCR2) && defined(COM21)
+ case TIMER2: cbi(TCCR2, COM21); break;
+ #endif
+
+ #if defined(TCCR0A) && defined(COM0A1)
+ case TIMER0A: cbi(TCCR0A, COM0A1); break;
+ #endif
+
+ #if defined(TIMER0B) && defined(COM0B1)
+ case TIMER0B: cbi(TCCR0A, COM0B1); break;
+ #endif
+ #if defined(TCCR2A) && defined(COM2A1)
+ case TIMER2A: cbi(TCCR2A, COM2A1); break;
+ #endif
+ #if defined(TCCR2A) && defined(COM2B1)
+ case TIMER2B: cbi(TCCR2A, COM2B1); break;
+ #endif
+
+ #if defined(TCCR3A) && defined(COM3A1)
+ case TIMER3A: cbi(TCCR3A, COM3A1); break;
+ #endif
+ #if defined(TCCR3A) && defined(COM3B1)
+ case TIMER3B: cbi(TCCR3A, COM3B1); break;
+ #endif
+ #if defined(TCCR3A) && defined(COM3C1)
+ case TIMER3C: cbi(TCCR3A, COM3C1); break;
+ #endif
+
+ #if defined(TCCR4A) && defined(COM4A1)
+ case TIMER4A: cbi(TCCR4A, COM4A1); break;
+ #endif
+ #if defined(TCCR4A) && defined(COM4B1)
+ case TIMER4B: cbi(TCCR4A, COM4B1); break;
+ #endif
+ #if defined(TCCR4A) && defined(COM4C1)
+ case TIMER4C: cbi(TCCR4A, COM4C1); break;
+ #endif
+ #if defined(TCCR4C) && defined(COM4D1)
+ case TIMER4D: cbi(TCCR4C, COM4D1); break;
+ #endif
+
+ #if defined(TCCR5A)
+ case TIMER5A: cbi(TCCR5A, COM5A1); break;
+ case TIMER5B: cbi(TCCR5A, COM5B1); break;
+ case TIMER5C: cbi(TCCR5A, COM5C1); break;
+ #endif
+ }
+}
+
+void digitalWrite(uint8_t pin, uint8_t val)
+{
+ uint8_t timer = digitalPinToTimer(pin);
+ uint8_t bit = digitalPinToBitMask(pin);
+ uint8_t port = digitalPinToPort(pin);
+ volatile uint8_t *out;
+
+ if (port == NOT_A_PIN) return;
+
+ // If the pin that support PWM output, we need to turn it off
+ // before doing a digital write.
+ if (timer != NOT_ON_TIMER) turnOffPWM(timer);
+
+ out = portOutputRegister(port);
+
+ uint8_t oldSREG = SREG;
+ cli();
+
+ if (val == LOW) {
+ *out &= ~bit;
+ } else {
+ *out |= bit;
+ }
+
+ SREG = oldSREG;
+}
+
+int digitalRead(uint8_t pin)
+{
+ uint8_t timer = digitalPinToTimer(pin);
+ uint8_t bit = digitalPinToBitMask(pin);
+ uint8_t port = digitalPinToPort(pin);
+
+ if (port == NOT_A_PIN) return LOW;
+
+ // If the pin that support PWM output, we need to turn it off
+ // before getting a digital reading.
+ if (timer != NOT_ON_TIMER) turnOffPWM(timer);
+
+ if (*portInputRegister(port) & bit) return HIGH;
+ return LOW;
+}
diff --git a/Minnow/wiring_private.h b/Minnow/wiring_private.h
new file mode 100644
index 0000000..ed7c8f0
--- /dev/null
+++ b/Minnow/wiring_private.h
@@ -0,0 +1,71 @@
+/*
+ wiring_private.h - Internal header file.
+ Part of Arduino - http://www.arduino.cc/
+
+ Copyright (c) 2005-2006 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
+*/
+
+#ifndef WiringPrivate_h
+#define WiringPrivate_h
+
+#include
+#include
+#include
+#include
+
+#include "Arduino.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#ifndef cbi
+#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
+#endif
+#ifndef sbi
+#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
+#endif
+
+uint32_t countPulseASM(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops);
+
+#define EXTERNAL_INT_0 0
+#define EXTERNAL_INT_1 1
+#define EXTERNAL_INT_2 2
+#define EXTERNAL_INT_3 3
+#define EXTERNAL_INT_4 4
+#define EXTERNAL_INT_5 5
+#define EXTERNAL_INT_6 6
+#define EXTERNAL_INT_7 7
+
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega128RFA1__) || defined(__AVR_ATmega256RFR2__)
+#define EXTERNAL_NUM_INTERRUPTS 8
+#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
+#define EXTERNAL_NUM_INTERRUPTS 3
+#elif defined(__AVR_ATmega32U4__)
+#define EXTERNAL_NUM_INTERRUPTS 5
+#else
+#define EXTERNAL_NUM_INTERRUPTS 2
+#endif
+
+typedef void (*voidFuncPtr)(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/PinMap2560big.png b/PinMap2560big.png
new file mode 100644
index 0000000..7de3fa5
Binary files /dev/null and b/PinMap2560big.png differ
diff --git a/README.asciidoc b/README.asciidoc
new file mode 100644
index 0000000..67c2c21
--- /dev/null
+++ b/README.asciidoc
@@ -0,0 +1,132 @@
+Minnow - A High Performance 3D Printer and CNC Firmware for Arduino
+===================================================================
+
+Minnow is an Arduino-based Pacemaker client implementation for 3D printer, CNC and laser cutter controller boards.
+
+The Pacemaker protocol is defined here: https://github.com/JustAnother1/Pacemaker
+
+The Minnow firmware was originally created by Robert Fairlie-Cuninghame based largely on the Marlin printer firmware by Erik van der Zalm.
+
+The firmware is intended for both standalone Arduino-based controller boards (using a PC or similar host platform) as well integrated Arduino + ARM controller boards.
+
+The Minnow firmware and Pacemaker protocol have been specifically designed to support a sustained, high rate of individual movement control segments with minimal processing overhead on the client, thereby allowing the use of a cheaper controller whilst also yielding a far more sophisticated level of motion planning, co-ordinate remapping and better support for non-linear co-ordinate systems than most current solutions without requiring a real time operating system on the host.
+
+The firmware has also been designed to provide a flexible host-based configuration system so that individual firmware builds are not required for different printer and controller configurations.
+
+The Minnow firmware also supports an arbitrary number of devices - steppers, digital input & outputs, heaters, fans, buzzers, etc (limited only by the device's capabilities).
+
+System requirements:
+
+ - a 16Mhz or 20Mhz AVR Arduino (i.e., not Due)
+ - at least 64KB flash memory (currently although this can be reduced using static configuration)
+ - at least 2KB SRAM memory
+
+TODO List
+
+- Makefile and Arduino libraries directory
+- Add event handling
+- Fully test movement control
+- Add advanced stepper & heater configuration
+- Added thermocouple support (thermistor support already available)
+- Add coding guide
+- Define LCD and Rotary encoder extensions
+- World domination
+
+Currently supported firmware configuration commands:
+----------------------------------------------------
+
+[width="100%",cols="12,^2,^2,^2,3",options="header"]
+|=============================
+| Name of element| datatype | read/write | allowed values| comment
+| System level configuration elements | | | |
+| system.hardware_name | string | rw | |
+| system.hardware_type | uint8 | rw | 0..255 |
+| system.hardware_rev | uint8 | rw | 0..255 |
+| system.board_identity | string | rw | |
+| system.board_serialnum | string | rw | |
+| system.num_digital_inputs | uint8 | rw | 0..255 |
+| system.num_digital_outputs | uint8 | rw | 0..255 |
+| system.num_pwm_outputs | uint8 | rw | 0..255 |
+| system.num_buzzers | uint8 | rw | 0..255 |
+| system.num_heaters | uint8 | rw | 0..255 |
+| system.num_temp_sensors | uint8 | rw | 0..255 |
+| system.num_steppers | uint8 | rw | 0..255 |
+| system.reset_eeprom (operation) | string | w | |
+| Device configuration elements | | | |
+| devices.digital_input..name | string | rw | |
+| devices.digital_input..pin | pin | rw | 0..255, A0..A15 | Arduino Pin Number
+| devices.digital_input..trigger_level | bool | rw | "true", "1" or "false", "0" |
+| devices.digital_input..enable_pullup | bool | rw | "true", "1" or "false", "0" |
+| devices.digital_output..name | string | rw | |
+| devices.digital_output..pin | pin | rw | 0..255, A0..A15 | Arduino Pin Number
+| devices.digital_output..initial_state | string | rw | |
+| devices.pwm_output..name | string | rw | |
+| devices.pwm_output..pin | pin | rw | 0..255, A0..A15 | Arduino Pin Number
+| devices.pwm_output..use_soft_pwm | bool | rw | "true", "1" or "false", "0" |
+| devices.buzzer..name | string | rw | |
+| devices.buzzer..pin | pin | rw | 0..255, A0..A15 | Arduino Pin Number
+| devices.temp_sensor..name | string | rw | |
+| devices.temp_sensor..pin | pin | rw | 0..255, A0..A15 | Arduino Pin Number
+| devices.temp_sensor..type | int16 | rw | −32768..+32767 | see below
+| devices.heater..name | string | rw | |
+| devices.heater..pin | pin | rw | 0..255, A0..A15 | Arduino Pin Number
+| devices.heater..power_on_level | uint8 | rw | 0..255 |
+| devices.heater..use_soft_pwm | bool | rw | "true", "1" or "false", "0" |
+| devices.heater..use_bang_bang | bool | rw | "true", "1" or "false", "0" |
+| devices.heater..use_pid | bool | rw | "true", "1" or "false", "0" |
+| devices.heater..temp_sensor | uint8 | rw | 0..255 |
+| devices.heater..max_temp | int16 | rw | −32768..+32767 |
+| devices.heater..bang_bang_hysteresis | uint8 | rw | 0..255 |
+| devices.heater..pid_range | uint8 | rw | 0..255 |
+| devices.heater..kp | float | rw | 1.2E-38 to 3.4E+38 |
+| devices.heater..ki | float | rw | 1.2E-38 to 3.4E+38 |
+| devices.heater..kd | float | rw | 1.2E-38 to 3.4E+38 |
+| devices.heater..dpi_do_autotune (operation) | string | rw | |
+| devices.stepper..name | string | rw | |
+| devices.stepper..enable_pin | pin | rw | 0..255, A0..A15 | Arduino Pin Number
+| devices.stepper..enable_invert | bool | rw | "true", "1" or "false", "0" | (0 = active low, 1 = active high)
+| devices.stepper..direction_pin | pin | rw | 0..255, A0..A15 | Arduino Pin Number
+| devices.stepper..direction_invert | bool | rw | "true", "1" or "false", "0" | 0 = high is increasing, 1 = high is decreasing
+| devices.stepper..step_pin | pin | rw | 0..255, A0..A15 | Arduino Pin Number
+| devices.stepper..step_invert | bool | rw | "true", "1" or "false", "0" | 0 = active high, 1 = active low
+| Statistics elements | | | |
+| stats.rx_count | invalid | r | - |
+| stats.rx_errors | invalid | r | - |
+| stats.queue_memory | invalid | r | - |
+| debug.stack_memory | invalid | r | - |
+| Diagnostic/development elements | | | |
+| debug.stack_low_water_mark | invalid | r | - |
+|=============================
+
+
+Values for devices.temp_sensor..type:
+----------------------------------------------------
+
+ Thermistor sensor types: (>0)
+
+ 1 is 100k thermistor - best choice for EPCOS 100k (4.7k pullup)
+ 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup)
+ 3 is mendel-parts thermistor (4.7k pullup)
+ 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !!
+ 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan) (4.7k pullup)
+ 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup)
+ 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup)
+ 71 is 100k Honeywell thermistor 135-104LAF-J01 (4.7k pullup)
+ 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup)
+ 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup)
+ 10 is 100k RS thermistor 198-961 (4.7k pullup)
+ 57 is 100k i3Berlin Extruder (./createTemperatureLookupMarlin.py --rp=4680 --t1=21.4:106300 --t2=187:1023 --t3=248:281 --num-temps=72)
+ 58 is 100k i3Berlin Bed (./createTemperatureLookup.py --rp=4670 --t1=21.7:110700.0 --t2=190.0:623.0 --t3=259.0:192.0 --num-temps=72)
+ 60 is 100k Maker's Tool Works Kapton Bed Thermister
+
+ 1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k
+ (but gives greater accuracy and more stable PID on hotend)
+ 51 is 100k thermistor - EPCOS (1k pullup)
+ 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup)
+ 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan) (1k pullup)
+
+ Thermocouple sensor types: (<0)
+
+ -1 is thermocouple with AD595
+
+
diff --git a/README.md b/README.md
deleted file mode 100644
index 58396df..0000000
--- a/README.md
+++ /dev/null
@@ -1,98 +0,0 @@
-Minnow - A High Performance 3D Printer and CNC Firmware for Arduino
-===================================================================
-
-Minnow is an Arduino-based Pacemaker client implementation for 3D printer, CNC and laser cutter controller boards.
-
-The Pacemaker protocol is defined here: https://github.com/JustAnother1/Pacemaker
-
-The Minnow firmware was originally created by Robert Fairlie-Cuninghame based largely on the Marlin printer firmware by Erik van der Zalm.
-
-The firmware is intended for both standalone Arduino-based controller boards (using a PC or similar host platform) as well integrated Arduino + ARM controller boards.
-
-The Minnow firmware and Pacemaker protocol have been specifically designed to support a sustained, high rate of individual movement control segments with minimal processing overhead on the client, thereby allowing the use of a cheaper controller whilst also yielding a far more sophisticated level of motion planning, co-ordinate remapping and better support for non-linear co-ordinate systems than most current solutions without requiring a real time operating system on the host.
-
-The firmware has also been designed to provide a flexible host-based configuration system so that individual firmware builds are not required for different printer and controller configurations.
-
-The Minnow firmware also supports an arbitrary number of devices - steppers, digital input & outputs, heaters, fans, buzzers, etc (limited only by the device's capabilities).
-
-System requirements:
- - a 16Mhz or 20Mhz AVR Arduino (i.e., not Due)
- - at least 64KB flash memory (currently although this can be reduced using static configuration)
- - at least 2KB SRAM memory
-
-TODO List
-- Makefile and Arduino libraries directory
-- Add event handling
-- Fully test movement control
-- Add advanced stepper & heater configuration
-- Added thermocouple support (thermistor support already available)
-- Add coding guide
-- Define LCD and Rotary encoder extensions
-- World domination
-
-Currently supported firmware configuration commands:
----------------------------------------------------
-
-* System level configuration elements
- - system.board_identity
- - system.board_serialnum
- - system.hardware_name
- - system.hardware_type
- - system.hardware_rev
- - system.reset_eeprom (operation)
-
-* Device configuration elements
- - devices.digital_input..name
- - devices.digital_input..pin
- - devices.digital_input..trigger_level
- - devices.digital_input..enable_pullup
-
- - devices.digital_output..name
- - devices.digital_output..pin
- - devices.digital_output..initial_state
-
- - devices.pwm_output..name
- - devices.pwm_output..pin
- - devices.pwm_output..use_soft_pwm
-
- - devices.buzzer..name
- - devices.buzzer..pin
-
- - devices.temp_sensor..name
- - devices.temp_sensor..pin
- - devices.temp_sensor..type
-
- - devices.heater..name
- - devices.heater..pin
- - devices.heater..temp_sensor
- - devices.heater..max_temp
- - devices.heater..power_on_level
- - devices.heater..use_soft_pwm
- - devices.heater..use_bang_bang
- - devices.heater..bang_bang_hysteresis
- - devices.heater..use_pid
- - devices.heater..pid_range
- - devices.heater..kp
- - devices.heater..ki
- - devices.heater..kd
- - devices.heater..dpi_do_autotune (operation)
-
- - devices.stepper..name
- - devices.stepper..enable_pin
- - devices.stepper..enable_invert (0 = active low, 1 = active high)
- - devices.stepper..direction_pin
- - devices.stepper..direction_invert
- - devices.stepper..step_pin
- - devices.stepper..step_invert
-
-* Statistics elements
- - stats.rx_count
- - stats.rx_errors
- - stats.queue_memory
- - debug.stack_memory
-
-* Diagnostic/development elements
- - debug.stack_low_water_mark
-
-
-