320 lines
12 KiB
C
320 lines
12 KiB
C
/* ************************************************************************** */
|
|
/* _____ _ */
|
|
/* libp7/packetio.h |_ _|__ _ _| |__ ___ _ _ */
|
|
/* | Project: libp7 | |/ _ \| | | | '_ \ / _ \ | | | */
|
|
/* | | (_) | |_| | | | | __/ |_| | */
|
|
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
|
/* Last updated: 2017/01/04 15:01:48 |___/ */
|
|
/* */
|
|
/* ************************************************************************** */
|
|
#ifndef LIBP7_PACKETIO_H
|
|
# define LIBP7_PACKETIO_H
|
|
# include <libp7.h>
|
|
# include <libp7/stream.h> /* for P7_B* */
|
|
# ifdef __cplusplus
|
|
extern "C" {
|
|
# endif
|
|
|
|
/* ************************************************************************** */
|
|
/* THE LIBP7 PACKET I/O API */
|
|
/* ************************************************************************** */
|
|
/* Basically, Protocol 7 is all about exchanging packets. libp7 takes care
|
|
* of all of the odd details, but you'll want to use this API to implement an
|
|
* interaction with the calculator. An interaction is called a packet flow.
|
|
* This packet flow highly depends on the command.
|
|
*
|
|
* A first example of packet flow is: the client sends a command (e.g. delete
|
|
* a file), and the server sends back an ACK (command has been executed)
|
|
* or the error if there is one (e.g. the command is not implemented, or the
|
|
* file doesn't exist).
|
|
*
|
|
* Another example of packet flow is: the client sends a command (e.g. file
|
|
* listing), the server accepts, the client sends a ROLESWP so that it becomes
|
|
* a server and the server becomes the client. The calculator (now client) will
|
|
* then send (sub-)commands (e.g. "here is a file entry"), then the client
|
|
* will ACK to each one, until the calculator finally sends a ROLESWAP to tell
|
|
* he has finished.
|
|
*
|
|
* Yet another example of packet flow (but there are others) is: the client
|
|
* sends a command (e.g. send a file), the server ACKs, then the client will
|
|
* send the data (libp7 takes care of that with the `p7_send_filestream`
|
|
* function).
|
|
*
|
|
* A last example of packet flow (but there may be others) is: the client
|
|
* sends a command (e.g. receive a file), the server ACKs, then the client
|
|
* sends a ROLESWP, and the calculator will use a sub-packet flow (e.g. file
|
|
* sending) to send the data, and will send a ROLESWP when it's done.
|
|
*
|
|
* All of these packet flows can be implemented using the methods listed
|
|
* here. If you want examples, just check out the `protocol` module in the
|
|
* libp7 source! */
|
|
/* ************************************************************************** */
|
|
/* Enumerations - give sense to those numbers! */
|
|
/* ************************************************************************** */
|
|
/* The packet type. */
|
|
typedef enum {
|
|
p7_pt_cmd = 0x01,
|
|
p7_pt_data = 0x02,
|
|
p7_pt_roleswp = 0x03,
|
|
p7_pt_check = 0x05,
|
|
p7_pt_ack = 0x06,
|
|
p7_pt_ohp = 0x0B,
|
|
p7_pt_error = 0x15,
|
|
p7_pt_terminate = 0x18
|
|
} p7_packettype_t;
|
|
|
|
/* The packet screen type - adapted from a string. */
|
|
typedef enum {
|
|
p7_pscr_typ01
|
|
} p7_packetscreen_t;
|
|
|
|
/* In case a file exists, what should we do? */
|
|
typedef enum {
|
|
/* request confirmation from the client before overwriting */
|
|
p7_ow_confirm = 0x00,
|
|
|
|
/* terminate if file exists */
|
|
p7_ow_terminate = 0x01,
|
|
|
|
/* force the overwrite */
|
|
p7_ow_force = 0x02
|
|
} p7_commandoverwrite_t;
|
|
|
|
/* The error codes */
|
|
typedef enum {
|
|
/* in case of checksum problems - libp7 will take care of this for you. */
|
|
p7_err_resend = 0x01,
|
|
|
|
/* file exists! what's the action you want to do? */
|
|
p7_err_overwrite = 0x02,
|
|
|
|
/* server asks you if you want to overwrite, you answer no */
|
|
p7_err_dont_overwrite = 0x03,
|
|
|
|
/* the most generic error - used as an 'else' error. */
|
|
p7_err_other = 0x04,
|
|
|
|
/* memory is full! (will terminate communication) */
|
|
p7_err_fullmem = 0x05
|
|
} p7_errcode_t;
|
|
|
|
/* The termination types. */
|
|
typedef enum {
|
|
/* communication terminated normally. */
|
|
p7_term_default = 0x00,
|
|
|
|
/* user asked for the termination to happen. */
|
|
p7_term_user = 0x01,
|
|
|
|
/* termination caused by timeouts */
|
|
p7_term_timeouts = 0x02,
|
|
|
|
/* answer to overwrite type 0x01 if file exists. */
|
|
p7_term_overwrite = 0x03
|
|
} p7_termtype_t;
|
|
|
|
/* ************************************************************************** */
|
|
/* Commands */
|
|
/* ************************************************************************** */
|
|
/* Commands have an OW field (overwrite action), an MCS type field,
|
|
* a FILESIZE field, and six arguments.
|
|
*
|
|
* The utility of an argument or not depends on the command, but the places
|
|
* of the arguments stay the same:
|
|
*
|
|
* # | Argument signification
|
|
* --+-----------------------
|
|
* 1 | Directory name
|
|
* 2 | File name
|
|
* 3 | New directory name
|
|
* 4 | New file name
|
|
* 5 | Storage device name
|
|
* 6 | ??? (unused everywhere)
|
|
*
|
|
* An exception seems to be that argument #2 in commands 0x_2
|
|
* (rename directory) is the new directory name (but maybe that's a typo).
|
|
*
|
|
* Also, command 0x56 has a completely different data format that the others
|
|
* commands (and even other packets in general, as it finishes with a binary
|
|
* zero, for some reason). */
|
|
|
|
/* Main commands */
|
|
int p7_send_cmd(p7_handle_t *handle, p7ushort_t subtype);
|
|
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);
|
|
|
|
/* Command models
|
|
* - Simple command */
|
|
# define p7cmd(C, CODE) \
|
|
static inline int p7_send_cmd##C(p7_handle_t *handle) { \
|
|
return (p7_send_cmd(handle, CODE)); }
|
|
/* - Command for a storage device */
|
|
# define p7cmd_dev(C, CODE) \
|
|
static inline int p7_send_cmd##C(p7_handle_t *handle, const char *devname) { \
|
|
return (p7_send_cmd_data(handle, CODE, 0, 0, 0, \
|
|
NULL, NULL, NULL, NULL, devname, NULL)); }
|
|
/* - Command for interacting with a directory */
|
|
# define p7cmd_dir(C, CODE) \
|
|
static inline int p7_send_cmd##C(p7_handle_t *handle, \
|
|
const char *dirname, const char *devname) { \
|
|
return (p7_send_cmd_data(handle, CODE, 0, 0, 0, \
|
|
dirname, NULL, NULL, NULL, devname, NULL)); }
|
|
/* - Command for renaming a directory */
|
|
# define p7cmd_rendir(C, CODE) \
|
|
static inline int p7_send_cmd##C(p7_handle_t *handle, \
|
|
const char *dirname, const char *newdir, const char *devname) { \
|
|
return (p7_send_cmd_data(handle, CODE, 0, 0, 0, \
|
|
dirname, newdir, NULL, NULL, devname, NULL)); }
|
|
|
|
/* - Command for interacting with a file */
|
|
# define p7cmd_file(C, CODE) \
|
|
static inline int p7_send_cmd##C(p7_handle_t *handle, \
|
|
const char *dirname, const char *filename, const char *devname) { \
|
|
return (p7_send_cmd_data(handle, CODE, 0, 0, 0, \
|
|
dirname, filename, NULL, NULL, devname, NULL)); }
|
|
/* - Command for sending a file */
|
|
# define p7cmd_send(C, CODE) \
|
|
static inline int p7_send_cmd##C(p7_handle_t *handle, \
|
|
int ow, p7uint_t fs, \
|
|
const char *dirname, const char *filename, const char *devname) { \
|
|
return (p7_send_cmd_data(handle, CODE, ow, 0, fs, \
|
|
dirname, filename, NULL, NULL, devname, NULL)); }
|
|
/* - Command for copying a file */
|
|
# define p7cmd_copy(C, CODE) \
|
|
static inline int p7_send_cmd##C(p7_handle_t *handle, \
|
|
const char *dirname, const char *filename, \
|
|
const char *newdir, const char *newname, const char *devname) { \
|
|
return (p7_send_cmd_data(handle, CODE, 0, 0, 0, \
|
|
dirname, filename, newdir, newname, devname, NULL)); }
|
|
/* - Command for renaming a file */
|
|
# define p7cmd_rename(C, CODE) \
|
|
static inline int p7_send_cmd##C(p7_handle_t *handle, \
|
|
const char *dirname, const char *filename, \
|
|
const char *newname, const char *devname) { \
|
|
return (p7_send_cmd_data(handle, CODE, 0, 0, 0, \
|
|
dirname, filename, NULL, newname, devname, NULL)); }
|
|
|
|
/* Command definitions
|
|
* Remember that these are only for the ease of use; you can use the macros
|
|
* to implement more commands without putting them here. */
|
|
p7cmd(sys_getinfo, 0x01)
|
|
p7cmd(bak_putram, 0x30)
|
|
p7cmd_dir(fls_mkdir, 0x40)
|
|
p7cmd_dir(fls_rmdir, 0x41)
|
|
p7cmd_dir(fls_mvdir, 0x42)
|
|
p7cmd_dir(fls_cwd, 0x43)
|
|
p7cmd_file(fls_reqfile, 0x44)
|
|
p7cmd_send(fls_sendfile, 0x45)
|
|
p7cmd_file(fls_delfile, 0x46)
|
|
p7cmd_rename(fls_renamefile, 0x47)
|
|
p7cmd_copy(fls_copyfile, 0x48)
|
|
p7cmd_dev(fls_reset, 0x4A)
|
|
p7cmd_dev(fls_reqcapacity, 0x4B)
|
|
p7cmd_dev(fls_reqallinfo, 0x4D)
|
|
p7cmd_dev(fls_opt, 0x51)
|
|
p7cmd(bak_reqrom, 0x4F)
|
|
p7cmd(bak_putrom, 0x50)
|
|
p7cmd(bak_reqcwe, 0x52)
|
|
p7cmd(bak_putcwe, 0x53)
|
|
p7cmd(bak_reqboot, 0x54)
|
|
p7cmd(bak_putboot, 0x55)
|
|
|
|
/* These functions are kept as functions because they're more complex */
|
|
int p7_send_cmdsys_setlink(p7_handle_t *handle,
|
|
int baudrate, int parity, int stopbits);
|
|
int p7_send_cmdosu_upandrun(p7_handle_t *handle,
|
|
p7uint_t upsize, p7uint_t loadaddr, p7uint_t straddr);
|
|
|
|
/* get and send some data using buffers */
|
|
int p7_send_buffer(p7_handle_t *handle, const p7_buffer_t *buffer,
|
|
int shift, void (*disp)(p7ushort_t, p7ushort_t));
|
|
int p7_get_buffer(p7_handle_t *handle, const p7_buffer_t *buffer, p7uint_t size,
|
|
int shift, void (*disp)(p7ushort_t, p7ushort_t));
|
|
|
|
/* get and send some data using memory areas */
|
|
int p7_send_data(p7_handle_t *handle, const void *vbuf, p7uint_t size,
|
|
int shift, void (*disp)(p7ushort_t, p7ushort_t));
|
|
int p7_get_data(p7_handle_t *handle, void *buf, p7uint_t size,
|
|
int shift, void (*disp)(p7ushort_t, p7ushort_t));
|
|
|
|
/* ************************************************************************** */
|
|
/* Other packets */
|
|
/* ************************************************************************** */
|
|
/* Send raw packets (you shouldn't use that directly) */
|
|
int p7_send_basic(p7_handle_t *handle,
|
|
p7_packettype_t type, p7ushort_t subtype, int resp);
|
|
int p7_send_ext(p7_handle_t *handle,
|
|
p7_packettype_t type, p7ushort_t subtype,
|
|
const void *data, p7ushort_t size, int resp);
|
|
|
|
/* Errors */
|
|
static inline int p7_send_err(p7_handle_t *handle, int code) {
|
|
return (p7_send_basic(handle, p7_pt_error, code, 1)); }
|
|
|
|
/* Acknowledgements */
|
|
int p7_send_ack(p7_handle_t *handle, int resp);
|
|
int p7_send_eack(p7_handle_t *handle, p7_server_t *info);
|
|
|
|
/* Answers to overwrite */
|
|
int p7_confirm_ow(p7_handle_t *handle);
|
|
# define p7_deny_ow(H) p7_send_err((H), p7_err_dont_overwrite)
|
|
|
|
/* Roleswap */
|
|
int p7_send_roleswp(p7_handle_t *handle);
|
|
|
|
/* Terminations */
|
|
int p7_send_term_because(p7_handle_t *handle, int reason);
|
|
# define p7_send_term(H) p7_send_term_because((H), p7_term_default)
|
|
|
|
/* ************************************************************************** */
|
|
/* Answer to command packets */
|
|
/* ************************************************************************** */
|
|
# define MAX_COMMAND_ARGUMENT_SIZE 256
|
|
# define MAX_VRAM_SIZE 1024 /* increase in case of other vram formats */
|
|
# define MAX_VRAM_WIDTH 128
|
|
# define MAX_VRAM_HEIGHT 64
|
|
# define MAX_RAWDATA_SIZE 256
|
|
|
|
/* The decoded packet representation. */
|
|
typedef struct {
|
|
/* main info */
|
|
unsigned int type;
|
|
int extended;
|
|
|
|
/* error, termination, check */
|
|
int code, initial;
|
|
|
|
/* commands */
|
|
int ow; int mcstype; p7uint_t filesize;
|
|
char *args[6]; char _argsdata[6][MAX_COMMAND_ARGUMENT_SIZE + 1];
|
|
p7uint_t uploadsize, loadaddr, straddr; /* 0x56 */
|
|
|
|
/* data */
|
|
p7ushort_t id, total;
|
|
unsigned char data[MAX_RAWDATA_SIZE];
|
|
p7ushort_t data_size;
|
|
|
|
/* server information */
|
|
p7_server_t info;
|
|
|
|
/* screen */
|
|
p7_packetscreen_t scrtype;
|
|
unsigned char vram[MAX_VRAM_SIZE];
|
|
} p7_packet_t;
|
|
|
|
/* ************************************************************************** */
|
|
/* Handle extractors */
|
|
/* ************************************************************************** */
|
|
/* Extract the decoded packet response from the handle */
|
|
const p7_packet_t *p7_get_response(p7_handle_t *handle);
|
|
|
|
/* Extract the server info from the handle */
|
|
const p7_server_t *p7_get_info(p7_handle_t *handle);
|
|
|
|
# ifdef __cplusplus
|
|
}
|
|
# endif
|
|
#endif /* LIBP7_PACKETIO_H */
|