kopia lustrzana https://gitlab.com/markol/Teathimble_Firmware
125 wiersze
3.6 KiB
C++
125 wiersze
3.6 KiB
C++
#include "queue.h"
|
|
|
|
/// movebuffer head pointer. Points to the last move in the queue.
|
|
/// this variable is used both in and out of interrupts, but is
|
|
/// only written outside of interrupts.
|
|
uint8_t mb_head = 0;
|
|
|
|
/// movebuffer tail pointer. Points to the currently executing move
|
|
/// this variable is read/written both in and out of interrupts.
|
|
uint8_t mb_tail = 0;
|
|
|
|
/// move buffer.
|
|
/// holds move queue
|
|
/// contents are read/written both in and out of interrupts, but
|
|
/// once writing starts in interrupts on a specific slot, the
|
|
/// slot will only be modified in interrupts until the slot is
|
|
/// is no longer live.
|
|
/// The size does not need to be a power of 2 anymore!
|
|
DDA BSS movebuffer[MOVEBUFFER_SIZE];
|
|
|
|
/// check if the queue is completely full
|
|
uint8_t queue_full() {
|
|
MEMORY_BARRIER();
|
|
return MB_NEXT(mb_head) == mb_tail;
|
|
}
|
|
|
|
/// check if the queue is completely empty
|
|
uint8_t queue_empty() {
|
|
uint8_t result;
|
|
|
|
ATOMIC_START
|
|
result = (mb_tail == mb_head && movebuffer[mb_tail].live == 0);
|
|
ATOMIC_END
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
DDA *queue_current_movement() {
|
|
DDA* current;
|
|
|
|
ATOMIC_START
|
|
current = &movebuffer[mb_tail];
|
|
|
|
if ( ! current->live || current->waitfor_temp || current->nullmove)
|
|
current = NULL;
|
|
ATOMIC_END
|
|
|
|
return current;
|
|
}
|
|
|
|
/// add a move to the movebuffer
|
|
/// \note this function waits for space to be available if necessary, check queue_full() first if waiting is a problem
|
|
/// This is the only function that modifies mb_head and it always called from outside an interrupt.
|
|
void enqueue_home(TARGET *t, uint8_t endstop_check, uint8_t endstop_stop_cond) {
|
|
// don't call this function when the queue is full, but just in case, wait for a move to complete and free up the space for the passed target
|
|
/*while (queue_full())
|
|
delay_us(100);
|
|
*/
|
|
uint8_t h = MB_NEXT(mb_head);;
|
|
|
|
DDA* new_movebuffer = &(movebuffer[h]);
|
|
|
|
// Initialise queue entry to a known state. This also clears flags like
|
|
// dda->live, dda->done and dda->wait_for_temp.
|
|
new_movebuffer->allflags = 0;
|
|
|
|
if (t != NULL) {
|
|
new_movebuffer->endstop_check = endstop_check;
|
|
new_movebuffer->endstop_stop_cond = endstop_stop_cond;
|
|
}
|
|
else {
|
|
// it's a wait for temp
|
|
new_movebuffer->waitfor_temp = 1;
|
|
}
|
|
dda_create(new_movebuffer, t);
|
|
|
|
|
|
mb_head = h;
|
|
|
|
uint8_t isdead;
|
|
|
|
ATOMIC_START
|
|
isdead = (movebuffer[mb_tail].live == 0);
|
|
ATOMIC_END
|
|
|
|
if (isdead) {
|
|
timer_reset();
|
|
next_move();
|
|
// Compensate for the cli() in timer_set().
|
|
sei();
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// This is the one function called by the timer interrupt.
|
|
// It calls a few other functions, though.
|
|
// -------------------------------------------------------
|
|
/// Take a step or go to the next move.
|
|
void queue_step() {
|
|
// do our next step
|
|
DDA* current_movebuffer = &movebuffer[mb_tail];
|
|
if (current_movebuffer->live) {
|
|
|
|
dda_step(current_movebuffer);
|
|
}
|
|
// Start the next move if this one is done.
|
|
if (current_movebuffer->live == 0)
|
|
next_move();
|
|
}
|
|
|
|
// called from step timer when current move is complete
|
|
void next_move(void)
|
|
{
|
|
while ((queue_empty() == 0) && (movebuffer[mb_tail].live == 0)) {
|
|
// next item
|
|
uint8_t t = MB_NEXT(mb_tail);
|
|
DDA* current_movebuffer = &movebuffer[t];
|
|
// Tail must be set before calling timer_set(), as timer_set() reenables
|
|
// the timer interrupt, potentially exposing mb_tail to the timer
|
|
// interrupt routine.
|
|
mb_tail = t;
|
|
dda_start(current_movebuffer);
|
|
}
|
|
} |