lw35-upgrade/printer/avr/main.c

1282 lines
27 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#define BAUDRATE 19200
inline void spi_process_data();
/* System functions */
/* Timers */
enum TIMERS{TIM_CARRIAGE,
TIM_WHEEL,
TIM_LINEFEED,
TIM_SYSTEM,
TIMS};
#define TIMESCALE 4
#define sleep_ms(channel, time_ms) sleep(channel, time_ms * TIMESCALE)
volatile uint16_t timer[TIMS];
#define set_timer(channel, time_systicks) {timer[channel] = time_systicks;}
uint8_t block_for(uint8_t channel, uint16_t time_systicks)
{
if (timer[channel] == 0) {
timer[channel] = time_systicks;
return 1;
}
return 0;
}
ISR (TIMER1_COMPA_vect)
{
uint8_t i;
for (i = 0; i < TIMS; ++i) {
if (timer[i] > 0) {
timer[i]--;
}
}
}
/* Look-up-tables */
/* Daisy wheel */
#define PRINTER_CONTROL_CHAR 56
#define PRINTER_NO_CHAR 128
#define ASCII_TRANSLATION_TABLE_SIZE 128 + 12
const uint8_t ascii_translation_table[ASCII_TRANSLATION_TABLE_SIZE] PROGMEM = {
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR, // ASCII 15
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR,
PRINTER_CONTROL_CHAR, // ASCII 31
PRINTER_NO_CHAR, // Space
52, // !
66, // "
44, // #
40, // $
29, // %
74, // &
58, // '
88, // (
86, // )
82, // *
84, // +
0, // ,
68, // -
1, // .
28, // /
38, // 0
30, // 1
32, // 2
31, // 3
33, // 4
34, // 5
35, // 6
36, // 7
37, // 8
39, // 9
94, // :
92, // ;
PRINTER_NO_CHAR, // <
71, // =
PRINTER_NO_CHAR, // >
64, // ?
PRINTER_NO_CHAR, // @
76, // A
72, // B
67, // C
65, // D
70, // E
69, // F
63, // G
87, // H
90, // I
62, // J
85, // K
78, // L
95, // M
91, // N
61, // O
80, // P
59, // Q
57, // R
79, // S
77, // T
89, // U
73, // V
93, // W
83, // X
75, // Y
81, // Z
PRINTER_NO_CHAR, // [
PRINTER_NO_CHAR, // BACKSLASH
PRINTER_NO_CHAR, // ]
PRINTER_NO_CHAR, // ^
60, // _
54, // `
5, // a
15, // b
8, // c
21, // d
2, // e
16, // f
17, // g
12, // h
6, // i
26, // j
19, // k
11, // l
10, // m
14, // n
7, // o
13, // p
24, // q
3, // r
4, // s
9, // t
18, // u
20, // v
27, // w
25, // x
22, // y
23, // z
PRINTER_NO_CHAR, // {
48, // |
PRINTER_NO_CHAR, // }
PRINTER_NO_CHAR, // ~
PRINTER_CONTROL_CHAR, // DEL
45, // ³
47, // ²
50, // ´
51, // §
56, // °
41, // ö
42, // ü
43, // ä
46, // Ö
49, // ß
53, // Ü
55, // Ä
};
/* Hardware functions */
void uart_putc(char c)
{
while (!(UCSRA & (1 << UDRE)));
UDR = c;
}
#define ENABLE_SERIAL_DEBUG
#ifdef ENABLE_SERIAL_DEBUG
void debug_putc(char c) {
uart_putc(c);
};
void debug_write(char *c)
{
while (*c) {
uart_putc(*c);
c++;
}
}
unsigned int debug_printf(char *format,...)
{
va_list args;
unsigned int i;
char printbuffer[64];
va_start (args, format);
i = vsprintf (printbuffer, format, args);
va_end (args);
debug_write(printbuffer);
return i;
}
#else
void debug_write(char *c) {};
void debug_putc(char c) {};
unsigned int debug_printf(char *format,...) {return 0;};
#endif
/* DC drive */
#define MOTLIM(t) t##C
#define PIN_DCMOTOR (1 << 4)
#define PIN_LIMITSWITCH (1 << 5)
#define SOLENOID(t) t##B
#define PIN_CORRECTION (1 << 1)
#define PIN_ARMHAMMER (1 << 0)
/* Stepper drive */
/* Drive pattern:
* -A, +C
* -B, +D
* +A, -C
* +B, -D
*/
struct stepper_config {
char port;
uint8_t timch;
uint8_t pin_a;
uint8_t pin_b;
uint8_t pin_c;
uint8_t pin_d;
uint8_t delay;
uint16_t wraparound;
};
struct stepper_status {
uint8_t step;
int8_t dir;
int8_t ldir;
uint8_t lpstate;
uint16_t pos; /* Absolute position */
uint16_t target_pos;
};
/* Stepper configs */
#define REVERSAL_MULTIPLIER 32
#define STEPPER_CFG_HW_CARRIAGE(t) t##B
const struct stepper_config STEPPER_CFG_CARRIAGE = {
.port = 'B',
.timch = TIM_CARRIAGE,
.pin_a = (1 << 5),
.pin_b = (1 << 4),
.pin_c = (1 << 3),
.pin_d = (1 << 2),
.delay = 3.5 * TIMESCALE,
.wraparound = 0 /* No wraparound */
};
#define STEPPER_CFG_HW_WHEEL(t) t##D
const struct stepper_config STEPPER_CFG_WHEEL = {
.port = 'D',
.timch = TIM_WHEEL,
.pin_a = (1 << 4),
.pin_b = (1 << 5),
.pin_c = (1 << 6),
.pin_d = (1 << 7),
.delay = 3.5 * TIMESCALE,
.wraparound = 96 * 2
};
#define STEPPER_CFG_HW_LINEFEED(t) t##C
const struct stepper_config STEPPER_CFG_LINEFEED= {
.port = 'C',
.timch = TIM_LINEFEED,
.pin_a = (1 << 2),
.pin_b = (1 << 3),
.pin_c = (1 << 0),
.pin_d = (1 << 1),
.delay = 3.5 * TIMESCALE,
.wraparound = 0 /* No wraparound */
};
/* Stepper helpers */
#define STEPPER_CFG(NAME) STEPPER_CFG_##NAME
#define STEPPER_NEXT(NAME, DIR) stepper_next_f(&stepper_status_##NAME, \
&STEPPER_CFG_##NAME, DIR)
#define STEPPER_SET_IO(NAME) STEPPER_CFG_HW_##NAME(DDR) = \
stepper_calc_ioc(STEPPER_CFG_HW_##NAME(DDR), \
&STEPPER_CFG_##NAME)
#define STEPPER_STOP(NAME) {STEPPER_NEXT(NAME, 0);}
/* Stepper vars */
struct stepper_status stepper_status_WHEEL = {
.step = 0,
.dir = -1,
.lpstate = 0
};
struct stepper_status stepper_status_CARRIAGE = {
.step = 0,
.dir = -1,
.lpstate = 0
};
struct stepper_status stepper_status_LINEFEED = {
.step = 0,
.dir = -1,
.lpstate = 0
};
/* Stepper functions */
uint8_t stepper_calc_ioc(uint8_t pstate, const struct stepper_config *cfg)
{
pstate |= cfg->pin_a | cfg->pin_b | cfg->pin_c | cfg->pin_d;
return pstate;
}
void stepper_next_f(struct stepper_status *stat,
const struct stepper_config *cfg,
int8_t dir)
{
uint8_t pstate = 0;
/* Get current state of port */
switch (cfg->port) {
case 'B':
pstate = PORTB;
break;
case 'C':
pstate = PORTC;
break;
case 'D':
pstate = PORTD;
break;
}
/* Calculate next stepper state */
if (stat->dir != 0) { /* Do not step for the recovery step */
if (dir == 1 && stat->step == 3)
stat->step = 0;
else if (dir == -1 && stat->step == 0)
stat->step = 3;
else
(stat->step) += dir;
}
/* Apply current state */
if (dir == 0) {
stat->lpstate = pstate;
//if (cfg->port == 'B') debug_printf("[%d] stop at: %x\r\n", stat->step, pstate & 0xF);
pstate &= ~(cfg->pin_a | cfg->pin_b | cfg->pin_c | cfg->pin_d);
} else {
if (stat->dir == 0) { /* If this is the first step */
pstate |= stat->lpstate & (cfg->pin_a | cfg->pin_b | cfg->pin_c | cfg->pin_d);
//if (cfg->port == 'B') debug_printf("[%d] restore to : %x\r\n", stat->step, pstate & 0xF);
} else {
switch (stat->step) {
case 0:
pstate &= ~cfg->pin_a;
pstate |= cfg->pin_c;
break;
case 1:
pstate &= ~cfg->pin_b;
pstate |= cfg->pin_d;
break;
case 2:
pstate |= cfg->pin_a;
pstate &= ~cfg->pin_c;
break;
case 3:
pstate |= cfg->pin_b;
pstate &= ~cfg->pin_d;
break;
default:
break;
}
//if (cfg->port == 'B') debug_printf("[%d] set to : %x\r\n", stat->step, pstate & 0xF);
}
}
/* Update status information */
if (stat->dir) { // Ignore recovery step
if (stat->ldir == dir) { // Ignore reversal step
stat->pos += dir;
if (cfg->wraparound) {
if (dir == 1) {
if (stat->pos >= cfg->wraparound) {
stat->pos = 0;
}
} else {
if (stat->pos == 65535) { // Underflow
stat->pos = cfg->wraparound - 1;
}
}
}
}
}
if (stat->dir)
stat->ldir = stat->dir;
stat->dir = dir;
/* Set new state of port */
switch (cfg->port) {
case 'B':
PORTB = pstate;
break;
case 'C':
PORTC = pstate;
break;
case 'D':
PORTD = pstate;
break;
}
}
int8_t stepper_required_direction(struct stepper_status *stat,
const struct stepper_config *cfg)
{
int8_t dir = 0;
uint16_t half;
if (stat->pos == stat->target_pos) {
return 0;
} else if (stat->pos > stat->target_pos) {
dir = -1;
} else {
dir = 1;
}
if (cfg->wraparound) {
half = cfg->wraparound / 2;
if ((stat->pos > half && stat->target_pos <= half) ||
(stat->pos <= half && stat->target_pos > half)){
dir *= -1;
}
}
return dir;
}
uint8_t stepper_perform_movement(struct stepper_status *stat,
const struct stepper_config *cfg)
{
int8_t dir;
/* Check whether we are in an active movement state,
or whether we need to go into one.*/
if (stat->dir != 0 || stat->pos != stat->target_pos) {
/* Set up direction */
if (block_for(cfg->timch, cfg->delay)) {
dir = stepper_required_direction(stat, cfg);
if ((dir == -1) && (stat->dir == 1)) { /* Reversal */
dir = 0;
//debug_write("[stp] Hard reversal detected. Pausing. -->|\r\n");
set_timer(cfg->timch, cfg->delay * REVERSAL_MULTIPLIER);
} else if ((dir == 1) && (stat->dir == -1)) { /* Reversal */
dir = 0;
//debug_write("[stp] Hard reversal detected. Pausing. |<--\r\n");
set_timer(cfg->timch, cfg->delay * REVERSAL_MULTIPLIER);
}
stepper_next_f(stat, cfg, dir);
}
}
return 0;
}
#define POSITION_REACHED(NAME) ((stepper_status_##NAME.dir == 0) && (stepper_status_##NAME.pos == stepper_status_##NAME.target_pos))
#define SET_TARGET(NAME, target) stepper_set_target(&stepper_status_##NAME, \
&STEPPER_CFG_##NAME,\
target)
#define SET_TARGET_DELTA(NAME, delta) SET_TARGET(NAME, \
stepper_status_##NAME.target_pos - (delta))
void stepper_set_target(struct stepper_status *stat,
const struct stepper_config *cfg,
uint16_t target)
{
if (cfg->wraparound) {
while (target >= -cfg->wraparound) {
debug_printf("WRAP- %u\r\n", target);
target += cfg->wraparound;
}
while (target >= cfg->wraparound) {
debug_printf("WRAP+ %u\r\n", target);
target -= cfg->wraparound;
}
}
stat->target_pos = target;
}
/* DC functions */
void arm_hammer()
{
SOLENOID(PORT) |= PIN_ARMHAMMER;
_delay_ms(30);
SOLENOID(PORT) &= ~(PIN_ARMHAMMER);
}
void arm_correction()
{
SOLENOID(PORT) |= PIN_CORRECTION;
_delay_ms(30);
SOLENOID(PORT) &= ~(PIN_CORRECTION);
}
#define DCMOTOR_EN MOTLIM(PORT) |= PIN_DCMOTOR
#define DCMOTOR_STOP MOTLIM(PORT) &= ~PIN_DCMOTOR
#define DCMOTOR_ISACTIVE (MOTLIM(PORT) & PIN_DCMOTOR)
#define LIMITSWITCH (!(MOTLIM(PIN) & PIN_LIMITSWITCH))
/* Main program code */
void move_carriage_to_far_left(uint8_t reset)
{
uint16_t cnt = 0;
/* Init stepper controller */
if (reset) {
stepper_status_CARRIAGE.step = 0;
}
stepper_status_CARRIAGE.dir = -1;
if (LIMITSWITCH) {
debug_write("[car] Clearing switch area...\r\n");
while (LIMITSWITCH) {
if (block_for(TIM_CARRIAGE, STEPPER_CFG_CARRIAGE.delay)) {
STEPPER_NEXT(CARRIAGE, 1);
}
}
for (cnt = 0; cnt < 16; cnt++) {
STEPPER_NEXT(CARRIAGE, 1);
}
STEPPER_STOP(CARRIAGE);
_delay_ms(100);
}
debug_write("[car] Moving carriage to far left...\r\n");
cnt = 0;
while (!LIMITSWITCH) {
if (block_for(TIM_CARRIAGE, STEPPER_CFG_CARRIAGE.delay)) {
cnt++;
STEPPER_NEXT(CARRIAGE, -1);
}
}
STEPPER_STOP(CARRIAGE);
stepper_status_CARRIAGE.pos = 0;
stepper_status_CARRIAGE.target_pos = 0;
debug_printf("[car] Carriage left after %u steps.\r\n", cnt);
}
void align_daisy_wheel()
{
int i;
debug_write("[whl] Aligning wheel...\r\n");
stepper_status_WHEEL.dir = 0;
stepper_status_WHEEL.lpstate = 0;
stepper_status_WHEEL.pos = 0;
stepper_status_WHEEL.step = 0;
stepper_status_WHEEL.target_pos = 0;
stepper_status_WHEEL.ldir = 0;
/* Rotate right for one revolution -> lock daisy wheel to assembly */
for (i = 0; i < (96 + 1) * 2; ) {
if (block_for(TIM_WHEEL, STEPPER_CFG_WHEEL.delay)) {
STEPPER_NEXT(WHEEL, 1);
i++;
}
}
/* Rotate left for one revolution -> align daisy wheel assembly */
for (i = 0; i < (96 + 1 + 6) * 2; ) {
if (block_for(TIM_WHEEL, STEPPER_CFG_WHEEL.delay)) {
STEPPER_NEXT(WHEEL, -1);
i++;
}
}
STEPPER_STOP(WHEEL);
_delay_ms(STEPPER_CFG_WHEEL.delay * REVERSAL_MULTIPLIER);
for (i = 0; i < 3;) {
if (block_for(TIM_WHEEL, STEPPER_CFG_WHEEL.delay)) {
STEPPER_NEXT(WHEEL, 1);
i++;
}
}
STEPPER_STOP(WHEEL);
stepper_status_WHEEL.ldir = 1;
stepper_status_WHEEL.target_pos = 0;
stepper_status_WHEEL.pos = 0;
debug_write("[whl] Alignment completed.\r\n");
}
void reset_printhead()
{
debug_write("[hmr] Resetting printhead...\r\n");
DCMOTOR_EN;
_delay_ms(200);
DCMOTOR_STOP;
debug_write("[hmr] Printhead reset completed.\r\n");
}
void initialize_paperfeed()
{
int i;
debug_write("[lfd] Initializing paperfeed...\r\n");
for (i = 0; i < 10;) {
if (block_for(TIM_LINEFEED, STEPPER_CFG_LINEFEED.delay)) {
STEPPER_NEXT(LINEFEED, 1);
i++;
}
}
STEPPER_STOP(LINEFEED);
stepper_status_LINEFEED.dir = 0;
stepper_status_LINEFEED.lpstate = 0;
stepper_status_LINEFEED.pos = 32768;
stepper_status_LINEFEED.step = 0;
stepper_status_LINEFEED.target_pos = 32768;
stepper_status_LINEFEED.ldir = 0;
debug_write("[lfd] Initialization completed.\r\n");
}
//void printer_test()
//{
// uint8_t buf[80] = {0};
// uint8_t *ptr = buf;
// uint8_t *rdptr = buf;
// uint8_t translated = 0;
// int state = 0;
// debug_write("[sys] Entering printer test mode\r\n");
// while(1) {
// switch (state) {
// case 0:
// _delay_ms(100); // Motor turnoff delay
// DCMOTOR_STOP;
// stepper_status_CARRIAGE.target_pos = 80;
// stepper_status_WHEEL.target_pos = 0;stat->lpstate = pstate;
// ptr = buf;
// debug_write(">");
// state++;
// break;
// case 1:
// if (UCSRA & (1 << RXC)) {
// //stepper_status_WHEEL.target_pos += 2;
// *ptr = UDR;
// uart_putc(*ptr);
// if (*ptr == '\r') {
// debug_write("\r\nOK.\r\n");
// DCMOTOR_EN;
// _delay_ms(100); // Let motor get up to speed
// state++;
// stepper_status_CARRIAGE.target_pos = 80;
// rdptr = buf;
// } else {
// ptr++;
// }
// }
// break;
// case 2:
// stepper_status_CARRIAGE.target_pos += 10;
// translated = pgm_read_byte(&ascii_translation_table[*rdptr]);
// if (translated != PRINTER_NO_CHAR) {
// //debug_printf("Prepare: %x (%c) -> %d", *rdptr, *rdptr, translated);
// SET_TARGET(WHEEL, translated * 2);
// state++;
// } else {
// //debug_printf("Skip: %x (%c) -> %d\r\n", *rdptr, *rdptr, translated);
// rdptr++;
// if (rdptr == ptr) {
// state = 0;
// }
// }
// break;
// case 3:
// if (POSITION_REACHED(CARRIAGE) && POSITION_REACHED(WHEEL)) {
// //debug_write("!!!\r\n");
// //DCMOTOR_EN;
// arm_hammer();
// _delay_ms(50);
// //DCMOTOR_STOP;
// rdptr++;
// if (rdptr == ptr) {
// state = 0;
// } else {
// state--;
// }
// }
// break;
// default:
// break;
// }
// stepper_perform_movement(&stepper_status_CARRIAGE, &STEPPER_CFG_CARRIAGE);
// stepper_perform_movement(&stepper_status_WHEEL, &STEPPER_CFG_WHEEL);
// }
//}
void systick_test()
{
debug_write("[tmr] System timer test\r\n");
while (1) {
if (block_for(TIM_SYSTEM, 1000 * TIMESCALE)) {
debug_write("tick.\r\n");
}
if (UCSRA & (1 << RXC)) {
break;
}
}
}
void hardfault() {
debug_write("HARDFAULT!\r\n");
STEPPER_STOP(WHEEL);
STEPPER_STOP(CARRIAGE);
STEPPER_STOP(LINEFEED);
DDRB = 0;
DDRC = 0;
DDRD = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
while(1);
}
/* SPI */
#define PRINT_BUFFER_SIZE 256 // Important: must be 256 atm, when changed, you need to change code handling print_buffer_*.
volatile char print_buffer[PRINT_BUFFER_SIZE];
volatile uint8_t print_buffer_wr = 0;
volatile uint8_t print_buffer_rd = 0;
#define SPI_COMMAND_NONE 0x00
#define SPI_COMMAND_PRINTER_WRITE 0x01
#define SPI_COMMAND_PRINTER_RESET 0x02
#define SPI_COMMAND_PRINTER_SETMODE 0x03
#define SPI_COMMAND_PRINTER_MANUAL 0x04
#define SPI_COMMAND_PRINTER_PAUSE 0x05
#define SPI_COMMAND_PRINTER_RESUME 0x06
#define SPI_COMMAND_PRINTER_CLEARBUF 0x07
#define SPI_COMMAND_KEYBOARD_GETKEY 0x20
#define SPI_COMMAND_KEYBOARD_CLEARBUF 0x21
#define SPI_COMMAND_SYSTEM_BACKLIGHT 0x40
#define UART_BYTE_READY (UCSRA & (1 << RXC))
inline void spi_process_data()
{
//print_buffer[print_buffer_wr++] = SPDR; // WARNING: No overflow protection
// Will auto wrap at 256; print_buffer_wr = print_buffer_wr % PRINT_BUFFER_SIZE;
}
/*ISR(SPI_STC_vect)
{
}*/
#define PRINT_CHARACTER_WIDTH 10
#define PRINT_LINE_HEIGHT 34
#define PRINTER_STOP_RIGHT 1100
enum printer_mode_t {MANUAL, INTELLIGENT};
#define GET_PRINT_CODE(c) (pgm_read_byte(&ascii_translation_table[c]))
uint16_t print_margin_left = 100;
uint16_t print_margin_right = PRINTER_STOP_RIGHT - 100;
int8_t move_one_character(uint8_t backward)
{
if (backward) {
if (stepper_status_CARRIAGE.target_pos < print_margin_left + PRINT_CHARACTER_WIDTH) {
return 1;
}
stepper_status_CARRIAGE.target_pos -= PRINT_CHARACTER_WIDTH;
} else {
if (stepper_status_CARRIAGE.target_pos >= print_margin_right - PRINT_CHARACTER_WIDTH) {
return 1;
}
stepper_status_CARRIAGE.target_pos += PRINT_CHARACTER_WIDTH;
}
return 0;
}
void move_carriage_to_left_margin()
{
stepper_status_CARRIAGE.target_pos = print_margin_left;
debug_putc('\r');
debug_putc('{');
}
/* Simulates the print of one line and returns the end position of the printhead */
/* It's only called once, so inline is good. */
inline int8_t simulate_print_run(uint8_t *start_end_index, uint8_t *recovery_index)
{
char current_char;
uint8_t index;
uint16_t carriage_position;
uint8_t translated;
uint8_t status = 0;
uint8_t line_matters = 0;
index = *start_end_index;
carriage_position = print_margin_left;
while (!status) {
current_char = print_buffer[index];
if (index == print_buffer_wr) { /* END OF BUFFER - Can't determine length */
status = 3;
line_matters = 1;
carriage_position = print_margin_right;
break;
}
if (current_char == '\n') {
index--;
status = 1;
break;
} else if (current_char < ASCII_TRANSLATION_TABLE_SIZE) {
translated = GET_PRINT_CODE(current_char);
if (translated == PRINTER_CONTROL_CHAR) {
// ignore
} else {
if (carriage_position >= print_margin_right - PRINT_CHARACTER_WIDTH) {
status = 2;
carriage_position += PRINT_CHARACTER_WIDTH;
//(*recovery_index) = index + 1;
break; /* Don't consume character */
} else {
carriage_position += PRINT_CHARACTER_WIDTH;
if (translated != PRINTER_NO_CHAR) {
line_matters = 1;
}
}
}
}
index++; /* Consume character */
(*recovery_index) = index + 1;
}
carriage_position -= PRINT_CHARACTER_WIDTH;
*start_end_index = index;
//debug_printf("$ restore to: %d M=%d S=%d\n", print_buffer[*recovery_index], line_matters, status);
//debug_printf("CMP %d <= %d\n", ((carriage_position - print_margin_left) / 2) , (stepper_status_CARRIAGE.target_pos - print_margin_left));
if (!line_matters) {
return 0;
} else if (((carriage_position - print_margin_left) / 2) < (stepper_status_CARRIAGE.target_pos - print_margin_left)) {
//debug_printf("next char: %c\n", print_buffer[index]);
//_delay_ms(5000);
stepper_status_CARRIAGE.target_pos = carriage_position;
return -1;
} else {
return 1;
}
}
enum printer_state {INIT, IDLE, HAMMER, PAUSED};
void printer_process()
{
static enum printer_state state = INIT;
static uint8_t backward = 0;
static uint8_t print_buffer_backward = 0;
static uint8_t print_buffer_recovery = 0;
static uint8_t current_is_linebreak = 0;
char current_char;
uint8_t translated;
uint8_t end_of_next_line = 0;
int8_t temp;
static char debug_character = 0;
switch (state) {
case IDLE:
if (print_buffer_rd != print_buffer_wr) { // maybe add "|| current_is_linebreak"
if (!DCMOTOR_ISACTIVE) {
DCMOTOR_EN;
_delay_ms(100); /* Let the motor get up to speed */
}
/* Fetch new character from buffer */
if (!current_is_linebreak) {
if (backward) {
current_char = print_buffer[print_buffer_backward];
print_buffer_backward--;
} else {
current_char = print_buffer[print_buffer_rd];
print_buffer_rd++;
}
} else {
current_char = '\0';
}
/* Check whether the current character is a command or something to print */
current_is_linebreak += (current_char == '\n');
if (current_is_linebreak) {
if (backward) {
uart_putc('=');
print_buffer_rd = print_buffer_recovery;
}
backward = 0; // Re-evaluate backward. Default is forward.
stepper_status_LINEFEED.target_pos -= PRINT_LINE_HEIGHT;
uart_putc('\n');
current_is_linebreak--;
//_delay_ms(1000);
/* Decide whether we move the carriage back to the left, or
* whether print the new line in reverse. */
end_of_next_line = print_buffer_rd;
temp = simulate_print_run(&end_of_next_line, &print_buffer_recovery);
if (temp == -1) {
//uart_putc('\r');
uart_putc('[');
backward = 1;
print_buffer_backward = end_of_next_line;
} else if (temp == 0) {
// do nothing
uart_putc('#');
} else {
move_carriage_to_left_margin();
}
} else if (current_char < ASCII_TRANSLATION_TABLE_SIZE) {
translated = GET_PRINT_CODE(current_char);
debug_character = current_char;
switch (translated) {
case PRINTER_CONTROL_CHAR:
break;
case PRINTER_NO_CHAR:
current_is_linebreak += move_one_character(backward);
if (!current_is_linebreak)
uart_putc(' ');
break;
default: /* It's a printable character */
SET_TARGET(WHEEL, translated * 2);
state = HAMMER;
break;
}
} else {
// TODO: Handle special commands
}
} else {
DCMOTOR_STOP;
}
break;
case HAMMER:
if (POSITION_REACHED(WHEEL) && POSITION_REACHED(CARRIAGE) && POSITION_REACHED(LINEFEED)) {
arm_hammer();
_delay_ms(50); // TODO: replace with timer
uart_putc(debug_character);
current_is_linebreak += move_one_character(backward);
state = IDLE;
}
break;
case INIT:
move_carriage_to_left_margin();
state = IDLE;
}
// if (print_buffer_rd != print_buffer_wr) {
// if (UCSRA & (1 << UDRE)) {
// UDR = print_buffer[print_buffer_rd++];
// }
// }
// // debug only: load the CPU with some stepper movements
// pgm_read_byte(&ascii_translation_table[123]);
// stepper_status_CARRIAGE.target_pos += 10;
// stepper_status_WHEEL.target_pos += 10;
// // -----------
if (stepper_status_CARRIAGE.target_pos > PRINTER_STOP_RIGHT) { // Right margin safety
hardfault();
}
stepper_perform_movement(&stepper_status_LINEFEED, &STEPPER_CFG_LINEFEED);
stepper_perform_movement(&stepper_status_CARRIAGE, &STEPPER_CFG_CARRIAGE);
stepper_perform_movement(&stepper_status_WHEEL, &STEPPER_CFG_WHEEL);
}
int system_test_auto()
{
char c;
int do_it = 0;
int print_stat = 0;
static int goto_wheel = 0;
debug_write("[sys] Entering system test mode\r\n");
debug_write(">");
while(1) {
if (UCSRA & (1 << RXC)) {
print_stat = 1;
c = UDR;
if (goto_wheel) {
goto_wheel = 0;
SET_TARGET(WHEEL, (GET_PRINT_CODE(c)) * 2);
} else if (c >= '0' && c <= '9') {
stepper_status_CARRIAGE.target_pos = 100 * (c - '0');
} else {
/* Linefeed control */
switch (c) {
case '=':
stepper_status_LINEFEED.target_pos += 10;
break;
case '\\':
if (stepper_status_LINEFEED.target_pos >= 10)
stepper_status_LINEFEED.target_pos -= 10;
break;
default:
break;
}
/* Carriage control */
// Note: Characters 0 - 9 for carriage handled in if above
switch (c) {
case ' ':
stepper_status_CARRIAGE.target_pos += 10;
break;
case 'z':
if (stepper_status_CARRIAGE.target_pos >= 10)
stepper_status_CARRIAGE.target_pos -= 10;
break;
case 'r':
move_carriage_to_far_left(0);
break;
default:
break;
}
/* DC component control (Hammer / correction / motor) */
switch (c) {
case 'h':
DCMOTOR_EN;
arm_hammer();
_delay_ms(100); /* Note, this also locks the carriage movement -> important! */
DCMOTOR_STOP;
break;
case 'H':
arm_hammer();
break;
case 'c':
arm_correction();
break;
case 'm':
DCMOTOR_STOP;
break;
case 'M':
DCMOTOR_EN;
break;
default:
break;
}
/* Wheel control */
switch (c) {
case 'g':
goto_wheel = 1;
break;
case '\'':
//if (stepper_status_WHEEL.target_pos >= 2)
SET_TARGET_DELTA(WHEEL, -2);
debug_printf("[whl] New wheel: %d\r\n", stepper_status_WHEEL.target_pos);
break;
case ',':
SET_TARGET_DELTA(WHEEL, 2);
debug_printf("[whl] New wheel: %d\r\n", stepper_status_WHEEL.target_pos);
break;
case '"':
//if (stepper_status_WHEEL.target_pos >= 2)
SET_TARGET_DELTA(WHEEL, -60);
debug_printf("[whl] New wheel: %d\r\n", stepper_status_WHEEL.target_pos);
break;
case '<':
SET_TARGET_DELTA(WHEEL, 60);
debug_printf("[whl] New wheel: %d\r\n", stepper_status_WHEEL.target_pos);
break;
case 'w':
align_daisy_wheel();
break;
case 't':
stepper_status_WHEEL.target_pos += 2;
stepper_status_CARRIAGE.target_pos += 10;
do_it = 1;
break;
default:
break;
}
/* System control */
switch (c) {
case 'i':
sei();
debug_write("Interrupts enabled.\r\n");
break;
case 'I':
cli();
debug_write("Interrupts disabled.\r\n");
break;
case 't':
systick_test();
break;
case 'f':
hardfault();
break;
default:
break;
}
}
}
stepper_perform_movement(&stepper_status_CARRIAGE, &STEPPER_CFG_CARRIAGE);
stepper_perform_movement(&stepper_status_WHEEL, &STEPPER_CFG_WHEEL);
stepper_perform_movement(&stepper_status_LINEFEED, &STEPPER_CFG_LINEFEED);
if (POSITION_REACHED(WHEEL) && POSITION_REACHED(CARRIAGE) && POSITION_REACHED(LINEFEED) && print_stat) {
print_stat = 0;
debug_printf("[pos] %uL %uC%c %uW\r\n",
stepper_status_LINEFEED.pos,
stepper_status_CARRIAGE.pos,
(LIMITSWITCH ? '*' : '+'),
stepper_status_WHEEL.pos);
}
if (do_it) {
if (stepper_status_CARRIAGE.pos == stepper_status_CARRIAGE.target_pos) {
do_it = 0;
DCMOTOR_EN;
arm_hammer();
_delay_ms(100);
DCMOTOR_STOP;
}
}
}
}
void mainloop()
{
while (1) {
printer_process();
}
}
int main()
{
/* Disable interrupts */
cli();
/* Pre-init I/O */
DDRB = 0;
DDRC = 0;
DDRD = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
/* Set up UART */
UCSRB = (1 << TXEN) | (1 << RXEN);
UBRRH = ((((F_CPU / BAUDRATE) / 16) - 1) >> 8);
UBRRL = (((F_CPU / BAUDRATE) / 16) - 1);
/* Set up DC components */
MOTLIM(DDR) |= PIN_DCMOTOR;
MOTLIM(DDR) &= ~(PIN_LIMITSWITCH);
MOTLIM(PORT) |= PIN_LIMITSWITCH; /* Pullup for limit switch */
SOLENOID(DDR) |= PIN_ARMHAMMER;
SOLENOID(DDR) |= PIN_CORRECTION;
/* Set up steppers */
STEPPER_SET_IO(CARRIAGE);
STEPPER_SET_IO(WHEEL);
STEPPER_SET_IO(LINEFEED);
/* Set up SysTick Timer */
TCCR1B = (1 << WGM12) | (1 << CS11); // f_tim = 8 MHz / 8
OCR1A = 2000 / TIMESCALE;
TIMSK = (1 << OCIE1A);
/* Init system */
debug_write("\n\n\r[sys] STARTING IO CONTROLLER...\r\n");
debug_write("[sys] Enabling interrupts.\r\n");
sei();
/* Align printer */
initialize_paperfeed();
//move_carriage_to_far_left(1);
//align_daisy_wheel();
//reset_printhead();
debug_write("[sys] Startup completed.\r\n");
/* Run system */
system_test_auto();
// mainloop();
// printer_test();
// system_test_auto();
// systick_test();
debug_write("[sys] REACHED END OF MAIN. HALTING.\r\n");
while (1);
}