Colin Godsey
5 years ago
committed by
GitHub
17 changed files with 859 additions and 64 deletions
@ -0,0 +1,273 @@ |
|||
/**
|
|||
* Marlin 3D Printer Firmware |
|||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|||
* |
|||
* Based on Sprinter and grbl. |
|||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
#include "../inc/MarlinConfigPre.h" |
|||
|
|||
#if ENABLED(DIRECT_STEPPING) |
|||
|
|||
#include "direct_stepping.h" |
|||
|
|||
#include "../MarlinCore.h" |
|||
|
|||
#define CHECK_PAGE(I, R) do{ \ |
|||
if (I >= sizeof(page_states) / sizeof(page_states[0])) { \ |
|||
fatal_error = true; \ |
|||
return R; \ |
|||
} \ |
|||
}while(0) |
|||
|
|||
#define CHECK_PAGE_STATE(I, R, S) do { \ |
|||
CHECK_PAGE(I, R); \ |
|||
if (page_states[I] != S) { \ |
|||
fatal_error = true; \ |
|||
return R; \ |
|||
} \ |
|||
}while(0) |
|||
|
|||
namespace DirectStepping { |
|||
|
|||
template<typename Cfg> |
|||
State SerialPageManager<Cfg>::state; |
|||
|
|||
template<typename Cfg> |
|||
volatile bool SerialPageManager<Cfg>::fatal_error; |
|||
|
|||
template<typename Cfg> |
|||
volatile PageState SerialPageManager<Cfg>::page_states[Cfg::NUM_PAGES]; |
|||
|
|||
template<typename Cfg> |
|||
volatile bool SerialPageManager<Cfg>::page_states_dirty; |
|||
|
|||
template<typename Cfg> |
|||
millis_t SerialPageManager<Cfg>::next_response; |
|||
|
|||
template<typename Cfg> |
|||
uint8_t SerialPageManager<Cfg>::pages[Cfg::NUM_PAGES][Cfg::PAGE_SIZE]; |
|||
|
|||
template<typename Cfg> |
|||
uint8_t SerialPageManager<Cfg>::checksum; |
|||
|
|||
template<typename Cfg> |
|||
typename Cfg::write_byte_idx_t SerialPageManager<Cfg>::write_byte_idx; |
|||
|
|||
template<typename Cfg> |
|||
typename Cfg::page_idx_t SerialPageManager<Cfg>::write_page_idx; |
|||
|
|||
template<typename Cfg> |
|||
typename Cfg::write_byte_idx_t SerialPageManager<Cfg>::write_page_size; |
|||
|
|||
template <typename Cfg> |
|||
void SerialPageManager<Cfg>::init() { |
|||
for (int i = 0 ; i < Cfg::NUM_PAGES ; i++) |
|||
page_states[i] = PageState::FREE; |
|||
|
|||
fatal_error = false; |
|||
next_response = 0; |
|||
state = State::NEWLINE; |
|||
|
|||
page_states_dirty = false; |
|||
|
|||
SERIAL_ECHOLNPGM("pages_ready"); |
|||
} |
|||
|
|||
template<typename Cfg> |
|||
FORCE_INLINE bool SerialPageManager<Cfg>::maybe_store_rxd_char(uint8_t c) { |
|||
switch (state) { |
|||
default: |
|||
case State::MONITOR: |
|||
switch (c) { |
|||
case '\n': |
|||
case '\r': |
|||
state = State::NEWLINE; |
|||
default: |
|||
return false; |
|||
} |
|||
case State::NEWLINE: |
|||
switch (c) { |
|||
case Cfg::CONTROL_CHAR: |
|||
state = State::ADDRESS; |
|||
return true; |
|||
case '\n': |
|||
case '\r': |
|||
state = State::NEWLINE; |
|||
return false; |
|||
default: |
|||
state = State::MONITOR; |
|||
return false; |
|||
} |
|||
case State::ADDRESS: |
|||
//TODO: 16 bit address, State::ADDRESS2
|
|||
write_page_idx = c; |
|||
write_byte_idx = 0; |
|||
checksum = 0; |
|||
|
|||
CHECK_PAGE(write_page_idx, true); |
|||
|
|||
if (page_states[write_page_idx] == PageState::FAIL) { |
|||
// Special case for fail
|
|||
state = State::UNFAIL; |
|||
return true; |
|||
} |
|||
|
|||
set_page_state(write_page_idx, PageState::WRITING); |
|||
|
|||
state = Cfg::DIRECTIONAL ? State::COLLECT : State::SIZE; |
|||
|
|||
return true; |
|||
case State::SIZE: |
|||
// Zero means full page size
|
|||
write_page_size = c; |
|||
state = State::COLLECT; |
|||
return true; |
|||
case State::COLLECT: |
|||
pages[write_page_idx][write_byte_idx++] = c; |
|||
checksum ^= c; |
|||
|
|||
// check if still collecting
|
|||
if (Cfg::PAGE_SIZE == 256) { |
|||
// special case for 8-bit, check if rolled back to 0
|
|||
if (Cfg::DIRECTIONAL || !write_page_size) { // full 256 bytes
|
|||
if (write_byte_idx) return true; |
|||
} else { |
|||
if (write_byte_idx < write_page_size) return true; |
|||
} |
|||
} else if (Cfg::DIRECTIONAL) { |
|||
if (write_byte_idx != Cfg::PAGE_SIZE) return true; |
|||
} else { |
|||
if (write_byte_idx < write_page_size) return true; |
|||
} |
|||
|
|||
state = State::CHECKSUM; |
|||
return true; |
|||
case State::CHECKSUM: { |
|||
const PageState page_state = (checksum == c) ? PageState::OK : PageState::FAIL; |
|||
set_page_state(write_page_idx, page_state); |
|||
state = State::MONITOR; |
|||
return true; |
|||
} |
|||
case State::UNFAIL: |
|||
if (c == 0) { |
|||
set_page_state(write_page_idx, PageState::FREE); |
|||
} else { |
|||
fatal_error = true; |
|||
} |
|||
state = State::MONITOR; |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
template <typename Cfg> |
|||
void SerialPageManager<Cfg>::write_responses() { |
|||
if (fatal_error) { |
|||
kill(GET_TEXT(MSG_BAD_PAGE)); |
|||
return; |
|||
} |
|||
|
|||
// Runs on a set interval also, as responses may get lost.
|
|||
if (next_response && next_response < millis()) { |
|||
page_states_dirty = true; |
|||
} |
|||
|
|||
if (!page_states_dirty) return; |
|||
|
|||
page_states_dirty = false; |
|||
next_response = millis() + Cfg::RESPONSE_INTERVAL_MS; |
|||
|
|||
SERIAL_ECHO(Cfg::CONTROL_CHAR); |
|||
constexpr int state_bits = 2; |
|||
constexpr int n_bytes = Cfg::NUM_PAGES >> state_bits; |
|||
volatile uint8_t bits_b[n_bytes] = { 0 }; |
|||
|
|||
for (page_idx_t i = 0 ; i < Cfg::NUM_PAGES ; i++) { |
|||
bits_b[i >> state_bits] |= page_states[i] << ((i * state_bits) & 0x7); |
|||
} |
|||
|
|||
uint8_t crc = 0; |
|||
for (uint8_t i = 0 ; i < n_bytes ; i++) { |
|||
crc ^= bits_b[i]; |
|||
SERIAL_ECHO(bits_b[i]); |
|||
} |
|||
|
|||
SERIAL_ECHO(crc); |
|||
SERIAL_EOL(); |
|||
} |
|||
|
|||
template <typename Cfg> |
|||
FORCE_INLINE void SerialPageManager<Cfg>::set_page_state(const page_idx_t page_idx, const PageState page_state) { |
|||
CHECK_PAGE(page_idx,); |
|||
|
|||
page_states[page_idx] = page_state; |
|||
page_states_dirty = true; |
|||
} |
|||
|
|||
template <> |
|||
FORCE_INLINE uint8_t *PageManager::get_page(const page_idx_t page_idx) { |
|||
CHECK_PAGE(page_idx, nullptr); |
|||
|
|||
return pages[page_idx]; |
|||
} |
|||
|
|||
template <> |
|||
FORCE_INLINE void PageManager::free_page(const page_idx_t page_idx) { |
|||
set_page_state(page_idx, PageState::FREE); |
|||
} |
|||
|
|||
}; |
|||
|
|||
DirectStepping::PageManager page_manager; |
|||
|
|||
const uint8_t segment_table[DirectStepping::Config::NUM_SEGMENTS][DirectStepping::Config::SEGMENT_STEPS] PROGMEM = { |
|||
|
|||
#if STEPPER_PAGE_FORMAT == SP_4x4D_128 |
|||
|
|||
{ 1, 1, 1, 1, 1, 1, 1, 0 }, // 0 = -7
|
|||
{ 1, 1, 1, 0, 1, 1, 1, 0 }, // 1 = -6
|
|||
{ 0, 1, 1, 0, 1, 0, 1, 1 }, // 2 = -5
|
|||
{ 0, 1, 0, 1, 0, 1, 0, 1 }, // 3 = -4
|
|||
{ 0, 1, 0, 0, 1, 0, 0, 1 }, // 4 = -3
|
|||
{ 0, 0, 1, 0, 0, 0, 1, 0 }, // 5 = -2
|
|||
{ 0, 0, 0, 0, 1, 0, 0, 0 }, // 6 = -1
|
|||
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // 7 = 0
|
|||
{ 0, 0, 0, 0, 1, 0, 0, 0 }, // 8 = 1
|
|||
{ 0, 0, 1, 0, 0, 0, 1, 0 }, // 9 = 2
|
|||
{ 0, 1, 0, 0, 1, 0, 0, 1 }, // 10 = 3
|
|||
{ 0, 1, 0, 1, 0, 1, 0, 1 }, // 11 = 4
|
|||
{ 0, 1, 1, 0, 1, 0, 1, 1 }, // 12 = 5
|
|||
{ 1, 1, 1, 0, 1, 1, 1, 0 }, // 13 = 6
|
|||
{ 1, 1, 1, 1, 1, 1, 1, 0 }, // 14 = 7
|
|||
{ 0 } |
|||
|
|||
#elif STEPPER_PAGE_FORMAT == SP_4x2_256 |
|||
|
|||
{ 0, 0, 0, 0 }, // 0
|
|||
{ 0, 1, 0, 0 }, // 1
|
|||
{ 1, 0, 1, 0 }, // 2
|
|||
{ 1, 1, 1, 0 }, // 3
|
|||
|
|||
#elif STEPPER_PAGE_FORMAT == SP_4x1_512 |
|||
|
|||
{0} // Uncompressed format, table not used
|
|||
|
|||
#endif |
|||
|
|||
}; |
|||
|
|||
#endif // DIRECT_STEPPING
|
@ -0,0 +1,137 @@ |
|||
/**
|
|||
* Marlin 3D Printer Firmware |
|||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|||
* |
|||
* Based on Sprinter and grbl. |
|||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
#pragma once |
|||
|
|||
#include "../inc/MarlinConfig.h" |
|||
|
|||
namespace DirectStepping { |
|||
|
|||
enum State : char { |
|||
MONITOR, NEWLINE, ADDRESS, SIZE, COLLECT, CHECKSUM, UNFAIL |
|||
}; |
|||
|
|||
enum PageState : uint8_t { |
|||
FREE, WRITING, OK, FAIL |
|||
}; |
|||
|
|||
// Static state used for stepping through direct stepping pages
|
|||
struct page_step_state_t { |
|||
// Current page
|
|||
uint8_t *page; |
|||
// Current segment
|
|||
uint16_t segment_idx; |
|||
// Current steps within segment
|
|||
uint8_t segment_steps; |
|||
// Segment delta
|
|||
xyze_uint8_t sd; |
|||
// Block delta
|
|||
xyze_int_t bd; |
|||
}; |
|||
|
|||
template<typename Cfg> |
|||
class SerialPageManager { |
|||
public: |
|||
|
|||
typedef typename Cfg::page_idx_t page_idx_t; |
|||
|
|||
static bool maybe_store_rxd_char(uint8_t c); |
|||
static void write_responses(); |
|||
|
|||
// common methods for page managers
|
|||
static void init(); |
|||
static uint8_t *get_page(const page_idx_t page_idx); |
|||
static void free_page(const page_idx_t page_idx); |
|||
|
|||
protected: |
|||
|
|||
typedef typename Cfg::write_byte_idx_t write_byte_idx_t; |
|||
|
|||
static State state; |
|||
static volatile bool fatal_error; |
|||
|
|||
static volatile PageState page_states[Cfg::NUM_PAGES]; |
|||
static volatile bool page_states_dirty; |
|||
static millis_t next_response; |
|||
|
|||
static uint8_t pages[Cfg::NUM_PAGES][Cfg::PAGE_SIZE]; |
|||
static uint8_t checksum; |
|||
static write_byte_idx_t write_byte_idx; |
|||
static page_idx_t write_page_idx; |
|||
static write_byte_idx_t write_page_size; |
|||
|
|||
static void set_page_state(const page_idx_t page_idx, const PageState page_state); |
|||
}; |
|||
|
|||
template<bool b, typename T, typename F> struct TypeSelector { typedef T type;} ; |
|||
template<typename T, typename F> struct TypeSelector<false, T, F> { typedef F type; }; |
|||
|
|||
template <int num_pages, int num_axes, int bits_segment, bool dir, int segments> |
|||
struct config_t { |
|||
static constexpr char CONTROL_CHAR = '!'; |
|||
|
|||
static constexpr int NUM_PAGES = num_pages; |
|||
static constexpr int NUM_AXES = num_axes; |
|||
static constexpr int BITS_SEGMENT = bits_segment; |
|||
static constexpr int DIRECTIONAL = dir ? 1 : 0; |
|||
static constexpr int SEGMENTS = segments; |
|||
|
|||
static constexpr int RAW = (BITS_SEGMENT == 1) ? 1 : 0; |
|||
static constexpr int NUM_SEGMENTS = 1 << BITS_SEGMENT; |
|||
static constexpr int SEGMENT_STEPS = 1 << (BITS_SEGMENT - DIRECTIONAL - RAW); |
|||
static constexpr int TOTAL_STEPS = SEGMENT_STEPS * SEGMENTS; |
|||
static constexpr int PAGE_SIZE = (NUM_AXES * BITS_SEGMENT * SEGMENTS) / 8; |
|||
|
|||
static constexpr millis_t RESPONSE_INTERVAL_MS = 50; |
|||
|
|||
typedef typename TypeSelector<(PAGE_SIZE>256), uint16_t, uint8_t>::type write_byte_idx_t; |
|||
typedef typename TypeSelector<(NUM_PAGES>256), uint16_t, uint8_t>::type page_idx_t; |
|||
}; |
|||
|
|||
template <uint8_t num_pages> |
|||
using SP_4x4D_128 = config_t<num_pages, 4, 4, true, 128>; |
|||
|
|||
template <uint8_t num_pages> |
|||
using SP_4x2_256 = config_t<num_pages, 4, 2, false, 256>; |
|||
|
|||
template <uint8_t num_pages> |
|||
using SP_4x1_512 = config_t<num_pages, 4, 1, false, 512>; |
|||
|
|||
// configured types
|
|||
typedef STEPPER_PAGE_FORMAT<STEPPER_PAGES> Config; |
|||
|
|||
template class PAGE_MANAGER<Config>; |
|||
typedef PAGE_MANAGER<Config> PageManager; |
|||
}; |
|||
|
|||
#define SP_4x4D_128 1 |
|||
//#define SP_4x4_128 2
|
|||
//#define SP_4x2D_256 3
|
|||
#define SP_4x2_256 4 |
|||
#define SP_4x1_512 5 |
|||
|
|||
typedef typename DirectStepping::Config::page_idx_t page_idx_t; |
|||
|
|||
// TODO: use config
|
|||
typedef DirectStepping::page_step_state_t page_step_state_t; |
|||
|
|||
extern const uint8_t segment_table[DirectStepping::Config::NUM_SEGMENTS][DirectStepping::Config::SEGMENT_STEPS]; |
|||
extern DirectStepping::PageManager page_manager; |
@ -0,0 +1,61 @@ |
|||
/**
|
|||
* Marlin 3D Printer Firmware |
|||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|||
* |
|||
* Based on Sprinter and grbl. |
|||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
#include "../../inc/MarlinConfig.h" |
|||
|
|||
#if ENABLED(DIRECT_STEPPING) |
|||
|
|||
#include "../../feature/direct_stepping.h" |
|||
|
|||
#include "../gcode.h" |
|||
#include "../../module/planner.h" |
|||
|
|||
/**
|
|||
* G6: Direct Stepper Move |
|||
*/ |
|||
void GcodeSuite::G6() { |
|||
// TODO: feedrate support?
|
|||
if (parser.seen('R')) |
|||
planner.last_page_step_rate = parser.value_ulong(); |
|||
|
|||
if (!DirectStepping::Config::DIRECTIONAL) { |
|||
if (parser.seen('X')) planner.last_page_dir.x = !!parser.value_byte(); |
|||
if (parser.seen('Y')) planner.last_page_dir.y = !!parser.value_byte(); |
|||
if (parser.seen('Z')) planner.last_page_dir.z = !!parser.value_byte(); |
|||
if (parser.seen('E')) planner.last_page_dir.e = !!parser.value_byte(); |
|||
} |
|||
|
|||
// No index means we just set the state
|
|||
if (!parser.seen('I')) return; |
|||
|
|||
// No speed is set, can't schedule the move
|
|||
if (!planner.last_page_step_rate) return; |
|||
|
|||
const page_idx_t page_idx = (page_idx_t) parser.value_ulong(); |
|||
|
|||
uint16_t num_steps = DirectStepping::Config::TOTAL_STEPS; |
|||
if (parser.seen('S')) num_steps = parser.value_ushort(); |
|||
|
|||
planner.buffer_page(page_idx, 0, num_steps); |
|||
reset_stepper_timeout(); |
|||
} |
|||
|
|||
#endif // DIRECT_STEPPING
|
Loading…
Reference in new issue