libcasio/include/libcasio/protocol/seven.h

414 lines
19 KiB
C

/* ****************************************************************************
* libcasio/protocol/seven.h -- CASIO's latest protocol.
* 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/>.
* ************************************************************************* */
#ifndef LIBCASIO_PROTOCOL_SEVEN_H
# define LIBCASIO_PROTOCOL_SEVEN_H
# include <libcasio/cdefs.h>
# include <libcasio/link.h>
# include <libcasio/protocol/typz.h>
CASIO_BEGIN_NAMESPACE
/* ************************************************************************* */
/* Packets */
/* ************************************************************************* */
/* Protocol 7.00 (the latest proprietary protocol from CASIO) is a protocol
* using several-bytes packets. Every packet, with one exception we'll detail
* later, contains a type, a subtype, an optional payload, and a checksum.
*
* Here are the known packet types: */
typedef enum casio_seven_type_e {
casio_seven_type_cmd = 0x01, /* ask something (initiate packet flow) */
casio_seven_type_data = 0x02, /* send some data */
casio_seven_type_swp = 0x03, /* change roles */
casio_seven_type_chk = 0x05, /* check if there is an interlocutor */
casio_seven_type_ack = 0x06, /* acknowledge ('okay') */
casio_seven_type_ohp = 0x0B, /* screenstreaming packet */
casio_seven_type_nak = 0x15, /* acknowledge negatively ('nope') */
casio_seven_type_end = 0x18 /* end the communication */
} casio_seven_type_t;
/* The subtype has a different meaning according to the type it is used with.
* For check packets, it can mean: */
# define casio_seven_chk_ini 0x00 /* initial check */
# define casio_seven_chk_wait 0x01 /* in-communication check, while waiting */
/* For ACK packets: */
# define casio_seven_ack_normal 0x00 /* normal ACK */
# define casio_seven_ack_ow 0x01 /* confirm overwrite */
# define casio_seven_ack_ext 0x02 /* extended ACK */
# define casio_seven_ack_term 0x03 /* ACK, end the communication (0x56) */
/* For NAK packets (error packets): */
typedef enum casio_seven_err_e {
casio_seven_err_default = 0x00, /* default error (unused?) */
casio_seven_err_resend = 0x01, /* checksum/timeout error, resend:
* please let the library use it. */
casio_seven_err_overwrite = 0x02, /* server response: confirm ow? */
casio_seven_err_dont_overwrite = 0x03, /* denial */
casio_seven_err_other = 0x04, /* generic error (other errors) */
casio_seven_err_fullmem = 0x05 /* full memory (terminates!) */
} casio_seven_err_t;
/* For END packets (terminate packets): */
typedef enum casio_seven_term_e {
casio_seven_term_default = 0x00, /* normal termination */
casio_seven_term_user = 0x01, /* user has interrupted comm. */
casio_seven_term_timeouts = 0x02, /* terminated due to timeouts */
casio_seven_term_overwrite = 0x03 /* in response to `ow_terminate` */
} casio_seven_term_t;
/* I said there was an exception earlier on, I wasn't lying: screenstreaming
* packets have a different format than other packets. Basically, after the
* type, there is a five-letter subtype (such as "TYP01" or "TYPZ1"), and
* for some types, subheaders. libcasio translates this into a VRAM and a
* picture format, which you can see in the Protocol 7.00 packet
* representation. */
/* ************************************************************************* */
/* Screenstreaming */
/* ************************************************************************* */
/* Screenstreaming packet flow is totally different from the normal packet
* flow: it's just the calculator sending its screen repeateadly, not
* expecting any answer from the 'passive' side. It is only available when
* the calculator is connected using USB, not 3-pin, to communicate with the
* current machine.
*
* There are two different types of screenstreaming, distinguished by a
* five-letter capture type:
* - "TYP01" is the basic monochrome capture (1-bit, 128x64);
* - "TYPZ1"/"TYPZ2" is the extended capture (see
* `libcasio/protocol/typz.h`). */
/* ************************************************************************* */
/* Command payload */
/* ************************************************************************* */
/* The command has a payload which contain, even in the cases where they are
* not useful, the overwrite status (OW), the MCS raw data type (DT),
* the file size (FS), and the six arguments (of variable length,
* although they never are above 16 bytes long).
*
* Some commands have a completely different format than others, such as
* the 0x56 command (upload'n'run), which also finishes with a binary zero.
*
* The overwrite status (OW) is useful for when sending a file. It can
* basically say, using the codes: */
typedef enum casio_seven_ow_e {
casio_seven_ow_confirm = 0x00, /* ask for confirmation */
casio_seven_ow_terminate = 0x01, /* terminate if the file exists */
casio_seven_ow_force = 0x02 /* force overwriting */
} casio_seven_ow_t;
/* With `casio_ow_confirm`, if the file exists, a
* `casio_err_overwrite` NAK packet, then, you will either confirm with an
* ACK packet, or infirm with a `casio_err_dont_overwrite` error packet.
*
* The MCS raw data type (DT) should be used with other arguments that are
* found within the arguments -- it is all documented in `libcasio/format*`.
* The filesize (FS) is used when sending a file or file information only.
* For some commands (such as 0x4E), it can also be the free capacity.
*
* The arguments usually are:
*
* # | Argument signification | Alternative significations
* --+-------------------------+----------------------------------------
* 1 | Directory name | Setup entry name
* 2 | File name | New directory name (directory renaming)
* | | Setup entry content (ASCII-hex)
* 3 | New directory name | MCS group name
* 4 | New file name |
* 5 | Storage device name |
* 6 | ??? (unused everywhere) |
*
* Whether arguments are used or not depend on the command. */
/* ************************************************************************* */
/* Protocol 7.00 limits */
/* ************************************************************************* */
/* The Protocol 7.00 packet representation includes all the data
* you could have in a packet. First, here are the buffer sizes: */
# define CASIO_SEVEN_MAX_VRAM_WIDTH 384 /* max. encountered VRAM width */
# define CASIO_SEVEN_MAX_VRAM_HEIGHT 500 /* max. encountered VRAM height */
# define CASIO_SEVEN_MAX_VRAM_SIZE \
(CASIO_SEVEN_MAX_VRAM_WIDTH * CASIO_SEVEN_MAX_VRAM_HEIGHT * 2)
# define CASIO_SEVEN_MAX_RAWDATA_SIZE 256 /* maximum raw data size */
# define CASIO_SEVEN_MAX_ENCDATA_SIZE ((CASIO_SEVEN_MAX_RAWDATA_SIZE) * 2)
# define CASIO_SEVEN_MAX_CMDARG_SIZE 256 /* maximum command argument size */
# define MAX_PACKET_SIZE (1 + 5 + CASIO_SEVEN_MAX_VRAM_SIZE + 2)
/* VRAM data isn't decoded directly by Protocol 7.00 Packet I/O utilities,
* although some functions such as `casio_getscreen` do decode it to a 32-bit
* pixel matrix (easier for the user, and extensible).
* Check `libcasio/picture.h` for picture format descriptions and utilities. */
/* ************************************************************************* */
/* Protocol 7.00 packet receiving and sending utilities */
/* ************************************************************************* */
CASIO_BEGIN_DECLS
/* This is the main function to receive a packet.
* It manages checksum errors, and timeouts; the only thing you should care
* about is the returned error.
*
* There are very few cases where you should this function directly, as the
* packet sending functions also manage receiving if necessary, so don't use
* it unless you're sure about what you're doing.
*
* `care_about_checksums` is only to set to zero if you don't want to react
* to checksums; for example, in the screenstreaming packet flow, where the
* receiver should not send anything. */
extern int casio_seven_receive OF((casio_link_t *casio__handle,
int casio__care_about_checksums));
/* These are the base functions to send a packet.
* Unless `resp` is zero, it will also get the response to the packet,
* and store its info in the handle's packet representation.
*
* You shouldn't use them directly to send a packet, but here they are: */
extern int casio_seven_send_basic OF((casio_link_t *casio__handle,
casio_seven_type_t casio__type, unsigned int casio__subtype,
int casio__resp));
extern int casio_seven_send_ext OF((casio_link_t *casio__handle,
casio_seven_type_t casio__type, unsigned int casio__subtype,
const void *casio__data, unsigned int casio__size,
int casio__resp));
/* Send checks.
* Initial checks are useful to check if there is another device speaking
* Protocol 7.00 at the other end of the line.
* Waiting checks are for the other device which is waiting for a command
* not to timeout (which takes six minutes). */
# define casio_seven_send_check(CASIO__H) \
(casio_seven_send_basic((CASIO__H), casio_seven_type_chk, \
casio_seven_chk_wait, 1))
# define casio_seven_send_ini_check(CASIO__H) \
(casio_seven_send_basic((CASIO__H), casio_seven_type_chk, \
casio_seven_chk_ini, 1))
/* Send acknowledgements (ACK packets).
* Basic ACK packets are used for plenty of things (`resp` should always be
* different from zero, as zero for this is used by data exchanging functions).
* Extended ACK is used for sending server information, usually as a response
* to the 0x01 command (sys_getinfo). */
# define casio_seven_send_ack(CASIO__H, CASIO__R) \
(casio_seven_send_basic((CASIO__H), casio_seven_type_ack, \
0x00, (CASIO__R)))
# define casio_seven_confirm_ow(CASIO__H) \
(casio_seven_send_basic((CASIO__H), casio_seven_type_ack, 0x01, 1))
extern int casio_seven_send_eack OF((casio_link_t *casio__handle,
casio_link_info_t *casio__info));
/* Send negative acknowledgements (NAK packets).
* These are used to report errors. */
# define casio_seven_send_err(CASIO__H, CASIO__C) \
(casio_seven_send_basic((CASIO__H), casio_seven_type_nak, (CASIO__C), 1))
# define casio_seven_deny_ow(CASIO__H) \
(casio_seven_send_err((CASIO__H), casio_seven_err_dont_overwrite))
/* Send termination packets.
* Will end the communication from the handle point of view. */
# define casio_seven_send_term_because(CASIO__H, CASIO__R) \
(casio_seven_send_basic((CASIO__H), casio_seven_type_end, (CASIO__R), 1))
# define casio_seven_send_term(CASIO__H) \
(casio_seven_send_term_because((CASIO__H), casio_seven_term_default))
/* Send a roleswap notice.
* Will pass the handle in passive mode. */
# define casio_seven_send_roleswp(CASIO__H) \
(casio_seven_send_basic((CASIO__H), casio_seven_type_swp, 0, 1))
# define casio_seven_send_swp(CASIO__H) \
(casio_seven_send_roleswp(CASIO__H))
/* Here are the base functions for sending a command.
* There are specific command-sending in `libcasio/protocol/seven/commands.h`,
* so if you're using a classical command, you should use them instead. */
extern int casio_seven_send_cmd OF((casio_link_t *casio__handle,
unsigned int casio__subtype));
extern int casio_seven_send_cmd_data OF((casio_link_t *casio__handle,
unsigned int casio__subtype, int casio__overwrite,
unsigned int casio__datatype, unsigned long casio__filesize,
const char *casio__arg0, const char *casio__arg1,
const char *casio__arg2, const char *casio__arg3,
const char *casio__arg4, const char *casio__arg5));
CASIO_END_DECLS
CASIO_END_NAMESPACE
# include <libcasio/protocol/seven/commands.h>
/* ************************************************************************* */
/* Protocol 7.00 environment */
/* ************************************************************************* */
CASIO_BEGIN_NAMESPACE
/* A Protocol 7.00 environment is the type of calculator there is on the
* other side. Environment identification is required for a more precise
* error guessing. */
typedef struct casio_seven_env_s {
const char *casio_seven_env_name; /* environment name, for logging */
unsigned int casio_seven_env_mask; /* the supported commands
* mask bit */
} casio_seven_env_t;
CASIO_BEGIN_DECLS
/* And here is everything you need lol. */
extern int casio_seven_getenv OF((casio_seven_env_t *casio__env,
const char *casio__id));
extern int casio_seven_command_is_supported OF((
const casio_seven_env_t *casio__env, unsigned int casio__code));
CASIO_END_DECLS
/* ************************************************************************* */
/* Protocol 7.00 packet representation */
/* ************************************************************************* */
/* This representation contains all the possible fields, and only some of them
* are used depending on the packet type/code. */
typedef struct casio_seven_packet_s {
/* main info */
casio_seven_type_t casio_seven_packet_type;
int casio_seven_packet_extended;
/* error, termination, check */
int casio_seven_packet_code;
int casio_seven_packet_initial;
/* commands */
int casio_seven_packet_ow;
int casio_seven_packet_mcstype;
unsigned long casio_seven_packet_filesize;
char *casio_seven_packet_args[6];
unsigned long casio_seven_packet_uploadsize;
unsigned long casio_seven_packet_loadaddr;
unsigned long casio_seven_packet_straddr;
/* data */
unsigned int casio_seven_packet_id;
unsigned int casio_seven_packet_total;
unsigned int casio_seven_packet_data_size;
/* server information */
casio_link_info_t casio_seven_packet_info;
/* screen */
casio_pictureformat_t casio_seven_packet_pictype;
unsigned int casio_seven_packet_height;
unsigned int casio_seven_packet_width;
/* big things */
unsigned char casio_seven_packet_data[CASIO_SEVEN_MAX_RAWDATA_SIZE];
char casio_seven_packet__argsdata[6][CASIO_SEVEN_MAX_CMDARG_SIZE + 1];
char casio_seven_packet_vram[CASIO_SEVEN_MAX_VRAM_SIZE];
} casio_seven_packet_t;
/* To extract it from the handle, use the extractors in `libcasio/link.h`. */
/* ************************************************************************* */
/* Packet flows */
/* ************************************************************************* */
/* Once the communication is initialized (`casio_init_link` with the
* `CASIO_LINKFLAG_ACTIVE | CASIO_LINKFLAG_CHECK` flags takes care of that),
* Protocol 7.00 is basically a set of packet flows.
*
* A packet flow always start with a command from the active side to the
* passive side. Then, once the command is ACK-ed, according to the command,
* different packet flows can occur. Here are a few characteristic examples:
*
* - Simple action. For example, file removing require nothing after the
* command confirmation;
* - File sending. After the overwrite flow, the active side sends data
* packets containing the file data
* (`casio_seven_send_buffer`/`casio_seven_send_data`);
* - File receiving. The active side sends a role swap packet, then the
* server (now active) does the file sending procedure (with command). Once
* it has finished sending the file, it swaps roles again;
* - File listing. The active side sends a role swap packet, then the
* server (now active) sends file information commands for each entry.
* Once it has finished, it swap roles again.
*
* If you have finished doing what you wanted to do and the communication is
* still active, send an END packet, to which the other calculator should
* respond with an ACK. */
/* ************************************************************************* */
/* Protocol 7.00 packet flow utilities */
/* ************************************************************************* */
CASIO_BEGIN_DECLS
/* Start and end the communication.
* Is used by the link opening and closing functions;
* you shouldn't use them unless you know what you're doing
* (and you probably don't if you actually want to use them). */
extern int casio_seven_start OF((casio_link_t *casio__handle));
extern int casio_seven_end OF((casio_link_t *casio__handle));
/* Send and receive data, using buffers.
* This will automatically divide your data into packets, or make up the
* data from packets.
*
* Packet shifting (enabled with `shift != 0`) is a technique discovered by
* Nessotrin (from Planète Casio), and made accessible by Cakeisalie5 in
* libcasio (previously libp7). It makes data exchanges quicker.
* It is advised not to use it for receiving data, or for sensitive
* data. */
extern int casio_seven_send_buffer OF((casio_link_t *casio__handle,
casio_stream_t *casio__stream, casio_off_t casio__size,
int casio__shift, casio_link_progress_t *casio__progress,
void *casio__pcookie));
extern int casio_seven_get_buffer OF((casio_link_t *casio__handle,
casio_stream_t *casio__stream, casio_off_t casio__size,
int casio__shift, casio_link_progress_t *casio__progress,
void *casio__pcookie));
/* Send and receive data, using memory areas.
* Beyond the buffer/memory difference, those and the previous ones are
* basically the same thing. */
extern int casio_seven_send_data OF((casio_link_t *casio__handle,
const void *casio__buf, casio_off_t casio__size,
int casio__shift, casio_link_progress_t *casio__progress,
void *casio__pcookie));
extern int casio_seven_get_data OF((casio_link_t *casio__handle,
void *casio__buf, casio_off_t casio__size,
int casio__shift, casio_link_progress_t *casio__progress,
void *casio__pcookie));
/* Send and receive data, using a stream.
* This is practicle when you want to encode and write on the fly. */
extern int casio_seven_open_data_stream OF((casio_stream_t **casio__stream,
casio_link_t *casio__link, casio_off_t casio__size,
casio_link_progress_t *casio__disp, void *casio__dcookie));
CASIO_END_DECLS
CASIO_END_NAMESPACE
#endif /* LIBCASIO_PROTOCOL_SEVEN_H */