From ffb91b51c308258cf62f03d05aba1d6eb986b4ad Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Sat, 12 May 2018 20:29:50 +0200 Subject: [PATCH] printer: Add preliminary printer controller --- printer/avr/.gitignore | 5 + printer/avr/Makefile | 26 ++ printer/avr/main.c | 816 ++++++++++++++++++++++++++++++++++++++++ printer/avr/main.obj | Bin 0 -> 23676 bytes printer/avr/printer.pro | 9 + 5 files changed, 856 insertions(+) create mode 100644 printer/avr/.gitignore create mode 100644 printer/avr/Makefile create mode 100644 printer/avr/main.c create mode 100755 printer/avr/main.obj create mode 100644 printer/avr/printer.pro diff --git a/printer/avr/.gitignore b/printer/avr/.gitignore new file mode 100644 index 0000000..93cb814 --- /dev/null +++ b/printer/avr/.gitignore @@ -0,0 +1,5 @@ +*.hex +*.o +*.pro.user +*.autosave +*.old* diff --git a/printer/avr/Makefile b/printer/avr/Makefile new file mode 100644 index 0000000..f88f849 --- /dev/null +++ b/printer/avr/Makefile @@ -0,0 +1,26 @@ +MCU=atmega8 +CFLAGS=-g -Wall -mcall-prologues -mmcu=$(MCU) -Os -DF_CPU=8000000 +LDFLAGS=-Wl,-gc-sections -Wl,-relax +CC=avr-gcc +TARGET=main +OBJECT_FILES=main.o + +all: $(TARGET).hex + +clean: + rm -f *.o *.hex *.obj *.hex + +%.hex: %.obj + avr-objcopy -R .eeprom -O ihex $< $@ + +%.obj: $(OBJECT_FILES) + $(CC) $(CFLAGS) $(OBJECT_FILES) $(LDFLAGS) -o $@ + +program: $(TARGET).obj + avrdude -p $(MCU) -c usbasp -U flash:w:$(TARGET).hex + #avrdude -p $(MCU) -P /dev/ttyUSB1 -c arduino -b 57600 -U flash:w:$(TARGET).hex + +fuse: + avrdude -p m8 -c usbasp -U lfuse:w:0xe4:m -U hfuse:w:0xd9:m + +.phony: program fuse diff --git a/printer/avr/main.c b/printer/avr/main.c new file mode 100644 index 0000000..0079e1c --- /dev/null +++ b/printer/avr/main.c @@ -0,0 +1,816 @@ +#include +#include +#include +#include +#include + +#define BAUDRATE 9600 +#define UBRR 51 // (F_CPU / BAUDRATE) / 32 + +/* System functions */ +/* Timers */ +enum TIMERS{TIM_CARRIAGE, + TIM_WHEEL, + TIM_LINEFEED, + 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]--; + } + } + return; +} + +/* Look-up-tables */ +/* Daisy wheel */ +#define PRINTER_CONTROL_CHAR 56 +#define PRINTER_NO_CHAR 128 + +const uint8_t ascii_translation_table[128 + 12] 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_tx(char c) +{ + while (!(UCSRA & (1 << UDRE))); + UDR = c; +} + +void uart_write(char *c) +{ + while (*c) { + uart_tx(*c); + c++; + } +} + +unsigned int uart_printf(char *format,...) +{ + va_list args; + unsigned int i; + char printbuffer[64]; + + va_start (args, format); + + i = vsprintf (printbuffer, format, args); + va_end (args); + + uart_write(printbuffer); + + return i; +} + +/* DC drive */ +#define MOTLIM(t) t##C +#define PIN_DCMOTOR (1 << 4) +#define PIN_LIMITSWITCH (1 << 5) + +#define SOLENOID(t) t##D +#define PIN_CORRECTION (1 << 2) +#define PIN_ARMHAMMER (1 << 3) + + +/* 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##C +const struct stepper_config STEPPER_CFG_CARRIAGE = { + .port = 'C', + .timch = TIM_CARRIAGE, + .pin_a = (1 << 3), + .pin_b = (1 << 1), + .pin_c = (1 << 0), + .pin_d = (1 << 2), + .delay = 3.5 * TIMESCALE, + .wraparound = 0 /* No wraparonud */ +}; + +#define STEPPER_CFG_HW_WHEEL(t) t##B +const struct stepper_config STEPPER_CFG_WHEEL = { + .port = 'B', + .timch = TIM_WHEEL, + .pin_a = (1 << 7), + .pin_b = (1 << 0), + .pin_c = (1 << 1), + .pin_d = (1 << 6), + .delay = 3.5 * TIMESCALE, + .wraparound = 96 * 2 +}; + +/* 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 +}; + +/* 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') uart_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') uart_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') uart_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; + uart_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; + uart_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.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) { + uart_printf("WRAP- %u\r\n", target); + target += cfg->wraparound; + } + while (target >= cfg->wraparound) { + uart_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); +} + +#define DCMOTOR_EN MOTLIM(PORT) |= PIN_DCMOTOR +#define DCMOTOR_STOP 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; + + uart_write("[car] Moving carriage to far left...\r\n"); + 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; + + uart_printf("[car] Carriage left after %u steps.\r\n", cnt); +} + +void align_daisy_wheel() +{ + int i; + + uart_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; + + for (i = 0; i < (96 + 1) * 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 < 4;) { + 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 = 4; + + uart_write("[whl] Alignment completed.\r\n"); +} + +void reset_printhead() +{ + uart_write("[hmr] Resetting printhead...\r\n"); + DCMOTOR_EN; + _delay_ms(200); + DCMOTOR_STOP; + uart_write("[hmr] Printhead reset completed.\r\n"); +} + +int system_test_auto() +{ + char c; + int do_it = 0; + int print_stat = 0; + + uart_write("[sys] Entering system test mode\r\n"); + uart_write(">"); + + while(1) { + if (UCSRA & (1 << RXC)) { + print_stat = 1; + c = UDR; + + if (c >= '0' && c <= '9') { + stepper_status_CARRIAGE.target_pos = 100 * (c - '0'); + } else { + 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; + case 'h': + DCMOTOR_EN; + arm_hammer(); + _delay_ms(100); /* Note, this also locks the carriage movement -> important! */ + DCMOTOR_STOP; + break; + default: + break; + } + + switch (c) { + case '\'': + //if (stepper_status_WHEEL.target_pos >= 2) + SET_TARGET_DELTA(WHEEL, -2); + uart_printf("[whl] New wheel: %d\r\n", stepper_status_WHEEL.target_pos); + break; + case ',': + SET_TARGET_DELTA(WHEEL, 2); + uart_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; + } + } + } + + stepper_perform_movement(&stepper_status_CARRIAGE, &STEPPER_CFG_CARRIAGE); + stepper_perform_movement(&stepper_status_WHEEL, &STEPPER_CFG_WHEEL); + + if (POSITION_REACHED(WHEEL) && POSITION_REACHED(CARRIAGE) && print_stat) { + print_stat = 0; + uart_printf("[pos] CAR: %u\r\n[pos] WHL: %u\r\n", + stepper_status_CARRIAGE.pos, + 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 printer_test() +{ + uint8_t buf[80] = {0}; + uint8_t *ptr = buf; + uint8_t *rdptr = buf; + uint8_t translated = 0; + int state = 0; + + uart_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; + ptr = buf; + uart_write(">"); + state++; + break; + case 1: + if (UCSRA & (1 << RXC)) { + //stepper_status_WHEEL.target_pos += 2; + *ptr = UDR; + uart_tx(*ptr); + if (*ptr == '\r') { + uart_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) { + //uart_printf("Prepare: %x (%c) -> %d", *rdptr, *rdptr, translated); + SET_TARGET(WHEEL, translated * 2); + state++; + } else { + //uart_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)) { + //uart_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() +{ + uart_write("[tmr] System timer test\r\n"); + while (1) { + if (block_for(0, 1000*4)) { + uart_write("hello"); + } + } +} + +int main() +{ + /* 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 = (UBRR >> 8) & 0xFF; + UBRRL = UBRR & 0xFF; + + /* 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); + + /* Set up SysTick Timer */ + TCCR1B = (1 << WGM12) | (1 << CS11); // f_tim = 8 MHz / 8 + OCR1A = 1000 / TIMESCALE; + TIMSK = (1 << OCIE1A); + + /* Init system */ + uart_write("\n\n\r[sys] STARTING IO CONTROLLER...\r\n"); + uart_write("[sys] Enabling interrupts.\r\n"); + sei(); + + /* Align printer */ + move_carriage_to_far_left(1); + align_daisy_wheel(); + reset_printhead(); + + uart_write("[sys] Startup completed.\r\n"); + + /* Run system */ + printer_test(); + system_test_auto(); + systick_test(); + + uart_write("[sys] REACHED END OF MAIN. HALTING.\r\n"); + while (1); +} diff --git a/printer/avr/main.obj b/printer/avr/main.obj new file mode 100755 index 0000000000000000000000000000000000000000..d1e169da57d0e8d2bae07675535be89a13cbc39b GIT binary patch literal 23676 zcmcJ1c|cT0ws+l&3b+C88V!vSS7^GMRnQ31pe85?7-JICw$LmI(AYFC^OD#t7;zb; z*)(R+$xJd?%%Wy8Ni=%1ye#ux(wfOSak*+tjL`rYT(T(NId$)?TQttR_s91txqW~2 zt5c^=ojO%_D_onElPw4W(UM3Ch?YwLGWsq;>fxL~3?zt5CShbSEpO2(z_}t!Ir;(? z;h^=y30X!wwCo-r@#v?PVfj5n2stQv=mA+;rj_3*xug|Rwd9nlq=%#m>3-=xsaz_P zN~IFXAr(tS(sIczrTh=clQ27G^0?bl@4O?wkXVJW6K^&|Mvb2keaobK@A1s>qL^egf8rc*P9oIaod0X?Y=Jw|9=0@2g|0Za)3|_N0YPh+txr3rSbEvt_ zP$#t2nS6ciSGs-ezFod;zFEFFUu0wCp~%KjtxF%h?%(oyNUOj3Wb*}Kqt6==B%Sp6 zeIczsoxJMb{mskrnF}5AoOfRo=G|?}{Y9|*R`^~LJ{E+wl25nL^XZcx2+}<#bH9=E z-u+c*@=owJP1`uF1*~s{L(zOp_*F1?CnS8;84X9HJU$_`YsdbGwi&*N?eP;ryB?Ib z_%cl1OLeBVE{$zk=k>Jim{9NCF>OfO7T=KV^+RuxhP8d*!Cf9Gn$8NH%P7fKlC^4 zf8U=wE2GOB(NC(Aw=^&E=C#&&Crb5UTbeT>EYi@n$C`(3U*|3GuAf#2$09h;4s*mo ze?(hO^Mr&`9no-5+Ycx{s-u>!_de$@1a0fU;?@aI`J>uKU$*D12p!(`Kyww?c+lT^ z;5&cQfwO+E$^6d-=TQ&Lb)LFI!Uw{uC%4V|zN=I29ugs~JJ%?mK7lp1dJU)7?UICuXe|~|-XqVA z!#dYac;t`%dg8BV<(cnzP0wE0)&BF4pZuO58fDr4vbga!w9@ z=Opy9yQ#hDi4#ig55m5R3~N;W`@*l4ZqrI{`f7ky`kB9Z=eDyue-yTNULg`8%{xL` zHLrOi!kdf3P?D@7)UVkFI$w9)Kis2}Q zql93Kn@{=VT`+SCPiSpn6h->NV77UD2gOF;o8rc4M=ysrzbTUDgJM)$Zo8)Oo)aJY znHAso0NavJ#I++dpYqkWHvQm}|9E`MMW4L;IQAf1Ci2#c=Zs#6jFxX-H%7O=ZH$sXG1?xjleX+_ zytpH5r>VNjQ}D=u*Pdt;UVp+gC?eX_TuKbhCFCvnh+Hi-Bz@l*e#v7g@7!Vu?YdnG zffXg)S4HxCPO`ve%iUmEaz*RaA5VCI-PY`Z@@+KM%8qN}`lWwe^0OVAl22Xs_)18l zuase65!&`(+kTJy@rgtJJv-lqvGIJ@6wvd%{`zEl$A;w4jy?Ws zC!X_b7R}CE82TFcwF+8r5)t${L0=WQK?~430sNyy)33+1UR*wI@Kq3#uM%o0dTn`gKFoURJ$}Lele~?} z-7ig$*8#F$xuKoF_V&r%%l|xn_`7pwI_152a(ah4bHZ$qx$EQxqc27t(b+HRvR&HN z-uT^`C8xL;<9q)Wycdkj6zFytpm2-}7J%0VT=X{g=+SlDD z;+kePFWVuuU>6AaX9SIM~6dOrZ!A( znA>2hud08reoOtM_0QG6UjIS;Nzad-Yo3ALo4n6?U-y0tcM*D>i$X~2i}K6zxigpK zPyAbihvhAGW9mZdwzcp2?uokJ*I@*P9BKDnT`z}qMux95wtXZ2!@mb=oH~0+e%@ap z{D-g!uBIc`jaXOb^>**2F`FY?7Mi_Rgyw7Oea+oo-&z5${JY*-Z<*eubL%ZpU9Sp_ z^1h?z{0n2uF$URS+1<6-Qr=rI1)LF{A4E7l5_m=4$p7`lqQOhPuOw$W9sz&KReB&SduZ!|0)C~bvyCSF_imZ7+xv?VE` z%TOl5YM0T)+vkmV%fBOT*MqHv&8Ep+10f=Ioq42gkW`ms?x;&%(NUKe+Ob%QlCBCK z@5Z{pP;QORY*`pnC=8QQgr8*R;1y%93cEdfJrlcwBu8vD-19oy*S7zs5VIlqXpB%N z#H^27HQqSlf0P~$(lP4|W#f%?!i3*OOLei0^4t+i`t1f^c}_RVHyurFx#YhjO!{rT zZ_;(I&nBP`!;hN7Q(HRa+%XG7GKMYev*yZ4sXi&9V`Gx}(p6zncd)d~yTZH9+w8@@ zh0t8Ekqm4Y@W=q{P25VCaeH^D)Y$52t!}lquFc(+yDQgF<}yx|P4b_F@T1QdpBa@Y ztxulP75C6S%HAUV6!-Jm!^Uk%Z*`37YDiqu@uK8O9^KK99M$ox6c=Z(?=!w~eUP*{ zwtm@b#!xA`yT7z6u5H=t#(vUd(ArlroHBu*45uveRpGDKd)nBK+USuRWwh^4g8v9w z@M~=Ms$YFJ*E`+9%L^;-z$AL=W;5tAGn1iymxmzad^LDF^M{GiTp z9=I&8pfXh^G&)86O zWPi(y^_TtohmGn=8zoA2L8K;hM@TRlXBy=h8w!rhSa0bbA(^iQNe$mMLVp_0Hp;IG z18EBjJIvjpwE46kc}^!^`~7JgtJEV;4KtyBsGo4;u9mC*=UTc{JF$G~kw1iA_QxAS zyYBf|8S|(ksV!Ihmj%326=9X#)gIG!`c%lrzX^RC?RnMdLim?gJgtqbTf=rmhP3`B zP_D5jtKC73iVKbVLD=l|g1xBeW@%k_m}KC&dT(54>&9v3D_gz0yh7Wqx~+BIxW+jBKIj+Wxk-~v3p)*FZ|AudXLHrsDw`5T zFXir)Z$0vgJmW}d*y_lQkvk**Fs>|YP2{FX-?%@FyDx0TIPW+_h9jX}Wi7LOQ{{=f z;O=C!X{ovS#AQFMP}y;Fs?(QdH1C(gj(m9KvOha67xK5okLsAW)O;;HKciVZ^6ZuK z{#WFuTer7vXkFD>+WJQ8hgZmUd*2m(Ls}md_6Yrr{aO~c&S_1C=L9TU9##`sAK4nY zdt6BC)s}8Q>BgsTNa}gE;1R_1!4kxT}{M=GtAw2A5-{!&PIiFcdr7 zjv}|C*l5VJ*VdF*l^PAPv9~@jsQ>>~`hgj-u^_!TKO-;Ja7(QUrz!C6BD-s;VZL)E zC^i6gmD@`l2Dj5tVs{xT93^g}(TGh^u}rNT3k>!Wx5EWm3^i^?bq$qTRaUXokWo=y zT7~LXl{p+0YJI(=(oy9$6gexaE1+Y=v|3pu*pTn2ak$-Bui8~!RQzq0(9GfDYVB?xrRzaI8}7N;TY4j2)|XLe0#K ze8_`ql+(R+73_8tg9@IbgcG?R!_M$*-y1Y^qgEq<>6%|g>zyBabTR~w) ze&M_Ya}4ux4Vk$M3iESwamlg2NH;GEUQD;qZJ8S8}+C!v{Gmb2v0u z*O|=Wr5t{c!%uSfzd8IXhod2|G&}P-yq?340A5Fww4cL&SMe?I{<59pM}{i$X|EAt z2J9gZ(#qKsKSc386tAUt1;rkUH&E=Q_%Vu=miJLyPx<#LUQh9Hikm3@C&k+-9?&1# z{UgN_DSn3H*%ZG(@x2u9qxe54{wu}XDLzQ?D-^#=@ezvui{gtEe?@Wd0Bq|7#p5YH zL-9;9t3f7yqS@z9=!eA!DTiSi2lGsQ~Z2S6Jh@+!=9C296VQeNSfb2tQI(WA<40vt_7 z&^7Z>!0CWTLD_RE9-+z^;e1}jRx(mWgjlJxl0^)!$YZiHX$9+TP2k#^Kqe~UARkR)IBa5gJV|AEGW1_b zXiuSv(Vlyu-A|}JA5nao`sX9o7TSg~n5^Vu1yJng@Db8S%~{D&`aJ@(*cL1eG+|pM zpyvnL*54_kG4<-la+j`0E$0jI<4e0rqfEkA`o6QS;^-FK8w(V?P}wT?LGiH zgJA%p$=4K*0lXXV97UY^A7wCE$uR{`e1_R(CEpT*T4E*NQ~yr}JsxtBUXzytP6wS@ zyOJu4Cm9YC0!V0^hS9b?&~7!P1s74dErNs}nB|(jSw5@pp;t#3*dBPYdJ3;Yn0=9LY;@btSF1CyEn5-m+Yd25O z#@9;b3!49}B%j)^$Sp0c(7|w%pj^#x9Giv9jBgf{D;x4p34K`nJT3HN z_!%LD;pYW?4J;K5jIR`;RU8evZ&mREz}F$@FF~wElNSWUBO`DQzCdG7iRTvuZ9W=R zc{I;TUQ)Fn-robmrJW|^LA8osV|uLQFI;TDO6Lm-S;+yxfB+I=J+==D*fu6Bd6SFh zH@SE|B&1UblsU}B@GHV?jDJ_i0US;H_%gL2j^e#+-btz~o@6-CN0`uW8pd-DTv5}Y zZZvsMK&<%fJ=$NzZ|@6Zu_7e29c3_C$p@UTJ`x5iH1HoW8xU(g$Ll7xjR|pr0s;HE zzK>?lFjjJe^TScj4@Wsa{9VXndcF_}8U9kZgW=DGYKH$IxEMYm{Ep$zxOx2bRQCLP<7@jx*|%~;7GQJ?!^ z;$X%{h{G5T74ce$3GV~7>#~&$5%sYcE$a7XH;EQS9OTD}`ZeojaW>;4MLnKJk>!jZ zMebvGG^t{En7ESR;o@q*-_ZVsirSo&)N(w@aA?;o^qYp!Z~ft!wVnDcN<@qaeWhV5 z8PECZ7S2}_IsZ%&wXv|0$)Y~@r--_LrgHw7CQhX-p$}t4Y!4IqQ}*EYZzyx~Q)Y8R9y|XNsE`wu+4m zk0Luc{3OGp$Jch@e_tq#S<#VaXhVJ9LEdL_fQyw zXp$`=#)N*=Fx(T0l!PBEnakmMVn5(C-*zz{9-#Nwns57|5F{(Pos0h*7H@Fx$Ho_J z!vhoA77lfzsBO6-VoYe8hOH!zvu6=E2k#KWsWi4*z{OQQXTyVBjNQx4yCyEimT+_M zZZ58tiu(QJQW|5}9Nd?R=?EYpwknWf><=a@xl7cqHLFGaTJwPDp%N(bAQv+aiH|Yf z!Nr3^e3kJf;z5R&ixR^nq8<4V0f#T&2Xcb$Kg9U ztUm)bid7u1Kch8?9>)8`oeXampI~^0_%y>i#X}4~DoTJg|9ryyaDcoGJc`xB@eSi2 z7e8fn9}z!ic)NHE@N|gnbdpbFHJjoBHZLU5qa_)@w`yIS9~#D(x(sdIN$1EPMZ}nJ zj%e6Q{>06Zr?@%tJU17f6%AMsl9l{f#5OQl$w=w*ZSjg~k zZk;?XKE!xgYyqtKaEp2o#WlGNcbo~T>QT&b}{~t zc$MM9;%^K~+`M>8#Ag|;F9hC4VnUzbbB)%QA&h@d9E&8Cc~{h)ajfKhaVq0K6pajj zEG9AR7w0m3L@Z?Z6H%W>e;3Ob|G8Mr@E4++;j<#nsY-}F4|$4C@hvolpQhLMT@?SB z#`X&oKg;d`BxGp>OjbeOw&=`gz zg2pmDBj%cz%Q+_JLql01?9us6@_@*HJ`gn8D z48}(W&1TpTG?(ECLANm+9fW?zWF@x*waye^iVvEabips0uqn{(L zVpVK>B9zmQe{uGet~gR!RAjN?H`DS8_+(0;B-K6H6l0z;(?w5dvGJDVq?9!LO->_4 zWp)=8uqXnSDQTuOvjs{joXS^4S{grPW_nG$B@K1NgNVh%Qkuz}%u*Vut*U`O^vFMwu;uKeF1 zyv7O5`i;p7z5n3Ogm*0 zZqPV&X{4si>2kArW|JB>rYQk|qsaAY$gBmLnQH~KDlx&L%?#m|UZV^i;IvpANg8%c zqb^H>PnE^sOS2>FF1SloN&f4V_4mwC?2q`u0X%Y1|Uk+i!m)o*Y zYrI9N3`5KpDqXf^yX-}3!!Tm1fEgR+i@@V*kp+ur!(6#VbF6AJE$=0yIde){3Myf~ z>1ByUoxb1#Y6+9%n*=}dCNY^_%?9|hr(iE>-Nn>MTY=qe=xw0xXvI}1#T%#ln)-`s z>D83(Z#tT~P%lZ{{kl=CAHA%L*GEIQj)`+-#_J=Zo5=(Nt%%o0MYp%7bgwGc&Rt?$;$*hkLm% zK_3m>IwsDWsgHw`qAtaO$a(^yM{L4gZCoJd@4jf>u3lvfp1 z)D}Aw>@=3$xTL1UWh-`+)ZC~XF5>Pr)ecrxQNBD5?pmnE6rUW14Qv7xjklmyz~p$s~ST~{jVh3J9Am?W-6)?+g|A~7bJ zuc#NIKN8VPsI-LdpyCs)gM1NQE}@dzKP+M0vnXy+JxLYnWr|x=Z(=oOzeVwi*14W# zic{3SVG*<5qWDDXTF)}YB}&gK?W@(1w)F4@#|JpVrA0wJ4Q1W&u)k6-QhEfY-Ec;h z)Ydp)zSwLCX!}W2SrWKzW{su7xhfT65h5Z6;xw(SytGWqr$9cfw^E#FY?lAqnQC{H z(w0lBYKv?u?Y4^Y8l0CYwEYxpe=5!xSWEaq90e3nTK=~UzDY9tm`+#d zEO2AU8KN)5WEroDUOH-8gi|uYZ z)`oykeGxMq#wQ6JpFJ-p3%r#K^I|6afH??BcmuSvjd@igV^I$jZ*jvZh)vTaX$b19#%E1Gn1Yf=9%vlJZhT z6~@N&YPj#mu2OHMq`Av0iy$~~&c$GCRF_xTz<8RczC&U;?>i)lR05o*R4G=81dO+0 zM}>WjMxfGFE_=1z<*couVhK}X5>&b*Iag1htf4uZ1nRHuq|lF9KO~GNA>lT;*V&CW~bl zwMrR%tS_O3pc*Wxgy)@VMSzw;l$SW5|IiQwq8;z;6Cw1}GdwV8kJ|u~;?tC7RXr|6 zkLKqhdqt70+*t&z(N$J;oZ8o-l2U4QB1AL|TnOO%u{AJN(@^DD4XZip3OZh?0|8Cz zzyi(bAvjd19wJ>+;c~2~Eq6JJZBPboEO%B>bEt%_jn;H2HOuT3C8>zPL7El_ZtSD2 z(z()s8_2aTY2~mZ+@_2=Ggi%_IiSc6mCNjvuq&Gh^jd3c-Q^W=G@M~c!j^2X>z!_h zx4E5g4RXQNvILt}f`INrr`-jQ6@g8v&34@XZY#Ez*Q~M8E$}^S*yu3h_IAcpQ$ zxU1Y|uXQ_V0eGm`X)8yyxEK*y%|?fSXJFQ2J*JDUl3*Y#FIw%??ff;Zs z&%^>VFq3EQ24;}*7FX4L7chh8^D>Ko2`k{4CBTF);h8&uiMW?%3V<0>%rp7G484zM zP|vVxoui2mZ+cX4FQWxeb`n+jwR!Fk@PICL5TWc2Y*| zJK8gLH_xCwTGCLNfGUj#Cfj`PeEkePgjXAHnhIma`105kO>&qM(;?I)g@08Gpko*55J ztnx)n^Exy{i1(?Liyo?!`q*$IY0h4T@j2b_;0+XVA8Bq1i1ZKMO-9Tk#0F#=*>#+fo zmd)!~3e1doybR8rnYlbu2+XZ_@XSJBW-aBJ#lWN&@eD>wMmf(+0%o?8XC?xZxsoz! zzoLO5LWFS3VBBy4UxkAP4;XMO{JlVs4*LkgJow1bH;T*~8V6fI`Xzu=>VUKX^M=kE zh##AS1BsA80v4j4Rr&`K0|JSGfyAIdVsIc47D$8#5)pyKkU(N+ATcbE7#>KB2qZ=Z z5~Bi%(SgL6K;ouAVr(EWE|9o6kcbQ<41q*cATd6Wm=H)r2NJgg5)%W7NrA-VKw?TD zF*T5w7D&Vd60w1VF_4H0Bus&XIgqdf67hjVLLiYCNF)Uk$$>;lATd3VNDU;?0*M)c z#LPhA)<9xbAdwzOWCRkk1BuK)0=~K9oeh2!6@_014> zG{H@j`i_sD@qG_GdpR8NrL>Y1WY5dZCmERq`J^Dvia!)(=94+|=udV&nV-1`AU+h| z4!=MYW@hG_;CDeG{Pv{H8MM?qn--f%Ze~7E_&b|`LUW+Jh00k_!a_0%uyJb9BCur< zSd~G4XVc$IvS@aG{#^Q-Lkbtq21^#BWs9L&;bN#!xHu!9EVdQ`nU|YiIGb3l`Ljvh zyan(B`Ap1bVjg}V4}ZL2&4-wo&;k_{>9-Kn}wBJRAl%hJb(HgR^o6iktv{IR<|t24P`Q z%l`rA-Rj@ghl9RO$eW-%3C`hggBc8ii+hz%tMa2EkMRt5IwS%{Iuh~|0b>dW{qc~; ze{WCAr$W924%~x-_GAI(?O6!H`c)NNAr2^0?Ql5b~&RGhn{` z$05(_e+KgPeUv@fDE~I(b^AKIao^!Ss$H>PhWy*mKTP4!Kl)b!P+!S+b_?*piS2EH zBLeh|hI|s(uk|kq@;Lu-UPZwCpALE6o-D}Yp2Ky}4%(9sd98gMpCyp5hWa>@vHtx5 z^;bb2|5gz7WBs)O<(mWYZIJ&IWW(`*@q7yM2F~7>Adip2n8IPk9fUmooe%EqLH%FQ za#{@K0yzbFZ9NMI`z~g^(R7J>p$wxg!~$=|93+E z5Xho`(f(4%%WyQQ^?wJrjPv(4$m{k6kw+nq`-yPR61KM+^1OY|Lmu~VN2}!rATNP^ z_%~1}|2N2M$pG>9SwMZXh1d53%5(i42pISO;mZ!xHwyCjcN;_0`~<*!{W!?y!1ydv z%M&pVI$PBI0?70Jx+frC26=o8!M(58-Wtf;;J}3TdjaeI5n-n&AMbrg1C;ajya4$! zbv_%w|IJhvD2IgeaSvCHU-vaWVLmuagqE94eAdmYNagL$=9Rc#cL7w;T zP`qRs;DChoOocq|Ny8UJXwOW@?|}8J0ep!1h`O)LW-G|E&9&L!ZV5n+0^q)Y0(WJ# z&E+Vi_;(JMlV#xRtgXDpWvsGQ*VdH5wlb5+Ol(E)b<$;9UQ=Uq5+l5SWO;n^=yC^e z6;5Y0Sy`jJ)P@~yD@zzGfsZOhK-nCt%iW;N1`3?j@bc4H>athrZ{qdW>t?12IBP~> zh7I~KFL!}0Cu_l+LZyEW*a7D(t#v>zKpp%*zk0oICG@o(D1ot1Bv7<7tz zkqy;wxRhbUnF)mY;V6O7Zw30Bf2KhBzygx+J)pX0N2lxcF)|kwz`OB(-B0@ANtt}y zw+>x}IT5}+!i;1s2YyijQ6=)UI8@w(z7PC70iqyObU(~(93Q=r6o6S-dHK2XdyNBK z26Rbyux8#dn>dV9i4MAA2LAzqlfs6w!6Ut!u@z?BS$G2))*WTxsIjl4tA@5z!Pf4Y zHI?wq0M2fgaxT*lT`Y{WlSUX^6j222%Rz(~VM{K4jUvV>r`utKkK{&ppfwgdR+bkz z%BxCn33V*5ErnU7WBc;u@NYY5CAc_g7*+mn6MbI?!f<({39qTzy&w|WtxObPyu!gH zL%BA=%@h9n&|1PWOq1XUfdl36nu`Bsw5A&pD9#%N`Cq^0MW&o!pY!}l~I8a_oV`szt ztyT!6R#wholzk=}?h|hyw<BGkf-p_6Dk!34zTGHhHAJ318Q~&?~ literal 0 HcmV?d00001 diff --git a/printer/avr/printer.pro b/printer/avr/printer.pro new file mode 100644 index 0000000..4e0df99 --- /dev/null +++ b/printer/avr/printer.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +INCLUDEPATH += /usr/avr/include + +SOURCES += \ + main.c