Fixed p7screen.
This commit is contained in:
parent
1b11596319
commit
31ad4cb0b6
|
@ -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))
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
11
man/p7.1.txt
11
man/p7.1.txt
|
@ -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*::
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
--------
|
||||
|
|
176
src/p7os/args.c
176
src/p7os/args.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 été 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue