267 lines
8.2 KiB
C
267 lines
8.2 KiB
C
/* *****************************************************************************
|
|
* protocol/seven/command.c -- the command utilities.
|
|
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
|
*
|
|
* This file is part of libp7.
|
|
* libp7 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.
|
|
*
|
|
* libp7 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 libp7; if not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Actually, most of the commands have the same format, so most are inline
|
|
* functions defined in `libp7/packetio.h`. These are the functions for the
|
|
* general format, and the commands with custom formats.
|
|
* ************************************************************************** */
|
|
#include <libp7/internals.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* ************************************************************************** */
|
|
/* Macros */
|
|
/* ************************************************************************** */
|
|
/* if command is not supported, return */
|
|
#define CHECK_IF_COMMAND_IS_SUPPORTED(N) \
|
|
if (!command_is_supported(N)) \
|
|
return (p7_error_unsupported);
|
|
|
|
/**
|
|
* p7_send_cmd:
|
|
* Send command packet without data field.
|
|
*
|
|
* Used to perform or request actions. The subtype selects the action.
|
|
*
|
|
* @arg handle the libp7 handle
|
|
* @arg subtype the subcommand
|
|
* @return if it worked
|
|
*/
|
|
|
|
int p7_send_cmd(p7_handle_t *handle, p7ushort_t subtype)
|
|
{
|
|
CHECK_IF_COMMAND_IS_SUPPORTED(subtype)
|
|
|
|
/* save last sent command */
|
|
handle->_last_sent_command = subtype;
|
|
|
|
/* send */
|
|
return (p7_send_basic(handle, p7_pt_cmd, subtype, 1));
|
|
}
|
|
|
|
/**
|
|
* p7_send_cmd_data:
|
|
* Send command packet with data field.
|
|
*
|
|
* Used to perform or request actions. The subtype selects the action.
|
|
*
|
|
* @arg handle the libp7 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 p7_send_cmd_data(p7_handle_t *handle, p7ushort_t subtype,
|
|
int overwrite, p7ushort_t datatype, p7uint_t filesize,
|
|
const char *arg1, const char *arg2, const char *arg3,
|
|
const char *arg4, const char *arg5, const char *arg6)
|
|
{
|
|
CHECK_IF_COMMAND_IS_SUPPORTED(subtype)
|
|
|
|
/* save last sent command */
|
|
handle->_last_sent_command = subtype;
|
|
|
|
/* get args length */
|
|
size_t l1 = arg1 ? strlen(arg1) : 0;
|
|
size_t l2 = arg2 ? strlen(arg2) : 0;
|
|
size_t l3 = arg3 ? strlen(arg3) : 0;
|
|
size_t l4 = arg4 ? strlen(arg4) : 0;
|
|
size_t l5 = arg5 ? strlen(arg5) : 0;
|
|
size_t l6 = arg6 ? strlen(arg6) : 0;
|
|
|
|
/* prepare data buffer */
|
|
unsigned int buflen = (unsigned int)(24 + l1 + l2 + l3 + l4 + l5 + l6);
|
|
unsigned char buf[buflen];
|
|
|
|
/* put info */
|
|
p7_putascii(buf, overwrite, 2);
|
|
p7_putascii(&buf[2], datatype, 2);
|
|
p7_putascii(&buf[4], filesize, 8);
|
|
p7_putascii(&buf[12], l1, 2);
|
|
p7_putascii(&buf[14], l2, 2);
|
|
p7_putascii(&buf[16], l3, 2);
|
|
p7_putascii(&buf[18], l4, 2);
|
|
p7_putascii(&buf[20], l5, 2);
|
|
p7_putascii(&buf[22], l6, 2);
|
|
|
|
/* put strings */
|
|
unsigned char *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 (p7_send_ext(handle, p7_pt_cmd, subtype, buf, buflen, 1));
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* Special commands */
|
|
/* ************************************************************************** */
|
|
/**
|
|
* p7_send_cmdsys_setlink:
|
|
* Set link settings.
|
|
*
|
|
* No input validation: we're trusting the user here.
|
|
*
|
|
* @arg handle the libp7 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 p7_send_cmdsys_setlink(p7_handle_t *handle,
|
|
int baudrate, int parity, int stopbits)
|
|
{
|
|
/* check if is a serial connexion */
|
|
if (~handle->_flags & p7_intflag_serial) return (p7_error_unsupported);
|
|
|
|
/* make arguments */
|
|
char sbaud[10], sparity[10], sstopbits[2];
|
|
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 (p7_send_cmd_data(handle, 0x02, 0, 0, 0,
|
|
sbaud, sparity, sstopbits, NULL, NULL, NULL));
|
|
}
|
|
|
|
/**
|
|
* p7_send_cmdosu_upandrun:
|
|
* Upload and run a binary.
|
|
*
|
|
* Risky and can only be interpreted by bootcode (OS Update mode).
|
|
*
|
|
* @arg handle the libp7 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 p7_send_cmdosu_upandrun(p7_handle_t *handle,
|
|
p7uint_t upsize, p7uint_t loadaddr, p7uint_t straddr)
|
|
{
|
|
CHECK_IF_COMMAND_IS_SUPPORTED(0x56)
|
|
|
|
/* save last sent command */
|
|
handle->_last_sent_command = 0x56;
|
|
|
|
/* prepare data buffer */
|
|
unsigned int buflen = 8 + 8 + 8;
|
|
unsigned char buf[buflen];
|
|
|
|
/* put info */
|
|
p7_putascii(buf, upsize, 8);
|
|
p7_putascii(&buf[8], loadaddr, 8);
|
|
p7_putascii(&buf[16], straddr, 8);
|
|
|
|
/* send packet */
|
|
return (p7_send_ext(handle, p7_pt_cmd, 0x56, buf, buflen, 1));
|
|
}
|
|
|
|
/* ************************************************************************** */
|
|
/* Decode incoming packet */
|
|
/* ************************************************************************** */
|
|
/* macro to copy an argument into the packet */
|
|
#define cpy_arg(I) { \
|
|
size_t ALEN = arglengths[I]; \
|
|
memcpy(packet->_argsdata[I], p, ALEN); \
|
|
packet->_argsdata[I][ALEN] = 0; \
|
|
packet->args[I] = ALEN ? packet->_argsdata[I] : NULL; \
|
|
p += ALEN; \
|
|
\
|
|
log_info("D%d is '%s'", I, packet->args[I]); }
|
|
|
|
/**
|
|
* p7_decode_command:
|
|
* Get data from command data field.
|
|
*
|
|
* Layout is described in the fxReverse projet documentation.
|
|
*
|
|
* @arg handle the handle
|
|
* @arg raw the raw data
|
|
* @arg raw_size the raw data size
|
|
* @return if there was an error
|
|
*/
|
|
|
|
int p7_decode_command(p7_handle_t *handle,
|
|
const unsigned char *raw, size_t raw_size)
|
|
{
|
|
p7_packet_t *packet = &handle->_response;
|
|
/* check up_and_run command */
|
|
if (packet->code == 0x56) {
|
|
if (raw_size != 12) return (1);
|
|
packet->uploadsize = p7_getascii(raw, 4);
|
|
packet->loadaddr = p7_getascii(&raw[4], 4);
|
|
packet->straddr = p7_getascii(&raw[8], 4);
|
|
return (0);
|
|
}
|
|
|
|
/* check minimum size */
|
|
if (raw_size < 24) return (1);
|
|
|
|
/* get overwrite */
|
|
packet->ow = p7_getascii(raw, 2);
|
|
log_info("overwrite mode is '%s' (0x%02x)",
|
|
p7_getowstring(packet->ow), packet->ow);
|
|
|
|
/* get data type (?) */
|
|
packet->mcstype = p7_getascii(&raw[2], 2);
|
|
log_info("datatype is *todo: put MCS datatypes* (0x%02x)", packet->mcstype);
|
|
|
|
/* filesize */
|
|
packet->filesize = p7_getascii(&raw[4], 8);
|
|
log_info("filesize is %" PRIuP7INT "o", packet->filesize);
|
|
|
|
/* args length */
|
|
size_t arglengths[6] = {
|
|
p7_getascii(&raw[12], 2), p7_getascii(&raw[14], 2),
|
|
p7_getascii(&raw[16], 2), p7_getascii(&raw[18], 2),
|
|
p7_getascii(&raw[20], 2), p7_getascii(&raw[22], 2)
|
|
};
|
|
size_t 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 */
|
|
const unsigned char *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);
|
|
}
|