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 - - -