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); }