#include #include #include #include #include #include #include #include #define PACKET_RECV_ERROR_THRESHOLD 30 tabby_printer *tabby_printer_open(const char *device) { tabby_printer *printer; if ((printer = malloc(sizeof(*printer))) == NULL) { goto error_malloc_printer; } if ((printer->fd = tabby_link_open(device)) < 0) { goto error_link_open; } printer->device = TABBY_PRINTER_DEVICE_ID; printer->status = TABBY_PRINTER_OK; return printer; error_link_open: free(printer); error_malloc_printer: return NULL; } void tabby_printer_close(tabby_printer *printer) { tabby_link_close(printer->fd); free(printer); } static uint16_t checksum(tabby_printer_packet *header, void *body) { uint16_t checksum = header->data[2] + header->data[3] + header->data[4] + header->data[5]; size_t i; for (i=0; isize; i++) { checksum += ((uint8_t *)body)[i]; } return checksum; } int tabby_printer_packet_recv(tabby_printer *printer, tabby_printer_packet *header, void *body) { ssize_t len; size_t i = 0, b = 0; uint8_t value; uint16_t sum = 0; memset(header, '\0', sizeof(*header)); while ((len = read(printer->fd, &value, 1)) >= 0) { if (i == 0) { if (value == TABBY_PRINTER_SYNC_1) { header->preamble[0] = value; i++; } else { continue; } } else if (i == 1) { if (value == TABBY_PRINTER_SYNC_2) { header->preamble[1] = value; i++; } else { i = 0; continue; } } else if (i == 2) { header->type = value; i++; } else if (i == 3) { header->compression = value; i++; } else if (i == 4) { header->size = value; i++; } else if (i == 5) { header->size |= value << 8; i++; b = 0; } else if (b < header->size) { ((uint8_t *)body)[b++] = value; } else if (b == header->size) { sum = value; b++; } else if (b == header->size + 1) { sum |= value << 8; if (checksum(header, body) != sum) { errno = EIO; goto error_io; } return errno = 0; } } error_io: return -errno; } int tabby_printer_packet_send(tabby_printer *printer, tabby_printer_packet *header, void *body) { uint16_t sum = checksum(header, body); if (write(printer->fd, header, sizeof(*header)) < 0) { goto error_io; } if (header->size) { if (write(printer->fd, body, header->size) < 0) { goto error_io; } } if (write(printer->fd, &sum, sizeof(sum)) < 0) { goto error_io; } if (read(printer->fd, &printer->response, sizeof(printer->response)) < 0) { goto error_io; } return 0; error_io: return -1; } static void init_header(tabby_printer_packet *header, tabby_printer_packet_type type, size_t size) { header->preamble[0] = TABBY_PRINTER_SYNC_1; header->preamble[1] = TABBY_PRINTER_SYNC_2; header->type = type; header->compression = TABBY_PRINTER_COMPRESSION_NONE; header->size = (uint16_t)size; } int tabby_printer_init(tabby_printer *printer) { tabby_printer_packet header; init_header(&header, TABBY_PRINTER_PACKET_INIT, 0); return tabby_printer_packet_send(printer, &header, NULL); } int tabby_printer_inquiry_send(tabby_printer *printer) { tabby_printer_packet header; init_header(&header, TABBY_PRINTER_PACKET_INQUIRY, 0); return tabby_printer_packet_send(printer, &header, NULL); } int tabby_printer_job_start(tabby_printer *printer, uint8_t sheets, uint8_t linefeeds, uint8_t palette, uint8_t density) { tabby_printer_packet header; uint8_t body[4] = { sheets, linefeeds, palette, density }; init_header(&header, TABBY_PRINTER_PACKET_JOB, sizeof(body)); return tabby_printer_packet_send(printer, &header, &body); } int tabby_printer_job_cancel(tabby_printer *printer) { tabby_printer_packet header; init_header(&header, TABBY_PRINTER_PACKET_CANCEL, 0); return tabby_printer_packet_send(printer, &header, NULL); } int tabby_printer_job_wait(tabby_printer *printer) { do { sleep(1); if (tabby_printer_inquiry_send(printer) < 0) { goto error_inquiry_send; } } while (printer->status & TABBY_PRINTER_UNTRAN); return 0; error_inquiry_send: return -1; } int tabby_printer_band_send(tabby_printer *printer, uint8_t *band) { tabby_printer_packet header; init_header(&header, TABBY_PRINTER_PACKET_DATA, TABBY_PRINTER_BAND_SIZE); return tabby_printer_packet_send(printer, &header, band); } int tabby_printer_band_finish(tabby_printer *printer) { tabby_printer_packet header; init_header(&header, TABBY_PRINTER_PACKET_DATA, 0); return tabby_printer_packet_send(printer, &header, NULL); } int tabby_printer_sheet_send(tabby_printer *printer, void *data, uint16_t size) { uint16_t offset = 0; tabby_printer_packet header; while (offset < size) { init_header(&header, TABBY_PRINTER_PACKET_DATA, TABBY_PRINTER_BAND_SIZE); if (tabby_printer_packet_send(printer, &header, ((uint8_t *)data) + offset) < 0) { goto error_packet_send; } if (printer->status & TABBY_PRINTER_SUM) { tabby_printer_init(printer); offset = 0; continue; } offset += TABBY_PRINTER_BAND_SIZE; } init_header(&header, TABBY_PRINTER_PACKET_DATA, 0); return tabby_printer_packet_send(printer, &header, NULL); error_packet_send: return -1; }