diff --git a/Makefile.vars b/Makefile.vars index da9fa6d..dd70f12 100755 --- a/Makefile.vars +++ b/Makefile.vars @@ -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)) diff --git a/include/libcasio/link.h b/include/libcasio/link.h index bd5f955..2a74865 100644 --- a/include/libcasio/link.h +++ b/include/libcasio/link.h @@ -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. */ diff --git a/include/libcasio/protocol/seven.h b/include/libcasio/protocol/seven.h index 96a6549..34597d2 100644 --- a/include/libcasio/protocol/seven.h +++ b/include/libcasio/protocol/seven.h @@ -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, diff --git a/lib/link/seven/receive.c b/lib/link/seven/receive.c index c3f9067..28bc6ee 100644 --- a/lib/link/seven/receive.c +++ b/lib/link/seven/receive.c @@ -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 (""); 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; diff --git a/lib/link/usage/getscreen.c b/lib/link/usage/getscreen.c index 9843921..7673f91 100644 --- a/lib/link/usage/getscreen.c +++ b/lib/link/usage/getscreen.c @@ -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); } diff --git a/man/p7.1.txt b/man/p7.1.txt index 41062a0..8ec9473 100644 --- a/man/p7.1.txt +++ b/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 *:: + If a serial connexion is used, tells p7 to use the given settings, which + are of the format , e.g. 9600N2. +*--set *:: + 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*:: diff --git a/man/p7os.1.txt b/man/p7os.1.txt index 8fd1007..ff494c3 100644 --- a/man/p7os.1.txt +++ b/man/p7os.1.txt @@ -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 *:: + 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. diff --git a/man/p7screen.1.txt b/man/p7screen.1.txt index 9951f3f..4b3620d 100644 --- a/man/p7screen.1.txt +++ b/man/p7screen.1.txt @@ -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 -------- diff --git a/src/p7os/args.c b/src/p7os/args.c index a250b28..02b5972 100644 --- a/src/p7os/args.c +++ b/src/p7os/args.c @@ -23,10 +23,12 @@ #include #include -/* ************************************************************************* */ -/* 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 ]\n" " [--no-prepare] [--uexe ]\n" " [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 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 " --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 ]\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 \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 ` or `--no-prepare` is expected!\n"); - if (args->local) casio_close(args->local); + fprintf(stderr, + "One of `-u ` 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); } diff --git a/src/p7os/main.c b/src/p7os/main.c index 55a9889..08a1424 100644 --- a/src/p7os/main.c +++ b/src/p7os/main.c @@ -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); diff --git a/src/p7os/main.h b/src/p7os/main.h index aa26fa6..c66e309 100644 --- a/src/p7os/main.h +++ b/src/p7os/main.h @@ -20,19 +20,21 @@ # define MAIN_H # include # include -# 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); diff --git a/src/p7os/procs/fxremote_flash.c b/src/p7os/procs/fxremote_flash.c new file mode 100644 index 0000000..5ae98ac --- /dev/null +++ b/src/p7os/procs/fxremote_flash.c @@ -0,0 +1,247 @@ +/* **************************************************************************** + * p7os/procs/fxremote_flash.c -- fxremote procedure for flashing. + * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey + * + * 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 . + * + * [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); +} diff --git a/src/p7screen/args.c b/src/p7screen/args.c index b020f63..2cd3d27 100644 --- a/src/p7screen/args.c +++ b/src/p7screen/args.c @@ -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); } diff --git a/src/p7screen/main.c b/src/p7screen/main.c index 07ad87b..327871d 100644 --- a/src/p7screen/main.c +++ b/src/p7screen/main.c @@ -19,10 +19,12 @@ #include "main.h" #include -/* ************************************************************************** */ -/* 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); } diff --git a/src/p7screen/main.h b/src/p7screen/main.h index 895db02..f4098ea 100644 --- a/src/p7screen/main.h +++ b/src/p7screen/main.h @@ -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 */