static bool s_heart_hid_printer(ticket_printer_t *self) { if ((zclock_time() - self->hid_status_at) > 5000) { #ifdef __WIN32__ char *command = strdup("<S1>"); int ret = boca_hid_write(self->hid_printer, command, strlen(command)); free(command); enum BOCA_STATUS status = BOCA_OFFLINE; if (ret > 0) { zclock_sleep(500); status = boca_hid_status(self->hid_printer); self->event = EVENT_BOCA_WRITE_OK; s_state_machine(self); } else { self->event = EVENT_BOCA_WRITE_ERROR; s_state_machine(self); s_handle_boca_status(self, &status, true); } #else enum BOCA_FEATURE_REPORT_STATUS feature_status = boca_hid_status_feature(self->hid_printer); enum BOCA_STATUS status = boca_status_from_feature(feature_status); #endif s_handle_boca_status(self, &status, true); return true; } return false; }
static void s_restart_boca_serial(ticket_printer_t *self, const char *port) { boca_serial_destroy(&self->serial_printer); self->serial_printer = boca_serial_new(port); if (self->serial_printer == NULL) { zsys_warning("ticket printer: restart serial printer failed"); self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); } else { zsys_info("ticket printer: restart serial printer ok."); self->event = EVENT_BOCA_RESTARTED; s_state_machine(self); self->boca_serial_restart_count = 0; } }
static void s_restart_boca_hid(ticket_printer_t *self, const char *dev_path) { #ifdef __APPLE__ //for mac we have to rescan to bring boca back. zstr_send(self->printer_store_req,"SCANPRINTERS"); zstr_recv(self->printer_store_req); #endif boca_hid_destroy(&self->hid_printer); self->hid_printer = boca_hid_new(dev_path); if (self->hid_printer == NULL) { zsys_warning("ticket printer: restart hid printer failed"); self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); } else { zsys_warning("ticket printer: restart hid printer ok"); self->event = EVENT_BOCA_RESTARTED; s_state_machine(self); self->boca_hid_restart_count = 0; } }
static int reader_pipe_event(zloop_t *loop, zsock_t *reader, void *arg) { int ret = 0; ticket_printer_t *self = (ticket_printer_t *) arg; zmsg_t *request = zmsg_recv(self->pipe); if (!request) { return -1; } char *command = zmsg_popstr(request); if (self->verbose) { zsys_debug("ticket printer: API command %s", command); } if (streq(command, "$TERM")) { self->event = EVENT_TERM; s_state_machine(self); ret = -1; } else if (streq(command, "VERBOSE")) { self->verbose = true; if (self->hid_printer != NULL) boca_hid_set_verbose(self->hid_printer, self->verbose); #ifdef __WIN32__ if (self->serial_printer != NULL) boca_serial_set_verbose(self->serial_printer, self->verbose); #endif } else if (streq(command, "START")) { char *ticket_store_endpoint = zmsg_popstr(request); self->ticket_store_req = zsock_new_req(ticket_store_endpoint); zsys_info("ticket printer: ticket printer is using ticket store %s", ticket_store_endpoint); zstr_free(&ticket_store_endpoint); self->event = EVENT_TICKET_STORE_READY; s_state_machine(self); zsock_signal(self->pipe, 0); } else if (streq(command, "SETPRINTERSTORE")) { char *printer_store_ep = zmsg_popstr(request); self->printer_store_req = zsock_new_req(printer_store_ep); zstr_free(&printer_store_ep); zsock_signal(self->pipe, 0); } else if (streq(command, "SETDIAGNOSTIC")) { self->diagnostic = true; } zstr_free(&command); zmsg_destroy(&request); return ret; }
int main (int argc, char *argv []) { // Arguments can be either of: // -p primary server, at tcp://localhost:5001 // -b backup server, at tcp://localhost:5002 zctx_t *ctx = zctx_new (); void *statepub = zsocket_new (ctx, ZMQ_PUB); void *statesub = zsocket_new (ctx, ZMQ_SUB); zsockopt_set_subscribe (statesub, ""); void *frontend = zsocket_new (ctx, ZMQ_ROUTER); bstar_t fsm = { 0 }; if (argc == 2 && streq (argv [1], "-p")) { printf ("I: Primary master, waiting for backup (slave)\n"); zsocket_bind (frontend, "tcp://*:5001"); zsocket_bind (statepub, "tcp://*:5003"); zsocket_connect (statesub, "tcp://localhost:5004"); fsm.state = STATE_PRIMARY; } else if (argc == 2 && streq (argv [1], "-b")) { printf ("I: Backup slave, waiting for primary (master)\n"); zsocket_bind (frontend, "tcp://*:5002"); zsocket_bind (statepub, "tcp://*:5004"); zsocket_connect (statesub, "tcp://localhost:5003"); fsm.state = STATE_BACKUP; } else { printf ("Usage: bstarsrv { -p | -b }\n"); zctx_destroy (&ctx); exit (0); } // Set timer for next outgoing state message int64_t send_state_at = zclock_time () + HEARTBEAT; while (!zctx_interrupted) { zmq_pollitem_t items [] = { { frontend, 0, ZMQ_POLLIN, 0 }, { statesub, 0, ZMQ_POLLIN, 0 } }; int time_left = (int) ((send_state_at - zclock_time ())); if (time_left < 0) time_left = 0; int rc = zmq_poll (items, 2, time_left * ZMQ_POLL_MSEC); if (rc == -1) break; // Context has been shut down if (items [0].revents & ZMQ_POLLIN) { // Have a client request zmsg_t *msg = zmsg_recv (frontend); fsm.event = CLIENT_REQUEST; if (s_state_machine (&fsm) == FALSE) // Answer client by echoing request back zmsg_send (&msg, frontend); else zmsg_destroy (&msg); } if (items [1].revents & ZMQ_POLLIN) { // Have state from our peer, execute as event char *message = zstr_recv (statesub); fsm.event = atoi (message); free (message); if (s_state_machine (&fsm)) break; // Error, so exit fsm.peer_expiry = zclock_time () + 2 * HEARTBEAT; } // If we timed-out, send state to peer if (zclock_time () >= send_state_at) { char message [2]; sprintf (message, "%d", fsm.state); zstr_send (statepub, message); send_state_at = zclock_time () + HEARTBEAT; } } if (zctx_interrupted) printf ("W: interrupted\n"); // Shutdown sockets and context zctx_destroy (&ctx); return 0; }
static void s_print_tix(ticket_printer_t *self, bool serial) { #ifdef __WIN32__ if (serial && self->serial_printer == NULL) return; #endif if (!serial && self->hid_printer == NULL) return; bool is_stop = false; int queue_size = serial ? TICKET_PRINTING_SIZE_SERIAL : TICKET_PRINTING_SIZE; while (self->tix_counter < queue_size && !is_stop) { int bytes_written = 0; char count_str[15]; sprintf(count_str, "%d", queue_size - self->tix_counter); zstr_sendx(self->ticket_store_req, "GETNEXTTICKETS", self->last_token, count_str, NULL); zpoller_t *poller = zpoller_new(self->ticket_store_req, NULL); zsock_t *reader = zpoller_wait(poller, 800); if (reader == NULL) { is_stop = true; } else { zmsg_t *msg = zmsg_recv(self->ticket_store_req); char *result = zmsg_popstr(msg); if (streq(result, "OK")) { char *count_str_resp = zmsg_popstr(msg); int tix_count = atoi(count_str_resp); zsys_info("ticket printer: read %d tix back", tix_count); while (tix_count > 0) { char *group = zmsg_popstr(msg); char *token = zmsg_popstr(msg); char *data = zmsg_popstr(msg); char *seq = zmsg_popstr(msg); zsys_info("ticket printer: sending tix %s to BOCA", seq); if (self->diagnostic) { char diagnostic_fgl[100] = {'\0'}; sprintf(diagnostic_fgl, "<RR><RC25,1050><F2>S_%s", seq); #ifdef __WIN32__ serial ? boca_serial_write(self->serial_printer, diagnostic_fgl) : boca_hid_write( self->hid_printer, diagnostic_fgl, strlen(diagnostic_fgl)); #else boca_hid_write( self->hid_printer, diagnostic_fgl, strlen(diagnostic_fgl)); #endif } #ifdef __WIN32__ bytes_written = serial ? boca_serial_write(self->serial_printer, data) : boca_hid_write( self->hid_printer, data, strlen(data)); #else bytes_written = boca_hid_write( self->hid_printer, data, strlen(data)); #endif if (bytes_written > 0) { self->tix_counter++; self->event = EVENT_BOCA_WRITE_OK; s_state_machine(self); } else { zsys_warning("ticket printer: can not write fgl to hid printer"); self->event = EVENT_BOCA_WRITE_ERROR; s_state_machine(self); is_stop = true; } free(self->last_token); self->last_token = strdup(token); zstr_free(&group); zstr_free(&token); zstr_free(&data); zstr_free(&seq); tix_count--; } zstr_free(&count_str_resp); } else { is_stop = true; } zstr_free(&result); zmsg_destroy(&msg); } zpoller_destroy(&poller); } }
static void s_handle_boca_status(ticket_printer_t *self, enum BOCA_STATUS *status, bool is_hid) { switch ((*status)) { case BOCA_TICKET_ACK: zstr_send(self->ticket_store_req, "TICKETPRINTED"); char *code = zstr_recv(self->ticket_store_req); if (code != NULL && streq(code, "OK")) { self->tix_counter--; } if (code != NULL) zstr_free(&code); self->event = EVENT_BOCA_ACK; s_state_machine(self); break; case BOCA_INVALID_CHECKSUM: self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); break; case BOCA_OUT_OF_PAPER: self->event = EVENT_BOCA_OOP; s_state_machine(self); break; case BOCA_X_ON: self->event = EVENT_BOCA_READY; s_state_machine(self); break; case BOCA_POWER_ON: self->state = STATE_IDLE; break; case BOCA_X_OFF: self->event = EVENT_BOCA_BUSY; s_state_machine(self); break; case BOCA_NAK: self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); break; case BOCA_PAPER_JAM: self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); break; case BOCA_ILLEGAL_DATA: self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); break; case BOCA_POWERUP_PROBLEM: self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); break; case BOCA_DOWNLOADING_ERROR: self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); break; case BOCA_CUTTER_JAM: self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); break; case BOCA_STUCK_TICKET: self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); break; case BOCA_UNKNOWN: break; case BOCA_OFFLINE: self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); break; case BOCA_GENERAL_ERROR: self->event = EVENT_BOCA_ERROR_STATUS; s_state_machine(self); break; } if (self->printer_store_req != NULL && (*status) != BOCA_UNKNOWN) { char str_status[5]; sprintf(str_status, "%d", boca_status_to_int((*status))); if (is_hid) { zstr_sendx(self->printer_store_req, "SETHIDPRINTERSTATUS", self->boca_hid_device_path, str_status, NULL); zmsg_t *resp = zmsg_recv(self->printer_store_req); char *result = zmsg_popstr(resp); if (streq(result, "FAIL")) { zsys_warning("ticket printer: could not update hid printer %s status %s", self->boca_hid_device_path, boca_status_display((*status))); } else { self->hid_status_at = zclock_time(); } zmsg_destroy(&resp); } #ifdef __WIN32__ else { zstr_sendx(self->printer_store_req, "SETSERIALPRINTERSTATUS", self->serial_printer->port, str_status, NULL); zmsg_t *resp = zmsg_recv(self->printer_store_req); char *result = zmsg_popstr(resp); if (streq(result, "FAIL")) { zsys_warning("ticket printer: could not update serial printer %s status %s", self->serial_printer->port, boca_status_display((*status))); } else { if (self->verbose) zsys_debug("ticket printer: update serial printer %s status %s", self->serial_printer->port, boca_status_display((*status))); self->serial_status_at = zclock_time(); } zmsg_destroy(&resp); } #endif } }