diff --git a/CMakeLists.txt b/CMakeLists.txt index 75d66b3e..3c8af6e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,6 +143,7 @@ set(H_FILES set(MK404_SOURCES parts/Board.cpp + parts/I2CPeripheral.cpp parts/boards/EinsyRambo.cpp parts/boards/MiniRambo.cpp parts/boards/MM_Control_01.cpp @@ -153,6 +154,7 @@ set(MK404_SOURCES parts/components/Button.cpp parts/components/EEPROM.cpp parts/components/Fan.cpp + parts/components/GLHelper.cpp parts/components/GCodeSniffer.cpp parts/components/HC595.cpp parts/components/HD44780.cpp @@ -162,6 +164,7 @@ set(MK404_SOURCES parts/components/LED.cpp parts/components/MMU1.cpp parts/components/MMU2.cpp + parts/components/PAT9125.cpp parts/components/PINDA.cpp parts/components/RotaryEncoder.cpp parts/components/SDCard.cpp @@ -177,16 +180,27 @@ set(MK404_SOURCES parts/printers/Prusa_MK25_13.cpp parts/printers/Prusa_MK25S_13.cpp parts/printers/Prusa_MK2MMU_13.cpp + parts/printers/Prusa_MK3.cpp + parts/printers/Prusa_MK3MMU2.cpp parts/printers/Prusa_MK3S.cpp parts/printers/Prusa_MK3SMMU2.cpp parts/printers/Test_Printer.cpp + parts/IScriptable.cpp + parts/Printer.cpp + parts/PrinterFactory.cpp + parts/Scriptable.cpp parts/ScriptHost.cpp + parts/SoftPWMable.cpp parts/TelemetryHost.cpp + utility/MK3S_Bear.cpp + utility/MK3S_Full.cpp + utility/MK3S_Lite.cpp utility/MK3SGL.cpp utility/GLObj.cpp utility/FatImage.cpp utility/GLPrint.cpp utility/Color.cpp + utility/OBJCollection.cpp utility/SerialPipe.cpp 3rdParty/arcball/Camera.cpp parts/IKeyClient.cpp @@ -232,6 +246,17 @@ ExternalProject_Add(simavr ) +add_custom_target(clean-simavr + COMMAND cd ${PROJECT_SOURCE_DIR}/3rdParty/simavr && make clean +) + +add_custom_target(clean-all + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMAND make clean + DEPENDS clean-simavr +) + + add_dependencies(MK404 simavr) set (LIBSIMAVR ${PROJECT_SOURCE_DIR}/3rdParty/simavr/simavr/obj-${SIMAVR_BIN_DIR}/libsimavr.a) diff --git a/MK404.cpp b/MK404.cpp index 946b29e2..7fd4e46d 100644 --- a/MK404.cpp +++ b/MK404.cpp @@ -171,7 +171,7 @@ void timerCB(int i) { glutReshapeWindow(iWinW, iWinH); } - glutTimerFunc(50, timerCB, i); + glutTimerFunc(25, timerCB, i); glutPostRedisplay(); } diff --git a/parts/ADCPeripheral.h b/parts/ADCPeripheral.h index c2634b99..0de4e9e9 100644 --- a/parts/ADCPeripheral.h +++ b/parts/ADCPeripheral.h @@ -28,7 +28,7 @@ class ADCPeripheral: public BasePeripheral { protected: // Returns the current mux number for this peripheral - uint8_t GetMuxNumber() { return m_uiMux; } + inline uint8_t GetMuxNumber() { return m_uiMux; } // Override this with your own ADC implementation. You don't need to worry abouy // verifying you are the current ADC channel. diff --git a/parts/Board.cpp b/parts/Board.cpp index c9144e23..a39b76d0 100644 --- a/parts/Board.cpp +++ b/parts/Board.cpp @@ -21,23 +21,101 @@ */ #include "Board.h" +#include "KeyController.h" // for KeyController +#include "ScriptHost.h" // for ScriptHost #include "TelemetryHost.h" +#include "Util.h" // for CXXDemangle +#include "avr_extint.h" // for avr_extint_set_strict_lvl_trig #include "avr_uart.h" #include "gsl-lite.hpp" +#include "sim_avr_types.h" // for avr_regbit_t #include "sim_elf.h" // for avr_load_firmware, elf_firmware_t, elf_read_fir... #include "sim_gdb.h" // for avr_gdb_init #include "sim_hex.h" // for read_ihex_file #include "sim_io.h" // for avr_io_getirq +#include "sim_regbit.h" // for avr_regbit_get, avr_regbit_set +#include "uart_pty.h" // for uart_pty #include #include // for exit, free #include // for memcpy, NULL #include // IWYU pragma: keep +#include // for operator<<, setw #include #include +#include // for type_info +#include // for usleep namespace Boards { using string = std::string; + Board::Board(const Wirings::Wiring &wiring,uint32_t uiFreqHz):Scriptable("Board"),m_wiring(wiring),m_uiFreq(uiFreqHz) + { + RegisterActionAndMenu("Quit", "Sends the quit signal to the AVR",ScriptAction::Quit); + RegisterActionAndMenu("Reset","Resets the board by resetting the AVR.", ScriptAction::Reset); + RegisterActionAndMenu("Pause","Pauses the simulated AVR execution.", ScriptAction::Pause); + RegisterActionAndMenu("Resume","Resumes simulated AVR execution.", ScriptAction::Unpause); + RegisterAction("WaitMs","Waits the specified number of milliseconds (in AVR-clock time)", ScriptAction::Wait,{ArgType::Int}); + + RegisterKeyHandler('r', "Resets the AVR/board"); + RegisterKeyHandler('z', "Pauses/resumes AVR execution"); + RegisterKeyHandler('q', "Shuts down the board and exits"); + + } + + Board::~Board() + { + if (m_thread) std::cerr << "PROGRAMMING ERROR: " << m_strBoard << " THREAD NOT STOPPED BEFORE DESTRUCTION.\n"; + } + + void Board::AddSerialPty(uart_pty *UART, const char chrNum) + { + UART->Init(m_pAVR); + UART->Connect(chrNum); + } + + bool Board::TryConnect(avr_irq_t *src, PinNames::Pin ePin) + { + if (m_wiring.IsPin(ePin)) + { + avr_connect_irq(src, m_wiring.DIRQLU(m_pAVR,ePin)); + return true; + } + return _PinNotConnectedMsg(ePin); + } + + avr_irq_t* Board::GetDIRQ(PinNames::Pin ePin) + { + if (m_wiring.IsPin(ePin)) + { + return m_wiring.DIRQLU(m_pAVR,ePin); + } + return nullptr; + } + + Board::MCUPin Board::GetPinNumber(PinNames::Pin ePin) + { + if (m_wiring.IsPin(ePin)) + { + return m_wiring.GetPin(ePin); + } + return -1; + } + + avr_irq_t* Board::GetPWMIRQ(PinNames::Pin ePin) + { + if (m_wiring.IsPin(ePin)) + { + return m_wiring.DPWMLU(m_pAVR,ePin); + } + return nullptr; + } + + bool Board::_PinNotConnectedMsg(PinNames::Pin ePin) + { + std:: cout << "Requested connection w/ Digital pin " << ePin << " on " << m_strBoard << ", but it is not defined!\n";; + return false; + } + void Board::CreateAVR() { m_pAVR = avr_make_mcu_by_name(m_wiring.GetMCUName().c_str()); @@ -233,4 +311,112 @@ namespace Boards { } return 0; } + + void Board::DisableInterruptLevelPoll(uint8_t uiNumIntLins) + { + for (int i=0; i &vArgs) + { + switch (ID) + { + case Quit: + SetQuitFlag(); + return LineStatus::Finished; + case Reset: + SetResetFlag(); + return LineStatus::Finished; + case Wait: + if (m_uiWtCycleCount >0) + { + if (--m_uiWtCycleCount==0) + { + return LineStatus::Finished; + } + else + { + return LineStatus::Waiting; + } + } + else + { + m_uiWtCycleCount = (m_uiFreq/1000)*stoi(vArgs.at(0)); + return LineStatus::Waiting; + } + break; + case Pause: + std::cout << "Pause\n"; + m_bPaused.store(true); + return LineStatus::Finished; + case Unpause: + m_bPaused.store(false); + return LineStatus::Finished; + } + return LineStatus::Unhandled; + } + + + void* Board::RunAVR() + { + avr_regbit_t MCUSR = m_pAVR->reset_flags.porf; + MCUSR.mask =0xFF; + MCUSR.bit = 0; + std::cout << "Starting " << m_wiring.GetMCUName() << " execution...\n"; + int state = cpu_Running; + while ((state != cpu_Done) && (state != cpu_Crashed) && !m_bQuit){ + // Re init the special workarounds we need after a reset. + if (m_bIsPrimary) // Only one board should be scripting. + { + ScriptHost::DispatchMenuCB(); + KeyController::GetController().OnAVRCycle(); // Handle/dispatch any pressed keys. + } + if (m_bIsPrimary && ScriptHost::IsInitialized()) + { + ScriptHost::OnAVRCycle(); + } + if (m_bPaused) + { + usleep(100000); + continue; + } + int8_t uiMCUSR = avr_regbit_get(m_pAVR,MCUSR); + if (uiMCUSR != m_uiLastMCUSR) + { + std::cout << "MCUSR: " << std::setw(2) << std::hex << (m_uiLastMCUSR = uiMCUSR) << '\n'; + if (uiMCUSR) // only run on change and not changed to 0 + { + OnAVRReset(); + } + } + OnAVRCycle(); + + if (m_bReset) + { + m_bReset = false; + avr_reset(m_pAVR); + avr_regbit_set(m_pAVR, m_pAVR->reset_flags.extrf); + } + state = avr_run(m_pAVR); + } + std::cout << m_wiring.GetMCUName() << "finished (" << state << ").\n"; + avr_terminate(m_pAVR); + return nullptr; + }; + + + std::string Board::GetStorageFileName(const std::string &strType) + { + std::string strFN {CXXDemangle(typeid(*this).name())};//= m_strBoard; + //strFN.append("_").append(m_wiring.GetMCUName()).append("_").append(strType).append(".bin"); + strFN.append("_").append(strType).append(".bin"); +#ifdef TEST_MODE // Creates special files in test mode that don't clobber your existing stuff. + strFN.append("_test"); +#endif + return strFN; + } }; // namespace Boards diff --git a/parts/Board.h b/parts/Board.h index 42b660d3..d605aa1a 100644 --- a/parts/Board.h +++ b/parts/Board.h @@ -25,30 +25,20 @@ #include "EEPROM.h" // for EEPROM #include "IKeyClient.h" #include "IScriptable.h" // for ArgType, IScriptable::LineStatus, IScript... -#include "KeyController.h" #include "PinNames.h" // for Pin -#include "ScriptHost.h" // for ScriptHost #include "Scriptable.h" // for Scriptable -#include "Util.h" #include "Wiring.h" // for Wiring -#include "avr_extint.h" // for avr_extint_set_strict_lvl_trig #include "sim_avr.h" // for avr_t, avr_flashaddr_t, avr_reset, avr_run -#include "sim_avr_types.h" // for avr_regbit_t #include "sim_irq.h" // for avr_connect_irq, avr_irq_t, avr_raise_irq -#include "sim_regbit.h" // for avr_regbit_get, avr_regbit_se #include #include // for uint32_t, uint8_t, int8_t -#include -#include // for printf, fprintf, NULL, stderr #include // for pthread_join, pthread_t #include // for string, basic_string, stoi -#include -#include // for uart_pty -#include // for usleep #include #include // for vector using namespace PinNames; //NOLINT - because proper using declarations don't support enums. +class uart_pty; namespace Boards { @@ -60,21 +50,9 @@ namespace Boards using MCUPin = signed char; // Creates a new board with the given pinspec, firmware file, frequency, and (optional) bootloader hex - Board(const Wirings::Wiring &wiring,uint32_t uiFreqHz):Scriptable("Board"),m_wiring(wiring),m_uiFreq(uiFreqHz) - { - RegisterActionAndMenu("Quit", "Sends the quit signal to the AVR",ScriptAction::Quit); - RegisterActionAndMenu("Reset","Resets the board by resetting the AVR.", ScriptAction::Reset); - RegisterActionAndMenu("Pause","Pauses the simulated AVR execution.", ScriptAction::Pause); - RegisterActionAndMenu("Resume","Resumes simulated AVR execution.", ScriptAction::Unpause); - RegisterAction("WaitMs","Waits the specified number of milliseconds (in AVR-clock time)", ScriptAction::Wait,{ArgType::Int}); - - RegisterKeyHandler('r', "Resets the AVR/board"); - RegisterKeyHandler('z', "Pauses/resumes AVR execution"); - RegisterKeyHandler('q', "Shuts down the board and exits"); - - }; + Board(const Wirings::Wiring &wiring,uint32_t uiFreqHz); - ~Board() override { if (m_thread) std::cerr << "PROGRAMMING ERROR: " << m_strBoard << " THREAD NOT STOPPED BEFORE DESTRUCTION.\n"; } + ~Board() override; void CreateBoard(const std::string &strFW, uint8_t uiVerbose, bool bGDB, uint32_t uiVCDRate, const std::string &strBoot = "stk500boot_v2_mega2560.hex"); void StartAVR(); @@ -84,7 +62,7 @@ namespace Boards inline avr_t * GetAVR(){return m_pAVR;} template - inline bool TryConnect(PinNames::Pin ePin, HW &hw, unsigned int eDest) + bool TryConnect(PinNames::Pin ePin, HW &hw, unsigned int eDest) { if (m_wiring.IsPin(ePin)) { @@ -98,7 +76,7 @@ namespace Boards }; template - inline bool TryConnect(HW &hw, unsigned int eDest,PinNames::Pin ePin) + bool TryConnect(HW &hw, unsigned int eDest,PinNames::Pin ePin) { if (m_wiring.IsPin(ePin)) { @@ -111,15 +89,7 @@ namespace Boards } }; - inline bool TryConnect(avr_irq_t *src, PinNames::Pin ePin) - { - if (m_wiring.IsPin(ePin)) - { - avr_connect_irq(src, m_wiring.DIRQLU(m_pAVR,ePin)); - return true; - } - return _PinNotConnectedMsg(ePin); - } + bool TryConnect(avr_irq_t *src, PinNames::Pin ePin); // Start the bootloader first boot instead of jumping right into the main FW. inline void SetStartBootloader() {m_pAVR->pc = m_pAVR->reset_pc;} @@ -161,110 +131,14 @@ namespace Boards void OnKeyPress(const Key& key) override; - LineStatus ProcessAction(unsigned int ID, const std::vector &vArgs) override - { - switch (ID) - { - case Quit: - SetQuitFlag(); - return LineStatus::Finished; - case Reset: - SetResetFlag(); - return LineStatus::Finished; - case Wait: - if (m_uiWtCycleCount >0) - { - if (--m_uiWtCycleCount==0) - { - return LineStatus::Finished; - } - else - { - return LineStatus::Waiting; - } - } - else - { - m_uiWtCycleCount = (m_uiFreq/1000)*stoi(vArgs.at(0)); - return LineStatus::Waiting; - } - break; - case Pause: - std::cout << "Pause\n"; - m_bPaused.store(true); - return LineStatus::Finished; - case Unpause: - m_bPaused.store(false); - return LineStatus::Finished; - } - return LineStatus::Unhandled; - } - - virtual void* RunAVR() - { - avr_regbit_t MCUSR = m_pAVR->reset_flags.porf; - MCUSR.mask =0xFF; - MCUSR.bit = 0; - std::cout << "Starting " << m_wiring.GetMCUName() << " execution...\n"; - int state = cpu_Running; - while ((state != cpu_Done) && (state != cpu_Crashed) && !m_bQuit){ - // Re init the special workarounds we need after a reset. - if (m_bIsPrimary) // Only one board should be scripting. - { - ScriptHost::DispatchMenuCB(); - KeyController::GetController().OnAVRCycle(); // Handle/dispatch any pressed keys. - } - if (m_bIsPrimary && ScriptHost::IsInitialized()) - { - ScriptHost::OnAVRCycle(); - } - if (m_bPaused) - { - usleep(100000); - continue; - } - int8_t uiMCUSR = avr_regbit_get(m_pAVR,MCUSR); - if (uiMCUSR != m_uiLastMCUSR) - { - std::cout << "MCUSR: " << std::setw(2) << std::hex << (m_uiLastMCUSR = uiMCUSR) << '\n'; - if (uiMCUSR) // only run on change and not changed to 0 - { - OnAVRReset(); - } - } - OnAVRCycle(); - - if (m_bReset) - { - m_bReset = false; - avr_reset(m_pAVR); - avr_regbit_set(m_pAVR, m_pAVR->reset_flags.extrf); - } - state = avr_run(m_pAVR); - } - std::cout << m_wiring.GetMCUName() << "finished (" << state << ").\n"; - avr_terminate(m_pAVR); - return nullptr; - }; - - + LineStatus ProcessAction(unsigned int ID, const std::vector &vArgs) override; + virtual void* RunAVR(); // suppress continuous polling for low INT lines... major performance drain. - void DisableInterruptLevelPoll(uint8_t uiNumIntLins) - { - for (int i=0; iInit(m_pAVR); - UART->Connect(chrNum); - } + void AddSerialPty(uart_pty *UART, const char chrNum); void AddUARTTrace(const char chrUART); @@ -273,43 +147,13 @@ namespace Boards avr_raise_irq(m_wiring.DIRQLU(m_pAVR,ePin),value); } - inline avr_irq_t* GetDIRQ(PinNames::Pin ePin) - { - if (m_wiring.IsPin(ePin)) - { - return m_wiring.DIRQLU(m_pAVR,ePin); - } - return nullptr; - } + avr_irq_t* GetDIRQ(PinNames::Pin ePin); - std::string GetStorageFileName(const std::string &strType) - { - std::string strFN {CXXDemangle(typeid(*this).name())};//= m_strBoard; - //strFN.append("_").append(m_wiring.GetMCUName()).append("_").append(strType).append(".bin"); - strFN.append("_").append(strType).append(".bin"); -#ifdef TEST_MODE // Creates special files in test mode that don't clobber your existing stuff. - strFN.append("_test"); -#endif - return strFN; - } + std::string GetStorageFileName(const std::string &strType); - inline MCUPin GetPinNumber(PinNames::Pin ePin) - { - if (m_wiring.IsPin(ePin)) - { - return m_wiring.GetPin(ePin); - } - return -1; - } + MCUPin GetPinNumber(PinNames::Pin ePin); - inline avr_irq_t* GetPWMIRQ(PinNames::Pin ePin) - { - if (m_wiring.IsPin(ePin)) - { - return m_wiring.DPWMLU(m_pAVR,ePin); - } - return nullptr; - } + avr_irq_t* GetPWMIRQ(PinNames::Pin ePin); template inline void AddHardware(HW &hw, types ... args) @@ -330,11 +174,7 @@ namespace Boards void _OnAVRDeinit(); - inline bool _PinNotConnectedMsg(PinNames::Pin ePin) - { - std:: cout << "Requested connection w/ Digital pin " << ePin << " on " << m_strBoard << ", but it is not defined!\n";; - return false; - } + bool _PinNotConnectedMsg(PinNames::Pin ePin); avr_flashaddr_t LoadFirmware(const std::string &strFW); diff --git a/parts/I2CPeripheral.cpp b/parts/I2CPeripheral.cpp new file mode 100644 index 00000000..18ce0ef9 --- /dev/null +++ b/parts/I2CPeripheral.cpp @@ -0,0 +1,174 @@ +/* + I2CPeripheral.cpp - Generalization helper for I2C-based peripherals. + This header auto-wires the bus and deals with some of the copypasta. + Currently only supports bit-banged mode as I haven't needed to deal + with "real" i2c hardware yet. + + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + + +#include "I2CPeripheral.h" +#include // for uint8_t, uint32_t, int32_t, uint16_t + +I2CPeripheral::I2CPeripheral(uint8_t uiAddress):m_uiDevAddr(uiAddress) +{ + +} + +bool I2CPeripheral::ProcessByte(const uint8_t &value) +{ + bool bReturn = false; + switch (m_state) + { + case State::AddrIn: + { + msgIn.bytes[2] = value; + if (msgIn.address != m_uiDevAddr) + { + m_SCLState = SCLS::Idle; + m_state = State::Idle; + break; + } + bReturn = true; + if (msgIn.isAddrRead) + { + m_SCLState = SCLS::WaitForWrite; // Wait for next clock + } + else + { + m_state = State::RegIn; + } + } + break; + case State::RegIn: + { + msgIn.bytes[1] = value; + m_state = State::DataIn; + bReturn = true; + // NOTE - this doesn't handle OOB regs. + } + break; + case State::DataIn: + { + msgIn.bytes[0] = value; + bReturn = SetRegVal(msgIn.writeRegAddr++,msgIn.data); + } + break; + default: + break; + } + //printf("I2C msg status: Addr: %02x Read: %u raw: %04x\n", msgIn.address, msgIn.isAddrRead, msgIn.raw); + return bReturn; +} + +void I2CPeripheral::_OnSCL(avr_irq_t *irq, uint32_t value) +{ + //if (value) printf("SCL: %u (%u)\n", value,m_uiBitCt); + bool bClockRise = !(irq->value) && value; + bool bClockFall = (irq->value) && !value; + if (m_SCLState ==SCLS::Idle || (bClockRise==bClockFall)) + { + return; + } + switch (m_SCLState) + { + default: + break; + case SCLS::Reading: + if (bClockRise) + { + if (m_uiBitCt == 8) // Byte done, do we ACK or NACK? + { + if (ProcessByte(m_uiByte)) + { + //printf("ACK\n"); + avr_raise_irq(m_pSDA,0); + } + // else + // printf("NACK\n"); + m_uiByte = m_uiBitCt = 0; + } + else + { + m_uiByte <<= 1; // Shift up. + m_uiByte |= (m_pSDA->value & 1u); + m_uiBitCt++; + } + } + break; + case SCLS::WaitForWrite: + if (bClockFall) + { + m_SCLState = SCLS::Writing; + } + break; + case SCLS::Writing: + { + if (bClockRise) + { + if (m_uiBitCt == 0) + { + m_uiBitCt = 8; + m_uiByte = GetRegVal(msgIn.writeRegAddr); + //printf("Sending %02x\n",m_uiByte); + } + avr_raise_irq(m_pSDA, static_cast(m_uiByte)>>(--m_uiBitCt) &1u); + } + else + { + if (m_uiBitCt == 0) + { + m_SCLState = SCLS::WaitForACK; + } + } + } + break; + case SCLS::WaitForACK: + { + if (bClockRise) + { + //printf("%cACK rec'd\n",m_pSDA->value? ' ':'N'); + } + else + { + m_SCLState = SCLS::Writing; // Back to writing. + } + } + break; + } +} + +void I2CPeripheral::_OnSDA(avr_irq_t */*irq*/, uint32_t value) +{ + if (m_pSCL->value) + { + if (value) + { + m_SCLState = SCLS::Idle; + } + else + { + m_SCLState = SCLS::Reading; + m_state = State::AddrIn; + m_uiBitCt = 0; + m_uiByte = 0; + } + //printf("I2C TX %s\n",value?"Stop" : "Start"); + } +} diff --git a/parts/I2CPeripheral.h b/parts/I2CPeripheral.h index dc5b550b..81f1d4dd 100644 --- a/parts/I2CPeripheral.h +++ b/parts/I2CPeripheral.h @@ -27,13 +27,16 @@ #include "BasePeripheral.h" #include "avr_twi.h" +#include "sim_avr.h" // for avr_t +#include "sim_io.h" // for avr_io_getirq +#include "sim_irq.h" // for avr_irq_t, avr_irq_register_notify #include // for uint8_t, uint32_t, int32_t, uint16_t #include class I2CPeripheral: public BasePeripheral { protected: - explicit I2CPeripheral(uint8_t uiAddress):m_uiDevAddr(uiAddress){}; + explicit I2CPeripheral(uint8_t uiAddress); ~I2CPeripheral() = default; // Sets up the IRQs on "avr" for this class. Optional name override IRQNAMES. @@ -86,148 +89,9 @@ class I2CPeripheral: public BasePeripheral } // Called on a read request of uiReg. You don't need to worry about tracking/incrementing the address on multi-reads. - //virtual uint8_t ProcessRead(uint8_t uiReg){}; - bool ProcessByte(const uint8_t &value) - { - bool bReturn = false; - switch (m_state) - { - case State::AddrIn: - { - msgIn.bytes[2] = value; - if (msgIn.address != m_uiDevAddr) - { - m_SCLState = SCLS::Idle; - m_state = State::Idle; - break; - } - bReturn = true; - if (msgIn.isAddrRead) - { - m_SCLState = SCLS::WaitForWrite; // Wait for next clock - } - else - { - m_state = State::RegIn; - } - } - break; - case State::RegIn: - { - msgIn.bytes[1] = value; - m_state = State::DataIn; - bReturn = true; - // NOTE - this doesn't handle OOB regs. - } - break; - case State::DataIn: - { - msgIn.bytes[0] = value; - bReturn = SetRegVal(msgIn.writeRegAddr++,msgIn.data); - } - break; - default: - break; - } - //printf("I2C msg status: Addr: %02x Read: %u raw: %04x\n", msgIn.address, msgIn.isAddrRead, msgIn.raw); - return bReturn; - } - - void _OnSCL(avr_irq_t *irq, uint32_t value) - { - //if (value) printf("SCL: %u (%u)\n", value,m_uiBitCt); - bool bClockRise = !(irq->value) && value; - bool bClockFall = (irq->value) && !value; - if (m_SCLState ==SCLS::Idle || (bClockRise==bClockFall)) - { - return; - } - switch (m_SCLState) - { - default: - break; - case SCLS::Reading: - if (bClockRise) - { - if (m_uiBitCt == 8) // Byte done, do we ACK or NACK? - { - if (ProcessByte(m_uiByte)) - { - //printf("ACK\n"); - avr_raise_irq(m_pSDA,0); - } - // else - // printf("NACK\n"); - m_uiByte = m_uiBitCt = 0; - } - else - { - m_uiByte <<= 1; // Shift up. - m_uiByte |= (m_pSDA->value & 1u); - m_uiBitCt++; - } - } - break; - case SCLS::WaitForWrite: - if (bClockFall) - { - m_SCLState = SCLS::Writing; - } - break; - case SCLS::Writing: - { - if (bClockRise) - { - if (m_uiBitCt == 0) - { - m_uiBitCt = 8; - m_uiByte = GetRegVal(msgIn.writeRegAddr); - //printf("Sending %02x\n",m_uiByte); - } - avr_raise_irq(m_pSDA, static_cast(m_uiByte)>>(--m_uiBitCt) &1u); - } - else - { - if (m_uiBitCt == 0) - { - m_SCLState = SCLS::WaitForACK; - } - } - } - break; - case SCLS::WaitForACK: - { - if (bClockRise) - { - //printf("%cACK rec'd\n",m_pSDA->value? ' ':'N'); - } - else - { - m_SCLState = SCLS::Writing; // Back to writing. - } - } - break; - } - } - - void _OnSDA(avr_irq_t */*irq*/, uint32_t value) - { - if (m_pSCL->value) - { - if (value) - { - m_SCLState = SCLS::Idle; - } - else - { - m_SCLState = SCLS::Reading; - m_state = State::AddrIn; - m_uiBitCt = 0; - m_uiByte = 0; - } - //printf("I2C TX %s\n",value?"Stop" : "Start"); - } - } + bool ProcessByte(const uint8_t &value); + void _OnSCL(avr_irq_t *irq, uint32_t value); + void _OnSDA(avr_irq_t */*irq*/, uint32_t value); const uint8_t m_uiDevAddr = 0; diff --git a/parts/IScriptable.cpp b/parts/IScriptable.cpp new file mode 100644 index 00000000..55f3f8c6 --- /dev/null +++ b/parts/IScriptable.cpp @@ -0,0 +1,141 @@ +/* + IScriptable.h - Scriptable base interface. Needs to be separate from + Scriptable because ScriptHost must also be scriptable, but would + create a cyclic header if it was. + So ScriptHost will be IScriptable but skips registering itself with itself + and needs to do that manually. + + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "IScriptable.h" + +#include +#include +#include +#include +#include + +IScriptable::LineStatus IScriptable::IssueLineError(const std::string &msg) +{ + std::cerr << m_strName << "ERROR: " << msg << '\n'; + return LineStatus::Error; +} + +IScriptable::LineStatus IScriptable::ProcessAction(unsigned int /*iAction*/, const std::vector &/*args*/) +{ + return IssueLineError(" Has registered actions but does not have an action handler!"); +} + +// Processes the menu callback. By default, will try the script handler for no-arg actions. +// If this is NOT what you want, overload this in your class. +void IScriptable::ProcessMenu(unsigned iAction) +{ + //printf("m_Act: %u\n", (unsigned)m_ActionArgs.count(iAction)); + if (m_ActionArgs.count(iAction)==0 || m_ActionArgs.at(iAction).size()==0) // If no args needed or it wasn't registered, try the script handler. + { + auto LSResult = ProcessAction(iAction,{}); + if (LSResult != LineStatus::Error && LSResult != LineStatus::Unhandled) + { + return; + } + } + std::cerr << "Programmer error: " << m_strName << " has registered menu items but no valid handler!\n"; +} + +void IScriptable::SetName(const std::string &strName) +{ + if (m_bRegistered) + { + std::cerr << "ERROR: Tried to change a Scriptable object's name after it has already registered.\n"; + } + else + { + m_strName = strName; + } +} + +// Prints help text for this Scriptable +void IScriptable::PrintRegisteredActions(bool bMarkdown) +{ + std::cout << (bMarkdown?"### ":"\t") << m_strName << "::\n"; + for (auto &ActID: m_ActionIDs) + { + unsigned int ID = ActID.second; + std::string strArgFmt = ActID.first; + strArgFmt.push_back('('); + if (m_ActionArgs[ID].size()>0) + { + for (auto &Arg : m_ActionArgs[ID]) + { + strArgFmt += GetArgTypeNames().at(Arg) + ", "; + } + strArgFmt[strArgFmt.size()-2] = ')'; + } + else + { + strArgFmt.push_back(')'); + } + if (bMarkdown) + { + std::cout << " - `" << std::setw(30) << std::left << strArgFmt << "` - `" << m_mHelp.at(ID) << "`\n"; + } + else + { + std::cout << "\t\t" << std::setw(30) << std::left << strArgFmt << m_mHelp.at(ID) << '\n'; + } + } +} +// Registers a new no-argument Scriptable action with the given function, description, and an ID that will be +// provided in ProcessAction. This lets you set up an internal enum and switch() on actions +// instead of needing to make a string-comparison if-else conditional. +bool IScriptable::RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID) +{ + if (m_ActionIDs.count(strAct)>0) + { + std::cerr << "ERROR: Attempted to register duplicate action handler " << m_strName << "::" << strAct; + return false; + } + m_ActionIDs[strAct] = ID; + m_mHelp[ID] = strDesc; + m_ActionArgs[ID].clear(); + return true; +} + +// Registers a scriptable action Name::strAct(), help description strDesc, internal ID, and a vector of argument types. +// The types are (currently) for display only but the count is used to sanity-check lines before passing them to you in ProcessAction. +void IScriptable::RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID, const std::vector& vTypes) +{ + if (!RegisterAction(strAct,strDesc, ID)) + { + return; + } + m_ActionArgs[ID] = vTypes; +} + +const std::map& IScriptable::GetArgTypeNames() +{ + static const std::map m { + {ArgType::Bool,"bool"}, + {ArgType::Float,"float"}, + {ArgType::Int,"int"}, + {ArgType::String,"string"}, + {ArgType::uint32,"uint32"} + }; + return m; +} diff --git a/parts/IScriptable.h b/parts/IScriptable.h index d163df8b..41007f69 100644 --- a/parts/IScriptable.h +++ b/parts/IScriptable.h @@ -26,11 +26,9 @@ #pragma once -#include -#include -#include #include #include +#include #include class Scriptable; class ScriptHost; @@ -56,6 +54,7 @@ class IScriptable public: explicit IScriptable(std::string strName):m_strName(std::move(strName)){} virtual ~IScriptable() = default; + enum class LineStatus { Error, @@ -69,117 +68,32 @@ class IScriptable protected: - inline IScriptable::LineStatus IssueLineError(const std::string &msg) - { - std::cerr << m_strName << "ERROR: " << msg << '\n'; - return LineStatus::Error; - } + IScriptable::LineStatus IssueLineError(const std::string &msg); - virtual LineStatus ProcessAction(unsigned int /*iAction*/, const std::vector &/*args*/) - { - return IssueLineError(" Has registered actions but does not have an action handler!"); - } + virtual LineStatus ProcessAction(unsigned int /*iAction*/, const std::vector &/*args*/); // Processes the menu callback. By default, will try the script handler for no-arg actions. // If this is NOT what you want, overload this in your class. - virtual void ProcessMenu(unsigned iAction) - { - //printf("m_Act: %u\n", (unsigned)m_ActionArgs.count(iAction)); - if (m_ActionArgs.count(iAction)==0 || m_ActionArgs.at(iAction).size()==0) // If no args needed or it wasn't registered, try the script handler. - { - auto LSResult = ProcessAction(iAction,{}); - if (LSResult != LineStatus::Error && LSResult != LineStatus::Unhandled) - { - return; - } - } - std::cerr << "Programmer error: " << m_strName << " has registered menu items but no valid handler!\n"; - } - - void SetName(const std::string &strName) - { - if (m_bRegistered) - { - std::cerr << "ERROR: Tried to change a Scriptable object's name after it has already registered.\n"; - } - else - { - m_strName = strName; - } - } + virtual void ProcessMenu(unsigned iAction); + + void SetName(const std::string &strName); // Returns the name. Used by, e.g. TelHost for consistency. inline std::string GetName() {return m_strName;} // Prints help text for this Scriptable - void PrintRegisteredActions(bool bMarkdown = false) - { - std::cout << (bMarkdown?"### ":"\t") << m_strName << "::\n"; - for (auto &ActID: m_ActionIDs) - { - unsigned int ID = ActID.second; - std::string strArgFmt = ActID.first; - strArgFmt.push_back('('); - if (m_ActionArgs[ID].size()>0) - { - for (auto &Arg : m_ActionArgs[ID]) - { - strArgFmt += GetArgTypeNames().at(Arg) + ", "; - } - strArgFmt[strArgFmt.size()-2] = ')'; - } - else - { - strArgFmt.push_back(')'); - } - if (bMarkdown) - { - std::cout << " - `" << std::setw(30) << std::left << strArgFmt << "` - `" << m_mHelp.at(ID) << "`\n"; - } - else - { - std::cout << "\t\t" << std::setw(30) << std::left << strArgFmt << m_mHelp.at(ID) << '\n'; - } - } - } + void PrintRegisteredActions(bool bMarkdown = false); + // Registers a new no-argument Scriptable action with the given function, description, and an ID that will be // provided in ProcessAction. This lets you set up an internal enum and switch() on actions // instead of needing to make a string-comparison if-else conditional. - inline virtual bool RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID) - { - if (m_ActionIDs.count(strAct)>0) - { - std::cerr << "ERROR: Attempted to register duplicate action handler " << m_strName << "::" << strAct; - return false; - } - m_ActionIDs[strAct] = ID; - m_mHelp[ID] = strDesc; - m_ActionArgs[ID].clear(); - return true; - } + virtual bool RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID); // Registers a scriptable action Name::strAct(), help description strDesc, internal ID, and a vector of argument types. // The types are (currently) for display only but the count is used to sanity-check lines before passing them to you in ProcessAction. - inline void RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID, const std::vector& vTypes) - { - if (!RegisterAction(strAct,strDesc, ID)) - { - return; - } - m_ActionArgs[ID] = vTypes; - } - - static const std::map& GetArgTypeNames() - { - static const std::map m { - {ArgType::Bool,"bool"}, - {ArgType::Float,"float"}, - {ArgType::Int,"int"}, - {ArgType::String,"string"}, - {ArgType::uint32,"uint32"} - }; - return m; - } + void RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID, const std::vector& vTypes); + + static const std::map& GetArgTypeNames(); private: std::string m_strName; diff --git a/parts/KeyController.cpp b/parts/KeyController.cpp index 76ebbb7d..4553b851 100644 --- a/parts/KeyController.cpp +++ b/parts/KeyController.cpp @@ -23,6 +23,7 @@ #include "IKeyClient.h" #include "IScriptable.h" #include +#include // for allocator_traits<>::value_type #include #include #include diff --git a/parts/PinNames.h b/parts/PinNames.h index c4ced6a1..156cbc24 100644 --- a/parts/PinNames.h +++ b/parts/PinNames.h @@ -1,3 +1,27 @@ +/* + PinNames.h - Wrangler for convenience pin names (e.g. master list of all pins.) + Not all boards have every pin, the idea is that if using TryConnect() you can potentially + reuse a board and disconnect a pin in its wiring to reduce copypasta code. + + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + + #pragma once #define __PIN_COMBO(x,y) x##y diff --git a/parts/Printer.cpp b/parts/Printer.cpp new file mode 100644 index 00000000..58d61ecb --- /dev/null +++ b/parts/Printer.cpp @@ -0,0 +1,46 @@ +/* + Printer.h - Printer interface for printer assemblies. + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "Printer.h" + +#include "Scriptable.h" +#include + + +Printer::Printer():Scriptable("Printer") +{ + RegisterAction("MouseBtn", "Simulates a mouse button (# = GL button enum, gl state)", ActMouseBtn, {ArgType::Int,ArgType::Int}); +} + +void Printer::SetVisualType(const std::string &visType) { + m_visType = visType; OnVisualTypeSet(visType); +} + +IScriptable::LineStatus Printer::ProcessAction(unsigned int iAct, const std::vector &vArgs) +{ + switch (iAct) + { + case ActMouseBtn: + OnMousePress(std::stoi(vArgs.at(0)),std::stoi(vArgs.at(1)),0,0); + return LineStatus::Finished; + default: + return LineStatus::Unhandled; + } +} diff --git a/parts/Printer.h b/parts/Printer.h index 248789d7..3366ac7a 100644 --- a/parts/Printer.h +++ b/parts/Printer.h @@ -21,10 +21,11 @@ #pragma once #include "GLHelper.h" +#include "IScriptable.h" #include "Scriptable.h" -#include #include #include +#include class Printer: public Scriptable { @@ -36,10 +37,7 @@ class Printer: public Scriptable ADVANCED = 0x2, }; - Printer():Scriptable("Printer") - { - RegisterAction("MouseBtn", "Simulates a mouse button (# = GL button enum, gl state)", ActMouseBtn, {ArgType::Int,ArgType::Int}); - } + Printer(); // GL methods, use these to render your printer visuals and virtual void Draw(){}; // pragma: LCOV_EXCL_START @@ -55,25 +53,16 @@ class Printer: public Scriptable virtual std::pair GetWindowSize() = 0; // pragma: LCOV_EXCL_STOP - std::string GetVisualType() { return m_visType; } - void SetVisualType(const std::string &visType) {m_visType = visType; OnVisualTypeSet(visType);} + inline std::string GetVisualType() { return m_visType; } + + void SetVisualType(const std::string &visType); inline void SetConnectSerial(bool bVal){m_bConnectSerial = bVal;} protected: - bool GetConnectSerial(){return m_bConnectSerial;} + inline bool GetConnectSerial(){return m_bConnectSerial;} - LineStatus ProcessAction(unsigned int iAct, const std::vector &vArgs) override - { - switch (iAct) - { - case ActMouseBtn: - OnMousePress(std::stoi(vArgs.at(0)),std::stoi(vArgs.at(1)),0,0); - return LineStatus::Finished; - default: - return LineStatus::Unhandled; - } - } + LineStatus ProcessAction(unsigned int iAct, const std::vector &vArgs) override; GLHelper m_gl{}; diff --git a/parts/PrinterFactory.cpp b/parts/PrinterFactory.cpp new file mode 100644 index 00000000..00887b88 --- /dev/null +++ b/parts/PrinterFactory.cpp @@ -0,0 +1,96 @@ +/* + PrinterFactory.cpp - Printer factory for printer models. + Add your printer implementation to the map of names->constructors. + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "PrinterFactory.h" +#include "printers/Prusa_MK1_13.h" +#include "printers/Prusa_MK25S_13.h" +#include "printers/Prusa_MK25_13.h" +#include "printers/Prusa_MK2MMU_13.h" +#include "printers/Prusa_MK2_13.h" +#include "printers/Prusa_MK3.h" +#include "printers/Prusa_MK3MMU2.h" +#include "printers/Prusa_MK3S.h" +#include "printers/Prusa_MK3SMMU2.h" +#include "printers/Test_Printer.h" +#include + +/* + There's probably a better/cleaner way to do this, but FWIW this is the + first implementation I put together that worked. It could probably be cleaned up + a bit by having the printer class be a subclass of Board, but I'm not entirely + sure that's the right way to go yet. I think time will tell once we get more models + in place... +*/ + + +std::vector PrinterFactory::GetModels() +{ + std::vector strModels; + for(auto &models: GetModelMap()) + { + strModels.push_back(models.first); + } + return strModels; +} + +void* PrinterFactory::GetPrinterByName(const std::string &strModel,Boards::Board *&pBoard, Printer *&pPrinter) //NOLINT +{ + if (!GetModelMap().count(strModel)) + { + std::cerr << "ERROR: Cannot create printer model. It is not registered. (Also, how did you bypass the argument constraints?!?\n"; + pBoard = nullptr; + pPrinter = nullptr; + return nullptr; + } + Ctor fnCreate = GetModelMap().at(strModel).first; + return fnCreate(pBoard,pPrinter); +} + +void PrinterFactory::DestroyPrinterByName(const std::string &strModel, void* p) +{ + if (!GetModelMap().count(strModel)) + { + std::cerr << "ERROR: Cannot delete printer model, It is not registered. (Also, how did you bypass the argument constraints?!?\n"; + return; + } + GetModelMap().at(strModel).second(p); +} + +using Ctor = void*(*)(Boards::Board *&pBoard, Printer *&pPrinter); +using Dtor = void(*)(void* p); + +// Someday: maybe a way to have printer classes register dynamically instead of needing to add them to the map? +std::map>& PrinterFactory::GetModelMap() +{ + static std::map> m_Models = { + {"Prusa_MK1_mR13", {&PrinterFactory::_CreatePrinter , &PrinterFactory::_DestroyPrinter}}, + {"Prusa_MK2_mR13", {&PrinterFactory::_CreatePrinter , &PrinterFactory::_DestroyPrinter}}, + {"Prusa_MK2MMU_mR13", {&PrinterFactory::_CreatePrinter, &PrinterFactory::_DestroyPrinter}}, + {"Prusa_MK25_mR13", {&PrinterFactory::_CreatePrinter , &PrinterFactory::_DestroyPrinter}}, + {"Prusa_MK25S_mR13", {&PrinterFactory::_CreatePrinter, &PrinterFactory::_DestroyPrinter}}, + {"Prusa_MK3", {&PrinterFactory::_CreatePrinter , &PrinterFactory::_DestroyPrinter}}, + {"Prusa_MK3S", {&PrinterFactory::_CreatePrinter , &PrinterFactory::_DestroyPrinter}}, + {"Prusa_MK3SMMU2", {&PrinterFactory::_CreatePrinter, &PrinterFactory::_DestroyPrinter}}, + {"Prusa_MK3MMU2", {&PrinterFactory::_CreatePrinter, &PrinterFactory::_DestroyPrinter}}, + {"Test_Printer", {&PrinterFactory::_CreatePrinter, &PrinterFactory::_DestroyPrinter}} + }; + return m_Models; +} diff --git a/parts/PrinterFactory.h b/parts/PrinterFactory.h index 44f53e63..04d39d13 100644 --- a/parts/PrinterFactory.h +++ b/parts/PrinterFactory.h @@ -23,17 +23,10 @@ #include "Board.h" #include "Printer.h" -#include "printers/Prusa_MK1_13.h" -#include "printers/Prusa_MK25S_13.h" -#include "printers/Prusa_MK25_13.h" -#include "printers/Prusa_MK2MMU_13.h" -#include "printers/Prusa_MK2_13.h" -#include "printers/Prusa_MK3.h" -#include "printers/Prusa_MK3MMU2.h" -#include "printers/Prusa_MK3S.h" -#include "printers/Prusa_MK3SMMU2.h" -#include "printers/Test_Printer.h" -#include +#include // for map +#include // for string +#include // for pair +#include // for vector /* There's probably a better/cleaner way to do this, but FWIW this is the @@ -61,38 +54,7 @@ class PrinterFactory return p; }; - static std::vector GetModels() - { - std::vector strModels; - for(auto &models: GetModelMap()) - { - strModels.push_back(models.first); - } - return strModels; - } - - static void* GetPrinterByName(const std::string &strModel,Boards::Board *&pBoard, Printer *&pPrinter) //NOLINT - { - if (!GetModelMap().count(strModel)) - { - std::cerr << "ERROR: Cannot create printer model. It is not registered. (Also, how did you bypass the argument constraints?!?\n"; - pBoard = nullptr; - pPrinter = nullptr; - return nullptr; - } - Ctor fnCreate = GetModelMap().at(strModel).first; - return fnCreate(pBoard,pPrinter); - } - - static void DestroyPrinterByName(const std::string &strModel, void* p) - { - if (!GetModelMap().count(strModel)) - { - std::cerr << "ERROR: Cannot delete printer model, It is not registered. (Also, how did you bypass the argument constraints?!?\n"; - return; - } - GetModelMap().at(strModel).second(p); - } + static std::vector GetModels(); template static void* _CreatePrinter(Boards::Board *&pBoard, Printer *&pPrinter)//NOLINT @@ -111,25 +73,12 @@ class PrinterFactory printer->~P(); }; + static void DestroyPrinterByName(const std::string &strModel, void* p); + private: using Ctor = void*(*)(Boards::Board *&pBoard, Printer *&pPrinter); using Dtor = void(*)(void* p); - + static void* GetPrinterByName(const std::string &strModel,Boards::Board *&pBoard, Printer *&pPrinter); //NOLINT + static std::map>& GetModelMap(); // Someday: maybe a way to have printer classes register dynamically instead of needing to add them to the map? - static std::map>& GetModelMap() - { - static std::map> m_Models = { - {"Prusa_MK1_mR13", {&PrinterFactory::_CreatePrinter , &PrinterFactory::_DestroyPrinter}}, - {"Prusa_MK2_mR13", {&PrinterFactory::_CreatePrinter , &PrinterFactory::_DestroyPrinter}}, - {"Prusa_MK2MMU_mR13", {&PrinterFactory::_CreatePrinter, &PrinterFactory::_DestroyPrinter}}, - {"Prusa_MK25_mR13", {&PrinterFactory::_CreatePrinter , &PrinterFactory::_DestroyPrinter}}, - {"Prusa_MK25S_mR13", {&PrinterFactory::_CreatePrinter, &PrinterFactory::_DestroyPrinter}}, - {"Prusa_MK3", {&PrinterFactory::_CreatePrinter , &PrinterFactory::_DestroyPrinter}}, - {"Prusa_MK3S", {&PrinterFactory::_CreatePrinter , &PrinterFactory::_DestroyPrinter}}, - {"Prusa_MK3SMMU2", {&PrinterFactory::_CreatePrinter, &PrinterFactory::_DestroyPrinter}}, - {"Prusa_MK3MMU2", {&PrinterFactory::_CreatePrinter, &PrinterFactory::_DestroyPrinter}}, - {"Test_Printer", {&PrinterFactory::_CreatePrinter, &PrinterFactory::_DestroyPrinter}} - }; - return m_Models; - } }; diff --git a/parts/SPIPeripheral.h b/parts/SPIPeripheral.h index fbe92241..906318f4 100644 --- a/parts/SPIPeripheral.h +++ b/parts/SPIPeripheral.h @@ -27,7 +27,7 @@ #pragma once #include "BasePeripheral.h" -#include +#include "avr_spi.h" class SPIPeripheral: public BasePeripheral { @@ -42,7 +42,7 @@ class SPIPeripheral: public BasePeripheral virtual void OnCSELIn(struct avr_irq_t * irq, uint32_t value) = 0; // Sets the flag that you have and want to send a reply. - void SetSendReplyFlag(){m_bSendReply = true;} + inline void SetSendReplyFlag(){m_bSendReply = true;} // Sets up the IRQs on "avr" for this class. Optional name override IRQNAMES. template @@ -61,7 +61,7 @@ class SPIPeripheral: public BasePeripheral bool m_bCSel = true; // Chipselect, active low. bool m_bSendReply = false; - void _OnCSELIn(struct avr_irq_t * irq, uint32_t value) + inline void _OnCSELIn(struct avr_irq_t * irq, uint32_t value) { m_bCSel = value; OnCSELIn(irq,value); diff --git a/parts/ScriptHost.cpp b/parts/ScriptHost.cpp index a6518981..ae85b9ff 100644 --- a/parts/ScriptHost.cpp +++ b/parts/ScriptHost.cpp @@ -78,6 +78,31 @@ void ScriptHost::LoadScript(const std::string &strFile) std::cout << "ScriptHost: Loaded " << m_script.size() << " lines from " << strFile << '\n'; } +bool ScriptHost::Init() +{ + GetHost()._Init(); + m_bIsInitialized = true; + return true; +} + +bool ScriptHost::Setup(const std::string &strScript,unsigned uiFreq) +{ + m_uiAVRFreq = uiFreq; + if (!strScript.empty()) + { + LoadScript(strScript); + } + return ValidateScript(); +} + +void ScriptHost::_Init() +{ + RegisterAction("SetTimeoutMs","Sets a timeout for actions that wait for an event",ActSetTimeoutMs,{ArgType::Int}); + RegisterAction("SetQuitOnTimeout","If 1, quits when a timeout occurs. Exit code will be non-zero.",ActSetQuitOnTimeout,{ArgType::Bool}); + RegisterAction("Log","Print the std::string to stdout",ActLog,{ArgType::String}); + m_clients[m_strName] = this; +} + // Parse line in the format Context::Action(arg1, arg2,...) ScriptHost::LineParts_t ScriptHost::GetLineParts(const std::string &strLine) { diff --git a/parts/ScriptHost.h b/parts/ScriptHost.h index 5e7ff419..f899eb0a 100644 --- a/parts/ScriptHost.h +++ b/parts/ScriptHost.h @@ -39,22 +39,10 @@ class ScriptHost: public IScriptable { return m_bIsInitialized; } - static bool Init() - { - GetHost()._Init(); - m_bIsInitialized = true; - return true; - } - static bool Setup(const std::string &strScript,unsigned uiFreq) - { - m_uiAVRFreq = uiFreq; - if (!strScript.empty()) - { - LoadScript(strScript); - } - return ValidateScript(); - } + static bool Init(); + + static bool Setup(const std::string &strScript,unsigned uiFreq); static void AddScriptable(const std::string &strName, IScriptable* src); @@ -107,16 +95,9 @@ class ScriptHost: public IScriptable //We can't register ourselves as a scriptable so just fake it with a processing func. LineStatus ProcessAction(unsigned int ID, const std::vector &vArgs) override; - ScriptHost():IScriptable("ScriptHost"){ - } + ScriptHost():IScriptable("ScriptHost"){} - void _Init() - { - RegisterAction("SetTimeoutMs","Sets a timeout for actions that wait for an event",ActSetTimeoutMs,{ArgType::Int}); - RegisterAction("SetQuitOnTimeout","If 1, quits when a timeout occurs. Exit code will be non-zero.",ActSetQuitOnTimeout,{ArgType::Bool}); - RegisterAction("Log","Print the std::string to stdout",ActLog,{ArgType::String}); - m_clients[m_strName] = this; - } + void _Init(); static ScriptHost& GetHost() { @@ -124,7 +105,6 @@ class ScriptHost: public IScriptable return h; } - using linestate_t = struct{ std::string strCtxt {""}; unsigned int iActID {0}; @@ -155,10 +135,6 @@ class ScriptHost: public IScriptable static std::atomic_uint m_uiQueuedMenu; - - - - enum Actions { ActSetTimeoutMs, @@ -166,8 +142,6 @@ class ScriptHost: public IScriptable ActLog }; - - static int m_iTimeoutCycles, m_iTimeoutCount; }; diff --git a/parts/Scriptable.cpp b/parts/Scriptable.cpp new file mode 100644 index 00000000..30d5ced5 --- /dev/null +++ b/parts/Scriptable.cpp @@ -0,0 +1,64 @@ +/* + Scriptable.h - a base class for an object that is scriptable. + + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "Scriptable.h" +#include "ScriptHost.h" +#include +#include + +// Registers a new no-argument Scriptable action with the given function, description, and an ID that will be +// provided in ProcessAction. This lets you set up an internal enum and switch() on actions +// instead of needing to make a string-comparison if-else conditional. +bool Scriptable::RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID) +{ + if (IScriptable::RegisterAction(strAct,strDesc,ID)) + { + ScriptHost::AddScriptable(m_strName,this); + m_bRegistered = true; + return true; + } + else + { + return false; + } +} + +// Convenience wrapper that also adds the action as a context menu entry. +bool Scriptable::RegisterActionAndMenu(const std::string &strAct, const std::string& strDesc, unsigned int ID) +{ + if (RegisterAction(strAct, strDesc, ID)) + { + RegisterMenu(strAct, ID); + return true; + } + return false; +} + +void Scriptable::RegisterMenu(const std::string &strLabel, unsigned uiID) +{ + ScriptHost::AddMenuEntry(strLabel, uiID, this); +} + +//Forwarder: +void Scriptable::RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID, const std::vector& vTypes) +{ + IScriptable::RegisterAction(strAct,strDesc,ID, vTypes); +} diff --git a/parts/Scriptable.h b/parts/Scriptable.h index db674cd1..d7e45b94 100644 --- a/parts/Scriptable.h +++ b/parts/Scriptable.h @@ -23,11 +23,9 @@ #pragma once #include "IScriptable.h" -#include "ScriptHost.h" -#include -#include #include #include +class ScriptHost; class Scriptable: public IScriptable { @@ -39,39 +37,13 @@ class Scriptable: public IScriptable // Registers a new no-argument Scriptable action with the given function, description, and an ID that will be // provided in ProcessAction. This lets you set up an internal enum and switch() on actions // instead of needing to make a string-comparison if-else conditional. - inline bool RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID) final - { - if (IScriptable::RegisterAction(strAct,strDesc,ID)) - { - ScriptHost::AddScriptable(m_strName,this); - m_bRegistered = true; - return true; - } - else - { - return false; - } - } + bool RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID) final; // Convenience wrapper that also adds the action as a context menu entry. - inline bool RegisterActionAndMenu(const std::string &strAct, const std::string& strDesc, unsigned int ID) - { - if (RegisterAction(strAct, strDesc, ID)) - { - RegisterMenu(strAct, ID); - return true; - } - return false; - } + bool RegisterActionAndMenu(const std::string &strAct, const std::string& strDesc, unsigned int ID); - void RegisterMenu(const std::string &strLabel, unsigned uiID) - { - ScriptHost::AddMenuEntry(strLabel, uiID, this); - } + void RegisterMenu(const std::string &strLabel, unsigned uiID); //Forwarder: - inline void RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID, const std::vector& vTypes) - { - IScriptable::RegisterAction(strAct,strDesc,ID, vTypes); - } + void RegisterAction(const std::string &strAct, const std::string& strDesc, unsigned int ID, const std::vector& vTypes); }; diff --git a/parts/SoftPWMable.cpp b/parts/SoftPWMable.cpp new file mode 100644 index 00000000..1dbcb2a6 --- /dev/null +++ b/parts/SoftPWMable.cpp @@ -0,0 +1,52 @@ +/* + SoftPWMable.h - Helper for soft-PWMed items that don't use PWM timers. + + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "SoftPWMable.h" + + +// Binding for soft PWM digital input register notify. +void SoftPWMable::OnDigitalInSPWM(avr_irq_t *irq, uint32_t value) +{ + if (!m_bIsSoftPWM) // For softpwm, + { + OnDigitalChange(irq,value); + return; + } + if (value) // Was off, start at full, we'll update rate later. + { + RegisterTimerUsec(m_fcnSoftTimeout,m_uiSoftTimeoutUs,this); + if (m_cntTOn>m_cntSoftPWM) + { + uint32_t uiTTotal = m_pAVR->cycle - m_cntSoftPWM; + OnWaveformChange(m_cntTOn-m_cntSoftPWM,uiTTotal); + } + m_cntSoftPWM = m_pAVR->cycle; + } + else if (!value) + { + uint64_t uiCycleDelta = m_pAVR->cycle - m_cntSoftPWM; + //TRACE(printf("New soft PWM delta: %d\n",uiCycleDelta/1000)); + uint16_t uiSoftPWM = ((uiCycleDelta/m_uiPrescale)-1); //62.5 Hz means full on is ~256k cycles. + OnPWMChange(irq,uiSoftPWM); + m_cntTOn = m_pAVR->cycle; + RegisterTimerUsec(m_fcnSoftTimeout,m_uiSoftTimeoutUs,this); + } +} diff --git a/parts/SoftPWMable.h b/parts/SoftPWMable.h index 4adb6ffb..ccd290fa 100644 --- a/parts/SoftPWMable.h +++ b/parts/SoftPWMable.h @@ -22,6 +22,12 @@ #pragma once #include "BasePeripheral.h" +#include "sim_avr.h" // for avr_t +#include "sim_avr_types.h" // for avr_cycle_count_t +#include "sim_cycle_timers.h" // for avr_cycle_timer_t +#include "sim_irq.h" // for avr_irq_t +#include // for uint32_t, uint16_t + class SoftPWMable : public BasePeripheral { @@ -47,33 +53,7 @@ class SoftPWMable : public BasePeripheral // pragma: LCOV_EXCL_STOP // Binding for soft PWM digital input register notify. - inline void OnDigitalInSPWM(avr_irq_t *irq, uint32_t value) - { - if (!m_bIsSoftPWM) // For softpwm, - { - OnDigitalChange(irq,value); - return; - } - if (value) // Was off, start at full, we'll update rate later. - { - RegisterTimerUsec(m_fcnSoftTimeout,m_uiSoftTimeoutUs,this); - if (m_cntTOn>m_cntSoftPWM) - { - uint32_t uiTTotal = m_pAVR->cycle - m_cntSoftPWM; - OnWaveformChange(m_cntTOn-m_cntSoftPWM,uiTTotal); - } - m_cntSoftPWM = m_pAVR->cycle; - } - else if (!value) - { - uint64_t uiCycleDelta = m_pAVR->cycle - m_cntSoftPWM; - //TRACE(printf("New soft PWM delta: %d\n",uiCycleDelta/1000)); - uint16_t uiSoftPWM = ((uiCycleDelta/m_uiPrescale)-1); //62.5 Hz means full on is ~256k cycles. - OnPWMChange(irq,uiSoftPWM); - m_cntTOn = m_pAVR->cycle; - RegisterTimerUsec(m_fcnSoftTimeout,m_uiSoftTimeoutUs,this); - } - } + void OnDigitalInSPWM(avr_irq_t *irq, uint32_t value); // Callback for handling full on/off states with softPWM tracking. template diff --git a/parts/TelemetryHost.cpp b/parts/TelemetryHost.cpp index 7bebd1ac..7ffe840a 100644 --- a/parts/TelemetryHost.cpp +++ b/parts/TelemetryHost.cpp @@ -22,10 +22,34 @@ #include "TelemetryHost.h" #include "sim_vcd_file.h" // for avr_vcd_add_signal #include // for find +#include #include #include #include +TelemetryHost::TelemetryHost():Scriptable("TelHost"),IKeyClient() +{ + memset(&m_trace, 0, sizeof(m_trace)); +#ifdef __CYGWIN__ + std::cout << "Cygwin detected - skipping TelHost action registration...\n"; +#else + // Sorry, this segfaults on win32 for some reason... + RegisterAction("WaitFor","Waits for a specified telemetry value to occur",ActWaitFor, {ArgType::String,ArgType::uint32}); + RegisterAction("WaitForGT","Waits for a specified telemetry value to be greater than specified",ActWaitForGT, {ArgType::String,ArgType::uint32}); + RegisterAction("WaitForLT","Waits for a specified telemetry value to be less than specified",ActWaitForLT, {ArgType::String,ArgType::uint32}); + RegisterActionAndMenu("StartTrace", "Starts the telemetry trace. You must have set a category or set of items with the -t option",ActStartTrace); + RegisterActionAndMenu("StopTrace", "Stops a running telemetry trace.",ActStopTrace); +#endif + RegisterKeyHandler('+',"Start VCD trace"); + RegisterKeyHandler('-',"Stop VCD trace"); +} + +void TelemetryHost::Init(avr_t *pAVR, const std::string &strVCDFile, uint32_t uiRateUs) +{ + _Init(pAVR, this); + avr_vcd_init(m_pAVR,strVCDFile.c_str(),&m_trace,uiRateUs); +} + void TelemetryHost::AddTrace(avr_irq_t *pIRQ, std::string strName, TelCats vCats, uint8_t uiBits) { bool bShouldAdd = false; @@ -70,6 +94,21 @@ void TelemetryHost::AddTrace(avr_irq_t *pIRQ, std::string strName, TelCats vCats } } +void TelemetryHost::OnKeyPress(const Key& key) +{ + switch (key) + { + case '+': + TelemetryHost::GetHost().StartTrace(); + std::cout << "Enabled VCD trace." << '\n'; + break; + case '-': + TelemetryHost::GetHost().StopTrace(); + std::cout << "Stopped VCD trace" << '\n'; + break; + } +} + void TelemetryHost::SetCategories(const std::vector &vsCats) { for (auto &sCat : vsCats) diff --git a/parts/TelemetryHost.h b/parts/TelemetryHost.h index 4ea78e5a..597ef601 100644 --- a/parts/TelemetryHost.h +++ b/parts/TelemetryHost.h @@ -29,8 +29,6 @@ #include "sim_irq.h" // for avr_irq_t #include "sim_vcd_file.h" // for avr_vcd_init, avr_vcd_start, avr_vcd_stop #include // for uint32_t, uint8_t -#include // for memset -#include #include // for map #include // for string #include // for vector @@ -86,11 +84,7 @@ class TelemetryHost: public BasePeripheral, public Scriptable, private IKeyClien } // Inits the VCD file at the specified rate (in us) - void Init(avr_t *pAVR, const std::string &strVCDFile, uint32_t uiRateUs = 100) - { - _Init(pAVR, this); - avr_vcd_init(m_pAVR,strVCDFile.c_str(),&m_trace,uiRateUs); - } + void Init(avr_t *pAVR, const std::string &strVCDFile, uint32_t uiRateUs = 100); inline void StartTrace() { @@ -117,42 +111,15 @@ class TelemetryHost: public BasePeripheral, public Scriptable, private IKeyClien void AddTrace(avr_irq_t *pIRQ, std::string strName, TelCats vCats, uint8_t uiBits = 1); - void Shutdown() + inline void Shutdown() { StopTrace(); } - void OnKeyPress(const Key& key) override - { - switch (key) - { - case '+': - TelemetryHost::GetHost().StartTrace(); - std::cout << "Enabled VCD trace." << '\n'; - break; - case '-': - TelemetryHost::GetHost().StopTrace(); - std::cout << "Stopped VCD trace" << '\n'; - break; - } - } + void OnKeyPress(const Key& key) override; + private: - TelemetryHost():Scriptable("TelHost"),IKeyClient() - { - memset(&m_trace, 0, sizeof(m_trace)); -#ifdef __CYGWIN__ - std::cout << "Cygwin detected - skipping TelHost action registration...\n"; -#else - // Sorry, this segfaults on win32 for some reason... - RegisterAction("WaitFor","Waits for a specified telemetry value to occur",ActWaitFor, {ArgType::String,ArgType::uint32}); - RegisterAction("WaitForGT","Waits for a specified telemetry value to be greater than specified",ActWaitForGT, {ArgType::String,ArgType::uint32}); - RegisterAction("WaitForLT","Waits for a specified telemetry value to be less than specified",ActWaitForLT, {ArgType::String,ArgType::uint32}); - RegisterActionAndMenu("StartTrace", "Starts the telemetry trace. You must have set a category or set of items with the -t option",ActStartTrace); - RegisterActionAndMenu("StopTrace", "Stops a running telemetry trace.",ActStopTrace); -#endif - RegisterKeyHandler('+',"Start VCD trace"); - RegisterKeyHandler('-',"Stop VCD trace"); - } + TelemetryHost(); enum Actions { diff --git a/parts/components/EEPROM.cpp b/parts/components/EEPROM.cpp index 0ba8020b..59db1b25 100644 --- a/parts/components/EEPROM.cpp +++ b/parts/components/EEPROM.cpp @@ -31,6 +31,19 @@ using std::ifstream; using std::ofstream; +EEPROM::EEPROM():Scriptable("EEPROM") +{ + RegisterAction("Poke","Pokes a value into the EEPROM. Args are (address,value)", ActPoke, {ArgType::Int, ArgType::Int}); + RegisterActionAndMenu("Save", "Saves EEPROM contents to disk.", ActSave); + RegisterActionAndMenu("Clear", "Clears EEPROM to 0xFF", ActClear); + RegisterActionAndMenu("Load", "Loads the last-used file again", ActLoad); +}; +// Loads EEPROM from a file or initializes the file for the first time. +EEPROM::EEPROM(struct avr_t * avr, const std::string &strFile):EEPROM() +{ + Load(avr, strFile); +}; + void EEPROM::Load(struct avr_t *avr, const std::string &strFile) { m_strFile = strFile; diff --git a/parts/components/EEPROM.h b/parts/components/EEPROM.h index 73d7f093..36056c9f 100644 --- a/parts/components/EEPROM.h +++ b/parts/components/EEPROM.h @@ -32,18 +32,10 @@ class EEPROM: public BasePeripheral, public Scriptable { public: - EEPROM():Scriptable("EEPROM") - { - RegisterAction("Poke","Pokes a value into the EEPROM. Args are (address,value)", ActPoke, {ArgType::Int, ArgType::Int}); - RegisterActionAndMenu("Save", "Saves EEPROM contents to disk.", ActSave); - RegisterActionAndMenu("Clear", "Clears EEPROM to 0xFF", ActClear); - RegisterActionAndMenu("Load", "Loads the last-used file again", ActLoad); - }; + EEPROM(); // Loads EEPROM from a file or initializes the file for the first time. - EEPROM(struct avr_t * avr, const std::string &strFile):EEPROM() - { - Load(avr, strFile); - }; + EEPROM(struct avr_t * avr, const std::string &strFile); + // Loads the given file. void Load(struct avr_t * avr, const std::string &strFile); diff --git a/parts/components/GCodeSniffer.h b/parts/components/GCodeSniffer.h index 6f84c901..db209e32 100644 --- a/parts/components/GCodeSniffer.h +++ b/parts/components/GCodeSniffer.h @@ -43,7 +43,7 @@ class GCodeSniffer : public BasePeripheral // Registers with SimAVR. void Init(avr_t *avr, unsigned char chrUART); - inline std::string GetName(){return std::string("Sniffer");} + inline const std::string GetName(){return std::string("Sniffer");} private: diff --git a/parts/components/GLHelper.cpp b/parts/components/GLHelper.cpp new file mode 100644 index 00000000..973ce3cb --- /dev/null +++ b/parts/components/GLHelper.cpp @@ -0,0 +1,210 @@ +/* + GLHelper.cpp - Lightweight helper for testing the GL drawing of parts. + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "GLHelper.h" + +#include "IScriptable.h" +#include "Scriptable.h" +#include //NOLINT +#include +#include +#include +#ifdef SUPPORTS_LIBPNG +#include // for exception +#include // NOLINT for image +#include // NOLINT for rgb_pixel, basic_rgb_pixel +#include // NOLINT for allocator_traits<>::value_type +#include // NOLINT for solid_pixel_buffer +#endif // SUPPORTS_LIBPNG +#include // IWYU pragma: keep +#include +#include +#include // IWYU pragma: keep +#include +#include + + +GLHelper::GLHelper(const std::string &strName):Scriptable(strName) +{ + RegisterAction("CheckPixel","Checks the pixel color at the given position matches specified (x,y,RGBA).",ActCheckPixel, {ArgType::uint32,ArgType::uint32, ArgType::uint32}); + RegisterAction("Snapshot", "Takes a snap of the current GL rendering", ActTakeSnapshot, {ArgType::String}); + RegisterAction("SnapRect", "Takes a snap a region (file,x,y,w,h)", ActTakeSnapshotArea, {ArgType::String,ArgType::Int,ArgType::Int,ArgType::Int,ArgType::Int}); +} + +// Function for running the GL stuff inside the GL context. +void GLHelper::OnDraw() +{ + if (m_iState == St_Queued2) + { + auto width = glutGet(GLUT_WINDOW_WIDTH); + auto height = glutGet(GLUT_WINDOW_HEIGHT); + m_iState = St_Busy; + if (m_vBuffer.size()!=(4u*width*height)) + { + m_vBuffer.resize(4u*width*height,0); + } + switch (m_iAct.load()) + { + case ActCheckPixel: + { + uint32_t uiTmp[4] {0}; + glReadPixels(m_x,(height-m_y)-1u, 1, 1, GL_RGBA, GL_UNSIGNED_INT, &uiTmp); + m_color = uiTmp[0]<<24U | (uiTmp[1]&0xFFu) << 16U | (uiTmp[2]&0xFFu) <<8U | (uiTmp[3]&0xFFu); + m_iState = St_Done; + } + break; + case ActTakeSnapshot: + { + m_w = width; + m_h = height; + } + /* FALLTHRU */ + case ActTakeSnapshotArea: + { + WritePNG(width, height, m_iAct==ActTakeSnapshotArea); + m_iState = St_Done; + } + break; + default: + { + + } + } + + } + if (m_iState == St_Queued) + { + m_iState = St_Queued2; + } +} + +bool GLHelper::WritePNG(int width, int height, bool bRegion) +{ + auto w = m_w.load(), h = m_h.load(); + if (bRegion) + { + glReadPixels(m_x,(height-m_y)-h,w, h, GL_BGRA, GL_UNSIGNED_BYTE, m_vBuffer.data()); + } + else + { + glReadPixels(0,0,width, height, GL_BGRA, GL_UNSIGNED_BYTE, m_vBuffer.data()); + + } +#ifdef SUPPORTS_LIBPNG + auto iPixCt = w*h; + png::image> img(w, h); + size_t i = 0,y=0; + while(i &vArgs) +{ + switch (iAct) + { + case ActCheckPixel: + { + if (m_iState == St_Idle) + { + // Dispatch check. + m_x = std::stoul(vArgs.at(0)); + m_y = std::stoul(vArgs.at(1)); // Work from the top down so new additions at the bottom of the window don't mess up existing tests. + m_iAct = iAct; + m_iState = St_Queued; + } + else if (m_iState == St_Done) + { + m_iState = St_Idle; + std::stringstream strVal; + strVal << "0x" << std::setw(8) << std::setfill('0') << std::hex << m_color.load(); + std::cout << "Actual pixel color: " << strVal.str() << '\n'; + // Check agains the first n chars, so you can ignore alpha. + bool bMatch = vArgs.at(2) == strVal.str().substr(0,vArgs.at(2).length()); + if (!bMatch) + { + return LineStatus::Timeout; + } + else + { + return LineStatus::Finished; + } + + } + return LineStatus::HoldExec; + } + break; + case ActTakeSnapshot: + case ActTakeSnapshotArea: + { + bool bIsArea = iAct == ActTakeSnapshotArea; + if (m_iState == St_Idle) + { + m_strFile = vArgs.at(0) + ".png"; + if (bIsArea) + { + m_x = std::stoi(vArgs.at(1)); + m_y = std::stoi(vArgs.at(2)); + m_w = std::stoi(vArgs.at(3)); + m_h = std::stoi(vArgs.at(4)); + } + m_iAct = iAct; + m_iState = St_Queued; + } + else if (m_iState == St_Done) + { + m_iState = St_Idle; + std::cout << "Wrote: " << m_strFile << '\n'; + return LineStatus::Finished; + } + return LineStatus::HoldExec; // Pauses primary board execution until finished. + } + break; + default: + return LineStatus::Unhandled; + } +} diff --git a/parts/components/GLHelper.h b/parts/components/GLHelper.h index 9baf8f87..3b161063 100644 --- a/parts/components/GLHelper.h +++ b/parts/components/GLHelper.h @@ -22,188 +22,29 @@ #include "IScriptable.h" #include "Scriptable.h" -#include "Util.h" -#ifdef SUPPORTS_LIBPNG -#include "png.hpp" -#endif // SUPPORTS_LIBPNG -#include //NOLINT -#include #include -#include -#include -#include +#include #include #include class GLHelper: public Scriptable { public: - explicit GLHelper(const std::string &strName = "GLHelper"):Scriptable(strName) - { - RegisterAction("CheckPixel","Checks the pixel color at the given position matches specified (x,y,RGBA).",ActCheckPixel, {ArgType::uint32,ArgType::uint32, ArgType::uint32}); - RegisterAction("Snapshot", "Takes a snap of the current GL rendering", ActTakeSnapshot, {ArgType::String}); - RegisterAction("SnapRect", "Takes a snap a region (file,x,y,w,h)", ActTakeSnapshotArea, {ArgType::String,ArgType::Int,ArgType::Int,ArgType::Int,ArgType::Int}); - } + explicit GLHelper(const std::string &strName = "GLHelper"); inline bool IsTakingSnapshot() { return m_iState >= St_Queued; } // Function for running the GL stuff inside the GL context. - void OnDraw() - { - auto width = glutGet(GLUT_WINDOW_WIDTH); - auto height = glutGet(GLUT_WINDOW_HEIGHT); - if (m_iState == St_Queued) - { - m_iState = St_Busy; - if (m_vBuffer.size()!=(4u*width*height)) - { - m_vBuffer.resize(4u*width*height,0); - } - switch (m_iAct.load()) - { - case ActCheckPixel: - { - uint32_t uiTmp[4] {0}; - glReadPixels(m_x,(height-m_y)-1u, 1, 1, GL_RGBA, GL_UNSIGNED_INT, &uiTmp); - m_color = uiTmp[0]<<24U | (uiTmp[1]&0xFFu) << 16U | (uiTmp[2]&0xFFu) <<8U | (uiTmp[3]&0xFFu); - m_iState = St_Done; - } - break; - case ActTakeSnapshot: - { - m_w = width; - m_h = height; - } - /* FALLTHRU */ - case ActTakeSnapshotArea: - { - WritePNG(width, height, m_iAct==ActTakeSnapshotArea); - m_iState = St_Done; - } - break; - default: - { - - } - } + void OnDraw(); - } - } protected: - bool WritePNG(int width, int height, bool bRegion) - { - auto w = m_w.load(), h = m_h.load(); - if (bRegion) - { - glReadPixels(m_x,(height-m_y)-h,w, h, GL_BGRA, GL_UNSIGNED_BYTE, m_vBuffer.data()); - } - else - { - glReadPixels(0,0,width, height, GL_BGRA, GL_UNSIGNED_BYTE, m_vBuffer.data()); + bool WritePNG(int width, int height, bool bRegion); - } -#ifdef SUPPORTS_LIBPNG - auto iPixCt = w*h; - png::image> img(w, h); - size_t i = 0,y=0; - while(i &vArgs) override - { - switch (iAct) - { - case ActCheckPixel: - { - if (m_iState == St_Idle) - { - // Dispatch check. - m_x = std::stoul(vArgs.at(0)); - m_y = std::stoul(vArgs.at(1)); // Work from the top down so new additions at the bottom of the window don't mess up existing tests. - m_iAct = iAct; - m_iState = St_Queued; - } - else if (m_iState == St_Done) - { - m_iState = St_Idle; - std::stringstream strVal; - strVal << "0x" << std::setw(8) << std::setfill('0') << std::hex << m_color.load(); - std::cout << "Actual pixel color: " << strVal.str() << '\n'; - // Check agains the first n chars, so you can ignore alpha. - bool bMatch = vArgs.at(2) == strVal.str().substr(0,vArgs.at(2).length()); - if (!bMatch) - { - return LineStatus::Timeout; - } - else - { - return LineStatus::Finished; - } - } - return LineStatus::HoldExec; - } - break; - case ActTakeSnapshot: - case ActTakeSnapshotArea: - { - bool bIsArea = iAct == ActTakeSnapshotArea; - if (m_iState == St_Idle) - { - m_strFile = vArgs.at(0) + ".png"; - if (bIsArea) - { - m_x = std::stoi(vArgs.at(1)); - m_y = std::stoi(vArgs.at(2)); - m_w = std::stoi(vArgs.at(3)); - m_h = std::stoi(vArgs.at(4)); - } - m_iAct = iAct; - m_iState = St_Queued; - } - else if (m_iState == St_Done) - { - m_iState = St_Idle; - std::cout << "Wrote: " << m_strFile << '\n'; - return LineStatus::Finished; - } - return LineStatus::HoldExec; // Pauses primary board execution until finished. - } - break; - default: - return LineStatus::Unhandled; - } - } + LineStatus ProcessAction(unsigned int iAct, const std::vector &vArgs) override; enum Actions { @@ -216,6 +57,7 @@ class GLHelper: public Scriptable St_Idle, St_Done, // DO NOT REORDER St_Queued, // we check against >=QUEUED to determine if a snapshot is in progress. + St_Queued2, // Used to delay 2 frames before taking a snap. St_Busy }; std::string m_strFile; diff --git a/parts/components/HC595.h b/parts/components/HC595.h index d4ff0790..f25d0402 100644 --- a/parts/components/HC595.h +++ b/parts/components/HC595.h @@ -86,7 +86,7 @@ class HC595: public BasePeripheral // Registers with SimAVR void Init(avr_t *avr); - std::string GetName(){return "HC595";} + inline const std::string GetName(){return "HC595";} private: // IRQ handlers. diff --git a/parts/components/PAT9125.cpp b/parts/components/PAT9125.cpp new file mode 100644 index 00000000..47f088b8 --- /dev/null +++ b/parts/components/PAT9125.cpp @@ -0,0 +1,275 @@ +/* + PAT9125.h - Simulator for the MK3 optical filament sensor. + + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ +#include "PAT9125.h" +#include "BasePeripheral.h" // for MAKE_C_TIMER_CALLBACK +#include "I2CPeripheral.h" // for I2CPeripheral +#include "IKeyClient.h" +#include "IScriptable.h" // for IScriptable::LineStatus +#include "Scriptable.h" // for Scriptable +#include "gsl-lite.hpp" +#include "sim_avr.h" // for avr_t +#include "sim_irq.h" // for avr_irq_t +#include // for uint8_t, uint32_t, int32_t, uint16_t +#include +#include +#include // for string +#include // for vector + + +PAT9125::PAT9125():I2CPeripheral(0x75),Scriptable("PAT9125"),IKeyClient() +{ + // Check register packing/sizes: + Expects(sizeof(m_regs) == sizeof(m_regs.raw)); + + RegisterActionAndMenu("Toggle","Toggles the IR sensor state",ActToggle); + RegisterAction("Set","Sets the sensor state to a specific enum entry. (int value)",ActSet,{ArgType::Int}); + RegisterActionAndMenu("Toggle Jam","Toggles a jam (motion stall)",ActToggleJam); + RegisterActionAndMenu("Resume Auto","Resumes auto (MMU-pulley-based) operation",ActResumeAuto); + + RegisterKeyHandler('f', "Toggle PAT9125 filament presence"); + RegisterKeyHandler('j', "Toggle a simulated jam on the PAT9125"); + RegisterKeyHandler('A',""); + +}; + +void PAT9125::Init(avr_t *pAVR, avr_irq_t *pSCL, avr_irq_t *pSDA) +{ + _Init(pAVR, pSDA, pSCL, this); + std::cout << "\n\n--------- Your attention please! ----------\n"; + std::cout << "NOTE: PAT9125 is minimally functional. If you encounter issues or need advanced functionality \n feel free to contribute or open an issue.\n"; + std::cout << "--------- Your attention please! ----------\n\n\n"; + RegisterNotify(E_IN, MAKE_C_CALLBACK(PAT9125,OnEMotion),this); + RegisterNotify(P_IN, MAKE_C_CALLBACK(PAT9125,OnPMotion),this); +} + + +void PAT9125::ToggleJam() +{ + if (m_state == FS_JAM) + { + m_state = FS_FILAMENT_PRESENT; + } + else + { + m_state = FS_JAM; + } + std::cout << "PAT9125 Jam: " << (m_state == FS_JAM) << '\n'; + +} + +void PAT9125::Toggle() +{ + switch (m_state) + { + case FS_AUTO: + std::cout << "Leaving PAT9125 Auto mode\n"; + m_state = m_bFilament ? FS_FILAMENT_PRESENT : FS_NO_FILAMENT; + /* FALLTHRU */ // Deliberate fallthrough - will toggle from current. + case FS_NO_FILAMENT: + m_bLoading = true; // Load from no filament only. + /* FALLTHRU */ + case FS_JAM: + m_state = FS_FILAMENT_PRESENT; + UpdateSensorState(); + break; + case FS_FILAMENT_PRESENT: + m_state = FS_NO_FILAMENT; + UpdateSensorState(); + break; + default: // No action + break; + } +} + +void PAT9125::OnKeyPress(const Key& key) +{ + switch(key) + { + case 'f': + Toggle(); + break; + case 'j': + ToggleJam(); + break; + case 'A': + Set(PAT9125::FS_AUTO); + break; + } +} + +void PAT9125::UpdateSensorState() +{ + if (m_state != FS_AUTO) + { + m_bFilament = m_state == FS_FILAMENT_PRESENT || m_state == FS_JAM; + } + std::cout << "Filament Present: " << m_bFilament << '\n'; + RaiseIRQ(LED_OUT,!m_bFilament); // LED is inverted. + if (m_bFilament) + { + m_regs.Shutter = 5; // Restore shutter/brightness. + m_regs.FrameAvg = 100; + m_uiNudgeCt = 0; + } + else + { + m_regs.Shutter = 20; // drop shutter as if underexposed. + m_regs.FrameAvg = 40; // and brightness. + } +} + +void PAT9125::OnPMotion(avr_irq_t *, uint32_t value) +{ + m_bLoading=false; // clear loading flag once E move started. + float fVal; + std::memcpy(&fVal,&value, sizeof(value)); + bool bLoaded = fVal>370.f; + if (m_state == FS_AUTO) // Set filament state if auto. + { + if (m_bFilament != bLoaded) + { + m_bFilament = bLoaded; // default length is 380, trip a few mm earlier because that's where the sensor is vs gears. + UpdateSensorState(); + } + } + if (bLoaded) // Pass through if fed enough to reach. + { + SetYMotion(m_fEPos,fVal-370.f); + } + + +} +void PAT9125::OnEMotion(avr_irq_t *, uint32_t value) +{ + m_bLoading=false; // clear loading flag once E move started. + if (m_bFilament) + { + float fV; + std::memcpy(&fV, &value, sizeof(value)); + SetYMotion(fV, m_fPPos); + } + else // Clear motion and regs. + { + m_regs.MStatus = 0; + m_regs.DeltaXYHi &= 0xF0; + m_regs.DYLow = 0; + } +} + +void PAT9125::SetYMotion(const float &fEVal, const float &fPVal) +{ + //printf("YMotion update: %f %f\n",fEVal, fPVal); + float fDelta = (fEVal+fPVal)-m_fYPos; + int16_t iCounts = fDelta*(5.f*static_cast(m_regs.Res_Y)/25.4f); + iCounts = -iCounts; + if (fDelta>0 && iCounts==0) // Enforce minimum motion of at least 1 count. + { + iCounts = -1; + } + else if (fDelta<0 && iCounts==0) + { + iCounts = 1; + } + m_fEPos = fEVal; + m_fPPos = fPVal; + m_fCurY = fEVal+fPVal; + m_regs.DeltaXYHi = (iCounts >> 8) & 0b1111; //NOLINT + m_regs.DYLow = iCounts & 0xFF; //NOLINT + if (m_state != FS_JAM) + { + m_regs.MStatus = 0x80; + } + +} + +uint8_t PAT9125::GetRegVal(uint8_t uiAddr) +{ + switch (uiAddr) + { + case 0x02: + { + uint8_t val = m_regs.MStatus; + if (!m_bLoading) + { + m_regs.MStatus = 0; // clear motion flag. + } + else + { + SetYMotion(m_fCurY += 1.f,m_fPPos); + m_uiNudgeCt++; + if (m_uiNudgeCt>4) + { + m_uiNudgeCt = 0; + m_bLoading = false; + } + } + return val; + } + case 0x04: + { + //printf("Read DY: %d (%f) \n",m_regs.raw[uiAddr], (m_fYPos-m_fCurY)); + m_fYPos = m_fCurY; + } + /* FALLTHRU */ + default: + //printf("Read: %02x, %02x\n",uiAddr, m_regs.raw[uiAddr]); + return gsl::at(m_regs.raw,uiAddr); + } +}; + +bool PAT9125::SetRegVal(uint8_t uiAddr, uint32_t uiData) +{ + if (!(m_uiRW & (1u<(uiData); + //printf("Wrote: %02x = %02x (%02x)\n",uiAddr,uiData, m_regs.raw[uiAddr]); + return true; +}; + +IScriptable::LineStatus PAT9125::ProcessAction(unsigned int iAct, const std::vector &vArgs) +{ + switch (iAct) + { + case ActToggle: + Toggle(); + return LineStatus::Finished; + case ActSet: + { + int iVal = stoi(vArgs.at(0)); + if (iVal<0 || iVal >= FSState::FS_MAX) + { + return IssueLineError(std::string("Set value ") + std::to_string(iVal) + " is out of the range [0,3]" ); + } + Set(static_cast(iVal)); + return LineStatus::Finished; + } + case ActToggleJam: + ToggleJam(); + return LineStatus::Finished; + case ActResumeAuto: + Set(FS_AUTO); + return LineStatus::Finished; + } + return LineStatus::Unhandled; +} diff --git a/parts/components/PAT9125.h b/parts/components/PAT9125.h index 2d87ce97..a70292a1 100644 --- a/parts/components/PAT9125.h +++ b/parts/components/PAT9125.h @@ -21,20 +21,13 @@ #pragma once -#include "BasePeripheral.h" // for MAKE_C_TIMER_CALLBACK #include "I2CPeripheral.h" // for I2CPeripheral #include "IKeyClient.h" #include "IScriptable.h" // for IScriptable::LineStatus #include "Scriptable.h" // for Scriptable -#include "gsl-lite.hpp" #include "sim_avr.h" // for avr_t -#include "sim_avr_types.h" // for avr_cycle_count_t -#include "sim_cycle_timers.h" // for avr_cycle_timer_t #include "sim_irq.h" // for avr_irq_t #include // for uint8_t, uint32_t, int32_t, uint16_t -#include -#include -#include #include // for string #include // for vector @@ -59,31 +52,9 @@ class PAT9125: public I2CPeripheral, public Scriptable, private IKeyClient FS_MAX }; - PAT9125():I2CPeripheral(0x75),Scriptable("PAT9125"),IKeyClient() - { - // Check register packing/sizes: - Expects(sizeof(m_regs) == sizeof(m_regs.raw)); - - RegisterActionAndMenu("Toggle","Toggles the IR sensor state",ActToggle); - RegisterAction("Set","Sets the sensor state to a specific enum entry. (int value)",ActSet,{ArgType::Int}); - RegisterActionAndMenu("Toggle Jam","Toggles a jam (motion stall)",ActToggleJam); - RegisterActionAndMenu("Resume Auto","Resumes auto (MMU-pulley-based) operation",ActResumeAuto); - - RegisterKeyHandler('f', "Toggle PAT9125 filament presence"); - RegisterKeyHandler('j', "Toggle a simulated jam on the PAT9125"); - RegisterKeyHandler('A',""); - - }; + PAT9125(); - void Init(avr_t *pAVR, avr_irq_t *pSCL, avr_irq_t *pSDA) - { - _Init(pAVR, pSDA, pSCL, this); - std::cout << "\n\n--------- Your attention please! ----------\n"; - std::cout << "NOTE: PAT9125 is minimally functional. If you encounter issues or need advanced functionality \n feel free to contribute or open an issue.\n"; - std::cout << "--------- Your attention please! ----------\n\n\n"; - RegisterNotify(E_IN, MAKE_C_CALLBACK(PAT9125,OnEMotion),this); - RegisterNotify(P_IN, MAKE_C_CALLBACK(PAT9125,OnPMotion),this); - } + void Init(avr_t *pAVR, avr_irq_t *pSCL, avr_irq_t *pSDA); inline void Set(FSState eVal) { @@ -91,221 +62,28 @@ class PAT9125: public I2CPeripheral, public Scriptable, private IKeyClient UpdateSensorState(); } - inline void ToggleJam() - { - if (m_state == FS_JAM) - { - m_state = FS_FILAMENT_PRESENT; - } - else - { - m_state = FS_JAM; - } - std::cout << "PAT9125 Jam: " << (m_state == FS_JAM) << '\n'; + void ToggleJam(); - } - - void Toggle() - { - switch (m_state) - { - case FS_AUTO: - std::cout << "Leaving PAT9125 Auto mode\n"; - m_state = m_bFilament ? FS_FILAMENT_PRESENT : FS_NO_FILAMENT; - /* FALLTHRU */ // Deliberate fallthrough - will toggle from current. - case FS_NO_FILAMENT: - m_bLoading = true; // Load from no filament only. - /* FALLTHRU */ - case FS_JAM: - m_state = FS_FILAMENT_PRESENT; - UpdateSensorState(); - break; - case FS_FILAMENT_PRESENT: - m_state = FS_NO_FILAMENT; - UpdateSensorState(); - break; - default: // No action - break; - } - } + void Toggle(); protected: - void OnKeyPress(const Key& key) override - { - switch(key) - { - case 'f': - Toggle(); - break; - case 'j': - ToggleJam(); - break; - case 'A': - Set(PAT9125::FS_AUTO); - break; - } - } - - void UpdateSensorState() - { - if (m_state != FS_AUTO) - { - m_bFilament = m_state == FS_FILAMENT_PRESENT || m_state == FS_JAM; - } - std::cout << "Filament Present: " << m_bFilament << '\n'; - RaiseIRQ(LED_OUT,!m_bFilament); // LED is inverted. - if (m_bFilament) - { - m_regs.Shutter = 5; // Restore shutter/brightness. - m_regs.FrameAvg = 100; - m_uiNudgeCt = 0; - } - else - { - m_regs.Shutter = 20; // drop shutter as if underexposed. - m_regs.FrameAvg = 40; // and brightness. - } - } + void OnKeyPress(const Key& key) override; - void OnPMotion(avr_irq_t *, uint32_t value) - { - m_bLoading=false; // clear loading flag once E move started. - float fVal; - std::memcpy(&fVal,&value, sizeof(value)); - bool bLoaded = fVal>370.f; - if (m_state == FS_AUTO) // Set filament state if auto. - { - if (m_bFilament != bLoaded) - { - m_bFilament = bLoaded; // default length is 380, trip a few mm earlier because that's where the sensor is vs gears. - UpdateSensorState(); - } - } - if (bLoaded) // Pass through if fed enough to reach. - { - SetYMotion(m_fEPos,fVal-370.f); - } + void UpdateSensorState(); + void OnPMotion(avr_irq_t *, uint32_t value); - } - void OnEMotion(avr_irq_t *, uint32_t value) - { - m_bLoading=false; // clear loading flag once E move started. - if (m_bFilament) - { - float fV; - std::memcpy(&fV, &value, sizeof(value)); - SetYMotion(fV, m_fPPos); - } - else // Clear motion and regs. - { - m_regs.MStatus = 0; - m_regs.DeltaXYHi &= 0xF0; - m_regs.DYLow = 0; - } - } + void OnEMotion(avr_irq_t *, uint32_t value); - void SetYMotion(const float &fEVal, const float &fPVal) - { - //printf("YMotion update: %f %f\n",fEVal, fPVal); - float fDelta = (fEVal+fPVal)-m_fYPos; - int16_t iCounts = fDelta*(5.f*static_cast(m_regs.Res_Y)/25.4f); - iCounts = -iCounts; - if (fDelta>0 && iCounts==0) // Enforce minimum motion of at least 1 count. - { - iCounts = -1; - } - else if (fDelta<0 && iCounts==0) - { - iCounts = 1; - } - m_fEPos = fEVal; - m_fPPos = fPVal; - m_fCurY = fEVal+fPVal; - m_regs.DeltaXYHi = (iCounts >> 8) & 0b1111; //NOLINT - m_regs.DYLow = iCounts & 0xFF; //NOLINT - if (m_state != FS_JAM) - { - m_regs.MStatus = 0x80; - } + void SetYMotion(const float &fEVal, const float &fPVal); - } + uint8_t GetRegVal(uint8_t uiAddr) override; - uint8_t GetRegVal(uint8_t uiAddr) override - { - switch (uiAddr) - { - case 0x02: - { - uint8_t val = m_regs.MStatus; - if (!m_bLoading) - { - m_regs.MStatus = 0; // clear motion flag. - } - else - { - SetYMotion(m_fCurY += 1.f,m_fPPos); - m_uiNudgeCt++; - if (m_uiNudgeCt>4) - { - m_uiNudgeCt = 0; - m_bLoading = false; - } - } - return val; - } - case 0x04: - { - //printf("Read DY: %d (%f) \n",m_regs.raw[uiAddr], (m_fYPos-m_fCurY)); - m_fYPos = m_fCurY; - } - /* FALLTHRU */ - default: - //printf("Read: %02x, %02x\n",uiAddr, m_regs.raw[uiAddr]); - return gsl::at(m_regs.raw,uiAddr); - } - }; + bool SetRegVal(uint8_t uiAddr, uint32_t uiData) override; - bool SetRegVal(uint8_t uiAddr, uint32_t uiData) override - { - if (!(m_uiRW & (1u<(uiData); - //printf("Wrote: %02x = %02x (%02x)\n",uiAddr,uiData, m_regs.raw[uiAddr]); - return true; - }; - - LineStatus ProcessAction(unsigned int iAct, const std::vector &vArgs) override - { - switch (iAct) - { - case ActToggle: - Toggle(); - return LineStatus::Finished; - case ActSet: - { - int iVal = stoi(vArgs.at(0)); - if (iVal<0 || iVal >= FSState::FS_MAX) - { - return IssueLineError(std::string("Set value ") + std::to_string(iVal) + " is out of the range [0,3]" ); - } - Set(static_cast(iVal)); - return LineStatus::Finished; - } - case ActToggleJam: - ToggleJam(); - return LineStatus::Finished; - case ActResumeAuto: - Set(FS_AUTO); - return LineStatus::Finished; - } - return LineStatus::Unhandled; - } + LineStatus ProcessAction(unsigned int iAct, const std::vector &vArgs) override; private: diff --git a/parts/printers/Prusa_MK3.cpp b/parts/printers/Prusa_MK3.cpp new file mode 100644 index 00000000..f6086925 --- /dev/null +++ b/parts/printers/Prusa_MK3.cpp @@ -0,0 +1,37 @@ +/* + Prusa_MK3.h - Printer definition for the Prusa MK3 (Laser sensor) + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "Prusa_MK3.h" // for Prusa_MK3 +#include "LED.h" // for LED +#include "PinNames.h" // for Pin::IR_SENSOR_PIN, Pin::SWI2C_SCL, Pin::SWI2C... +#include "TMC2130.h" // for TMC2130 +#include "sim_irq.h" // for avr_raise_irq +#include // for operator<<, cout, ostream + +void Prusa_MK3::SetupIR() +{ + avr_raise_irq(GetDIRQ(IR_SENSOR_PIN),1); + std::cout << "MK3 - adding laser sensor\n"; + AddHardware(LaserSensor, GetDIRQ(SWI2C_SCL), GetDIRQ(SWI2C_SDA)); + lIR.ConnectFrom(LaserSensor.GetIRQ(PAT9125::LED_OUT),LED::LED_IN); + + LaserSensor.ConnectFrom(E.GetIRQ(TMC2130::POSITION_OUT), PAT9125::E_IN); + LaserSensor.Set(PAT9125::FS_FILAMENT_PRESENT); +}; // Overridde to setup the PAT. diff --git a/parts/printers/Prusa_MK3.h b/parts/printers/Prusa_MK3.h index 86e3761e..73256d59 100644 --- a/parts/printers/Prusa_MK3.h +++ b/parts/printers/Prusa_MK3.h @@ -22,24 +22,11 @@ #include "PAT9125.h" #include "Prusa_MK3S.h" // for Prusa_MK3S -#include "sim_irq.h" -#include - -class MK3SGL; class Prusa_MK3: public Prusa_MK3S { protected: - void SetupIR() override - { - avr_raise_irq(GetDIRQ(IR_SENSOR_PIN),1); - std::cout << "MK3 - adding laser sensor\n"; - AddHardware(LaserSensor, GetDIRQ(SWI2C_SCL), GetDIRQ(SWI2C_SDA)); - lIR.ConnectFrom(LaserSensor.GetIRQ(PAT9125::LED_OUT),LED::LED_IN); - - LaserSensor.ConnectFrom(E.GetIRQ(TMC2130::POSITION_OUT), PAT9125::E_IN); - LaserSensor.Set(PAT9125::FS_FILAMENT_PRESENT); - }; // Overridde to setup the PAT. + void SetupIR() override; PAT9125 LaserSensor; }; diff --git a/parts/printers/Prusa_MK3MMU2.cpp b/parts/printers/Prusa_MK3MMU2.cpp new file mode 100644 index 00000000..17406c80 --- /dev/null +++ b/parts/printers/Prusa_MK3MMU2.cpp @@ -0,0 +1,39 @@ +/* + Prusa_MK3MMU2.h - Printer definition for the Prusa MK3 w/MMU2 + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "Prusa_MK3MMU2.h" // for Prusa_MK3SMMU2 +#include "LED.h" // for LED +#include "MMU2.h" // for MMU2 +#include "PinNames.h" // for Pin::IR_SENSOR_PIN, Pin::SWI2C_SCL, Pin::SWI2C... +#include "TMC2130.h" // for TMC2130 +#include "sim_irq.h" // for avr_raise_irq +#include // for operator<<, cout, ostream + +void Prusa_MK3MMU2::SetupIR() +{ + avr_raise_irq(GetDIRQ(IR_SENSOR_PIN),1); + std::cout << "MK3 - adding laser sensor\n"; + AddHardware(LaserSensor, GetDIRQ(SWI2C_SCL), GetDIRQ(SWI2C_SDA)); + lIR.ConnectFrom(LaserSensor.GetIRQ(PAT9125::LED_OUT),LED::LED_IN); + + LaserSensor.ConnectFrom(E.GetIRQ(TMC2130::POSITION_OUT), PAT9125::E_IN); + LaserSensor.ConnectFrom(m_MMU.GetIRQ(MMU2::FEED_DISTANCE), PAT9125::P_IN); + LaserSensor.Set(PAT9125::FS_AUTO); // No filament - but this just updates the LED. +}; // Overridde to setup the PAT. diff --git a/parts/printers/Prusa_MK3MMU2.h b/parts/printers/Prusa_MK3MMU2.h index 2f3c5962..d45d3360 100644 --- a/parts/printers/Prusa_MK3MMU2.h +++ b/parts/printers/Prusa_MK3MMU2.h @@ -21,27 +21,12 @@ #pragma once #include "PAT9125.h" -#include "Prusa_MK3.h" // for Prusa_MK3 #include "Prusa_MK3SMMU2.h" // for Prusa_MK3SMMU2 -#include - -class SerialPipe; - class Prusa_MK3MMU2 : public Prusa_MK3SMMU2 { protected: - void SetupIR() override - { - avr_raise_irq(GetDIRQ(IR_SENSOR_PIN),1); - std::cout << "MK3 - adding laser sensor\n"; - AddHardware(LaserSensor, GetDIRQ(SWI2C_SCL), GetDIRQ(SWI2C_SDA)); - lIR.ConnectFrom(LaserSensor.GetIRQ(PAT9125::LED_OUT),LED::LED_IN); - - LaserSensor.ConnectFrom(E.GetIRQ(TMC2130::POSITION_OUT), PAT9125::E_IN); - LaserSensor.ConnectFrom(m_MMU.GetIRQ(MMU2::FEED_DISTANCE), PAT9125::P_IN); - LaserSensor.Set(PAT9125::FS_AUTO); // No filament - but this just updates the LED. - }; // Overridde to setup the PAT. + void SetupIR() override; PAT9125 LaserSensor; }; diff --git a/parts/printers/Prusa_MK3S.h b/parts/printers/Prusa_MK3S.h index b96e9251..adb34b96 100644 --- a/parts/printers/Prusa_MK3S.h +++ b/parts/printers/Prusa_MK3S.h @@ -56,7 +56,7 @@ class Prusa_MK3S : public Boards::EinsyRambo, public Printer void OnAVRCycle() override; - virtual bool GetHasMMU() {return false;} + inline virtual bool GetHasMMU() {return false;} std::unique_ptr m_pVis {nullptr}; diff --git a/parts/printers/Prusa_MK3SMMU2.h b/parts/printers/Prusa_MK3SMMU2.h index c899f301..993d8c4e 100644 --- a/parts/printers/Prusa_MK3SMMU2.h +++ b/parts/printers/Prusa_MK3SMMU2.h @@ -40,7 +40,7 @@ class Prusa_MK3SMMU2 : public Prusa_MK3S void Draw() override; void OnVisualTypeSet(const std::string &type) override; - bool GetHasMMU() override {return true;} + inline bool GetHasMMU() override {return true;} std::pair GetWindowSize() override; diff --git a/parts/printers/Test_Printer.h b/parts/printers/Test_Printer.h index bfa3c35c..8d04fa2e 100644 --- a/parts/printers/Test_Printer.h +++ b/parts/printers/Test_Printer.h @@ -33,7 +33,7 @@ class Test_Printer : public Boards::Test_Board, public Printer ~Test_Printer() override = default; - std::pair GetWindowSize() override {return { 5 + m_lcd.GetWidth() * 6, 50 + 5 + m_lcd.GetHeight() * 9}; }; + inline std::pair GetWindowSize() override {return { 5 + m_lcd.GetWidth() * 6, 50 + 5 + m_lcd.GetHeight() * 9}; }; void Draw() override; diff --git a/scripts/tests/test_A4982.c b/scripts/tests/test_A4982.c index eae6ddc1..719c3d81 100644 --- a/scripts/tests/test_A4982.c +++ b/scripts/tests/test_A4982.c @@ -138,6 +138,7 @@ int main() for (int i=0; i<64; i++) step(); + _delay_ms(25); printf("STEP64 1\n"); while(1); diff --git a/scripts/tests/test_MMU1.txt b/scripts/tests/test_MMU1.txt index 545dce6e..d31703a2 100644 --- a/scripts/tests/test_MMU1.txt +++ b/scripts/tests/test_MMU1.txt @@ -23,8 +23,8 @@ TelHost::WaitFor(MMU1_>STEP1,0) Serial0::NextLineMustBe(OUT 0) TelHost::WaitFor(MMU1_8>tool_out,0) Board::WaitMs(2) -GLHelper::SnapRect(tests/snaps/MMU105,144,244,27,40) Serial0::NextLineMustBe(STEP) TelHost::WaitFor(MMU1_>STEP0,1) TelHost::WaitFor(MMU1_>STEP0,0) +GLHelper::SnapRect(tests/snaps/MMU105,144,244,27,40) Board::Quit() diff --git a/utility/FatImage.cpp b/utility/FatImage.cpp index db78bf3b..c57c914b 100644 --- a/utility/FatImage.cpp +++ b/utility/FatImage.cpp @@ -27,6 +27,7 @@ #include #include // IWYU pragma: keep #include +#include #include // for vector // const mapFatImage::SectorsPerFat = @@ -73,6 +74,57 @@ const std::map& FatImage::GetNameToSize() return m; }; +uint8_t FatImage::GetSectorsPerCluster(Size imgSize) +{ + return imgSize>Size::M256 ? 8 : 1; +} + +uint32_t FatImage::GetSizeInBytes(Size imgSize) +{ + return static_cast(imgSize)<<20u; // 20 = 1024*1024 +} + +uint32_t FatImage::GetSecondFatAddr(Size imgSize) +{ + return FirstFATAddr + (Sector2Bytes(SectorsPerFat(imgSize))); +} + +uint32_t FatImage::GetDataStartAddr(Size imgSize) +{ + return FirstFATAddr + (Sector2Bytes(SectorsPerFat(imgSize))<<1u); // <<10 = 2*512, 2*bytespersector. +} + +uint32_t FatImage::SectorsPerFat(Size size) +{ + switch (size) + { + case Size::M32: + return 505; + case Size::M64: + return 1009; + case Size::M128: + return 2017; + case Size::M256: + return 4033; + case Size::M512: + return 1022; + case Size::G1: + return 2044; + case Size::G2: + return 4088; + } + return 0; +}; + +std::vector FatImage::GetSizes() +{ + std::vector strSize; + for(auto &c : GetNameToSize()) + { + strSize.push_back(c.first); + } + return strSize; +} bool FatImage::MakeFatImage(const std::string &strFile, const std::string &strSize) { diff --git a/utility/FatImage.h b/utility/FatImage.h index eeeb6db2..e1eff0f0 100644 --- a/utility/FatImage.h +++ b/utility/FatImage.h @@ -26,7 +26,6 @@ #include // for uint32_t, uint8_t #include // for _Rb_tree_const_iterator, map #include // for string -#include // for pair #include // for vector class FatImage @@ -44,17 +43,9 @@ class FatImage G2 = 2048 }; - static bool MakeFatImage(const std::string &strFile, const std::string &strSize); + static std::vector GetSizes(); - static std::vector GetSizes() - { - std::vector strSize; - for(auto &c : GetNameToSize()) - { - strSize.push_back(c.first); - } - return strSize; - } + static bool MakeFatImage(const std::string &strFile, const std::string &strSize); private: static inline constexpr uint32_t Sector2Bytes(uint32_t val) { return val<<9u; } // <<9 = 512 bytes/sector. @@ -62,35 +53,15 @@ class FatImage static constexpr uint32_t FirstFATAddr = 0x4000; - static inline uint8_t GetSectorsPerCluster(Size imgSize) { return imgSize>Size::M256 ? 8 : 1; } + static uint8_t GetSectorsPerCluster(Size imgSize); - static uint32_t GetSizeInBytes(Size imgSize) { return static_cast(imgSize)<<20u; } // 20 = 1024*1024 + static uint32_t GetSizeInBytes(Size imgSize); - static uint32_t GetSecondFatAddr(Size imgSize) {return FirstFATAddr + (Sector2Bytes(SectorsPerFat(imgSize)));} + static uint32_t GetSecondFatAddr(Size imgSize); - static uint32_t GetDataStartAddr(Size imgSize) { return FirstFATAddr + (Sector2Bytes(SectorsPerFat(imgSize))<<1u); } // <<10 = 2*512, 2*bytespersector. + static uint32_t GetDataStartAddr(Size imgSize); - static uint32_t SectorsPerFat(Size size) - { - switch (size) - { - case Size::M32: - return 505; - case Size::M64: - return 1009; - case Size::M128: - return 2017; - case Size::M256: - return 4033; - case Size::M512: - return 1022; - case Size::G1: - return 2044; - case Size::G2: - return 4088; - } - return 0; - }; + static uint32_t SectorsPerFat(Size size); static const std::map& GetNameToSize(); diff --git a/utility/MK3S_Bear.cpp b/utility/MK3S_Bear.cpp new file mode 100644 index 00000000..38c31cfe --- /dev/null +++ b/utility/MK3S_Bear.cpp @@ -0,0 +1,126 @@ +/* + MK3S_Full.h - Object collection for the standard visuals. + + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "MK3S_Bear.h" +#include "GLObj.h" +#include "OBJCollection.h" +#include + +MK3S_Bear::MK3S_Bear(bool /*bMMU*/):OBJCollection("Bear") +{ + AddObject(ObjClass::Z, "assets/bear21_mk3s_simulator_x-axis.obj",0,-.127,0,CM_TO_M)->SetSwapMode(GLObj::SwapMode::YMINUSZ); + m_pE = AddObject(ObjClass::X, "assets/bear21_mk3s_simulator_e-axis_w-hotend-fan.obj",-0.130-0.182000, 0.318000, -0.186000,CM_TO_M); + m_pE->SetSwapMode(GLObj::SwapMode::YMINUSZ); + m_pPFS = AddObject(ObjClass::Other, "assets/bear21_mk3s_simulator_print_fan.obj", CM_TO_M); + m_pPFS->SetSwapMode(GLObj::SwapMode::YMINUSZ); + AddObject(ObjClass::Y, "assets/bear21_mk3s_simulator_y-axis.obj",0,0,-.1175,CM_TO_M)->SetSwapMode(GLObj::SwapMode::YMINUSZ); + m_pBaseObj = AddObject(ObjClass::Fixed, "assets/bear21_mk3s_simulator_frame.obj", CM_TO_M); + m_pBaseObj->SetSwapMode(GLObj::SwapMode::YMINUSZ); + m_pKnob = AddObject(ObjClass::Other, "assets/bear21_mk3s_simulator_lcd_knob.obj",CM_TO_M); + m_pFan = AddObject(ObjClass::Other, "assets/bear21_mk3s_simulator_hotend-fan-blade.obj",CM_TO_M); + SetMaterialMode(GL_AMBIENT_AND_DIFFUSE); // These first ones only have Kd. + AddObject(ObjClass::PrintSurface, "assets/SSSheet.obj",-0.127000,0.236000,-0.170000); + AddObject(ObjClass::Media, "assets/SDCard.obj",-0.157000, 0.147000, -0.448998,MM_TO_M); + m_pEVis = AddObject(ObjClass::Other,"assets/Triangles.obj",MM_TO_M); + m_pPFan = AddObject(ObjClass::Other, "assets/Print-fan_rotor.obj"); +}; + +void MK3S_Bear::SetupLighting() +{ + float fNone[] = {0,0,0,1}; + float fWhite[] = {1,1,1,1}; + + float fPos[] = {2,-2,-2,0}; + glLightfv(GL_LIGHT0,GL_AMBIENT, static_cast(fNone)); + glLightfv(GL_LIGHT0,GL_SPECULAR, static_cast(fWhite)); + glLightfv(GL_LIGHT0,GL_DIFFUSE, static_cast(fWhite)); + glLightfv(GL_LIGHT0,GL_POSITION, static_cast(fPos)); +} + +void MK3S_Bear::GetBaseCenter(gsl::span fTrans) +{ + m_pBaseObj->GetCenteringTransform(fTrans); + float fTmp = fTrans[1]; + fTrans[1] = fTrans[2]; + fTrans[2] = -fTmp; +}; + +void MK3S_Bear::GetNozzleCamPos(gsl::span fPos) +{ + fPos[0] = -0.131f; + fPos[1] = -0.11f; + fPos[2] = -0.054f; +} + +void MK3S_Bear::DrawKnob(int iRotation) +{ + if (m_pKnob == nullptr) + { + return; + } + glPushMatrix(); + glTranslatef(0.060,0.197,0.054); + glRotatef(-45.f,1,0,0); + glPushMatrix(); + glRotatef(static_cast(iRotation),0,0,1); + m_pKnob->Draw(); + glPopMatrix(); + glPopMatrix(); +} + +void MK3S_Bear::DrawEFan(int iRotation) +{ + glTranslatef(-0.153000, 0.252000, -0.150000); + glRotatef(90,0,1,0); + float fTransform[3]; + m_pFan->GetCenteringTransform(fTransform); + glTranslatef (-fTransform[0], -fTransform[1], -fTransform[2]); + glRotatef(static_cast(iRotation),0,0,1); + glTranslatef (fTransform[0], fTransform[1], fTransform[2]); + m_pFan->Draw(); +} + +void MK3S_Bear::DrawPFan(int iRotation) +{ + glTranslatef(-0.11100, 0.2710, -0.148000); + glPushMatrix(); + glTranslatef(-0.03000, 0.0, -0.002000); + glRotatef(90,0,1,0); + m_pPFS->Draw(); + glPopMatrix(); + glRotatef(90,1,0,0); + glPushMatrix(); + glRotatef(static_cast(iRotation),0,1,0); + m_pPFan->Draw(); + glPopMatrix(); +} + +void MK3S_Bear::DrawEVis(float fEPos) +{ + glTranslatef(-0.201000, -0.053000, -0.451998); + float fTransform[3]; + m_pEVis->GetCenteringTransform(fTransform); + fTransform[1] +=.0015f; + glTranslatef (-fTransform[0] , -fTransform[1], -fTransform[2]); + glRotatef((-36.f/28.f)*6.f*(fEPos*1000.f),0,0,1); + glTranslatef (fTransform[0], fTransform[1], fTransform[2]); + m_pEVis->Draw(); +} diff --git a/utility/MK3S_Bear.h b/utility/MK3S_Bear.h index 9d4a116f..24cca84e 100644 --- a/utility/MK3S_Bear.h +++ b/utility/MK3S_Bear.h @@ -23,41 +23,17 @@ #include "GLObj.h" #include "OBJCollection.h" +#include "gsl-lite.hpp" +#include +#include class MK3S_Bear: public OBJCollection { public: - explicit MK3S_Bear(bool /*bMMU*/):OBJCollection("Bear") - { - AddObject(ObjClass::Z, "assets/bear21_mk3s_simulator_x-axis.obj",0,-.127,0,CM_TO_M)->SetSwapMode(GLObj::SwapMode::YMINUSZ); - m_pE = AddObject(ObjClass::X, "assets/bear21_mk3s_simulator_e-axis_w-hotend-fan.obj",-0.130-0.182000, 0.318000, -0.186000,CM_TO_M); - m_pE->SetSwapMode(GLObj::SwapMode::YMINUSZ); - m_pPFS = AddObject(ObjClass::Other, "assets/bear21_mk3s_simulator_print_fan.obj", CM_TO_M); - m_pPFS->SetSwapMode(GLObj::SwapMode::YMINUSZ); - AddObject(ObjClass::Y, "assets/bear21_mk3s_simulator_y-axis.obj",0,0,-.1175,CM_TO_M)->SetSwapMode(GLObj::SwapMode::YMINUSZ); - m_pBaseObj = AddObject(ObjClass::Fixed, "assets/bear21_mk3s_simulator_frame.obj", CM_TO_M); - m_pBaseObj->SetSwapMode(GLObj::SwapMode::YMINUSZ); - m_pKnob = AddObject(ObjClass::Other, "assets/bear21_mk3s_simulator_lcd_knob.obj",CM_TO_M); - m_pFan = AddObject(ObjClass::Other, "assets/bear21_mk3s_simulator_hotend-fan-blade.obj",CM_TO_M); - SetMaterialMode(GL_AMBIENT_AND_DIFFUSE); // These first ones only have Kd. - AddObject(ObjClass::PrintSurface, "assets/SSSheet.obj",-0.127000,0.236000,-0.170000); - AddObject(ObjClass::Media, "assets/SDCard.obj",-0.157000, 0.147000, -0.448998,MM_TO_M); - m_pEVis = AddObject(ObjClass::Other,"assets/Triangles.obj",MM_TO_M); - m_pPFan = AddObject(ObjClass::Other, "assets/Print-fan_rotor.obj"); - }; - - void SetupLighting() override - { - float fNone[] = {0,0,0,1}; - float fWhite[] = {1,1,1,1}; + explicit MK3S_Bear(bool /*bMMU*/); - float fPos[] = {2,-2,-2,0}; - glLightfv(GL_LIGHT0,GL_AMBIENT, static_cast(fNone)); - glLightfv(GL_LIGHT0,GL_SPECULAR, static_cast(fWhite)); - glLightfv(GL_LIGHT0,GL_DIFFUSE, static_cast(fWhite)); - glLightfv(GL_LIGHT0,GL_POSITION, static_cast(fPos)); - } + void SetupLighting() override; inline bool SupportsMMU() override { return false; } @@ -77,76 +53,18 @@ class MK3S_Bear: public OBJCollection inline void SetNozzleCam(bool bOn) override { m_pE->SetSubobjectVisible(89,!bOn); } - void GetBaseCenter(gsl::span fTrans) override - { - m_pBaseObj->GetCenteringTransform(fTrans); - float fTmp = fTrans[1]; - fTrans[1] = fTrans[2]; - fTrans[2] = -fTmp; - }; + void GetBaseCenter(gsl::span fTrans) override; - void GetNozzleCamPos(gsl::span fPos) override - { - fPos[0] = -0.131f; - fPos[1] = -0.11f; - fPos[2] = -0.054f; - } + void GetNozzleCamPos(gsl::span fPos) override; - void DrawKnob(int iRotation) override - { - if (m_pKnob == nullptr) - { - return; - } - glPushMatrix(); - glTranslatef(0.060,0.197,0.054); - glRotatef(-45.f,1,0,0); - glPushMatrix(); - glRotatef(static_cast(iRotation),0,0,1); - m_pKnob->Draw(); - glPopMatrix(); - glPopMatrix(); - } - - void DrawEFan(int iRotation) override - { - glTranslatef(-0.153000, 0.252000, -0.150000); - glRotatef(90,0,1,0); - float fTransform[3]; - m_pFan->GetCenteringTransform(fTransform); - glTranslatef (-fTransform[0], -fTransform[1], -fTransform[2]); - glRotatef(static_cast(iRotation),0,0,1); - glTranslatef (fTransform[0], fTransform[1], fTransform[2]); - m_pFan->Draw(); - } - - void DrawPFan(int iRotation) override - { - glTranslatef(-0.11100, 0.2710, -0.148000); - glPushMatrix(); - glTranslatef(-0.03000, 0.0, -0.002000); - glRotatef(90,0,1,0); - m_pPFS->Draw(); - glPopMatrix(); - glRotatef(90,1,0,0); - glPushMatrix(); - glRotatef(static_cast(iRotation),0,1,0); - m_pPFan->Draw(); - glPopMatrix(); - } - - void DrawEVis(float fEPos) override - { - glTranslatef(-0.201000, -0.053000, -0.451998); - float fTransform[3]; - m_pEVis->GetCenteringTransform(fTransform); - fTransform[1] +=.0015f; - glTranslatef (-fTransform[0] , -fTransform[1], -fTransform[2]); - glRotatef((-36.f/28.f)*6.f*(fEPos*1000.f),0,0,1); - glTranslatef (fTransform[0], fTransform[1], fTransform[2]); - m_pEVis->Draw(); - } + void DrawKnob(int iRotation) override; + + void DrawEFan(int iRotation) override; + + void DrawPFan(int iRotation) override; + + void DrawEVis(float fEPos) override; std::shared_ptr m_pKnob = nullptr, m_pFan = nullptr, m_pEVis = nullptr, m_pPFan = nullptr, m_pE = nullptr, m_pPFS = nullptr; diff --git a/utility/MK3S_Full.cpp b/utility/MK3S_Full.cpp new file mode 100644 index 00000000..c2ec53a7 --- /dev/null +++ b/utility/MK3S_Full.cpp @@ -0,0 +1,43 @@ +/* + MK3S_Full.cpp - Object collection for the standard visuals. + + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "MK3S_Full.h" +#include "GLObj.h" +#include "MK3S_Lite.h" +#include "OBJCollection.h" + +MK3S_Full::MK3S_Full(bool bMMU):MK3S_Lite(bMMU) +{ + float fXCorr = -0.044; + // float fYCorr = -0.141; + float fZCorr = -0.210; + SetName("Full"); + AddObject(ObjClass::Z, "assets/Z_AXIS.obj", 0,fZCorr,0); + if (bMMU) + { + AddObject(ObjClass::X, "assets/E_MMU.obj",fXCorr,fZCorr,0,MM_TO_M)->SetKeepNormalsIfScaling(true); + } + else + { + AddObject(ObjClass::X, "assets/E_STD.obj",fXCorr,fZCorr,0,MM_TO_M)->SetKeepNormalsIfScaling(true); + } + m_pBaseObj = AddObject(ObjClass::Fixed, "assets/Stationary.obj"); +}; diff --git a/utility/MK3S_Full.h b/utility/MK3S_Full.h index 240939d1..35546234 100644 --- a/utility/MK3S_Full.h +++ b/utility/MK3S_Full.h @@ -23,35 +23,19 @@ #include "GLObj.h" #include "MK3S_Lite.h" -#include "OBJCollection.h" - +#include "gsl-lite.hpp" +#include class MK3S_Full: public MK3S_Lite { public: - explicit MK3S_Full(bool bMMU):MK3S_Lite(bMMU) - { - float fXCorr = -0.044; - // float fYCorr = -0.141; - float fZCorr = -0.210; - SetName("Full"); - AddObject(ObjClass::Z, "assets/Z_AXIS.obj", 0,fZCorr,0); - if (bMMU) - { - AddObject(ObjClass::X, "assets/E_MMU.obj",fXCorr,fZCorr,0,MM_TO_M)->SetKeepNormalsIfScaling(true); - } - else - { - AddObject(ObjClass::X, "assets/E_STD.obj",fXCorr,fZCorr,0,MM_TO_M)->SetKeepNormalsIfScaling(true); - } - m_pBaseObj = AddObject(ObjClass::Fixed, "assets/Stationary.obj"); - }; + explicit MK3S_Full(bool bMMU); inline void SetNozzleCam(bool bOn) override { m_pE->SetSubobjectVisible(0,!bOn); } - void OnLoadComplete() override {}; + inline void OnLoadComplete() override {}; inline float GetScaleFactor() override { return m_pBaseObj->GetScaleFactor();}; - void GetBaseCenter(gsl::spanfTrans) override {m_pBaseObj->GetCenteringTransform(fTrans);} + inline void GetBaseCenter(gsl::spanfTrans) override {m_pBaseObj->GetCenteringTransform(fTrans);} }; diff --git a/utility/MK3S_Lite.cpp b/utility/MK3S_Lite.cpp new file mode 100644 index 00000000..f07e3cf7 --- /dev/null +++ b/utility/MK3S_Lite.cpp @@ -0,0 +1,123 @@ +/* + MK3S_Lite.h - Object collection for the "lite" visuals. + + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + +#include "MK3S_Lite.h" +#include "GLObj.h" +#include "OBJCollection.h" +#include // for map +#include // for string +#include // for vector + + +MK3S_Lite::MK3S_Lite(bool /*bMMU*/):OBJCollection("Lite") +{ + AddObject(ObjClass::Y, "assets/Y_AXIS.obj", 0, 0, -0.141); + AddObject(ObjClass::PrintSurface, "assets/SSSheet.obj", 0.025,0.083,0.431 + -0.141); + AddObject(ObjClass::Media, "assets/SDCard.obj",0,0,0,MM_TO_M)->SetKeepNormalsIfScaling(true); + m_pE = AddObject(ObjClass::X, "assets/X_AXIS.obj",-0.044,-0.210,0); + m_pKnob = AddObject(ObjClass::Other, "assets/LCD-knobR2.obj"); + m_pPFan = AddObject(ObjClass::Other, "assets/Print-fan_rotor.obj"); + m_pEFan = AddObject(ObjClass::Other, "assets/E_Fan.obj",MM_TO_M); + m_pEFan->SetKeepNormalsIfScaling(true); + m_pEVis = AddObject(ObjClass::Other,"assets/Triangles.obj",MM_TO_M); + m_pEVis->SetKeepNormalsIfScaling(true); +}; + +void MK3S_Lite::OnLoadComplete() +{ + m_mObjs.at(ObjClass::Y).at(0)->SetAllVisible(false); + m_mObjs.at(ObjClass::Y).at(0)->SetSubobjectVisible(2); // heatbed, sheet + auto pExtruder = m_mObjs.at(ObjClass::X).at(0); + pExtruder->SetAllVisible(false); + pExtruder->SetSubobjectVisible(19); // V6 + //pExtruder->SetSubobjectVisible(20); + pExtruder->SetSubobjectVisible(1); // PINDA + pExtruder->SetSubobjectVisible(2); +} + +void MK3S_Lite::SetupLighting() +{ + float fAmb[] = {.1,.1,.1,1}; + float fSpec[] = {.4,.4,.4,.5}; + float fDiff[] = {1.5,1.5,1.5,1}; + float fPos[] = {2,2,2,0}; + glLightfv(GL_LIGHT0,GL_AMBIENT, static_cast(fAmb)); + glLightfv(GL_LIGHT0,GL_SPECULAR, static_cast(fSpec)); + glLightfv(GL_LIGHT0,GL_DIFFUSE, static_cast(fDiff)); + glLightfv(GL_LIGHT0,GL_POSITION, static_cast(fPos)); +} + +void MK3S_Lite::GetBaseCenter(gsl::span fTrans) +{ + // Values stolen from the full model so we don't have to load the frame: + fTrans[0] = -0.154; + fTrans[1] = -0.204; + fTrans[2] = -0.3134; +} + +void MK3S_Lite::DrawKnob(int iRotation) +{ + if (m_pKnob == nullptr) + { + return; + } + glPushMatrix(); + glTranslatef(0.215,0.051,0.501); + glRotatef(-45.f,1,0,0); + glPushMatrix(); + glRotatef(static_cast(iRotation),0,0,1); + m_pKnob->Draw(); + glPopMatrix(); + glPopMatrix(); +} + +void MK3S_Lite::DrawEVis(float fEPos) +{ + float fTransform[3]; + glTranslatef(-0.044,-0.210,0.f); + m_pEVis->GetCenteringTransform(fTransform); + fTransform[1] +=.0015f; + glTranslatef (-fTransform[0] , -fTransform[1], -fTransform[2]); + glRotatef((-36.f/28.f)*6.f*(fEPos*1000.f),0,0,1); + glTranslatef (fTransform[0], fTransform[1], fTransform[2]); + m_pEVis->Draw(); +} + +void MK3S_Lite::DrawEFan(int iRotation) +{ + glTranslatef(-0.044,-0.210,0.f); + float fTransform[3]; + m_pEFan->GetCenteringTransform(fTransform); + glTranslatef (-fTransform[0], -fTransform[1], -fTransform[2]); + glRotatef(static_cast(iRotation),1,0,0); + glTranslatef (fTransform[0], fTransform[1], fTransform[2]); + m_pEFan->Draw(); +} + +void MK3S_Lite::DrawPFan(int iRotation) +{ + glTranslatef(0.042,0.118,0.314); + glRotatef(180-45.0,1,0,0); + glPushMatrix(); + glRotatef(static_cast(iRotation),0,1,0); + m_pPFan->Draw(); + glPopMatrix(); +} diff --git a/utility/MK3S_Lite.h b/utility/MK3S_Lite.h index 581840dd..4ae515ea 100644 --- a/utility/MK3S_Lite.h +++ b/utility/MK3S_Lite.h @@ -21,50 +21,22 @@ #pragma once -#include "GLObj.h" #include "OBJCollection.h" +#include "gsl-lite.hpp" +#include +#include + +class GLObj; class MK3S_Lite: public OBJCollection { public: - explicit MK3S_Lite(bool /*bMMU*/):OBJCollection("Lite") - { - AddObject(ObjClass::Y, "assets/Y_AXIS.obj", 0, 0, -0.141); - AddObject(ObjClass::PrintSurface, "assets/SSSheet.obj", 0.025,0.083,0.431 + -0.141); - AddObject(ObjClass::Media, "assets/SDCard.obj",0,0,0,MM_TO_M)->SetKeepNormalsIfScaling(true); - m_pE = AddObject(ObjClass::X, "assets/X_AXIS.obj",-0.044,-0.210,0); - m_pKnob = AddObject(ObjClass::Other, "assets/LCD-knobR2.obj"); - m_pPFan = AddObject(ObjClass::Other, "assets/Print-fan_rotor.obj"); - m_pEFan = AddObject(ObjClass::Other, "assets/E_Fan.obj",MM_TO_M); - m_pEFan->SetKeepNormalsIfScaling(true); - m_pEVis = AddObject(ObjClass::Other,"assets/Triangles.obj",MM_TO_M); - m_pEVis->SetKeepNormalsIfScaling(true); - }; - - - void OnLoadComplete() override - { - m_mObjs.at(ObjClass::Y).at(0)->SetAllVisible(false); - m_mObjs.at(ObjClass::Y).at(0)->SetSubobjectVisible(2); // heatbed, sheet - auto pExtruder = m_mObjs.at(ObjClass::X).at(0); - pExtruder->SetAllVisible(false); - pExtruder->SetSubobjectVisible(19); // V6 - //pExtruder->SetSubobjectVisible(20); - pExtruder->SetSubobjectVisible(1); // PINDA - pExtruder->SetSubobjectVisible(2); - } + explicit MK3S_Lite(bool /*bMMU*/); - void SetupLighting() override - { - float fAmb[] = {.1,.1,.1,1}; - float fSpec[] = {.4,.4,.4,.5}; - float fDiff[] = {1.5,1.5,1.5,1}; - float fPos[] = {2,2,2,0}; - glLightfv(GL_LIGHT0,GL_AMBIENT, static_cast(fAmb)); - glLightfv(GL_LIGHT0,GL_SPECULAR, static_cast(fSpec)); - glLightfv(GL_LIGHT0,GL_DIFFUSE, static_cast(fDiff)); - glLightfv(GL_LIGHT0,GL_POSITION, static_cast(fPos)); - } + + void OnLoadComplete() override; + + void SetupLighting() override; inline bool SupportsMMU() override { return true; } @@ -76,31 +48,11 @@ class MK3S_Lite: public OBJCollection inline void ApplyPrintTransform() override { glTranslatef(0.024,0.084,-0.281); }; - void GetBaseCenter(gsl::span fTrans) override - { - // Values stolen from the full model so we don't have to load the frame: - fTrans[0] = -0.154; - fTrans[1] = -0.204; - fTrans[2] = -0.3134; - } + void GetBaseCenter(gsl::span fTrans) override; float GetScaleFactor() override { return 0.210874f; } - void DrawKnob(int iRotation) override - { - if (m_pKnob == nullptr) - { - return; - } - glPushMatrix(); - glTranslatef(0.215,0.051,0.501); - glRotatef(-45.f,1,0,0); - glPushMatrix(); - glRotatef(static_cast(iRotation),0,0,1); - m_pKnob->Draw(); - glPopMatrix(); - glPopMatrix(); - } + void DrawKnob(int iRotation) override; inline void GetNozzleCamPos(gsl::span fPos) override { @@ -109,39 +61,11 @@ class MK3S_Lite: public OBJCollection fPos[2] = -0.04f; } - void DrawEVis(float fEPos) override - { - float fTransform[3]; - glTranslatef(-0.044,-0.210,0.f); - m_pEVis->GetCenteringTransform(fTransform); - fTransform[1] +=.0015f; - glTranslatef (-fTransform[0] , -fTransform[1], -fTransform[2]); - glRotatef((-36.f/28.f)*6.f*(fEPos*1000.f),0,0,1); - glTranslatef (fTransform[0], fTransform[1], fTransform[2]); - m_pEVis->Draw(); - } + void DrawEVis(float fEPos) override; - void DrawEFan(int iRotation) override - { - glTranslatef(-0.044,-0.210,0.f); - float fTransform[3]; - m_pEFan->GetCenteringTransform(fTransform); - glTranslatef (-fTransform[0], -fTransform[1], -fTransform[2]); - glRotatef(static_cast(iRotation),1,0,0); - glTranslatef (fTransform[0], fTransform[1], fTransform[2]); - m_pEFan->Draw(); - } - - void DrawPFan(int iRotation) override - { - glTranslatef(0.042,0.118,0.314); - glRotatef(180-45.0,1,0,0); - glPushMatrix(); - glRotatef(static_cast(iRotation),0,1,0); - m_pPFan->Draw(); - glPopMatrix(); - } + void DrawEFan(int iRotation) override; + void DrawPFan(int iRotation) override; protected: diff --git a/utility/OBJCollection.cpp b/utility/OBJCollection.cpp new file mode 100644 index 00000000..5fd2ca65 --- /dev/null +++ b/utility/OBJCollection.cpp @@ -0,0 +1,66 @@ +/* + OBJCollection.h - Base class wrangler for a collection of OBJs that comprise a + set of visuals for a single printer. + + Copyright 2020 VintagePC + + This file is part of MK404. + + MK404 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. + + MK404 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 MK404. If not, see . + */ + + +#include "OBJCollection.h" +#include "GLObj.h" +#include +#include + +void OBJCollection::Load() +{ + for (auto &sets : m_mObjs) + { + for (auto &obj : sets.second) + { + obj->Load(); + } + } + OnLoadComplete(); +}; + + +void OBJCollection::Draw(const ObjClass type) +{ + if (m_mObjs.count(type)==0) + { + return; + } + + for (auto &obj : m_mObjs.at(type)) + { + obj->Draw(); + } + +} + + +void OBJCollection::SetMaterialMode(GLenum type) +{ + for (auto &sets : m_mObjs) + { + for (auto &obj : sets.second) + { + obj->SetMaterialMode(type); + } + } +}; diff --git a/utility/OBJCollection.h b/utility/OBJCollection.h index 90f96190..26c040d9 100644 --- a/utility/OBJCollection.h +++ b/utility/OBJCollection.h @@ -23,9 +23,12 @@ #pragma once #include "GLObj.h" +#include "gsl-lite.hpp" // for span +#include // for GLenum #include #include #include +#include // for move #include class OBJCollection @@ -35,17 +38,7 @@ class OBJCollection explicit OBJCollection(std::string strName):m_strName(std::move(strName)){}; ~OBJCollection() = default; // pragma: LCOV_EXCL_LINE - void Load() - { - for (auto &sets : m_mObjs) - { - for (auto &obj : sets.second) - { - obj->Load(); - } - } - OnLoadComplete(); - }; + void Load(); // Note: class reference is for the motion, e.g. // an object of class "X" is moved when X changes. @@ -62,23 +55,11 @@ class OBJCollection }; - inline void Draw(const ObjClass type) - { - if (m_mObjs.count(type)==0) - { - return; - } - - for (auto &obj : m_mObjs.at(type)) - { - obj->Draw(); - } - - }; + void Draw(const ObjClass type); virtual inline void ApplyPLEDTransform() {}; // pragma: LCOV_EXCL_START - these lines are not reachable if derivatives are properly implemented. - virtual void GetBaseCenter(gsl::span fTrans) + virtual inline void GetBaseCenter(gsl::span fTrans) { m_pBaseObj->GetCenteringTransform(fTrans); }; @@ -89,7 +70,7 @@ class OBJCollection virtual inline void ApplyLCDTransform() {}; virtual inline void ApplyPrintTransform(){}; - virtual float GetScaleFactor(){return 1.f;}; + virtual inline float GetScaleFactor(){return 1.f;}; virtual inline void SetNozzleCam(bool /*bOn*/) {}; @@ -102,7 +83,7 @@ class OBJCollection // pragma: LCOV_EXCL_STOP - virtual bool SupportsMMU() { return false; } + virtual inline bool SupportsMMU() { return false; } inline const std::string GetName() { return m_strName;} @@ -118,16 +99,7 @@ class OBJCollection static constexpr float MM_TO_M = 1.f/1000.f; static constexpr float CM_TO_M = 1.f/100.f; - void SetMaterialMode(GLenum type) - { - for (auto &sets : m_mObjs) - { - for (auto &obj : sets.second) - { - obj->SetMaterialMode(type); - } - } - }; + void SetMaterialMode(GLenum type); std::shared_ptr m_pBaseObj = nullptr;