From 67585aae7bd6c13073cb0ca011d39b9a753c5037 Mon Sep 17 00:00:00 2001 From: matthew wildoer Date: Fri, 17 Nov 2017 19:40:44 +1100 Subject: [PATCH] Rebuild input structure Impliment OO CAN network Can Heartbeats Interlocks on bus failure --- g2core.atsln | 4 + g2core/board/geratech_proto.mk | 7 +- g2core/board/geratech_proto/board_can.cpp | 48 +- g2core/board/geratech_proto/board_can.h | 39 +- g2core/can_bus.cpp | 147 +++--- g2core/can_bus.h | 121 ++++- g2core/canonical_machine.cpp | 13 +- g2core/canonical_machine.h | 5 +- g2core/config_app.cpp | 160 +++--- g2core/controller.cpp | 36 +- g2core/g2core.cppproj | 340 ++++++++++++- g2core/gpio.cpp | 576 ++++++++-------------- g2core/gpio.h | 237 ++++----- g2core/main.cpp | 3 + g2core/settings/settings_geratech.h | 2 + g2core/xio.h | 1 + 16 files changed, 1002 insertions(+), 737 deletions(-) diff --git a/g2core.atsln b/g2core.atsln index 93cd6ae1..dd094480 100644 --- a/g2core.atsln +++ b/g2core.atsln @@ -9,6 +9,7 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution G2v9k|ARM = G2v9k|ARM + GeratechProto|ARM = GeratechProto|ARM gShield|ARM = gShield|ARM Makeblock-v9|ARM = Makeblock-v9|ARM Othermill|ARM = Othermill|ARM @@ -28,6 +29,8 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.G2v9k|ARM.ActiveCfg = G2v9k|ARM {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.G2v9k|ARM.Build.0 = G2v9k|ARM + {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.GeratechProto|ARM.ActiveCfg = GeratechProto|ARM + {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.GeratechProto|ARM.Build.0 = GeratechProto|ARM {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.gShield|ARM.ActiveCfg = gShield|ARM {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.gShield|ARM.Build.0 = gShield|ARM {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.Makeblock-v9|ARM.ActiveCfg = Makeblock-v9|ARM @@ -58,6 +61,7 @@ Global {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.Zen7x12|ARM.ActiveCfg = Zen7x12|ARM {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.Zen7x12|ARM.Build.0 = Zen7x12|ARM {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.G2v9k|ARM.ActiveCfg = Stub|ARM + {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.GeratechProto|ARM.ActiveCfg = GeratechProto|ARM {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.gShield|ARM.ActiveCfg = Stub|ARM {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.Makeblock-v9|ARM.ActiveCfg = Stub|ARM {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.Othermill|ARM.ActiveCfg = Stub|ARM diff --git a/g2core/board/geratech_proto.mk b/g2core/board/geratech_proto.mk index 4825df1c..c3bf85d3 100644 --- a/g2core/board/geratech_proto.mk +++ b/g2core/board/geratech_proto.mk @@ -28,15 +28,14 @@ ifeq ("$(BOARD)","geratech_proto") # Note: we call it "g2core-due" instead of "due" since the Motate built-in provides # a "due" BASE_BOARD. - BASE_BOARD = g2core-due + BASE_BOARD = geratech-due DEVICE_DEFINES += MOTATE_BOARD="geratech_proto" DEVICE_DEFINES += SETTINGS_FILE=${SETTINGS_FILE} endif ########## -# The general g2core-due BASE_BOARD. -ifeq ("$(BASE_BOARD)","g2core-due") +ifeq ("$(BASE_BOARD)","geratech-due") _BOARD_FOUND = 1 DEVICE_DEFINES += MOTATE_CONFIG_HAS_USBSERIAL=1 @@ -47,8 +46,6 @@ ifeq ("$(BASE_BOARD)","g2core-due") export CHIP CHIP_LOWERCASE = sam3x8e - # Note: we call it "g2core-due" instead of "due" since the Motate built-in provides - # a "due" BASE_BOARD. BOARD_PATH = ./board/geratech_proto SOURCE_DIRS += ${BOARD_PATH} device/step_dir_driver #SOURCE_DIRS += ${BOARD_PATH} device/step_dir_geratech_servo diff --git a/g2core/board/geratech_proto/board_can.cpp b/g2core/board/geratech_proto/board_can.cpp index e98cbf9a..ecf3a204 100644 --- a/g2core/board/geratech_proto/board_can.cpp +++ b/g2core/board/geratech_proto/board_can.cpp @@ -19,9 +19,12 @@ #include "board_can.h" +#ifndef _BOARD_CAN_C_ +#define _BOARD_CAN_C_ + CANRaw::CANRaw(Can* pCan, uint32_t En ) { m_pCan = pCan; - nIRQ=(m_pCan == CAN0 ? CAN0_IRQn : CAN1_IRQn); + nIRQ=(m_pCan == CAN0 ? CAN0_IRQn : CAN1_IRQn); enablePin = En; bigEndian = false; busSpeed = 0; @@ -118,15 +121,15 @@ uint32_t CANRaw::begin(uint32_t baudrate) return init(baudrate); } -uint32_t CANRaw::begin(uint32_t baudrate, uint8_t enablePin) +uint32_t CANRaw::begin(uint32_t baudrate, uint8_t _enablePin) { - this->enablePin = enablePin; + this->enablePin = _enablePin; return init(baudrate); } -uint32_t CANRaw::beginAutoSpeed(uint8_t enablePin) +uint32_t CANRaw::beginAutoSpeed(uint8_t _enablePin) { - this->enablePin = enablePin; + this->enablePin = _enablePin; return beginAutoSpeed(); } @@ -436,25 +439,25 @@ void CANRaw::detachCANInterrupt(uint8_t mailBox) cbCANFrame[mailBox] = 0; } -bool CANRaw::attachObj(CANListener *listener) +bool CANRaw::attachObj(CANListener *_listener) { for (int i = 0; i < SIZE_LISTENERS; i++) { if (this->listener[i] == NULL) { - this->listener[i] = listener; - listener->callbacksActive = 0; + this->listener[i] = _listener; + _listener->callbacksActive = 0; return true; } } return false; } -bool CANRaw::detachObj(CANListener *listener) +bool CANRaw::detachObj(CANListener *_listener) { for (int i = 0; i < SIZE_LISTENERS; i++) { - if (this->listener[i] == listener) + if (this->listener[i] == _listener) { this->listener[i] = NULL; return true; @@ -1584,10 +1587,6 @@ void CAN1_Handler(void) CANRaw Can0(CAN0, 0); CANRaw Can1(CAN1, 0); -void hw_can_message_received (CAN_FRAME *frame) { - can_message_received(frame->id, frame->length, frame->data.bytes); -} - void hw_can_init () { Can0.begin(CAN_BPS_250K); @@ -1605,20 +1604,13 @@ void hw_can_init () { Can0.setRXFilter(0, 0, false); //catch all mailbox - no mailbox ID specified //now register all of the callback functions. - Can0.setCallback(0, hw_can_message_received); - Can0.setCallback(1, hw_can_message_received); - Can0.setCallback(3, hw_can_message_received); - Can0.setCallback(4, hw_can_message_received); - Can0.setCallback(5, hw_can_message_received); + Can0.setCallback(0, can_message_received); + Can0.setCallback(1, can_message_received); + Can0.setCallback(3, can_message_received); + Can0.setCallback(4, can_message_received); + Can0.setCallback(5, can_message_received); //this function will get a callback for any mailbox that doesn't have a registered callback from above -> 2 and 6 - Can0.setGeneralCallback(hw_can_message_received); + Can0.setGeneralCallback(can_message_received); } -void hw_can_send_frame (uint32_t id, uint8_t length, uint8_t *data) { - CAN_FRAME f; - f.id = id; - f.length = length; - for (int i=0; i canNodes; +bool canTrueBool = true; + +// SystickEvent for handling can heartbeat (must be registered before it is active) +Motate::SysTickEvent can_heartbeat_check {[&] { + +}, nullptr}; + +CanEndpoint::CanEndpoint (CanNode *_node) { + this->node = node; + this->node->endpoints.addEntry(&this->endpointEntry); + cm.saftey_interlock_list.addEntry(&this->initInterlock); + this->CanEndpoint::state = CAN_ENDPOINT_INITALIZING; +} + +CanEndpoint::~CanEndpoint () { + this->node->endpoints.removeEntry(&this->endpointEntry); +} + +bool CanDigitalInput::processMessage(CanFrame *frame) { + if (frame->id == canId) { + ioDigitalInput::updateValue(frame->data.bytes[0]); + this->CanEndpoint::state = CAN_ENPOINT_RUNNING; + return true; + } else { + return false; + } +} + +CanDigitalInput::CanDigitalInput(int _canId, ioMode _mode, inputAction _action, inputFunc _function, uint16_t _lockout_ms) : CanEndpoint(this->node), ioDigitalInput(_canId, _mode, _action, _function, _lockout_ms) { + this->canId = _canId; + canNodes.iterateOver([&](CanNode *_node) { + if (_node->nodeId == _canId & (1<endpoints.addEntry(&this->endpointEntry); + this->node = _node; + return true; + } else return false; + }); +} + +CanNode::CanNode (int _nodeId) { + Motate::SysTickTimer.registerEvent(&this->heartbeatCheck); + cm.saftey_interlock_list.addEntry(&this->heartbeatInterlock); + canNodes.addEntry(&this->nodeEntry); + this->nodeId = _nodeId; +} + +CanNode::~CanNode() { + Motate::SysTickTimer.unregisterEvent(&this->heartbeatCheck); + cm.saftey_interlock_list.removeEntry(&this->heartbeatInterlock); +} + +bool CanNode::processFrame(CanFrame *frame) { + if (this->nodeId == frame->nodeId()) { + this->heartbeatCounter = 0; + + this->endpoints.iterateOver([&] (CanEndpoint *endpoint) { + return endpoint->processMessage(frame); + }); + + return true; + } else return false; +} + +void can_init() { + hw_can_init(); +} + +void can_message_received (CanFrame *frame) { + if (frame->id == 0) cm_shutdown(STAT_SHUTDOWN, "CAN Estop"); // Shutdown State (EStop) + else canNodes.iterateOver([&] (CanNode *node) { + return node->processFrame(frame); + }); // If it's not an EStop, give it to the registry to process +} + +void can_send_frame (CanFrame frame) { + Can0.sendFrame(frame); +} + +#endif \ No newline at end of file diff --git a/g2core/can_bus.h b/g2core/can_bus.h index c9026e76..eccd10d5 100644 --- a/g2core/can_bus.h +++ b/g2core/can_bus.h @@ -1,19 +1,122 @@ - -#ifndef CAN_H_ONCE -#define CAN_H_ONCE - #include "g2core.h" #include "hardware.h" #include "gpio.h" #include "xio.h" +#include "dynamic_registry.h" +#include "MotateTimers.h" +#include "canonical_machine.h" +#include "board_can.h" -#ifdef CAN_ENABLED +#ifndef CAN_H_ONCE +#define CAN_H_ONCE -typedef void(*ccb_t)(uint8_t*) ; // Can Callback Type +const int canIDLength = 11; +const int canIDTypeBits = 7; +const int canPhysicalNodeMax = (1 << (canIDLength - canIDTypeBits)); +const int canHeartbeat = 62; +const int canHeartbeatIDStart = canHeartbeat * canPhysicalNodeMax; +const int canPoll = 63; +const int canPollIDStart = canPoll * canPhysicalNodeMax; +const int canHeartbeatTimeout = 100; +extern bool canTrueBool; -void can_send_message (uint32_t id, uint8_t length, uint8_t *data); +typedef union { + uint64_t value; + struct { + uint32_t low; + uint32_t high; + }; + struct { + uint16_t s0; + uint16_t s1; + uint16_t s2; + uint16_t s3; + }; + uint8_t bytes[8]; + uint8_t byte[8]; //alternate name so you can omit the s if you feel it makes more sense +} BytesUnion; -void can_digital_output(uint8_t, bool); +typedef struct CanFrame { + uint32_t id; // EID if id set, SID otherwise + uint32_t fid; // family ID + uint8_t rtr; // Remote Transmission Request + uint8_t priority; // Priority but only important for TX frames and then only for special uses. + uint8_t extended; // Extended ID flag + uint16_t time; // CAN timer value when mailbox message was received. + uint8_t length; // Number of data bytes + BytesUnion data; // 64 bits - lots of ways to access it. + + uint32_t nodeId () { + return this->id & (1<::EntryType endpointEntry = {this, nullptr}; + DynamicRegistry::EntryType initInterlock = {&canTrueBool, nullptr}; + CanEndpointState state = CAN_ENDPOINT_INITALIZING; + + CanEndpoint (CanNode *_node); + ~CanEndpoint (); +}; + +class CanNode { + public: + DynamicRegistry endpoints; + + int nodeId; + DynamicRegistry::EntryType nodeEntry = {this, nullptr}; + + int heartbeatCounter = canHeartbeatTimeout; + bool heartbeatInterlockBool = true; + DynamicRegistry::EntryType heartbeatInterlock = {&heartbeatInterlockBool, nullptr}; + + Motate::SysTickEvent heartbeatCheck {[&] { + heartbeatCounter++; + heartbeatInterlockBool = (heartbeatCounter > canHeartbeatTimeout); + }, nullptr}; + + CanNode (int _nodeId); + ~CanNode(); + + void poll() { + CanFrame frame; + frame.id = canPollIDStart + this->nodeId; + frame.length = 0; + can_send_frame(frame); // Poll the node + } + + bool processFrame (CanFrame *frame); +}; + +class CanDigitalInput : public CanEndpoint, public ioDigitalInput { + public: + int canId; + + bool processMessage(CanFrame *frame); + + void reset () { + ioDigitalInput::reset(); + this->CanEndpoint::state = CAN_ENDPOINT_INITALIZING; + this->node->poll(); + } + + CanDigitalInput(int _canId, ioMode _mode = IO_MODE_DISABLED, inputAction _action = INPUT_ACTION_NONE, inputFunc _function = INPUT_FUNCTION_NONE, uint16_t _lockout_ms = 0); +}; + +extern DynamicRegistry canNodes; -#endif #endif diff --git a/g2core/canonical_machine.cpp b/g2core/canonical_machine.cpp index 9064852c..d93fa935 100644 --- a/g2core/canonical_machine.cpp +++ b/g2core/canonical_machine.cpp @@ -788,8 +788,8 @@ void canonical_machine_reset() cm.queue_flush_state = FLUSH_OFF; cm.end_hold_requested = false; cm.limit_requested = 0; // resets switch closures that occurred during initialization - cm.safety_interlock_disengaged = 0; // ditto - cm.safety_interlock_reengaged = 0; // ditto + //cm.safety_interlock_disengaged = 0; // ditto + //cm.safety_interlock_reengaged = 0; // ditto cm.shutdown_requested = 0; // ditto cm.probe_report_enable = PROBE_REPORT_ENABLE; @@ -1890,6 +1890,7 @@ stat_t cm_feedhold_sequencing_callback() * cm_end_hold() - end a feedhold by returning the system to normal operation * cm_queue_flush() - Flush planner queue and correct model positions */ + bool cm_has_hold() { return (cm.hold_state != FEEDHOLD_OFF); @@ -2506,10 +2507,10 @@ stat_t cm_set_hi(nvObj_t *nv) nv->valuetype = TYPE_NULL; return (STAT_INPUT_LESS_THAN_MIN_VALUE); } - if (nv->value > D_IN_CHANNELS+D_IN_CAN_CHANNELS) { - nv->valuetype = TYPE_NULL; - return (STAT_INPUT_EXCEEDS_MAX_VALUE); - } + //if (nv->value > D_IN_CHANNELS) { + //nv->valuetype = TYPE_NULL; + //return (STAT_INPUT_EXCEEDS_MAX_VALUE); + //} set_ui8(nv); return (STAT_OK); } diff --git a/g2core/canonical_machine.h b/g2core/canonical_machine.h index 4ff6e9cf..eb84b2c0 100644 --- a/g2core/canonical_machine.h +++ b/g2core/canonical_machine.h @@ -35,6 +35,7 @@ #include "config.h" #include "hardware.h" // Note: hardware.h is specific to the hardware target selected #include "settings.h" +#include "dynamic_registry.h" #if MARLIN_COMPAT_ENABLED == true #include "marlin_compatibility.h" // import Marlin definitions and enums @@ -424,9 +425,9 @@ typedef struct cmSingleton { // struct to manage cm globals and c cmOverrideState mfo_state; // feed override state machine cmQueueFlushState queue_flush_state; // master queue flush state machine - uint8_t safety_interlock_disengaged; // set non-zero to start interlock processing (value is input number) - uint8_t safety_interlock_reengaged; // set non-zero to end interlock processing (value is input number) cmSafetyState safety_interlock_state; // safety interlock state + DynamicRegistry saftey_interlock_list; + uint32_t esc_boot_timer; // timer for Electronic Speed Control (Spindle electronics) to boot cmHomingState homing_state; // home: homing cycle sub-state machine diff --git a/g2core/config_app.cpp b/g2core/config_app.cpp index 1cfbb9a3..0e82df58 100644 --- a/g2core/config_app.cpp +++ b/g2core/config_app.cpp @@ -355,80 +355,80 @@ const cfgItem_t cfgArray[] = { { "c","clb",_fip, 3, cm_print_lb, get_flt, set_flt, (float *)&cm.a[AXIS_C].latch_backoff, C_LATCH_BACKOFF }, { "c","czb",_fip, 3, cm_print_zb, get_flt, set_flt, (float *)&cm.a[AXIS_C].zero_backoff, C_ZERO_BACKOFF }, - // Digital input configs - { "di1","di1mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[0].mode, DI1_MODE }, - { "di1","di1ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[0].action, DI1_ACTION }, - { "di1","di1fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[0].function, DI1_FUNCTION }, - - { "di2","di2mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[1].mode, DI2_MODE }, - { "di2","di2ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[1].action, DI2_ACTION }, - { "di2","di2fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[1].function, DI2_FUNCTION }, - - { "di3","di3mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[2].mode, DI3_MODE }, - { "di3","di3ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[2].action, DI3_ACTION }, - { "di3","di3fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[2].function, DI3_FUNCTION }, - - { "di4","di4mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[3].mode, DI4_MODE }, - { "di4","di4ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[3].action, DI4_ACTION }, - { "di4","di4fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[3].function, DI4_FUNCTION }, - - { "di5","di5mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[4].mode, DI5_MODE }, - { "di5","di5ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[4].action, DI5_ACTION }, - { "di5","di5fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[4].function, DI5_FUNCTION }, - - { "di6","di6mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[5].mode, DI6_MODE }, - { "di6","di6ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[5].action, DI6_ACTION }, - { "di6","di6fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[5].function, DI6_FUNCTION }, - - { "di7","di7mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[6].mode, DI7_MODE }, - { "di7","di7ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[6].action, DI7_ACTION }, - { "di7","di7fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[6].function, DI7_FUNCTION }, - - { "di8","di8mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[7].mode, DI8_MODE }, - { "di8","di8ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[7].action, DI8_ACTION }, - { "di8","di8fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[7].function, DI8_FUNCTION }, -#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 9) - { "di9","di9mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[8].mode, DI9_MODE }, - { "di9","di9ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[8].action, DI9_ACTION }, - { "di9","di9fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[8].function, DI9_FUNCTION }, -#endif -#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 10) - { "di10","di10mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[9].mode, DI10_MODE }, - { "di10","di10ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[9].action, DI10_ACTION }, - { "di10","di10fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[9].function, DI10_FUNCTION }, -#endif -#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 11) - { "di11","di11mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[10].mode, DI11_MODE }, - { "di11","di11ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[10].action, DI11_ACTION }, - { "di11","di11fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[10].function, DI11_FUNCTION }, -#endif -#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 12) - { "di12","di12mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[11].mode, DI12_MODE }, - { "di12","di12ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[11].action, DI12_ACTION }, - { "di12","di12fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[11].function, DI12_FUNCTION }, -#endif - - // Digital input state readers - { "in","in1", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, - { "in","in2", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, - { "in","in3", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, - { "in","in4", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, - { "in","in5", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, - { "in","in6", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, - { "in","in7", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, - { "in","in8", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, -#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 9) - { "in","in9", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, -#endif -#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 10) - { "in","in10", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, -#endif -#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 11) - { "in","in11", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, -#endif -#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 12) - { "in","in12", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, -#endif + //// Digital input configs + //{ "di1","di1mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[0].mode, DI1_MODE }, + //{ "di1","di1ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[0].action, DI1_ACTION }, + //{ "di1","di1fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[0].function, DI1_FUNCTION }, +// + //{ "di2","di2mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[1].mode, DI2_MODE }, + //{ "di2","di2ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[1].action, DI2_ACTION }, + //{ "di2","di2fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[1].function, DI2_FUNCTION }, +// + //{ "di3","di3mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[2].mode, DI3_MODE }, + //{ "di3","di3ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[2].action, DI3_ACTION }, + //{ "di3","di3fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[2].function, DI3_FUNCTION }, +// + //{ "di4","di4mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[3].mode, DI4_MODE }, + //{ "di4","di4ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[3].action, DI4_ACTION }, + //{ "di4","di4fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[3].function, DI4_FUNCTION }, +// + //{ "di5","di5mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[4].mode, DI5_MODE }, + //{ "di5","di5ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[4].action, DI5_ACTION }, + //{ "di5","di5fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[4].function, DI5_FUNCTION }, +// + //{ "di6","di6mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[5].mode, DI6_MODE }, + //{ "di6","di6ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[5].action, DI6_ACTION }, + //{ "di6","di6fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[5].function, DI6_FUNCTION }, +// + //{ "di7","di7mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[6].mode, DI7_MODE }, + //{ "di7","di7ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[6].action, DI7_ACTION }, + //{ "di7","di7fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[6].function, DI7_FUNCTION }, +// + //{ "di8","di8mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[7].mode, DI8_MODE }, + //{ "di8","di8ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[7].action, DI8_ACTION }, + //{ "di8","di8fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[7].function, DI8_FUNCTION }, +//#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 9) + //{ "di9","di9mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[8].mode, DI9_MODE }, + //{ "di9","di9ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[8].action, DI9_ACTION }, + //{ "di9","di9fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[8].function, DI9_FUNCTION }, +//#endif +//#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 10) + //{ "di10","di10mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[9].mode, DI10_MODE }, + //{ "di10","di10ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[9].action, DI10_ACTION }, + //{ "di10","di10fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[9].function, DI10_FUNCTION }, +//#endif +//#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 11) + //{ "di11","di11mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[10].mode, DI11_MODE }, + //{ "di11","di11ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[10].action, DI11_ACTION }, + //{ "di11","di11fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[10].function, DI11_FUNCTION }, +//#endif +//#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 12) + //{ "di12","di12mo",_fip, 0, io_print_mo, get_int8,io_set_mo, (float *)&d_in[11].mode, DI12_MODE }, + //{ "di12","di12ac",_fip, 0, io_print_ac, get_ui8, io_set_ac, (float *)&d_in[11].action, DI12_ACTION }, + //{ "di12","di12fn",_fip, 0, io_print_fn, get_ui8, io_set_fn, (float *)&d_in[11].function, DI12_FUNCTION }, +//#endif +// + //// Digital input state readers + //{ "in","in1", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, + //{ "in","in2", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, + //{ "in","in3", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, + //{ "in","in4", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, + //{ "in","in5", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, + //{ "in","in6", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, + //{ "in","in7", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, + //{ "in","in8", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, +//#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 9) + //{ "in","in9", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, +//#endif +//#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 10) + //{ "in","in10", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, +//#endif +//#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 11) + //{ "in","in11", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, +//#endif +//#if (D_IN_CAN_CHANNELS+D_IN_CHANNELS >= 12) + //{ "in","in12", _f0, 0, io_print_in, io_get_input, set_ro, (float *)&cs.null, 0 }, +//#endif // digital output configs { "do1", "do1mo", _fip, 0, io_print_domode, get_int8, io_set_domode, (float *)&d_out[0].mode, DO1_MODE }, @@ -1382,18 +1382,18 @@ static stat_t _do_offsets(nvObj_t *nv) // print offset parameters for G54-G59,G static stat_t _do_inputs(nvObj_t *nv) // print parameters for all input groups { - char group[GROUP_LEN]; - for (uint8_t i=1; i < D_IN_CAN_CHANNELS+D_IN_CHANNELS+1; i++) { - sprintf(group, "di%d", i); - _do_group(nv, group); - } + //char group[GROUP_LEN]; + //for (uint8_t i=1; i < D_IN_CAN_CHANNELS+D_IN_CHANNELS+1; i++) { + //sprintf(group, "di%d", i); + //_do_group(nv, group); + //} return (STAT_COMPLETE); // STAT_COMPLETE suppresses the normal response line } static stat_t _do_outputs(nvObj_t *nv) // print parameters for all output groups { char group[GROUP_LEN]; - for (uint8_t i=1; i < D_OUT_CHANNELS+D_OUT_CAN_CHANNELS+1; i++) { + for (uint8_t i=1; i < D_OUT_CHANNELS+1; i++) { sprintf(group, "do%d", i); _do_group(nv, group); } diff --git a/g2core/controller.cpp b/g2core/controller.cpp index b33f128c..13060cab 100644 --- a/g2core/controller.cpp +++ b/g2core/controller.cpp @@ -297,7 +297,7 @@ static void _dispatch_kernel(const devflags_t flags) nv_copy_string(nv, cs.bufp); // copy the Gcode line nv->valuetype = TYPE_STRING; status = gcode_parser(cs.bufp); - + #if MARLIN_COMPAT_ENABLED == true if (js.json_mode == MARLIN_COMM_MODE) { // in case a marlin-specific M-code was found cs.comm_request_mode = MARLIN_COMM_MODE; // mode of this command @@ -337,7 +337,7 @@ static stat_t _controller_state() { if (cs.controller_state == CONTROLLER_CONNECTED) { // first time through after reset cs.controller_state = CONTROLLER_STARTUP; - + // This is here just to put a small delay in before the startup message. #if MARLIN_COMPAT_ENABLED == true // For Marlin compatibility, we need this to be long enough for the UI to say something and reveal @@ -501,25 +501,19 @@ static stat_t _limit_switch_handler(void) static stat_t _interlock_handler(void) { if (cm.safety_interlock_enable) { - // interlock broken - if (cm.safety_interlock_disengaged != 0) { - cm.safety_interlock_disengaged = 0; - cm.safety_interlock_state = SAFETY_INTERLOCK_DISENGAGED; - cm_request_feedhold(); // may have already requested STOP as INPUT_ACTION - // feedhold was initiated by input action in gpio - // pause spindle - // pause coolant - } - - // interlock restored - if ((cm.safety_interlock_reengaged != 0) && (mp_runtime_is_idle())) { - cm.safety_interlock_reengaged = 0; - cm.safety_interlock_state = SAFETY_INTERLOCK_ENGAGED; // interlock restored - // restart spindle with dwell - cm_request_end_hold(); // use cm_request_end_hold() instead of just ending - // restart coolant - } + if (cm.saftey_interlock_list.iterateOver([&](bool *check){ return *check; })) { + cm.safety_interlock_state = SAFETY_INTERLOCK_DISENGAGED; // Interlock broken + cm_request_feedhold(); // may have already requested STOP as INPUT_ACTION + // TODO pause spindle + // TODO pause coolant + } else { + cm.safety_interlock_state = SAFETY_INTERLOCK_ENGAGED; // Interlock restored + // TODO restart spindle with dwell + cm_request_end_hold(); // use cm_request_end_hold() instead of just ending + // TODO restart coolant + } } + return(STAT_OK); } @@ -555,5 +549,3 @@ stat_t _test_system_assertions() xio_test_assertions(); return (STAT_OK); } - - diff --git a/g2core/g2core.cppproj b/g2core/g2core.cppproj index 9842edf3..39f34ae6 100644 --- a/g2core/g2core.cppproj +++ b/g2core/g2core.cppproj @@ -21,7 +21,8 @@ exception_table 1 3.5.0 - SWD + + com.atmel.avrdbg.tool.atmelice com.atmel.avrdbg.tool.samice @@ -56,7 +57,7 @@ - + @@ -117,6 +118,8 @@ False + 0 + @@ -1520,6 +1523,72 @@ Makefile bin\TestQuadratic\ + + + + True + True + True + True + True + + + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\CMSIS\Include + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\Device\ATMEL + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\Device\ATMEL\sam3xa\include + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\CMSIS\Include + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL\sam3xa\include + + + Optimize (-O1) + True + Maximum (-g3) + True + + + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\CMSIS\Include + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\Device\ATMEL + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\Device\ATMEL\sam3xa\include + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\CMSIS\Include + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL\sam3xa\include + + + Optimize (-O1) + True + Maximum (-g3) + True + + + libm + + + True + -Tsam3x8c_flash.ld + Default (-g) + + + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\CMSIS\Include + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL\sam3xa\include + + + Default (-Wa,-g) + + + True + CONFIG=geratech COLOR=0 VERBOSE=1 + clean CONFIG=geratech + Makefile + + bin\GeratechProto\ + compile @@ -1596,6 +1665,216 @@ compile + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + compile @@ -1692,6 +1971,12 @@ compile + + compile + + + compile + compile @@ -1707,6 +1992,12 @@ compile + + compile + + + compile + compile @@ -1719,6 +2010,12 @@ compile + + compile + + + compile + compile @@ -1929,6 +2226,12 @@ + + + + + + @@ -1970,6 +2273,39 @@ compile + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + compile diff --git a/g2core/gpio.cpp b/g2core/gpio.cpp index 241cf2cd..4a42d6e4 100644 --- a/g2core/gpio.cpp +++ b/g2core/gpio.cpp @@ -40,355 +40,184 @@ * and lockout subsequent interrupts for the defined lockout period. Ditto on the method. */ +#ifndef _GPIO_C_GUARD_ +#define _GPIO_C_GUARD_ + #include "g2core.h" // #1 #include "config.h" // #2 -#include "gpio.h" #include "stepper.h" #include "encoder.h" #include "hardware.h" #include "canonical_machine.h" -#include "can_bus.h" #include "text_parser.h" #include "controller.h" #include "util.h" #include "report.h" #include "xio.h" - #include "MotateTimers.h" -using namespace Motate; - -/**** Allocate structures ****/ - -d_in_t d_in [D_IN_CHANNELS + D_IN_CAN_CHANNELS]; -d_out_t d_out [D_OUT_CHANNELS + D_OUT_CAN_CHANNELS]; -a_in_t a_in [A_IN_CHANNELS + A_IN_CAN_CHANNELS]; -a_out_t a_out [A_OUT_CHANNELS + A_OUT_CAN_CHANNELS]; - -/**** Extended DI structure ****/ - -// To be merged with ioDigitalInput later. -// For now, we use a pointer to the correct d_in, since the old code did. -// input_pin_num is the Motate pin number. -// ext_pin_number is the JSON ("external") pin number, as in "di1". -template -struct ioDigitalInputExt { - IRQPin input_pin; - - /* Priority only needs set once in the system during startup. - * However, if we wish to switch the interrupt trigger, here are other options: - * kPinInterruptOnRisingEdge - * kPinInterruptOnFallingEdge - * - * To change the trigger or priority provide a third paramater intValue that will - * be called as pin.setInterrupts(intValue), or call pin.setInterrupts at any point. - * Note that it may cause an interrupt to fire *immediately*! - * intValue defaults to kPinInterruptOnChange|kPinInterruptPriorityMedium if not specified. - */ - ioDigitalInputExt() : input_pin {kPullUp|kDebounce, [&]{this->pin_changed();}} { - }; - - ioDigitalInputExt(const ioDigitalInputExt&) = delete; // delete copy - ioDigitalInputExt(ioDigitalInputExt&&) = delete; // delete move - - void reset() { - if (D_IN_CHANNELS < ext_pin_number) { return; } - - d_in_t *in = &d_in[ext_pin_number-1]; - - if (in->mode == IO_MODE_DISABLED) { - in->state = INPUT_DISABLED; - return; - } - - bool pin_value = (bool)input_pin; - int8_t pin_value_corrected = (pin_value ^ ((int)in->mode ^ 1)); // correct for NO or NC mode - in->state = (ioState)pin_value_corrected; - } +#include "dynamic_registry.h" +#include "gpio.h" - void pin_changed() { - if (D_IN_CHANNELS < ext_pin_number) { return; } +using namespace Motate; - d_in_t *in = &d_in[ext_pin_number-1]; +DynamicRegistry digitalInputs; +d_out_t d_out[D_OUT_CHANNELS]; +a_in_t a_in[A_IN_CHANNELS]; +a_out_t a_out[A_OUT_CHANNELS]; - // return if input is disabled (not supposed to happen) - if (in->mode == IO_MODE_DISABLED) { - in->state = INPUT_DISABLED; - return; - } +void ioDigitalInput::reset() { + if (mode == IO_MODE_DISABLED) { + state = INPUT_DISABLED; + return; + } + + this->lockout_timer.clear(); +} - // return if the input is in lockout period (take no action) - if (in->lockout_timer.isSet() && !in->lockout_timer.isPast()) { - return; - } +void ioDigitalInput::updateValue(bool value) { + // return if input is disabled (not supposed to happen) + if (mode == IO_MODE_DISABLED) { + state = INPUT_DISABLED; + return; + } - // return if no change in state - bool pin_value = (bool)input_pin; - int8_t pin_value_corrected = (pin_value ^ ((int)in->mode ^ 1)); // correct for NO or NC mode - if (in->state == (ioState)pin_value_corrected) { - return; - } + // return if the input is in lockout period (take no action) + if (lockout_timer.isSet() && !lockout_timer.isPast()) { + return; + } - // lockout the pin for lockout_ms - in->lockout_timer.set(in->lockout_ms); + int8_t value_corrected = (value ^ ((int)mode ^ 1)); // correct for NO or NC mode + if (state == (ioState)value_corrected) { + return; + } - // record the changed state - in->state = (ioState)pin_value_corrected; - if (pin_value_corrected == INPUT_ACTIVE) { - in->edge = INPUT_EDGE_LEADING; - } else { - in->edge = INPUT_EDGE_TRAILING; - } + // lockout the pin for lockout_ms + lockout_timer.set(lockout_ms); - // perform homing operations if in homing mode - if (in->homing_mode) { - if (in->edge == INPUT_EDGE_LEADING) { // we only want the leading edge to fire - en_take_encoder_snapshot(); - cm_start_hold(); - } - return; - } + // record the changed state + state = (ioState)value_corrected; + if (value_corrected == INPUT_ACTIVE) { + edge = INPUT_EDGE_LEADING; + } else { + edge = INPUT_EDGE_TRAILING; + } - // perform probing operations if in probing mode - if (in->probing_mode) { - // We want to capture either way. - // Probing tests the start condition for the correct direction ahead of time. - // If we see any edge, it's the right one. - en_take_encoder_snapshot(); - cm_start_hold(); - return; - } + // perform homing operations if in homing mode + if (homing_mode) { + if (edge == INPUT_EDGE_LEADING) { // we only want the leading edge to fire + en_take_encoder_snapshot(); + cm_start_hold(); + } + return; + } - // *** NOTE: From this point on all conditionals assume we are NOT in homing or probe mode *** - - // trigger the action on leading edges - if (in->edge == INPUT_EDGE_LEADING) { - if (in->action == INPUT_ACTION_STOP) { - cm_start_hold(); - } - if (in->action == INPUT_ACTION_FAST_STOP) { - cm_start_hold(); // for now is same as STOP - } - if (in->action == INPUT_ACTION_HALT) { - cm_halt_all(); // hard stop, including spindle and coolant - } - if (in->action == INPUT_ACTION_ALARM) { - char msg[10]; - sprintf(msg, "input %d", ext_pin_number); - cm_alarm(STAT_ALARM, msg); - } - if (in->action == INPUT_ACTION_SHUTDOWN) { - char msg[10]; - sprintf(msg, "input %d", ext_pin_number); - cm_shutdown(STAT_SHUTDOWN, msg); - } - if (in->action == INPUT_ACTION_PANIC) { - char msg[10]; - sprintf(msg, "input %d", ext_pin_number); - cm_panic(STAT_PANIC, msg); - } - if (in->action == INPUT_ACTION_RESET) { - hw_hard_reset(); - } - } + // perform probing operations if in probing mode + if (probing_mode) { + // We want to capture either way. + // Probing tests the start condition for the correct direction ahead of time. + // If we see any edge, it's the right one. + en_take_encoder_snapshot(); + cm_start_hold(); + return; + } - // these functions trigger on the leading edge - if (in->edge == INPUT_EDGE_LEADING) { - if (in->function == INPUT_FUNCTION_LIMIT) { - cm.limit_requested = ext_pin_number; + // *** NOTE: From this point on all conditionals assume we are NOT in homing or probe mode *** - } else if (in->function == INPUT_FUNCTION_SHUTDOWN) { - cm.shutdown_requested = ext_pin_number; + // trigger the action on leading edges + if (edge == INPUT_EDGE_LEADING) { + if (action == INPUT_ACTION_STOP) { + cm_start_hold(); + } + if (action == INPUT_ACTION_FAST_STOP) { + cm_start_hold(); // for now is same as STOP + } + if (action == INPUT_ACTION_HALT) { + cm_halt_all(); // hard stop, including spindle and coolant + } + if (action == INPUT_ACTION_ALARM) { + char msg[10]; + sprintf(msg, "input %d", this->external_pin_num); + cm_alarm(STAT_ALARM, msg); + } + if (action == INPUT_ACTION_SHUTDOWN) { + char msg[10]; + sprintf(msg, "input %d", this->external_pin_num); + cm_shutdown(STAT_SHUTDOWN, msg); + } + if (action == INPUT_ACTION_PANIC) { + char msg[10]; + sprintf(msg, "input %d", this->external_pin_num); + cm_panic(STAT_PANIC, msg); + } + if (action == INPUT_ACTION_RESET) { + hw_hard_reset(); + } + } - } else if (in->function == INPUT_FUNCTION_INTERLOCK) { - cm.safety_interlock_disengaged = ext_pin_number; - } - } + // these functions trigger on the leading edge + if (edge == INPUT_EDGE_LEADING) { + if (function == INPUT_FUNCTION_LIMIT) { + cm.limit_requested = this->external_pin_num; - // trigger interlock release on trailing edge - if (in->edge == INPUT_EDGE_TRAILING) { - if (in->function == INPUT_FUNCTION_INTERLOCK) { - cm.safety_interlock_reengaged = ext_pin_number; - } - } + } else if (function == INPUT_FUNCTION_SHUTDOWN) { + cm.shutdown_requested = this->external_pin_num; - sr_request_status_report(SR_REQUEST_TIMED); //+++++ Put this one back in. - }; -}; + } else if (function == INPUT_FUNCTION_INTERLOCK) { + cm.saftey_interlock_list.addEntry(&this->safteyInterlockEntry); + } + } -struct ioDigitalInputVirtual { - uint8_t ext_pin_number = D_IN_CHANNELS; + // trigger interlock release on trailing edge + if (edge == INPUT_EDGE_TRAILING) { + if (function == INPUT_FUNCTION_INTERLOCK) { + cm.saftey_interlock_list.removeEntry(&this->safteyInterlockEntry); + } + } - bool reset() { - if (D_IN_CAN_CHANNELS+D_IN_CHANNELS < ext_pin_number) { return false; } + sr_request_status_report(SR_REQUEST_TIMED); //+++++ Put this one back in. +} - d_in_t *in = &d_in[ext_pin_number-1]; +template +class ioDigitalInputExt : public ioDigitalInput { +public: + ioDigitalInputExt(ioMode _mode = 0, inputAction _action = 0, inputFunc _function = 0, uint16_t _lockout_ms = INPUT_LOCKOUT_MS) : ioDigitalInput (_mode, _action, _function, _lockout_ms) { + + } + + IRQPin input_pin; - if (in->mode == IO_MODE_DISABLED) { - in->state = INPUT_DISABLED; - return false; - } + /* Priority only needs set once in the system during startup. + * However, if we wish to switch the interrupt trigger, here are other options: + * kPinInterruptOnRisingEdge + * kPinInterruptOnFallingEdge + * + * To change the trigger or priority provide a third parameter intValue that will + * be called as pin.setInterrupts(intValue), or call pin.setInterrupts at any point. + * Note that it may cause an interrupt to fire *immediately*! + * intValue defaults to kPinInterruptOnChange|kPinInterruptPriorityMedium if not specified. + */ + + ioDigitalInputExt() : input_pin {kPullUp|kDebounce, [&]{this->updatePin();}} {}; - // bool pin_value = (bool)input_pin; - // int8_t pin_value_corrected = (pin_value ^ ((int)in->mode ^ 1)); // correct for NO or NC mode - in->state = INPUT_INACTIVE; - return true; + ioDigitalInputExt(const ioDigitalInputExt&) = delete; // delete copy + ioDigitalInputExt(ioDigitalInputExt&&) = delete; // delete move + + Motate::SysTickEvent polling_check {[&] { + updateValue((bool)input_pin); + }, nullptr}; + + inline void reset() override { + SysTickTimer.unregisterEvent(this->polling_check); + ioDigitalInput::reset(); + updateValue((bool)input_pin); + SysTickTimer.registerEvent(this->polling_check); } - - void reset_with_value (bool pin_value) { - if (reset()) return; - d_in_t *in = &d_in[ext_pin_number-1]; - int8_t pin_value_corrected = (pin_value ^ ((int)in->mode ^ 1)); // correct for NO or NC mode - in->state = (ioState)pin_value_corrected; + + inline void updatePin() { + updateValue((bool)input_pin); } - - void pin_changed(bool pin_value) { - // xio_writeline("pin_changed\n"); - if (D_IN_CAN_CHANNELS+D_IN_CHANNELS < ext_pin_number) { return; } - // xio_writeline("in_range\n"); - d_in_t *in = &d_in[ext_pin_number-1]; - - // return if input is disabled (not supposed to happen) - if (in->mode == IO_MODE_DISABLED) { - in->state = INPUT_DISABLED; - return; - } - // xio_writeline("input_enabled\n"); - // return if the input is in lockout period (take no action) - if (in->lockout_timer.isSet() && !in->lockout_timer.isPast()) { - return; - } - // xio_writeline("no_lockout\n"); - // return if no change in state - int8_t pin_value_corrected = (pin_value ^ ((int)in->mode ^ 1)); // correct for NO or NC mode - // printf("new_pin_value: %i\n", pin_value); - // printf("new_pin_state: %i\n", pin_value_corrected); - if (in->state == (ioState)pin_value_corrected) { - return; - } - //xio_writeline("input_different_to_last_state"); - // lockout the pin for lockout_ms - in->lockout_timer.set(in->lockout_ms); - - // record the changed state - in->state = (ioState)pin_value_corrected; - if (pin_value_corrected == INPUT_ACTIVE) { - in->edge = INPUT_EDGE_LEADING; - } else { - in->edge = INPUT_EDGE_TRAILING; - } - - - // perform homing operations if in homing mode - if (in->homing_mode) { - if (in->edge == INPUT_EDGE_LEADING) { // we only want the leading edge to fire - en_take_encoder_snapshot(); - cm_start_hold(); - } - return; - } - - // perform probing operations if in probing mode - if (in->probing_mode) { - // We want to capture either way. - // Probing tests the start condition for the correct direction ahead of time. - // If we see any edge, it's the right one. - en_take_encoder_snapshot(); - cm_start_hold(); - return; - } - - // *** NOTE: From this point on all conditionals assume we are NOT in homing or probe mode *** - - // trigger the action on leading edges - if (in->edge == INPUT_EDGE_LEADING) { - if (in->action == INPUT_ACTION_STOP) { - cm_start_hold(); - } - if (in->action == INPUT_ACTION_FAST_STOP) { - cm_start_hold(); // for now is same as STOP - } - if (in->action == INPUT_ACTION_HALT) { - cm_halt_all(); // hard stop, including spindle and coolant - } - if (in->action == INPUT_ACTION_ALARM) { - char msg[10]; - sprintf(msg, "input %d", ext_pin_number); - cm_alarm(STAT_ALARM, msg); - } - if (in->action == INPUT_ACTION_SHUTDOWN) { - char msg[10]; - sprintf(msg, "input %d", ext_pin_number); - cm_shutdown(STAT_SHUTDOWN, msg); - } - if (in->action == INPUT_ACTION_PANIC) { - char msg[10]; - sprintf(msg, "input %d", ext_pin_number); - cm_panic(STAT_PANIC, msg); - } - if (in->action == INPUT_ACTION_RESET) { - hw_hard_reset(); - } - } - - // these functions trigger on the leading edge - if (in->edge == INPUT_EDGE_LEADING) { - if (in->function == INPUT_FUNCTION_LIMIT) { - cm.limit_requested = ext_pin_number; - - } else if (in->function == INPUT_FUNCTION_SHUTDOWN) { - cm.shutdown_requested = ext_pin_number; - - } else if (in->function == INPUT_FUNCTION_INTERLOCK) { - cm.safety_interlock_disengaged = ext_pin_number; - } - } - - // trigger interlock release on trailing edge - if (in->edge == INPUT_EDGE_TRAILING) { - if (in->function == INPUT_FUNCTION_INTERLOCK) { - cm.safety_interlock_reengaged = ext_pin_number; - } - } - - sr_request_status_report(SR_REQUEST_TIMED); //+++++ Put this one back in. - }; }; -/**** Setup Low Level Stuff ****/ - -ioDigitalInputExt _din1; -ioDigitalInputExt _din2; -ioDigitalInputExt _din3; -ioDigitalInputExt _din4; -ioDigitalInputExt _din5; -ioDigitalInputExt _din6; -ioDigitalInputExt _din7; -ioDigitalInputExt _din8; -ioDigitalInputExt _din9; -ioDigitalInputExt _din10; -ioDigitalInputExt _din11; -ioDigitalInputExt _din12; - -#ifdef CAN_ENABLED -//Generated with -//perl -e 'for($i=1;$i<13;$i++) { print "#if D_IN_CAN_CHANNELS >= ${i}\nioDigitalInputVirtual<${i}> _vdin${i};\n#endif\n";}' - -ioDigitalInputVirtual _vdin[D_IN_CAN_CHANNELS]; - -void can_gpio_received (int pin_num, uint8_t length, uint8_t* data) { - //printf("pin: %i\n value: %i\n", pin_num, data[0]); - - if (pin_num >= D_IN_CAN_CHANNELS) return; - - bool pin_value=false; - - if (data[0] > 0) pin_value=true; - printf("%i/n", pin_num); - _vdin[pin_num].pin_changed(pin_value); -} - -#endif - // Generated with: // perl -e 'for($i=1;$i<14;$i++) { print "#if OUTPUT${i}_PWM == 1\nstatic PWMOutputPin output_${i}_pin;\n#else\nstatic PWMLikeOutputPin output_${i}_pin;\n#endif\n";}' // BEGIN generated @@ -489,10 +318,6 @@ void gpio_init(void) output_13_pin.setFrequency(200000); // END generated - for (int i=0;i= 13 if (d_out[13-1].mode != IO_MODE_DISABLED) { (output_13_pin = (d_out[13-1].mode == IO_ACTIVE_LOW) ? 1.0 : 0.0); } #endif - - //Can reset -#ifdef CAN_ENABLED - for (int i=D_OUT_CHANNELS; i< D_OUT_CHANNELS+D_OUT_CAN_CHANNELS-1; i++){ - if (d_out[i].mode != IO_MODE_DISABLED) { - can_digital_output(i, ((d_out[13-1].mode == IO_ACTIVE_LOW) ? true : false)); - } - } -#endif } void inputs_reset(void) { - d_in_t *in; - - for (uint8_t i=0; imode == IO_MODE_DISABLED) { - in->state = INPUT_DISABLED; - continue; - } - in->lockout_ms = INPUT_LOCKOUT_MS; - in->lockout_timer.clear(); - } - - _din1.reset(); - _din2.reset(); - _din3.reset(); - _din4.reset(); - _din5.reset(); - _din6.reset(); - _din7.reset(); - _din8.reset(); - _din9.reset(); - _din10.reset(); - _din11.reset(); - _din12.reset(); - - for (int i=0;ireset(); + return false; + }); } void gpio_reset(void) @@ -612,10 +406,18 @@ void gpio_reset(void) */ void gpio_set_homing_mode(const uint8_t input_num_ext, const bool is_homing) { - if (input_num_ext == 0) { - return; - } - d_in[input_num_ext-1].homing_mode = is_homing; + if (input_num_ext == 0) { + return; + } + + digitalInputs.iterateOver([&](ioDigitalInput *input){ + if (input->external_pin_num == input_num_ext) { + input->homing_mode = is_homing; + return true; + } + + return false; + }); } void gpio_set_probing_mode(const uint8_t input_num_ext, const bool is_probing) @@ -623,27 +425,41 @@ void gpio_set_probing_mode(const uint8_t input_num_ext, const bool is_probing) if (input_num_ext == 0) { return; } - d_in[input_num_ext-1].probing_mode = is_probing; + + digitalInputs.iterateOver([&](ioDigitalInput *input){ + if (input->external_pin_num == input_num_ext) { + input->probing_mode = is_probing; + return true; + } else return false; + }); } int8_t gpio_get_probing_input(void) { - //inputs_reset(); - - for (uint8_t i = 0; i <= D_IN_CHANNELS+D_IN_CAN_CHANNELS; i++) { - if (d_in[i-1].function == INPUT_FUNCTION_PROBE) { - return (i); - } - } - return (-1); + int8_t probingInput = -1; + digitalInputs.iterateOver([&](ioDigitalInput *input){ + if (input->function == INPUT_FUNCTION_PROBE) { + probingInput = input->external_pin_num; + return true; + } else return false; + }); + return probingInput; } -bool gpio_read_input(const uint8_t input_num_ext) +bool gpio_read_input(uint8_t input_num_ext) { - if (input_num_ext == 0) { - return false; - } - return (d_in[input_num_ext-1].state); + if (input_num_ext == 0) { + return false; + } + + bool inputValue; + digitalInputs.iterateOver([&](ioDigitalInput *input){ + if (input->external_pin_num == input_num_ext) { + inputValue = input->state; + return true; + } else return false; + }); + return input_num_ext; } @@ -704,7 +520,19 @@ stat_t io_get_input(nvObj_t *nv) // skip over "in" num_start+=2; } - nv->value = d_in[strtol(num_start, NULL, 10)-1].state; + + ioState inputState; + uint8_t pinNum = strtol(num_start, NULL, 10); + if (!digitalInputs.iterateOver([&](ioDigitalInput *input){ + if (input->external_pin_num == pinNum) { + inputState = input->state; + return true; + } + + return false; + })) return (STAT_INPUT_VALUE_RANGE_ERROR); + + nv->value = inputState; if (nv->value > 1.1) { nv->valuetype = TYPE_NULL; @@ -725,7 +553,7 @@ stat_t io_set_domode(nvObj_t *nv) // output function // the token has been stripped down to an ASCII digit string - use it as an index uint8_t output_num = strtol(num_start, NULL, 10); - if (output_num > D_OUT_CHANNELS+D_OUT_CAN_CHANNELS) { + if (output_num > D_OUT_CHANNELS) { nv->valuetype = TYPE_NULL; return(STAT_NO_GPIO); } // Force pins that aren't available to be "disabled" @@ -767,7 +595,7 @@ stat_t io_get_output(nvObj_t *nv) // the token has been stripped down to an ASCII digit string - use it as an index uint8_t output_num = strtol(num_start, NULL, 10); - if (output_num > D_OUT_CHANNELS + D_OUT_CAN_CHANNELS) { + if (output_num > D_OUT_CHANNELS) { nv->valuetype = TYPE_NULL; return(STAT_NO_GPIO); } @@ -905,3 +733,5 @@ stat_t io_set_output(nvObj_t *nv) xio_writeline(cs.out_buf); } #endif + +#endif // End Guard \ No newline at end of file diff --git a/g2core/gpio.h b/g2core/gpio.h index e51194b6..88ff5166 100644 --- a/g2core/gpio.h +++ b/g2core/gpio.h @@ -1,142 +1,151 @@ /* - * gpio.h - Digital IO handling functions - * This file is part of the g2core project - * - * Copyright (c) 2015 - 2017 Alden S. Hart, Jr. - * Copyright (c) 2015 - 2017 Robert Giseburt - * - * This file ("the software") is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2 as published by the - * Free Software Foundation. You should have received a copy of the GNU General Public - * License, version 2 along with the software. If not, see . - * - * As a special exception, you may use this file as part of a software library without - * restriction. Specifically, if other files instantiate templates or use macros or - * inline functions from this file, or you compile this file and link it with other - * files to produce an executable, this file does not by itself cause the resulting - * executable to be covered by the GNU General Public License. This exception does not - * however invalidate any other reasons why the executable file might be covered by the - * GNU General Public License. - * - * THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY - * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT - * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ +* gpio.h - Digital IO handling functions +* This file is part of the g2core project +* +* Copyright (c) 2015 - 2017 Alden S. Hart, Jr. +* Copyright (c) 2015 - 2017 Robert Giseburt +* +* This file ("the software") is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License, version 2 as published by the +* Free Software Foundation. You should have received a copy of the GNU General Public +* License, version 2 along with the software. If not, see . +* +* As a special exception, you may use this file as part of a software library without +* restriction. Specifically, if other files instantiate templates or use macros or +* inline functions from this file, or you compile this file and link it with other +* files to produce an executable, this file does not by itself cause the resulting +* executable to be covered by the GNU General Public License. This exception does not +* however invalidate any other reasons why the executable file might be covered by the +* GNU General Public License. +* +* THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY +* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ #ifndef GPIO_H_ONCE #define GPIO_H_ONCE -/* - * GPIO defines - */ -//--- change as required for board and switch hardware ---// - -#define D_IN_CHANNELS 8 // number of digital inputs supported -#define D_OUT_CHANNELS 9 // number of digital outputs supported -#define A_IN_CHANNELS 0 // number of analog inputs supported -#define A_OUT_CHANNELS 0 // number of analog outputs supported - -// #ifndef D_IN_CAN_CHANNELS -#define D_IN_CAN_CHANNELS 2 -// #endif -#ifndef D_OUT_CAN_CHANNELS -#define D_OUT_CAN_CHANNELS 0 -#endif -#ifndef A_IN_CAN_CHANNELS -#define A_IN_CAN_CHANNELS 0 -#endif -#ifndef A_OUT_CAN_CHANNELS -#define A_OUT_CAN_CHANNELS 0 -#endif - -//#define INPUT_LOCKOUT_MS 50 // milliseconds to go dead after input firing -#define INPUT_LOCKOUT_MS 10 // milliseconds to go dead after input firing +#include "dynamic_registry.h" +#define INPUT_LOCKOUT_MS 10 // milliseconds to go dead after input firing +#define D_OUT_CHANNELS 9 +#define A_IN_CHANNELS 0 +#define A_OUT_CHANNELS 0 //--- do not change from here down ---// typedef enum { - IO_ACTIVE_LOW = 0, // input is active low (aka normally open) - IO_ACTIVE_HIGH = 1, // input is active high (aka normally closed) - IO_MODE_DISABLED = 2, // input is disabled - IO_MODE_MAX // unused. Just for range checking + IO_ACTIVE_LOW = 0, // input is active low (aka normally open) + IO_ACTIVE_HIGH = 1, // input is active high (aka normally closed) + IO_MODE_DISABLED = 2, // input is disabled + IO_MODE_MAX // unused. Just for range checking } ioMode; #define NORMALLY_OPEN IO_ACTIVE_LOW // equivalent #define NORMALLY_CLOSED IO_ACTIVE_HIGH // equivalent typedef enum { // actions are initiated from within the input's ISR - INPUT_ACTION_NONE = 0, - INPUT_ACTION_STOP, // stop at normal jerk - preserves positional accuracy - INPUT_ACTION_FAST_STOP, // stop at high jerk - preserves positional accuracy - INPUT_ACTION_HALT, // stop immediately - not guaranteed to preserve position - INPUT_ACTION_CYCLE_START, // start / restart cycle after feedhold (RESERVED) - INPUT_ACTION_ALARM, // initiate an alarm. stops everything immediately - preserves position - INPUT_ACTION_SHUTDOWN, // initiate a shutdown. stops everything immediately - does not preserve position - INPUT_ACTION_PANIC, // initiate a panic. stops everything immediately - does not preserve position - INPUT_ACTION_RESET, // reset system - INPUT_ACTION_MAX // unused. Just for range checking + INPUT_ACTION_NONE = 0, + INPUT_ACTION_STOP, // stop at normal jerk - preserves positional accuracy + INPUT_ACTION_FAST_STOP, // stop at high jerk - preserves positional accuracy + INPUT_ACTION_HALT, // stop immediately - not guaranteed to preserve position + INPUT_ACTION_CYCLE_START, // start / restart cycle after feedhold (RESERVED) + INPUT_ACTION_ALARM, // initiate an alarm. stops everything immediately - preserves position + INPUT_ACTION_SHUTDOWN, // initiate a shutdown. stops everything immediately - does not preserve position + INPUT_ACTION_PANIC, // initiate a panic. stops everything immediately - does not preserve position + INPUT_ACTION_RESET, // reset system + INPUT_ACTION_MAX // unused. Just for range checking } inputAction; typedef enum { // functions are requested from the ISR, run from the main loop - INPUT_FUNCTION_NONE = 0, - INPUT_FUNCTION_LIMIT = 1, // limit switch processing - INPUT_FUNCTION_INTERLOCK = 2, // interlock processing - INPUT_FUNCTION_SHUTDOWN = 3, // shutdown in support of external emergency stop - INPUT_FUNCTION_PROBE = 4, // assign input as probe input - INPUT_FUNCTION_MAX // unused. Just for range checking + INPUT_FUNCTION_NONE = 0, + INPUT_FUNCTION_LIMIT = 1, // limit switch processing + INPUT_FUNCTION_INTERLOCK = 2, // interlock processing + INPUT_FUNCTION_SHUTDOWN = 3, // shutdown in support of external emergency stop + INPUT_FUNCTION_PROBE = 4, // assign input as probe input + INPUT_FUNCTION_TOOL_HEIGHT_SETTER = 5, + INPUT_FUNCTION_MAX // unused. Just for range checking } inputFunc; typedef enum { - INPUT_INACTIVE = 0, // aka switch open, also read as 'false' - INPUT_ACTIVE = 1, // aka switch closed, also read as 'true' - INPUT_DISABLED = 2 // value returned if input is disabled + INPUT_INACTIVE = 0, // aka switch open, also read as 'false' + INPUT_ACTIVE = 1, // aka switch closed, also read as 'true' + INPUT_DISABLED = 2 // value returned if input is disabled } ioState; typedef enum { - INPUT_EDGE_NONE = 0, // no edge detected or edge flag reset (must be zero) - INPUT_EDGE_LEADING, // flag is set when leading edge is detected - INPUT_EDGE_TRAILING // flag is set when trailing edge is detected + INPUT_EDGE_NONE = 0, // no edge detected or edge flag reset (must be zero) + INPUT_EDGE_LEADING, // flag is set when leading edge is detected + INPUT_EDGE_TRAILING // flag is set when trailing edge is detected } inputEdgeFlag; /* - * GPIO structures - */ -typedef struct ioDigitalInput { // one struct per digital input - ioMode mode; // -1=disabled, 0=active low (NO), 1= active high (NC) - inputAction action; // 0=none, 1=stop, 2=halt, 3=stop_steps, 4=reset - inputFunc function; // function to perform when activated / deactivated - ioState state; // input state 0=inactive, 1=active, -1=disabled - inputEdgeFlag edge; // keeps a transient record of edges for immediate inquiry - bool homing_mode; // set true when input is in homing mode. - bool probing_mode; // set true when input is in probing mode. - uint16_t lockout_ms; // number of milliseconds for debounce lockout - Motate::Timeout lockout_timer; // time to expire current debounce lockout, or 0 if no lockout -} d_in_t; +* GPIO structures +*/ + +class ioDigitalInput { // one struct per digital input +public: + ioState state; // input state 0=inactive, 1=active, -1=disabled + inputEdgeFlag edge; // keeps a transient record of edges for immediate inquiry + bool homing_mode; // set true when input is in homing mode. + bool probing_mode; // set true when input is in probing mode. + Motate::Timeout lockout_timer; // time to expire current debounce lockout, or 0 if no lockout + + bool trueBool = true; + DynamicRegistry::EntryType safteyInterlockEntry = {&trueBool, nullptr}; + + uint16_t external_pin_num; + + void updateValue (bool inputValue); // Update the input's value + + //inputAction getAction () { return this->action; } + //void setAction (inputAction _action) { action = _action; } + //inputFunc getFunction () { return this->function;} + //void setFunction (inputFunc _function) { + //this->function = _function; + //} + + ioMode mode; // -1=disabled, 0=active low (NO), 1= active high (NC) + inputAction action; // 0=none, 1=stop, 2=halt, 3=stop_steps, 4=reset + inputFunc function; // function to perform when activated / deactivated + uint16_t lockout_ms; // number of milliseconds for debounce lockout + + void reset(void); // Reset the input + + ioDigitalInput (uint16_t _ext_pin_num, ioMode _mode = IO_MODE_DISABLED, inputAction _action = INPUT_ACTION_NONE, inputFunc _function = INPUT_FUNCTION_NONE, uint16_t _lockout_ms = INPUT_LOCKOUT_MS) { + this->mode = _mode; + this->action = _action; + this->function = _function; + this->lockout_ms = _lockout_ms; + this->external_pin_num = _ext_pin_num; + this->reset(); + } +}; + +typedef ioDigitalInput d_in_t; typedef struct gpioDigitalOutput { // one struct per digital output - ioMode mode; + ioMode mode; } d_out_t; typedef struct gpioAnalogInput { // one struct per analog input - ioMode mode; + ioMode mode; } a_in_t; typedef struct gpioAnalogOutput { // one struct per analog output - ioMode mode; + ioMode mode; } a_out_t; -extern d_in_t d_in[D_IN_CHANNELS + D_IN_CAN_CHANNELS]; -extern d_out_t d_out[D_OUT_CHANNELS + D_OUT_CAN_CHANNELS]; -extern a_in_t a_in[A_IN_CHANNELS + A_IN_CAN_CHANNELS]; -extern a_out_t a_out[A_OUT_CHANNELS + A_OUT_CAN_CHANNELS]; +extern DynamicRegistry digitalInputs; +extern d_out_t d_out[D_OUT_CHANNELS]; +extern a_in_t a_in[A_IN_CHANNELS]; +extern a_out_t a_out[A_OUT_CHANNELS]; /* - * GPIO function prototypes - */ - - void can_gpio_received (int, uint8_t, uint8_t*); +* GPIO function prototypes +*/ void gpio_init(void); void gpio_reset(void); @@ -159,20 +168,20 @@ stat_t io_get_output(nvObj_t *nv); stat_t io_set_output(nvObj_t *nv); #ifdef __TEXT_MODE - void io_print_mo(nvObj_t *nv); - void io_print_ac(nvObj_t *nv); - void io_print_fn(nvObj_t *nv); - void io_print_in(nvObj_t *nv); - void io_print_domode(nvObj_t *nv); - void io_print_out(nvObj_t *nv); +void io_print_mo(nvObj_t *nv); +void io_print_ac(nvObj_t *nv); +void io_print_fn(nvObj_t *nv); +void io_print_in(nvObj_t *nv); +void io_print_domode(nvObj_t *nv); +void io_print_out(nvObj_t *nv); #else - #define io_print_mo tx_print_stub - #define io_print_ac tx_print_stub - #define io_print_fn tx_print_stub - #define io_print_in tx_print_stub - #define io_print_st tx_print_stub - #define io_print_domode tx_print_stub - #define io_print_out tx_print_stub +#define io_print_mo tx_print_stub +#define io_print_ac tx_print_stub +#define io_print_fn tx_print_stub +#define io_print_in tx_print_stub +#define io_print_st tx_print_stub +#define io_print_domode tx_print_stub +#define io_print_out tx_print_stub #endif // __TEXT_MODE #endif // End of include guard: GPIO_H_ONCE diff --git a/g2core/main.cpp b/g2core/main.cpp index 8c276827..367eb785 100644 --- a/g2core/main.cpp +++ b/g2core/main.cpp @@ -119,6 +119,9 @@ void application_init_startup(void) spindle_init(); // should be after PWM and canonical machine inits and config_init() spindle_reset(); temperature_init(); + #ifdef CAN_ENABLED + can_init(); + #endif gpio_reset(); } diff --git a/g2core/settings/settings_geratech.h b/g2core/settings/settings_geratech.h index 2c2ffff7..df02d21b 100644 --- a/g2core/settings/settings_geratech.h +++ b/g2core/settings/settings_geratech.h @@ -204,6 +204,8 @@ //*** CAN Settings ************************************************************ //***************************************************************************** +#define CAN_NODES_EXPECTED 2 + #define CAN_GPIO_INPUT_ADDRESS_1 0xA1 #define CAN_GPIO_INPUT_ADDRESS_2 0x42 //#define D_IN_CAN_CHANNELS 0 diff --git a/g2core/xio.h b/g2core/xio.h index 6ffb0860..f119614e 100644 --- a/g2core/xio.h +++ b/g2core/xio.h @@ -168,6 +168,7 @@ extern "C" { /**** xio_flash_file - object to hold in-flash (compiled-in) "files" to run ****/ +extern bool cm_has_hold(void); struct xio_flash_file { const char * const _data; const int32_t _length;