/* **************************************************************************** * link/seven/send.c -- prepare and send a packet. * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey * * This file is part of libcasio. * libcasio is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3.0 of the License, * or (at your option) any later version. * * libcasio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libcasio; if not, see . * * These functions are the one used behind the others to send a packet. * ************************************************************************* */ #include "../link.h" #include #include #define checksub8(BUF, SIZE) \ casio_checksum_sub(&((char*)(BUF))[1], (SIZE) - 3, 0) /* Internal macros. */ #define buffer \ handle->casio_link_send_buffers[handle->casio_link_flags \ & casio_linkflag_sendalt] #define buffer_size \ handle->casio_link_send_buffers_size[handle->casio_link_flags \ & casio_linkflag_sendalt] #define switch_buffer() \ if (handle->casio_link_flags & casio_linkflag_shifted) \ handle->casio_link_flags = \ ( handle->casio_link_flags & ~casio_linkflag_sendalt) | \ (~handle->casio_link_flags & casio_linkflag_sendalt); /* --- * Main functions. * --- */ /** * casio_seven_send_buf: * Send a buffer. * * @arg handle the link handle * @arg buf the buffer to send (NULL if normal buffer) * @arg bufsize the buffer size * @arg resp check response (is yes for 99.9% of the cases) * @return if worked (0 if none) */ CASIO_LOCAL int casio_seven_send_buf(casio_link_t *handle, const unsigned char *buf, size_t bufsize, int resp) { int err; int wasresend = 0, resp_err = 0, retries = 3; /* check if handler is initialized */ if (!handle) return (casio_error_init); /* check if user wants to shift * with hack: if `buf` is non-NULL, we simply want to send * a custom packet */ if (!buf && !resp) { if (handle->casio_link_flags & casio_linkflag_shifted) return (casio_error_shift); else handle->casio_link_flags |= casio_linkflag_shifted; } /* get buffer */ if (!buf) { buf = buffer; bufsize = buffer_size; } /* sending loop */ while (1) { /* log resend request */ if (wasresend) { if (--retries < 0) { msg((ll_error, "Three retries in a row? Something is wrong.")); return (casio_error_damned); } switch_buffer(); buf = buffer; bufsize = buffer_size; msg((ll_warn, "resend request was received, resend it goes")); } /* send prepared packet */ err = casio_write(handle->casio_link_stream, buf, bufsize, 0); if (err) return (err); /* set wasreset for logging */ wasresend = 1; /* check if we want an answer */ if (!resp) break; if ((resp_err = casio_seven_receive(handle, 1))) break; if (response.casio_seven_packet_type == casio_seven_type_nak && response.casio_seven_packet_code == casio_seven_err_resend) continue; break; } /* packet sending is finished */ if (!resp_err && handle->casio_link_curr_type == casio_seven_type_swp) handle->casio_link_flags &= ~casio_linkflag_active; return (resp_err); } /** * casio_seven_send_basic: * Send a non-extended packet. * * @arg handle the link handle * @arg type the packet type * @arg subtype the packet subtype * @arg resp check response (is yes for 99.9% of the cases) * @return if worked (0 if none) */ int CASIO_EXPORT casio_seven_send_basic(casio_link_t *handle, casio_seven_type_t type, unsigned int subtype, int resp) { /* change buffer and prepare packet */ switch_buffer(); buffer[0] = (unsigned char)type; casio_putascii(&buffer[1], subtype, 2); buffer[3] = '0'; casio_putascii(&buffer[4], checksub8(buffer, 6), 2); buffer_size = 6; /* log packet */ msg((ll_info, "sending the following basic packet :")); mem((ll_info, buffer, buffer_size)); /* send it */ handle->casio_link_curr_type = type; return (casio_seven_send_buf(handle, NULL, 0, resp)); } /** * casio_seven_send_ext: * Send an extended packet. * * @arg handle the link handle * @arg type the packet type * @arg subtype the packet subtype * @arg data the packet data * @arg size the packet data size * @arg resp check response (is yes for 99.9% of the cases) * @return if it worked */ int CASIO_EXPORT casio_seven_send_ext(casio_link_t *handle, casio_seven_type_t type, unsigned int subtype, const void *data, unsigned int size, int resp) { /* check if should be a binary zero at end of packet */ int binary_zero = (type == casio_seven_type_cmd && subtype == casio_seven_cmdosu_upandrun); /* change buffer and prepare packet */ switch_buffer(); /* - first infos - */ buffer[0] = (unsigned char)type; casio_putascii(&buffer[1], subtype, 2); buffer[3] = '1'; /* - data - */ size = casio_seven_encoderaw(&buffer[8], data, size); casio_putascii(&buffer[4], size, 4); /* - checksum - */ casio_putascii(&buffer[8 + size], checksub8(buffer, 8 + size + 2), 2); buffer_size = 8 + size + 2; if (binary_zero) { buffer[buffer_size] = 0; buffer_size++; } /* log packet */ msg((ll_info, "sending the following extended packet :")); mem((ll_info, buffer, buffer_size)); /* send it */ handle->casio_link_curr_type = type; return (casio_seven_send_buf(handle, NULL, 0, resp)); } /** * casio_seven_send_again: * Send the last packet again. * * Useful for when resending wasn't managed in one of the previous functions. * Only used for unshifting right now. * * @arg handle the link handle * @return if it worked */ int CASIO_EXPORT casio_seven_send_again(casio_link_t *handle) { /* log packet */ msg((ll_info, "sending again the following packet :")); mem((ll_info, buffer, buffer_size)); /* send it */ return (casio_seven_send_buf(handle, NULL, 0, 1)); } /* --- * Special packets. * --- */ /** * casio_seven_send_err_resend: * Resend the resend error. * * @arg handle the handle to send the resend error for. * @return the error code (0 if ok). */ int CASIO_EXPORT casio_seven_send_err_resend(casio_link_t *handle) { static const unsigned char resend_buf[] = {casio_seven_type_nak, '0', '1', '0', '6', 'F', 0}; /* send packet */ msg((ll_info, "sending resend packet:")); mem((ll_info, resend_buf, 6)); return (casio_seven_send_buf(handle, resend_buf, 6, 0)); } /** * casio_seven_send_timeout_check: * Send a timeout check. * * @arg handle the handle to send the timeout check for. * @return the error code (0 if ok). */ int CASIO_EXPORT casio_seven_send_timeout_check(casio_link_t *handle) { static const unsigned char check_buf[] = {casio_seven_type_chk, '0', '1', '0', '6', 'F', 0}; /* send packet */ msg((ll_info, "sending timeout check packet:")); mem((ll_info, check_buf, 6)); return (casio_seven_send_buf(handle, check_buf, 6, 0)); }