/* Hey EMACS -*- linux-c -*- */
/* $Id: ti89.c 1397 2005-07-20 10:55:03Z roms $ */
/* libticalcs - Ti Calculator library, a part of the TiLP project
* Copyright (C) 1999-2005 Romain Lievin
* Copyright (c) 2005, Christian Walther (patches for Mac OS-X port)
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
This unit provides TI89/TI92+/V200/TI89 Titanium support.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "gettext.h"
#include "headers.h"
#include "externs.h"
#include "update.h"
#include "packets.h"
#include "calc_err.h"
#include "cmd89.h"
#include "rom89.h"
#include "keys89.h"
#include "pause.h"
#include "dirlist.h"
#include "printl.h"
// Screen coordinates of the TI89
#define TI89_ROWS 128
#define TI89_COLS 240
#define TI89_ROWS_VISIBLE 100
#define TI89_COLS_VISIBLE 160
int ti89_supported_operations(void)
{
return
(OPS_ISREADY |
OPS_SCREENDUMP |
OPS_SEND_KEY | OPS_RECV_KEY | OPS_REMOTE |
OPS_DIRLIST |
OPS_SEND_BACKUP | OPS_RECV_BACKUP |
OPS_SEND_VARS | OPS_RECV_VARS |
OPS_SEND_FLASH | OPS_RECV_FLASH |
OPS_IDLIST | OPS_ROMDUMP | OPS_CLOCK);
}
int ti89_isready(void)
{
uint16_t status;
printl2(0, _("Is calculator ready ?\n"));
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
TRYF(ti89_send_RDY());
TRYF(ti89_recv_ACK(&status));
TRYF(cable->close());
UNLOCK_TRANSFER();
return (status & 0x01) ? ERR_NOT_READY : 0;
}
int ti89_send_key(uint16_t key)
{
LOCK_TRANSFER();
TRYF(cable->open());
TRYF(ti89_send_KEY(key));
TRYF(ti89_recv_ACK(NULL));
TRYF(cable->close());
UNLOCK_TRANSFER();
return 0;
}
int ti89_screendump(uint8_t ** bitmap, int mask_mode,
TicalcScreenCoord * sc)
{
uint32_t max_cnt;
int err;
printl2(0, _("Receiving screendump...\n"));
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
sc->width = TI89_COLS;
sc->height = TI89_ROWS;
switch (ticalcs_calc_type) {
case CALC_TI89:
case CALC_TI89T:
sc->clipped_width = TI89_COLS_VISIBLE;
sc->clipped_height = TI89_ROWS_VISIBLE;
break;
case CALC_TI92P:
case CALC_V200:
sc->clipped_width = TI89_COLS;
sc->clipped_height = TI89_ROWS;
break;
}
if (*bitmap != NULL)
free(*bitmap);
(*bitmap) =
(uint8_t *) malloc(TI89_COLS * TI89_ROWS * sizeof(uint8_t) / 8);
if ((*bitmap) == NULL) {
printl2(2, "Unable to allocate memory.\n");
exit(0);
}
TRYF(ti89_send_SCR());
TRYF(ti89_recv_ACK(NULL));
err = ti89_recv_XDP(&max_cnt, *bitmap); // pb with checksum
if (err != ERR_CHECKSUM) {
TRYF(err)};
TRYF(ti89_send_ACK());
printl2(0, _("Done.\n"));
TRYF(cable->close());
UNLOCK_TRANSFER();
// Clip the unused part of the screen (nethertheless useable witha asm prog)
if (((ticalcs_calc_type == CALC_TI89) || (ticalcs_calc_type == CALC_TI89T))
&& (mask_mode == CLIPPED_SCREEN)) {
int i, j, k;
for (i = 0, j = 0; j < TI89_ROWS_VISIBLE; j++)
for (k = 0; k < (TI89_COLS_VISIBLE >> 3); k++)
(*bitmap)[i++] = (*bitmap)[j * (TI89_COLS >> 3) + k];
}
return 0;
}
int ti89_directorylist(TNode ** tree, uint32_t * memory)
{
uint8_t buffer[65536];
TiVarEntry info;
uint32_t block_size;
int i, j;
TNode *vars, *apps;
uint8_t extra = (ticalcs_calc_type == CALC_V200) ? 8 : 0;
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
printl2(0, _("Directory listing...\n"));
TRYF(ti89_send_REQ(TI89_FDIR << 24, TI89_RDIR, ""));
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_VAR(&info.size, &info.type, info.name));
TRYF(ti89_send_ACK());
TRYF(ti89_send_CTS());
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_XDP(&block_size, buffer));
TRYF(ti89_send_ACK());
TRYF(ti89_recv_EOT());
TRYF(ti89_send_ACK());
// get list of folders & FLASH apps
*tree = t_node_new(NULL);
vars = t_node_new(NULL);
apps = t_node_new(NULL);
t_node_append(*tree, vars);
t_node_append(*tree, apps);
for (j = 4; j < (int)block_size;) {
TiVarEntry *fe = calloc(1, sizeof(TiVarEntry));
TNode *node;
memcpy(fe->name, buffer + j, 8);
fe->name[8] = '\0';
fe->type = buffer[j + 8];
fe->attr = buffer[j + 9];
fe->size = buffer[j + 10] | (buffer[j + 11] << 8) | (buffer[j + 12] << 16); // | (buffer[j+13] << 24);
j += 14 + extra;
strcpy(fe->folder, "");
tifiles_translate_varname(fe->name, fe->trans, fe->type);
node = t_node_new(fe);
printl2(0, _("Name: %8s | "), fe->name);
printl2(0, _("Type: %8s | "), tifiles_vartype2string(fe->type));
printl2(0, _("Attr: %i | "), fe->attr);
printl2(0, _("Size: %08X\n"), fe->size);
if (fe->type == TI89_DIR)
t_node_append(vars, node);
else if (fe->type == TI89_APPL)
continue; // AMS<2.08 returns FLASH apps
}
// get list of variables into each folder
for (i = 0; i < (int)t_node_n_children(vars); i++) {
TNode *folder = t_node_nth_child(vars, i);
char *folder_name = ((TiVarEntry *) (folder->data))->name;
printl2(0, _("Directory listing in %8s...\n"), folder_name);
TRYF(ti89_send_REQ(TI89_LDIR << 24, TI89_RDIR, folder_name));
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_VAR(&info.size, &info.type, info.name));
TRYF(ti89_send_ACK());
TRYF(ti89_send_CTS());
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_XDP(&block_size, buffer));
TRYF(ti89_send_ACK());
TRYF(ti89_recv_EOT());
TRYF(ti89_send_ACK());
for (j = 4 + 14 + extra; j < (int)block_size;) {
TiVarEntry *ve = calloc(1, sizeof(TiVarEntry));
TNode *node;
memcpy(ve->name, buffer + j, 8);
ve->name[8] = '\0';
ve->type = buffer[j + 8];
ve->attr = buffer[j + 9];
ve->size = buffer[j + 10] | (buffer[j + 11] << 8) | (buffer[j + 12] << 16); // | (buffer[j+13] << 24);
j += 14 + extra;
strcpy(ve->folder, folder_name);
tifiles_translate_varname(ve->name, ve->trans, ve->type);
node = t_node_new(ve);
printl2(0, _("Name: %8s | "), ve->trans);
printl2(0, _("Type: %8s | "), tifiles_vartype2string(ve->type));
printl2(0, _("Attr: %i | "), ve->attr);
printl2(0, _("Size: %08X\n"), ve->size);
sprintf(update->label_text, _("Reading of '%s/%s'"),
((TiVarEntry *) (folder->data))->trans, ve->trans);
update_label();
if (update->cancel)
return -1;
if (ve->type == TI89_APPL) {
if (!ticalc_check_if_app_exists(*tree, ve->name))
t_node_append(apps, node);
else
free(ve);
} else
t_node_append(folder, node);
}
printl2(0, "\n");
}
*memory = ticalc_dirlist_memused(*tree);
TRYF(cable->close());
UNLOCK_TRANSFER();
return 0;
}
int ti89_recv_var(char *filename, int mask_mode, TiVarEntry * entry);
int ti89_recv_backup(const char *filename, int mask_mode)
{
int i, j;
int i_max, j_max;
int mask = MODE_BACKUP;
TNode *tree, *vars;
uint32_t mem;
int nvars, ivars = 0;
int b;
printl2(0, _("Receiving backup...\n"));
// Do a directory list and check for something to backup
TRYF(ti89_directorylist(&tree, &mem));
nvars = ticalc_dirlist_numvars(tree);
if (!nvars)
return ERR_NO_VARS;
// Check whether the last folder is empty
vars = t_node_nth_child(tree, 0);
b = t_node_n_children(t_node_nth_child(vars,
t_node_n_children(vars) - 1));
// Receive all variables, except FLASH apps
i_max = t_node_n_children(vars);
for (i = 0; i < i_max; i++) {
TNode *parent = t_node_nth_child(vars, i);
j_max = t_node_n_children(parent);
for (j = 0; j < j_max; j++) {
TNode *node = t_node_nth_child(parent, j);
TiVarEntry *ve = (TiVarEntry *) (node->data);
if (!i && !j)
mask = mask_mode | MODE_RECEIVE_FIRST_VAR;
else if ((i == i_max - 1) && (j == j_max - 1) && b)
mask = mask_mode | MODE_RECEIVE_LAST_VAR;
else if ((i == i_max - 2) && (j == j_max - 1) && !b)
mask = mask_mode | MODE_RECEIVE_LAST_VAR;
else
mask = mask_mode;
TRYF(ti89_isready());
TRYF(ti89_recv_var((char *) filename, mask, ve));
(update->main_percentage) = (float) ivars++ / nvars;
if (update->cancel)
return ERR_ABORT;
}
}
ticalc_dirlist_destroy(&tree);
update_stop();
TRY(cable->close());
return 0;
}
int ti89_send_var(const char *filename, int mask_mode, char **actions);
int ti89_send_backup(const char *filename, int mask_mode)
{
printl2(0, _("Sending backup...\n"));
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
sprintf(update->label_text, _("Sending backup..."));
update_label();
TRYF(ti89_send_VAR(0, TI89_BKUP, "main"));
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_CTS());
TRYF(ti89_send_ACK());
TRYF(ti89_send_EOT());
TRYF(ti89_recv_ACK(NULL));
TRYF(cable->close());
UNLOCK_TRANSFER();
TRYF(ti89_send_var(filename, mask_mode | MODE_BACKUP, NULL));
return 0;
}
int ti89_recv_var(char *filename, int mask_mode, TiVarEntry * entry)
{
static Ti9xRegular *content;
uint16_t status;
TiVarEntry *ve;
char *fn;
static int nvar = 0;
uint32_t unused;
uint8_t varname[20], utf8[35];
printl2(0, _("Receiving variable(s)...\n"));
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
if ((mask_mode & MODE_RECEIVE_FIRST_VAR) ||
(mask_mode & MODE_RECEIVE_SINGLE_VAR)) {
content = ti9x_create_regular_content();
nvar = 0;
}
content->calc_type = ticalcs_calc_type;
content->entries = (TiVarEntry *) tifiles_realloc(content->entries,
(nvar +
1) *
sizeof(TiVarEntry));
ve = &(content->entries[nvar]);
memcpy(ve, entry, sizeof(TiVarEntry));
strcpy((char*)varname, entry->folder);
strcat((char*)varname, "\\");
strcat((char*)varname, entry->name);
tifiles_translate_varname((char*)varname, (char*)utf8, entry->type);
sprintf(update->label_text, _("Receiving '%s'"), utf8);
update_label();
TRYF(ti89_send_REQ(0, entry->type, (char*)varname));
TRYF(ti89_recv_ACK(&status));
if (status != 0)
return ERR_MISSING_VAR;
TRYF(ti89_recv_VAR(&ve->size, &ve->type, ve->name));
TRYF(ti89_send_ACK());
TRYF(ti89_send_CTS());
TRYF(ti89_recv_ACK(NULL));
ve->data = tifiles_calloc(ve->size + 4, 1);
TRYF(ti89_recv_XDP(&unused, ve->data));
memmove(ve->data, ve->data + 4, ve->size);
TRYF(ti89_send_ACK());
TRYF(ti89_recv_EOT());
TRYF(ti89_send_ACK());
if (++nvar > 1)
strcpy(content->comment, "Group file received by TiLP");
else
strcpy(content->comment, "Single file received by TiLP");
content->num_entries = nvar;
if (mask_mode & MODE_RECEIVE_SINGLE_VAR) { // single
ti9x_write_regular_file(NULL, content, &fn);
strcpy(filename, fn);
tifiles_free(fn);
ti9x_free_regular_content(content);
} else if (mask_mode & MODE_RECEIVE_LAST_VAR) { // group
ti9x_write_regular_file(filename, content, NULL);
ti9x_free_regular_content(content);
}
TRYF(cable->close());
UNLOCK_TRANSFER();
PAUSE(PAUSE_BETWEEN_VARS);
return 0;
}
int ti89_send_var(const char *filename, int mask_mode, char **actions)
{
Ti9xRegular content = { 0 };
int i;
uint16_t status;
printl2(0, _("Sending variable(s)...\n"));
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
sprintf(update->label_text, _("Sending variable(s)..."));
update_label();
TRYF(ti9x_read_regular_file(filename, &content));
for (i = 0; i < content.num_entries; i++) {
TiVarEntry *entry = &(content.entries[i]);
uint8_t buffer[65536 + 4] = { 0 };
uint8_t vartype = entry->type;
uint8_t full_name[18], varname[18], utf8[35];
if (actions == NULL) // backup or old behaviour
strcpy((char*)varname, entry->name);
else if (actions[i][0] == ACT_SKIP) {
printl2(0, _(" '%s' has been skipped !\n"), entry->name);
continue;
} else if (actions[i][0] == ACT_OVER)
strcpy((char*)varname, actions[i] + 1);
if ((mask_mode & MODE_LOCAL_PATH) && !(mask_mode & MODE_BACKUP)) { // local & not backup
strcpy((char*)full_name, (char*)varname);
} else { // full or backup
strcpy((char*)full_name, entry->folder);
strcat((char*)full_name, "\\");
strcat((char*)full_name, (char*)varname);
}
tifiles_translate_varname((char*)full_name, (char*)utf8, entry->type);
sprintf(update->label_text, _("Sending '%s'"), utf8);
update_label();
if (mask_mode & MODE_BACKUP) { // backup: keep attributes
switch (entry->attr) {
case TI89_VNONE:
vartype = TI89_BKUP;
break;
case TI89_VLOCK:
vartype = 0x26;
break;
case TI89_VARCH:
vartype = 0x27;
break;
}
TRYF(ti89_send_RTS(entry->size, vartype, (char*)full_name));
} else {
TRYF(ti89_send_VAR(entry->size, vartype, (char*)full_name));
}
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_CTS());
TRYF(ti89_send_ACK());
memcpy(buffer + 4, entry->data, entry->size);
TRYF(ti89_send_XDP(entry->size + 4, buffer));
TRYF(ti89_recv_ACK(&status));
TRYF(ti89_send_EOT());
TRYF(ti89_recv_ACK(NULL));
if (mask_mode & MODE_BACKUP) {
(update->main_percentage) = (float) i / content.num_entries;
if (update->cancel)
return ERR_ABORT;
}
}
ti9x_free_regular_content(&content);
TRYF(cable->close());
UNLOCK_TRANSFER();
return 0;
}
// automatically build filename and put it into 'filename'.
// mask_mode is unused
// 'entry' contains informations
int ti89_recv_var_2(char *filename, int mask_mode, TiVarEntry * entry)
{
Ti9xRegular *content;
uint32_t unused;
uint8_t utf8[35];
int nvar, err;
char tipath[18];
char *tiname;
printl2(0, _("Receiving variable(s)...\n"));
// open cable
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
// create variable content and fills
content = ti9x_create_regular_content();
content->calc_type = ticalcs_calc_type;
// receive packets
for(nvar = 1;; nvar++)
{
TiVarEntry *ve;
content->entries = (TiVarEntry *) tifiles_realloc(content->entries, nvar * sizeof(TiVarEntry));
ve = &(content->entries[nvar-1]);
strcpy(ve->folder, "main");
err = ti89_recv_VAR(&ve->size, &ve->type, tipath);
TRYF(ti89_send_ACK());
if(err == ERR_EOT) // end of transmission
goto exit;
else
content->num_entries = nvar;
// from Christian (TI can send varname or fldname/varname)
if ((tiname = strchr(tipath, '\\')) != NULL)
{
*tiname = '\0';
strcpy(ve->folder, tipath);
strcpy(ve->name, tiname + 1);
}
else
{
strcpy(ve->folder, "main");
strcpy(ve->name, tipath);
}
tifiles_translate_varname(ve->name, (char*)utf8, ve->type);
sprintf(update->label_text, _("Receiving '%s'"), utf8);
update_label();
TRYF(ti89_send_CTS());
TRYF(ti89_recv_ACK(NULL));
ve->data = tifiles_calloc(ve->size + 4, 1);
TRYF(ti89_recv_XDP(&unused, ve->data));
memmove(ve->data, ve->data + 4, ve->size);
TRYF(ti89_send_ACK());
}
exit:
// close cable
TRYF(cable->close());
UNLOCK_TRANSFER();
// write file content
nvar--;
if(nvar > 1)
{
strcpy(content->comment, "Group file received by TiLP");
strcat(filename, "group.92g");
ti9x_write_regular_file(filename, content, NULL);
}
else
{
strcpy(content->comment, "Single file received by TiLP");
strcat(filename, content->entries[0].name);
strcat(filename, ".");
strcat(filename, tifiles_vartype2file(content->entries[0].type));
ti9x_write_regular_file(filename, content, NULL);
}
ti9x_free_regular_content(content);
return 0;
}
int ti89_send_flash(const char *filename, int mask_mode)
{
Ti9xFlash content = { 0 };
Ti9xFlash *ptr;
int i, nblocks;
int nheaders = 0;
printl2(0, _("Sending FLASH app/os...\n"));
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
sprintf(update->label_text, _("Sending FLASH OS/App..."));
update_label();
TRYF(ti9x_read_flash_file(filename, &content));
// count headers
for (ptr = &content; ptr != NULL; ptr = ptr->next)
nheaders++;
// keep the last one (data)
for (i = 0, ptr = &content; i < nheaders - 1; i++)
ptr = ptr->next;
printl2(0, _("FLASH app/os name: \"%s\"\n"), ptr->name);
printl2(0, _("FLASH app/os size: %i bytes.\n"), ptr->data_length);
if (ptr->data_type == TI89_AMS)
{
if(ticalcs_calc_type == CALC_TI89T)
{
TRYF(ti89_send_RTS2(ptr->data_length, ptr->data_type, ""));
}
else
{
TRYF(ti89_send_RTS(ptr->data_length, ptr->data_type, ""));
}
}
else
{
TRYF(ti89_send_RTS(ptr->data_length, ptr->data_type, ptr->name));
}
nblocks = ptr->data_length / 65536;
for (i = 0; i <= nblocks; i++) {
uint32_t length = (i != nblocks) ? 65536 : ptr->data_length % 65536;
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_CTS());
TRYF(ti89_send_ACK());
TRYF(ti89_send_XDP(length, (ptr->data_part) + 65536 * i));
TRYF(ti89_recv_ACK(NULL));
if (i != nblocks) {
TRYF(ti89_send_CONT());
} else {
TRYF(ti89_send_EOT());
}
update->main_percentage = (float) i / nblocks;
if (update->cancel)
return ERR_ABORT;
}
if (ptr->data_type == TI89_AMS)
TRYF(ti89_recv_ACK(NULL));
printl2(0, _("Flash application/os sent completely.\n"));
TRYF(cable->close());
UNLOCK_TRANSFER();
return 0;
}
int ti89_recv_flash(const char *filename, int mask_mode, TiVarEntry * ve)
{
Ti9xFlash *content;
int i;
printl2(0, _("Receiving FLASH application...\n"));
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
content = ti9x_create_flash_content();
content->calc_type = ticalcs_calc_type;
content->data_part = (uint8_t *) tifiles_calloc(2 * 1024 * 1024, 1); // 2MB max
sprintf(update->label_text, _("Receiving '%s'"), ve->name);
update_label();
TRYF(ti89_send_REQ(0x00, TI89_APPL, ve->name));
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_VAR(&content->data_length, &content->data_type,
content->name));
content->data_length = 0;
for (i = 0;; i++) {
int err;
uint32_t block_size;
TRYF(ti89_send_ACK());
TRYF(ti89_send_CTS());
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_XDP
(&block_size, content->data_part + content->data_length));
TRYF(ti89_send_ACK());
content->data_length += block_size;
err = ti89_recv_CONT();
if (err == ERR_EOT)
break;
TRYF(err);
(update->main_percentage) = (float) content->data_length / ve->size;
if (update->cancel)
return ERR_ABORT;
}
TRYF(ti89_send_ACK());
ti9x_write_flash_file(filename, content);
ti9x_free_flash_content(content);
TRYF(cable->close());
UNLOCK_TRANSFER();
return 0;
}
#define DUMP_ROM89_FILE "dumprom.89z"
//#define ROMSIZE (2*1024) // 2MB or 4MB (Titanium)
int ti89_dump_rom(const char *filename, int mask_mode)
{
int i, j;
uint8_t data;
time_t start, elapsed, estimated, remaining;
char buffer[257];
char tmp[257];
int pad;
FILE *f, *file;
uint16_t checksum, sum;
int ROMSIZE = (ticalcs_calc_type == CALC_TI89T) ||
(ticalcs_calc_type == CALC_V200) ? 4*1024 : 2*1024;
printl2(0, _("ROM dumping...\n"));
// Copies ROM dump program into a file
f = fopen(DUMP_ROM89_FILE, "wb");
if (f == NULL)
return ERR_FILE_OPEN;
fwrite(romDump89, sizeof(unsigned char), romDumpSize89, f);
fclose(f);
// Transfer program to calc
TRYF(ti89_send_var(DUMP_ROM89_FILE, MODE_SEND_ONE_VAR, NULL));
unlink(DUMP_ROM89_FILE);
// Launch calculator program by remote control
sprintf(update->label_text, _("Launching..."));
update_label();
TRY(ti89_send_key(KEY89_CLEAR));
PAUSE(50);
TRY(ti89_send_key(KEY89_CLEAR));
PAUSE(50);
TRY(ti89_send_key('m'));
TRY(ti89_send_key('a'));
TRY(ti89_send_key('i'));
TRY(ti89_send_key('n'));
TRY(ti89_send_key('\\'));
TRY(ti89_send_key('r'));
TRY(ti89_send_key('o'));
TRY(ti89_send_key('m'));
TRY(ti89_send_key('d'));
TRY(ti89_send_key('u'));
TRY(ti89_send_key('m'));
TRY(ti89_send_key('p'));
TRY(ti89_send_key(KEY89_LP));
TRY(ti89_send_key(KEY89_RP));
TRY(ti89_send_key(KEY89_ENTER));
// Open file
file = fopen(filename, "wb");
if (file == NULL)
return ERR_OPEN_FILE;
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
// Receive it now blocks per blocks (1024 + CHK)
update_start();
sprintf(update->label_text, _("Receiving..."));
update_label();
start = time(NULL);
for (i = 0; i < ROMSIZE; i++) {
sum = 0;
update->total = 1024;
for (j = 0; j < 1024; j++) {
TRY(cable->get(&data));
fprintf(file, "%c", data);
sum += data;
update->count = j;
update_pbar();
if (update->cancel)
return -1;
}
TRY(cable->get(&data));
checksum = data << 8;
TRY(cable->get(&data));
checksum |= data;
if (sum != checksum)
return ERR_CHECKSUM;
TRY(cable->put(0xda));
update->main_percentage = (float) i / (ROMSIZE);
if (update->cancel)
return -1;
elapsed = (long) difftime(time(NULL), start);
estimated = (long) (elapsed * (float) (ROMSIZE) / i);
remaining = (long) difftime(estimated, elapsed);
sprintf(buffer, "%s", ctime(&remaining));
sscanf(buffer, "%3s %3s %i %s %i", tmp, tmp, &pad, tmp, &pad);
sprintf(update->label_text, _("Remaining (mm:ss): %s"), tmp + 3);
update_label();
}
TRY(cable->put(0xcc)); // make ROM dumping program exit.
fclose(file);
TRYF(cable->close());
UNLOCK_TRANSFER();
return 0;
}
int ti89_get_idlist(char *id)
{
uint32_t varsize;
uint8_t vartype;
uint8_t varname[9];
printl2(0, _("Getting ID list...\n"));
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
sprintf(update->label_text, _("Getting variable..."));
update_label();
TRYF(ti89_send_REQ(0x0000, TI89_IDLIST, ""));
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_VAR(&varsize, &vartype, (char*)varname));
TRYF(ti89_send_ACK());
TRYF(ti89_send_CTS());
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_XDP(&varsize, (uint8_t*)id));
id[varsize] = '\0';
TRYF(ti89_send_ACK());
TRYF(ti89_recv_EOT());
TRYF(ti89_send_ACK());
TRYF(cable->close());
UNLOCK_TRANSFER();
return 0;
}
int ti89_get_clock(TicalcClock * clock, int mode)
{
uint32_t varsize;
uint8_t vartype;
uint8_t varname[9];
uint8_t buffer[32];
printl2(0, _("Getting clock...\n"));
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
sprintf(update->label_text, _("Getting clock..."));
update_label();
TRYF(ti89_send_REQ(0x0000, TI89_CLK, "Clock"));
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_VAR(&varsize, &vartype, (char*)varname));
TRYF(ti89_send_ACK());
TRYF(ti89_send_CTS());
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_XDP(&varsize, buffer));
TRYF(ti89_send_ACK());
TRYF(ti89_recv_EOT());
TRYF(ti89_send_ACK());
TRYF(cable->close());
UNLOCK_TRANSFER();
clock->year = (buffer[6] << 8) | buffer[7];
clock->month = buffer[8];
clock->day = buffer[9];
clock->hours = buffer[10];
clock->minutes = buffer[11];
clock->seconds = buffer[12];
clock->date_format = buffer[13];
clock->time_format = buffer[14];
return 0;
}
int ti89_set_clock(const TicalcClock * clock, int mode)
{
uint8_t buffer[16] = { 0 };
uint16_t status;
buffer[6] = clock->year >> 8;
buffer[7] = clock->year & 0x00ff;
buffer[8] = clock->month;
buffer[9] = clock->day;
buffer[10] = clock->hours;
buffer[11] = clock->minutes;
buffer[12] = clock->seconds;
buffer[13] = clock->date_format;
buffer[14] = clock->time_format;
buffer[15] = 0xff;
printl2(0, _("Setting clock...\n"));
LOCK_TRANSFER();
TRYF(cable->open());
update_start();
sprintf(update->label_text, _("Setting clock..."));
update_label();
TRYF(ti89_send_RTS(0x10, TI89_CLK, "Clock"));
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_recv_CTS());
TRYF(ti89_send_ACK());
TRYF(ti89_send_XDP(0x10, buffer));
TRYF(ti89_recv_ACK(NULL));
TRYF(ti89_send_EOT());
TRYF(ti89_recv_ACK(&status));
TRYF(cable->close());
UNLOCK_TRANSFER();
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1