Fixed p7screen.

This commit is contained in:
Thomas Touhey 2018-04-27 15:32:44 +02:00
parent 1b11596319
commit 31ad4cb0b6
No known key found for this signature in database
GPG Key ID: 2ECEB0517AD947FB
15 changed files with 841 additions and 353 deletions

View File

@ -218,10 +218,10 @@ define get-util-source
U_CFLAGS_$1 := $(CFLAGS) $(foreach dep,$(U_DEPS_$1),$(DEP_$(dep)_CFLAGS)) \
-D BIN="\"$1$(if $(FOR_WINDOWS),.exe)\"" \
-D NAME="\"p7utils\"" -D VERSION="\"$(VERSION)\"" \
-D NAME="\"libcasio utilities\"" -D VERSION="\"$(VERSION)\"" \
-D MAINTAINER="\"$(MAINTAINER_NAME) <$(MAINTAINER_MAIL)>\"" \
-D DEFAULT_STORAGE="\"$(DEFAULT_STORAGE)\"" \
-D DEFAULT_ZOOM="\"$(DEFAULT_ZOOM)\""
-D DEFAULT_ZOOM="\"$(DEFAULT_ZOOM)\"" -D DEFAULT_ZOOM_I="$(DEFAULT_ZOOM)"
U_LIBS_$1 := $(foreach dep,$(U_DEPS_$1),$(DEP_$(dep)_LIBS))
U_LDFLAGS_$1 := $(foreach dep,$(U_DEPS_$1),$(DEP_$(dep)_LIBS))

View File

@ -26,12 +26,14 @@
# include "picture.h"
CASIO_BEGIN_NAMESPACE
/* ************************************************************************* */
/* Link and link information */
/* ************************************************************************* */
/* ---
* Link and link information.
* --- */
/* The link structure is private, as it contains diiiirty things.
* You should only manipulate pointers to it (unless you're contributing
* to libcasio). */
struct casio_link_s;
typedef struct casio_link_s casio_link_t;
@ -71,9 +73,11 @@ typedef struct casio_link_info_s {
char casio_link_info_hwid[9];
char casio_link_info_cpuid[17];
} casio_link_info_t;
/* ************************************************************************* */
/* Basic callbacks */
/* ************************************************************************* */
/* ---
* Basic callbacks.
* --- */
/* The user shall confirm or not a link action. */
typedef int casio_link_confirm_t OF((void *casio__cookie));
@ -86,20 +90,31 @@ typedef int casio_link_confirm_t OF((void *casio__cookie));
typedef void casio_link_progress_t OF((void *casio__cookie,
unsigned int casio__id, unsigned int casio__total));
/* This callback is for displaying/using a received picture, with
* `casio_getscreen` for example. */
typedef void casio_link_screen_t OF((void *casio__cookie,
int casio__w, int casio__h,
casio_pixel_t **casio__pixels));
/* List files. */
typedef void casio_link_list_t OF((void *casio__cookie,
const char *casio__path, const casio_stat_t *casio__stat));
/* ************************************************************************* */
/* Basic link handle operations */
/* ************************************************************************* */
/* ---
* Other structures.
* --- */
/* Screen. */
typedef struct casio_screen_s {
unsigned int casio_screen_width;
unsigned int casio_screen_height;
unsigned int casio_screen_realwidth;
unsigned int casio_screen_realheight;
casio_pixel_t **casio_screen_pixels;
} casio_screen_t;
/* ---
* Basic link handle operations.
* --- */
/* Initialization flags.
* `CASIO_LINKFLAG_ACTIVE`: start off as active;
* `CASIO_LINKFLAG_CHECK`: check (initial packet);
@ -166,11 +181,18 @@ CASIO_EXTERN int CASIO_EXPORT casio_seven_serve
CASIO_EXTERN int CASIO_EXPORT casio_setlink
OF((casio_link_t *casio__handle, const casio_streamattrs_t *casio__attrs));
/* Set up a screen streaming receiver. */
/* Receive and free a screen streaming frame.
* The screen is a double pointer because it is allocated or reallocated
* when required only. */
CASIO_EXTERN int CASIO_EXPORT casio_getscreen
OF((casio_link_t *casio__handle,
casio_link_screen_t *casio__callback, void *casio__scookie));
CASIO_EXTERN int CASIO_EXPORT casio_get_screen
OF((casio_link_t *casio__handle, casio_screen_t **casio__screen));
CASIO_EXTERN int CASIO_EXPORT casio_make_screen
OF((casio_screen_t **casio__screen, unsigned int casio__width,
unsigned int casio__height));
CASIO_EXTERN int CASIO_EXPORT casio_free_screen
OF((casio_screen_t *casio__screen));
/* Backup the ROM. */

View File

@ -177,12 +177,18 @@ CASIO_BEGIN_DECLS
* 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. */
* Flags can be the following:
*
* `CHECKSUMS`: shall we care about checksums? Do not use if you don't want
* to react to checksums; for example, in the screenstreaming
* packet flow, the receiver should not send anything.
* `SCRALIGN`: shall we try aligning ourselves to the next screen packet? */
# define CASIO_SEVEN_RECEIVEFLAG_CHECKSUMS 1
# define CASIO_SEVEN_RECEIVEFLAG_SCRALIGN 2
CASIO_EXTERN int CASIO_EXPORT casio_seven_receive
OF((casio_link_t *casio__handle, int casio__care_about_checksums));
OF((casio_link_t *casio__handle, unsigned int casio__flags));
/* These are the base functions to send a packet.
* Unless `resp` is zero, it will also get the response to the packet,

View File

@ -25,9 +25,10 @@
#define checksub8(BUF, SIZE, INI) \
casio_checksum_sub(&((char*)(BUF))[1], (SIZE) - 3, (INI))
/* ************************************************************************* */
/* Logging */
/* ************************************************************************* */
/* ---
* Functions useful for logging.
* --- */
/**
* getcmdstring:
* Get command code string (useful for logging).
@ -154,9 +155,11 @@ CASIO_LOCAL const char *gettermstring(casio_seven_term_t code)
if (code > 0x03) return ("<unknown termination reason>");
return (strings[code]);
}
/* ************************************************************************* */
/* Main receiving function */
/* ************************************************************************* */
/* ---
* Main receiving function.
* --- */
/**
* casio_seven_decode:
* Receive a packet.
@ -166,6 +169,7 @@ CASIO_LOCAL const char *gettermstring(casio_seven_term_t code)
* It uses buffered I/O to read progressively all of the packet.
*
* @arg handle the link handle
* @arg scralign shall we align screen?
* @return the error (0 if ok)
*/
@ -175,15 +179,15 @@ CASIO_LOCAL const char *gettermstring(casio_seven_term_t code)
&buffer[received], (size_t)(N)); \
received += (N); if (COMP_PACKET_err) return (COMP_PACKET_err); }
CASIO_LOCAL int casio_seven_decode(casio_link_t *handle)
CASIO_LOCAL int casio_seven_decode(casio_link_t *handle, int scralign)
{
/* prepare reception */
size_t received = 0;
int check_sum = 1, is_extended;
unsigned long csum, csum_ex;
unsigned int subtype, data_size;
/* get first three bytes, check if is CAL */
/* Get first three bytes, check if is CAL. */
do {
COMPLETE_PACKET(3)
if (memcmp(buffer, "CAL", 3))
@ -200,10 +204,30 @@ CASIO_LOCAL int casio_seven_decode(casio_link_t *handle)
msg((ll_info, "Restart receiving the packet."));
} while (1);
/* get the type */
/* Align on the screen if required. */
if (scralign) {
int tries = MAX_PACKET_SIZE + 1;
/* Adjust. */
while (memcmp(buffer, "\x0BTY", 3)) {
if (!--tries)
return (casio_error_unknown);
buffer[0] = buffer[1];
buffer[1] = buffer[2];
received = 2;
COMPLETE_PACKET(1)
}
}
/* Get the type. */
response.casio_seven_packet_type = buffer[0];
/* image has a particular format starting from here, look for it now! */
/* Image has a particular format starting from here, look for it now! */
if (response.casio_seven_packet_type == casio_seven_type_ohp) {
unsigned int image_size;
size_t hdsize;
@ -416,59 +440,76 @@ CASIO_LOCAL int casio_seven_decode(casio_link_t *handle)
/* finally, return the packet */
return (0);
}
/* ************************************************************************* */
/* Receiving function with error management */
/* ************************************************************************* */
/* ---
* Receiving function with error management.
* --- */
/**
* casio_seven_receive:
* Receives packet, checks for errors.
*
* @arg handle the link handle
* @arg checksum if 0 and invalid checksum, ignore and receive again
* @arg flags receive flags.
* @return if it worked
*/
int CASIO_EXPORT casio_seven_receive(casio_link_t *handle, int checksum)
int CASIO_EXPORT casio_seven_receive(casio_link_t *handle, unsigned int flags)
{
int err, wasresend = 0;
/* make checks */
if (!handle) return (casio_error_init);
/* Make checks. */
if (!handle)
return (casio_error_init);
/* Main loop. */
/* main loop */
while (1) {
/* receive */
/* Receive the packet. */
msg((ll_info, "Receiving the packet..."));
err = casio_seven_decode(handle);
err = casio_seven_decode(handle,
!!(flags & CASIO_SEVEN_RECEIVEFLAG_SCRALIGN));
/* check out the error */
if (err && !(err == casio_error_csum && !checksum)) {
/* Check out the error. */
if (err && !(err == casio_error_csum
&& ~flags & CASIO_SEVEN_RECEIVEFLAG_CHECKSUMS)) {
switch (err) {
/* if calc couldn't be found, terminate communication */
case casio_error_nocalc: goto fail;
case casio_error_nocalc:
/* If the calculator couldn't be found, terminate
* the communication. */
goto fail;
/* if it is a timeout, remove a try */
case casio_error_timeout:
/* send a check */
err = casio_seven_send_timeout_check(handle);
if (err) goto fail;
/* If it is a timeout, send a check, get the corresponding
* ACK and remove a try. */
/* get the ack */
err = casio_seven_decode(handle);
err = casio_seven_send_timeout_check(handle);
if (err)
goto fail;
err = casio_seven_decode(handle, 0);
if (!err && response.casio_seven_packet_type
!= casio_seven_type_ack)
err = casio_error_unknown;
if (err) goto fail;
if (err)
goto fail;
/* try again
/* Try again.
* TODO: check if we should resend the previous packet...? */
break;
/* if it is a bad checksum, ask for resend ; also,
* reset tries number in case of bad checksum between timeouts */
case casio_error_csum:
/* check if we didn't already give a chance to the
* other side */
/* If it is a bad checksum, ask for resend; also,
* reset tries number in case of bad checksum between
* timeouts.
*
* First of all, check if we didn't already give a chance
* to the other side. */
if (wasresend) {
msg((ll_error, "Two checksum failures, ending now."));
casio_seven_send_basic(handle, casio_seven_type_end,
@ -479,38 +520,44 @@ int CASIO_EXPORT casio_seven_receive(casio_link_t *handle, int checksum)
goto fail;
}
/* if we receive an invalid checksum while we are in packet
/* If we receive an invalid checksum while we are in packet
* shifting mode, or if we received an error when we sent a
* resend error, cut connexion... we can't do anything. */
if ((handle->casio_link_flags & casio_linkflag_shifted) \
|| wasresend) {
handle->casio_link_flags |= casio_linkflag_ended;
return (casio_error_damned);
}
/* otherwise, check tries and send resend error */
/* Otherwise, check tries and send resend error. */
err = casio_seven_send_err_resend(handle);
if (err) return (err);
if (err)
return (err);
/* set things */
wasresend = 1;
err = casio_error_csum;
break;
/* should not catch bad type & others */
default: return (casio_error_csum);
default:
/* Should not catch bad type & others. */
return (casio_error_csum);
}
/* then try again to get the answer :) */
/* Then try again to get the answer :) */
continue;
}
/* TODO: check out the type and stuff...? */
/* go away! */
/* Go away! */
break;
}
/* everything went well... or not? */
return (0);
fail:
handle->casio_link_flags |= casio_linkflag_ended;

View File

@ -21,58 +21,105 @@
#define WIDTH CASIO_SEVEN_MAX_VRAM_WIDTH
#define HEIGHT CASIO_SEVEN_MAX_VRAM_HEIGHT
/* ---
* Screen management.
* --- */
int CASIO_EXPORT casio_make_screen(casio_screen_t **screenp,
unsigned int width, unsigned int height)
{
casio_screen_t *screen;
casio_pixel_t **pixels, *base;
int y;
/* Allocate and prepare the screen. */
screen = casio_alloc(sizeof(casio_screen_t)
+ sizeof(casio_pixel_t*) * width
+ sizeof(casio_pixel_t) * width * height, 1);
if (!screen)
return (casio_error_alloc);
screen->casio_screen_width = width;
screen->casio_screen_realwidth = width;
screen->casio_screen_height = height;
screen->casio_screen_realheight = height;
screen->casio_screen_pixels = (casio_pixel_t **)&screen[1];
/* Prepare the pixels. */
pixels = screen->casio_screen_pixels;
base = (casio_pixel_t*)(&pixels[height]);
for (y = height - 1; y >= 0; y--)
pixels[y] = base + y * width;
*screenp = screen;
return (0);
}
int CASIO_EXPORT casio_free_screen(casio_screen_t *screen)
{
casio_free(screen);
return (0);
}
/* ---
* Gather the screen.
* --- */
/**
* casio_getscreen:
* casio_get_screen:
* Get the screen.
*
* @arg handle the link handle.
* @arg callback the main callback for the function.
* @arg scookie the callback cookie.
* @arg screen the screen to allocate/reallocate/reuse.
* @return if it worked.
*/
int CASIO_EXPORT casio_getscreen(casio_link_t *handle,
casio_link_screen_t *callback, void *cbcookie)
int CASIO_EXPORT casio_get_screen(casio_link_t *handle,
casio_screen_t **screenp)
{
int err = 0, y;
casio_pixel_t **pixels = NULL, *base;
unsigned int width, height;
int err = 0;
casio_screen_t *screen;
/* Make checks. */
/* make checks. */
chk_handle(handle);
chk_seven(handle); /* TODO: SCSI? */
chk_passive(handle);
/* allocate pixels. */
pixels = casio_alloc(sizeof(casio_pixel_t*) * HEIGHT
+ sizeof(casio_pixel_t) * WIDTH * HEIGHT, 1);
if (!pixels) failure(alloc);
/* Prepare the screen. */
/* prepare pixels. */
base = (casio_pixel_t*)(pixels + HEIGHT);
for (y = HEIGHT - 1; y >= 0; y--)
pixels[y] = base + y * WIDTH;
screen = *screenp;
if (!(screen && screen->casio_screen_realwidth == WIDTH
&& screen->casio_screen_realheight)) {
/* Allocate the thing first, so that if we fail, the screen is
* still there to be used by the user, in case. */
/* main loop */
while (1) {
/* get packet */
if ((err = casio_seven_receive(handle, 0)))
goto fail;
if (response.casio_seven_packet_type != casio_seven_type_ohp)
failure(unknown);
if ((err = casio_make_screen(&screen, WIDTH, HEIGHT)))
return (err);
/* convert */
width = response.casio_seven_packet_width;
height = response.casio_seven_packet_height;
casio_decode_picture(pixels,
response.casio_seven_packet_vram,
response.casio_seven_packet_pictype,
width, height);
(*callback)(cbcookie, width, height, pixels);
if (*screenp)
casio_free_screen(*screenp);
*screenp = screen;
}
err = 0;
fail:
casio_free(pixels);
/* Get the screen packet. */
if ((err = casio_seven_receive(handle, CASIO_SEVEN_RECEIVEFLAG_SCRALIGN)))
return (err);
if (response.casio_seven_packet_type != casio_seven_type_ohp)
return (casio_error_unknown);
/* Convert the screen buffer. */
screen->casio_screen_width = response.casio_seven_packet_width;
screen->casio_screen_height = response.casio_seven_packet_height;
casio_decode_picture(screen->casio_screen_pixels,
response.casio_seven_packet_vram,
response.casio_seven_packet_pictype,
screen->casio_screen_width,
screen->casio_screen_height);
return (0);
}

View File

@ -57,6 +57,17 @@ value next to them.
::
If this option isn't used, the program will look for a calculator connected
using direct USB.
*--use <settings>*::
If a serial connexion is used, tells p7 to use the given settings, which
are of the format <speed><parity><stop bits>, e.g. 9600N2.
*--set <settings>*::
If a serial connexion is used, tells p7 to make an agreement with the
calculator to change the connexion settings to the given one. If different
from the default settings and not exiting, the next call to p7 or any
other similar utility will have to be called with the *--use* option.
*--reset*::
Same as *--set*, except that the settings are set to be the default
ones for the protocol.
*--storage abc0*::
The storage device with which to interact.
*--no-term, --no-exit*::

View File

@ -7,7 +7,7 @@ Thomas "Cakeisalie5" Touhey
NAME
----
p7os - backup and setup CASIO calculator's software components using protocol 7
p7os - interact with software components of CASIO calculators
SYNOPSIS
--------
@ -29,6 +29,8 @@ Available submenus are :
with it.
*get [-o os.bin]*::
Backup the bootcode, CASIOWIN entry and OS.
*flash <os.bin>*::
Flash the calculator's CASIOWIN entry and OS image.
You have to *prepare* before doing any other action. Preparing means sending
a P7 server on the calculator that will be able to execute commands required
@ -36,8 +38,8 @@ by other subcommands.
OPTIONS
-------
Options start with one or two dashes. Some of the options require an additional
value next to them.
Options start with one or two dashes. Some of the options require an
additional value next to them.
*-h, --help*::
Display command/subcommand help page and quit.

View File

@ -18,8 +18,11 @@ p7screen [-h|--help] [-v|--version]
DESCRIPTION
-----------
p7screen is a command-line utility to display streamed screen from casio fx
calculator, using its communication protocol 7.00 and screenstreaming mode.
p7screen is a command-line utility to display streamed screen from CASIO fx
calculators, using its communication protocol 7.00 and screenstreaming mode.
Notice that *p7*(1) serial-related options are not available here, as
screenstreaming is only available on USB cables by choice from CASIO.
OPTIONS
-------
@ -31,7 +34,7 @@ value next to them.
*-v, --version*::
Display version and quit.
*-z ZOOM, --zoom=ZOOM*::
Change the zoom (will change the window size too).
Change the zoom (size of a pixel square, will change the window size too).
SEE ALSO
--------

View File

@ -23,10 +23,12 @@
#include <getopt.h>
#include <errno.h>
/* ************************************************************************* */
/* Help and version messages */
/* ************************************************************************* */
/* ---
* Help and version messages.
* --- */
/* The version message - that's when the President comes in */
static const char version_message[] =
BIN " - from " NAME " v" VERSION " (licensed under GPLv2)\n"
"Maintained by " MAINTAINER ".\n"
@ -36,17 +38,20 @@ BIN " - from " NAME " v" VERSION " (licensed under GPLv2)\n"
"FITNESS FOR A PARTICULAR PURPOSE.";
/* Main help message */
static const char help_main0[] =
"Usage: " BIN " [--version|-v] [--help|-h] [--com <device>]\n"
" [--no-prepare] [--uexe <path>]\n"
" <subcommand> [options...]\n"
"\n"
"This program interacts with a CASIO calculator's firmware.\n"
"Keep in mind that using it is dangerous and could easily brick your\n"
"calculator if you aren't careful enough.\n"
"Keep in mind that using it is HIGHLY DANGEROUS and could easily brick your\n"
"calculator if you aren't careful enough. AVOID USING IT IF YOU DO NOT\n"
"KNOW WHAT YOU'RE DOING.\n"
"\n"
"Subcommands you can use are :\n"
" prepare-only Set-up the update program, but leave it for other programs\n"
" prepare-only Set-up the update program, but leave it for other "
"programs\n"
" to interact with it.\n"
" get Get the OS image.\n"
" flash Flash the OS image.\n"
@ -66,16 +71,19 @@ static const char help_main1[] =
" calculator connected using direct USB.\n"
" --no-prepare Use the current environment, instead of uploading one.\n"
" -u, --uexe <path> Use a custom update program.\n"
" If `--no-prepare` is not given, this option is required.\n"
" If `--no-prepare` is not given, this option is "
"required.\n"
"\n"
"Type \"" BIN " <subcommand> --help\" for some help about a subcommand.\n"
"Report bugs to " MAINTAINER ".";
/* Subcommands help messages footer */
/* Subcommands help messages footer. */
#define FOOT \
"\nType \"" BIN " --help\" for other subcommands and general options."
/* Help message for prepare subcommand */
static const char help_prepare_only[] =
"Usage: " BIN " prepare-only\n"
"Send the P7 server on the calculator for further operations.\n"
@ -83,6 +91,7 @@ static const char help_prepare_only[] =
FOOT;
/* Help message for get subcommand */
static const char help_get[] =
"Usage: " BIN " get [-o <os.bin>]\n"
"Get the calculator OS image.\n"
@ -92,13 +101,16 @@ static const char help_get[] =
FOOT;
/* Help message for flash subcommand. */
static const char help_flash[] =
"Usage: " BIN " flash <rom.bin>\n"
"Flash the calculator's OS image.\n"
FOOT;
/* ************************************************************************* */
/* Main help message. */
/* ************************************************************************* */
/* ---
* Put the help message.
* --- */
/**
* put_loglevel:
* Put a loglevel (for listing).
@ -111,7 +123,8 @@ static void put_loglevel(char **first, const char *level)
{
if (!*first) {
*first = malloc(strlen(level) + 2);
if (!*first) return ;
if (!*first)
return ;
strcpy(*first + 1, level);
**first = 'F';
return ;
@ -146,10 +159,13 @@ static void put_help(void)
/* second big part */
puts(help_main1);
}
/* ************************************************************************* */
/* Main function */
/* ************************************************************************* */
/* Help macro */
/* ---
* Main argument parsing function.
* --- */
/* Help macro. */
#define sub_init(CMD, NARGS) { \
args->menu = mn_##CMD; \
if (help || pc != (NARGS)) { \
@ -158,6 +174,7 @@ static void put_help(void)
}}
/* Options. */
static const char shopts[] = "hvu:o:#";
static const struct option longopts[] = {
{"help", no_argument, NULL, 'h'},
@ -184,58 +201,82 @@ static const struct option longopts[] = {
int parse_args(int ac, char **av, args_t *args)
{
int c, help = 0, version = 0;
int c, help = 0, version = 0, pc;
char **pv, *sub;
const char *s_out = "os.bin", *s_uexe = NULL, *s_log = NULL;
/* Initialize the arguments. */
memset(args, 0, sizeof(*args));
/* get all options */
args->menu = 0;
args->noprepare = 0;
args->com = NULL;
args->local = NULL;
args->localpath = NULL;
args->uexe = NULL;
/* Get all options. */
opterr = 0;
while (1) {
c = getopt_long(ac, av, shopts, longopts, NULL);
if (c < 0) break;
while ((c = getopt_long(ac, av, shopts, longopts, NULL)) >= 0) switch (c) {
case 'h':
help = 1;
break;
case 'v':
version = 1;
break;
switch (c) {
case 'h': help = 1; break;
case 'v': version = 1; break;
/* COM port, should prepare or not. */
/* COM port, should prepare or not */
case 'c': args->com = optarg; break;
case 'n': args->noprepare = 1; break;
case 'c':
args->com = optarg;
break;
case 'n':
args->noprepare = 1;
break;
/* log level, Update.Exe, output path */
case 'l': s_log = optarg; break;
case 'u': s_uexe = optarg; break;
case 'o': s_out = optarg; break;
/* error */
case 'l':
s_log = optarg;
break;
case 'u':
s_uexe = optarg;
break;
case 'o':
s_out = optarg;
break;
/* Error. */
case '?':
if (optopt == 'o')
log("-o, --output: expected an argument\n");
fprintf(stderr, "-o, --output: expected an argument\n");
else if (optopt == 'c')
log("--com: expected an argument\n");
fprintf(stderr, "--com: expected an argument\n");
else if (optopt == 'u')
log("-u, --uexe: expected an argument\n");
fprintf(stderr, "-u, --uexe: expected an argument\n");
else
break;
return (1);
}
}
/* check for version */
/* Check for version. */
if (version) {
puts(version_message);
return (1);
}
/* get non-option arguments (subcommand and parameters) */
int pc = ac - optind;
char **pv = &av[optind];
char *sub = pc ? pv[0] : NULL;
pc--; pv++;
/* Get non-option arguments (subcommand and parameters). */
pc = ac - optind;
pv = &av[optind];
sub = pc ? pv[0] : NULL;
pc--;
pv++;
/* Subcommand parsing. */
/* subcommand. */
char fpmode[3] = "r\0";
if (!sub || !strcmp(sub, "help")) {
put_help();
@ -243,12 +284,12 @@ int parse_args(int ac, char **av, args_t *args)
} else if (!strcmp(sub, "version")) {
puts(version_message);
return (1);
} else if (!strcmp(sub, "prepare-only")) {
sub_init(prepare_only, 0)
if (args->noprepare) {
log("So we should prepare but we should not prepare? Duh!\n");
fprintf(stderr,
"So we should prepare but we should not prepare? Duh!\n");
return (1);
}
} else if (!strcmp(sub, "get")) {
@ -259,15 +300,17 @@ int parse_args(int ac, char **av, args_t *args)
sub_init(flash, 1)
args->localpath = pv[0];
} else {
log("Unknown subcommand '%s'.\n", sub);
fprintf(stderr, "Unknown subcommand '%s'.\n", sub);
return (1);
}
/* open destination file */
/* Open destination file. */
if (args->localpath) {
FILE *localfile = fopen(args->localpath, fpmode);
if (!localfile) {
log("Could not open local file: %s\n", strerror(errno));
fprintf(stderr, "Could not open local file: %s\n",
strerror(errno));
return (1);
}
@ -276,40 +319,51 @@ int parse_args(int ac, char **av, args_t *args)
fpmode[0] == 'w' || fpmode[1] == '+' ? localfile : NULL,
1, 1);
if (err) {
log("Could not make a stream out of local file: %s\n",
fprintf(stderr, "Could not make a stream out of local file: %s\n",
casio_strerror(err));
return (1);
}
}
/* open update.exe file */
/* Open update.exe file. */
if (!args->noprepare) {
FILE *uexe;
int err;
if (!s_uexe) {
log("One of `-u <file>` or `--no-prepare` is expected!\n");
if (args->local) casio_close(args->local);
fprintf(stderr,
"One of `-u <file>` or `--no-prepare` is expected!\n");
if (args->local)
casio_close(args->local);
return (1);
}
FILE *uexe = fopen(s_uexe, "r");
uexe = fopen(s_uexe, "r");
if (!uexe) {
log("Could not open update program: %s\n", strerror(errno));
if (args->local) casio_close(args->local);
fprintf(stderr, "Could not open update program: %s\n",
strerror(errno));
if (args->local)
casio_close(args->local);
return (1);
}
int err = casio_open_stream_file(&args->uexe,
err = casio_open_stream_file(&args->uexe,
uexe, NULL, 1, 0);
if (err) {
log("Could not make a stream out of the update.exe: %s\n",
fprintf(stderr,
"Could not make a stream out of the update.exe: %s\n",
casio_strerror(err));
if (args->local) casio_close(args->local);
if (args->local)
casio_close(args->local);
return (1);
}
}
/* set the log level */
if (s_log) casio_setlog(s_log);
/* Set the log level. */
if (s_log)
casio_setlog(s_log);
/* everything went well :) */
return (0);
}

View File

@ -57,48 +57,57 @@ int main(int ac, char **av)
{
int err; args_t args;
/* parse args */
/* Parse the arguments. */
if (parse_args(ac, av, &args))
return (0);
/* prepare */
/* Prepare. */
if (!args.noprepare) {
err = prepare(&args);
if (err) goto fail;
}
/* check according to menu */
/* Check according to menu. */
switch (args.menu) {
case mn_prepare_only: break;
case mn_prepare_only:
/* Nothing here. */
break;
case mn_get:
err = backup_rom(&args); break;
err = backup_rom(&args);
break;
case mn_flash:
#if 0
err = fxremote_flash(&args); break;
#endif
fprintf(stderr,
"fxRemote-like flashing has been removed.\n"
"Sorry for the inconvenience.\n");
err = 0; break;
err = fxremote_flash(&args);
break;
}
fail:
/* close the file, remove if necessary */
/* Close the file, remove if necessary. */
if (args.localpath) {
casio_close(args.local);
if (err && casio_iswritable(args.local))
remove(args.localpath);
}
/* displaying error */
if (err) switch (err) {
/* Display the error, if any. */
switch (err) {
case 0:
break;
case casio_error_nocalc:
log(error_noconnexion); break;
fprintf(stderr, error_noconnexion);
break;
case casio_error_noaccess:
log(error_noaccess); break;
fprintf(stderr, error_noaccess);
break;
case casio_error_command:
log(error_unsupported); break;
default: log(error_unplanned, casio_strerror(err));
fprintf(stderr, error_unsupported);
break;
default:
fprintf(stderr, error_unplanned, casio_strerror(err));
}
return (1);

View File

@ -20,19 +20,21 @@
# define MAIN_H
# include <stdio.h>
# include <libcasio.h>
# define log(S, ...) fprintf(stderr, S, ##__VA_ARGS__)
/* ************************************************************************** */
/* CLI options */
/* ************************************************************************** */
/* Menu */
/* ---
* Command-line arguments.
* --- */
/* Menu. */
enum menu_e {
mn_prepare_only = 1,
mn_get = 2,
mn_flash = 3
};
/* Arguments */
/* Arguments. */
typedef struct {
enum menu_e menu;
int noprepare;
@ -45,9 +47,11 @@ typedef struct {
const char *localpath;
casio_stream_t *uexe;
} args_t;
/* ************************************************************************* */
/* Progress displayer */
/* ************************************************************************* */
/* ---
* Progress displayer.
* --- */
typedef struct {
const char *msg, *success;
@ -61,15 +65,19 @@ extern void osdisp(void *cookie, unsigned int id, unsigned int total);
extern void osdisp_interrupt(osdisp_t *cookie);
extern void osdisp_success(osdisp_t *cookie);
/* ************************************************************************* */
/* Central functions */
/* ************************************************************************* */
/* ---
* Central functions.
* --- */
/* Utilities. */
extern int parse_args(int ac, char **av, args_t *args);
extern int open_link(casio_link_t **link, args_t *args,
unsigned long flags, casio_streamattrs_t *attrs);
/* Main functions. */
extern int prepare(args_t *args);
extern int backup_rom(args_t *args);
extern int fxremote_flash(args_t *args);

View File

@ -0,0 +1,247 @@
/* ****************************************************************************
* p7os/procs/fxremote_flash.c -- fxremote procedure for flashing.
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of p7utils.
* p7utils is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2.0 of the License,
* or (at your option) any later version.
*
* p7utils 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with p7utils; if not, see <http://www.gnu.org/licenses/>.
*
* [EN] WARNING: Two calculators were bricked during the correction of
* this file. Any change to this file has to be made very carefully.
*
* [FR] AVERTISSEMENT : Deux calculatrices ont é rendues inutilisables
* pendant la correction de ce fichier. Tout changement doit être fait
* avec la plus grande prudence.
* ************************************************************************* */
#include "../main.h"
/* FIXME: this procedure already bricked two calculators.
* Avoid bricking a third one and wait for Dark Storm for Planète Casio
* to try to find the problem before using it. PLEASE. */
#define KiB * 1024
#ifndef min
# define min(a, b) ((a) < (b) ? (a) : (b))
#endif
struct data_transfer_block {
casio_uint32_t destination;
casio_uint32_t length;
unsigned char data[0x3FC];
};
struct data_copy_block {
casio_uint32_t destination;
casio_uint32_t length;
casio_uint32_t source;
};
/**
* send_sector:
* Send a sector data and flashwrite it.
*
* @arg handle the link handle.
* @arg stream the update.exe stream.
* @arg addr the address.
* @arg size the sector data size.
* @return the error code (0 if ok).
*/
static int send_sector(casio_link_t *handle, casio_stream_t *buffer,
unsigned long addr, unsigned long size)
{
int err, buf_err;
osdisp_t osdisp_cookie;
/* Sending the data to the Update.Exe's. */
{
char osdisp_string[100];
struct data_transfer_block block;
unsigned long buf = 0x88030000, left = size;
int num, total;
osdisp_init(&osdisp_cookie, osdisp_string, "Flashwriting.");
sprintf(osdisp_string, "Copying sector at 0x%08lX (%lu bytes).",
addr, size);
num = 1;
total = size / 0x3FC + !!(size % 0x3FC);
osdisp(&osdisp_cookie, 1, 0);
while (left) {
unsigned long len = left < 0x3FC ? left : 0x3FC;
/* Prepare the block. */
block.destination = casio_be32toh(buf);
block.length = casio_be32toh(len);
if ((buf_err = casio_read(buffer, block.data, len))) {
osdisp_interrupt(&osdisp_cookie);
return (casio_error_read);
}
/* Pass the block. */
buf += len; left -= len;
/* Send the command with the block. */
err = casio_seven_send_ext(handle, casio_seven_type_cmd,
0x70, &block, 8 + len, 1);
if (err) { osdisp_interrupt(&osdisp_cookie); return (err); }
osdisp(&osdisp_cookie, num++, total);
}
osdisp_success(&osdisp_cookie);
}
/* Copy the internal buffer to the flash sector. */
{
struct data_copy_block block;
block.destination = casio_htobe32(addr);
block.length = casio_htobe32(size);
block.source = casio_htobe32(0x88030000);
err = casio_seven_send_ext(handle, casio_seven_type_cmd,
0x71, &block, 12, 1);
if (err) return (err);
printf("Flashwrote the internal buffer at 0x%08lX.\n", addr);
}
return (0);
}
/**
* fxremote_flash:
* Flash the fxRemote way.
*
* @arg args the arguments.
* @return the error code (0 if ok).
*/
int fxremote_flash(args_t *args)
{
int err, buf_err;
casio_link_t *handle = NULL;
casio_streamattrs_t attrs;
casio_stream_t *buffer = args->local;
unsigned long addr, top; casio_off_t size;
osdisp_t osdisp_cookie;
/* Get the file size. */
err = casio_getsize(buffer, &size);
if (err)
return (err);
if (!size)
return (casio_error_empty);
top = (unsigned long)size | 0xA0000000;
printf("Image to flash goes from 0xA0010000 to 0x%08lX.\n", top - 1);
/* Open the link. */
attrs.casio_streamattrs_flags =
CASIO_TWOSTOPBITS | CASIO_PARDIS | CASIO_DTRCTL_HANDSHAKE
| CASIO_RTSCTL_HANDSHAKE | CASIO_XONCTL_ENABLE | CASIO_XOFFCTL_ENABLE;
attrs.casio_streamattrs_speed = CASIO_B115200;
attrs.casio_streamattrs_cc[CASIO_XON] = 0x11;
attrs.casio_streamattrs_cc[CASIO_XOFF] = 0x13;
err = open_link(&handle, args,
CASIO_LINKFLAG_ACTIVE | CASIO_LINKFLAG_NODISC, &attrs);
if (err)
return (err);
/* Get the 52 bytes at 0xA000FFC0.
* Probably checking if the two first bytes are "00 20" (SH3) or
* else ("00 00", "FF FF", ..., SH4).
* The calculator first sends the ACK (managed by `casio_seven_send_cmd`),
* then the data packet (managed by `casio_seven_receive`).
*
* The original fxRemote does this, so will I.
* XXX: should I check as well? */
if ((err = casio_seven_send_cmd(handle, 0x76))
|| (err = casio_seven_receive(handle, 1)))
goto fail;
/* Clear the sectors.
* The original fxRemote does that before setting the sectors.
* Maybe it just ANDs, or something...? Anyway, I'll do it as well. */
{
int num = 1, total = (top - 0xA0010000) / 0x10000;
osdisp_init(&osdisp_cookie, "Clearing the sectors.", "Cleared!");
osdisp(&osdisp_cookie, 1, 0);
for (addr = 0xA0010000; addr < top; addr += 0x10000) {
casio_uint32_t localaddr;
localaddr = casio_htobe32(addr);
err = casio_seven_send_ext(handle, casio_seven_type_cmd,
0x72, &localaddr, 4, 1);
if (err) {
osdisp_interrupt(&osdisp_cookie);
goto fail;
}
osdisp(&osdisp_cookie, num++, total);
}
osdisp_success(&osdisp_cookie);
}
/* Send each sector. */
for (addr = 0xA0020000; addr < top; addr += 0x10000) {
/* Seek to the address. */
buf_err = casio_seek(buffer, addr & 0x0FFFFFFF, CASIO_SEEK_SET);
if (buf_err) {
err = casio_error_noseek;
goto fail;
}
/* Send the sector from there. */
err = send_sector(handle, buffer, addr, min(size - addr, 0x10000));
if (err)
goto fail;
}
/* fxRemote sends the first OS sector once all of the other sectors
* are sent, for some reason. I'll do the same here. */
addr = 0xA0010000;
{
/* Seek to the address. */
buf_err = casio_seek(buffer, addr & 0x0FFFFFFF, CASIO_SEEK_SET);
if (buf_err) {
err = casio_error_noseek;
goto fail;
}
/* Send the sector from there. */
err = send_sector(handle, buffer, addr, min(size - addr, 0x10000));
if (err)
goto fail;
}
/* Final command. */
err = casio_seven_send_basic(handle, casio_seven_type_cmd, 0x79, 0);
if (err)
goto fail;
err = 0;
fail:
if (err)
casio_seven_send_term_because(handle, casio_seven_term_user);
casio_close_link(handle);
return (err);
}

View File

@ -116,12 +116,10 @@ static void put_help(void)
* @return 0 if ok, other if not.
*/
int parse_args(int ac, char **av, int *zoom)
int parse_args(int ac, char **av, unsigned int *zoom)
{
/* initialize args */
*zoom = DEFAULT_ZOOM;
/* define options */
int c, help = 0, version = 0;
const char *s_log = NULL;
const char short_options[] = "hvz:";
const struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
@ -131,30 +129,38 @@ int parse_args(int ac, char **av, int *zoom)
{NULL, 0, NULL, 0}
};
/* Initialize the arguments. */
*zoom = DEFAULT_ZOOM_I;
/* get all options */
int c; opterr = 0;
int help = 0, version = 0;
const char *s_log = NULL;
opterr = 0;
while ((c = getopt_long(ac, av, short_options, long_options, NULL)) != -1)
switch (c) {
/* help */
case 'h': help = 1; break;
/* version */
case 'v': version = 1; break;
/* zoom */
/* Help, version, log level. */
case 'h':
help = 1;
break;
case 'v':
version = 1;
break;
case 'l':
s_log = optarg;
break;
/* Zoom. */
case 'z':
*zoom = atoi(optarg);
*zoom = (unsigned int)atoi(optarg);
if (*zoom <= 0 || *zoom > 16) {
fprintf(stderr, "-z, --zoom: should be between 1 and 16");
return (1);
}
break;
case 'l':
s_log = optarg;
break;
/* Error (ignore unknown options?). */
/* error (ignore) */
case '?':
if (optopt == 'z')
fprintf(stderr, "-z, --zoom: expected an argument\n");
@ -163,16 +169,23 @@ int parse_args(int ac, char **av, int *zoom)
return (1);
}
/* check if there is any parameter */
if (ac - optind) help = 1;
/* Check if there is any parameter. */
if (ac - optind)
help = 1;
/* Set the log level. */
/* set the log level */
if (s_log)
casio_setlog(s_log);
/* print help or version if required, and return */
if (version) puts(version_message);
else if (help) put_help();
else return (0);
/* Print help or version if required, and return. */
if (version)
puts(version_message);
else if (help)
put_help();
else
return (0);
return (1);
}

View File

@ -19,10 +19,12 @@
#include "main.h"
#include <SDL.h>
/* ************************************************************************** */
/* Error messages */
/* ************************************************************************** */
/* ---
* Error messages.
* --- */
/* Couldn't initialize connexion to calculator. */
static const char error_noconnexion[] =
"Could not connect to the calculator.\n"
"- Is it plugged in and in PROJ mode?\n"
@ -30,139 +32,165 @@ static const char error_noconnexion[] =
"- Have you tried changing the cable?\n";
/* Calculator was found but program wasn't allowed to communicate with it. */
static const char error_noaccess[] =
"Could not get access to the calculator.\n"
"Install the appropriate udev rule, or run as root.\n";
/* The calculator acted in a weird way. */
static const char error_unplanned[] =
"The calculator didn't act as planned.\n"
"Stop receive mode on calculator and start it again before re-running " \
BIN ".\n"
"Error was: %s\n";
/* ************************************************************************** */
/* Globals */
/* ************************************************************************** */
/* The z00m (omG) */
static int zoom;
/* ---
* Globals.
* --- */
/* The z00m (omG). */
static unsigned int zoom;
/* ---
* Main functions.
* --- */
/* ************************************************************************** */
/* Auxiliary functions */
/* ************************************************************************** */
/**
* display_callback:
* The main callback for screen streaming.
* display_screen:
* Display the screen.
*
* @arg vcookie the cookie (unused).
* @arg w the width of the received image
* @arg h the height of the received image
* @arg pixels the image data
* @arg link the link handle to use.
* @return the main code.
*/
static void display_callback(void *vcookie,
int w, int h, casio_uint32_t **pixels)
static int display_screen(casio_link_t *link)
{
static SDL_Window *window = NULL;
static SDL_Renderer *rendr = NULL;
static SDL_Texture *texture = NULL;
static int saved_w = 0, saved_h = 0;
SDL_Window *window = NULL;
SDL_Renderer *rendr = NULL;
SDL_Texture *texture = NULL;
int ret = 1, err;
unsigned int w, saved_w, h, saved_h;
casio_screen_t *screen = NULL;
casio_pixel_t **pixels;
(void)vcookie;
while (1) {
/* Get the screen. */
if (!window) {
int ret;
switch ((err = casio_get_screen(link, &screen))) {
case 0:
break;
case casio_error_nocalc:
goto end;
case casio_error_timeout:
fprintf(stderr, error_noconnexion);
goto fail;
default:
fprintf(stderr, error_unplanned, casio_strerror(err));
goto fail;
}
/* We haven't got a window, our objective is to create one,
* with a renderer and a texture. First, let's create the window. */
w = screen->casio_screen_width;
h = screen->casio_screen_height;
pixels = screen->casio_screen_pixels;
window = SDL_CreateWindow("p7screen",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
w * zoom, h * zoom, 0);
if (!window) {
fprintf(stderr, "Couldn't create the window: %s\n",
SDL_GetError());
return ;
/* We haven't got a window, our objective is to create one,
* with a renderer and a texture. First, let's create the
* window. */
window = SDL_CreateWindow("p7screen",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
w * zoom, h * zoom, 0);
if (!window) {
fprintf(stderr, "Couldn't create the window: %s\n",
SDL_GetError());
goto fail;
}
/* Then let's create the renderer. */
rendr = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
if (!rendr) {
fprintf(stderr, "Couldn't create the renderer: %s\n",
SDL_GetError());
goto fail;
}
/* Finally, create the texture we're gonna use for drawing
* the picture as a classic ARGB pixel matric (8 bits per
* component). */
texture = SDL_CreateTexture(rendr, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, w * zoom, h * zoom);
if (!texture) {
fprintf(stderr, "Couldn't create the texture: %s\n",
SDL_GetError());
goto fail;
}
/* Save data and display message. */
saved_w = w;
saved_h = h;
puts("Turn off your calculator (SHIFT+AC) "
"when you have finished.");
} else if (saved_w != w || saved_h != h) {
/* The dimensions have changed somehow, we're gonna manage it!
* FIXME: one day. */
fprintf(stderr, "Unmanaged dimensions changed.\n");
goto fail;
}
/* Then let's create the renderer. */
/* Copy the data. */
rendr = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
if (!rendr) {
SDL_DestroyWindow(window);
window = NULL;
{
Uint32 *px;
int pitch, linesize = w * zoom;
unsigned int x, y, zx, zy;
fprintf(stderr, "Couldn't create the renderer: %s\n",
SDL_GetError());
return ;
SDL_LockTexture(texture, NULL, (void **)&px, &pitch);
for (y = 0; y < h; y++) {
Uint32 *refline = px;
for (x = 0; x < w; x++) {
Uint32 pixel = pixels[y][x];
for (zx = 0; zx < zoom; zx++)
*px++ = pixel;
}
for (zy = 1; zy < zoom; zy++) {
memcpy(px, refline, linesize * sizeof(uint32_t));
px += linesize;
}
}
SDL_UnlockTexture(texture);
}
/* Finally, create the texture we're gonna use for drawing
* the picture as a classic ARGB pixel matric (8 bits per
* component). */
/* Flippin' flip the screen! */
texture = SDL_CreateTexture(rendr, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, w * zoom, h * zoom);
if (!texture) {
SDL_DestroyRenderer(rendr);
rendr = NULL;
SDL_DestroyWindow(window);
window = NULL;
fprintf(stderr, "Couldn't create the texture: %s\n",
SDL_GetError());
return ;
}
/* Save data and display message. */
saved_w = w;
saved_h = h;
puts("Turn off your calculator (SHIFT+AC) when you have finished.");
} else if (saved_w != w || saved_h != h) {
/* The dimensions have changed somehow, we're gonna manage it!
* FIXME: one day. */
return ;
SDL_RenderCopy(rendr, texture, NULL, NULL);
SDL_RenderPresent(rendr);
}
/* Copy the data. */
{
Uint32 *px;
int pitch;
int linesize = w * zoom;
SDL_LockTexture(texture, NULL, (void **)&px, &pitch);
for (int y = 0; y < h; y++) {
Uint32 *refline = px;
for (int x = 0; x < w; x++) {
Uint32 pixel = pixels[y][x];
for (int zx = 0; zx < zoom; zx++)
*px++ = pixel;
}
for (int zy = 1; zy < zoom; zy++) {
memcpy(px, refline, linesize * sizeof(uint32_t));
px += linesize;
}
}
SDL_UnlockTexture(texture);
}
/* Flippin' flip the screen! */
SDL_RenderCopy(rendr, texture, NULL, NULL);
SDL_RenderPresent(rendr);
end:
ret = 0;
fail:
casio_free_screen(screen);
if (texture)
SDL_DestroyTexture(texture);
if (rendr)
SDL_DestroyRenderer(rendr);
if (window)
SDL_DestroyWindow(window);
return (ret);
}
/* ************************************************************************** */
/* Main function */
/* ************************************************************************** */
/**
* main:
* Entry point of the program.
@ -176,13 +204,14 @@ int main(int ac, char **av)
{
int err; casio_link_t *handle = NULL;
/* parse args */
/* Parse the arguments. */
if (parse_args(ac, av, &zoom))
return (0);
/* Make the libcasio link handle. */
if ((err = casio_open_usb(&handle, 0))) {
/* display error */
switch (err) {
case casio_error_nocalc:
fprintf(stderr, error_noconnexion);
@ -199,30 +228,20 @@ int main(int ac, char **av)
return (1);
}
/* Initialize SDL */
/* Initialize the SDL. */
if (SDL_Init(SDL_INIT_VIDEO)) {
fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError());
return (3);
}
atexit(SDL_Quit);
/* receive screen */
if ((err = casio_getscreen(handle, &display_callback, NULL))
&& err != casio_error_nocalc) {
switch (err) {
case casio_error_timeout:
fprintf(stderr, error_noconnexion);
break;
default:
fprintf(stderr, error_unplanned, casio_strerror(err));
break;
}
return (1);
}
/* Display the screen. */
display_screen(handle);
/* Close the link and exit. */
/* close */
casio_close_link(handle);
/* everything went well */
return (0);
}

View File

@ -25,6 +25,6 @@
/* Prototypes. */
int parse_args(int ac, char **av, int *zoom);
int parse_args(int ac, char **av, unsigned int *zoom);
#endif /* MAIN_H */