cake
/
libcasio
Archived
1
1
Fork 0
This repository has been archived on 2024-03-16. You can view files and clone it, but cannot push or open issues or pull requests.
libcasio/lib/link/seven/command.c

335 lines
9.5 KiB
C

/* ****************************************************************************
* link/seven/command.c -- the command utilities.
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* 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 <http://www.gnu.org/licenses/>.
*
* Actually, most of the commands have the same format, so most are inline
* functions defined in `libcasio/packetio.h`. These are the functions for the
* general format, and the commands with custom formats.
* ************************************************************************* */
#include "../link.h"
#include <stdlib.h>
#include <string.h>
/* ---
* Logging.
* --- */
/**
* getowstring:
* Get overwrite string (useful for logging).
*
* @arg code overwrite code
* @return the string
*/
CASIO_LOCAL const char* getowstring(casio_seven_ow_t code)
{
static const char *moo[] = {
"request confirmation before overwriting",
"terminate if file exists",
"force overwrite"
};
if (code > 0x02) return ("<unknown overwriting mode>");
return (moo[code]);
}
/* ---
* Macros.
* --- */
/* if command is not supported, return. */
#define CHECK_IF_COMMAND_IS_SUPPORTED(N) \
if (!command_is_supported(N)) \
return (casio_error_op);
/**
* casio_seven_send_cmd:
* Send command packet without data field.
*
* Used to perform or request actions. The subtype selects the action.
*
* @arg handle the link handle
* @arg subtype the subcommand
* @return if it worked
*/
int CASIO_EXPORT casio_seven_send_cmd(casio_link_t *handle,
unsigned int subtype)
{
CHECK_IF_COMMAND_IS_SUPPORTED(subtype)
/* save last sent command */
handle->casio_link_last_command = subtype;
/* send */
return (casio_seven_send_basic(handle, casio_seven_type_cmd, subtype, 1));
}
/**
* casio_seven_send_cmd_data:
* Send command packet with data field.
*
* Used to perform or request actions. The subtype selects the action.
*
* @arg handle the link handle
* @arg subtype The subcommand
* @arg overwrite Mode of operation if a file exists
* @arg datatype MCS data type
* @arg filesize the filesize
* @arg arg1 first command argument
* @arg arg2 second command argument
* @arg arg3 third command argument
* @arg arg4 fourth command argument
* @arg arg5 fifth command argument
* @arg arg6 sixth command argument
* @return if it worked
*/
int CASIO_EXPORT casio_seven_send_cmd_data(casio_link_t *handle,
unsigned int subtype, int overwrite,
unsigned int datatype, unsigned long filesize,
const char *arg1, const char *arg2, const char *arg3,
const char *arg4, const char *arg5, const char *arg6)
{
unsigned char buf[120 /* 24 + 96 */], *b;
unsigned int buflen;
size_t l1, l2, l3, l4, l5, l6;
CHECK_IF_COMMAND_IS_SUPPORTED(subtype)
handle->casio_link_last_command = subtype;
/* get args length */
l1 = arg1 ? strlen(arg1) : 0;
l2 = arg2 ? strlen(arg2) : 0;
l3 = arg3 ? strlen(arg3) : 0;
l4 = arg4 ? strlen(arg4) : 0;
l5 = arg5 ? strlen(arg5) : 0;
l6 = arg6 ? strlen(arg6) : 0;
if (l1 > 16 || l2 > 16 || l3 > 16 || l4 > 16 || l5 > 16 || l6 > 16)
return (casio_error_op);
/* prepare data buffer */
buflen = (unsigned int)(24 + l1 + l2 + l3 + l4 + l5 + l6);
/* put info */
casio_putascii(buf, overwrite, 2);
casio_putascii(&buf[2], datatype, 2);
casio_putascii(&buf[4], filesize, 8);
casio_putascii(&buf[12], l1, 2);
casio_putascii(&buf[14], l2, 2);
casio_putascii(&buf[16], l3, 2);
casio_putascii(&buf[18], l4, 2);
casio_putascii(&buf[20], l5, 2);
casio_putascii(&buf[22], l6, 2);
/* put strings */
b = &buf[24];
memcpy(b, arg1, l1); b += l1;
memcpy(b, arg2, l2); b += l2;
memcpy(b, arg3, l3); b += l3;
memcpy(b, arg4, l4); b += l4;
memcpy(b, arg5, l5); b += l5;
memcpy(b, arg6, l6);
/* send */
return (casio_seven_send_ext(handle,
casio_seven_type_cmd, subtype, buf, buflen, 1));
}
/* ---
* Typical MCS command.
* --- */
/**
* casio_seven_send_typical_mcs_command:
* Send a typical MCS command.
*
* @arg handle the link handle.
* @arg code the command code.
* @arg head the MCS head.
* @arg file the file.
* @arg ow the overwrite.
* @return the error code (0 if ok).
*/
int CASIO_EXPORT casio_seven_send_typical_mcs_command(casio_link_t *handle,
int code, casio_mcshead_t *head, casio_mcsfile_t *file, int ow)
{
unsigned long sz = 0;
/* FIXME: get the file size when not NULL */
(void)file;
return (casio_seven_send_cmd_data(handle, code, ow,
head->casio_mcshead_rawtype, sz,
head->casio_mcshead_dirname, head->casio_mcshead_name,
head->casio_mcshead_group, NULL, NULL, NULL));
}
/* ---
* Special commands.
* --- */
/**
* casio_seven_send_cmdsys_setlink:
* Set link settings.
*
* @arg handle the link handle.
* @arg baudrate the baud rate.
* @arg parity the parity (0 for none, 1 for odd, 2 for even).
* @arg stopbits the number of stop bits (1 or 2).
* @return if it worked.
*/
int CASIO_EXPORT casio_seven_send_cmdsys_setlink(casio_link_t *handle,
int baudrate, int parity, int stopbits)
{
char sbaud[10], sparity[10], sstopbits[2];
/* check if is a serial connexion */
if (~casio_get_openmode(handle->casio_link_stream) & CASIO_OPENMODE_SERIAL)
return (casio_error_op);
/* make arguments */
sprintf(sbaud, "%d",
baudrate >= 0 && baudrate < 1000000 ? baudrate : 9600);
sprintf(sstopbits, "%d", (stopbits >= 2) + 1);
if (!parity) strcpy(sparity, "NONE");
else if (parity % 2) strcpy(sparity, "ODD");
else strcpy(sparity, "EVEN");
/* send the command and receive answer */
return (casio_seven_send_cmd_data(handle, casio_seven_cmdsys_setlink,
0, 0, 0, sbaud, sparity, sstopbits, NULL, NULL, NULL));
}
/**
* casio_seven_send_cmdosu_upandrun:
* Upload and run a binary.
*
* Risky and can only be interpreted by bootcode (OS Update mode).
*
* @arg handle the link handle
* @arg upsize the uploaded file size
* @arg loadaddr the load address (usually 0x88030000)
* @arg straddr the start adress (usually 0x88030000)
* @return if it worked
*/
int CASIO_EXPORT casio_seven_send_cmdosu_upandrun(casio_link_t *handle,
unsigned long upsize, unsigned long loadaddr, unsigned long straddr)
{
unsigned char buf[24];
CHECK_IF_COMMAND_IS_SUPPORTED(casio_seven_cmdosu_upandrun)
handle->casio_link_last_command = casio_seven_cmdosu_upandrun;
/* put info */
casio_putascii(&buf[0], upsize, 8);
casio_putascii(&buf[8], loadaddr, 8);
casio_putascii(&buf[16], straddr, 8);
/* send packet */
return (casio_seven_send_ext(handle, casio_seven_type_cmd,
casio_seven_cmdosu_upandrun, buf, 24, 1));
}
/* ---
* Decode incoming packet.
* --- */
/* Macro to copy an argument into the packet. */
#define cpy_arg(I) { \
size_t ALEN = arglengths[I]; \
memcpy(packet->casio_seven_packet__argsdata[I], p, ALEN); \
packet->casio_seven_packet__argsdata[I][ALEN] = 0; \
packet->casio_seven_packet_args[I] = ALEN ? \
packet->casio_seven_packet__argsdata[I] : NULL; \
p += ALEN; \
\
msg((ll_info, "D%d is '%s'", I, packet->casio_seven_packet_args[I])); }
/**
* casio_seven_decode_command:
* Get data from command data field.
*
* Layout is described in the fxReverse projet documentation.
*
* @arg handle the link handle
* @arg raw the raw data
* @arg raw_size the raw data size
* @return if there was an error
*/
int CASIO_EXPORT casio_seven_decode_command(casio_link_t *handle,
const unsigned char *raw, unsigned int raw_size)
{
casio_seven_packet_t *packet = &handle->casio_link_response;
size_t arglengths[6], total_args;
const unsigned char *p;
/* check up_and_run command */
if (packet->casio_seven_packet_code == casio_seven_cmdosu_upandrun) {
if (raw_size != 12) return (1);
packet->casio_seven_packet_uploadsize = casio_getascii(raw, 4);
packet->casio_seven_packet_loadaddr = casio_getascii(&raw[4], 4);
packet->casio_seven_packet_straddr = casio_getascii(&raw[8], 4);
return (0);
}
/* check minimum size */
if (raw_size < 24) return (1);
/* get overwrite */
packet->casio_seven_packet_ow = casio_getascii(raw, 2);
msg((ll_info, "overwrite mode is '%s' (0x%02x)",
getowstring(packet->casio_seven_packet_ow),
packet->casio_seven_packet_ow));
/* get data type */
packet->casio_seven_packet_mcstype = casio_getascii(&raw[2], 2);
msg((ll_info, "datatype is 0x%02x", packet->casio_seven_packet_mcstype));
/* filesize */
packet->casio_seven_packet_filesize = casio_getascii(&raw[4], 8);
msg((ll_info, "filesize is %lo", packet->casio_seven_packet_filesize));
/* args length */
arglengths[0] = casio_getascii(&raw[12], 2);
arglengths[1] = casio_getascii(&raw[14], 2);
arglengths[2] = casio_getascii(&raw[16], 2);
arglengths[3] = casio_getascii(&raw[18], 2);
arglengths[4] = casio_getascii(&raw[20], 2);
arglengths[5] = casio_getascii(&raw[22], 2);
total_args = arglengths[0] + arglengths[1]
+ arglengths[2] + arglengths[3] + arglengths[4]
+ arglengths[5];
/* re-check size */
if (raw_size != 24 + total_args) return (1);
/* copy the arguments */
p = &raw[24];
cpy_arg(0) cpy_arg(1) cpy_arg(2)
cpy_arg(3) cpy_arg(4) cpy_arg(5)
/* it worked */
return (0);
}