/* Hey EMACS -*- linux-c -*- */ /* $Id: ti73.c 1397 2005-07-20 10:55:03Z roms $ */ /* libticalcs - Ti Calculator library, a part of the TiLP project * Copyright (C) 1999-2004 Romain Lievin * * 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 TI73/TI83+/TI84+ support. */ #include #include #include //#include #include "gettext.h" #include "headers.h" #include "externs.h" #include "update.h" #include "packets.h" #include "calc_err.h" #include "cmd73.h" #include "rom83p.h" #include "pause.h" #include "printl.h" #ifdef __WIN32__ #pragma warning( disable : 4761 4244) #endif // Screen coordinates of the TI83+ #define TI73_ROWS 64 #define TI73_COLS 96 int ti73_supported_operations(void) { return (OPS_ISREADY | OPS_SCREENDUMP | OPS_SEND_KEY | OPS_DIRLIST | OPS_SEND_BACKUP | OPS_RECV_BACKUP | OPS_SEND_VARS | OPS_RECV_VARS | OPS_SEND_FLASH | OPS_RECV_FLASH | OPS_IDLIST | OPS_ROMDUMP); } int ti73_isready(void) { uint16_t status; printl2(0, _("Is calculator ready ?\n")); LOCK_TRANSFER(); TRYF(cable->open()); update_start(); TRYF(ti73_send_RDY()); TRYF(ti73_recv_ACK(&status)); TRYF(cable->close()); UNLOCK_TRANSFER(); return (status & 0x01) ? ERR_NOT_READY : 0; } int ti73_send_key(uint16_t key) { LOCK_TRANSFER(); TRYF(cable->open()); TRYF(ti73_send_KEY(key)); TRYF(ti73_recv_ACK(NULL)); TRYF(cable->close()); UNLOCK_TRANSFER(); return 0; } int ti73_directorylist(TNode ** tree, uint32_t * memory) { uint16_t unused; TNode *vars, *apps, *folder; printl2(0, _("Directory listing...\n")); LOCK_TRANSFER(); TRYF(cable->open()); update_start(); TRYF(ti73_send_REQ(0x0000, TI73_DIR, "", 0x00)); TRYF(ti73_recv_ACK(NULL)); TRYF(ti73_recv_XDP(&unused, (uint8_t *) memory)); fixup(*memory); TRYF(ti73_send_ACK()); *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); folder = t_node_new(NULL); t_node_append(vars, folder); for (;;) { TiVarEntry *ve = calloc(1, sizeof(TiVarEntry)); TNode *node; int err; err = ti73_recv_VAR((uint16_t *) & ve->size, &ve->type, ve->name, &ve->attr); fixup(ve->size); TRYF(ti73_send_ACK()); if (err == ERR_EOT) break; else if (err != 0) return err; tifiles_translate_varname(ve->name, ve->trans, ve->type); node = t_node_new(ve); if (ve->type != TI73_APPL) t_node_append(folder, node); else t_node_append(apps, node); sprintf(update->label_text, _("Reading of '%s'"), ve->trans); update_label(); if (update->cancel) return ERR_ABORT; } TRYF(cable->close()); UNLOCK_TRANSFER(); return 0; } int ti73_screendump(uint8_t ** bitmap, int mask_mode, TicalcScreenCoord * sc) { uint16_t max_cnt; int err; printl2(0, _("Receiving screendump...\n")); LOCK_TRANSFER(); TRYF(cable->open()); update_start(); sc->width = TI73_COLS; sc->height = TI73_ROWS; sc->clipped_width = TI73_COLS; sc->clipped_height = TI73_ROWS; if (*bitmap != NULL) free(*bitmap); (*bitmap) = (uint8_t *) malloc(TI73_COLS * TI73_ROWS * sizeof(uint8_t) / 8); if ((*bitmap) == NULL) { printl2(2, "Unable to allocate memory.\n"); exit(0); } TRYF(ti73_send_SCR()); TRYF(ti73_recv_ACK(NULL)); err = ti73_recv_XDP(&max_cnt, *bitmap); // pb with checksum if (err != ERR_CHECKSUM) { TRYF(err)}; TRYF(ti73_send_ACK()); printl2(0, _("Done.\n")); TRYF(cable->close()); UNLOCK_TRANSFER(); return 0; } int ti73_recv_backup(const char *filename, int mask_mode) { Ti8xBackup *content; uint8_t varname[9] = { 0 }; uint8_t attr; printl2(0, _("Receiving backup...\n")); LOCK_TRANSFER(); TRYF(cable->open()); update_start(); content = ti8x_create_backup_content(); content->calc_type = ticalcs_calc_type; sprintf(update->label_text, _("Receiving backup...")); update_label(); // silent request TRYF(ti73_send_REQ(0x0000, TI73_BKUP, "", 0x00)); TRYF(ti73_recv_ACK(NULL)); TRYF(ti73_recv_VAR (&content->data_length1, &content->type, (char*)varname, &attr)); content->data_length2 = varname[0] | (varname[1] << 8); content->data_length3 = varname[2] | (varname[3] << 8); content->mem_address = varname[4] | (varname[5] << 8); TRYF(ti73_send_ACK()); TRYF(ti73_send_CTS()); TRYF(ti73_recv_ACK(NULL)); content->data_part1 = tifiles_calloc(65536, 1); TRYF(ti73_recv_XDP(&content->data_length1, content->data_part1)); TRYF(ti73_send_ACK()); update->main_percentage = (float) 1 / 3; content->data_part2 = tifiles_calloc(65536, 1); TRYF(ti73_recv_XDP(&content->data_length2, content->data_part2)); TRYF(ti73_send_ACK()); update->main_percentage = (float) 2 / 3; content->data_part3 = tifiles_calloc(65536, 1); TRYF(ti73_recv_XDP(&content->data_length3, content->data_part3)); TRYF(ti73_send_ACK()); update->main_percentage = (float) 3 / 3; content->data_part4 = NULL; strcpy(content->comment, "Backup file received by TiLP"); ti8x_write_backup_file(filename, content); ti8x_free_backup_content(content); TRYF(cable->close()); UNLOCK_TRANSFER(); return 0; } int ti73_send_backup(const char *filename, int mask_mode) { Ti8xBackup content = { 0 }; uint16_t length; uint8_t varname[9]; uint8_t rej_code; printl2(0, _("Sending backup...\n")); LOCK_TRANSFER(); TRYF(cable->open()); update_start(); sprintf(update->label_text, _("Sending...")); update_label(); TRYF(ti8x_read_backup_file(filename, &content)); length = content.data_length1; varname[0] = LSB(content.data_length2); varname[1] = MSB(content.data_length2); varname[2] = LSB(content.data_length3); varname[3] = MSB(content.data_length3); varname[4] = LSB(content.mem_address); varname[5] = MSB(content.mem_address); TRYF(ti73_send_RTS(content.data_length1, TI73_BKUP, (char*)varname, 0x00)); TRYF(ti73_recv_ACK(NULL)); TRYF(ti73_recv_SKIP(&rej_code)) TRYF(ti73_send_ACK()); switch (rej_code) { case REJ_EXIT: case REJ_SKIP: return ERR_ABORT; break; case REJ_MEMORY: return ERR_OUT_OF_MEMORY; break; default: // RTS break; } TRYF(ti73_send_XDP(content.data_length1, content.data_part1)); TRYF(ti73_recv_ACK(NULL)); update->main_percentage = (float) 1 / 3; TRYF(ti73_send_XDP(content.data_length2, content.data_part2)); TRYF(ti73_recv_ACK(NULL)); update->main_percentage = (float) 2 / 3; TRYF(ti73_send_XDP(content.data_length3, content.data_part3)); TRYF(ti73_recv_ACK(NULL)); update->main_percentage = (float) 3 / 3; TRYF(ti73_send_ACK()); ti8x_free_backup_content(&content); TRYF(cable->close()); UNLOCK_TRANSFER(); return 0; } int ti73_recv_var(char *filename, int mask_mode, TiVarEntry * entry) { static Ti8xRegular *content; TiVarEntry *ve; char *fn; static int nvar = 0; 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 = ti8x_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)); sprintf(update->label_text, _("Receiving '%s'"), tifiles_translate_varname2(entry->name, entry->type)); update_label(); // silent request TRYF(ti73_send_REQ(entry->size, entry->type, entry->name, entry->attr)); TRYF(ti73_recv_ACK(NULL)); TRYF(ti73_recv_VAR((uint16_t *) & ve->size, &ve->type, ve->name, &entry->attr)); fixup(ve->size); TRYF(ti73_send_ACK()); TRYF(ti73_send_CTS()); TRYF(ti73_recv_ACK(NULL)); ve->data = tifiles_calloc(ve->size, 1); TRYF(ti73_recv_XDP((uint16_t *) & ve->size, ve->data)); TRYF(ti73_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 ti8x_write_regular_file(NULL, content, &fn); strcpy(filename, fn); tifiles_free(fn); ti8x_free_regular_content(content); } else if (mask_mode & MODE_RECEIVE_LAST_VAR) { // group ti8x_write_regular_file(filename, content, NULL); ti8x_free_regular_content(content); } TRYF(cable->close()); UNLOCK_TRANSFER(); PAUSE(PAUSE_BETWEEN_VARS); return 0; } int ti73_send_var(const char *filename, int mask_mode, char **actions) { Ti8xRegular content = { 0 }; int i; uint8_t rej_code; uint8_t attrb; printl2(0, _("Sending variable(s)...\n")); LOCK_TRANSFER(); TRYF(cable->open()); update_start(); sprintf(update->label_text, _("Sending...")); update_label(); TRYF(ti8x_read_regular_file(filename, &content)); for (i = 0; i < content.num_entries; i++) { TiVarEntry *entry = &(content.entries[i]); uint8_t varname[18]; 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); attrb = (mask_mode & MODE_SEND_TO_FLASH) ? ATTRB_ARCHIVED : entry->attr; TRYF(ti73_send_RTS(entry->size, entry->type, (char*)varname, attrb)); TRYF(ti73_recv_ACK(NULL)); TRYF(ti73_recv_SKIP(&rej_code)); TRYF(ti73_send_ACK()); switch (rej_code) { case REJ_EXIT: return ERR_ABORT; break; case REJ_SKIP: continue; break; case REJ_MEMORY: return ERR_OUT_OF_MEMORY; break; default: // RTS break; } sprintf(update->label_text, _("Sending '%s'"), tifiles_translate_varname2(entry->name, entry->type)); update_label(); TRYF(ti73_send_XDP(entry->size, entry->data)); TRYF(ti73_recv_ACK(NULL)); printl2(0, "\n"); } TRYF(ti73_send_EOT()); TRYF(cable->close()); UNLOCK_TRANSFER(); return 0; } int ti73_recv_var_2(char *filename, int mask_mode, TiVarEntry * entry) { return ERR_VOID_FUNCTION; } int ti73_send_flash(const char *filename, int mask_mode) { Ti8xFlash content = { 0 }; int i; 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(ti8x_read_flash_file(filename, &content)); for (i = 0; i < content.num_pages; i++) { Ti8xFlashPage *fp = &(content.pages[i]); TRYF(ti73_send_VAR2 (fp->length, content.data_type, fp->flag, fp->offset, fp->page)); TRYF(ti73_recv_ACK(NULL)); TRYF(ti73_recv_CTS(10)); TRYF(ti73_send_ACK()); TRYF(ti73_send_XDP(fp->length, fp->data)); TRYF(ti73_recv_ACK(NULL)); if(ticalcs_calc_type != CALC_TI84P) { if (i == 1) PAUSE(1000); // This pause is NEEDED ! if (i == content.num_pages - 2) PAUSE(2500); // This pause is NEEDED ! } update->main_percentage = (float) i / content.num_pages; if (update->cancel) return ERR_ABORT; } TRYF(ti73_send_EOT()); TRYF(ti73_recv_ACK(NULL)); TRYF(cable->close()); UNLOCK_TRANSFER(); return 0; } int ti73_recv_flash(const char *filename, int mask_mode, TiVarEntry * ve) { Ti8xFlash *content; int npages; uint32_t size = 0; if(ticalcs_calc_type == CALC_TI84P) return ERR_VOID_FUNCTION; printl2(0, _("Receiving FLASH application...\n")); LOCK_TRANSFER(); TRYF(cable->open()); update_start(); content = ti8x_create_flash_content(); content->calc_type = ticalcs_calc_type; content->num_pages = 2048; // TI83+ has 512 KB of FLASH max content->pages = (Ti8xFlashPage *) tifiles_calloc(content->num_pages, sizeof(Ti8xFlashPage)); sprintf(update->label_text, _("Receiving '%s'"), ve->name); update_label(); // silent request TRYF(ti73_send_REQ2(0x00, TI73_APPL, ve->name, 0x00)); TRYF(ti73_recv_ACK(NULL)); for (size = 0, npages = 0;; npages++) { int err; uint16_t data_length; uint8_t data_type; char name[9]; Ti8xFlashPage *fp = &(content->pages[npages]); err = ti73_recv_VAR2(&data_length, &data_type, name, &fp->offset, &fp->page); TRYF(ti73_send_ACK()); if (err == ERR_EOT) goto exit; TRYF(err); TRYF(ti73_send_CTS()); TRYF(ti73_recv_ACK(NULL)); fp->data = tifiles_calloc(fp->length, 1); TRYF(ti73_recv_XDP((uint16_t *) & fp->length, fp->data)); fixup(fp->length); TRYF(ti73_send_ACK()); size += fp->length; (update->main_percentage) = (float) size / ve->size; if (update->cancel) return ERR_ABORT; } exit: content->num_pages = npages; ti8x_write_flash_file(filename, content); ti8x_free_flash_content(content); TRYF(cable->close()); UNLOCK_TRANSFER(); return 0; } #define DUMP_ROM73_FILE "dumprom.8Xp" //#define ROMSIZE 512 // 512KB (TI83+) or 1MB (TI84+) or 2MB (SilverEdition) int ti73_dump_rom(const char *filename, int mask_mode) { int i, j; uint8_t data; time_t start, elapsed, estimated, remaining; char buffer[256]; char tmp[256]; int pad; FILE *f, *file; uint16_t checksum, sum; int err; int b = 0; int ROMSIZE = (mask_mode == ROM_SE) ? 2048 : (ticalcs_calc_type == CALC_TI84P) ? 1024 : 512; printl2(0, _("ROM dumping...\n")); // Copies ROM dump program into a file f = fopen(DUMP_ROM73_FILE, "wb"); if (f == NULL) return ERR_FILE_OPEN; fwrite(romDump83p, sizeof(unsigned char), romDumpSize83p, f); fclose(f); // Transfer program to calc TRYF(ti73_send_var(DUMP_ROM73_FILE, MODE_SEND_ONE_VAR, NULL)); unlink(DUMP_ROM73_FILE); // Open file file = fopen(filename, "wb"); if (file == NULL) return ERR_OPEN_FILE; LOCK_TRANSFER(); TRYF(cable->open()); update_start(); // Wait for user's action (execing program) sprintf(update->label_text, _("Waiting user's action...")); update_label(); do { update_refresh(); if (update->cancel) return ERR_ABORT; err = cable->get(&data); sum = data; } while (err == ERR_READ_TIMEOUT); fprintf(file, "%c", data); // 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++) { if (b) sum = 0; update->total = 1024; for (j = 0; j < 1023 + b; j++) { TRYF(cable->get(&data)); fprintf(file, "%c", data); sum += data; update->count = j; update_pbar(); if (update->cancel) return -1; } b = 1; TRYF(cable->get(&data)); checksum = data << 8; TRYF(cable->get(&data)); checksum |= data; if (sum != checksum) return ERR_CHECKSUM; TRYF(cable->put(0xda)); update->count = ROMSIZE; 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(); } fclose(file); TRYF(cable->close()); UNLOCK_TRANSFER(); return 0; } int ti73_get_idlist(char *id) { uint16_t unused; uint16_t varsize; uint8_t vartype; uint8_t varname[9]; uint8_t varattr; printl2(0, _("Getting ID list...\n")); LOCK_TRANSFER(); TRYF(cable->open()); update_start(); sprintf(update->label_text, _("Getting variable...")); update_label(); TRYF(ti73_send_REQ(0x0000, TI73_IDLIST, "", 0x00)); TRYF(ti73_recv_ACK(&unused)); TRYF(ti73_recv_VAR((uint16_t *) & varsize, &vartype, (char*)varname, &varattr)); fixup(varsize); TRYF(ti73_send_ACK()); TRYF(ti73_send_CTS()); TRYF(ti73_recv_ACK(NULL)); TRYF(ti73_recv_XDP(&varsize, (uint8_t *)id)); id[varsize] = '\0'; TRYF(ti73_send_ACK()); TRYF(cable->close()); UNLOCK_TRANSFER(); return 0; }