diff --git a/.gitignore b/.gitignore index 0143c08..77d4698 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ #added by jmil on 2010-04-20 .sconsign.dblite +G3Firmware.suo build html *.o diff --git a/G3Firmware.sln b/G3Firmware.sln new file mode 100644 index 0000000..125f112 --- /dev/null +++ b/G3Firmware.sln @@ -0,0 +1,158 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extruder", "Extruder", "{B8BCEC9D-EBA2-47E3-A7DF-2D668B3AC267}" + ProjectSection(SolutionItems) = preProject + firmware\src\Extruder\DebugPacketProcessor.cc = firmware\src\Extruder\DebugPacketProcessor.cc + firmware\src\Extruder\DebugPacketProcessor.hh = firmware\src\Extruder\DebugPacketProcessor.hh + firmware\src\Extruder\EepromMap.cc = firmware\src\Extruder\EepromMap.cc + firmware\src\Extruder\EepromMap.hh = firmware\src\Extruder\EepromMap.hh + firmware\src\Extruder\Host.cc = firmware\src\Extruder\Host.cc + firmware\src\Extruder\Host.hh = firmware\src\Extruder\Host.hh + firmware\src\Extruder\Main.cc = firmware\src\Extruder\Main.cc + firmware\src\Extruder\Main.hh = firmware\src\Extruder\Main.hh + firmware\src\Extruder\MotorController.cc = firmware\src\Extruder\MotorController.cc + firmware\src\Extruder\MotorController.hh = firmware\src\Extruder\MotorController.hh + firmware\src\Extruder\Version.hh = firmware\src\Extruder\Version.hh + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{AE577DDE-9F1C-404B-9AF4-5A9C8D8BF39B}" + ProjectSection(SolutionItems) = preProject + firmware\src\shared\AnalogPin.cc = firmware\src\shared\AnalogPin.cc + firmware\src\shared\AnalogPin.hh = firmware\src\shared\AnalogPin.hh + firmware\src\shared\ButtonArray.hh = firmware\src\shared\ButtonArray.hh + firmware\src\shared\CircularBuffer.hh = firmware\src\shared\CircularBuffer.hh + firmware\src\shared\Commands.hh = firmware\src\shared\Commands.hh + firmware\src\shared\CoolingFan.cc = firmware\src\shared\CoolingFan.cc + firmware\src\shared\CoolingFan.hh = firmware\src\shared\CoolingFan.hh + firmware\src\shared\Display.hh = firmware\src\shared\Display.hh + firmware\src\shared\Eeprom.cc = firmware\src\shared\Eeprom.cc + firmware\src\shared\Eeprom.hh = firmware\src\shared\Eeprom.hh + firmware\src\shared\Heater.cc = firmware\src\shared\Heater.cc + firmware\src\shared\Heater.hh = firmware\src\shared\Heater.hh + firmware\src\shared\HeatingElement.hh = firmware\src\shared\HeatingElement.hh + firmware\src\shared\Interface.cc = firmware\src\shared\Interface.cc + firmware\src\shared\Interface.hh = firmware\src\shared\Interface.hh + firmware\src\shared\InterfaceBoard.cc = firmware\src\shared\InterfaceBoard.cc + firmware\src\shared\InterfaceBoard.hh = firmware\src\shared\InterfaceBoard.hh + firmware\src\shared\LiquidCrystal.cc = firmware\src\shared\LiquidCrystal.cc + firmware\src\shared\LiquidCrystal.hh = firmware\src\shared\LiquidCrystal.hh + firmware\src\shared\Menu.cc = firmware\src\shared\Menu.cc + firmware\src\shared\Menu.hh = firmware\src\shared\Menu.hh + firmware\src\shared\Packet.cc = firmware\src\shared\Packet.cc + firmware\src\shared\Packet.hh = firmware\src\shared\Packet.hh + firmware\src\shared\PID.cc = firmware\src\shared\PID.cc + firmware\src\shared\PID.hh = firmware\src\shared\PID.hh + firmware\src\shared\PinTmplt.hh = firmware\src\shared\PinTmplt.hh + firmware\src\shared\ProtocolDocumentation.hh = firmware\src\shared\ProtocolDocumentation.hh + firmware\src\shared\PSU.cc = firmware\src\shared\PSU.cc + firmware\src\shared\PSU.hh = firmware\src\shared\PSU.hh + firmware\src\shared\StepperAxis.cc = firmware\src\shared\StepperAxis.cc + firmware\src\shared\StepperAxis.hh = firmware\src\shared\StepperAxis.hh + firmware\src\shared\StepperInterface.hh = firmware\src\shared\StepperInterface.hh + firmware\src\shared\TemperatureSensor.hh = firmware\src\shared\TemperatureSensor.hh + firmware\src\shared\Thermistor.cc = firmware\src\shared\Thermistor.cc + firmware\src\shared\Thermistor.hh = firmware\src\shared\Thermistor.hh + firmware\src\shared\ThermistorTable.cc = firmware\src\shared\ThermistorTable.cc + firmware\src\shared\ThermistorTable.hh = firmware\src\shared\ThermistorTable.hh + firmware\src\shared\Thermocouple.cc = firmware\src\shared\Thermocouple.cc + firmware\src\shared\Thermocouple.hh = firmware\src\shared\Thermocouple.hh + firmware\src\shared\Timeout.cc = firmware\src\shared\Timeout.cc + firmware\src\shared\Timeout.hh = firmware\src\shared\Timeout.hh + firmware\src\shared\Types.hh = firmware\src\shared\Types.hh + firmware\src\shared\UART.cc = firmware\src\shared\UART.cc + firmware\src\shared\UART.hh = firmware\src\shared\UART.hh + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Motherboard", "Motherboard", "{C51D0777-6F43-435A-B194-9FB6DE71E516}" + ProjectSection(SolutionItems) = preProject + firmware\src\Motherboard\Command.cc = firmware\src\Motherboard\Command.cc + firmware\src\Motherboard\Command.hh = firmware\src\Motherboard\Command.hh + firmware\src\Motherboard\DebugPacketProcessor.cc = firmware\src\Motherboard\DebugPacketProcessor.cc + firmware\src\Motherboard\DebugPacketProcessor.hh = firmware\src\Motherboard\DebugPacketProcessor.hh + firmware\src\Motherboard\EepromMap.cc = firmware\src\Motherboard\EepromMap.cc + firmware\src\Motherboard\EepromMap.hh = firmware\src\Motherboard\EepromMap.hh + firmware\src\Motherboard\Errors.hh = firmware\src\Motherboard\Errors.hh + firmware\src\Motherboard\Host.cc = firmware\src\Motherboard\Host.cc + firmware\src\Motherboard\Host.hh = firmware\src\Motherboard\Host.hh + firmware\src\Motherboard\Main.cc = firmware\src\Motherboard\Main.cc + firmware\src\Motherboard\Main.hh = firmware\src\Motherboard\Main.hh + firmware\src\Motherboard\Point.hh = firmware\src\Motherboard\Point.hh + firmware\src\Motherboard\SDCard.cc = firmware\src\Motherboard\SDCard.cc + firmware\src\Motherboard\SDCard.hh = firmware\src\Motherboard\SDCard.hh + firmware\src\Motherboard\Steppers.cc = firmware\src\Motherboard\Steppers.cc + firmware\src\Motherboard\Steppers.hh = firmware\src\Motherboard\Steppers.hh + firmware\src\Motherboard\Tool.cc = firmware\src\Motherboard\Tool.cc + firmware\src\Motherboard\Tool.hh = firmware\src\Motherboard\Tool.hh + firmware\src\Motherboard\Version.hh = firmware\src\Motherboard\Version.hh + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mb24", "mb24", "{C338C176-CD4F-4133-8B44-BA1B2EFD66B8}" + ProjectSection(SolutionItems) = preProject + firmware\src\Motherboard\boards\mb24\ButtonArray.cc = firmware\src\Motherboard\boards\mb24\ButtonArray.cc + firmware\src\Motherboard\boards\mb24\Configuration.hh = firmware\src\Motherboard\boards\mb24\Configuration.hh + firmware\src\Motherboard\boards\mb24\Motherboard.cc = firmware\src\Motherboard\boards\mb24\Motherboard.cc + firmware\src\Motherboard\boards\mb24\Motherboard.hh = firmware\src\Motherboard\boards\mb24\Motherboard.hh + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rrmbv12", "rrmbv12", "{5B20E4BA-3A26-4273-8495-099508DE2D96}" + ProjectSection(SolutionItems) = preProject + firmware\src\Motherboard\boards\rrmbv12\Configuration.hh = firmware\src\Motherboard\boards\rrmbv12\Configuration.hh + firmware\src\Motherboard\boards\rrmbv12\Motherboard.cc = firmware\src\Motherboard\boards\rrmbv12\Motherboard.cc + firmware\src\Motherboard\boards\rrmbv12\Motherboard.hh = firmware\src\Motherboard\boards\rrmbv12\Motherboard.hh + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib_sd", "lib_sd", "{656CB7F3-AB12-4881-9A8F-22644216D524}" + ProjectSection(SolutionItems) = preProject + firmware\src\Motherboard\lib_sd\byteordering.c = firmware\src\Motherboard\lib_sd\byteordering.c + firmware\src\Motherboard\lib_sd\byteordering.h = firmware\src\Motherboard\lib_sd\byteordering.h + firmware\src\Motherboard\lib_sd\ChangeLog = firmware\src\Motherboard\lib_sd\ChangeLog + firmware\src\Motherboard\lib_sd\fat.c = firmware\src\Motherboard\lib_sd\fat.c + firmware\src\Motherboard\lib_sd\fat.h = firmware\src\Motherboard\lib_sd\fat.h + firmware\src\Motherboard\lib_sd\fat_config.h = firmware\src\Motherboard\lib_sd\fat_config.h + firmware\src\Motherboard\lib_sd\partition.c = firmware\src\Motherboard\lib_sd\partition.c + firmware\src\Motherboard\lib_sd\partition.h = firmware\src\Motherboard\lib_sd\partition.h + firmware\src\Motherboard\lib_sd\partition_config.h = firmware\src\Motherboard\lib_sd\partition_config.h + firmware\src\Motherboard\lib_sd\README.txt = firmware\src\Motherboard\lib_sd\README.txt + firmware\src\Motherboard\lib_sd\sd-reader_config.h = firmware\src\Motherboard\lib_sd\sd-reader_config.h + firmware\src\Motherboard\lib_sd\sd_raw.c = firmware\src\Motherboard\lib_sd\sd_raw.c + firmware\src\Motherboard\lib_sd\sd_raw.h = firmware\src\Motherboard\lib_sd\sd_raw.h + firmware\src\Motherboard\lib_sd\sd_raw_config.h = firmware\src\Motherboard\lib_sd\sd_raw_config.h + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "boards", "boards", "{2BF72BB7-EC26-4DFE-AE91-AA5F8996EF2A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ecv22", "ecv22", "{717E20D4-3D03-4098-BC43-782400939F44}" + ProjectSection(SolutionItems) = preProject + firmware\src\Extruder\boards\ecv22\Configuration.hh = firmware\src\Extruder\boards\ecv22\Configuration.hh + firmware\src\Extruder\boards\ecv22\ExtruderBoard.cc = firmware\src\Extruder\boards\ecv22\ExtruderBoard.cc + firmware\src\Extruder\boards\ecv22\ExtruderBoard.hh = firmware\src\Extruder\boards\ecv22\ExtruderBoard.hh + firmware\src\Extruder\boards\ecv22\ExtruderMotor.cc = firmware\src\Extruder\boards\ecv22\ExtruderMotor.cc + firmware\src\Extruder\boards\ecv22\ExtruderMotor.hh = firmware\src\Extruder\boards\ecv22\ExtruderMotor.hh + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ecv34", "ecv34", "{489403D6-ED19-4806-9E94-093A2570008C}" + ProjectSection(SolutionItems) = preProject + firmware\src\Extruder\boards\ecv34\.UART.cc.swp = firmware\src\Extruder\boards\ecv34\.UART.cc.swp + firmware\src\Extruder\boards\ecv34\Configuration.cc = firmware\src\Extruder\boards\ecv34\Configuration.cc + firmware\src\Extruder\boards\ecv34\Configuration.hh = firmware\src\Extruder\boards\ecv34\Configuration.hh + firmware\src\Extruder\boards\ecv34\ExtruderBoard.cc = firmware\src\Extruder\boards\ecv34\ExtruderBoard.cc + firmware\src\Extruder\boards\ecv34\ExtruderBoard.hh = firmware\src\Extruder\boards\ecv34\ExtruderBoard.hh + firmware\src\Extruder\boards\ecv34\ExtruderMotor.cc = firmware\src\Extruder\boards\ecv34\ExtruderMotor.cc + firmware\src\Extruder\boards\ecv34\ExtruderMotor.hh = firmware\src\Extruder\boards\ecv34\ExtruderMotor.hh + firmware\src\Extruder\boards\ecv34\SoftwareServo.hh = firmware\src\Extruder\boards\ecv34\SoftwareServo.hh + EndProjectSection +EndProject +Global + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {2BF72BB7-EC26-4DFE-AE91-AA5F8996EF2A} = {B8BCEC9D-EBA2-47E3-A7DF-2D668B3AC267} + {C338C176-CD4F-4133-8B44-BA1B2EFD66B8} = {C51D0777-6F43-435A-B194-9FB6DE71E516} + {5B20E4BA-3A26-4273-8495-099508DE2D96} = {C51D0777-6F43-435A-B194-9FB6DE71E516} + {656CB7F3-AB12-4881-9A8F-22644216D524} = {C51D0777-6F43-435A-B194-9FB6DE71E516} + {717E20D4-3D03-4098-BC43-782400939F44} = {2BF72BB7-EC26-4DFE-AE91-AA5F8996EF2A} + {489403D6-ED19-4806-9E94-093A2570008C} = {2BF72BB7-EC26-4DFE-AE91-AA5F8996EF2A} + EndGlobalSection +EndGlobal diff --git a/firmware/src/Extruder/DebugPacketProcessor.cc b/firmware/src/Extruder/DebugPacketProcessor.cc index 5d7c752..8006cf2 100644 --- a/firmware/src/Extruder/DebugPacketProcessor.cc +++ b/firmware/src/Extruder/DebugPacketProcessor.cc @@ -67,10 +67,12 @@ bool processDebugPacket(const InPacket& from_host, OutPacket& to_host) { to_host.append8(from_host.read8(i)); } return true; +/* } else if (command == CommandCode::DEBUG_GENERATE_BAD_PACKET) { // TODO } else if (command == CommandCode::DEBUG_SIMULATE_BAD_PACKET) { // TODO +*/ } else if (command == CommandCode::DEBUG_SLAVE_PASSTHRU) { return true; } diff --git a/firmware/src/Extruder/Main.cc b/firmware/src/Extruder/Main.cc index de5bb4a..f8df4ac 100644 --- a/firmware/src/Extruder/Main.cc +++ b/firmware/src/Extruder/Main.cc @@ -28,16 +28,16 @@ #include "MotorController.hh" void reset() { - cli(); + ATOMIC_BLOCK(ATOMIC_FORCEON) { - uint8_t resetFlags = MCUSR & 0x0f; - MCUSR = 0x0; + uint8_t resetFlags = MCUSR & 0x0f; + MCUSR = 0x0; - // Intialize various modules - initThermistorTables(); - eeprom::init(); - ExtruderBoard::getBoard().reset(resetFlags); - sei(); + // Intialize various modules + initThermistorTables(); + eeprom::init(); + ExtruderBoard::getBoard().reset(resetFlags); + } } int main() { diff --git a/firmware/src/Extruder/boards/ecv22/Configuration.hh b/firmware/src/Extruder/boards/ecv22/Configuration.hh index 89a500e..ae56a9b 100644 --- a/firmware/src/Extruder/boards/ecv22/Configuration.hh +++ b/firmware/src/Extruder/boards/ecv22/Configuration.hh @@ -18,6 +18,8 @@ #ifndef BOARDS_ECV22_CONFIGURATION_HH_ #define BOARDS_ECV22_CONFIGURATION_HH_ +#include "PinTmplt.hh" + // Board configuration files define pin configurations // for different motherboards, as well as available // features. diff --git a/firmware/src/Extruder/boards/ecv22/ExtruderBoard.cc b/firmware/src/Extruder/boards/ecv22/ExtruderBoard.cc index 0448031..71a8e4c 100644 --- a/firmware/src/Extruder/boards/ecv22/ExtruderBoard.cc +++ b/firmware/src/Extruder/boards/ecv22/ExtruderBoard.cc @@ -107,13 +107,13 @@ void ExtruderBoard::reset(uint8_t resetFlags) { TIMSK2 = 0x00; // turn off channel A PWM by default // TIMER2 is used to PWM mosfet channel B on OC2A, and channel A on // PC1 (using the OC2B register). - DEBUG_LED.setDirection(true); - CHANNEL_A.setValue(false); - CHANNEL_A.setDirection(true); // set channel A as output - CHANNEL_B.setValue(false); - CHANNEL_B.setDirection(true); // set channel B as output - CHANNEL_C.setValue(false); - CHANNEL_C.setDirection(true); // set channel C as output + DEBUG_LED::setDirection(true); + CHANNEL_A::setValue(false); + CHANNEL_A::setDirection(true); // set channel A as output + CHANNEL_B::setValue(false); + CHANNEL_B::setDirection(true); // set channel B as output + CHANNEL_C::setValue(false); + CHANNEL_C::setDirection(true); // set channel C as output TCCR2A = 0b10000011; TCCR2B = 0b00000110; // prescaler 1/256 OCR2A = 0; @@ -209,14 +209,6 @@ void ExtruderBoard::setMotorSpeedRPM(uint32_t speed, bool direction) { setExtruderMotorRPM(speed, direction); } -micros_t ExtruderBoard::getCurrentMicros() { - micros_t micros_snapshot; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - micros_snapshot = micros; - } - return micros_snapshot; -} - // ms between servo updates; conservative to avoid 7805 overheating #define SERVO_CYCLE_LENGTH 8 volatile uint8_t servo_cycle = 0; @@ -243,10 +235,10 @@ void setChannel(ChannelChoice c, uint8_t value, bool binary) { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { if (binary) { pwmAOn(false); - CHANNEL_A.setValue(value != 0); + CHANNEL_A::setValue(value != 0); } else if (value == 0 || value == 255) { pwmAOn(false); - CHANNEL_A.setValue(value == 255); + CHANNEL_A::setValue(value == 255); } else { OCR2B = value; pwmAOn(true); @@ -256,10 +248,10 @@ void setChannel(ChannelChoice c, uint8_t value, bool binary) { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { if (binary) { pwmBOn(false); - CHANNEL_B.setValue(value != 0); + CHANNEL_B::setValue(value != 0); } else if (value == 0 || value == 255) { pwmBOn(false); - CHANNEL_B.setValue(value == 255); + CHANNEL_B::setValue(value == 255); } else { OCR2A = value; pwmBOn(true); @@ -267,7 +259,7 @@ void setChannel(ChannelChoice c, uint8_t value, bool binary) { } } else { // channel C -- no pwm - CHANNEL_C.setValue(value == 0?false:true); + CHANNEL_C::setValue(value == 0?false:true); } } @@ -288,7 +280,7 @@ void ExtruderBoard::setValve(bool on) { } void ExtruderBoard::indicateError(int errorCode) { - DEBUG_LED.setValue(errorCode != 0); + DEBUG_LED::setValue(errorCode != 0); } void ExtruderBoard::setUsingPlatform(bool is_using) { @@ -322,12 +314,12 @@ void BuildPlatformHeatingElement::setHeatingElement(uint8_t value) { ISR(TIMER2_OVF_vect) { if (OCR2B != 0) { - CHANNEL_A.setValue(true); + CHANNEL_A::setValue(true); } } ISR(TIMER2_COMPB_vect) { - CHANNEL_A.setValue(false); + CHANNEL_A::setValue(false); } #ifdef DEFAULT_EXTERNAL_STEPPER diff --git a/firmware/src/Extruder/boards/ecv22/ExtruderBoard.hh b/firmware/src/Extruder/boards/ecv22/ExtruderBoard.hh index 685aa7b..d0f72f2 100644 --- a/firmware/src/Extruder/boards/ecv22/ExtruderBoard.hh +++ b/firmware/src/Extruder/boards/ecv22/ExtruderBoard.hh @@ -108,7 +108,7 @@ public: /// Get the number of microseconds that have passed since /// the board was initialized. This value will wrap after /// 2**16 microseconds; callers should compensate for this. - micros_t getCurrentMicros(); + inline micros_t getCurrentMicros() { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {return micros;} } /// Perform the timer interrupt routine. void doInterrupt(); /// Indicate an error by manipulating the debug LED. diff --git a/firmware/src/Extruder/boards/ecv22/ExtruderMotor.cc b/firmware/src/Extruder/boards/ecv22/ExtruderMotor.cc index e393c5e..04db52b 100644 --- a/firmware/src/Extruder/boards/ecv22/ExtruderMotor.cc +++ b/firmware/src/Extruder/boards/ecv22/ExtruderMotor.cc @@ -22,7 +22,7 @@ #include "ExtruderMotor.hh" #include "Eeprom.hh" #include "EepromMap.hh" -#include "Pin.hh" +#include "PinTmplt.hh" using namespace eeprom; @@ -35,12 +35,14 @@ int16_t stepper_accumulator; uint8_t stepper_phase; bool swap_motor = false; -Pin motor_enable_pin = HB1_ENABLE_PIN; -Pin motor_dir_pin = HB1_DIR_PIN; +#define motor1_enable_pin HB1_ENABLE_PIN +#define motor1_dir_pin HB1_DIR_PIN +#define motor2_enable_pin HB2_ENABLE_PIN +#define motor2_dir_pin HB2_DIR_PIN -Pin external_enable_pin = ES_ENABLE_PIN; -Pin external_dir_pin = ES_DIR_PIN; -Pin external_step_pin = ES_STEP_PIN; +#define external_enable_pin ES_ENABLE_PIN +#define external_dir_pin ES_DIR_PIN +#define external_step_pin ES_STEP_PIN // FIXME: Hardcoded steps per revolution. Eventually, this needs to be configurable // Set to 200 for standard Makerbot Stepper Motor Driver V2.3 @@ -54,12 +56,12 @@ volatile int32_t ext_stepper_counter = 0; // TIMER0 is used to PWM motor driver A enable on OC0B. void initExtruderMotor() { last_extruder_speed = 0; - HB1_ENABLE_PIN.setDirection(true); - HB1_ENABLE_PIN.setValue(false); - HB1_DIR_PIN.setDirection(true); - HB2_ENABLE_PIN.setDirection(true); - HB2_ENABLE_PIN.setValue(false); - HB2_DIR_PIN.setDirection(true); + HB1_ENABLE_PIN::setDirection(true); + HB1_ENABLE_PIN::setValue(false); + HB1_DIR_PIN::setDirection(true); + HB2_ENABLE_PIN::setDirection(true); + HB2_ENABLE_PIN::setValue(false); + HB2_DIR_PIN::setDirection(true); stepper_motor_mode = false; stepper_accumulator = 0; stepper_phase = 1; @@ -67,8 +69,6 @@ void initExtruderMotor() { uint16_t ef = getEeprom16(EXTRA_FEATURES,EF_DEFAULT); if ((ef & EF_SWAP_MOTOR_CONTROLLERS) != 0) { swap_motor = true; - motor_enable_pin = HB2_ENABLE_PIN; - motor_dir_pin = HB2_DIR_PIN; } } @@ -82,14 +82,14 @@ void setStepperMode(bool mode, bool external/* = false*/) { TIMSK0 = _BV(TOIE0); } else if (external_stepper_motor_mode) { // Setup pins - external_enable_pin.setDirection(true); - external_enable_pin.setValue(true); // true = disabled + external_enable_pin::setDirection(true); + external_enable_pin::setValue(true); // true = disabled - external_dir_pin.setDirection(true); - external_dir_pin.setValue(true); // true = forward + external_dir_pin::setDirection(true); + external_dir_pin::setValue(true); // true = forward - external_step_pin.setDirection(true); - external_step_pin.setValue(false); + external_step_pin::setDirection(true); + external_step_pin::setValue(false); // CTC Mode TCCR0A = _BV(WGM01); @@ -116,25 +116,33 @@ void setExtruderMotor(int16_t speed) { TIMSK0 = 0; if (speed == 0) { TCCR0A = _BV(WGM01) | _BV(WGM00); - motor_enable_pin.setValue(false); + if ( swap_motor ) + motor2_enable_pin::setValue(false); + else + motor1_enable_pin::setValue(false); } else if (speed == 255) { TCCR0A = _BV(WGM01) | _BV(WGM00); - motor_enable_pin.setValue(true); + if ( swap_motor ) + motor2_enable_pin::setValue(true); + else + motor1_enable_pin::setValue(true); } else { - motor_enable_pin.setValue(true); if (swap_motor) { + motor2_enable_pin::setValue(true); TCCR0A = _BV(COM0A1) | _BV(WGM01) | _BV(WGM00); } else { + motor1_enable_pin::setValue(true); TCCR0A = _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); } } bool backwards = speed < 0; if (backwards) { speed = -speed; } if (speed > 255) { speed = 255; } - motor_dir_pin.setValue(!backwards); if (swap_motor) { + motor2_dir_pin::setValue(!backwards); OCR0A = speed; } else { + motor1_dir_pin::setValue(!backwards); OCR0B = speed; } } @@ -157,16 +165,16 @@ void setExtruderMotorRPM(uint32_t micros, bool direction) { // This is now done in setExtruderMotorOn() // TIMSK0 = _BV(OCIE1A); - external_dir_pin.setValue(direction); // true = forward - external_enable_pin.setValue(false); // true = disabled - external_step_pin.setValue(false); - // DEBUG_LED.setValue(true); + external_dir_pin::setValue(direction); // true = forward + external_enable_pin::setValue(false); // true = disabled + external_step_pin::setValue(false); + // DEBUG_LED::setValue(true); } else { // Timer/Counter 0 Output Compare A Match Interrupt Off TIMSK0 = 0; - external_enable_pin.setValue(true); // true = disabled + external_enable_pin::setValue(true); // true = disabled ext_stepper_ticks_per_step = 0; - // DEBUG_LED.setValue(false); + // DEBUG_LED::setValue(false); } } @@ -200,10 +208,10 @@ volatile uint8_t stepper_pwm = 0; inline void setStep() { const bool enable = (last_extruder_speed != 0) && (((stepper_pwm++) & 0x01) == 0); const uint8_t mask = 1 << stepper_phase; - HB1_DIR_PIN.setValue((hb1_dir_pattern & mask) != 0); - HB1_ENABLE_PIN.setValue( enable && ((hb1_en_pattern & mask) != 0) ); - HB2_DIR_PIN.setValue((hb2_dir_pattern & mask) != 0); - HB2_ENABLE_PIN.setValue( enable && ((hb2_en_pattern & mask) != 0) ); + HB1_DIR_PIN::setValue((hb1_dir_pattern & mask) != 0); + HB1_ENABLE_PIN::setValue( enable && ((hb1_en_pattern & mask) != 0) ); + HB2_DIR_PIN::setValue((hb2_dir_pattern & mask) != 0); + HB2_ENABLE_PIN::setValue( enable && ((hb2_en_pattern & mask) != 0) ); } ISR(TIMER0_OVF_vect) { @@ -224,9 +232,9 @@ ISR(TIMER0_COMPA_vect) { if (ext_stepper_ticks_per_step > 0) { ++ext_stepper_counter; if (ext_stepper_counter >= ext_stepper_ticks_per_step) { - external_step_pin.setValue(true); + external_step_pin::setValue(true); ext_stepper_counter -= ext_stepper_ticks_per_step; - external_step_pin.setValue(false); + external_step_pin::setValue(false); } } } diff --git a/firmware/src/Extruder/boards/ecv34/Configuration.hh b/firmware/src/Extruder/boards/ecv34/Configuration.hh index 73089a1..44f7e48 100644 --- a/firmware/src/Extruder/boards/ecv34/Configuration.hh +++ b/firmware/src/Extruder/boards/ecv34/Configuration.hh @@ -18,6 +18,8 @@ #ifndef BOARDS_ECV34_CONFIGURATION_HH_ #define BOARDS_ECV34_CONFIGURATION_HH_ +#include "PinTmplt.hh" + // Board configuration files define pin configurations // for different motherboards, as well as available // features. diff --git a/firmware/src/Extruder/boards/ecv34/ExtruderBoard.cc b/firmware/src/Extruder/boards/ecv34/ExtruderBoard.cc index 9447029..8945062 100644 --- a/firmware/src/Extruder/boards/ecv34/ExtruderBoard.cc +++ b/firmware/src/Extruder/boards/ecv34/ExtruderBoard.cc @@ -33,13 +33,11 @@ ExtruderBoard ExtruderBoard::extruder_board; ExtruderBoard::ExtruderBoard() : micros(0L), - extruder_thermocouple(THERMOCOUPLE_CS,THERMOCOUPLE_SCK,THERMOCOUPLE_SO), + extruder_thermocouple(), platform_thermistor(PLATFORM_PIN,1), extruder_heater(extruder_thermocouple,extruder_element,SAMPLE_INTERVAL_MICROS_THERMOCOUPLE,eeprom::EXTRUDER_PID_BASE), platform_heater(platform_thermistor,platform_element,SAMPLE_INTERVAL_MICROS_THERMISTOR,eeprom::HBP_PID_BASE), using_platform(true), - servoA(SERVO0), - servoB(SERVO1), coolingFan(extruder_heater, eeprom::COOLING_FAN_BASE) { } @@ -87,12 +85,12 @@ void ExtruderBoard::reset(uint8_t resetFlags) { // Set the output mode for the mosfets. All three should default // off. - CHANNEL_A.setValue(false); - CHANNEL_A.setDirection(true); - CHANNEL_B.setValue(false); - CHANNEL_B.setDirection(true); - CHANNEL_C.setValue(false); - CHANNEL_C.setDirection(true); + CHANNEL_A::setValue(false); + CHANNEL_A::setDirection(true); + CHANNEL_B::setValue(false); + CHANNEL_B::setDirection(true); + CHANNEL_C::setValue(false); + CHANNEL_C::setDirection(true); // Timer 0: // Mode: Phase-correct PWM (WGM2:0 = 001), cycle freq= 976 Hz @@ -141,6 +139,10 @@ void ExtruderBoard::reset(uint8_t resetFlags) { getHostUART().enable(true); getHostUART().in.reset(); + MOTOR_DIR_PIN::setDirection(true); + MOTOR_DIR_PIN::setValue(true); + MOTOR_ENABLE_PIN::setDirection(true); + coolingFan.reset(); // flashIndicatorLED(); @@ -151,28 +153,26 @@ void ExtruderBoard::reset(uint8_t resetFlags) { } void ExtruderBoard::runExtruderSlice() { - motor_controller.update(); - - extruder_heater.manage_temperature(); - - if(isUsingPlatform()) { - platform_heater.manage_temperature(); - } - - coolingFan.manageCoolingFan(); -} - -int ExtruderBoard::get_current_temperature() -{ - return extruder_heater.get_current_temperature(); + motor_controller.update(); + + static uint8_t manage = 0; + manage++; + switch(manage%3) + { + case 0: + extruder_heater.manage_temperature(); + break; + case 1: + if(isUsingPlatform()) { + platform_heater.manage_temperature(); + } + break; + case 2: + coolingFan.manageCoolingFan(); + break; + } } -void ExtruderBoard::set_target_temperature(int temp ) -{ - return extruder_heater.set_target_temperature(temp); -} - - void ExtruderBoard::setMotorSpeed(int16_t speed) { // Since the motor and regulated cooling fan share an output, only one can be enabled at a time. // Therefore, we should override the motor speed command if the cooling fan is activated. @@ -182,34 +182,28 @@ void ExtruderBoard::setMotorSpeed(int16_t speed) { } void ExtruderBoard::setServo(uint8_t index, int value) { - SoftwareServo* servo; if (index == 0) { - servo = &servoA; + if (value == -1) { + servoA.disable(); + } + else { + if (!(servoA.isEnabled())) { + servoA.enable(); + } + servoA.setPosition(value); + } } else if (index == 1) { - servo = &servoB; - } - else { - return; - } - - if (value == -1) { - servo->disable(); - } - else { - if (!(servo->isEnabled())) { - servo->enable(); - } - servo->setPosition(value); - } -} - -micros_t ExtruderBoard::getCurrentMicros() { - micros_t micros_snapshot; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - micros_snapshot = micros; + if (value == -1) { + servoB.disable(); + } + else { + if (!(servoB.isEnabled())) { + servoB.enable(); + } + servoB.setPosition(value); + } } - return micros_snapshot; } /// Run the extruder board interrupt @@ -226,41 +220,29 @@ void ExtruderBoard::doInterrupt() { servo_counter = 0; if (servoA.isEnabled()) { - servoA.pin.setValue(true); + servoA.setValue(true); } if (servoB.isEnabled()) { - servoB.pin.setValue(true); + servoB.setValue(true); } } if ((servoA.isEnabled()) && (servo_counter > servoA.getCounts())) { - servoA.pin.setValue(false); + servoA.setValue(false); } if ((servoB.isEnabled()) && (servo_counter > servoB.getCounts())) { - servoB.pin.setValue(false); + servoB.setValue(false); } } -//runs the AutoBuildPlatform (connected to 'Extra' screw terms on ECv3.x ) -void ExtruderBoard::setAutomatedBuildPlatformRunning(bool state) -{ - CHANNEL_A.setValue(state); -} //runs the Extruder Cooling Fan (connected to 'A1/B1' screw term on ECv3.x) -void ExtruderBoard::setFanRunning(bool state) { - //CHANNEL_A.setValue(on); - MOTOR_DIR_PIN.setDirection(true); - MOTOR_DIR_PIN.setValue(true); - MOTOR_ENABLE_PIN.setDirection(true); - MOTOR_ENABLE_PIN.setValue(state); -} void ExtruderBoard::setValve(bool on) { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { setUsingPlatform(false); pwmBOn(false); - CHANNEL_B.setValue(on); + CHANNEL_B::setValue(on); } } @@ -269,13 +251,6 @@ void ExtruderBoard::indicateError(int errorCode) { //DEBUG_LED.setValue(errorCode != 0); } -void ExtruderBoard::lightIndicatorLED() { - MOTOR_DIR_PIN.setValue(true); -} - -void ExtruderBoard::setUsingPlatform(bool is_using) { - using_platform = is_using; -} /// Timer two comparator A match interrupt ISR(TIMER2_COMPA_vect) { @@ -288,7 +263,7 @@ void ExtruderHeatingElement::setHeatingElement(uint8_t value) { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { if (value == 0 || value == 255) { pwmCOn(false); - CHANNEL_C.setValue(value == 255); + CHANNEL_C::setValue(value == 255); } else { OCR0A = value; pwmCOn(true); @@ -302,6 +277,6 @@ void BuildPlatformHeatingElement::setHeatingElement(uint8_t value) { // It works relatively well. ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { pwmBOn(false); - CHANNEL_B.setValue(value != 0); + CHANNEL_B::setValue(value != 0); } } diff --git a/firmware/src/Extruder/boards/ecv34/ExtruderBoard.hh b/firmware/src/Extruder/boards/ecv34/ExtruderBoard.hh index 244a42e..3a9c038 100644 --- a/firmware/src/Extruder/boards/ecv34/ExtruderBoard.hh +++ b/firmware/src/Extruder/boards/ecv34/ExtruderBoard.hh @@ -74,8 +74,8 @@ private: uint8_t slave_id; - SoftwareServo servoA; - SoftwareServo servoB; + SoftwareServo servoA; + SoftwareServo servoB; CoolingFan coolingFan; public: @@ -88,11 +88,11 @@ public: // reset. uint8_t getResetFlags(); - int get_current_temperature(); - void set_target_temperature(int); + inline int get_current_temperature() { return extruder_heater.get_current_temperature(); } + inline void set_target_temperature(int temp) { return extruder_heater.set_target_temperature(temp); } - Heater& getExtruderHeater() { return extruder_heater; } - Heater& getPlatformHeater() { return platform_heater; } + inline Heater& getExtruderHeater() { return extruder_heater; } + inline Heater& getPlatformHeater() { return platform_heater; } MotorController& getMotorController() { return motor_controller; } @@ -100,28 +100,33 @@ public: void setMotorSpeedRPM(uint32_t speed, bool direction) {} // Unsupported on 3.4 /// Enable/Disable the extruder cooling fan - void setFanRunning(bool state); + //runs the Extruder Cooling Fan (connected to 'A1/B1' screw term on ECv3.x) + inline void setFanRunning(bool state) { + //CHANNEL_A.setValue(on); + MOTOR_ENABLE_PIN::setValue(state); + } /// Enable/Disable the automatic build platform motor - void setAutomatedBuildPlatformRunning(bool state); + //runs the AutoBuildPlatform (connected to 'Extra' screw terms on ECv3.x ) + inline void setAutomatedBuildPlatformRunning(bool state) { CHANNEL_A::setValue(state); } void setValve(bool on); - UART& getHostUART() { return UART::getHostUART(); } + inline UART& getHostUART() { return UART::getHostUART(); } /// Get the number of microseconds that have passed since /// the board was initialized. This value will wrap after /// 2**16 microseconds; callers should compensate for this. - micros_t getCurrentMicros(); + inline micros_t getCurrentMicros() { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {return micros;} } /// Perform the timer interrupt routine. void doInterrupt(); /// Indicate an error by manipulating the debug LED. void indicateError(int errorCode); - void lightIndicatorLED(); + inline void lightIndicatorLED() { MOTOR_DIR_PIN::setValue(true); } bool isUsingPlatform() { return using_platform; } - void setUsingPlatform(bool is_using); + inline void setUsingPlatform(bool is_using) { using_platform = is_using; } // Index 0 = ServoA, Index 1 = ServoB. Value = -1 to turn off, 0-180 to set position. void setServo(uint8_t index, int value); diff --git a/firmware/src/Extruder/boards/ecv34/ExtruderMotor.cc b/firmware/src/Extruder/boards/ecv34/ExtruderMotor.cc index f20eb01..21c1485 100644 --- a/firmware/src/Extruder/boards/ecv34/ExtruderMotor.cc +++ b/firmware/src/Extruder/boards/ecv34/ExtruderMotor.cc @@ -18,7 +18,7 @@ #include #include #include "Configuration.hh" -#include "Pin.hh" +#include "PinTmplt.hh" // Enable pin D5 is also OC0B. @@ -30,9 +30,9 @@ int16_t last_extruder_speed; // Timer0 has a duty cycle of 1/16 ms. void initExtruderMotor() { last_extruder_speed = 0; - MOTOR_ENABLE_PIN.setDirection(true); - MOTOR_ENABLE_PIN.setValue(false); - MOTOR_DIR_PIN.setDirection(true); + MOTOR_ENABLE_PIN::setDirection(true); + MOTOR_ENABLE_PIN::setValue(false); + MOTOR_DIR_PIN::setDirection(true); } @@ -48,12 +48,12 @@ void setExtruderMotor(int16_t speed) { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { if (speed == 0 || speed == 255) { TCCR0A &= 0b11001111; - MOTOR_ENABLE_PIN.setValue(speed==255); + MOTOR_ENABLE_PIN::setValue(speed==255,true); } else { - MOTOR_ENABLE_PIN.setValue(true); + MOTOR_ENABLE_PIN::setValue(true,true); TCCR0A |= 0b00100000; } - MOTOR_DIR_PIN.setValue(!backwards); + MOTOR_DIR_PIN::setValue(!backwards,true); OCR0B = speed; } } diff --git a/firmware/src/Extruder/boards/ecv34/SoftwareServo.cc b/firmware/src/Extruder/boards/ecv34/SoftwareServo.cc deleted file mode 100644 index d94c313..0000000 --- a/firmware/src/Extruder/boards/ecv34/SoftwareServo.cc +++ /dev/null @@ -1,29 +0,0 @@ -#include "SoftwareServo.hh" - -SoftwareServo::SoftwareServo(Pin pin) : - pin(pin) -{ - pin.setDirection(true); - pin.setValue(false); -} - -void SoftwareServo::setPosition(uint8_t position) { - // Program the timer match value so that we generate a pulse width per: - // http://www.servocity.com/html/hs-311_standard.html - // 600us + (value * 10) - // so 0deg = 600us, 90deg = 1500us, 180deg = 2400us - if (position > 180) { - position = 180; - } - - counts = 600 + 10*position; -} - -void SoftwareServo::enable() { - enabled = true; -} - -void SoftwareServo::disable() { - enabled = false; - pin.setValue(false); -} diff --git a/firmware/src/Extruder/boards/ecv34/SoftwareServo.hh b/firmware/src/Extruder/boards/ecv34/SoftwareServo.hh index 6106da8..6c3515d 100644 --- a/firmware/src/Extruder/boards/ecv34/SoftwareServo.hh +++ b/firmware/src/Extruder/boards/ecv34/SoftwareServo.hh @@ -18,7 +18,7 @@ #ifndef SOFTWARE_SERVO_HH_ #define SOFTWARE_SERVO_HH_ -#include "Pin.hh" +#include "PinTmplt.hh" /// Software implementation of a hobby servo driver. Though module is implemented /// purely in software, it does require periodic servicing from a microsecond @@ -31,24 +31,46 @@ /// src\Extruder\boards\ecv34\ExtruderBoard.cc. This will have to be replicated /// (or perhaps somehow refactored) before use in another board. /// \ingroup SoftwareLibraries -class SoftwareServo { +template class SoftwareServo { public: /// Create a new sofware serial instance. /// \param [in] pin Digital output #Pin that this servo should be attached to. - SoftwareServo(Pin pin); + SoftwareServo() : enabled(false) + { + pin::setDirection(true); + pin::setValue(false); + } /// Set the servo position /// \param[in] position Servo position in degrees, from 0 - 180 - void setPosition(uint8_t position); + void setPosition(uint8_t position){ + // Program the timer match value so that we generate a pulse width per: + // http://www.servocity.com/html/hs-311_standard.html + // 600us + (value * 10) + // so 0deg = 600us, 90deg = 1500us, 180deg = 2400us + if (position > 180) { + position = 180; + } + counts = 600 + 10*position; + } /// Enable the software servo module. The servo output will not be modified /// automatically; it is dependant on the code in: /// src\Extruder\boards\ecv34\ExtruderBoard.cc - void enable(); + inline void enable() { enabled = true; } /// Disable the software servo module. The servo output will be turned off /// immediately (which may cause a glitch if the output was already on). - void disable(); + inline void disable() + { + enabled = false; + pin::setValue(false); + } + + inline void setValue(bool val) + { + pin::setValue(val); + } /// Determine if this software servo module is enabled. /// \return true if the software servo module is enabled. @@ -59,7 +81,6 @@ public: /// \return Pulse width of the servo control signal, in microseconds. uint16_t getCounts() { return counts; } - Pin pin; ///< #Pin this servo is attached to. private: bool enabled; ///< True if the servo is enabled. uint16_t counts; ///< Length of servo on-time, in microseconds. diff --git a/firmware/src/Motherboard/Command.cc b/firmware/src/Motherboard/Command.cc index 91a6865..91b6765 100644 --- a/firmware/src/Motherboard/Command.cc +++ b/firmware/src/Motherboard/Command.cc @@ -38,11 +38,10 @@ bool outstanding_tool_command = false; bool paused = false; uint16_t getRemainingCapacity() { - uint16_t sz; - ATOMIC_BLOCK(ATOMIC_FORCEON) { - sz = command_buffer.getRemainingCapacity(); + //ATOMIC_BLOCK(ATOMIC_FORCEON) + { + return command_buffer.getRemainingCapacity(); } - return sz; } void pause(bool pause) { @@ -61,11 +60,11 @@ void push(uint8_t byte) { command_buffer.push(byte); } -uint8_t pop8() { +inline uint8_t pop8() { return command_buffer.pop(); } -int16_t pop16() { +inline int16_t pop16() { union { // AVR is little-endian int16_t a; @@ -78,7 +77,7 @@ int16_t pop16() { return shared.a; } -int32_t pop32() { +inline int32_t pop32() { union { // AVR is little-endian int32_t a; @@ -118,251 +117,302 @@ void runCommandSlice() { command_buffer.push(sdcard::playbackNext()); } } - if (paused) { return; } - if (mode == HOMING) { - if (!steppers::isRunning()) { - mode = READY; - } else if (homing_timeout.hasElapsed()) { - steppers::abort(); - mode = READY; - } - } - if (mode == MOVING) { - if (!steppers::isRunning()) { mode = READY; } - } - if (mode == DELAY) { - // check timers - if (delay_timeout.hasElapsed()) { - mode = READY; - } - } - if (mode == WAIT_ON_TOOL) { - if (tool_wait_timeout.hasElapsed()) { - mode = READY; - } else if (tool::getLock()) { - OutPacket& out = tool::getOutPacket(); - InPacket& in = tool::getInPacket(); - out.reset(); - out.append8(tool::getCurrentToolheadIndex()); - out.append8(SLAVE_CMD_GET_TOOL_STATUS); - tool::startTransaction(); - // WHILE: bounded by timeout in runToolSlice - while (!tool::isTransactionDone()) { - tool::runToolSlice(); - } - if (!in.hasError()) { - if (in.read8(1) & 0x01) { - mode = READY; - } - } - tool::releaseLock(); - } - } - if (mode == WAIT_ON_PLATFORM) { - // FIXME: Duplicates most code from WAIT_ON_TOOL - if (tool_wait_timeout.hasElapsed()) { - mode = READY; - } else if (tool::getLock()) { - OutPacket& out = tool::getOutPacket(); - InPacket& in = tool::getInPacket(); - out.reset(); - out.append8(tool::getCurrentToolheadIndex()); - out.append8(SLAVE_CMD_IS_PLATFORM_READY); - tool::startTransaction(); - // WHILE: bounded by timeout in runToolSlice - while (!tool::isTransactionDone()) { - tool::runToolSlice(); - } - if (!in.hasError()) { - if (in.read8(1) != 0) { - mode = READY; - } - } - tool::releaseLock(); - } - } - if (mode == READY) { - // process next command on the queue. - if (command_buffer.getLength() > 0) { - uint8_t command = command_buffer[0]; - if (command == HOST_CMD_QUEUE_POINT_ABS) { - // check for completion - if (command_buffer.getLength() >= 17) { - command_buffer.pop(); // remove the command code - mode = MOVING; - int32_t x = pop32(); - int32_t y = pop32(); - int32_t z = pop32(); - int32_t dda = pop32(); - steppers::setTarget(Point(x,y,z),dda); - } - } else if (command == HOST_CMD_QUEUE_POINT_EXT) { - // check for completion - if (command_buffer.getLength() >= 25) { - command_buffer.pop(); // remove the command code - mode = MOVING; - int32_t x = pop32(); - int32_t y = pop32(); - int32_t z = pop32(); - int32_t a = pop32(); - int32_t b = pop32(); - int32_t dda = pop32(); - steppers::setTarget(Point(x,y,z,a,b),dda); - } - } else if (command == HOST_CMD_QUEUE_POINT_NEW) { - // check for completion - if (command_buffer.getLength() >= 26) { - command_buffer.pop(); // remove the command code - mode = MOVING; - int32_t x = pop32(); - int32_t y = pop32(); - int32_t z = pop32(); - int32_t a = pop32(); - int32_t b = pop32(); - int32_t us = pop32(); - uint8_t relative = pop8(); - steppers::setTargetNew(Point(x,y,z,a,b),us,relative); - } - } else if (command == HOST_CMD_CHANGE_TOOL) { - if (command_buffer.getLength() >= 2) { - command_buffer.pop(); // remove the command code - tool::setCurrentToolheadIndex(command_buffer.pop()); - } - } else if (command == HOST_CMD_ENABLE_AXES) { - if (command_buffer.getLength() >= 2) { - command_buffer.pop(); // remove the command code - uint8_t axes = command_buffer.pop(); - bool enable = (axes & 0x80) != 0; - for (int i = 0; i < STEPPER_COUNT; i++) { - if ((axes & _BV(i)) != 0) { - steppers::enableAxis(i, enable); - } - } - } - } else if (command == HOST_CMD_SET_POSITION) { - // check for completion - if (command_buffer.getLength() >= 13) { - command_buffer.pop(); // remove the command code - int32_t x = pop32(); - int32_t y = pop32(); - int32_t z = pop32(); - steppers::definePosition(Point(x,y,z)); - } - } else if (command == HOST_CMD_SET_POSITION_EXT) { - // check for completion - if (command_buffer.getLength() >= 21) { - command_buffer.pop(); // remove the command code - int32_t x = pop32(); - int32_t y = pop32(); - int32_t z = pop32(); - int32_t a = pop32(); - int32_t b = pop32(); - steppers::definePosition(Point(x,y,z,a,b)); - } - } else if (command == HOST_CMD_DELAY) { - if (command_buffer.getLength() >= 5) { - mode = DELAY; - command_buffer.pop(); // remove the command code - // parameter is in milliseconds; timeouts need microseconds - uint32_t microseconds = pop32() * 1000; - delay_timeout.start(microseconds); - } - } else if (command == HOST_CMD_FIND_AXES_MINIMUM || - command == HOST_CMD_FIND_AXES_MAXIMUM) { - if (command_buffer.getLength() >= 8) { - command_buffer.pop(); // remove the command - uint8_t flags = pop8(); - uint32_t feedrate = pop32(); // feedrate in us per step - uint16_t timeout_s = pop16(); - bool direction = command == HOST_CMD_FIND_AXES_MAXIMUM; - mode = HOMING; - homing_timeout.start(timeout_s * 1000L * 1000L); - steppers::startHoming(command==HOST_CMD_FIND_AXES_MAXIMUM, - flags, - feedrate); - } - } else if (command == HOST_CMD_WAIT_FOR_TOOL) { - if (command_buffer.getLength() >= 6) { - mode = WAIT_ON_TOOL; - command_buffer.pop(); - uint8_t currentToolIndex = command_buffer.pop(); - uint16_t toolPingDelay = (uint16_t)pop16(); - uint16_t toolTimeout = (uint16_t)pop16(); - tool_wait_timeout.start(toolTimeout*1000000L); - } - } else if (command == HOST_CMD_WAIT_FOR_PLATFORM) { - // FIXME: Almost equivalent to WAIT_FOR_TOOL - if (command_buffer.getLength() >= 6) { - mode = WAIT_ON_PLATFORM; - command_buffer.pop(); - uint8_t currentToolIndex = command_buffer.pop(); - uint16_t toolPingDelay = (uint16_t)pop16(); - uint16_t toolTimeout = (uint16_t)pop16(); - tool_wait_timeout.start(toolTimeout*1000000L); - } - } else if (command == HOST_CMD_STORE_HOME_POSITION) { + if (!paused) + { + switch(mode) + { + case HOMING: { + if (!steppers::isRunning()) { + mode = READY; + } else if (homing_timeout.hasElapsed()) { + steppers::abort(); + mode = READY; + } + break; + } + case MOVING: { + if (!steppers::isRunning()) { mode = READY; } + break; + } + case DELAY: { + // check timers + if (delay_timeout.hasElapsed()) { + mode = READY; + } + break; + } + case WAIT_ON_TOOL: { + if (tool_wait_timeout.hasElapsed()) { + mode = READY; + } else if (tool::getLock()) { + OutPacket& out = tool::getOutPacket(); + InPacket& in = tool::getInPacket(); + out.reset(); + out.append8(tool::getCurrentToolheadIndex()); + out.append8(SLAVE_CMD_GET_TOOL_STATUS); + tool::startTransaction(); + tool::waitForTransaction(); + if (!in.hasError()) { + if (in.read8(1) & 0x01) { + mode = READY; + } + } + tool::releaseLock(); + } + break; + } + case WAIT_ON_PLATFORM: { + // FIXME: Duplicates most code from WAIT_ON_TOOL + if (tool_wait_timeout.hasElapsed()) { + mode = READY; + } else if (tool::getLock()) { + OutPacket& out = tool::getOutPacket(); + InPacket& in = tool::getInPacket(); + out.reset(); + out.append8(tool::getCurrentToolheadIndex()); + out.append8(SLAVE_CMD_IS_PLATFORM_READY); + tool::startTransaction(); + tool::waitForTransaction(); + if (!in.hasError()) { + if (in.read8(1) != 0) { + mode = READY; + } + } + tool::releaseLock(); + } + break; + } + } + + if (mode == READY) { + // process next command on the queue. + if (command_buffer.getLength() > 0) { + uint8_t command = command_buffer[0]; + switch(command) + { + case HOST_CMD_QUEUE_POINT_ABS:{ + // check for completion + if (command_buffer.getLength() >= 17) { + command_buffer.pop(); // remove the command code + mode = MOVING; + Point pt(pop32(), pop32(), pop32() ); + int32_t dda = pop32(); + steppers::setTarget(pt,dda); + } + break; + } + case HOST_CMD_QUEUE_POINT_ABS_16: { + // check for completion + if (command_buffer.getLength() >= 15) { + command_buffer.pop(); // remove the command code + mode = MOVING; + Point pt(pop16(), pop16(), pop16(), pop16(), pop16() ); + int32_t dda = pop32(); + steppers::setTarget(pt,dda); + } + break; + } + case HOST_CMD_QUEUE_POINT_NEW_16: { + // check for completion + if (command_buffer.getLength() >= 16) { + command_buffer.pop(); // remove the command code + mode = MOVING; + Point pt(pop16(), pop16(), pop16(), pop16(), pop16() ); + int32_t us = pop32(); + uint8_t relative = pop8(); + steppers::setTargetNew(pt,us,relative); + } + break; + } + case HOST_CMD_QUEUE_POINT_EXT: { + // check for completion + if (command_buffer.getLength() >= 25) { + command_buffer.pop(); // remove the command code + mode = MOVING; + Point pt(pop32(), pop32(), pop32(), pop32(), pop32() ); + int32_t dda = pop32(); + steppers::setTarget(pt,dda); + } + break; + } + case HOST_CMD_QUEUE_POINT_NEW: { + // check for completion + if (command_buffer.getLength() >= 26) { + command_buffer.pop(); // remove the command code + mode = MOVING; + Point pt(pop32(), pop32(), pop32(), pop32(), pop32() ); + int32_t us = pop32(); + uint8_t relative = pop8(); + steppers::setTargetNew(pt,us,relative); + } + break; + } + case HOST_CMD_CHANGE_TOOL: { + if (command_buffer.getLength() >= 2) { + command_buffer.pop(); // remove the command code + tool::setCurrentToolheadIndex(command_buffer.pop()); + } + break; + } + case HOST_CMD_ENABLE_AXES: { + if (command_buffer.getLength() >= 2) { + command_buffer.pop(); // remove the command code + uint8_t axes = command_buffer.pop(); + bool enable = (axes & 0x80) != 0; + for (int i = 0; i < STEPPER_COUNT; i++) { + if ((axes & _BV(i)) != 0) { + steppers::enableAxis(i, enable); + } + } + } + break; + } + case HOST_CMD_SET_POSITION: { + // check for completion + if (command_buffer.getLength() >= 13) { + command_buffer.pop(); // remove the command code + Point pt(pop32(), pop32(), pop32()); + steppers::definePosition(pt); + } + break; + } + case HOST_CMD_SET_POSITION_EXT: { + // check for completion + if (command_buffer.getLength() >= 21) { + command_buffer.pop(); // remove the command code + Point pt(pop32(), pop32(), pop32(), pop32(), pop32() ); + steppers::definePosition(pt); + } + break; + } + case HOST_CMD_SET_POSITION_16: { + // check for completion + if (command_buffer.getLength() >= 11) { + command_buffer.pop(); // remove the command code + Point pt(pop16(), pop16(), pop16(), pop16(), pop16() ); + steppers::definePosition(pt); + } + break; + } + case HOST_CMD_DELAY: { + if (command_buffer.getLength() >= 5) { + mode = DELAY; + command_buffer.pop(); // remove the command code + // parameter is in milliseconds; timeouts need microseconds + uint32_t microseconds = pop32() * 1000; + delay_timeout.start(microseconds); + } + break; + } + case HOST_CMD_FIND_AXES_MINIMUM: + case HOST_CMD_FIND_AXES_MAXIMUM: { + if (command_buffer.getLength() >= 8) { + command_buffer.pop(); // remove the command + uint8_t flags = pop8(); + uint32_t feedrate = pop32(); // feedrate in us per step + uint16_t timeout_s = pop16(); + bool direction = command == HOST_CMD_FIND_AXES_MAXIMUM; + mode = HOMING; + homing_timeout.start(timeout_s * 1000L * 1000L); + steppers::startHoming(command==HOST_CMD_FIND_AXES_MAXIMUM, + flags, + feedrate); + } + break; + } + case HOST_CMD_WAIT_FOR_TOOL: { + if (command_buffer.getLength() >= 6) { + mode = WAIT_ON_TOOL; + command_buffer.pop(); + uint8_t currentToolIndex = command_buffer.pop(); + uint16_t toolPingDelay = (uint16_t)pop16(); + uint16_t toolTimeout = (uint16_t)pop16(); + tool_wait_timeout.start(toolTimeout*1000000L); + } + break; + } + case HOST_CMD_WAIT_FOR_PLATFORM: { + // FIXME: Almost equivalent to WAIT_FOR_TOOL + if (command_buffer.getLength() >= 6) { + mode = WAIT_ON_PLATFORM; + command_buffer.pop(); + uint8_t currentToolIndex = command_buffer.pop(); + uint16_t toolPingDelay = (uint16_t)pop16(); + uint16_t toolTimeout = (uint16_t)pop16(); + tool_wait_timeout.start(toolTimeout*1000000L); + } + break; + } + case HOST_CMD_STORE_HOME_POSITION: { - // check for completion - if (command_buffer.getLength() >= 2) { - command_buffer.pop(); - uint8_t axes = pop8(); + // check for completion + if (command_buffer.getLength() >= 2) { + command_buffer.pop(); + uint8_t axes = pop8(); - // Go through each axis, and if that axis is specified, read it's value, - // then record it to the eeprom. - for (uint8_t i = 0; i < STEPPER_COUNT; i++) { - if ( axes & (1 << i) ) { - uint16_t offset = eeprom::AXIS_HOME_POSITIONS + 4*i; - uint32_t position = steppers::getPosition()[i]; - cli(); - eeprom_write_block(&position, (void*) offset, 4); - sei(); - } - } - } - } else if (command == HOST_CMD_RECALL_HOME_POSITION) { - // check for completion - if (command_buffer.getLength() >= 2) { - command_buffer.pop(); - uint8_t axes = pop8(); + // Go through each axis, and if that axis is specified, read it's value, + // then record it to the eeprom. + Point point; + steppers::getPosition(&point); + uint16_t offset = eeprom::AXIS_HOME_POSITIONS; + for (uint8_t i = 0; i < STEPPER_COUNT; i++) { + if ( axes & (1 << i) ) { + uint32_t position = point[i]; + eeprom_write_block(&position, (void*) offset, 4); + } + offset += 4; + } + } + break; + } + case HOST_CMD_RECALL_HOME_POSITION: { + // check for completion + if (command_buffer.getLength() >= 2) { + command_buffer.pop(); + uint8_t axes = pop8(); - Point newPoint = steppers::getPosition(); + Point newPoint; + steppers::getPosition(&newPoint); // load existing position first - for (uint8_t i = 0; i < STEPPER_COUNT; i++) { - if ( axes & (1 << i) ) { - uint16_t offset = eeprom::AXIS_HOME_POSITIONS + 4*i; - cli(); - eeprom_read_block(&(newPoint[i]), (void*) offset, 4); - sei(); - } - } + uint16_t offset = eeprom::AXIS_HOME_POSITIONS; + for (uint8_t i = 0; i < STEPPER_COUNT; i++) { + if ( axes & (1 << i) ) { + eeprom_read_block(&(newPoint[i]), (void*) offset, 4); + } + offset += 4; + } - steppers::definePosition(newPoint); - } + steppers::definePosition(newPoint); + } - } else if (command == HOST_CMD_TOOL_COMMAND) { - if (command_buffer.getLength() >= 4) { // needs a payload - uint8_t payload_length = command_buffer[3]; - if (command_buffer.getLength() >= 4+payload_length) { - // command is ready - if (tool::getLock()) { - OutPacket& out = tool::getOutPacket(); - out.reset(); - command_buffer.pop(); // remove the command code - out.append8(command_buffer.pop()); // copy tool index - out.append8(command_buffer.pop()); // copy command code - int len = pop8(); // get payload length - for (int i = 0; i < len; i++) { - out.append8(command_buffer.pop()); - } - // we don't care about the response, so we can release - // the lock after we initiate the transfer - tool::startTransaction(); - tool::releaseLock(); - } - } - } - } else { - } + break; + } + case HOST_CMD_TOOL_COMMAND: { + if (command_buffer.getLength() >= 4) { // needs a payload + uint8_t payload_length = command_buffer[3]; + if (command_buffer.getLength() >= 4+payload_length) { + // command is ready + if (tool::getLock()) { + OutPacket& out = tool::getOutPacket(); + out.reset(); + command_buffer.pop(); // remove the command code + out.append8(command_buffer.pop()); // copy tool index + out.append8(command_buffer.pop()); // copy command code + int len = pop8(); // get payload length + for (int i = 0; i < len; i++) { + out.append8(command_buffer.pop()); + } + // we don't care about the response, so we can release + // the lock after we initiate the transfer + tool::startTransaction(); + tool::releaseLock(); + } + } + } + break; + } + } + } } } } diff --git a/firmware/src/Motherboard/DebugPacketProcessor.cc b/firmware/src/Motherboard/DebugPacketProcessor.cc index c849dce..120d9ac 100644 --- a/firmware/src/Motherboard/DebugPacketProcessor.cc +++ b/firmware/src/Motherboard/DebugPacketProcessor.cc @@ -79,10 +79,12 @@ bool processDebugPacket(const InPacket& from_host, OutPacket& to_host) { to_host.append8(from_host.read8(i)); } return true; +/* } else if (command == CommandCode::DEBUG_GENERATE_BAD_PACKET) { // TODO } else if (command == CommandCode::DEBUG_SIMULATE_BAD_PACKET) { // TODO +*/ } else if (command == CommandCode::DEBUG_SLAVE_PASSTHRU) { // BLOCK: wait until sent { diff --git a/firmware/src/Motherboard/Host.cc b/firmware/src/Motherboard/Host.cc index 6a57fec..4c89cef 100644 --- a/firmware/src/Motherboard/Host.cc +++ b/firmware/src/Motherboard/Host.cc @@ -59,63 +59,67 @@ HostState currentState; bool do_host_reset = true; -void runHostSlice() { - InPacket& in = UART::getHostUART().in; - OutPacket& out = UART::getHostUART().out; - if (out.isSending()) { - // still sending; wait until send is complete before reading new host packets. - return; - } - if (do_host_reset) { - do_host_reset = false; - // Then, reset local board - reset(false); - packet_in_timeout.abort(); +void resetHost() { +} - // Clear the machine and build names - machineName[0] = 0; - buildName[0] = 0; - currentState = HOST_STATE_READY; +void runHostSlice() { - return; - } - if (in.isStarted() && !in.isFinished()) { - if (!packet_in_timeout.isActive()) { - // initiate timeout - packet_in_timeout.start(HOST_PACKET_TIMEOUT_MICROS); - } else if (packet_in_timeout.hasElapsed()) { - in.timeout(); - } - } - if (in.hasError()) { - // Reset packet quickly and start handling the next packet. - // Report error code. - if (in.getErrorCode() == PacketError::PACKET_TIMEOUT) { - Motherboard::getBoard().indicateError(ERR_HOST_PACKET_TIMEOUT); - } else { - Motherboard::getBoard().indicateError(ERR_HOST_PACKET_MISC); - } - in.reset(); - } - if (in.isFinished()) { - packet_in_timeout.abort(); - out.reset(); -#if defined(HONOR_DEBUG_PACKETS) && (HONOR_DEBUG_PACKETS == 1) - if (processDebugPacket(in, out)) { - // okay, processed - } else -#endif - if (processCommandPacket(in, out)) { - // okay, processed - } else if (processQueryPacket(in, out)) { - // okay, processed - } else { - // Unrecognized command - out.append8(RC_CMD_UNSUPPORTED); - } - in.reset(); + // still sending; wait until send is complete before reading new host packets. + OutPacket& out = UART::getHostUART().out; + if (!out.isSending()) { + if (do_host_reset) { + do_host_reset = false; + // Then, reset local board + reset(false); + packet_in_timeout.abort(); + + // Clear the machine and build names + machineName[0] = 0; + buildName[0] = 0; + currentState = HOST_STATE_READY; + } + else + { + InPacket& in = UART::getHostUART().in; + if (in.isStarted() && !in.isFinished()) { + if (!packet_in_timeout.isActive()) { + // initiate timeout + packet_in_timeout.start(HOST_PACKET_TIMEOUT_MICROS); + } else if (packet_in_timeout.hasElapsed()) { + in.timeout(); + } + } + if (in.hasError()) { + // Reset packet quickly and start handling the next packet. + // Report error code. + if (in.getErrorCode() == PacketError::PACKET_TIMEOUT) { + Motherboard::getBoard().indicateError(ERR_HOST_PACKET_TIMEOUT); + } else { + Motherboard::getBoard().indicateError(ERR_HOST_PACKET_MISC); + } + in.reset(); + } + if (in.isFinished()) { + packet_in_timeout.abort(); + out.reset(); + #if defined(HONOR_DEBUG_PACKETS) && (HONOR_DEBUG_PACKETS == 1) + if (processDebugPacket(in, out)) { + // okay, processed + } else + #endif + if (processCommandPacket(in, out)) { + // okay, processed + } else if (processQueryPacket(in, out)) { + // okay, processed + } else { + // Unrecognized command + out.append8(RC_CMD_UNSUPPORTED); + } + in.reset(); UART::getHostUART().beginSend(); - } + } + } + } } /// Identify a command packet, and process it. If the packet is a command @@ -196,28 +200,41 @@ inline void handleGetBufferSize(const InPacket& from_host, OutPacket& to_host) { } inline void handleGetPosition(const InPacket& from_host, OutPacket& to_host) { - ATOMIC_BLOCK(ATOMIC_FORCEON) { - const Point p = steppers::getPosition(); - to_host.append8(RC_OK); - to_host.append32(p[0]); - to_host.append32(p[1]); - to_host.append32(p[2]); + //ATOMIC_BLOCK(ATOMIC_FORCEON) + { + Motherboard& board = Motherboard::getBoard(); // From spec: // endstop status bits: (7-0) : | N/A | N/A | z max | z min | y max | y min | x max | x min | - Motherboard& board = Motherboard::getBoard(); uint8_t endstop_status = 0; - for (int i = 3; i > 0; i--) { - StepperInterface& si = board.getStepperInterface(i-1); + for (int i = 2; i >= 0; i--) { + const StepperInterface* si = board.getStepperInterface(i); endstop_status <<= 2; - endstop_status |= (si.isAtMaximum()?2:0) | (si.isAtMinimum()?1:0); + endstop_status |= (si->isAtMaximum()?2:0) | (si->isAtMinimum()?1:0); } + Point p; + steppers::getPosition(&p); + to_host.append8(RC_OK); + to_host.append32(p[0]); + to_host.append32(p[1]); + to_host.append32(p[2]); to_host.append8(endstop_status); } } inline void handleGetPositionExt(const InPacket& from_host, OutPacket& to_host) { - ATOMIC_BLOCK(ATOMIC_FORCEON) { - const Point p = steppers::getPosition(); + //ATOMIC_BLOCK(ATOMIC_FORCEON) + { + // From spec: + // endstop status bits: (15-0) : | b max | b min | a max | a min | z max | z min | y max | y min | x max | x min | + Motherboard& board = Motherboard::getBoard(); + uint8_t endstop_status = 0; + for (int i = STEPPER_COUNT-1; i >= 0; i--) { + const StepperInterface* si = board.getStepperInterface(i); + endstop_status <<= 2; + endstop_status |= (si->isAtMaximum()?2:0) | (si->isAtMinimum()?1:0); + } + Point p; + steppers::getPosition(&p); to_host.append8(RC_OK); to_host.append32(p[0]); to_host.append32(p[1]); @@ -229,15 +246,35 @@ inline void handleGetPositionExt(const InPacket& from_host, OutPacket& to_host) to_host.append32(0); to_host.append32(0); #endif + to_host.append16(endstop_status); + } +} + +inline void handleGetPosition16(const InPacket& from_host, OutPacket& to_host) { + //ATOMIC_BLOCK(ATOMIC_FORCEON) + { // From spec: // endstop status bits: (15-0) : | b max | b min | a max | a min | z max | z min | y max | y min | x max | x min | Motherboard& board = Motherboard::getBoard(); uint8_t endstop_status = 0; - for (int i = STEPPER_COUNT; i > 0; i--) { - StepperInterface& si = board.getStepperInterface(i-1); + for (int i = STEPPER_COUNT-1; i >= 0; i--) { + const StepperInterface* si = board.getStepperInterface(i); endstop_status <<= 2; - endstop_status |= (si.isAtMaximum()?2:0) | (si.isAtMinimum()?1:0); + endstop_status |= (si->isAtMaximum()?2:0) | (si->isAtMinimum()?1:0); } + Point p; + steppers::getPosition(&p); + to_host.append8(RC_OK); + to_host.append16(p[0]); + to_host.append16(p[1]); + to_host.append16(p[2]); +#if STEPPER_COUNT > 3 + to_host.append16(p[3]); + to_host.append16(p[4]); +#else + to_host.append16(0); + to_host.append16(0); +#endif to_host.append16(endstop_status); } } @@ -310,10 +347,7 @@ void doToolPause(OutPacket& to_host) { // to check for timeouts on this loop. tool::startTransaction(); tool::releaseLock(); - // WHILE: bounded by tool timeout in runToolSlice - while (!tool::isTransactionDone()) { - tool::runToolSlice(); - } + tool::waitForTransaction(); if (in.getErrorCode() == PacketError::PACKET_TIMEOUT) { to_host.append8(RC_DOWNSTREAM_TIMEOUT); } else { @@ -351,10 +385,7 @@ inline void handleToolQuery(const InPacket& from_host, OutPacket& to_host) { // to check for timeouts on this loop. tool::startTransaction(); tool::releaseLock(); - // WHILE: bounded by tool timeout in runToolSlice - while (!tool::isTransactionDone()) { - tool::runToolSlice(); - } + tool::waitForTransaction(); if (in.getErrorCode() == PacketError::PACKET_TIMEOUT) { to_host.append8(RC_DOWNSTREAM_TIMEOUT); } else { @@ -477,12 +508,17 @@ bool processQueryPacket(const InPacket& from_host, OutPacket& to_host) { case HOST_CMD_GET_BUFFER_SIZE: handleGetBufferSize(from_host,to_host); return true; +/* case HOST_CMD_GET_POSITION: handleGetPosition(from_host,to_host); return true; case HOST_CMD_GET_POSITION_EXT: handleGetPositionExt(from_host,to_host); return true; +*/ + case HOST_CMD_GET_POSITION_16: + handleGetPosition16(from_host,to_host); + return true; case HOST_CMD_CAPTURE_TO_FILE: handleCaptureToFile(from_host,to_host); return true; @@ -555,10 +591,6 @@ char* getBuildName() { return buildName; } -HostState getHostState() { - return currentState; -} - sdcard::SdErrorCode startBuildFromSD() { sdcard::SdErrorCode e; diff --git a/firmware/src/Motherboard/Host.hh b/firmware/src/Motherboard/Host.hh index 1d13327..8cf02c6 100644 --- a/firmware/src/Motherboard/Host.hh +++ b/firmware/src/Motherboard/Host.hh @@ -38,6 +38,8 @@ enum HostState { HOST_STATE_ERROR = 3 }; +void resetHost(); + /// Run the host slice. This function handles incoming packets and host resets. void runHostSlice(); @@ -53,7 +55,8 @@ char* getBuildName(); /// state machine, which is used to determine what information should be /// displayed on the interface board. /// \return Current host state. -HostState getHostState(); +extern HostState currentState; +inline HostState getHostState() { return currentState; } /// Start a build from SD card. The build name should be set by overwriting /// the value of buildName, provided by #getBuildName(). diff --git a/firmware/src/Motherboard/Main.cc b/firmware/src/Motherboard/Main.cc index 147c157..97daf9d 100644 --- a/firmware/src/Motherboard/Main.cc +++ b/firmware/src/Motherboard/Main.cc @@ -28,39 +28,45 @@ #include "SDCard.hh" #include "Eeprom.hh" #include "EepromMap.hh" +#include void reset(bool hard_reset) { + Motherboard& board = Motherboard::getBoard(); ATOMIC_BLOCK(ATOMIC_FORCEON) { - Motherboard& board = Motherboard::getBoard(); sdcard::reset(); steppers::abort(); command::reset(); eeprom::init(); board.reset(); - sei(); - // If we've just come from a hard reset, wait for 2.5 seconds before - // trying to ping an extruder. This gives the extruder time to boot - // before we send it a packet. - if (hard_reset) { - Timeout t; - t.start(1000L*2500L); // wait for 2500 ms - while (!t.hasElapsed()); - tool::test(); // Run test - } - if (!tool::reset()) - { - // Fail, but let it go; toggling the PSU is dangerous. - } + } + + board.initInterfaceBoard(); + + // If we've just come from a hard reset, wait for 2.5 seconds before + // trying to ping an extruder. This gives the extruder time to boot + // before we send it a packet. + if (hard_reset) { + Timeout t; + t.start(1000L*2500L); // wait for 2500 ms + while (!t.hasElapsed()); + tool::test(); // Run test + } + + if (!tool::reset()) + { + // Fail, but let it go; toggling the PSU is dangerous. } + } int main() { Motherboard& board = Motherboard::getBoard(); - steppers::init(Motherboard::getBoard()); + steppers::init(board); reset(true); - sei(); + while (1) { + // Toolhead interaction thread. tool::runToolSlice(); // Host interaction thread. @@ -69,6 +75,12 @@ int main() { command::runCommandSlice(); // Motherboard slice board.runMotherboardSlice(); + +#ifdef TRACE_MAIN_LOOP_CYCLES + static bool debug = false; + debug = !debug; + DEBUG_PIN::setValue(debug); +#endif } return 0; } diff --git a/firmware/src/Motherboard/Point.cc b/firmware/src/Motherboard/Point.cc deleted file mode 100644 index 2184103..0000000 --- a/firmware/src/Motherboard/Point.cc +++ /dev/null @@ -1,33 +0,0 @@ -#include "Point.hh" - -Point::Point() -{ -} - -Point::Point(int32_t x, int32_t y, int32_t z, int32_t a, int32_t b) { - coordinates[0] = x; - coordinates[1] = y; - coordinates[2] = z; -#if AXIS_COUNT > 3 - coordinates[3] = a; - coordinates[4] = b; -#endif -} - -Point::Point(int32_t x, int32_t y, int32_t z) { - coordinates[0] = x; - coordinates[1] = y; - coordinates[2] = z; -#if AXIS_COUNT > 3 - coordinates[3] = 0; - coordinates[4] = 0; -#endif -} - -const int32_t& Point::operator[](unsigned int index) const { - return coordinates[index]; -} - -int32_t& Point::operator[](unsigned int index) { - return coordinates[index]; -} diff --git a/firmware/src/Motherboard/Point.hh b/firmware/src/Motherboard/Point.hh index f20a679..32d836e 100644 --- a/firmware/src/Motherboard/Point.hh +++ b/firmware/src/Motherboard/Point.hh @@ -14,7 +14,7 @@ private: int32_t coordinates[AXIS_COUNT]; ///< n-dimensional coordinate public: /// Default point constructor - Point(); + Point() {} /// Construct a point with the given cooridnates. Coordinates are in /// stepper steps. @@ -23,31 +23,33 @@ public: /// \param[in] z Z axis position /// \param[in] a (if supported) A axis position /// \param[in] b (if supported) B axis position - Point(int32_t x, int32_t y, int32_t z, int32_t a, int32_t b); - - - // TODO: Can this be removed by giving the 5-dimensional function - // some initial values? - /// Construct a point with the given cooridnates. Coordinates are in - /// stepper steps. If used on a 5-dimesional system, the A and B - /// axes are set to zero. - /// \param[in] x X axis position - /// \param[in] y Y axis position - /// \param[in] z Z axis position - Point(int32_t x, int32_t y, int32_t z); +#if AXIS_COUNT > 3 + Point(int32_t x, int32_t y, int32_t z, int32_t a = 0, int32_t b = 0) +#else + Point(int32_t x, int32_t y, int32_t z) +#endif + { + coordinates[0] = x; + coordinates[1] = y; + coordinates[2] = z; +#if AXIS_COUNT > 3 + coordinates[3] = a; + coordinates[4] = b; +#endif + } /// Constant array accessor. /// \param[in] index Axis to look up /// \return Axis position, in steps - const int32_t& operator[](unsigned int index) const; + inline const int32_t& operator[](unsigned int index) const { return coordinates[index]; } /// Array accessor. /// \param[in] index Axis to look up /// \return Reference to the variable containing the axis' position. - int32_t& operator[](unsigned int index); - + inline int32_t& operator[](unsigned int index) { return coordinates[index];} + } __attribute__ ((__packed__)); diff --git a/firmware/src/Motherboard/Steppers.cc b/firmware/src/Motherboard/Steppers.cc index 23707a8..e1c3bdd 100644 --- a/firmware/src/Motherboard/Steppers.cc +++ b/firmware/src/Motherboard/Steppers.cc @@ -24,10 +24,10 @@ namespace steppers { volatile bool is_running; -int32_t intervals; +volatile bool is_homing; volatile int32_t intervals_remaining; +int32_t intervals; StepperAxis axes[STEPPER_COUNT]; -volatile bool is_homing; bool holdZ = false; @@ -39,29 +39,43 @@ bool isRunning() { void init(Motherboard& motherboard) { is_running = false; for (int i = 0; i < STEPPER_COUNT; i++) { - axes[i] = StepperAxis(motherboard.getStepperInterface(i)); + axes[i] = StepperAxis(motherboard.getStepperInterface(i)); } } void abort() { - is_running = false; - is_homing = false; + ATOMIC_BLOCK(ATOMIC_FORCEON) + { + is_running = false; + is_homing = false; + } } /// Define current position as given point void definePosition(const Point& position) { - for (int i = 0; i < STEPPER_COUNT; i++) { - axes[i].definePosition(position[i]); - } + ATOMIC_BLOCK(ATOMIC_FORCEON) + { + axes[0].position = position[0]; + axes[1].position = position[1]; + axes[2].position = position[2]; +#if STEPPER_COUNT > 3 + axes[3].position = position[3]; + axes[4].position = position[4]; +#endif + } } -/// Get current position -const Point getPosition() { +const void getPosition(Point* pt) { + ATOMIC_BLOCK(ATOMIC_FORCEON) + { + (*pt)[0] = axes[0].position; + (*pt)[1] = axes[1].position; + (*pt)[2] = axes[2].position; #if STEPPER_COUNT > 3 - return Point(axes[0].position,axes[1].position,axes[2].position,axes[3].position,axes[4].position); -#else - return Point(axes[0].position,axes[1].position,axes[2].position); + (*pt)[3] = axes[3].position; + (*pt)[4] = axes[4].position; #endif + } } void setHoldZ(bool holdZ_in) { @@ -69,68 +83,86 @@ void setHoldZ(bool holdZ_in) { } void setTarget(const Point& target, int32_t dda_interval) { - int32_t max_delta = 0; - for (int i = 0; i < AXIS_COUNT; i++) { - axes[i].setTarget(target[i], false); - const int32_t delta = axes[i].delta; - // Only shut z axis on inactivity - if (i == 2 && !holdZ) axes[i].enableStepper(delta != 0); - else if (delta != 0) axes[i].enableStepper(true); - if (delta > max_delta) { - max_delta = delta; - } - } - // compute number of intervals for this move - intervals = ((max_delta * dda_interval) / INTERVAL_IN_MICROSECONDS); - intervals_remaining = intervals; - const int32_t negative_half_interval = -intervals / 2; - for (int i = 0; i < AXIS_COUNT; i++) { - axes[i].counter = negative_half_interval; - } - is_running = true; + int32_t max_delta = 0; + for (int i = 0; i < STEPPER_COUNT; i++) { + StepperAxis& axis = axes[i]; + const int32_t delta = axis.setTarget(target[i], false); + // Only shut z axis on inactivity + if (i == 2 && !holdZ) { + axis.enableStepper(delta != 0); + } + else if (delta != 0) { + axis.enableStepper(true); + } + if (delta > max_delta) { + max_delta = delta; + } + } + ATOMIC_BLOCK(ATOMIC_FORCEON){ + // compute number of intervals for this move + intervals = ((max_delta * dda_interval) / INTERVAL_IN_MICROSECONDS); + intervals_remaining = intervals; + const int32_t negative_half_interval = -intervals / 2; + axes[0].counter = negative_half_interval; + axes[1].counter = negative_half_interval; + axes[2].counter = negative_half_interval; +#if STEPPER_COUNT > 3 + axes[3].counter = negative_half_interval; + axes[4].counter = negative_half_interval; +#endif + is_running = true; + } } void setTargetNew(const Point& target, int32_t us, uint8_t relative) { - for (int i = 0; i < AXIS_COUNT; i++) { - axes[i].setTarget(target[i], (relative & (1 << i)) != 0); - // Only shut z axis on inactivity - const int32_t delta = axes[i].delta; - if (i == 2 && !holdZ) { - axes[i].enableStepper(delta != 0); - } else if (delta != 0) { - axes[i].enableStepper(true); - } - } - // compute number of intervals for this move - intervals = us / INTERVAL_IN_MICROSECONDS; - intervals_remaining = intervals; - const int32_t negative_half_interval = -intervals / 2; - for (int i = 0; i < AXIS_COUNT; i++) { - axes[i].counter = negative_half_interval; - } - is_running = true; + for (int i = 0; i < STEPPER_COUNT; i++) { + StepperAxis& axis = axes[i]; + const int32_t delta = axis.setTarget(target[i], (relative & (1 << i)) != 0); + // Only shut z axis on inactivity + if (i == 2 && !holdZ) { + axes[i].enableStepper(delta != 0); + } else if (delta != 0) { + axes[i].enableStepper(true); + } + } + ATOMIC_BLOCK(ATOMIC_FORCEON){ + // compute number of intervals for this move + intervals = us / INTERVAL_IN_MICROSECONDS; + intervals_remaining = intervals; + const int32_t negative_half_interval = -intervals / 2; + axes[0].counter = negative_half_interval; + axes[1].counter = negative_half_interval; + axes[2].counter = negative_half_interval; +#if STEPPER_COUNT > 3 + axes[3].counter = negative_half_interval; + axes[4].counter = negative_half_interval; +#endif + is_running = true; + } } /// Start homing void startHoming(const bool maximums, const uint8_t axes_enabled, const uint32_t us_per_step) { - intervals_remaining = INT32_MAX; - intervals = us_per_step / INTERVAL_IN_MICROSECONDS; - const int32_t negative_half_interval = -intervals / 2; - for (int i = 0; i < AXIS_COUNT; i++) { - axes[i].counter = negative_half_interval; - if ((axes_enabled & (1< 0 + axes[0].doInterrupt(intervals); +#endif +#if STEPPER_COUNT > 1 + axes[1].doInterrupt(intervals); +#endif +#if STEPPER_COUNT > 2 + axes[2].doInterrupt(intervals); +#endif +#if STEPPER_COUNT > 3 + axes[3].doInterrupt(intervals); +#endif +#if STEPPER_COUNT > 4 + axes[4].doInterrupt(intervals); +#endif } return is_running; } else if (is_homing) { - is_homing = false; - for (int i = 0; i < STEPPER_COUNT; i++) { - bool still_homing = axes[i].doHoming(intervals); - is_homing = still_homing || is_homing; - } + is_homing = +#if STEPPER_COUNT > 0 + axes[0].doHoming(intervals) || +#endif +#if STEPPER_COUNT > 1 + axes[1].doHoming(intervals) || +#endif +#if STEPPER_COUNT > 2 + axes[2].doHoming(intervals) || +#endif +#if STEPPER_COUNT > 3 + axes[3].doHoming(intervals) || +#endif +#if STEPPER_COUNT > 4 + axes[4].doHoming(intervals) || +#endif + false; return is_homing; } return false; diff --git a/firmware/src/Motherboard/Steppers.hh b/firmware/src/Motherboard/Steppers.hh index 6fc5ce5..118dceb 100644 --- a/firmware/src/Motherboard/Steppers.hh +++ b/firmware/src/Motherboard/Steppers.hh @@ -20,7 +20,7 @@ #include "Configuration.hh" #include -#include "Pin.hh" +#include "PinTmplt.hh" #include "Command.hh" #include "Point.hh" @@ -83,7 +83,8 @@ namespace steppers { /// Get the current system position /// \return The current machine position. - const Point getPosition(); +// const Point getPosition(); + const void getPosition(Point* point); /// Control whether the Z axis should stay enabled during the entire /// build (defaults to off). This is useful for machines that have @@ -92,6 +93,8 @@ namespace steppers { /// through the entire build. If false, it will be /// disabled when not moving. void setHoldZ(bool holdZ); + + }; #endif // STEPPERS_HH_ diff --git a/firmware/src/Motherboard/Tool.cc b/firmware/src/Motherboard/Tool.cc index 26aedfb..e111bd6 100644 --- a/firmware/src/Motherboard/Tool.cc +++ b/firmware/src/Motherboard/Tool.cc @@ -26,8 +26,6 @@ #define TOOL_PACKET_TIMEOUT_MS 50L #define TOOL_PACKET_TIMEOUT_MICROS (1000L*TOOL_PACKET_TIMEOUT_MS) -#define DELAY_BETWEEN_TRANSMISSIONS_MICROS (500L) - namespace tool { // TODO: Don't bother initializing these here. @@ -101,10 +99,7 @@ bool getToolVersion() { // override standard timeout timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2); releaseLock(); - // WHILE: bounded by tool timeout - while (!isTransactionDone()) { - runToolSlice(); // This will most likely time out if there's multiple toolheads. - } + waitForTransaction(); if (in.getErrorCode() == PacketError::PACKET_TIMEOUT) { return false; @@ -143,13 +138,11 @@ void setToolIndicatorLED() { // override standard timeout timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2); releaseLock(); - // WHILE: bounded by tool timeout - while (!isTransactionDone()) { - runToolSlice(); // This will most likely time out if there's multiple toolheads. - } + waitForTransaction(); } bool reset() { + // This code is very lightly modified from handleToolQuery in Host.cc. // We don't give up if we fail to get a lock; we force it instead. Timeout acquire_lock_timeout; @@ -158,7 +151,7 @@ bool reset() { if (acquire_lock_timeout.hasElapsed()) { locked = true; // grant ourselves the lock transaction_active = false; // abort transaction! - Motherboard::getBoard().indicateError(ERR_SLAVE_LOCK_TIMEOUT); + Motherboard::getBoard().indicateError(ERR_SLAVE_LOCK_TIMEOUT); break; } } @@ -171,10 +164,7 @@ bool reset() { // override standard timeout timeout.start(TOOL_PACKET_TIMEOUT_MICROS*2); releaseLock(); - // WHILE: bounded by tool timeout - while (!isTransactionDone()) { - runToolSlice(); // This will most likely time out if there's multiple toolheads. - } + waitForTransaction(); return UART::getSlaveUART().in.isFinished(); } @@ -215,67 +205,68 @@ void releaseLock() { locked = false; } +static Timeout lastTransaction; void startTransaction() { - sent_packet_count++; - - // Enforce a minimum off-time between transactions - // TODO: Base this on the time from the last transaction. - Timeout t; - t.start(DELAY_BETWEEN_TRANSMISSIONS_MICROS); // wait for xxx us - while (!t.hasElapsed()); - transaction_active = true; + sent_packet_count++; + timeout.start(TOOL_PACKET_TIMEOUT_MICROS); // 50 ms timeout retries = RETRIES; - UART::getSlaveUART().in.reset(); - UART::getSlaveUART().beginSend(); + UART::getSlaveUART().in.reset(); + UART::getSlaveUART().beginSend(); } bool isTransactionDone() { return !transaction_active; } -void runToolSlice() { +void waitForTransaction() +{ + while (transaction_active) { + tool::runToolSlice(); + } +} + +static bool retryCommunication(){ + if (retries) { + packet_retry_count++; + retries--; + timeout.start(TOOL_PACKET_TIMEOUT_MICROS); // 50 ms timeout UART& uart = UART::getSlaveUART(); + uart.out.prepareForResend(); + uart.in.reset(); + uart.reset(); + uart.beginSend(); + return true; + } + return false; +} + +void runToolSlice() { + UART& uart = UART::getSlaveUART(); if (transaction_active) { - if (uart.in.isFinished()) - { + if (uart.in.isFinished()) { transaction_active = false; } else if (uart.in.hasError()) { - if (uart.in.getErrorCode() == PacketError::NOISE_BYTE) { - noise_byte_count++; - uart.in.reset(); - } else - if (retries) { - packet_retry_count++; - retries--; - timeout.start(TOOL_PACKET_TIMEOUT_MICROS); // 50 ms timeout - uart.out.prepareForResend(); - uart.in.reset(); - uart.reset(); - uart.beginSend(); - } else { - packet_failure_count++; - transaction_active = false; - Motherboard::getBoard().indicateError(ERR_SLAVE_PACKET_MISC); - } + if (uart.in.getErrorCode() == PacketError::NOISE_BYTE) { + noise_byte_count++; + uart.in.reset(); + } else if ( !retryCommunication() ) { + transaction_active = false; + Motherboard::getBoard().indicateError(ERR_SLAVE_PACKET_MISC); + } } else if (timeout.hasElapsed()) { - if (retries) { - packet_retry_count++; - retries--; - timeout.start(TOOL_PACKET_TIMEOUT_MICROS); // 50 ms timeout - uart.out.prepareForResend(); - uart.in.reset(); - uart.reset(); - uart.beginSend(); - } else { - packet_failure_count++; + if ( !retryCommunication() ) { uart.in.timeout(); uart.reset(); + packet_failure_count++; transaction_active = false; - Motherboard::getBoard().indicateError(ERR_SLAVE_PACKET_TIMEOUT); + Motherboard::getBoard().indicateError(ERR_SLAVE_PACKET_TIMEOUT); } } + else + { + } } } diff --git a/firmware/src/Motherboard/Tool.hh b/firmware/src/Motherboard/Tool.hh index f829efd..1cf1a41 100644 --- a/firmware/src/Motherboard/Tool.hh +++ b/firmware/src/Motherboard/Tool.hh @@ -57,6 +57,10 @@ void startTransaction(); /// \return True if the transaction is complete. bool isTransactionDone(); +/// Wait for a transaction to completed. +void waitForTransaction(); + + /// Get the output packet /// \return Reference to the output packet, which the host should fill with a query /// to send to the tool. diff --git a/firmware/src/Motherboard/boards/mb24/ButtonArray.cc b/firmware/src/Motherboard/boards/mb24/ButtonArray.cc index 8fda342..8072be7 100644 --- a/firmware/src/Motherboard/boards/mb24/ButtonArray.cc +++ b/firmware/src/Motherboard/boards/mb24/ButtonArray.cc @@ -6,15 +6,17 @@ static uint8_t previousC; void ButtonArray::init() { previousL = 0; previousC = 0; - +#if HAS_INTERFACE_BUTTONS > 0 // Set all of the known buttons to inputs (see above note) DDRL = DDRL & 0x1; DDRC = DDRC & 0xF9; PORTL = PORTL & 0x1; PORTC = PORTC & 0xF9; +#endif // HAS_INTERFACE_BUTTONS > 0 } void ButtonArray::scanButtons() { +#if HAS_INTERFACE_BUTTONS > 0 // Don't bother scanning if we already have a button. if (buttonPressWaiting) { return; @@ -55,9 +57,11 @@ void ButtonArray::scanButtons() { previousL = newL; previousC = newC; +#endif // HAS_INTERFACE_BUTTONS > 0 } bool ButtonArray::getButton(ButtonName& button) { +#if HAS_INTERFACE_BUTTONS > 0 bool buttonValid; uint8_t buttonNumber; @@ -73,4 +77,7 @@ bool ButtonArray::getButton(ButtonName& button) { } return buttonValid; +#else + return false; +#endif // HAS_INTERFACE_BUTTONS > 0 } diff --git a/firmware/src/Motherboard/boards/mb24/Configuration.hh b/firmware/src/Motherboard/boards/mb24/Configuration.hh index f47eedb..f7bde44 100644 --- a/firmware/src/Motherboard/boards/mb24/Configuration.hh +++ b/firmware/src/Motherboard/boards/mb24/Configuration.hh @@ -18,6 +18,7 @@ #ifndef BOARDS_MB24_CONFIGURATION_HH_ #define BOARDS_MB24_CONFIGURATION_HH_ +#include "PinTmplt.hh" /// This file details the pin assignments and features of the /// Makerbot Motherboard v2.x @@ -147,9 +148,15 @@ #define HONOR_DEBUG_PACKETS 1 #define HAS_INTERFACE_BOARD 1 +#if HAS_INTERFACE_BOARD > 0 +#define DISPLAY_TYPE_NONE 0 +#define DISPLAY_TYPE_LIQUIDCRYSTAL 1 -/// Pin mappings for the LCD connection. +//#define DISPLAY_TYPE DISPLAY_TYPE_NONE +#define DISPLAY_TYPE DISPLAY_TYPE_LIQUIDCRYSTAL + +/// Pin mappings for the LiquidCrystal class connection. #define LCD_RS_PIN Pin(PortC,4) #define LCD_ENABLE_PIN Pin(PortC,3) #define LCD_D0_PIN Pin(PortD,7) @@ -163,6 +170,8 @@ /// modified, the #scanButtons() function _must_ be updated to reflect this. /// /// TLDR: These are here for decoration only, actual pins defined in #scanButtons() +#define HAS_INTERFACE_BUTTONS 1 +#if HAS_INTERFACE_BUTTONS > 0 #define INTERFACE_X+_PIN Pin(PortL,7) #define INTERFACE_X-_PIN Pin(PortL,6) #define INTERFACE_Y+_PIN Pin(PortL,5) @@ -177,5 +186,11 @@ #define INTERFACE_FOO_PIN Pin(PortC,0) #define INTERFACE_BAR_PIN Pin(PortL,0) #define INTERFACE_DEBUG_PIN Pin(PortB,7) +#endif // HAS_INTERFACE_BUTTONS > 0 + +#else +#define HAS_INTERFACE_BUTTONS 0 +#endif // HAS_INTERFACE_BOARD > 0 + #endif // BOARDS_RRMBV12_CONFIGURATION_HH_ diff --git a/firmware/src/Motherboard/boards/mb24/Motherboard.cc b/firmware/src/Motherboard/boards/mb24/Motherboard.cc index f829190..7c453cf 100644 --- a/firmware/src/Motherboard/boards/mb24/Motherboard.cc +++ b/firmware/src/Motherboard/boards/mb24/Motherboard.cc @@ -33,69 +33,65 @@ /// Instantiate static motherboard instance Motherboard Motherboard::motherboard; + /// Create motherboard object -Motherboard::Motherboard() : - lcd(LCD_RS_PIN, - LCD_ENABLE_PIN, - LCD_D0_PIN, - LCD_D1_PIN, - LCD_D2_PIN, - LCD_D3_PIN), - interfaceBoard(buttonArray, - lcd, - INTERFACE_FOO_PIN, - INTERFACE_BAR_PIN, +Motherboard::Motherboard() +#if HAS_INTERFACE_BOARD > 0 + : + interfaceBoard( +#if HAS_INTERFACE_BUTTONS > 0 &mainMenu, +#else + &monitorMode, +#endif // HAS_INTERFACE_BUTTONS > 0 &monitorMode) +#endif // HAS_INTERFACE_BOARD > 0 +{ +} + +#if STEPPER_COUNT > 0 +StepperTmpltEndstops<0, X_DIR_PIN,X_STEP_PIN,X_ENABLE_PIN,X_MAX_PIN,X_MIN_PIN> Motherboard::stepperX; +#endif +#if STEPPER_COUNT > 1 +StepperTmpltEndstops<1, Y_DIR_PIN,Y_STEP_PIN,Y_ENABLE_PIN,Y_MAX_PIN,Y_MIN_PIN> Motherboard::stepperY; +#endif +#if STEPPER_COUNT > 2 +StepperTmpltEndstops<2, Z_DIR_PIN,Z_STEP_PIN,Z_ENABLE_PIN,Z_MAX_PIN,Z_MIN_PIN> Motherboard::stepperZ; +#endif +#if STEPPER_COUNT > 3 +StepperTmplt<3, A_DIR_PIN,A_STEP_PIN,A_ENABLE_PIN> Motherboard::stepperA; +#endif +#if STEPPER_COUNT > 4 +StepperTmplt<4, B_DIR_PIN,B_STEP_PIN,B_ENABLE_PIN> Motherboard::stepperB; +#endif +const StepperInterface* Motherboard::stepper[STEPPER_COUNT] = { /// Set up the stepper pins on board creation #if STEPPER_COUNT > 0 - stepper[0] = StepperInterface(X_DIR_PIN, - X_STEP_PIN, - X_ENABLE_PIN, - X_MAX_PIN, - X_MIN_PIN, - eeprom::AXIS_INVERSION); + &stepperX #endif #if STEPPER_COUNT > 1 - stepper[1] = StepperInterface(Y_DIR_PIN, - Y_STEP_PIN, - Y_ENABLE_PIN, - Y_MAX_PIN, - Y_MIN_PIN, - eeprom::AXIS_INVERSION); + ,&stepperY #endif #if STEPPER_COUNT > 2 - stepper[2] = StepperInterface(Z_DIR_PIN, - Z_STEP_PIN, - Z_ENABLE_PIN, - Z_MAX_PIN, - Z_MIN_PIN, - eeprom::AXIS_INVERSION); + ,&stepperZ #endif #if STEPPER_COUNT > 3 - stepper[3] = StepperInterface(A_DIR_PIN, - A_STEP_PIN, - A_ENABLE_PIN, - Pin(), - Pin(), - eeprom::AXIS_INVERSION); + ,&stepperA #endif #if STEPPER_COUNT > 4 - stepper[4] = StepperInterface(B_DIR_PIN, - B_STEP_PIN, - B_ENABLE_PIN, - Pin(), - Pin(), - eeprom::AXIS_INVERSION); + ,&stepperB // swap B for extruder before of lower port usage #endif -} +}; /// Reset the motherboard to its initial state. /// This only resets the board, and does not send a reset /// to any attached toolheads. void Motherboard::reset() { + // Configure the debug pin. + DEBUG_PIN::setDirection(true); + indicateError(0); // turn off blinker // Init steppers @@ -110,10 +106,23 @@ void Motherboard::reset() { bool hold_z = (axis_invert & (1<<7)) == 0; steppers::setHoldZ(hold_z); - for (int i = 0; i < STEPPER_COUNT; i++) { - stepper[i].init(i); - } - // Initialize the host and slave UARTs +#if STEPPER_COUNT > 0 + stepperX.init(); +#endif +#if STEPPER_COUNT > 1 + stepperY.init(); +#endif +#if STEPPER_COUNT > 2 + stepperZ.init(); +#endif +#if STEPPER_COUNT > 3 + stepperA.init(); +#endif +#if STEPPER_COUNT > 4 + stepperB.init(); // swap B for extruder before of lower port usage +#endif + + // Initialize the host and slave UARTs UART::getHostUART().enable(true); UART::getHostUART().in.reset(); UART::getSlaveUART().enable(true); @@ -129,58 +138,56 @@ void Motherboard::reset() { TCCR2A = 0x00; TCCR2B = 0x07; // prescaler at 1/1024 TIMSK2 = 0x01; // OVF flag on - // Configure the debug pin. - DEBUG_PIN.setDirection(true); +} +void Motherboard::initInterfaceBoard() { +#if HAS_INTERFACE_BOARD > 0 // Check if the interface board is attached - hasInterfaceBoard = interface::isConnected(); - + hasInterfaceBoard = interface::isConnected(); if (hasInterfaceBoard) { // Make sure our interface board is initialized - interfaceBoard.init(); - - // Then add the splash screen to it. - interfaceBoard.pushScreen(&splashScreen); - - // Finally, set up the *** interface - interface::init(&interfaceBoard, &lcd); + interfaceBoard.init(); - interface_update_timeout.start(interfaceBoard.getUpdateRate()); - } + // Then add the splash screen to it. + interfaceBoard.pushScreen(&splashScreen); - // Blindly try to reset the toolhead with index 0. -// resetToolhead(); -} + // Finally, set up the *** interface + interface::init(&interfaceBoard); -/// Get the number of microseconds that have passed since -/// the board was booted. -micros_t Motherboard::getCurrentMicros() { - micros_t micros_snapshot; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - micros_snapshot = micros; + interface_update_timeout.start(interfaceBoard.getUpdateRate()); } - return micros_snapshot; +#endif // HAS_INTERFACE_BOARD > 0 } /// Run the motherboard interrupt void Motherboard::doInterrupt() { + + micros += INTERVAL_IN_MICROSECONDS; + +#if HAS_INTERFACE_BOARD > 0 if (hasInterfaceBoard) { - interfaceBoard.doInterrupt(); + interfaceBoard.doInterrupt(); } - micros += INTERVAL_IN_MICROSECONDS; - // Do not move steppers if the board is in a paused state +#endif // HAS_INTERFACE_BOARD > 0 + + // Do not move steppers if the board is in a paused state if (command::isPaused()) return; - steppers::doInterrupt(); + steppers::doInterrupt(); + } void Motherboard::runMotherboardSlice() { + +#if HAS_INTERFACE_BOARD > 0 if (hasInterfaceBoard) { if (interface_update_timeout.hasElapsed()) { - interfaceBoard.doUpdate(); - interface_update_timeout.start(interfaceBoard.getUpdateRate()); + interfaceBoard.doUpdate(); + interface_update_timeout.start(interfaceBoard.getUpdateRate()); } } +#endif + } @@ -204,7 +211,7 @@ enum { void Motherboard::indicateError(int error_code) { if (error_code == 0) { blink_state = BLINK_NONE; - DEBUG_PIN.setValue(false); + DEBUG_PIN::setValue(false); } else if (blink_count != error_code) { blink_state = BLINK_OFF; @@ -238,7 +245,7 @@ ISR(TIMER2_OVF_vect) { blinked_so_far++; blink_state = BLINK_OFF; blink_ovfs_remaining = OVFS_OFF; - DEBUG_PIN.setValue(false); + DEBUG_PIN::setValue(false); } else if (blink_state == BLINK_OFF) { if (blinked_so_far >= blink_count) { blink_state = BLINK_PAUSE; @@ -246,13 +253,13 @@ ISR(TIMER2_OVF_vect) { } else { blink_state = BLINK_ON; blink_ovfs_remaining = OVFS_ON; - DEBUG_PIN.setValue(true); + DEBUG_PIN::setValue(true); } } else if (blink_state == BLINK_PAUSE) { blinked_so_far = 0; blink_state = BLINK_ON; blink_ovfs_remaining = OVFS_ON; - DEBUG_PIN.setValue(true); + DEBUG_PIN::setValue(true); } } } diff --git a/firmware/src/Motherboard/boards/mb24/Motherboard.hh b/firmware/src/Motherboard/boards/mb24/Motherboard.hh index 59326de..9477bfc 100644 --- a/firmware/src/Motherboard/boards/mb24/Motherboard.hh +++ b/firmware/src/Motherboard/boards/mb24/Motherboard.hh @@ -21,13 +21,10 @@ #include "UART.hh" #include "StepperInterface.hh" #include "Types.hh" -#include "PSU.hh" +//#include "PSU.hh" #include "Configuration.hh" #include "Timeout.hh" -#include "Menu.hh" #include "InterfaceBoard.hh" -#include "LiquidCrystal.hh" -#include "ButtonArray.hh" /// Main class for Motherboard version 2.4+ (Gen4 electronics) @@ -35,17 +32,34 @@ /// \ingroup MBv24 class Motherboard { private: - // TODO: Declare this in main, drop the singleton. - /// Static instance of the motherboard - static Motherboard motherboard; + // TODO: Declare this in main, drop the singleton. + /// Static instance of the motherboard + static Motherboard motherboard; public: - /// Get the motherboard instance. - static Motherboard& getBoard() { return motherboard; } + /// Get the motherboard instance. + static Motherboard& getBoard() { return motherboard; } private: - /// Collection of stepper controllers that are on this board - StepperInterface stepper[STEPPER_COUNT]; +#if STEPPER_COUNT > 0 + + static StepperTmpltEndstops<0, X_DIR_PIN,X_STEP_PIN,X_ENABLE_PIN,X_MAX_PIN,X_MIN_PIN> stepperX; +#endif +#if STEPPER_COUNT > 1 + static StepperTmpltEndstops<1, Y_DIR_PIN,Y_STEP_PIN,Y_ENABLE_PIN,Y_MAX_PIN,Y_MIN_PIN> stepperY; +#endif +#if STEPPER_COUNT > 2 + static StepperTmpltEndstops<2, Z_DIR_PIN,Z_STEP_PIN,Z_ENABLE_PIN,Z_MAX_PIN,Z_MIN_PIN> stepperZ; +#endif +#if STEPPER_COUNT > 3 + static StepperTmplt<3, A_DIR_PIN,A_STEP_PIN,A_ENABLE_PIN> stepperA; +#endif +#if STEPPER_COUNT > 4 + static StepperTmplt<4, B_DIR_PIN,B_STEP_PIN,B_ENABLE_PIN> stepperB; +#endif + + /// Collection of stepper controllers that are on this board + static const StepperInterface* stepper[STEPPER_COUNT]; /// Microseconds since board initialization volatile micros_t micros; @@ -53,19 +67,19 @@ private: /// Private constructor; use the singleton Motherboard(); +#if HAS_INTERFACE_BOARD > 0 // TODO: Move this to an interface board slice. Timeout interface_update_timeout; /// True if we have an interface board attached bool hasInterfaceBoard; - ButtonArray buttonArray; - LiquidCrystal lcd; - InterfaceBoard interfaceBoard; + InterfaceBoard interfaceBoard; - MainMenu mainMenu; ///< Main system menu - SplashScreen splashScreen; ///< Displayed at startup - MonitorMode monitorMode; ///< Displayed during build + MainMenu mainMenu; ///< Main system menu + SplashScreen splashScreen; ///< Displayed at startup + MonitorMode monitorMode; ///< Displayed during build +#endif // HAS_INTERFACE_BOARD > 0 public: /// Reset the motherboard to its initial state. @@ -73,12 +87,14 @@ public: /// to any attached toolheads. void reset(); + void initInterfaceBoard(); + void runMotherboardSlice(); /// Count the number of steppers available on this board. const int getStepperCount() const { return STEPPER_COUNT; } /// Get the stepper interface for the nth stepper. - StepperInterface& getStepperInterface(int n) + inline const StepperInterface* getStepperInterface(int n) { return stepper[n]; } @@ -86,7 +102,7 @@ public: /// Get the number of microseconds that have passed since /// the board was initialized. This value will wrap after /// 2**32 microseconds (ca. 70 minutes); callers should compensate for this. - micros_t getCurrentMicros(); + inline micros_t getCurrentMicros() { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {return micros;} } /// Write an error code to the debug pin. void indicateError(int errorCode); diff --git a/firmware/src/Motherboard/boards/rrmbv12/Motherboard.cc b/firmware/src/Motherboard/boards/rrmbv12/Motherboard.cc index 98fe3bb..e760eda 100644 --- a/firmware/src/Motherboard/boards/rrmbv12/Motherboard.cc +++ b/firmware/src/Motherboard/boards/rrmbv12/Motherboard.cc @@ -80,6 +80,7 @@ Motherboard::Motherboard(const Pin& psu_pin) : /// This only resets the board, and does not send a reset /// to any attached toolheads. void Motherboard::reset() { + indicateError(0); // turn off blinker // Init and turn on power supply @@ -101,21 +102,22 @@ void Motherboard::reset() { for (int i = 0; i < STEPPER_COUNT; i++) { stepper[i].init(i); } + // Initialize the host and slave UARTs - UART::getHostUART().enable(true); - UART::getHostUART().in.reset(); + UART::getHostUART().enable(true); + UART::getHostUART().in.reset(); - // TODO: These aren't done on other platforms, are they necessary? - UART::getHostUART().reset(); - UART::getHostUART().out.reset(); + // TODO: These aren't done on other platforms, are they necessary? + UART::getHostUART().reset(); + UART::getHostUART().out.reset(); - UART::getSlaveUART().enable(true); - UART::getSlaveUART().in.reset(); + UART::getSlaveUART().enable(true); + UART::getSlaveUART().in.reset(); - // TODO: These aren't done on other platforms, are they necessary? - UART::getSlaveUART().reset(); - UART::getSlaveUART().out.reset(); + // TODO: These aren't done on other platforms, are they necessary? + UART::getSlaveUART().reset(); + UART::getSlaveUART().out.reset(); // Reset and configure timer 1, the microsecond and stepper @@ -133,16 +135,6 @@ void Motherboard::reset() { DEBUG_PIN.setDirection(true); } -/// Get the number of microseconds that have passed since -/// the board was booted. -micros_t Motherboard::getCurrentMicros() { - micros_t micros_snapshot; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - micros_snapshot = micros; - } - return micros_snapshot; -} - void Motherboard::runMotherboardSlice() { } diff --git a/firmware/src/Motherboard/boards/rrmbv12/Motherboard.hh b/firmware/src/Motherboard/boards/rrmbv12/Motherboard.hh index a151486..0850e90 100644 --- a/firmware/src/Motherboard/boards/rrmbv12/Motherboard.hh +++ b/firmware/src/Motherboard/boards/rrmbv12/Motherboard.hh @@ -55,7 +55,7 @@ public: const int getStepperCount() const { return STEPPERS; } /// Get the stepper interface for the nth stepper. - StepperInterface& getStepperInterface(int n) + inline const StepperInterface* getStepperInterface(int n) { return stepper[n]; } @@ -63,7 +63,7 @@ public: /// Get the number of microseconds that have passed since /// the board was initialized. This value will wrap after /// 2**16 microseconds; callers should compensate for this. - micros_t getCurrentMicros(); + inline micros_t getCurrentMicros() { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {return micros;} } /// Write an error code to the debug pin. void indicateError(int errorCode); diff --git a/firmware/src/Motherboard/lib_sd/sd_raw_config.h b/firmware/src/Motherboard/lib_sd/sd_raw_config.h index 1451cf9..799af8b 100644 --- a/firmware/src/Motherboard/lib_sd/sd_raw_config.h +++ b/firmware/src/Motherboard/lib_sd/sd_raw_config.h @@ -13,7 +13,7 @@ #include #include "Configuration.hh" -#include "Pin.hh" +#include "PinTmplt.hh" #ifdef __cplusplus extern "C" @@ -115,11 +115,11 @@ extern "C" #error "no sd/mmc pin mapping available!" #endif -#define configure_pin_available() SD_DETECT_PIN.setDirection(false) -#define configure_pin_locked() SD_WRITE_PIN.setDirection(false) +#define configure_pin_available() SD_DETECT_PIN::setDirection(false) +#define configure_pin_locked() SD_WRITE_PIN::setDirection(false) -#define get_pin_available() SD_DETECT_PIN.getValue() -#define get_pin_locked() !SD_WRITE_PIN.getValue() +#define get_pin_available() SD_DETECT_PIN::getValue() +#define get_pin_locked() !SD_WRITE_PIN::getValue() #if SD_RAW_SDHC typedef uint64_t offset_t; diff --git a/firmware/src/shared/AvrPort.cc b/firmware/src/shared/AvrPort.cc deleted file mode 100644 index 9d125b4..0000000 --- a/firmware/src/shared/AvrPort.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2010 by Adam Mayer - * - * 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 - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - - -#include "AvrPort.hh" - -#include - -// The AVR port and pin mapping is based on a convention that has held true for all ATMega chips -// released so far: that the ports begin in sequence from register 0x00 from A onwards, and are -// arranged: -// 0 PINx -// 1 DDRx -// 2 PORTx -// This is verified true for the 168/328/644p/1280/2560. - -// We support three platforms: Atmega168 (1 UART), Atmega644, and Atmega1280/2560 -#if defined (__AVR_ATmega168__) \ - || defined (__AVR_ATmega328__) \ - || defined (__AVR_ATmega644P__) \ - || defined (__AVR_ATmega1280__) \ - || defined (__AVR_ATmega2560__) -#else - #error UART not implemented on this processor type! -#endif - - -#define PINx _SFR_MEM8(port_base+0) -#define DDRx _SFR_MEM8(port_base+1) -#define PORTx _SFR_MEM8(port_base+2) - - -AvrPort::AvrPort() : - port_base(NULL_PORT) { -} - - -AvrPort::AvrPort(port_base_t port_base_in) : - port_base(port_base_in) { -} - -bool AvrPort::isNull() { - return port_base == NULL_PORT; -} - - -void AvrPort::setPinDirection(uint8_t pin_index, bool out) { - DDRx = (DDRx & ~_BV(pin_index)) | (out?_BV(pin_index):0); -} - - -bool AvrPort::getPin(uint8_t pin_index) { - return (PINx & _BV(pin_index)) != 0; -} - - -void AvrPort::setPin(uint8_t pin_index, bool on) { - PORTx = (PORTx & ~_BV(pin_index)) | (on?_BV(pin_index):0); -} - - - -#if defined(__AVR_ATmega644P__) || \ - defined(__AVR_ATmega1280__) || \ - defined(__AVR_ATmega2560__) -AvrPort PortA(0x20); -#endif // __AVR_ATmega644P__ -AvrPort PortB(0x23); -AvrPort PortC(0x26); -AvrPort PortD(0x29); -#if defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) -AvrPort PortE(0x2C); -AvrPort PortF(0x2F); -AvrPort PortG(0x32); -AvrPort PortH(0x100); -AvrPort PortJ(0x103); -AvrPort PortK(0x106); -AvrPort PortL(0x109); -#endif //__AVR_ATmega1280__ diff --git a/firmware/src/shared/AvrPort.hh b/firmware/src/shared/AvrPort.hh deleted file mode 100644 index aefc177..0000000 --- a/firmware/src/shared/AvrPort.hh +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2010 by Adam Mayer - * - * 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 - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -#ifndef SHARED_AVR_PORT_HH_ -#define SHARED_AVR_PORT_HH_ - -#include - -#if defined (__AVR_ATmega168__) \ - || defined (__AVR_ATmega328__) \ - || defined (__AVR_ATmega644P__) - - typedef uint8_t port_base_t; - #define NULL_PORT 0xff - -#elif defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) - - typedef uint16_t port_base_t; - #define NULL_PORT 0xffff - -#endif - - -/// The port module represents an eight bit, digital IO port on the -/// AVR microcontroller. This library creates static -/// -/// Porting notes: -/// Be sure to define all of the ports supported by your processor, and to -/// verify that the port registers follow the same convention as the 168. -/// \ingroup HardwareLibraries -class AvrPort { -private: - port_base_t port_base; -public: - AvrPort(); - AvrPort(port_base_t port_base_in); - bool isNull(); - void setPinDirection(uint8_t pin_index, bool out); - bool getPin(uint8_t pin_index); - void setPin(uint8_t pin_index, bool on); -}; - - -extern AvrPort PortA, PortB, PortC, PortD; - -#if defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) - extern AvrPort PortE, PortF, PortG, PortH; - extern AvrPort PortJ, PortK, PortL; -#endif // __AVR_ATmega1280__ - - -#endif // SHARED_AVR_PORT_HH_ - diff --git a/firmware/src/shared/CircularBuffer.hh b/firmware/src/shared/CircularBuffer.hh index a27cd7b..4da9a7a 100644 --- a/firmware/src/shared/CircularBuffer.hh +++ b/firmware/src/shared/CircularBuffer.hh @@ -87,17 +87,17 @@ public: } /// Get the length of the buffer - inline const BufSizeType getLength() const { + inline BufSizeType getLength() const { return length; } /// Get the remaining capacity of this buffer - inline const BufSizeType getRemainingCapacity() const { + inline BufSizeType getRemainingCapacity() const { return size - length; } /// Check if the buffer is empty - inline const bool isEmpty() const { + inline bool isEmpty() const { return length == 0; } /// Read the buffer directly @@ -106,11 +106,11 @@ public: return data[actual_index]; } /// Check the overflow flag - inline const bool hasOverflow() const { + inline bool hasOverflow() const { return overflow; } /// Check the underflow flag - inline const bool hasUnderflow() const { + inline bool hasUnderflow() const { return underflow; } }; diff --git a/firmware/src/shared/Commands.hh b/firmware/src/shared/Commands.hh index 5d8f6ce..e3fd35c 100644 --- a/firmware/src/shared/Commands.hh +++ b/firmware/src/shared/Commands.hh @@ -105,6 +105,11 @@ #define HOST_CMD_STORE_HOME_POSITION 143 #define HOST_CMD_RECALL_HOME_POSITION 144 +#define HOST_CMD_QUEUE_POINT_ABS_16 160 +#define HOST_CMD_QUEUE_POINT_NEW_16 161 +#define HOST_CMD_SET_POSITION_16 162 +#define HOST_CMD_GET_POSITION_16 163 + #define HOST_CMD_DEBUG_ECHO 0x70 // These are our query commands from the host diff --git a/firmware/src/shared/CoolingFan.cc b/firmware/src/shared/CoolingFan.cc index 2ee5520..e4d6e2b 100644 --- a/firmware/src/shared/CoolingFan.cc +++ b/firmware/src/shared/CoolingFan.cc @@ -40,18 +40,6 @@ void CoolingFan::reset() { } } -void CoolingFan::setSetpoint(int temperature) { - setPoint = temperature; -} - -void CoolingFan::enable() { - enabled = true; -} - -void CoolingFan::disable() { - enabled = false; - setFanRunning(false); -} void CoolingFan::manageCoolingFan() { // TODO: only change the state if necessary diff --git a/firmware/src/shared/CoolingFan.hh b/firmware/src/shared/CoolingFan.hh index b333764..9eef87e 100644 --- a/firmware/src/shared/CoolingFan.hh +++ b/firmware/src/shared/CoolingFan.hh @@ -41,7 +41,7 @@ private: Heater& heater; ///< Heater module to read the current temperature from. bool enabled; ///< If true, the control circuit actively controls the fan. - int setPoint; ///< Setpoint temperature, in degrees Celcius. + int16_t setPoint; ///< Setpoint temperature, in degrees Celcius. uint16_t eeprom_base; ///< Base address to read EEPROM configuration from @@ -55,26 +55,26 @@ public: /// Temporarily override the setpoint temperature with a new one. /// The saved valued will be restored when the fan is reset. /// \param[in] temperature Setpoint temperature, in degrees Celcius - void setSetpoint(int temperature); + inline void setSetpoint(int16_t temperature) { setPoint = temperature; } /// Enable the cooling fan module, The fan state will not be modified /// until the next call to #manageCoolingFan(). - void enable(); + inline void enable(){ enabled = true; } /// Disable the cooling fan module. The fan will be disabled /// immediately, and further calls to #manageCoolingFan() will have no /// effect. - void disable(); + inline void disable() { enabled = false; setFanRunning(false); } /// Determine if the cooling fan module is enabled. Note that this just /// means that temperature regulation is enabled, and does not necesicarily /// mean that the fan is turned on. /// \return true if the cooling fan module is managing temperature. - bool isEnabled() { return enabled; } + inline bool isEnabled() { return enabled; } /// Get the setpoint temperature /// \return the current setpoint temperature, in degrees Celcius. - int getSetpoint() { return setPoint; } + inline int16_t getSetpoint() { return setPoint; } /// Reset the cooling fan module, reloading it's default state (tempertaure /// and enabled status) from the EEPROM. diff --git a/firmware/src/shared/Display.hh b/firmware/src/shared/Display.hh new file mode 100644 index 0000000..116c938 --- /dev/null +++ b/firmware/src/shared/Display.hh @@ -0,0 +1,27 @@ +#ifndef DISPLAY_HH +#define DISPLAY_HH + +// TODO: Proper attribution + +#include +#include + +class Display { +public: + Display() {}; + + virtual void init() {}; + virtual void clear() {}; + virtual size_t width() const { return 1; } + virtual size_t height() const { return 1; } + virtual void setCursor(uint8_t, uint8_t) {}; + virtual void write(uint8_t) {}; + + virtual void writeInt(uint16_t value, uint8_t digits) {} + virtual void writeString(const char message[]) {}; + virtual void writeFromPgmspace(const prog_char message[]) {}; + + // note: the base interface provides a NULL Display implementation which does nothing. +}; + +#endif // LIQUID_CRYSTAL_HH diff --git a/firmware/src/shared/Heater.cc b/firmware/src/shared/Heater.cc index 37fba5a..3b701cf 100644 --- a/firmware/src/shared/Heater.cc +++ b/firmware/src/shared/Heater.cc @@ -83,11 +83,6 @@ void Heater::reset() { next_sense_timeout.start(sample_interval_micros); } -void Heater::set_target_temperature(int temp) -{ - pid.setTarget(temp); -} - // We now define target hysteresis in absolute degrees. The original // implementation (+/-5%) was giving us swings of 10% in either direction // *before* any artifacts of process instability came in. @@ -99,27 +94,6 @@ bool Heater::has_reached_target_temperature() (current_temperature <= (pid.getTarget() + TARGET_HYSTERESIS)); } -int Heater::get_set_temperature() { - return pid.getTarget(); -} - -int Heater::get_current_temperature() -{ - return sensor.getTemperature(); -} - -int Heater::getPIDErrorTerm() { - return pid.getErrorTerm(); -} - -int Heater::getPIDDeltaTerm() { - return pid.getDeltaTerm(); -} - -int Heater::getPIDLastOutput() { - return pid.getLastOutput(); -} - void Heater::manage_temperature() { if (fail_state) { @@ -176,7 +150,7 @@ void Heater::manage_temperature() set_output(255); } else { - int mv = pid.calculate(current_temperature); + int16_t mv = pid.calculate(current_temperature); // offset value to compensate for heat bleed-off. // There are probably more elegant ways to do this, // but this works pretty well. @@ -190,18 +164,9 @@ void Heater::manage_temperature() } } -void Heater::set_output(uint8_t value) -{ - element.setHeatingElement(value); -} - void Heater::fail() { fail_state = true; set_output(0); } -bool Heater::has_failed() -{ - return fail_state; -} diff --git a/firmware/src/shared/Heater.hh b/firmware/src/shared/Heater.hh index 537d4cb..7d0c11b 100644 --- a/firmware/src/shared/Heater.hh +++ b/firmware/src/shared/Heater.hh @@ -20,7 +20,7 @@ #include "TemperatureSensor.hh" #include "HeatingElement.hh" -#include "Pin.hh" +#include "PinTmplt.hh" #include "PID.hh" #include "Types.hh" #include "Timeout.hh" @@ -43,7 +43,7 @@ class Heater ///< be updated at. // TODO: Delete this. - int current_temperature; ///< Last known temperature reading + int16_t current_temperature; ///< Last known temperature reading uint16_t eeprom_base; ///< Base address to read EEPROM configuration from PID pid; ///< PID controller instance @@ -79,15 +79,15 @@ class Heater /// Get the current sensor temperature /// \return Current sensor temperature, in degrees Celcius - int get_current_temperature(); + inline int16_t get_current_temperature() { return sensor.getTemperature(); } /// Get the setpoint temperature /// \return Setpoint temperature, in degrees Celcius - int get_set_temperature(); + inline int16_t get_set_temperature() { return pid.getTarget(); } /// Set the target output temperature /// \param temp New target temperature, in degrees Celcius. - void set_target_temperature(int temp); + inline void set_target_temperature(int16_t temp) { pid.setTarget(temp); } /// Check if the heater is within the specified band /// \return True if the heater temperature is within #TARGET_HYSTERESIS degrees @@ -96,7 +96,7 @@ class Heater /// Check if the heater is in a failure state /// \return true if the heater has failed. - bool has_failed(); + inline bool has_failed() { return fail_state; } /// Run the heater management loop. This must be called periodically, /// at a higher frequency than #sample_interval_micros. @@ -104,22 +104,22 @@ class Heater /// Change the setpoint temperature /// \param value New setpoint temperature, in degrees Celcius. - void set_output(uint8_t value); + inline void set_output(uint8_t value) { element.setHeatingElement(value); } /// Reset the heater to a to board-on state void reset(); /// Get the current PID error term /// \return E term from the PID controller - int getPIDErrorTerm(); + inline int16_t getPIDErrorTerm() { return pid.getErrorTerm(); } /// Get the current PID delta term /// \return D term from the PID controller - int getPIDDeltaTerm(); + inline int16_t getPIDDeltaTerm() { return pid.getDeltaTerm(); } /// Get the last PID output /// \return last output from the PID controller - int getPIDLastOutput(); + inline int16_t getPIDLastOutput() { return pid.getLastOutput(); } }; #endif // HEATER_H diff --git a/firmware/src/shared/Interface.cc b/firmware/src/shared/Interface.cc index 902c9aa..daa7867 100644 --- a/firmware/src/shared/Interface.cc +++ b/firmware/src/shared/Interface.cc @@ -1,70 +1,51 @@ #include "Interface.hh" #include "InterfaceBoard.hh" +#if HAS_INTERFACE_BOARD > 0 // TODO: Make this a proper module. -#if defined HAS_INTERFACE_BOARD namespace interface { -LiquidCrystal* lcd; InterfaceBoard* board; bool isConnected() { +#if HAS_INTERFACE_BUTTONS > 0 // Strategy: Set up the foo pin as an input, turn on pull up resistor, // then measure it. If low, then we probably have an interface board. // If high, we probably don't. - INTERFACE_FOO_PIN.setValue(true); - INTERFACE_FOO_PIN.setDirection(false); + INTERFACE_FOO_PIN::setValue(true); + INTERFACE_FOO_PIN::setDirection(false); // if we are pulled down, then we have an led attached?? - if (!INTERFACE_FOO_PIN.getValue()) { - INTERFACE_FOO_PIN.setDirection(true); - INTERFACE_FOO_PIN.setValue(true); + if (!INTERFACE_FOO_PIN::getValue()) { + INTERFACE_FOO_PIN::setDirection(true); + INTERFACE_FOO_PIN::setValue(true); return true; } else { - INTERFACE_FOO_PIN.setDirection(true); - INTERFACE_FOO_PIN.setValue(false); + INTERFACE_FOO_PIN::setDirection(true); + INTERFACE_FOO_PIN::setValue(false); return false; } - return (!INTERFACE_FOO_PIN.getValue()); + return (!INTERFACE_FOO_PIN::getValue()); +#else + return true; +#endif HAS_INTERFACE_BUTTONS > 0 } -void init(InterfaceBoard* board_in, LiquidCrystal* lcd_in) { +void init(InterfaceBoard* board_in) { board = board_in; - lcd = lcd_in; } -void pushScreen(Screen* newScreen) { - board->pushScreen(newScreen); } -void popScreen() { - board->popScreen(); -} - -void doInterrupt() { - board->doInterrupt(); -} - -micros_t getUpdateRate() { - return board->getUpdateRate(); -} - -void doUpdate() { - board->doUpdate(); -} - - -} - -#endif +#endif // HAS_INTERFACE_BOARD > 0 diff --git a/firmware/src/shared/Interface.hh b/firmware/src/shared/Interface.hh index 438e365..8452db7 100644 --- a/firmware/src/shared/Interface.hh +++ b/firmware/src/shared/Interface.hh @@ -19,41 +19,41 @@ #ifndef INTERFACE_HH_ #define INTERFACE_HH_ - -#include "Menu.hh" #include "InterfaceBoard.hh" -#include "LiquidCrystal.hh" +#if HAS_INTERFACE_BOARD > 0 #include "Types.hh" // TODO: This style interface is weird; find a way to replace it. namespace interface { +extern InterfaceBoard* board; + /// Set the current interface board and lcd. This *must* be called before using /// any of the functions in this interface. -void init(InterfaceBoard* board_in, LiquidCrystal* lcd_in); +void init(InterfaceBoard* board_in); /// Returns true if the interface board is connected bool isConnected(); /// Display a new screen by pushing it to the screen stack. /// \param[in] newScreen Screen to be added to the stack. -void pushScreen(Screen* newScreen); +inline void pushScreen(Screen* newScreen) { board->pushScreen(newScreen); } /// Remove the top screen from the screen stack. If there is only one screen left, /// it will not be removed. -void popScreen(); +inline void popScreen() { board->popScreen(); } /// Screen update interrupt. This scans the keypad to look for any changes. To /// ensure a consistant user response, it should be called from a medium frequency /// interrupt. -void doInterrupt(); +inline void doInterrupt() { board->doInterrupt(); } /// Update the display. This function is where the current display screen /// should handle button presses, redraw it's screen, etc. It is run from the /// motherboard slice, not an interrupt, because it may take a relatively long /// time to run. -void doUpdate(); +inline void doUpdate() { board->doUpdate();} /// Returns the minimum amount of time that should elapse before the current /// display screen is updated again. This is customizable to allow for both @@ -61,8 +61,11 @@ void doUpdate(); /// the machine is not printing, as well as slow-updating screens (monitor /// mode) that can be displayed while the machine is running, without causing /// much impact. -micros_t getUpdateRate(); +inline micros_t getUpdateRate() { return board->getUpdateRate();} + } +#endif // HAS_INTERFACE_BOARD > 0 + #endif diff --git a/firmware/src/shared/InterfaceBoard.cc b/firmware/src/shared/InterfaceBoard.cc index ea6cfeb..a67e5ca 100644 --- a/firmware/src/shared/InterfaceBoard.cc +++ b/firmware/src/shared/InterfaceBoard.cc @@ -1,36 +1,59 @@ #include "InterfaceBoard.hh" -#include "Configuration.hh" -#include "LiquidCrystal.hh" +#if HAS_INTERFACE_BOARD > 0 #include "Host.hh" -#if defined HAS_INTERFACE_BOARD +#if DISPLAY_TYPE == DISPLAY_TYPE_NONE +#include "Display.hh" +static Display globalDisplay; + +#elif DISPLAY_TYPE == DISPLAY_TYPE_LIQUIDCRYSTAL +#include "LiquidCrystal.hh" +static LiquidCrystal globalDisplay; + +#elif DISPLAY_TYPE == DISPLAY_TYPE_MODTRONIXLCD2S +#include "ModtronixLCD2S.hh" +static ModtronixLCD2S globalDisplay; + +#elif DISPLAY_TYPE == DISPLAY_TYPE_DUAL +#include "DualDisplay.hh" +static DualDisplay globalDisplay; +#endif + + +#define foo_pin INTERFACE_FOO_PIN +#define bar_pin INTERFACE_BAR_PIN -InterfaceBoard::InterfaceBoard(ButtonArray& buttons_in, - LiquidCrystal& lcd_in, - const Pin& foo_pin_in, - const Pin& bar_pin_in, - Screen* mainScreen_in, +void InterfaceBoard::Debug(const char message[]) +{ + static bool init = false; + if ( !init ) { globalDisplay.init(); init = true; } + static uint16_t row = 0; + globalDisplay.setCursor(0,row++%globalDisplay.height()); + globalDisplay.writeInt(row,4); + globalDisplay.write(' '); + globalDisplay.writeString(message); +} + +InterfaceBoard::InterfaceBoard(Screen* mainScreen_in, Screen* buildScreen_in) : - lcd(lcd_in), - buttons(buttons_in), - foo_pin(foo_pin_in), - bar_pin(bar_pin_in) + display(globalDisplay) { buildScreen = buildScreen_in; mainScreen = mainScreen_in; } + void InterfaceBoard::init() { buttons.init(); - lcd.begin(LCD_SCREEN_WIDTH, LCD_SCREEN_HEIGHT); - lcd.clear(); - lcd.home(); + display.init(); - foo_pin.setValue(false); - foo_pin.setDirection(true); - bar_pin.setValue(false); - bar_pin.setDirection(true); +#if HAS_INTERFACE_BUTTONS > 0 + foo_pin::setValue(false); + foo_pin::setDirection(true); + bar_pin::setValue(false); + bar_pin::setDirection(true); +#endif HAS_INTERFACE_BUTTONS > 0 building = false; @@ -39,14 +62,6 @@ void InterfaceBoard::init() { pushScreen(mainScreen); } -void InterfaceBoard::doInterrupt() { - buttons.scanButtons(); -} - -micros_t InterfaceBoard::getUpdateRate() { - return screenStack[screenIndex]->getUpdateRate(); -} - void InterfaceBoard::doUpdate() { // If we are building, make sure we show a build menu; otherwise, @@ -55,7 +70,7 @@ void InterfaceBoard::doUpdate() { case host::HOST_STATE_BUILDING: case host::HOST_STATE_BUILDING_FROM_SD: if (!building) { - pushScreen(buildScreen); + pushScreen(buildScreen); building = true; } break; @@ -68,14 +83,15 @@ void InterfaceBoard::doUpdate() { } - static ButtonArray::ButtonName button; +#if HAS_INTERFACE_BUTTONS > 0 + static ButtonArray::ButtonName button; if (buttons.getButton(button)) { screenStack[screenIndex]->notifyButtonPressed(button); } - - screenStack[screenIndex]->update(lcd, false); +#endif + screenStack[screenIndex]->update(display, false); } void InterfaceBoard::pushScreen(Screen* newScreen) { @@ -84,7 +100,7 @@ void InterfaceBoard::pushScreen(Screen* newScreen) { screenStack[screenIndex] = newScreen; } screenStack[screenIndex]->reset(); - screenStack[screenIndex]->update(lcd, true); + screenStack[screenIndex]->update(display, true); } void InterfaceBoard::popScreen() { @@ -93,7 +109,7 @@ void InterfaceBoard::popScreen() { screenIndex--; } - screenStack[screenIndex]->update(lcd, true); + screenStack[screenIndex]->update(display, true); } -#endif +#endif // HAS_INTERFACE_BOARD > 0 diff --git a/firmware/src/shared/InterfaceBoard.hh b/firmware/src/shared/InterfaceBoard.hh index d8f6a8d..73e43ae 100644 --- a/firmware/src/shared/InterfaceBoard.hh +++ b/firmware/src/shared/InterfaceBoard.hh @@ -20,8 +20,9 @@ #define INTERFACE_BOARD_HH_ #include "Configuration.hh" -#include "Pin.hh" #include "ButtonArray.hh" +#if HAS_INTERFACE_BOARD > 0 +#include "Display.hh" #include "Menu.hh" /// Maximum number of screens that can be active at once. @@ -30,8 +31,6 @@ /// Character LCD screen geometry /// /// Porting Note: Screens may need to be rewritten to support different sizes. -#define LCD_SCREEN_WIDTH 16 -#define LCD_SCREEN_HEIGHT 4 /// The InterfaceBoard module provides support for the MakerBot Industries @@ -40,9 +39,10 @@ /// \ingroup HardwareLibraries class InterfaceBoard { public: - LiquidCrystal& lcd; ///< LCD to write to + Display& display; ///< LCD to write to private: - ButtonArray& buttons; ///< Button array to read from + + ButtonArray buttons; ///< Button array to read from // TODO: Drop this? Screen* buildScreen; ///< Screen to display while building @@ -56,25 +56,14 @@ private: Screen* screenStack[SCREEN_STACK_DEPTH]; int8_t screenIndex; ///< Stack index of the current screen. - Pin foo_pin; ///< Pin connected to the 'foo' LED - Pin bar_pin; ///< Pin connected to the 'bar' LED - /// TODO: Delete this. bool building; ///< True if the bot is building public: /// Construct an interface board. - /// \param[in] button array to read from - /// \param[in] LCD to display on - /// \param[in] Pin connected to the foo LED - /// \param[in] Pin connected to the bar LED /// \param[in] Main screen, shown as root display /// \param[in] Screen to display while building - InterfaceBoard(ButtonArray& buttons_in, - LiquidCrystal& lcd_in, - const Pin& foo_pin_in, - const Pin& bar_pin_in, - Screen* mainScreen_in, + InterfaceBoard(Screen* mainScreen_in, Screen* buildScreen_in); /// Initialze the interface board. This needs to be called once @@ -83,7 +72,7 @@ public: /// This should be called periodically by a high-speed interrupt to /// service the button input pad. - void doInterrupt(); + inline void doInterrupt() { buttons.scanButtons(); } /// Add a new screen to the stack. This automatically calls reset() /// and then update() on the screen, to ensure that it displays @@ -96,11 +85,13 @@ public: /// being displayed, then this function does nothing. void popScreen(); - micros_t getUpdateRate(); + inline micros_t getUpdateRate() const { return screenStack[screenIndex]->getUpdateRate(); } void doUpdate(); void showMonitorMode(); -}; + static void Debug(const char message[]); +}; +#endif #endif diff --git a/firmware/src/shared/LiquidCrystal.cc b/firmware/src/shared/LiquidCrystal.cc index f46f716..8e0299f 100755 --- a/firmware/src/shared/LiquidCrystal.cc +++ b/firmware/src/shared/LiquidCrystal.cc @@ -1,8 +1,49 @@ -#include "LiquidCrystal.hh" #include #include #include +#include "InterfaceBoard.hh" + +#if HAS_INTERFACE_BOARD > 0 +#include "LiquidCrystal.hh" + +#define _rs_pin LCD_RS_PIN +#define _enable_pin LCD_ENABLE_PIN +#define _d0_pin LCD_D0_PIN +#define _d1_pin LCD_D1_PIN +#define _d2_pin LCD_D2_PIN +#define _d3_pin LCD_D3_PIN + +// commands +#define LCD_CLEARDISPLAY 0x01 +#define LCD_RETURNHOME 0x02 +#define LCD_ENTRYMODESET 0x04 +#define LCD_DISPLAYCONTROL 0x08 +#define LCD_CURSORSHIFT 0x10 +#define LCD_FUNCTIONSET 0x20 +#define LCD_SETCGRAMADDR 0x40 +#define LCD_SETDDRAMADDR 0x80 + +// flags for display entry mode +#define LCD_ENTRYRIGHT 0x00 +#define LCD_ENTRYLEFT 0x02 +#define LCD_ENTRYSHIFTINCREMENT 0x01 +#define LCD_ENTRYSHIFTDECREMENT 0x00 + +// flags for display on/off control +#define LCD_DISPLAYON 0x04 +#define LCD_DISPLAYOFF 0x00 +#define LCD_CURSORON 0x02 +#define LCD_CURSOROFF 0x00 +#define LCD_BLINKON 0x01 +#define LCD_BLINKOFF 0x00 + +// flags for display/cursor shift +#define LCD_DISPLAYMOVE 0x08 +#define LCD_CURSORMOVE 0x00 +#define LCD_MOVERIGHT 0x04 +#define LCD_MOVELEFT 0x00 + // When the display powers up, it is configured as follows: // @@ -23,62 +64,73 @@ // can't assume that its in that state when a sketch starts (and the // LiquidCrystal constructor is called). -LiquidCrystal::LiquidCrystal(Pin rs, Pin rw, Pin enable, - Pin d0, Pin d1, Pin d2, Pin d3, - Pin d4, Pin d5, Pin d6, Pin d7) -{ - init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7); -} -LiquidCrystal::LiquidCrystal(Pin rs, Pin enable, - Pin d0, Pin d1, Pin d2, Pin d3, - Pin d4, Pin d5, Pin d6, Pin d7) +void LiquidCrystal::init() { - init(0, rs, Pin(), enable, d0, d1, d2, d3, d4, d5, d6, d7); + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + _rs_pin::setDirection(true, true); + _enable_pin::setDirection(true, true); + + _rs_pin::setValue(false, true); + _enable_pin::setValue(false, true); + + _d0_pin::setDirection(true, true); + _d1_pin::setDirection(true, true); + _d2_pin::setDirection(true, true); + _d3_pin::setDirection(true, true); + + _d0_pin::setValue(false, true); + _d1_pin::setValue(false, true); + _d2_pin::setValue(false, true); + _d3_pin::setValue(false, true); + } + + _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; + + + begin(width(), height()); } -LiquidCrystal::LiquidCrystal(Pin rs, Pin rw, Pin enable, - Pin d0, Pin d1, Pin d2, Pin d3) + +/************ low level data pushing commands **********/ +static inline void _delay_248ns(void) { - init(1, rs, rw, enable, d0, d1, d2, d3, Pin(), Pin(), Pin(), Pin()); + __asm__ __volatile__ ("nop \n\tnop \n\tnop \n\tnop \n\t"); } -LiquidCrystal::LiquidCrystal(Pin rs, Pin enable, - Pin d0, Pin d1, Pin d2, Pin d3) -{ - init(1, rs, Pin(), enable, d0, d1, d2, d3, Pin(), Pin(), Pin(), Pin()); +inline void LiquidCrystal::write4bits(uint8_t value) { + // set the 4 bits and then pulse the enable line + // we do everything in atomic block to save from entering and + // leaving the atomic block when setting pins on ports + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + _d0_pin::setValue((value & 0x01) != 0, true); + _d1_pin::setValue((value & 0x02) != 0, true); + _d2_pin::setValue((value & 0x04) != 0, true); + _d3_pin::setValue((value & 0x08) != 0, true); + _enable_pin::setValue(true, true); + } + + _delay_248ns(); + _enable_pin::setValue(false); + } -void LiquidCrystal::init(uint8_t fourbitmode, Pin rs, Pin rw, Pin enable, - Pin d0, Pin d1, Pin d2, Pin d3, - Pin d4, Pin d5, Pin d6, Pin d7) -{ - _rs_pin = rs; - _rw_pin = rw; - _enable_pin = enable; - - _data_pins[0] = d0; - _data_pins[1] = d1; - _data_pins[2] = d2; - _data_pins[3] = d3; - _data_pins[4] = d4; - _data_pins[5] = d5; - _data_pins[6] = d6; - _data_pins[7] = d7; - - _rs_pin.setDirection(true); - // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin# - if (!_rw_pin.isNull()) { _rw_pin.setDirection(true); } - _enable_pin.setDirection(true); - - if (fourbitmode) - _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; - else - _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS; - - begin(16, 1); +// write either command or data, with automatic 4/8-bit selection +void LiquidCrystal::send(uint8_t value, bool mode) { + _rs_pin::setValue(mode); + + write4bits(value>>4); + _delay_248ns(); // delay to keep enable_pin low before half a cycle time. + write4bits(value); + + _delay_us(37); // commands need > 37us to settle [citation needed] } + + + void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { if (lines > 1) { _displayfunction |= LCD_2LINE; @@ -93,17 +145,11 @@ void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! // according to datasheet, we need at least 40ms after power rises above 2.7V - // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50 + // before sending commands. Arduino can turn on way before 4.5V so we'll wait 50 _delay_us(50000); - // Now we pull both RS and R/W low to begin commands - _rs_pin.setValue(false); - _enable_pin.setValue(false); - if (!_rw_pin.isNull()) { - _rw_pin.setValue(false); - } + - //put the LCD into 4 bit or 8 bit mode - if (! (_displayfunction & LCD_8BITMODE)) { + //put the LCD into 4 bit o // this is according to the hitachi HD44780 datasheet // figure 24, pg 46 @@ -119,23 +165,8 @@ void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { write4bits(0x03); _delay_us(150); - // finally, set to 8-bit interface + // finally, set to 4-bit interface write4bits(0x02); - } else { - // this is according to the hitachi HD44780 datasheet - // page 45 figure 23 - - // Send function set command sequence - command(LCD_FUNCTIONSET | _displayfunction); - _delay_us(4500); // wait more than 4.1ms - - // second try - command(LCD_FUNCTIONSET | _displayfunction); - _delay_us(150); - - // third go - command(LCD_FUNCTIONSET | _displayfunction); - } // finally, set # lines, font size, etc. command(LCD_FUNCTIONSET | _displayfunction); @@ -251,14 +282,6 @@ void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) { /*********** mid level commands, for sending data/cmds */ -inline void LiquidCrystal::command(uint8_t value) { - send(value, false); -} - -inline void LiquidCrystal::write(uint8_t value) { - send(value, true); -} - void LiquidCrystal::writeInt(uint16_t value, uint8_t digits) { @@ -275,69 +298,25 @@ void LiquidCrystal::writeInt(uint16_t value, uint8_t digits) { for (uint8_t i = 0; i < digits; i++) { nextDigit = currentDigit/10; - write((value%currentDigit)/nextDigit+'0'); + write(uint8_t((value%currentDigit)/nextDigit)+'0'); currentDigit = nextDigit; } } -void LiquidCrystal::writeString(char message[]) { - char* letter = message; +void LiquidCrystal::writeString(const char message[]) { + const char* letter = message; while (*letter != 0) { write(*letter); letter++; } } -void LiquidCrystal::writeFromPgmspace(const prog_uchar message[]) { +void LiquidCrystal::writeFromPgmspace(const prog_char message[]) { char letter; - while (letter = pgm_read_byte(message++)) { + while ((letter = pgm_read_byte(message++))) { write(letter); } } -/************ low level data pushing commands **********/ - -// write either command or data, with automatic 4/8-bit selection -void LiquidCrystal::send(uint8_t value, bool mode) { - _rs_pin.setValue(mode); - - // if there is a RW pin indicated, set it low to Write - if (!_rw_pin.isNull()) { - _rw_pin.setValue(false); - } - - if (_displayfunction & LCD_8BITMODE) { - write8bits(value); - } else { - write4bits(value>>4); - write4bits(value); - } -} - -void LiquidCrystal::pulseEnable(void) { - _enable_pin.setValue(false); - _delay_us(1); - _enable_pin.setValue(true); - _delay_us(1); // enable pulse must be >450ns - _enable_pin.setValue(false); - _delay_us(1); // commands need > 37us to settle [citation needed] -} - -void LiquidCrystal::write4bits(uint8_t value) { - for (int i = 0; i < 4; i++) { - _data_pins[i].setDirection(true); - _data_pins[i].setValue(((value >> i) & 0x01) != 0); - } - - pulseEnable(); -} - -void LiquidCrystal::write8bits(uint8_t value) { - for (int i = 0; i < 8; i++) { - _data_pins[i].setDirection(true); - _data_pins[i].setValue(((value >> i) & 0x01) != 0); - } - - pulseEnable(); -} +#endif // HAS_INTERFACE_BOARD > 0 diff --git a/firmware/src/shared/LiquidCrystal.hh b/firmware/src/shared/LiquidCrystal.hh index 7b70f0e..de833bc 100755 --- a/firmware/src/shared/LiquidCrystal.hh +++ b/firmware/src/shared/LiquidCrystal.hh @@ -4,38 +4,7 @@ // TODO: Proper attribution #include -#include -#include "Pin.hh" - -// commands -#define LCD_CLEARDISPLAY 0x01 -#define LCD_RETURNHOME 0x02 -#define LCD_ENTRYMODESET 0x04 -#define LCD_DISPLAYCONTROL 0x08 -#define LCD_CURSORSHIFT 0x10 -#define LCD_FUNCTIONSET 0x20 -#define LCD_SETCGRAMADDR 0x40 -#define LCD_SETDDRAMADDR 0x80 - -// flags for display entry mode -#define LCD_ENTRYRIGHT 0x00 -#define LCD_ENTRYLEFT 0x02 -#define LCD_ENTRYSHIFTINCREMENT 0x01 -#define LCD_ENTRYSHIFTDECREMENT 0x00 - -// flags for display on/off control -#define LCD_DISPLAYON 0x04 -#define LCD_DISPLAYOFF 0x00 -#define LCD_CURSORON 0x02 -#define LCD_CURSOROFF 0x00 -#define LCD_BLINKON 0x01 -#define LCD_BLINKOFF 0x00 - -// flags for display/cursor shift -#define LCD_DISPLAYMOVE 0x08 -#define LCD_CURSORMOVE 0x00 -#define LCD_MOVERIGHT 0x04 -#define LCD_MOVELEFT 0x00 +#include"Display.hh" // flags for function set #define LCD_8BITMODE 0x10 @@ -45,26 +14,18 @@ #define LCD_5x10DOTS 0x04 #define LCD_5x8DOTS 0x00 -class LiquidCrystal { +#if HAS_INTERFACE_BOARD > 0 + +class LiquidCrystal : public Display { public: - LiquidCrystal(Pin rs, Pin enable, - Pin d0, Pin d1, Pin d2, Pin d3, - Pin d4, Pin d5, Pin d6, Pin d7); - LiquidCrystal(Pin rs, Pin rw, Pin enable, - Pin d0, Pin d1, Pin d2, Pin d3, - Pin d4, Pin d5, Pin d6, Pin d7); - LiquidCrystal(Pin rs, Pin rw, Pin enable, - Pin d0, Pin d1, Pin d2, Pin d3); - LiquidCrystal(Pin rs, Pin enable, - Pin d0, Pin d1, Pin d2, Pin d3); - - void init(uint8_t fourbitmode, Pin rs, Pin rw, Pin enable, - Pin d0, Pin d1, Pin d2, Pin d3, - Pin d4, Pin d5, Pin d6, Pin d7); - + void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS); - void clear(); + virtual void init(); + virtual void clear(); + virtual size_t width() const { return 16; } + virtual size_t height() const { return 4; } + void home(); void noDisplay(); @@ -81,28 +42,24 @@ public: void noAutoscroll(); void createChar(uint8_t, uint8_t[]); - void setCursor(uint8_t, uint8_t); - virtual void write(uint8_t); + virtual void setCursor(uint8_t, uint8_t); + virtual void write(uint8_t value) { send(value, true); } /** Added by MakerBot Industries to support storing strings in flash **/ - void writeInt(uint16_t value, uint8_t digits); + virtual void writeInt(uint16_t value, uint8_t digits); + + virtual void writeString(const char message[]); - void writeString(char message[]); + virtual void writeFromPgmspace(const prog_char message[]); + + inline void command(uint8_t value) { send(value, false); } - void writeFromPgmspace(const prog_uchar message[]); - void command(uint8_t); private: void send(uint8_t, bool); void write4bits(uint8_t); - void write8bits(uint8_t); - void pulseEnable(); - - Pin _rs_pin; // LOW: command. HIGH: character. - Pin _rw_pin; // LOW: write to LCD. HIGH: read from LCD. - Pin _enable_pin; // activated by a HIGH pulse. - Pin _data_pins[8]; + uint8_t _displayfunction; uint8_t _displaycontrol; @@ -113,4 +70,6 @@ private: uint8_t _numlines,_currline; }; +#endif //HAS_INTERFACE_BOARD > 0 + #endif // LIQUID_CRYSTAL_HH diff --git a/firmware/src/shared/Menu.cc b/firmware/src/shared/Menu.cc index 397dd19..b38260a 100644 --- a/firmware/src/shared/Menu.cc +++ b/firmware/src/shared/Menu.cc @@ -1,8 +1,6 @@ +#include "InterfaceBoard.hh" +#if HAS_INTERFACE_BOARD > 0 #include "Menu.hh" -#include "Configuration.hh" - -// TODO: Kill this, should be hanlded by build system. -#ifdef HAS_INTERFACE_BOARD #include "Steppers.hh" #include "Commands.hh" @@ -10,7 +8,6 @@ #include "Tool.hh" #include "Host.hh" #include "Timeout.hh" -#include "InterfaceBoard.hh" #include "Interface.hh" #include #include @@ -24,8 +21,7 @@ #define HOST_TOOL_RESPONSE_TIMEOUT_MICROS (1000L*HOST_TOOL_RESPONSE_TIMEOUT_MS) /// Send a query packet to the extruder -bool queryExtruderParameter(uint8_t parameter, OutPacket& responsePacket) { - +bool queryExtruderParameter(uint8_t parameter, uint16_t& value ) { Timeout acquire_lock_timeout; acquire_lock_timeout.start(HOST_TOOL_RESPONSE_TIMEOUT_MS); while (!tool::getLock()) { @@ -33,10 +29,9 @@ bool queryExtruderParameter(uint8_t parameter, OutPacket& responsePacket) { return false; } } + OutPacket& out = tool::getOutPacket(); - InPacket& in = tool::getInPacket(); out.reset(); - responsePacket.reset(); // Fill the query packet. The first byte is the toolhead index, and the // second is the @@ -47,50 +42,46 @@ bool queryExtruderParameter(uint8_t parameter, OutPacket& responsePacket) { // to check for timeouts on this loop. tool::startTransaction(); tool::releaseLock(); - // WHILE: bounded by tool timeout in runToolSlice - while (!tool::isTransactionDone()) { - tool::runToolSlice(); - } + + // do this busy work after the transaction has started + InPacket& in = tool::getInPacket(); + + tool::waitForTransaction(); + if (in.getErrorCode() == PacketError::PACKET_TIMEOUT) { return false; } else { - // Copy payload back. Start from 0-- we need the response code. - for (uint8_t i = 0; i < in.getLength(); i++) { - responsePacket.append8(in.read8(i)); - } - } + value = in.read16(1); - // Check that the extruder was able to process the request - if (!rcCompare(responsePacket.read8(0),RC_OK)) { - return false; + // Check that the extruder was able to process the request + return rcCompare(in.read8(0),RC_OK); } - return true; } -void SplashScreen::update(LiquidCrystal& lcd, bool forceRedraw) { - static PROGMEM prog_uchar splash1[] = " "; - static PROGMEM prog_uchar splash2[] = " Thing-O-Matic "; - static PROGMEM prog_uchar splash3[] = " --------- "; - static PROGMEM prog_uchar splash4[] = " "; +void SplashScreen::update(Display& display, bool forceRedraw) { + static PROGMEM prog_char splash1[] = " "; + static PROGMEM prog_char splash2[] = " Thing-O-Matic "; + static PROGMEM prog_char splash3[] = " --------- "; + static PROGMEM prog_char splash4[] = " "; if (forceRedraw) { - lcd.setCursor(0,0); - lcd.writeFromPgmspace(splash1); + display.setCursor(0,0); + display.writeFromPgmspace(splash1); - lcd.setCursor(0,1); - lcd.writeFromPgmspace(splash2); + display.setCursor(0,1); + display.writeFromPgmspace(splash2); - lcd.setCursor(0,2); - lcd.writeFromPgmspace(splash3); + display.setCursor(0,2); + display.writeFromPgmspace(splash3); - lcd.setCursor(0,3); - lcd.writeFromPgmspace(splash4); + display.setCursor(0,3); + display.writeFromPgmspace(splash4); } else { // The machine has started, so we're done! - interface::popScreen(); + interface::popScreen(); } } @@ -106,44 +97,46 @@ void JogMode::reset() { distanceChanged = false; } -void JogMode::update(LiquidCrystal& lcd, bool forceRedraw) { - static PROGMEM prog_uchar jog1[] = "Jog mode: "; - static PROGMEM prog_uchar jog2[] = " Y+ Z+"; - static PROGMEM prog_uchar jog3[] = "X- X+ (mode)"; - static PROGMEM prog_uchar jog4[] = " Y- Z-"; +void JogMode::update(Display& display, bool forceRedraw) { + static PROGMEM prog_char jog1[] = "Jog mode: "; + static PROGMEM prog_char jog2[] = " Y+ Z+"; + static PROGMEM prog_char jog3[] = "X- X+ (mode)"; + static PROGMEM prog_char jog4[] = " Y- Z-"; - static PROGMEM prog_uchar distanceShort[] = "SHORT"; - static PROGMEM prog_uchar distanceLong[] = "LONG"; + static PROGMEM prog_char distanceShort[] = "SHORT"; + static PROGMEM prog_char distanceLong[] = "LONG"; if (forceRedraw || distanceChanged) { - lcd.clear(); - lcd.setCursor(0,0); - lcd.writeFromPgmspace(jog1); + display.clear(); + display.setCursor(0,0); + display.writeFromPgmspace(jog1); switch (jogDistance) { case DISTANCE_SHORT: - lcd.writeFromPgmspace(distanceShort); + display.writeFromPgmspace(distanceShort); break; case DISTANCE_LONG: - lcd.writeFromPgmspace(distanceLong); + display.writeFromPgmspace(distanceLong); break; } - lcd.setCursor(0,1); - lcd.writeFromPgmspace(jog2); + display.setCursor(0,1); + display.writeFromPgmspace(jog2); - lcd.setCursor(0,2); - lcd.writeFromPgmspace(jog3); + display.setCursor(0,2); + display.writeFromPgmspace(jog3); - lcd.setCursor(0,3); - lcd.writeFromPgmspace(jog4); + display.setCursor(0,3); + display.writeFromPgmspace(jog4); distanceChanged = false; } } void JogMode::jog(ButtonArray::ButtonName direction) { - Point position = steppers::getPosition(); + + Point position; + steppers::getPosition(&position); int32_t interval = 2000; uint8_t steps; @@ -208,8 +201,8 @@ void JogMode::notifyButtonPressed(ButtonArray::ButtonName button) { } -void SnakeMode::update(LiquidCrystal& lcd, bool forceRedraw) { - static PROGMEM prog_uchar gameOver[] = "GAME OVER!"; +void SnakeMode::update(Display& display, bool forceRedraw) { + static PROGMEM prog_char gameOver[] = "GAME OVER!"; // If we are dead, restart the game. if (!snakeAlive) { @@ -217,22 +210,30 @@ void SnakeMode::update(LiquidCrystal& lcd, bool forceRedraw) { forceRedraw = true; } + if (appleReset) + { + // Put the apple in an initial position (this could collide with the snake!) + applePosition.x = rand()%display.width(); + applePosition.y = rand()%display.height(); + appleReset = false; + } + if (forceRedraw) { - lcd.clear(); + display.clear(); for (uint8_t i = 0; i < snakeLength; i++) { - lcd.setCursor(snakeBody[i].x, snakeBody[i].y); - lcd.write('O'); + display.setCursor(snakeBody[i].x, snakeBody[i].y); + display.write('O'); } } // Always redraw the apple, just in case. - lcd.setCursor(applePosition.x, applePosition.y); - lcd.write('*'); + display.setCursor(applePosition.x, applePosition.y); + display.write('*'); // First, undraw the snake's tail - lcd.setCursor(snakeBody[snakeLength-1].x, snakeBody[snakeLength-1].y); - lcd.write(' '); + display.setCursor(snakeBody[snakeLength-1].x, snakeBody[snakeLength-1].y); + display.write(' '); // Then, shift the snakes body parts back, deleting the tail for(int8_t i = snakeLength-1; i >= 0; i--) { @@ -243,22 +244,22 @@ void SnakeMode::update(LiquidCrystal& lcd, bool forceRedraw) { switch(snakeDirection) { case DIR_EAST: - snakeBody[0].x = (snakeBody[0].x + 1) % LCD_SCREEN_WIDTH; + snakeBody[0].x = (snakeBody[0].x + 1) % display.width(); break; case DIR_WEST: - snakeBody[0].x = (snakeBody[0].x + LCD_SCREEN_WIDTH - 1) % LCD_SCREEN_WIDTH; + snakeBody[0].x = (snakeBody[0].x + display.width() - 1) % display.width(); break; case DIR_NORTH: - snakeBody[0].y = (snakeBody[0].y + LCD_SCREEN_HEIGHT - 1) % LCD_SCREEN_HEIGHT; + snakeBody[0].y = (snakeBody[0].y + display.height() - 1) % display.height(); break; case DIR_SOUTH: - snakeBody[0].y = (snakeBody[0].y + 1) % LCD_SCREEN_HEIGHT; + snakeBody[0].y = (snakeBody[0].y + 1) % display.height(); break; } // Now, draw the snakes new head - lcd.setCursor(snakeBody[0].x, snakeBody[0].y); - lcd.write('O'); + display.setCursor(snakeBody[0].x, snakeBody[0].y); + display.write('O'); // Check if the snake has run into itself for (uint8_t i = 1; i < snakeLength; i++) { @@ -266,8 +267,8 @@ void SnakeMode::update(LiquidCrystal& lcd, bool forceRedraw) { && snakeBody[i].y == snakeBody[0].y) { snakeAlive = false; - lcd.setCursor(1,1); - lcd.writeFromPgmspace(gameOver); + display.setCursor(1,1); + display.writeFromPgmspace(gameOver); updateRate = 5000L * 1000L; } } @@ -282,11 +283,11 @@ void SnakeMode::update(LiquidCrystal& lcd, bool forceRedraw) { updateRate -= 5L * 1000L; } - applePosition.x = rand()%LCD_SCREEN_WIDTH; - applePosition.y = rand()%LCD_SCREEN_HEIGHT; + applePosition.x = rand()%display.width(); + applePosition.y = rand()%display.height(); - lcd.setCursor(applePosition.x, applePosition.y); - lcd.write('*'); + display.setCursor(applePosition.x, applePosition.y); + display.write('*'); } } @@ -302,29 +303,27 @@ void SnakeMode::reset() { snakeBody[1].x = 1; snakeBody[1].y = 1; snakeBody[2].x = 0; snakeBody[2].y = 1; - // Put the apple in an initial position (this could collide with the snake!) - applePosition.x = rand()%LCD_SCREEN_WIDTH; - applePosition.y = rand()%LCD_SCREEN_HEIGHT; + appleReset = true; } void SnakeMode::notifyButtonPressed(ButtonArray::ButtonName button) { switch (button) { case ButtonArray::YMINUS: - snakeDirection = DIR_SOUTH; - break; + snakeDirection = DIR_SOUTH; + break; case ButtonArray::YPLUS: - snakeDirection = DIR_NORTH; - break; + snakeDirection = DIR_NORTH; + break; case ButtonArray::XMINUS: - snakeDirection = DIR_WEST; - break; + snakeDirection = DIR_WEST; + break; case ButtonArray::XPLUS: - snakeDirection = DIR_EAST; - break; + snakeDirection = DIR_EAST; + break; case ButtonArray::CANCEL: - interface::popScreen(); - break; + interface::popScreen(); + break; } } @@ -333,81 +332,69 @@ void MonitorMode::reset() { updatePhase = 0; } -void MonitorMode::update(LiquidCrystal& lcd, bool forceRedraw) { - static PROGMEM prog_uchar extruder_temp[] = "Tool: ---/---C"; - static PROGMEM prog_uchar platform_temp[] = "Bed: ---/---C"; +void MonitorMode::update(Display& display, bool forceRedraw) { + static PROGMEM prog_char extruder_temp[] = "Tool: ---/---C"; + static PROGMEM prog_char platform_temp[] = "Bed: ---/---C"; if (forceRedraw) { - lcd.clear(); - lcd.setCursor(0,0); + display.clear(); + display.setCursor(0,0); switch(host::getHostState()) { case host::HOST_STATE_READY: - lcd.writeString(host::getMachineName()); + display.writeString(host::getMachineName()); break; case host::HOST_STATE_BUILDING: case host::HOST_STATE_BUILDING_FROM_SD: - lcd.writeString(host::getBuildName()); + display.writeString(host::getBuildName()); break; case host::HOST_STATE_ERROR: - lcd.writeString("error!"); + display.writeString("error!"); break; } - lcd.setCursor(0,2); - lcd.writeFromPgmspace(extruder_temp); + display.setCursor(0,2); + display.writeFromPgmspace(extruder_temp); - lcd.setCursor(0,3); - lcd.writeFromPgmspace(platform_temp); + display.setCursor(0,3); + display.writeFromPgmspace(platform_temp); } else { } - OutPacket responsePacket; - + bool success = false; + uint16_t data = 0; // Redraw tool info switch (updatePhase) { case 0: - lcd.setCursor(6,2); - if (queryExtruderParameter(SLAVE_CMD_GET_TEMP, responsePacket)) { - uint16_t data = responsePacket.read16(1); - lcd.writeInt(data,3); - } else { - lcd.writeString("XXX"); - } + display.setCursor(6,2); + success = queryExtruderParameter(SLAVE_CMD_GET_TEMP, data); break; case 1: - lcd.setCursor(10,2); - if (queryExtruderParameter(SLAVE_CMD_GET_SP, responsePacket)) { - uint16_t data = responsePacket.read16(1); - lcd.writeInt(data,3); - } else { - lcd.writeString("XXX"); - } + display.setCursor(10,2); + success = queryExtruderParameter(SLAVE_CMD_GET_SP, data); break; case 2: - lcd.setCursor(6,3); - if (queryExtruderParameter(SLAVE_CMD_GET_PLATFORM_TEMP, responsePacket)) { - uint16_t data = responsePacket.read16(1); - lcd.writeInt(data,3); - } else { - lcd.writeString("XXX"); - } + display.setCursor(6,3); + success = queryExtruderParameter(SLAVE_CMD_GET_PLATFORM_TEMP, data); break; case 3: - lcd.setCursor(10,3); - if (queryExtruderParameter(SLAVE_CMD_GET_PLATFORM_SP, responsePacket)) { - uint16_t data = responsePacket.read16(1); - lcd.writeInt(data,3); - } else { - lcd.writeString("XXX"); - } + display.setCursor(10,3); + success = queryExtruderParameter(SLAVE_CMD_GET_PLATFORM_SP, data); break; } + if ( success ) + { + display.writeInt(data,3); + } else { + display.writeString("XXX"); + } + + updatePhase++; if (updatePhase > 3) { updatePhase = 0; @@ -430,36 +417,36 @@ void MonitorMode::notifyButtonPressed(ButtonArray::ButtonName button) { } -void Menu::update(LiquidCrystal& lcd, bool forceRedraw) { - static PROGMEM prog_uchar blankLine[] = " "; +void Menu::update(Display& display, bool forceRedraw) { + static PROGMEM prog_char blankLine[] = " "; // Do we need to redraw the whole menu? - if ((itemIndex/LCD_SCREEN_HEIGHT) != (lastDrawIndex/LCD_SCREEN_HEIGHT) + if ((itemIndex/display.height()) != (lastDrawIndex/display.height()) || forceRedraw ) { // Redraw the whole menu - lcd.clear(); + display.clear(); - for (uint8_t i = 0; i < LCD_SCREEN_HEIGHT; i++) { - // Instead of using lcd.clear(), clear one line at a time so there + for (uint8_t i = 0; i < display.height(); i++) { + // Instead of using display.clear(), clear one line at a time so there // is less screen flickr. - if (i+(itemIndex/LCD_SCREEN_HEIGHT)*LCD_SCREEN_HEIGHT +1 > itemCount) { + if (i+(itemIndex/display.height())*display.height() +1 > itemCount) { break; } - lcd.setCursor(1,i); + display.setCursor(1,i); // Draw one page of items at a time - drawItem(i+(itemIndex/LCD_SCREEN_HEIGHT)*LCD_SCREEN_HEIGHT, lcd); + drawItem(i+(itemIndex/display.height())*display.height(), display); } } else { // Only need to clear the previous cursor - lcd.setCursor(0,(lastDrawIndex%LCD_SCREEN_HEIGHT)); - lcd.write(' '); + display.setCursor(0,(lastDrawIndex%display.height())); + display.write(' '); } - lcd.setCursor(0,(itemIndex%LCD_SCREEN_HEIGHT)); - lcd.write('>'); + display.setCursor(0,(itemIndex%display.height())); + display.write('>'); lastDrawIndex = itemIndex; } @@ -523,22 +510,22 @@ void CancelBuildMenu::resetState() { firstItemIndex = 2; } -void CancelBuildMenu::drawItem(uint8_t index, LiquidCrystal& lcd) { - static PROGMEM prog_uchar cancel[] = "Cancel Build?"; - static PROGMEM prog_uchar yes[] = "Yes"; - static PROGMEM prog_uchar no[] = "No"; +void CancelBuildMenu::drawItem(uint8_t index, Display& display) { + static PROGMEM prog_char cancel[] = "Cancel Build?"; + static PROGMEM prog_char yes[] = "Yes"; + static PROGMEM prog_char no[] = "No"; switch (index) { case 0: - lcd.writeFromPgmspace(cancel); + display.writeFromPgmspace(cancel); break; case 1: break; case 2: - lcd.writeFromPgmspace(yes); + display.writeFromPgmspace(yes); break; case 3: - lcd.writeFromPgmspace(no); + display.writeFromPgmspace(no); break; } } @@ -564,27 +551,27 @@ MainMenu::MainMenu() { reset(); } -void MainMenu::drawItem(uint8_t index, LiquidCrystal& lcd) { - static PROGMEM prog_uchar monitor[] = "Monitor Mode"; - static PROGMEM prog_uchar build[] = "Build from SD"; - static PROGMEM prog_uchar jog[] = "Jog Mode"; - static PROGMEM prog_uchar snake[] = "Snake Game"; +void MainMenu::drawItem(uint8_t index, Display& display) { + static PROGMEM prog_char monitor[] = "Monitor Mode"; + static PROGMEM prog_char build[] = "Build from SD"; + static PROGMEM prog_char jog[] = "Jog Mode"; + static PROGMEM prog_char snake[] = "Snake Game"; switch (index) { case 0: - lcd.writeFromPgmspace(monitor); + display.writeFromPgmspace(monitor); break; case 1: - lcd.writeFromPgmspace(build); + display.writeFromPgmspace(build); break; case 2: - lcd.writeFromPgmspace(jog); + display.writeFromPgmspace(jog); break; case 3: // blank break; case 4: - lcd.writeFromPgmspace(snake); + display.writeFromPgmspace(snake); break; } } @@ -681,13 +668,13 @@ bool SDMenu::getFilename(uint8_t index, char buffer[], uint8_t buffer_size) { return true; } -void SDMenu::drawItem(uint8_t index, LiquidCrystal& lcd) { +void SDMenu::drawItem(uint8_t index, Display& display) { if (index > itemCount - 1) { // TODO: report error return; } - const uint8_t MAX_FILE_LEN = LCD_SCREEN_WIDTH; + const uint8_t MAX_FILE_LEN = display.width(); char fnbuf[MAX_FILE_LEN]; if ( !getFilename(index, fnbuf, MAX_FILE_LEN) ) { @@ -697,7 +684,7 @@ void SDMenu::drawItem(uint8_t index, LiquidCrystal& lcd) { uint8_t idx; for (idx = 0; (idx < MAX_FILE_LEN) && (fnbuf[idx] != 0); idx++) { - lcd.write(fnbuf[idx]); + display.write(fnbuf[idx]); } } diff --git a/firmware/src/shared/Menu.hh b/firmware/src/shared/Menu.hh index facc93c..c574e3f 100644 --- a/firmware/src/shared/Menu.hh +++ b/firmware/src/shared/Menu.hh @@ -1,9 +1,9 @@ #ifndef MENU_HH_ #define MENU_HH_ +#if HAS_INTERFACE_BOARD > 0 + #include "Types.hh" -#include "ButtonArray.hh" -#include "LiquidCrystal.hh" /// The screen class defines a standard interface for anything that should /// be displayed on the LCD. @@ -21,7 +21,7 @@ public: /// \param[in] lcd LCD to write to /// \param[in] forceRedraw if true, redraw the entire screen. If false, /// only updated sections need to be redrawn. - virtual void update(LiquidCrystal& lcd, bool forceRedraw); + virtual void update(Display& display, bool forceRedraw); /// Reset the screen to it's default state virtual void reset(); @@ -45,7 +45,7 @@ class Menu: public Screen { public: micros_t getUpdateRate() {return 500L * 1000L;} - void update(LiquidCrystal& lcd, bool forceRedraw); + void update(Display& display, bool forceRedraw); void reset(); @@ -65,7 +65,7 @@ protected: /// Draw an item at the current cursor position. /// \param[in] index Index of the item to draw /// \param[in] LCD screen to draw onto - virtual void drawItem(uint8_t index, LiquidCrystal& lcd); + virtual void drawItem(uint8_t index, Display& display); /// Handle selection of a menu item /// \param[in] index Index of the menu item that was selected @@ -82,7 +82,7 @@ class SplashScreen: public Screen { public: micros_t getUpdateRate() {return 50L * 1000L;} - void update(LiquidCrystal& lcd, bool forceRedraw); + void update(Display& display, bool forceRedraw); void reset(); @@ -105,7 +105,7 @@ private: public: micros_t getUpdateRate() {return 50L * 1000L;} - void update(LiquidCrystal& lcd, bool forceRedraw); + void update(Display& display, bool forceRedraw); void reset(); @@ -140,6 +140,7 @@ private: bool snakeAlive; // The state of our snake direction_t snakeDirection; // The direction the snake is heading coord_t applePosition; // Location of the apple + bool appleReset; uint8_t applesEaten; // Number of apples that have been eaten // int gameSpeed = START_SPEED; // Speed of the game (in ms per turn) @@ -148,7 +149,7 @@ public: micros_t getUpdateRate() {return updateRate;} // Refresh the display information - void update(LiquidCrystal& lcd, bool forceRedraw); + void update(Display& display, bool forceRedraw); void reset(); @@ -169,7 +170,7 @@ protected: char buffer[], uint8_t buffer_size); - void drawItem(uint8_t index, LiquidCrystal& lcd); + void drawItem(uint8_t index, Display& display); void handleSelect(uint8_t index); }; @@ -181,7 +182,7 @@ public: void resetState(); protected: - void drawItem(uint8_t index, LiquidCrystal& lcd); + void drawItem(uint8_t index, Display& display); void handleSelect(uint8_t index); }; @@ -196,7 +197,7 @@ private: public: micros_t getUpdateRate() {return 500L * 1000L;} - void update(LiquidCrystal& lcd, bool forceRedraw); + void update(Display& display, bool forceRedraw); void reset(); @@ -209,7 +210,7 @@ public: MainMenu(); protected: - void drawItem(uint8_t index, LiquidCrystal& lcd); + void drawItem(uint8_t index, Display& display); void handleSelect(uint8_t index); @@ -221,4 +222,6 @@ private: SnakeMode snake; }; +#endif // HAS_INTERFACE_BOARD > 0 + #endif diff --git a/firmware/src/shared/PID.cc b/firmware/src/shared/PID.cc index 1eb53db..d93a327 100644 --- a/firmware/src/shared/PID.cc +++ b/firmware/src/shared/PID.cc @@ -61,8 +61,8 @@ void PID::reset_state() { // which will give us a delta impulse for that one calculation round and then // the D term will immediately disappear. By averaging the last N deltas, we // allow changes to be registered rather than get subsumed in the sampling noise. -int PID::calculate(const int pv) { - int e = sp - pv; +int16_t PID::calculate(const int16_t pv) { + int16_t e = sp - pv; error_acc += e; // Clamp the error accumulator at accepted values. // This will help control overcorrection for accumulated error during the run-up @@ -76,7 +76,7 @@ int PID::calculate(const int pv) { } float p_term = (float)e * p_gain; float i_term = (float)error_acc * i_gain; - int delta = e - prev_error; + int16_t delta = e - prev_error; // Add to delta history delta_summation -= delta_history[delta_idx]; delta_history[delta_idx] = delta; @@ -87,26 +87,15 @@ int PID::calculate(const int pv) { prev_error = e; - last_output = ((int)(p_term + i_term + d_term))*OUTPUT_SCALE; + last_output = (int16_t)((p_term + i_term + d_term)*OUTPUT_SCALE); return last_output; } -void PID::setTarget(const int target) { +void PID::setTarget(const int16_t target) { if (sp != target) { reset_state(); sp = target; } } -int PID::getErrorTerm() { - return error_acc; -} - -int PID::getDeltaTerm() { - return (int)delta_summation; -} - -int PID::getLastOutput() { - return (int)last_output; -} diff --git a/firmware/src/shared/PID.hh b/firmware/src/shared/PID.hh index 58049bf..45e3a7f 100644 --- a/firmware/src/shared/PID.hh +++ b/firmware/src/shared/PID.hh @@ -42,11 +42,11 @@ private: int16_t delta_history[DELTA_SAMPLES]; float delta_summation; ///< ? uint8_t delta_idx; ///< Current index in the delta history buffer - int prev_error; ///< Previous input for calculating next delta - int error_acc; ///< Accumulated error, for calculating integral + int16_t prev_error; ///< Previous input for calculating next delta + int16_t error_acc; ///< Accumulated error, for calculating integral - int sp; ///< Process set point - int last_output; ///< Last output of the PID controller + int16_t sp; ///< Process set point + int16_t last_output; ///< Last output of the PID controller public: /// Initialize the PID module @@ -70,7 +70,7 @@ public: /// Get the current PID target /// \return Current setpoint - const int getTarget() const { return sp; } + int16_t getTarget() const { return sp; } /// Reset the PID to board-on values void reset(); @@ -81,19 +81,19 @@ public: /// Calculate the next cycle of the PID loop. /// \param[in] pv Process value (measured value from the sensor) /// \return output value (used to control the output) - int calculate(int pv); + int16_t calculate(int16_t pv); /// Get the current value of the error term /// \return Error term - int getErrorTerm(); + inline int16_t getErrorTerm() { return error_acc; } /// Get the current value of the delta term /// \return Delta term - int getDeltaTerm(); + inline int16_t getDeltaTerm() { return (int16_t)delta_summation; } /// Get the last process output value /// \return Last process output value - int getLastOutput(); + inline int16_t getLastOutput() { return last_output; } }; #endif /* PID_HH_ */ diff --git a/firmware/src/shared/PSU.cc b/firmware/src/shared/PSU.cc index 38d94c8..5496f35 100644 --- a/firmware/src/shared/PSU.cc +++ b/firmware/src/shared/PSU.cc @@ -14,20 +14,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see */ - +#if defined PSU_PIN #include "PSU.hh" -PSU::PSU(const Pin& psu) : - psu_pin(psu) -{ -} void PSU::init() { - psu_pin.setDirection(true); + PSU_PIN::setDirection(true); turnOn(true); } void PSU::turnOn(bool on) { // PSU pin is pulled low to turn on power supply - psu_pin.setValue(!on); + PSU_PIN::setValue(!on); } +#endif \ No newline at end of file diff --git a/firmware/src/shared/PSU.hh b/firmware/src/shared/PSU.hh index 3ac44a2..d5742a0 100644 --- a/firmware/src/shared/PSU.hh +++ b/firmware/src/shared/PSU.hh @@ -18,15 +18,13 @@ #ifndef BOARDS_RRMBV12_PSU_HH_ #define BOARDS_RRMBV12_PSU_HH_ -#include "Pin.hh" +#if defined PSU_PIN +#include "PinTmplt.hh" /// Simple wrapper class for encapsulating the PSU functionality /// \ingroup SoftwareLibraries class PSU { -private: - Pin psu_pin; ///< Power supply enable pin public: - PSU(const Pin& psu); /// Initialize the PSU void init(); @@ -35,5 +33,6 @@ public: /// \param[in] on True to turn the PSU on, False to turn it off. void turnOn(bool on); }; +#endif #endif // BOARDS_RRMBV12_PSU_HH_ diff --git a/firmware/src/shared/Packet.cc b/firmware/src/shared/Packet.cc index 1c8726a..ae92376 100644 --- a/firmware/src/shared/Packet.cc +++ b/firmware/src/shared/Packet.cc @@ -16,10 +16,19 @@ */ #include "Packet.hh" +#include "Configuration.hh" #include +#include +void InPacket::appendByte(uint8_t data) { + if (length < MAX_PACKET_PAYLOAD) { + crc = _crc_ibutton_update(crc, data); + payload[length] = data; + length++; + } +} /// Append a byte and update the CRC -void Packet::appendByte(uint8_t data) { +void OutPacket::appendByte(uint8_t data) { if (length < MAX_PACKET_PAYLOAD) { crc = _crc_ibutton_update(crc, data); payload[length] = data; @@ -39,51 +48,70 @@ void Packet::reset() { state = PS_START; } -InPacket::InPacket() { - reset(); +void InPacket::computeCRC() +{ + if ( state == PS_COMPUTE_CRC ) + { + state = PS_LAST; + uint8_t _crc = 0; + for( uint8_t ndx = 0; ndx < length; ndx++ ) + { + _crc = _crc_ibutton_update(_crc, payload[ndx]); + } + if (crc != _crc) { + error(PacketError::BAD_CRC); + } + } } -/// Reset the entire packet reception. -void InPacket::reset() { - Packet::reset(); -} //process a byte for our packet. void InPacket::processByte(uint8_t b) { - if (state == PS_START) { - if (b == START_BYTE) { - state = PS_LEN; - } else { - error(PacketError::NOISE_BYTE); - } - } else if (state == PS_LEN) { - if (b < MAX_PACKET_PAYLOAD) { - expected_length = b; - state = (expected_length == 0) ? PS_CRC : PS_PAYLOAD; - } else { - error(PacketError::EXCEEDED_MAX_LENGTH); - } - } else if (state == PS_PAYLOAD) { - appendByte(b); - if (length >= expected_length) { - state = PS_CRC; - } - } else if (state == PS_CRC) { - if (crc == b) { - state = PS_LAST; - } else { - error(PacketError::BAD_CRC); - } - } + switch(state){ + case PS_START: + if (b == START_BYTE) { + state = PS_LEN; + } else { + error(PacketError::NOISE_BYTE); + } + break; + case PS_LEN: + if (b < MAX_PACKET_PAYLOAD) { + expected_length = b; + state = (expected_length == 0) ? PS_CRC : PS_PAYLOAD; + } else { + error(PacketError::EXCEEDED_MAX_LENGTH); + } + break; + case PS_PAYLOAD: + appendByte(b); + if (length >= expected_length) { + state = PS_CRC; + } + break; + case PS_CRC: + crc = b; + state = PS_COMPUTE_CRC; +/* + if ( crc == b ) + { + state = PS_LAST; + } + else + { + error(PacketError::BAD_CRC); + } +*/ + break; + default: + break; + } + + } // Reads an 8-bit byte from the specified index of the payload -uint8_t Packet::read8(uint8_t index) const { - return payload[index]; -} -uint16_t Packet::read16(uint8_t index) const { - return payload[index] | (payload[index + 1] << 8); -} +/* uint32_t Packet::read32(uint8_t index) const { union { // AVR is little-endian @@ -92,23 +120,15 @@ uint32_t Packet::read32(uint8_t index) const { uint8_t data[4]; } b; } shared; - shared.b.data[0] = payload[index]; + return *((uint32_t*)(payload+index)); + shared.b.data[0] = p[index]; shared.b.data[1] = payload[index+1]; shared.b.data[2] = payload[index+2]; shared.b.data[3] = payload[index+3]; return shared.a; } - -OutPacket::OutPacket() { - reset(); -} - -/// Reset the entire packet transmission. -void OutPacket::reset() { - Packet::reset(); - send_payload_index = 0; -} +*/ void OutPacket::prepareForResend() { error_code = PacketError::NO_ERROR; @@ -116,36 +136,37 @@ void OutPacket::prepareForResend() { send_payload_index = 0; } uint8_t OutPacket::getNextByteToSend() { - uint8_t next_byte = 0; - if (state == PS_START) { - next_byte = START_BYTE; - state = PS_LEN; - } else if (state == PS_LEN) { - next_byte = length; - state = (length==0)?PS_CRC:PS_PAYLOAD; - } else if (state == PS_PAYLOAD) { - next_byte= payload[send_payload_index++]; - if (send_payload_index >= length) { - state = PS_CRC; - } - } else if (state == PS_CRC) { - next_byte = crc; - state = PS_LAST; + switch(state){ + case PS_START: + state = PS_LEN; + return START_BYTE; + case PS_LEN: + state = (length==0)?PS_CRC:PS_PAYLOAD; + return length; + case PS_PAYLOAD: + { + uint8_t next_byte = payload[send_payload_index++]; + if (send_payload_index >= length) { + state = PS_CRC; + } + return next_byte; + } + case PS_CRC: + state = PS_LAST; + return crc; + default: + // we should never get here + return 0; } - return next_byte; } -// Add an 8-bit byte to the end of the payload -void OutPacket::append8(uint8_t value) { - appendByte(value); -} void OutPacket::append16(uint16_t value) { appendByte(value&0xff); - appendByte((value>>8)&0xff); + appendByte((value>>8)); // don't need to bit-wise AND the last byte } void OutPacket::append32(uint32_t value) { appendByte(value&0xff); appendByte((value>>8)&0xff); appendByte((value>>16)&0xff); - appendByte((value>>24)&0xff); + appendByte((value>>24)); // don't need to bit-wise AND the last byte } diff --git a/firmware/src/shared/Packet.hh b/firmware/src/shared/Packet.hh index 26ab069..ebfcb55 100644 --- a/firmware/src/shared/Packet.hh +++ b/firmware/src/shared/Packet.hh @@ -19,6 +19,7 @@ #define SHARED_PACKET_HH_ #include +#include #define START_BYTE 0xD5 #define MAX_PACKET_PAYLOAD 32 @@ -66,18 +67,17 @@ protected: PS_LEN, PS_PAYLOAD, PS_CRC, + PS_COMPUTE_CRC, PS_LAST } PacketState; - volatile uint8_t length; /// The current length of the payload (data[0] if raw packets) - volatile uint8_t crc; /// The CRC of the current contents of the payload (data[-1] of raw packets) - volatile uint8_t payload[MAX_PACKET_PAYLOAD]; /// Data payload (starts at data[2] of raw packet) + volatile uint8_t length; /// The current length of the payload (data[0] if raw packets) + volatile uint8_t crc; /// The CRC of the current contents of the payload (data[-1] of raw packets) volatile uint8_t error_code; // Have any errors cropped up during processing? volatile PacketState state; + uint8_t payload[MAX_PACKET_PAYLOAD]; /// Data payload (starts at data[2] of raw packet) - /// Append a byte and update the CRC - void appendByte(uint8_t data); /// Reset this packet to an empty state void reset(); @@ -86,42 +86,49 @@ protected: error_code = error_code_in; } public: - uint8_t getLength() const { return length; } + inline uint8_t getLength() const { return length; } - bool hasError() const { + inline bool hasError() const { return error_code != PacketError::NO_ERROR; } - uint8_t getErrorCode() const { return error_code; } + inline uint8_t getErrorCode() const { return error_code; } // Reads an 8-bit byte from the specified index of the payload - uint8_t read8(uint8_t idx) const; - uint16_t read16(uint8_t idx) const; - uint32_t read32(uint8_t idx) const; + inline uint8_t read8(uint8_t idx) const { return payload[idx]; } + inline uint16_t read16(uint8_t idx) const { return *((uint16_t*)(payload+idx)); } //payload[index] | (payload[index + 1] << 8); } + inline uint32_t read32(uint8_t idx) const { return *((uint32_t*)(payload+idx)); } uint8_t debugGetState() const { return state; } - const volatile uint8_t* getData() const { return payload; } + inline const uint8_t* getData() const { return payload; } }; /// Input Packet. class InPacket: public Packet { private: volatile uint8_t expected_length; + + /// Append a byte and update the CRC in a separate step + void appendByte(uint8_t data); + void computeCRC(); + public: - InPacket(); + InPacket() { Packet::reset(); } /// Reset the entire packet reception. - void reset(); + void reset() { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { Packet::reset(); } } + //process a byte for our packet. void processByte(uint8_t b); - bool isFinished() const { + inline bool isFinished() { + if ( state == PS_COMPUTE_CRC ) {computeCRC();} return state == PS_LAST; } - bool isStarted() const { + inline bool isStarted() const { return state != PS_START; } @@ -137,17 +144,25 @@ public: class OutPacket: public Packet { private: uint8_t send_payload_index; + /// Append a byte and update the CRC + void appendByte(uint8_t data); + public: - OutPacket(); + OutPacket() { Packet::reset(); send_payload_index = 0; } /// Reset the entire packet transmission. - void reset(); - - bool isFinished() const { + void reset() { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + Packet::reset(); + send_payload_index = 0; + } + } + + inline bool isFinished() const { return state == PS_LAST; } - bool isSending() const { + inline bool isSending() const { return state != PS_START && state != PS_LAST; } @@ -157,8 +172,8 @@ public: void prepareForResend(); // Add an 8-bit byte to the end of the payload - void append8(uint8_t value); - void append16(uint16_t value); + inline void append8(uint8_t value) { appendByte(value); } + void append16(uint16_t value); void append32(uint32_t value); }; diff --git a/firmware/src/shared/Pin.cc b/firmware/src/shared/Pin.cc deleted file mode 100644 index 6010a95..0000000 --- a/firmware/src/shared/Pin.cc +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pin.hh" - diff --git a/firmware/src/shared/Pin.hh b/firmware/src/shared/Pin.hh deleted file mode 100644 index 2b39db7..0000000 --- a/firmware/src/shared/Pin.hh +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PIN_HH -#define PIN_HH - -#include "AvrPort.hh" -#include "Pin.hh" - -/// \ingroup HardwareLibraries -class Pin { -private: - AvrPort port; - uint8_t pin_index : 4; -public: - Pin() : port(AvrPort()), pin_index(0) {} - Pin(AvrPort& port_in, uint8_t pin_index_in) : port(port_in), pin_index(pin_index_in) {} - bool isNull() { return port.isNull(); } - void setDirection(bool out) { port.setPinDirection(pin_index,out); } - bool getValue() { return port.getPin(pin_index); } - void setValue(bool on) { port.setPin(pin_index,on); } - const uint8_t getPinIndex() const { return pin_index; } -}; - -#endif // PIN_HH diff --git a/firmware/src/shared/PinTmplt.hh b/firmware/src/shared/PinTmplt.hh new file mode 100644 index 0000000..4dc0a9b --- /dev/null +++ b/firmware/src/shared/PinTmplt.hh @@ -0,0 +1,136 @@ +/* + * Copyright 2012 by Craig Link + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +#ifndef PIN_TMPLT_HH_ +#define PIN_TMPLT_HH_ + +#include +#include + +// The AVR port and pin mapping is based on a convention that has held true for all ATMega chips +// released so far: that the ports begin in sequence from register 0x00 from A onwards, and are +// arranged: +// 0 PINx +// 1 DDRx +// 2 PORTx +// This is verified true for the 168/328/644p/1280/2560. + +// We support three platforms: Atmega168 (1 UART), Atmega644, and Atmega1280/2560 +#if defined (__AVR_ATmega168__) \ + || defined (__AVR_ATmega328__) \ + || defined (__AVR_ATmega644P__) \ + || defined (__AVR_ATmega1280__) \ + || defined (__AVR_ATmega2560__) +#else + #error UART not implemented on this processor type! +#endif + +// The AVR port and pin mapping is based on a convention that has held true for all ATMega chips +// released so far: that the ports begin in sequence from register 0x00 from A onwards, and are +// arranged: +// 0 PINx +// 1 DDRx +// 2 PORTx +// This is verified true for the 168/644p/1280. + +#define PINx _SFR_MEM8(port_base+0) +#define DDRx _SFR_MEM8(port_base+1) +#define PORTx _SFR_MEM8(port_base+2) + + +template < uint16_t port_base, uint8_t pin_index > class PinTmplt { +public: + + // ports with 2 byte base address need to be wrapped in an atomic + // block. We provide the option for the caller to wrap several calls in a single + // atomic block for code optimizing. + // see http://code.google.com/p/arduino/issues/detail?id=146 + // and http://code.google.com/p/digitalwritefast/ + + static inline void setDirection(bool output, bool externalAtomicBlock = false) + { + if (port_base != 0) + { + if( (port_base < 0x40) || externalAtomicBlock ) + { + output ? DDRx |= _BV(pin_index) : DDRx &= ~_BV(pin_index); + } + else + { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + output ? DDRx |= _BV(pin_index) : DDRx &= ~_BV(pin_index); + } + } + } + } + + static inline void setValue(bool on, bool externalAtomicBlock = false) + { + if (port_base != 0) + { + if( (port_base < 0x40) || externalAtomicBlock ) + { + on ? PORTx |= _BV(pin_index) : PORTx &= ~_BV(pin_index); + } + else + { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + on ? PORTx |= _BV(pin_index) : PORTx &= ~_BV(pin_index); + } + } + } + } + + static inline bool getValue() + { + if (port_base != 0) + { + return !!(PINx & _BV(pin_index)); + } + else + { + return 0; + } + } + +}; + +#define Pin(port_id,pin_id) PinTmplt + +#define NULL_PIN PinTmplt<0,0> + +#if defined(__AVR_ATmega644P__) || \ + defined(__AVR_ATmega1280__) || \ + defined(__AVR_ATmega2560__) +const uint8_t PortA = 0x20; +#endif // __AVR_ATmega644P__ +const uint8_t PortB = 0x23; +const uint8_t PortC = 0x26; +const uint8_t PortD = 0x29; +#if defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) +const uint8_t PortE = 0x2C; +const uint8_t PortF = 0x2F; +const uint8_t PortG = 0x32; +const uint16_t PortH = 0x100; +const uint16_t PortJ = 0x103; +const uint16_t PortK = 0x106; +const uint16_t PortL = 0x109; +#endif //__AVR_ATmega1280__ +#endif // SHARED_AVR_PORT_HH_ + diff --git a/firmware/src/shared/StepperAxis.cc b/firmware/src/shared/StepperAxis.cc index c69bce1..8cf89d5 100644 --- a/firmware/src/shared/StepperAxis.cc +++ b/firmware/src/shared/StepperAxis.cc @@ -1,17 +1,18 @@ #include "StepperAxis.hh" +#if STEPPER_COUNT > 0 StepperAxis::StepperAxis() : interface(0) { } -StepperAxis::StepperAxis(StepperInterface& stepper_interface) : - interface(&stepper_interface) { +StepperAxis::StepperAxis(const StepperInterface* stepper_interface) : + interface(stepper_interface) { reset(); } -void StepperAxis::setTarget(const int32_t target_in, +int32_t StepperAxis::setTarget(const int32_t target, bool relative) { - target = target_in; + ATOMIC_BLOCK(ATOMIC_FORCEON){ if (relative) { delta = target; } else { @@ -25,27 +26,18 @@ void StepperAxis::setTarget(const int32_t target_in, delta = -delta; direction = false; } + return delta; + } } void StepperAxis::setHoming(const bool direction_in) { - direction = direction_in; - interface->setEnabled(true); - delta = 1; -} - -void StepperAxis::definePosition(const int32_t position_in) { - position = position_in; -} - -void StepperAxis::enableStepper(bool enable) { - interface->setEnabled(enable); + direction = direction_in; + interface->setEnabled(true); + delta = 1; } void StepperAxis::reset() { position = 0; - minimum = 0; - maximum = 0; - target = 0; counter = 0; delta = 0; #if defined(SINGLE_SWITCH_ENDSTOPS) && (SINGLE_SWITCH_ENDSTOPS == 1) @@ -138,3 +130,4 @@ bool StepperAxis::doHoming(const int32_t intervals) { } return true; } +#endif \ No newline at end of file diff --git a/firmware/src/shared/StepperAxis.hh b/firmware/src/shared/StepperAxis.hh index 6d13ef7..b9b1e4e 100644 --- a/firmware/src/shared/StepperAxis.hh +++ b/firmware/src/shared/StepperAxis.hh @@ -1,26 +1,29 @@ #ifndef STEPPERAXIS_HH #define STEPPERAXIS_HH -#include "StepperInterface.hh" #include "Configuration.hh" +#if STEPPER_COUNT > 0 +#include "StepperInterface.hh" + /// The stepper axis module implements a driver for a single stepper axis. It is designed /// to be accessed via the Steppers namespace, and uses a StepperInterface to talk to the /// actual hardware. /// \ingroup SoftwareLibraries class StepperAxis { +protected: + const StepperInterface* interface; ///< Interface this axis is connected to + public: - StepperInterface* interface; ///< Interface this axis is connected to + bool direction; ///< True for positive, false for negative + int32_t delta; ///< Amount to increment counter per tick volatile int32_t position; ///< Current position of this axis, in steps - int32_t minimum; ///< Minimum position, in steps - int32_t maximum; ///< Maximum position, in steps - volatile int32_t target; ///< Target position, in steps volatile int32_t counter; ///< Step counter; represents the proportion of ///< a step so far passed. When the counter hits ///< zero, a step is taken. - volatile int32_t delta; ///< Amount to increment counter per tick - volatile bool direction; ///< True for positive, false for negative + +protected: #if defined(SINGLE_SWITCH_ENDSTOPS) && (SINGLE_SWITCH_ENDSTOPS == 1) volatile bool prev_direction; ///< Record the previous direction for endstop detection volatile int32_t endstop_play; ///< Amount to move while endstop triggered, to see which way to move @@ -50,25 +53,22 @@ public: /// Construct a stepper axis, using the given stepper /// interface /// \param[in] Stepper interface to use - StepperAxis(StepperInterface& stepper_interface); + StepperAxis(const StepperInterface* stepper_interface); /// Set the target position for the axis to travel to. /// \param[in] target_in Postion to move to, in steps /// \param[in] relative If true, consider the target position /// to be relative to the current position. - void setTarget(const int32_t target_in, bool relative); + // Returns the amount of movement required + int32_t setTarget(const int32_t target_in, bool relative); /// Start a homing procedure /// \param[in] direction_in If true, home in the positive direction. void setHoming(const bool direction_in); - /// Reset the axis position to the given position. - /// \param[in] position_in New axis position - void definePosition(const int32_t position_in); - /// Set whether the stepper motor driver on the given axis should be enabled /// \param[in] enable If true, enable the axis; otherwise, disable it. - void enableStepper(bool enable); + inline void enableStepper(bool enable) { interface->setEnabled(enable); } /// Reset to initial state void reset(); @@ -82,5 +82,5 @@ public: /// \return True if the axis is still homing. bool doHoming(const int32_t intervals); }; - +#endif #endif // STEPPERAXIS_HH diff --git a/firmware/src/shared/StepperInterface.cc b/firmware/src/shared/StepperInterface.cc deleted file mode 100644 index e769225..0000000 --- a/firmware/src/shared/StepperInterface.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2010 by Adam Mayer - * - * 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 - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -#include "StepperInterface.hh" -#include "Eeprom.hh" -#include "EepromMap.hh" -#include "Configuration.hh" - -StepperInterface::StepperInterface(const Pin& dir, - const Pin& step, - const Pin& enable, - const Pin& max, - const Pin& min, - const uint16_t eeprom_base_in) : - dir_pin(dir), - step_pin(step), - enable_pin(enable), - max_pin(max), - min_pin(min), - invert_endstops(true), - invert_axis(false), - eeprom_base(eeprom_base_in) { -} - -void StepperInterface::setDirection(bool forward) { - if (invert_axis) forward = !forward; - dir_pin.setValue(forward); -} - -void StepperInterface::step(bool value) { - step_pin.setValue(value); -} - -void StepperInterface::setEnabled(bool enabled) { - // The A3982 stepper driver chip has an inverted enable. - enable_pin.setValue(!enabled); -} - -bool StepperInterface::isAtMaximum() { - if (max_pin.isNull()) return false; - bool v = max_pin.getValue(); - if (invert_endstops) v = !v; - return v; -} - -bool StepperInterface::isAtMinimum() { - if (min_pin.isNull()) return false; - bool v = min_pin.getValue(); - if (invert_endstops) v = !v; - return v; -} - -void StepperInterface::init(uint8_t idx) { - dir_pin.setDirection(true); - step_pin.setDirection(true); - enable_pin.setValue(true); - enable_pin.setDirection(true); - // get inversion characteristics - uint8_t axes_invert = eeprom::getEeprom8(eeprom_base, 1<<1); - uint8_t endstops_invert = eeprom::getEeprom8(eeprom_base + 1, 0); - bool endstops_present = (endstops_invert & (1<<7)) != 0; - - // If endstops are not present, then we consider them inverted, since they will - // always register as high (pulled up). - invert_endstops = !endstops_present || ((endstops_invert & (1< + * Copyright 2011 by Craig Link craig@moonrock.com * * 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 @@ -18,63 +18,130 @@ #ifndef STEPPERINTERFACE_HH_ #define STEPPERINTERFACE_HH_ -#include +#include +#include "Eeprom.hh" +#include "EepromMap.hh" +#include "Configuration.hh" -/// The StepperInterface module represents a connection to a single stepper controller. -/// \ingroup SoftwareLibraries +/// StepperInterface instances encapsulate the low-level communication +/// with a stepper board. class StepperInterface { -private: - /// Default constructor - StepperInterface() {} - StepperInterface(const Pin& dir, - const Pin& step, - const Pin& enable, - const Pin& max, - const Pin& min, - uint16_t eeprom_base_in); +public: + /// Set the direction for the stepper to move + virtual void setDirection(bool forward) const = 0; + + /// Set the value of the step line + virtual void step(bool value) const = 0; + + /// Enable or disable this axis + virtual void setEnabled(bool enabled) const = 0; + + /// True if the axis has triggered its maximum endstop + virtual bool isAtMaximum() const = 0; + /// True if the axis has triggered its minimum endstop + virtual bool isAtMinimum() const = 0; + +}; + +template < uint8_t offset, class dir_pin, class step_pin, class enable_pin > class StepperTmplt : public StepperInterface { + +public: + + /// Set the direction for the stepper to move + // only called from within the StepperAxis interupt routine, so we can assume we're in an atomic block + virtual void setDirection(bool forward) const { dir_pin::setValue(invert_axis ? !forward : forward, true); } + + /// Set the value of the step line + // only called from within the StepperAxis interupt routine, so we can assume we're in an atomic block + virtual void step(bool value) const {step_pin::setValue(value, true);} - friend class Motherboard; + /// Enable or disable this axis + virtual void setEnabled(bool enabled) const + { + // The A3982 stepper driver chip has an inverted enable. + enable_pin::setValue(!enabled); + } -private: - /// Initialize the pins for the interface - /// \param[in] idx Stepper index that this interface refers to (used to look up - /// it's settings in the EEPROM) - void init(uint8_t idx); + /// True if the axis has triggered its maximum endstop + virtual bool isAtMaximum() const + { + return false; + } + /// True if the axis has triggered its minimum endstop + virtual bool isAtMinimum() const + { + return false; + } +protected: - Pin dir_pin; ///< Pin (output) that the direction line is connected to - Pin step_pin; ///< Pin (output) that the step line is connected to - Pin enable_pin; ///< Pin (output) that the enable line is connected to - Pin max_pin; ///< Pin (input) that the maximum endstop is connected to. - Pin min_pin; ///< Pin (input) that the minimum endstop is connected to. - bool invert_endstops; ///< True if endstops input polarity is inverted for - ///< this axis. - bool invert_axis; ///< True if motions for this axis should be inverted + friend class Motherboard; - uint16_t eeprom_base; ///< Base address to read EEPROM configuration from + bool invert_axis; + /// Default constructor + //StepperInterface() {} + StepperTmplt() : invert_axis(false) {} + + void init() + { + dir_pin::setDirection(true); + step_pin::setDirection(true); + enable_pin::setDirection(true); + + enable_pin::setValue(true); + // get inversion characteristics + uint8_t axes_invert = eeprom::getEeprom8(eeprom::AXIS_INVERSION, 1<<1); + invert_axis = (axes_invert & (1< class StepperTmpltEndstops + : public StepperTmplt< offset, dir_pin, step_pin, enable_pin > +{ public: - /// Set the direction for the stepper to move - /// \param[in] forward True to move the stepper forward, false otherwise. - void setDirection(bool forward); - /// Set the value of the step line - /// \param[in] value True to enable, false to disable. This should be toggled - /// back and fourth to effect stepping. - void step(bool value); + /// True if the axis has triggered its maximum endstop + virtual bool isAtMaximum() const + { + bool v = max_pin::getValue(); + if (invert_endstops) v = !v; + return v; + } + /// True if the axis has triggered its minimum endstop + virtual bool isAtMinimum() const + { + bool v = min_pin::getValue(); + if (invert_endstops) v = !v; + return v; + } + +protected: + + friend class Motherboard; + + bool invert_endstops; + + StepperTmpltEndstops() : invert_endstops(true) {} + + void init() + { + StepperTmplt< offset, dir_pin, step_pin, enable_pin >::init(); + uint8_t endstops_invert = eeprom::getEeprom8(eeprom::ENDSTOP_INVERSION, 0); + bool endstops_present = (endstops_invert & (1<<7)) != 0; + // If endstops are not present, then we consider them inverted, since they will + // always register as high (pulled up). + invert_endstops = !endstops_present || ((endstops_invert & (1< 0 // We'll throw in nops to get the timing right (if necessary) inline void nop() { @@ -29,18 +30,15 @@ inline void nop() { asm volatile("nop"::); } +#define cs_pin THERMOCOUPLE_CS ///< Chip select pin (output) +#define sck_pin THERMOCOUPLE_SCK ///< Clock pin (output) +#define so_pin THERMOCOUPLE_SO ///< Data pin (input) -Thermocouple::Thermocouple(const Pin& cs,const Pin& sck,const Pin& so) : - cs_pin(cs), - sck_pin(sck), - so_pin(so) -{ -} void Thermocouple::init() { - cs_pin.setDirection(true); - sck_pin.setDirection(true); - so_pin.setDirection(false); + cs_pin::setDirection(true); + sck_pin::setDirection(true); + so_pin::setDirection(false); // cs_pin.setValue(true); // Clock select is active low // sck_pin.setValue(false); // TODO: Is this a good idea? @@ -49,33 +47,35 @@ void Thermocouple::init() { Thermocouple::SensorState Thermocouple::update() { // TODO: Check timing against datasheet. - cs_pin.setValue(false); + cs_pin::setValue(false); nop(); - sck_pin.setValue(false); + sck_pin::setValue(false); nop(); int raw = 0; for (int i = 0; i < 16; i++) { - sck_pin.setValue(true); + sck_pin::setValue(true); nop(); if (i >= 1 && i < 11) { // data bit... skip LSBs raw = raw << 1; - if (so_pin.getValue()) { raw = raw | 0x01; } + if (so_pin::getValue()) { raw = raw | 0x01; } } if (i == 13) { // Safety check: Check for open thermocouple input - if (so_pin.getValue()) { + if (so_pin::getValue()) { current_temp = BAD_TEMPERATURE; // Set the temperature to 1024 as an error condition return SS_ERROR_UNPLUGGED; } } - sck_pin.setValue(false); + sck_pin::setValue(false); nop(); } - cs_pin.setValue(true); + cs_pin::setValue(true); nop(); - sck_pin.setValue(false); + sck_pin::setValue(false); current_temp = raw; return SS_OK; } + +#endif \ No newline at end of file diff --git a/firmware/src/shared/Thermocouple.hh b/firmware/src/shared/Thermocouple.hh index efc19c3..6ebd548 100644 --- a/firmware/src/shared/Thermocouple.hh +++ b/firmware/src/shared/Thermocouple.hh @@ -18,26 +18,24 @@ #ifndef THERMOCOUPLE_HH_ #define THERMOCOUPLE_HH_ + +#if HAS_THERMOCOUPLE > 0 #include "TemperatureSensor.hh" -#include "Pin.hh" +#include "PinTmplt.hh" /// The thermocouple module provides a bitbanging driver that can read the /// temperature from (chip name) sensor, and also report on any error conditions. /// \ingroup SoftwareLibraries class Thermocouple : public TemperatureSensor { -private: - Pin cs_pin; ///< Chip select pin (output) - Pin sck_pin; ///< Clock pin (output) - Pin so_pin; ///< Data pin (input) public: /// Create a new thermocouple instance, and attach it to the given pins. /// \param [in] cs Chip Select (output). /// \param [in] sck Clock Pin (output). Can be shared with other thermocouples. /// \param [in] so Data Pin (input) - Thermocouple(const Pin& cs,const Pin& sck,const Pin& so); - void init(); + virtual void init(); - SensorState update(); + virtual SensorState update(); }; +#endif #endif // THERMOCOUPLE_HH_ diff --git a/firmware/src/shared/Timeout.cc b/firmware/src/shared/Timeout.cc index 6ebe45d..32789f5 100644 --- a/firmware/src/shared/Timeout.cc +++ b/firmware/src/shared/Timeout.cc @@ -28,18 +28,16 @@ inline micros_t getMicros() { return Motherboard::getBoard().getCurrentMicros(); } #endif -Timeout::Timeout() : active(false), elapsed(false) {} - void Timeout::start(micros_t duration_micros_in) { active = true; elapsed = false; - start_stamp_micros = getMicros(); + start_stamp_micros = getMicros(); duration_micros = duration_micros_in; } bool Timeout::hasElapsed() { if (active && !elapsed) { - micros_t delta = getMicros() - start_stamp_micros; + micros_t delta = getMicros() - start_stamp_micros; if (delta >= duration_micros) { active = false; elapsed = true; diff --git a/firmware/src/shared/Timeout.hh b/firmware/src/shared/Timeout.hh index 2b98e67..c9368d3 100644 --- a/firmware/src/shared/Timeout.hh +++ b/firmware/src/shared/Timeout.hh @@ -36,12 +36,13 @@ private: bool active; ///< True if the timeout object is actively counting down. bool elapsed; ///< True if the timeout object has elapsed. - //TODO: Instead of storing start and duration, precompute and store the elapse time. + //TODO: Instead of storing start and duration, precompute and store the elapse time. micros_t start_stamp_micros; micros_t duration_micros; public: /// Instantiate a new timeout object. - Timeout(); + Timeout() : active(false), elapsed(false) {} + /// Start a new timeout cycle that will elapse after the given amount of time. /// \param [in] duration_micros Microseconds until the timeout cycle should elapse. diff --git a/firmware/src/shared/UART.cc b/firmware/src/shared/UART.cc index a53f9c2..e86a940 100644 --- a/firmware/src/shared/UART.cc +++ b/firmware/src/shared/UART.cc @@ -17,7 +17,7 @@ #include "UART.hh" -#include "Pin.hh" +#include "PinTmplt.hh" #include #include #include @@ -31,6 +31,7 @@ #include "ExtruderBoard.hh" #endif +#define RS485_TRANSMISSION_LINE_DELAY_US 1 // We have to track the number of bytes that have been sent, so that we can filter // them from our receive buffer later.This is only used for RS485 mode. volatile uint8_t loopback_bytes = 0; @@ -45,10 +46,12 @@ volatile uint8_t loopback_bytes = 0; #error UART not implemented on this processor type! #endif +// Use double-speed mode for more accurate baud rate? +#define UCSRA_VALUE(uart_) _BV(U2X##uart_) // baud rate doubling + #if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328__) - #define UBRR_VALUE 25 - #define UCSR0A_VALUE 0 + #define UBRR_VALUE 16 #define INIT_SERIAL(uart_) \ { \ @@ -56,36 +59,16 @@ volatile uint8_t loopback_bytes = 0; UBRR0L = UBRR_VALUE & 0xff; \ \ /* set config for uart, explicitly clear TX interrupt flag */ \ - UCSR0A = UCSR0A_VALUE | _BV(TXC0); \ + UCSR0A = UCSRA_VALUE(uart_) | _BV(TXC0); \ UCSR0B = _BV(RXEN0) | _BV(TXEN0); \ UCSR0C = _BV(UCSZ01)|_BV(UCSZ00); \ } -#elif defined (__AVR_ATmega644P__) - - #define UBRR_VALUE 25 - #define UBRRA_VALUE 0 - - // Adapted from ancient arduino/wiring rabbit hole - #define INIT_SERIAL(uart_) \ - { \ - UBRR##uart_##H = UBRR_VALUE >> 8; \ - UBRR##uart_##L = UBRR_VALUE & 0xff; \ - \ - /* set config for uart_ */ \ - UCSR##uart_##A = UBRRA_VALUE; \ - UCSR##uart_##B = _BV(RXEN##uart_) | _BV(TXEN##uart_); \ - UCSR##uart_##C = _BV(UCSZ##uart_##1)|_BV(UCSZ##uart_##0); \ - } - -#elif defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) +#elif defined (__AVR_ATmega644P__) || defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) - // Use double-speed mode for more accurate baud rate? #define UBRR0_VALUE 16 // 115200 baud - #define UBRR1_VALUE 51 // 38400 baud - #define UCSRA_VALUE(uart_) _BV(U2X##uart_) + #define UBRR1_VALUE 16 // 115200 baud - // Adapted from ancient arduino/wiring rabbit hole #define INIT_SERIAL(uart_) \ { \ UBRR##uart_##H = UBRR##uart_##_VALUE >> 8; \ @@ -138,26 +121,15 @@ void UART::init_serial() { #endif } -void UART::send_byte(char data) { - if(index_ == 0) { - UDR0 = data; - } -#if HAS_SLAVE_UART - else { - UDR1 = data; - } -#endif -} - // Transition to a non-transmitting state. This is only used for RS485 mode. inline void listen() { -// TX_ENABLE_PIN.setValue(false); - TX_ENABLE_PIN.setValue(false); +// TX_ENABLE_PIN::setValue(false); + TX_ENABLE_PIN::setValue(false); } // Transition to a transmitting state inline void speak() { - TX_ENABLE_PIN.setValue(true); + TX_ENABLE_PIN::setValue(true); } UART::UART(uint8_t index, communication_mode mode) : @@ -175,11 +147,18 @@ void UART::beginSend() { if (mode_ == RS485) { speak(); - _delay_us(10); + _delay_us(RS485_TRANSMISSION_LINE_DELAY_US); loopback_bytes = 1; } - send_byte(out.getNextByteToSend()); + if(index_ == 0) { + UDR0 = out.getNextByteToSend(); + } +#if HAS_SLAVE_UART + else { + UDR1 = out.getNextByteToSend(); + } +#endif } void UART::enable(bool enabled) { @@ -197,9 +176,9 @@ void UART::enable(bool enabled) { if (mode_ == RS485) { // If this is an RS485 pin, set up the RX and TX enable control lines. - TX_ENABLE_PIN.setDirection(true); - RX_ENABLE_PIN.setDirection(true); - RX_ENABLE_PIN.setValue(false); // Active low + TX_ENABLE_PIN::setDirection(true); + RX_ENABLE_PIN::setDirection(true); + RX_ENABLE_PIN::setValue(false); // Active low listen(); loopback_bytes = 0; @@ -283,7 +262,7 @@ void UART::reset() { loopback_bytes++; UDR1 = UART::getSlaveUART().out.getNextByteToSend(); } else { - _delay_us(10); + //_delay_us(RS485_TRANSMISSION_LINE_DELAY_US); listen(); } } diff --git a/firmware/src/shared/UART.hh b/firmware/src/shared/UART.hh index e373660..3865d20 100644 --- a/firmware/src/shared/UART.hh +++ b/firmware/src/shared/UART.hh @@ -71,9 +71,6 @@ private: /// Initialize the serial configuration. Must be called once at boot. void init_serial(); - /// Send a byte of data over the serial line. - /// \param[in] data Data byte to send - inline void send_byte(char data); const communication_mode mode_; ///< Communication mode we are speaking const uint8_t index_; ///< Hardware UART index @@ -88,7 +85,7 @@ public: /// Enable or disable the serial port. /// \param[in] true to enable the serial port, false to disable it. - void enable(bool enabled); + void enable(bool enabled); /// Reset the UART to a listening state. This is important for /// RS485-based comms.