Exemple #1
0
extern void REG_logAll(REG_map* src)
{
  Serial.println("reg_map: ");
  LOG_U32(REG_HEADER);
  LOG_U32(REG_MICROS);
  LOG_U32(REG_MILLIS);
  LOG_U8(REG_LEFTDIR);
  LOG_U8(REG_LEFTDC);
  LOG_U8(REG_RIGHTDIR);
  LOG_U8(REG_RIGHTDC);
  LOG_32(REG_LEFTPOS);
  LOG_32(REG_RIGHTPOS);
  LOG_U16(REG_AMB_LINE_N);
  LOG_U16(REG_AMB_LINE_E);
  LOG_U16(REG_AMB_LINE_S);
  LOG_U16(REG_AMB_LINE_W);
  LOG_U16(REG_AMB_COL_NE);
  LOG_U16(REG_AMB_COL_SE);
  LOG_U16(REG_AMB_COL_SW);
  LOG_U16(REG_AMB_COL_NW);
  LOG_U16(REG_IR_LINE_N);
  LOG_U16(REG_IR_LINE_E);
  LOG_U16(REG_IR_LINE_S);
  LOG_U16(REG_IR_LINE_W);
  LOG_U16(REG_IR_COL_NE);
  LOG_U16(REG_IR_COL_SE);
  LOG_U16(REG_IR_COL_SW);
  LOG_U16(REG_IR_COL_NW);
  LOG_U32(REG_TRAILER);
}
bool process_char(char c) {
    bool isDigit = (('0'<=c) && (c<='9'));
    bool isWhite = ((' ' == c)||('\t'==c));
    uint8_t b = 0;

    // ignore '\r'
    if (('\r' == c))
        return TRUE;
    // at end-of-line, command is complete => call process_command
    if (('\n' == c)) {
#ifdef DEBUG
        uint8_t i;
        for(i=0;i<31;i++) {
            if (codes_seen & ((uint32_t)1 << i)) {
                if (numbers_got & ((uint32_t)1 << i)) {
                    LOG_STRING("P: TOKEN ");LOG_CHAR('A'+i);LOG_S32(numbers[i]);LOG_NEWLINE;
                } else {
                    LOG_STRING("P: TOKEN ");LOG_CHAR('A'+i);LOG_NEWLINE;
                }
            }
        }
#endif
        if (base64_len) {
            LOG_STRING("P: TOKEN $ (");LOG_U8(base64_len);LOG_STRING("Bytes)\n");
            // if Stepper queue is empty, transfer modulation data now, else later
            if (STEPPER_QUEUE_is_empty()) {
                for(b=0;b<base64_len;b++)
                    LASER_RASTERDATA_put(base64_bytes[b]);
                base64_len=b=0;
            }
        }
        if (state != ERROR_STATE) {
            LOG_STRING("P: PROCESS COMMAND\n");
            process_command();
            // if stepper queue was not empty before, transfer modulation now
            if(base64_len) {
                for(b=0;b<base64_len;b++)
                    LASER_RASTERDATA_put(base64_bytes[b]);
                base64_len=0;
            }
        } else
            LOG_STRING("P: ERROR-STATE: IGNORE COMMAND!\n");
        // re-init parser
        codes_seen = 0;
        numbers_got = 0;
        state = EXPECT_FIRST_LETTER;
        return state != ERROR_STATE;
    }
    // XXX update checksum

    // state dependent interpretation of characters
    switch(state) {
        case EXPECT_FIRST_LETTER:
            codes_seen = 0;
            numbers_got = 0;
            memset(numbers, 0, sizeof(numbers));
            memset(integers, 0, sizeof(integers));
            memset(base64_bytes, 0, sizeof(base64_bytes));
            memset(filename, 0, sizeof(filename));
            filename_len = 0;
            base64_len = 0;
            state = EXPECT_LETTER;
            // intentionally no break !
        case EXPECT_LETTER:
            if ((('A'<=c) && (c<='Z'))) {
                last_letter = c-'A';
                codes_seen |= ((uint32_t)1) << last_letter;
                state = EXPECT_NUMBER_OR_SIGN;
                return TRUE;
            } else if (isWhite) { // ignore whitespace
                return TRUE;
            } else if ('*' == c) {
                state = PARSE_CHECKSUM;
                return TRUE;
            } else if (';' == c) {
                state = IGNORE_REST;
                return TRUE;
            } else if ('(' == c) {
                state = COMMENT_MODE;
                return TRUE;
            } else if ('$' == c) {
                state = EXPECT_BASE64_1;
                return TRUE;
            } else if ('\'' == c) {
                state = PARSE_FILENAME_TICKS;
                return TRUE;
            } else if ('"' == c) {
                state = PARSE_FILENAME_DOUBLETICKS;
                return TRUE;
            } else if (!filename_len) {
                state = PARSE_FILENAME;
                filename[filename_len++] = c;
                filename[filename_len] = 0;
                return TRUE;
            }
            LOG_PARSE_ERROR("unexpected character and filename already set!");
            break;
        case EXPECT_NUMBER_OR_SIGN:
            if (isWhite) {
                state = EXPECT_LETTER;
                return TRUE;
            } else if (!(isDigit || (c == '+') || (c=='-'))) {
                if (filename_len) {
                    LOG_PARSE_ERROR("filename already set: unexpected character found");
                }
                state = PARSE_FILENAME;
                filename[filename_len++] = last_letter + 'A';
                filename[filename_len++] = c;
                filename[filename_len] = 0;
                return TRUE;
            }
            state = EXPECT_FIRST_DIGIT;
            current_int = 0;
            digits = 0;
            subdigits = 0;
            if (c == '-') {
                isNegative = TRUE;
                return TRUE;
            }
            isNegative = FALSE;
            if (c == '+')    // needless, but valid
                return TRUE;
            // intentionally no break!
        case EXPECT_FIRST_DIGIT:    // first digit of a number
            if (isWhite) {
                state = EXPECT_LETTER;
                return TRUE;
            } else if (!isDigit)
                LOG_PARSE_ERROR("Expected [0-9\\w]");
            current_int = (uint8_t) c - '0';
            digits++;
            state = EXPECT_ANOTHERDIGIT;
            // fall through to number storage
            break;
        case EXPECT_ANOTHERDIGIT: // digits of a number before '.' or 'eE'
            if (isDigit) {
                if (digits>9)
                    LOG_PARSE_ERROR("Too many leading digits!");
                times_ten(current_int);
                current_int += (uint8_t) (c - '0');
                digits++;
                // fall through to number storage
                break;
            } else if ('.' == c) {
                state = EXPECT_SUBDIGITS;
                break;
            } else if (isWhite) {
                state = EXPECT_LETTER;
                break;
            } else if ('*' == c) {
                state = PARSE_CHECKSUM;
                break;
            } else if (';' == c) {
                state = IGNORE_REST;
                break;
            } else if ('(' == c) {
                state = COMMENT_MODE;
                break;
            } else if ('$' == c) {
                state = EXPECT_BASE64_1;
                break;
            } else if ('\'' == c) {
                state = PARSE_FILENAME_TICKS;
                break;
            } else if ('"' == c) {
                state = PARSE_FILENAME_DOUBLETICKS;
                break;
            } else
                LOG_PARSE_ERROR("Expected [0-9.\\w]");

        case EXPECT_SUBDIGITS:    // digits of a number after '.'
            if (isDigit) {
                if (subdigits >= SCALE_DIGITS) // ignore further digits
                    return TRUE;
                if (digits+subdigits > 9) //capacity exceeded!
                    //~ LOG_PARSE_ERROR("Too many total digits!");
                    return TRUE; // ignore further digits
                times_ten(current_int);
                current_int += (uint8_t) (c - '0');
                subdigits++;
                // fall through to number storage
                break;
            } else if (isWhite) {
                state = EXPECT_LETTER;
                return TRUE;
            } else
                LOG_PARSE_ERROR("Expected [0-9\\w]");
        case EXPECT_BASE64_1:    // expect first char of a base64-string
            if (isWhite) {
                state = EXPECT_LETTER;
                return TRUE;
            }
            b = base64_value(c);
            if (b > 63) {
                state = IGNORE_REST;
                LOG_PARSE_ERROR("Expected a BASE64 character");
            }
            base64_bytes[base64_len] = b<<2;
            state = EXPECT_BASE64_2;
            return TRUE;
        case EXPECT_BASE64_2:    // expect second char of a base64-string
            b = base64_value(c);
            if (b > 63) {
                state = IGNORE_REST;
                LOG_PARSE_ERROR("Expected a BASE64 character");
            }
            base64_bytes[base64_len++] |= (b >> 4);
            if (base64_len >= sizeof(base64_bytes)) {
                state = IGNORE_REST;
                LOG_PARSE_ERROR("Too many Base64 Bytes (Buffer full)");
            }
            base64_bytes[base64_len] = (b << 4);
            state = EXPECT_BASE64_3;
            return TRUE;
        case EXPECT_BASE64_3:    // expect third char of a base64-string (may be '=')
            if ('=' != c) {
                b = base64_value(c);
                if (b > 63) {
                    state = IGNORE_REST;
                    LOG_PARSE_ERROR("Expected a BASE64 character");
                }
                base64_bytes[base64_len++] |= (b >> 2);
                if (base64_len >= sizeof(base64_bytes)) {
                    state = IGNORE_REST;
                    LOG_PARSE_ERROR("Too many Base64 Bytes (Buffer full)");
                }
                base64_bytes[base64_len] = (b << 6);
            }
            state = EXPECT_BASE64_4;
            return TRUE;
        case EXPECT_BASE64_4:    // expect fourth char of a base64-string (may be '=')
            if ('=' != c) {
                b = base64_value(c);
                if (b > 63) {
                    state = IGNORE_REST;
                    LOG_PARSE_ERROR("Expected a BASE64 character");
                }
                base64_bytes[base64_len++] |= b;
                if (base64_len >= sizeof(base64_bytes)) {
                    state = IGNORE_REST;
                    LOG_PARSE_ERROR("Too many Base64 Bytes (Buffer full)");
                }
            }
            state = EXPECT_BASE64_1;
            return TRUE;
        case COMMENT_MODE:    // inside comment mode ()
            // just eat everything between '(' and ')'
            if (c == ')') {
                state = EXPECT_LETTER;
            }
            return TRUE;
        case ERROR_STATE: // after an error, ignore until end of line and do not process_command at eol!
            return FALSE;
        case PARSE_CHECKSUM: // after a '*': parse digits of the checksum (untile end of line)
            // ignored.
        case IGNORE_REST:    // after a ; (comment until end of line)
            // just eat everything after a ';'
            return TRUE;
        case PARSE_FILENAME_DOUBLETICKS: // parse filename inside double ticks ""
            if ('"' == c) {
                state = EXPECT_LETTER;
                return TRUE;
            }
            b = filename_len;
            filename[b++] = c;
            filename[b] = 0;
            filename_len = b;
            return (filename_len < sizeof(filename));
        case PARSE_FILENAME_TICKS: // parse filename inside single ticks ''
            if ('\'' == c) {
                state = EXPECT_LETTER;
                return TRUE;
            }
            b = filename_len;
            filename[b++] = c;
            filename[b] = 0;
            filename_len = b;
            return (filename_len < sizeof(filename));
        case PARSE_FILENAME: // Characters which must be a filename
            if (isWhite) {
                state = EXPECT_LETTER;
                return TRUE;
            }
            b = filename_len;
            filename[b++] = c;
            filename[b] = 0;
            filename_len = b;
            return (filename_len < sizeof(filename));

        default:
            LOG_PARSE_ERROR("Unknown or undefined State");
    }
// ALWAYS supported. may use accel/deccel for faster moves. do only use with OFF tool (or none)
bool move_kernel(void) {
    register state_t *s asm("r28") = state_ptr;
    uint8_t flag;
    uint16_t tmp;

    LOG_STRING("Stepper: MOVE\n");
    // first part: step the necessary axes
    if (s->axis_mask & X_AXIS_MASK) {
        if (s->count_direction[X_AXIS] == 1) {
            SET_X_INC;
        } else {
            SET_X_DEC;
        }
        ADVANCE_STEP_COUNTER(s->step_ctr[X_AXIS], s->steps[X_AXIS], s->steps_total, flag);
        if (flag) {
            SET_X_STEP;
            if (s->count_direction[X_AXIS] == 1) {LOG_STEP("X+");} else LOG_STEP("X-");
            ADVANCE_POSITION(s->position[X_AXIS], s->count_direction[X_AXIS]);
            CLR_X_STEP;
        }
    }
    if (s->axis_mask & Y_AXIS_MASK) {
        if (s->count_direction[Y_AXIS] == 1) {
            SET_Y_INC;
        } else {
            SET_Y_DEC;
        }
        ADVANCE_STEP_COUNTER(s->step_ctr[Y_AXIS], s->steps[Y_AXIS], s->steps_total, flag);
        if (flag) {
            SET_Y_STEP;
            if (s->count_direction[Y_AXIS] == 1) {LOG_STEP("Y+");} else LOG_STEP("Y-");
            ADVANCE_POSITION(s->position[Y_AXIS], s->count_direction[Y_AXIS]);
            CLR_Y_STEP;
        }
    }
    if (s->axis_mask & Z_AXIS_MASK) {
        if (s->count_direction[Z_AXIS] == 1) {
            SET_Z_INC;
        } else {
            SET_Z_DEC;
        }
        ADVANCE_STEP_COUNTER(s->step_ctr[Z_AXIS], s->steps[Z_AXIS], s->steps_total, flag);
        if (flag) {
            SET_Z_STEP;
            if (s->count_direction[Z_AXIS] == 1) {LOG_STEP("Z+");} else LOG_STEP("Z-");
            ADVANCE_POSITION(s->position[Z_AXIS], s->count_direction[Z_AXIS]);
            CLR_Z_STEP;
        }
    };
    LOG_POS;

    // fail-safe:
    if (!(s->axis_mask & 7))
        return FALSE; // axis mask empty -> finished

    // stupid ramp, but faster than staying at 244Hz. clamp to at most 8Khz.
    // 'mantissa' bits. the more, the slower is the accel/deccel. 6 is good
    #define MAGIC   6
    #define MAGIC2   (16-MAGIC+1)*(1<<MAGIC)
    tmp = min(s->steps_to_go, 1 + s->steps_total - s->steps_to_go);
    if (tmp <= MAGIC2)
        tmp = MAGIC2 - tmp;
    else
        tmp = 0;

    LOG_STRING("MOVE_OCR1A_CALC");LOG_X16(tmp);
    // extract exponent (as flag)
    flag = tmp >> MAGIC;LOG_U8(flag);
    if (flag) {
        // if no underflow, force highest bit set
        tmp |= 1 << MAGIC;
        flag--;
    }
    // zero exponents bits
    tmp &= (2 << MAGIC) -1;
    // solve
    for(;flag;flag--) {
        if (tmp < 32768) {
            tmp <<= 1;
        } else {
            // overflow
            tmp = 65535;
            break;
        }
    }
    LOG_X16(tmp);
    OCR1A = max(2000U, tmp);
    LOG_X16(OCR1A);LOG_STRING("ST: new OCR1A Value\n");
    return (--s->steps_to_go != 0);
}
bool home_kernel(void) {
    register state_t *s asm("r28") = state_ptr;

    LOG_STRING("Stepper: HOME"); LOG_U8(s->job);LOG_NEWLINE;

    if(SIM_ACTIVE)
       s->job = STEPPER_HOME_REF;

    if (s->job == STEPPER_HOME) {
        // first part of homing: find the ref switches
        // check limit switches
        #ifdef X_HOME_IS_ACTIVE
        if ((s->axis_mask & X_AXIS_MASK) && (X_HOME_IS_ACTIVE))
        #endif
            s->axis_mask &=~ X_AXIS_MASK;

        #ifdef Y_HOME_IS_ACTIVE
        if ((s->axis_mask & Y_AXIS_MASK) && (Y_HOME_IS_ACTIVE))
        #endif
            s->axis_mask &=~ Y_AXIS_MASK;

        #ifdef Z_HOME_IS_ACTIVE
        if ((s->axis_mask & Z_AXIS_MASK) && (Z_HOME_IS_ACTIVE))
        #endif
            s->axis_mask &=~ Z_AXIS_MASK;

        // step the steppers
        if (s->axis_mask & X_AXIS_MASK) {
            SET_X_STEP;
            ADVANCE_POSITION(s->position[X_AXIS], s->count_direction[X_AXIS]);
            CLR_X_STEP;
        }

        if (s->axis_mask & Y_AXIS_MASK) {
            SET_Y_STEP;
            ADVANCE_POSITION(s->position[Y_AXIS], s->count_direction[Y_AXIS]);
            CLR_Y_STEP;
        }

        if (s->axis_mask & Z_AXIS_MASK) {
            SET_Z_STEP;
            ADVANCE_POSITION(s->position[Z_AXIS], s->count_direction[Z_AXIS]);
            CLR_Z_STEP;

        }

        LOG_POS;
        if (s->axis_mask & 0x07) // not yet finished, continue in next IRQ
            return TRUE;

        // re-init for second part
        s->axis_mask = (s->axis_mask >> 4) * 0x11; // upper 4 bits stored a copy of the original mask

        s->count_direction[0] = -X_HOME_DIR;
        s->count_direction[1] = -Y_HOME_DIR;
        s->count_direction[2] = -Z_HOME_DIR;
        if (s->count_direction[X_AXIS] == 1) SET_X_INC; else SET_X_DEC;
        if (s->count_direction[Y_AXIS] == 1) SET_Y_INC; else SET_Y_DEC;
        if (s->count_direction[Z_AXIS] == 1) SET_Z_INC; else SET_Z_DEC;
        s->job = STEPPER_HOME_REF;  // search for refpoint
        OCR1A = 65535; // second part is as slow as possible
        return TRUE;

    } else {
        // 2(nd) part: find refpos

        // check limit switches
        #ifdef X_HOME_IS_ACTIVE
        if ((s->axis_mask & X_AXIS_MASK) && (!X_HOME_IS_ACTIVE))
// ONLY to be called from ISR !!!
bool arc_kernel(void) {
    register state_t *s asm("r28") = state_ptr;

    LOG_STRING("Stepper: ARC ");LOG_U8(s->job);LOG_NEWLINE;

    switch (s->job) {
    // CCW octants
    case STEPPER_ARC_CCW_OCT0:
            // octant 1: x > 0, y >= 0, x > y
            // always y+, sometimes x-
            if (s->arc_err <= s->arc_dy -s->arc_x)
                ARC_KERNEL_STEP_X_NEG;
            ARC_KERNEL_STEP_Y_POS;

            if (s->arc_y >= s->arc_x)
                s->job = STEPPER_ARC_CCW_OCT1;
            break;

    case STEPPER_ARC_CCW_OCT1:
            // octant 2: x > 0, y > 0, x <= y
            // always x-, sometimes y+
            if (s->arc_err > s->arc_y - s->arc_dx)
                ARC_KERNEL_STEP_Y_POS;
            ARC_KERNEL_STEP_X_NEG;

            if (s->arc_x <= 0)
                s->job = STEPPER_ARC_CCW_OCT2;
            break;

    case STEPPER_ARC_CCW_OCT2:
            // octant 3: x <= 0, y > 0, -x <= y
            // always x-, sometimes y-
            if (s->arc_err <= -(s->arc_dx + s->arc_y))
                ARC_KERNEL_STEP_Y_NEG;
            ARC_KERNEL_STEP_X_NEG;

            if (s->arc_x <= -s->arc_y)
                s->job = STEPPER_ARC_CCW_OCT3;
            break;

    case STEPPER_ARC_CCW_OCT3:
            // octant 4: x < 0, y > 0, -x > y
            // always y-, sometimes x-
            if (s->arc_err > -(s->arc_dy + s->arc_x))
                ARC_KERNEL_STEP_X_NEG;
            ARC_KERNEL_STEP_Y_NEG;

            if (s->arc_y <= 0)
                s->job = STEPPER_ARC_CCW_OCT4;
            break;

    case STEPPER_ARC_CCW_OCT4:
            // octant 5: x < 0, y <= 0, -x > -y
            // always y-, sometimes x+
            if (s->arc_err <= s->arc_x - s->arc_dy)
                ARC_KERNEL_STEP_X_POS;
            ARC_KERNEL_STEP_Y_NEG;

            if (s->arc_x >= s->arc_y)
                s->job = STEPPER_ARC_CCW_OCT5;
            break;

    case STEPPER_ARC_CCW_OCT5:
            // octant 6: x < 0, y < 0, -x <= -y
            // always x+, sometimes y-
            if (s->arc_err > s->arc_dx - s->arc_y)
                ARC_KERNEL_STEP_Y_NEG;
            ARC_KERNEL_STEP_X_POS;

            if (s->arc_x >= 0)
                s->job = STEPPER_ARC_CCW_OCT6;
            break;

    case STEPPER_ARC_CCW_OCT6:
            // octant 7: x >= 0, y < 0, x <= -y
            // always x+, sometimes y+
            if (s->arc_err <= s->arc_dx + s->arc_y)
                ARC_KERNEL_STEP_Y_POS;
            ARC_KERNEL_STEP_X_POS;

            if (s->arc_x >= -s->arc_y)
                s->job = STEPPER_ARC_CCW_OCT7;
            break;

    case STEPPER_ARC_CCW_OCT7:
            // octant 8: x > 0, y < 0, x > -y
            // always y+, sometimes x+
            if (s->arc_err > s->arc_x + s->arc_dy)
                ARC_KERNEL_STEP_X_POS;
            ARC_KERNEL_STEP_Y_POS;

            if (s->arc_y >= 0)
                s->job = STEPPER_ARC_CCW_OCT0;
            break;

    // CW octants
    case STEPPER_ARC_CW_OCT0:
            // octant 1: x > 0, y >= 0, x > y
            // always y-, sometimes x+
            if (s->arc_err > -s->arc_dy + s->arc_x)
                ARC_KERNEL_STEP_X_POS;
            ARC_KERNEL_STEP_Y_NEG;

            if (s->arc_y <= 0)
                s->job = STEPPER_ARC_CW_OCT7;
            break;

    case STEPPER_ARC_CW_OCT1:
            // octant 2: x > 0, y > 0, x <= y
            // always x+, sometimes y-
            if (s->arc_err <= -s->arc_y + s->arc_dx)
                ARC_KERNEL_STEP_Y_NEG;
            ARC_KERNEL_STEP_X_POS;

            if (s->arc_y < s->arc_x)
                s->job = STEPPER_ARC_CW_OCT0;
            break;

    case STEPPER_ARC_CW_OCT2:
            // octant 3: x <= 0, y > 0, -x <= y
            // always x+, sometimes y+
            if (s->arc_err > s->arc_dx + s->arc_y)
                ARC_KERNEL_STEP_Y_POS;
            ARC_KERNEL_STEP_X_POS;

            if (s->arc_x >= 0)
                s->job = STEPPER_ARC_CW_OCT1;
            break;

    case STEPPER_ARC_CW_OCT3:
            // octant 4: x < 0, y > 0, -x > y
            // always y+, sometimes x+
            if (s->arc_err <= s->arc_dy + s->arc_x)
                ARC_KERNEL_STEP_X_POS;
            ARC_KERNEL_STEP_Y_POS;

            if (s->arc_x > -s->arc_y)
                s->job = STEPPER_ARC_CW_OCT2;
            break;

    case STEPPER_ARC_CW_OCT4:
            // octant 5: x < 0, y <= 0, -x > -y
            // always y+, sometimes x-
            if (s->arc_err > -s->arc_x + s->arc_dy)
                ARC_KERNEL_STEP_X_NEG;
            ARC_KERNEL_STEP_Y_POS;

            if (s->arc_y >= 0)
                s->job = STEPPER_ARC_CW_OCT3;
            break;

    case STEPPER_ARC_CW_OCT5:
            // octant 6: x < 0, y < 0, -x <= -y
            // always x-, sometimes y+
            if (s->arc_err <= -s->arc_dx + s->arc_y)
                ARC_KERNEL_STEP_Y_POS;
            ARC_KERNEL_STEP_X_NEG;

            if (s->arc_x < s->arc_y)
                s->job = STEPPER_ARC_CW_OCT4;
            break;

    case STEPPER_ARC_CW_OCT6:
            // octant 7: x >= 0, y < 0, x <= -y
            // always x-, sometimes y-
            if (s->arc_err > -(s->arc_dx + s->arc_y))
                ARC_KERNEL_STEP_Y_NEG;
            ARC_KERNEL_STEP_X_NEG;

            if (s->arc_x <= 0)
                s->job = STEPPER_ARC_CW_OCT5;
            break;

    case STEPPER_ARC_CW_OCT7:
            // octant 8: x > 0, y < 0, x > -y
            // always y-, sometimes x-
            if (s->arc_err <= -(s->arc_x + s->arc_dy))
                ARC_KERNEL_STEP_X_NEG;
            ARC_KERNEL_STEP_Y_NEG;

            if (s->arc_x < -s->arc_y)
                s->job = STEPPER_ARC_CW_OCT6;
            break;
    };

    // handle Z movement, if any
    if (s->axis_mask & Z_AXIS_MASK) {
        uint8_t flag;
        if (s->count_direction[Z_AXIS] == 1) {
            SET_Z_INC;
        } else {
            SET_Z_DEC;
        }
        ADVANCE_STEP_COUNTER(s->step_ctr[Z_AXIS], s->steps[Z_AXIS], s->steps_total, flag);
        if (flag) {
            SET_Z_STEP;
            if (s->count_direction[Z_AXIS] == 1) {LOG_STEP("Z+");} else LOG_STEP("Z-");
            ADVANCE_POSITION(s->position[Z_AXIS], s->count_direction[Z_AXIS]);
            CLR_Z_STEP;
        }
    }

    LOG_POS;

    //~ avg_speed in x: |y|/R * mm_per_step * tickrate
    //~ total avg_speed is R/max(|x|,|y|) * mm_per_step * steprate
    //~ ->
    //~ F_CPU/OCR1A = steprate = avg_speed * max(|x|,|y|) / (R*mm_per_step)
    //~ ->
    //~ OCR1A = F_CPU * R * mm_per_step / (avg_speed * max(|x|,|y|)
    //~ at hor/vert tangents:
    //~ OCR1A_0 = F_CPU * mm_per_step / avg_speed = s-> base_ticks
    //~ ->
    //~ OCR1A = s->base_ticks * R / max(|x|,|y|)  = s->base_ticks ... sqrt(2)*s->base_ticks
    //~ -> s->base_ticks <= 40404 !!!!

    //s->speedfactor = round(256.0*sqrt(square(s->arc_x) + square(s->arc_y)) / max(abs(s->arc_x), abs(s->arc_y)));

    OCR1A = (((uint32_t) s->base_ticks) * (s->arc_radius)) / max(abs(s->arc_x),abs(s->arc_y));
    //~ OCR1A = s->base_ticks; // XXX: speedfactor correction!

    LOG_STRING("new OCR1A:");LOG_X16(OCR1A);LOG_X16(s->base_ticks);LOG_NEWLINE;

    s->steps_to_go--;
    return (s->steps_to_go != 0);
}