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/eack.c

306 lines
9.4 KiB
C

/* ****************************************************************************
* link/seven/eack.c -- extended ACK management.
* 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/>.
* ************************************************************************* */
#include "../link.h"
#include <string.h>
/* ---
* Raw layout of an extended ack data.
* --- */
/* `hwid`: hardware identifier (ASCII);
* `cpuid`: processor identifier (ASCII);
*
* `preprog_rom_capacity`: preprogrammed ROM capacity (ASCII-DEC, KiB);
* `flash_rom_capacity`: flash ROM capacity (ASCII-DEC, KiB);
* `ram_capacity`: RAM capacity (ASCII-DEC, KiB);
*
* `preprog_rom_version`: preprogrammed ROM version.
* `bootcode_version`: bootcode version.
* `bootcode_offset`: bootcode offset (ASCII-HEX);
* `bootcode_size`: bootcode size (ASCII-HEX, KiB);
* `os_version`: OS version;
* `os_offset`: OS offset;
* `os_size`: OS size (ASCII-HEX, KiB);
*
* `protocol_version`: protocol version (x.xx, generally "7.00");
* `product_id`: product ID;
* `username`: name set by the user in SYSTEM (Oxffs if in exam mode).
*
* Versions are coded as "xx.xx.xxxx" + 0xff bytes. */
typedef struct {
unsigned char hwid[8];
unsigned char cpuid[16];
unsigned char preprog_rom_capacity[8];
unsigned char flash_rom_capacity[8];
unsigned char ram_capacity[8];
unsigned char preprog_rom_version[16];
unsigned char bootcode_version[16];
unsigned char bootcode_offset[8];
unsigned char bootcode_size[8];
unsigned char os_version[16];
unsigned char os_offset[8];
unsigned char os_size[8];
unsigned char protocol_version[4];
unsigned char product_id[16];
unsigned char username[16];
} packetdata_ackext_t;
/* ---
* Utilities.
* --- */
/**
* version_of_string:
* Get version from 16-bytes char buffer.
*
* data is not a string as it doesn't finish with an '\0'.
*
* @arg ver the version destination
* @arg data the raw version data ("xx.xx.xx" + type)
*/
CASIO_LOCAL void version_of_string(casio_version_t *ver,
unsigned char const *data)
{
casio_decode_version(ver, (const char*)data);
}
/**
* string_of_version:
* Put version in 16-bytes char buffer.
*
* @arg ver the version source.
* @arg data the raw version data destination ("xx.xx.xx" + type).
*/
CASIO_LOCAL void string_of_version(unsigned char *data,
casio_version_t const *ver)
{
casio_encode_version((char *)data, ver);
memset(&data[10], '\xFF', 6);
}
/* ---
* Send ACK packets.
* --- */
/**
* casio_seven_send_eack:
* Sends an extended ack.
*
* @arg handle the link handle
* @arg info the link information to return.
* @return the error code (0 if ok)
*/
int CASIO_EXPORT casio_seven_send_eack(casio_link_t *handle,
casio_link_info_t *info)
{
packetdata_ackext_t raw;
/* Initialize the structure with 0xFFs. */
memset(&raw, 0xFF, sizeof(packetdata_ackext_t));
/* Put in the structure. */
memcpy(raw.hwid, info->casio_link_info_hwid,
strnlen(info->casio_link_info_hwid, 8));
memcpy(raw.cpuid, info->casio_link_info_cpuid,
strnlen(info->casio_link_info_cpuid, 16));
if (info->casio_link_info_flags & casio_link_info_flag_preprog) {
casio_putascii(raw.preprog_rom_capacity,
info->casio_link_info_rom_capacity, 8);
string_of_version(raw.preprog_rom_version,
&info->casio_link_info_rom_version);
}
casio_putascii(raw.flash_rom_capacity,
casio_gethex(info->casio_link_info_flash_rom_capacity / 1024), 8);
casio_putascii(raw.ram_capacity,
casio_gethex(info->casio_link_info_ram_capacity / 1024), 8);
if (info->casio_link_info_flags & casio_link_info_flag_bootcode) {
string_of_version(raw.bootcode_version,
&info->casio_link_info_bootcode_version);
casio_putascii(raw.bootcode_offset,
info->casio_link_info_bootcode_offset, 8);
casio_putascii(raw.bootcode_size,
casio_gethex(info->casio_link_info_bootcode_size / 1024), 8);
}
if (info->casio_link_info_flags & casio_link_info_flag_os) {
string_of_version(raw.os_version, &info->casio_link_info_os_version);
casio_putascii(raw.os_offset, info->casio_link_info_os_offset, 8);
casio_putascii(raw.os_size,
casio_gethex(info->casio_link_info_os_size / 1024), 8);
}
memcpy(raw.protocol_version, "7.00", 4);
memcpy(raw.product_id, info->casio_link_info_product_id,
strnlen(info->casio_link_info_product_id, 16));
memcpy(raw.username, info->casio_link_info_username,
strnlen(info->casio_link_info_username, 16));
/* Send the packet. */
return (casio_seven_send_ext(handle, casio_seven_type_ack, 0x02, &raw,
sizeof(packetdata_ackext_t), 1));
}
/* ---
* Decode an ACK packet.
* --- */
/**
* cpy_string:
* Copy a string terminated with 0xFFs, with a maximum size.
*
* @arg dest the destination string.
* @arg src the source string.
* @arg n the maximum size of the string.
*/
CASIO_LOCAL void cpy_string(char *dest, const char *src, size_t n)
{
const char *l = memchr(src, 0xFF, n);
memset(dest, 0, n + 1);
memcpy(dest, src, l ? (size_t)(l - src) : n);
}
/**
* casio_seven_decode_ack:
* Get data from ack data field.
*
* Layout is described in the fxReverse projet documentation.
*
* @arg handle the handle
* @arg data the raw data
* @arg data_size the raw data size
* @return if there was an error
*/
int CASIO_EXPORT casio_seven_decode_ack(casio_link_t *handle,
const unsigned char *data, unsigned int data_size)
{
casio_seven_packet_t *packet = &handle->casio_link_response;
casio_link_info_t *info = &packet->casio_seven_packet_info;
const packetdata_ackext_t *d = (const void*)data;
/* Check the data size. */
msg((ll_info, "ack packet is extended"));
if (data_size != sizeof(packetdata_ackext_t)) {
msg((ll_warn, "eack extension is of invalid size?"));
return (1);
}
info->casio_link_info_flags = 0;
/* Hardware identifier, processor identifier. */
cpy_string(info->casio_link_info_hwid, (const char*)d->hwid, 8);
cpy_string(info->casio_link_info_cpuid, (const char*)d->cpuid, 16);
msg((ll_info, "hardware identifier is '%s'", info->casio_link_info_hwid));
msg((ll_info, "cpu identifier is '%s'", info->casio_link_info_cpuid));
/* Preprogrammed ROM information (valid, capacity, version). */
info->casio_link_info_rom_capacity =
casio_getascii(d->preprog_rom_capacity, 8) * 1000;
version_of_string(&info->casio_link_info_rom_version,
d->preprog_rom_version);
if (d->preprog_rom_version[2] != 0xFF) {
info->casio_link_info_flags |= casio_link_info_flag_preprog;
msg((ll_info, "preprogrammed ROM capacity is %luo",
info->casio_link_info_rom_capacity));
msg((ll_info, "Preprogrammed ROM version is %.10s",
d->preprog_rom_version));
} elsemsg((ll_info, "Preprogrammed ROM information looks wiped out!"))
/* Flash ROM and RAM capacities. */
info->casio_link_info_flash_rom_capacity =
casio_getdec(casio_getascii(d->flash_rom_capacity, 8)) * 1024;
info->casio_link_info_ram_capacity =
casio_getdec(casio_getascii(d->ram_capacity, 8)) * 1024;
msg((ll_info, "flash ROM capacity is %luKiB",
info->casio_link_info_flash_rom_capacity / 1024));
msg((ll_info, "RAM capacity is %luKiB",
info->casio_link_info_ram_capacity / 1024));
/* Bootcode information (valid, offset, size, version). */
version_of_string(&info->casio_link_info_bootcode_version,
d->bootcode_version);
info->casio_link_info_bootcode_offset =
casio_getascii(d->bootcode_offset, 8);
info->casio_link_info_bootcode_size =
casio_getdec(casio_getascii(d->bootcode_size, 8)) * 1024;
if (d->bootcode_version[2] != 0xFF) {
info->casio_link_info_flags |= casio_link_info_flag_bootcode;
msg((ll_info, "Bootcode version is %.10s", d->bootcode_version));
msg((ll_info, "bootcode offset is 0x%08lX",
info->casio_link_info_bootcode_offset));
msg((ll_info, "bootcode size is %luKiB",
info->casio_link_info_bootcode_size / 1024));
} elsemsg((ll_info, "Bootcode information looks wiped out!"))
/* OS information (valid, offset, size, version). */
version_of_string(&info->casio_link_info_os_version, d->os_version);
info->casio_link_info_os_offset = casio_getascii(d->os_offset, 8);
info->casio_link_info_os_size =
casio_getdec(casio_getascii(d->os_size, 8)) * 1024;
if (d->os_version[2] != 0xFF) {
info->casio_link_info_flags |= casio_link_info_flag_os;
msg((ll_info, "OS version is %.10s", d->os_version));
msg((ll_info, "OS offset is 0x%08lX" ,
info->casio_link_info_os_offset));
msg((ll_info, "OS size is %luKiB",
info->casio_link_info_os_size / 1024));
} elsemsg((ll_info, "OS information looks wiped out!"))
/* Product ID and username. */
cpy_string(info->casio_link_info_product_id,
(const char*)d->product_id, 16);
cpy_string(info->casio_link_info_username, (const char*)d->username, 16);
msg((ll_info, "product ID is %s", info->casio_link_info_product_id));
msg((ll_info, "username is %s", info->casio_link_info_username));
return (0);
}