1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id: link_nul.c 1059 2005-05-14 09:45:42Z roms $ */
3 
4 /*  libticalcs2 - hand-helds support library, a part of the TiLP project
5  *  Copyright (c) 1999-2005  Romain Liévin
6  *  Copyright (c) 2005  Benjamin Moody (ROM dumper)
7  *  Copyright (c) 2006  Tyler Cassidy
8  *  Copyright (C) 2006  Kevin Kofler
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software Foundation,
22  *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  */
24 
25 /*
26 	TI73/TI83+/TI84+ support.
27 */
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 
38 #include "ticalcs.h"
39 #include "gettext.h"
40 #include "internal.h"
41 #include "logging.h"
42 #include "error.h"
43 
44 #include "dbus_pkt.h"
45 #include "cmdz80.h"
46 #include "rom73.h"
47 #include "rom83p.h"
48 #include "rom84pc.h"
49 #include "romdump.h"
50 #include "keys83p.h"
51 
52 #define SEND_RDY ti73_send_RDY
53 #define SEND_KEY ti73_send_KEY
54 #define SEND_SCR ti73_send_SCR
55 #define SEND_ACK ti73_send_ACK
56 #define SEND_VAR ti73_send_VAR
57 #define SEND_VAR2 ti73_send_VAR2
58 #define SEND_XDP ti73_send_XDP
59 #define SEND_REQ ti73_send_REQ
60 #define SEND_REQ2 ti73_send_REQ2
61 #define SEND_RTS ti73_send_RTS
62 #define SEND_CTS ti73_send_CTS
63 #define SEND_DEL ti73_send_DEL
64 #define SEND_VER ti73_send_VER
65 #define SEND_EOT ti73_send_EOT
66 
67 #define RECV_ACK ti73_recv_ACK
68 #define RECV_VAR ti73_recv_VAR
69 #define RECV_VAR2 ti73_recv_VAR2
70 #define RECV_XDP ti73_recv_XDP
71 #define RECV_SKP ti73_recv_SKP
72 #define RECV_CTS ti73_recv_CTS
73 
74 // Screen coordinates of the TI83+
75 #define TI73_ROWS  64
76 #define TI73_COLS  96
77 #define TI84PC_ROWS 240
78 #define TI84PC_COLS 320
79 
is_ready(CalcHandle * handle)80 static int		is_ready	(CalcHandle* handle)
81 {
82 	int ret;
83 	uint16_t status;
84 
85 	ret = SEND_RDY(handle);
86 	if (!ret)
87 	{
88 		ret = RECV_ACK(handle, &status);
89 		if (!ret)
90 		{
91 			ret = (MSB(status) & 0x01) ? ERR_NOT_READY : 0;
92 		}
93 	}
94 
95 	return ret;
96 }
97 
send_key(CalcHandle * handle,uint32_t key)98 static int		send_key	(CalcHandle* handle, uint32_t key)
99 {
100 	int ret;
101 	uint16_t status;
102 
103 	ret = SEND_KEY(handle, (uint16_t)key);
104 	if (!ret)
105 	{
106 		ret = RECV_ACK(handle, &status);	// when the key is received
107 		if (!ret)
108 		{
109 			ret = RECV_ACK(handle, NULL);	// after it completes the resulting action
110 		}
111 	}
112 
113 	return ret;
114 }
115 
execute(CalcHandle * handle,VarEntry * ve,const char * args)116 static int		execute		(CalcHandle* handle, VarEntry *ve, const char* args)
117 {
118 	int ret;
119 
120 	if (handle->model == CALC_TI73 && ve->type == TI73_ASM)
121 	{
122 		return ERR_VOID_FUNCTION;
123 	}
124 
125 	// Go back to homescreen
126 	PAUSE(200);
127 	ret = send_key(handle, KEY83P_Quit);
128 	if (!ret)
129 	{
130 		ret = send_key(handle, KEY83P_Clear);
131 		if (!ret)
132 		{
133 			ret = send_key(handle, KEY83P_Clear);
134 		}
135 	}
136 
137 	if (!ret)
138 	{
139 		// Launch program by remote control
140 		if (ve->type == TI83p_ASM)
141 		{
142 			ret = send_key(handle, KEY83P_Asm);
143 		}
144 		if (!ret)
145 		{
146 			ret = send_key(handle, KEY83P_Exec);
147 			if (!ret)
148 			{
149 				unsigned int i;
150 				for (i = 0; !ret && i < strlen(ve->name); i++)
151 				{
152 					const CalcKey *ck = ticalcs_keys_83p((ve->name)[i]);
153 					ret = send_key(handle, (uint32_t)(ck->normal.value));
154 				}
155 
156 				if (!ret)
157 				{
158 					ret = send_key(handle, KEY83P_Enter);
159 
160 					PAUSE(200);
161 				}
162 			}
163 		}
164 	}
165 
166 	return ret;
167 }
168 
recv_screen(CalcHandle * handle,CalcScreenCoord * sc,uint8_t ** bitmap)169 static int		recv_screen	(CalcHandle* handle, CalcScreenCoord* sc, uint8_t** bitmap)
170 {
171 	int ret;
172 	uint8_t *buffer = handle->buffer2;
173 	uint8_t *data = NULL;
174 
175 	data = (uint8_t *)ticalcs_alloc_screen(65537U);
176 	if (data == NULL)
177 	{
178 		return ERR_MALLOC;
179 	}
180 
181 	ret = SEND_SCR(handle);
182 	if (!ret)
183 	{
184 		ret = RECV_ACK(handle, NULL);
185 		if (!ret)
186 		{
187 			uint16_t pktsize;
188 			ret = RECV_XDP(handle, &pktsize, data);
189 			if (!ret || ret == ERR_CHECKSUM) // problem with checksum
190 			{
191 				ret = SEND_ACK(handle);
192 				if (!ret)
193 				{
194 					if (pktsize == TI73_COLS * TI73_ROWS / 8)
195 					{
196 						/* TI-73 / 83+ / 84+ */
197 						sc->width = TI73_COLS;
198 						sc->height = TI73_ROWS;
199 						sc->clipped_width = TI73_COLS;
200 						sc->clipped_height = TI73_ROWS;
201 						sc->pixel_format = CALC_PIXFMT_MONO;
202 						*bitmap = ticalcs_realloc_screen(data, TI73_COLS * TI73_ROWS / 8);
203 					}
204 					else
205 					{
206 						/* TI-84+CSE */
207 						uint32_t size = pktsize;
208 
209 						sc->width = TI84PC_COLS;
210 						sc->height = TI84PC_ROWS;
211 						sc->clipped_width = TI84PC_COLS;
212 						sc->clipped_height = TI84PC_ROWS;
213 						sc->pixel_format = CALC_PIXFMT_RGB_565_LE;
214 
215 						while (1)
216 						{
217 							ret = RECV_XDP(handle, &pktsize, buffer);
218 							if (ret == ERR_EOT)
219 							{
220 								ret = SEND_ACK(handle);
221 								break;
222 							}
223 
224 							*bitmap = ticalcs_realloc_screen(data, size + pktsize);
225 							if (*bitmap != NULL)
226 							{
227 								data = *bitmap;
228 								memcpy(data + size, buffer, pktsize);
229 								size += pktsize;
230 
231 								ret = SEND_ACK(handle);
232 								if (ret)
233 								{
234 									break;
235 								}
236 
237 								update_->max1 = TI84PC_COLS * TI84PC_ROWS * 2;
238 								update_->cnt1 = size;
239 								update_->pbar();
240 							}
241 							else
242 							{
243 								ticalcs_free_screen(data);
244 								ret = ERR_MALLOC;
245 								break;
246 							}
247 						}
248 
249 						if (!ret)
250 						{
251 							*bitmap = ticalcs_alloc_screen(TI84PC_ROWS * TI84PC_COLS * 2);
252 							ret = ticalcs_screen_84pcse_rle_uncompress(data, size, *bitmap, TI84PC_ROWS * TI84PC_COLS * 2);
253 						}
254 					}
255 				}
256 			}
257 		}
258 	}
259 
260 	if (ret)
261 	{
262 		ticalcs_free_screen(*bitmap);
263 		*bitmap = NULL;
264 	}
265 
266 	return ret;
267 }
268 
get_dirlist(CalcHandle * handle,GNode ** vars,GNode ** apps)269 static int		get_dirlist	(CalcHandle* handle, GNode** vars, GNode** apps)
270 {
271 	int ret;
272 	TreeInfo *ti;
273 	GNode *folder, *root, *node;
274 	uint16_t unused;
275 	uint32_t memory;
276 	char *utf8;
277 
278 	ret = dirlist_init_trees(handle, vars, apps);
279 	if (ret)
280 	{
281 		return ret;
282 	}
283 	ti = (*vars)->data;
284 
285 	ret = SEND_REQ(handle, 0x0000, TI73_DIR, "\0\0\0\0\0\0\0", 0x00, 0x00);
286 	if (!ret)
287 	{
288 		ret = RECV_ACK(handle, &unused);
289 		if (!ret)
290 		{
291 			ret = RECV_XDP(handle, &unused, handle->buffer2);
292 			if (!ret)
293 			{
294 				ret = SEND_ACK(handle);
295 				if (!ret)
296 				{
297 					uint8_t * mem = (uint8_t *)handle->buffer2;
298 					memory = (((uint32_t)(mem[1])) << 8) | mem[0]; // Clamp mem_free to a 16-bit value.
299 				}
300 			}
301 		}
302 	}
303 	if (ret)
304 	{
305 		return ret;
306 	}
307 
308 	ti->mem_free = memory;
309 
310 	folder = dirlist_create_append_node(NULL, vars);
311 	if (!folder)
312 	{
313 		return ERR_MALLOC;
314 	}
315 	root = dirlist_create_append_node(NULL, apps);
316 	if (!root)
317 	{
318 		return ERR_MALLOC;
319 	}
320 
321 	// Add permanent variables (Window, RclWindow, TblSet aka WINDW, ZSTO, TABLE)
322 	{
323 		VarEntry *ve;
324 
325 		ve = tifiles_ve_create();
326 		ve->type = TI84p_WINDW;
327 		node = dirlist_create_append_node(ve, &folder);
328 
329 		if (node != NULL)
330 		{
331 			if (handle->model != CALC_TI73)
332 			{
333 				ve = tifiles_ve_create();
334 				ve->type = TI84p_ZSTO;
335 				node = dirlist_create_append_node(ve, &folder);
336 			}
337 
338 			if (node != NULL)
339 			{
340 				ve = tifiles_ve_create();
341 				ve->type = TI84p_TABLE;
342 				node = dirlist_create_append_node(ve, &folder);
343 			}
344 		}
345 	}
346 
347 	if (!node)
348 	{
349 		return ERR_MALLOC;
350 	}
351 
352 	for (;;)
353 	{
354 		VarEntry *ve = tifiles_ve_create();
355 		uint16_t ve_size;
356 		int ret2;
357 
358 		ret = RECV_VAR(handle, &ve_size, &ve->type, ve->name, &ve->attr, &ve->version);
359 		ve->size = ve_size;
360 		ret2 = SEND_ACK(handle);
361 		if (ret)
362 		{
363 			if (ret == ERR_EOT)
364 			{
365 				ret = 0;
366 			}
367 error:
368 			tifiles_ve_delete(ve);
369 			break;
370 		}
371 		if (ret2)
372 		{
373 			ret = ret2;
374 			goto error;
375 		}
376 
377 		if (ve->type == TI73_APPL)
378 		{
379 			/* Size is reported as a number of pages -- compute amount
380 			   of space consumed (the actual application may be
381 			   somewhat smaller.)  Note: the MSB of the "size" word is
382 			   the application's starting page number. */
383 			ve->size = (ve->size & 0xff) * 0x4000;
384 		}
385 
386 		node = dirlist_create_append_node(ve, (ve->type != TI73_APPL) ? &folder : &root);
387 		if (!node)
388 		{
389 			return ERR_MALLOC;
390 		}
391 
392 		utf8 = ticonv_varname_to_utf8(handle->model, ve->name, ve->type);
393 		ticalcs_slprintf(update_->text, sizeof(update_->text), _("Parsing %s"), utf8);
394 		ticonv_utf8_free(utf8);
395 		update_label();
396 	}
397 
398 	return ret;
399 }
400 
get_memfree(CalcHandle * handle,uint32_t * ram,uint32_t * flash)401 static int		get_memfree	(CalcHandle* handle, uint32_t* ram, uint32_t* flash)
402 {
403 	int ret;
404 	uint16_t unused;
405 
406 	*ram = -1;
407 	*flash = -1;
408 
409 	ret = SEND_REQ(handle, 0x0000, TI73_DIR, "\0\0\0\0\0\0\0", 0x00, 0x00);
410 	if (!ret)
411 	{
412 		ret = RECV_ACK(handle, &unused);
413 		if (!ret)
414 		{
415 			ret = RECV_XDP(handle, &unused, handle->buffer2);
416 			if (!ret)
417 			{
418 				ret = SEND_EOT(handle);
419 				if (!ret)
420 				{
421 					uint8_t * mem = (uint8_t *)handle->buffer2;
422 					*ram = (((uint32_t)(mem[1])) << 8) | mem[0]; // Clamp mem_free to a 16-bit value.
423 				}
424 			}
425 		}
426 	}
427 
428 	return ret;
429 }
430 
send_backup(CalcHandle * handle,BackupContent * content)431 static int		send_backup	(CalcHandle* handle, BackupContent* content)
432 {
433 	int ret;
434 	uint16_t length;
435 	char varname[9];
436 	uint8_t rej_code;
437 	uint16_t status;
438 
439 	length = content->data_length1;
440 	varname[0] = LSB(content->data_length2);
441 	varname[1] = MSB(content->data_length2);
442 	varname[2] = LSB(content->data_length3);
443 	varname[3] = MSB(content->data_length3);
444 	varname[4] = LSB(content->mem_address);
445 	varname[5] = MSB(content->mem_address);
446 	varname[6] = 0;
447 	varname[7] = 0;
448 	varname[8] = 0;
449 
450 	do
451 	{
452 		ret = SEND_RTS(handle, content->data_length1, TI73_BKUP, varname, 0x00, content->version);
453 		if (!ret)
454 		{
455 			ret = RECV_ACK(handle, &status);
456 			if (!ret)
457 			{
458 				ret = RECV_SKP(handle, &rej_code);
459 				if (!ret)
460 				{
461 					ret = SEND_ACK(handle);
462 				}
463 			}
464 		}
465 		if (!ret)
466 		{
467 			switch (rej_code)
468 			{
469 			case DBUS_REJ_EXIT:
470 			case DBUS_REJ_SKIP:
471 				return ERR_ABORT;
472 			case DBUS_REJ_MEMORY:
473 				return ERR_OUT_OF_MEMORY;
474 			case DBUS_REJ_VERSION:
475 				return ERR_VAR_VERSION;
476 			case 0:						// CTS
477 				break;
478 			default:
479 				return ERR_VAR_REJECTED;
480 			}
481 
482 			update_->cnt2 = 0;
483 			update_->max2 = 3;
484 			update_->pbar();
485 
486 			ret = SEND_XDP(handle, content->data_length1, content->data_part1);
487 			if (!ret)
488 			{
489 				ret = RECV_ACK(handle, &status);
490 			}
491 			if (ret)
492 			{
493 				break;
494 			}
495 			update_->cnt2++;
496 			update_->pbar();
497 
498 			ret = SEND_XDP(handle, content->data_length2, content->data_part2);
499 			if (!ret)
500 			{
501 				ret = RECV_ACK(handle, &status);
502 			}
503 			if (ret)
504 			{
505 				break;
506 			}
507 			update_->cnt2++;
508 			update_->pbar();
509 
510 			ret = SEND_XDP(handle, content->data_length3, content->data_part3);
511 			if (!ret)
512 			{
513 				ret = RECV_ACK(handle, &status);
514 			}
515 			if (ret)
516 			{
517 				break;
518 			}
519 			update_->cnt2++;
520 			update_->pbar();
521 
522 			ret = SEND_ACK(handle);
523 		}
524 	} while(0);
525 
526 	return ret;
527 }
528 
recv_backup(CalcHandle * handle,BackupContent * content)529 static int		recv_backup	(CalcHandle* handle, BackupContent* content)
530 {
531 	int ret;
532 	char varname[9];
533 	uint8_t attr, ver;
534 
535 	content->model = handle->model;
536 	ticalcs_strlcpy(content->comment, tifiles_comment_set_backup(), sizeof(content->comment));
537 
538 	varname[0] = 0;
539 	ret = SEND_REQ(handle, 0x0000, TI73_BKUP, "\0\0\0\0\0\0\0", 0x00, 0x00);
540 	if (!ret)
541 	{
542 		ret = RECV_ACK(handle, NULL);
543 	}
544 	if (ret)
545 	{
546 		return ret;
547 	}
548 
549 	do
550 	{
551 		ret = RECV_VAR(handle, &content->data_length1, &content->type, varname, &attr, &ver);
552 		if (ret)
553 		{
554 			break;
555 		}
556 
557 		content->data_length2 = (uint8_t)varname[0] | (((uint16_t)(uint8_t)varname[1]) << 8);
558 		content->data_length3 = (uint8_t)varname[2] | (((uint16_t)(uint8_t)varname[3]) << 8);
559 		content->mem_address  = (uint8_t)varname[4] | (((uint16_t)(uint8_t)varname[5]) << 8);
560 		content->version = ver;
561 		ret = SEND_ACK(handle);
562 		if (!ret)
563 		{
564 			ret = SEND_CTS(handle);
565 			if (!ret)
566 			{
567 				ret = RECV_ACK(handle, NULL);
568 			}
569 		}
570 		if (ret)
571 		{
572 			break;
573 		}
574 
575 		update_->cnt2 = 0;
576 		update_->max2 = 3;
577 		update_->pbar();
578 
579 		content->data_part1 = tifiles_ve_alloc_data(65536);
580 		ret = RECV_XDP(handle, &content->data_length1, content->data_part1);
581 		if (!ret)
582 		{
583 			ret = SEND_ACK(handle);
584 		}
585 		if (ret)
586 		{
587 			break;
588 		}
589 		update_->cnt2++;
590 		update_->pbar();
591 
592 		content->data_part2 = tifiles_ve_alloc_data(65536);
593 		ret = RECV_XDP(handle, &content->data_length2, content->data_part2);
594 		if (!ret)
595 		{
596 			ret = SEND_ACK(handle);
597 		}
598 		if (ret)
599 		{
600 			break;
601 		}
602 		update_->cnt2++;
603 		update_->pbar();
604 
605 		content->data_part3 = tifiles_ve_alloc_data(65536);
606 		ret = RECV_XDP(handle, &content->data_length3, content->data_part3);
607 		if (!ret)
608 		{
609 			ret = SEND_ACK(handle);
610 		}
611 		if (ret)
612 		{
613 			break;
614 		}
615 		update_->cnt2++;
616 		update_->pbar();
617 
618 		content->data_part4 = NULL;
619 	} while(0);
620 
621 	return ret;
622 }
623 
send_var(CalcHandle * handle,CalcMode mode,FileContent * content)624 static int		send_var	(CalcHandle* handle, CalcMode mode, FileContent* content)
625 {
626 	int ret = 0;
627 	unsigned int i;
628 	uint8_t rej_code;
629 	uint16_t status;
630 
631 	update_->cnt2 = 0;
632 	update_->max2 = content->num_entries;
633 
634 	for (i = 0; !ret && i < content->num_entries; i++)
635 	{
636 		VarEntry *entry = content->entries[i];
637 		uint16_t size;
638 
639 		if (!ticalcs_validate_varentry(entry))
640 		{
641 			ticalcs_critical("%s: skipping invalid content entry #%u", __FUNCTION__, i);
642 			continue;
643 		}
644 
645 		if (entry->action == ACT_SKIP)
646 		{
647 			ticalcs_info("%s: skipping variable #%u because requested", __FUNCTION__, i);
648 			continue;
649 		}
650 
651 		if (entry->size >= 65536U)
652 		{
653 			ticalcs_critical("%s: oversized variable has size %u, clamping to 65535", __FUNCTION__, entry->size);
654 			size = 65535;
655 		}
656 		else
657 		{
658 			size = (uint16_t)entry->size;
659 		}
660 
661 		ret = SEND_RTS(handle, size, entry->type, entry->name, entry->attr, entry->version);
662 		if (!ret)
663 		{
664 			ret = RECV_ACK(handle, &status);
665 			if (!ret)
666 			{
667 				ret = RECV_SKP(handle, &rej_code);
668 				if (!ret)
669 				{
670 					ret = SEND_ACK(handle);
671 				}
672 			}
673 		}
674 		if (ret)
675 		{
676 			break;
677 		}
678 
679 		switch (rej_code)
680 		{
681 		case DBUS_REJ_EXIT:
682 			ret = ERR_ABORT;
683 			break;
684 		case DBUS_REJ_SKIP:
685 			continue;
686 		case DBUS_REJ_MEMORY:
687 			ret = ERR_OUT_OF_MEMORY;
688 			break;
689 		case DBUS_REJ_VERSION:
690 			ret = ERR_VAR_VERSION;
691 			// Fall through.
692 		case 0:					// CTS
693 			break;
694 		default:
695 			ret = ERR_VAR_REJECTED;
696 			break;
697 		}
698 
699 		if (ret)
700 		{
701 			break;
702 		}
703 
704 		ticonv_varname_to_utf8_sn(handle->model, entry->name, update_->text, sizeof(update_->text), entry->type);
705 		update_label();
706 
707 		ret = SEND_XDP(handle, size, entry->data);
708 		if (!ret)
709 		{
710 			ret = RECV_ACK(handle, &status);
711 			if (!ret)
712 			{
713 				ret = SEND_EOT(handle);
714 				if (!ret)
715 				{
716 					ticalcs_info("Sent variable #%u", i);
717 
718 					update_->cnt2 = i+1;
719 					update_->max2 = content->num_entries;
720 					update_->pbar();
721 				}
722 			}
723 		}
724 	}
725 
726 	return ret;
727 }
728 
recv_var(CalcHandle * handle,CalcMode mode,FileContent * content,VarRequest * vr)729 static int		recv_var	(CalcHandle* handle, CalcMode mode, FileContent* content, VarRequest* vr)
730 {
731 	int ret;
732 	uint16_t unused;
733 	VarEntry *ve;
734 	uint16_t ve_size;
735 
736 	content->model = handle->model;
737 	ticalcs_strlcpy(content->comment, tifiles_comment_set_single(), sizeof(content->comment));
738 	content->num_entries = 1;
739 	content->entries = tifiles_ve_create_array(1);
740 	ve = content->entries[0] = tifiles_ve_create();
741 	memcpy(ve, vr, sizeof(VarEntry));
742 
743 	ticonv_varname_to_utf8_sn(handle->model, vr->name, update_->text, sizeof(update_->text), vr->type);
744 	update_label();
745 
746 	do
747 	{
748 		// silent request
749 		ret = SEND_REQ(handle, (uint16_t)vr->size, vr->type, vr->name, vr->attr, vr->version);
750 		if (!ret)
751 		{
752 			ret = RECV_ACK(handle, &unused);
753 			if (!ret)
754 			{
755 				ret = RECV_VAR(handle, &ve_size, &ve->type, ve->name, &ve->attr, &ve->version);
756 			}
757 		}
758 		if (ret)
759 		{
760 			break;
761 		}
762 
763 		ve->size = ve_size;
764 
765 		ret = SEND_ACK(handle);
766 		if (!ret)
767 		{
768 			ret = SEND_CTS(handle);
769 			if (!ret)
770 			{
771 				ret = RECV_ACK(handle, NULL);
772 			}
773 		}
774 		if (ret)
775 		{
776 			break;
777 		}
778 
779 		ve->data = tifiles_ve_alloc_data(ve->size);
780 		ret = RECV_XDP(handle, &ve_size, ve->data);
781 		if (!ret)
782 		{
783 			ve->size = ve_size;
784 
785 			if (handle->model != CALC_TI73 && ve->type == TI83p_PIC)
786 			{
787 				if (ve->version >= 0xA)
788 				{
789 					content->model = CALC_TI84PC;
790 				}
791 				else
792 				{
793 					content->model = CALC_TI83P;
794 				}
795 			}
796 
797 			ret = SEND_ACK(handle);
798 		}
799 	} while(0);
800 
801 	return ret;
802 }
803 
804 static int		get_version	(CalcHandle* handle, CalcInfos* infos);
805 
send_flash(CalcHandle * handle,FlashContent * content)806 static int		send_flash	(CalcHandle* handle, FlashContent* content)
807 {
808 	int ret;
809 	FlashContent *ptr;
810 	unsigned int i, j;
811 	uint16_t size;
812 	int cpu15mhz = 0;
813 
814 	// search for data header
815 	for (ptr = content; ptr != NULL; ptr = ptr->next)
816 	{
817 		if (ptr->data_type == TI83p_AMS || ptr->data_type == TI83p_APPL)
818 		{
819 			break;
820 		}
821 	}
822 	if (ptr == NULL)
823 	{
824 		return -1;
825 	}
826 
827 	if (ptr->data_type == TI83p_AMS)
828 	{
829 		size = 0x100;
830 	}
831 	else if (ptr->data_type == TI83p_APPL)
832 	{
833 		size = 0x80;
834 	}
835 	else
836 	{
837 		return -1;
838 	}
839 
840 	// check for 83+ Silver Edition (not usable in boot mode, sic!)
841 	if (handle->model != CALC_TI73 && ptr->data_type == TI83p_APPL)
842 	{
843 		CalcInfos infos;
844 
845 		ret = get_version(handle, &infos);
846 		if (ret)
847 		{
848 			return ret;
849 		}
850 		cpu15mhz = infos.hw_version & 1;
851 
852 		if (!infos.battery)
853 		{
854 			ticalcs_info(_("Battery low, stopping flash app transfer"));
855 			return -1;
856 		}
857 	}
858 
859 	ticalcs_info(_("FLASH name: \"%s\""), ptr->name);
860 	ticalcs_info(_("FLASH size: %i bytes."), ptr->data_length);
861 
862 	ticonv_varname_to_utf8_sn(handle->model, ptr->name, update_->text, sizeof(update_->text), ptr->data_type);
863 	update_label();
864 
865 	update_->cnt2 = 0;
866 	update_->max2 = ptr->data_length;
867 
868 	for (i = 0; !ret && i < ptr->num_pages; i++)
869 	{
870 		FlashPage *fp = ptr->pages[i];
871 
872 		if ((ptr->data_type == TI83p_AMS) && (i == 1))	// need relocation ?
873 		{
874 			fp->addr = 0x4000;
875 		}
876 
877 		for (j = 0; !ret && j < fp->size; j += size)
878 		{
879 			uint16_t addr = fp->addr + j;
880 			uint8_t* data = fp->data + j;
881 
882 			ret = SEND_VAR2(handle, size, ptr->data_type, fp->flag, addr, fp->page);
883 			if (!ret)
884 			{
885 				ret = RECV_ACK(handle, NULL);
886 			}
887 			if (ret)
888 			{
889 				break;
890 			}
891 
892 			if (handle->model == CALC_TI73 && ptr->data_type == TI83p_APPL)
893 			{
894 				ret = RECV_CTS(handle, 0);
895 			}	 // Depends on OS version?
896 			else
897 			{
898 				ret = RECV_CTS(handle, 10);
899 			}
900 			if (!ret)
901 			{
902 				ret = SEND_ACK(handle);
903 				if (!ret)
904 				{
905 					ret = SEND_XDP(handle, size, data);
906 					if (!ret)
907 					{
908 						ret = RECV_ACK(handle, NULL);
909 						if (!ret)
910 						{
911 							update_->cnt2 += size;
912 							update_->pbar();
913 						}
914 					}
915 				}
916 			}
917 		}
918 
919 		/* Note:
920 			TI83+SE, TI84+ and TI84+SE don't need a pause (otherwise transfer fails).
921 			TI73 and TI83+ need a pause (otherwise transfer fails).
922 			Delay also causes OS transfers to fail on the 15Mhz calcs and unneeded for OS's
923 		*/
924 		if (!ret && !cpu15mhz && ptr->data_type == TI83p_APPL)
925 		{
926 			if (i == 1)
927 			{
928 				PAUSE(1000);		// This pause is NEEDED !
929 			}
930 			if (i == ptr->num_pages - 2)
931 			{
932 				PAUSE(2500);		// This pause is NEEDED !
933 			}
934 		}
935 	}
936 
937 	if (!ret)
938 	{
939 		ret = SEND_EOT(handle);
940 		if (!ret)
941 		{
942 			ret = RECV_ACK(handle, NULL);
943 		}
944 	}
945 
946 	return ret;
947 }
948 
recv_flash(CalcHandle * handle,FlashContent * content,VarRequest * vr)949 static int		recv_flash	(CalcHandle* handle, FlashContent* content, VarRequest* vr)
950 {
951 	int ret;
952 	FlashPage *fp;
953 	uint16_t data_addr;
954 	uint16_t old_page = 0;
955 	uint16_t data_page;
956 	uint16_t data_length;
957 	uint8_t data_type;
958 	uint32_t size;
959 	int first_block;
960 	int page;
961 	int offset;
962 	uint8_t buffer[FLASH_PAGE_SIZE + 4];
963 
964 	ticonv_varname_to_utf8_sn(handle->model, vr->name, update_->text, sizeof(update_->text), vr->type);
965 	update_label();
966 
967 	content->model = handle->model;
968 	ticalcs_strlcpy(content->name, vr->name, sizeof(content->name));
969 	content->data_type = vr->type;
970 	content->device_type = handle->model == CALC_TI73 ? DEVICE_TYPE_73 : DEVICE_TYPE_83P;
971 	content->num_pages = 2048;	// TI83+ has 512 KB of FLASH max
972 	content->pages = tifiles_fp_create_array(content->num_pages);
973 
974 	page = 0;
975 	fp = content->pages[page] = tifiles_fp_create();
976 
977 	ret = SEND_REQ2(handle, 0x00, TI73_APPL, vr->name, 0x00);
978 	if (!ret)
979 	{
980 		ret = RECV_ACK(handle, NULL);
981 	}
982 	if (ret)
983 	{
984 		return ret;
985 	}
986 
987 	update_->cnt2 = 0;
988 	update_->max2 = vr->size;
989 
990 	for (size = 0, first_block = 1, offset = 0; !ret;)
991 	{
992 		char name[9];
993 		int ret2;
994 
995 		ret = RECV_VAR2(handle, &data_length, &data_type, name, &data_addr, &data_page);
996 		ret2 = SEND_ACK(handle);
997 		if (ret)
998 		{
999 			if (ret == ERR_EOT)
1000 			{
1001 				ret = 0;
1002 			}
1003 			break;
1004 		}
1005 		if (ret2)
1006 		{
1007 			ret = ret2;
1008 			break;
1009 		}
1010 
1011 		if (first_block)
1012 		{
1013 			old_page = data_page;
1014 
1015 			fp->addr = data_addr & 0x4000;
1016 			fp->page = data_page;
1017 		}
1018 		if (old_page != data_page)
1019 		{
1020 			fp->addr = data_addr & 0x4000;
1021 			fp->page = old_page;
1022 			fp->flag = 0x80;
1023 			fp->size = offset;
1024 			fp->data = tifiles_fp_alloc_data(FLASH_PAGE_SIZE);
1025 			memcpy(fp->data, buffer, fp->size);
1026 
1027 			page++;
1028 			offset = 0;
1029 			old_page = data_page;
1030 
1031 			fp = content->pages[page] = tifiles_fp_create();
1032 		}
1033 
1034 		ret = SEND_CTS(handle);
1035 		if (!ret)
1036 		{
1037 			ret = RECV_ACK(handle, NULL);
1038 			if (!ret)
1039 			{
1040 				ret = RECV_XDP(handle, &data_length, &buffer[offset]);
1041 				if (!ret)
1042 				{
1043 					ret = SEND_ACK(handle);
1044 				}
1045 			}
1046 		}
1047 		if (ret)
1048 		{
1049 			break;
1050 		}
1051 
1052 		if (first_block)
1053 		{
1054 			first_block = 0;
1055 
1056 			/* compute actual application size */
1057 			if (buffer[0] == 0x80 && buffer[1] == 0x0f)
1058 			{
1059 				uint32_t len = ((uint32_t)(buffer[2])) << 24 | ((uint32_t)(buffer[3])) << 16 | ((uint32_t)(buffer[4])) << 8 | (uint32_t)(buffer[5]);
1060 				update_->max2 = len + 75;
1061 			}
1062 		}
1063 
1064 		size += data_length;
1065 		offset += data_length;
1066 
1067 		update_->cnt2 = size;
1068 		update_->pbar();
1069 	}
1070 
1071 	fp->addr = data_addr & 0x4000;
1072 	fp->page = old_page;
1073 	fp->flag = 0x80;
1074 	fp->size = offset;
1075 	fp->data = tifiles_fp_alloc_data(FLASH_PAGE_SIZE);
1076 	memcpy(fp->data, buffer, fp->size);
1077 	page++;
1078 
1079 	content->num_pages = page;
1080 
1081 	return ret;
1082 }
1083 
recv_idlist(CalcHandle * handle,uint8_t * id)1084 static int		recv_idlist	(CalcHandle* handle, uint8_t* id)
1085 {
1086 	int ret;
1087 	uint16_t unused;
1088 	uint16_t varsize;
1089 	uint8_t vartype;
1090 	char varname[9];
1091 	uint8_t varattr;
1092 	uint8_t version;
1093 	uint8_t data[16];
1094 	int i;
1095 
1096 	ticalcs_strlcpy(update_->text, "ID-LIST", sizeof(update_->text));
1097 	update_label();
1098 
1099 	ret = SEND_REQ(handle, 0x0000, TI73_IDLIST, "\0\0\0\0\0\0\0", 0x00, 0x00);
1100 	if (!ret)
1101 	{
1102 		ret = RECV_ACK(handle, &unused);
1103 		if (!ret)
1104 		{
1105 			ret = RECV_VAR(handle, &varsize, &vartype, varname, &varattr, &version);
1106 			if (!ret)
1107 			{
1108 				ret = SEND_ACK(handle);
1109 				if (!ret)
1110 				{
1111 					ret = SEND_CTS(handle);
1112 					if (!ret)
1113 					{
1114 						ret = RECV_ACK(handle, NULL);
1115 						if (!ret)
1116 						{
1117 							ret = RECV_XDP(handle, &varsize, data);
1118 							if (!ret)
1119 							{
1120 								ret = SEND_ACK(handle);
1121 								if (!ret)
1122 								{
1123 									i = data[9];
1124 									data[9] = data[10];
1125 									data[10] = i;
1126 
1127 									for (i = 4; i < varsize; i++)
1128 									{
1129 										sprintf((char *)&id[2 * (i-4)], "%02x", data[i]);
1130 									}
1131 									id[7*2] = '\0';
1132 								}
1133 							}
1134 						}
1135 					}
1136 				}
1137 			}
1138 		}
1139 	}
1140 
1141 	return ret;
1142 }
1143 
dump_rom_1(CalcHandle * handle)1144 static int		dump_rom_1	(CalcHandle* handle)
1145 {
1146 	// Send dumping program
1147 	if (handle->model == CALC_TI73)
1148 	{
1149 		return rd_send(handle, "romdump.73p", romDumpSize73, romDump73);
1150 	}
1151 	else
1152 	{
1153 		CalcInfos infos;
1154 
1155 		int ret = get_version(handle, &infos);
1156 		if (!ret)
1157 		{
1158 			if (infos.hw_version < 5)
1159 			{
1160 				ret = rd_send(handle, "romdump.8Xp", romDumpSize8Xp, romDump8Xp);
1161 			}
1162 			else
1163 			{
1164 				ret = rd_send(handle, "romdump.8Xp", romDumpSize84pc, romDump84pc);
1165 			}
1166 		}
1167 
1168 		return ret;
1169 	}
1170 }
1171 
dump_rom_2(CalcHandle * handle,CalcDumpSize size,const char * filename)1172 static int		dump_rom_2	(CalcHandle* handle, CalcDumpSize size, const char *filename)
1173 {
1174 	static const uint16_t keys_83p[] = {
1175 		0x40, 0x09, 0x09, 0xFC9C, /* Quit, Clear, Clear, Asm( */
1176 		0xDA, 0xAB, 0xA8, 0xA6,   /* prgm, R, O, M */
1177 		0x9D, 0xAE, 0xA6, 0xA9,   /* D, U, M, P */
1178 		0x86, 0x05 };             /* ), Enter */
1179 
1180 	static const uint16_t keys_73[] = {
1181 		0x40, 0x09, 0x09, 0xDA,   /* Quit, Clear, Clear, prgm */
1182 		0xAB, 0xA8, 0xA6, 0x9D,   /* R, O, M, D, */
1183 		0xAE, 0xA6, 0xA9, 0x05 }; /* U, M, P, Enter */
1184 
1185 	int ret = 0;
1186 	const uint16_t *keys;
1187 	unsigned int i, nkeys;
1188 
1189 	if (handle->model == CALC_TI73)
1190 	{
1191 		keys = keys_73;
1192 		nkeys = sizeof(keys_73) / sizeof(keys_73[0]);
1193 	}
1194 	else
1195 	{
1196 		keys = keys_83p;
1197 		nkeys = sizeof(keys_83p) / sizeof(keys_83p[0]);
1198 	}
1199 
1200 	// Launch program by remote control
1201 	PAUSE(200);
1202 	for (i = 0; !ret && i < nkeys - 1; i++)
1203 	{
1204 		ret = send_key(handle, (uint32_t)(keys[i]));
1205 		PAUSE(100);
1206 	}
1207 
1208 	if (!ret)
1209 	{
1210 		// This fixes a 100% reproducible timeout: send_key normally requests an ACK,
1211 		// but when the program is running, no ACK is sent. Therefore, hit the Enter key
1212 		// without requesting an ACK.
1213 		ret = SEND_KEY(handle, keys[i]);
1214 		if (!ret)
1215 		{
1216 			ret = RECV_ACK(handle, NULL); // when the key is received
1217 			if (!ret)
1218 			{
1219 				PAUSE(1000);
1220 
1221 				// Get dump
1222 				// (Normally there would be another ACK after the program exits,
1223 				// but the ROM dumper disables that behavior)
1224 				ret = rd_dump(handle, filename);
1225 			}
1226 		}
1227 	}
1228 
1229 	return ret;
1230 }
1231 
set_clock(CalcHandle * handle,CalcClock * _clock)1232 static int		set_clock	(CalcHandle* handle, CalcClock* _clock)
1233 {
1234 	int ret;
1235 	uint8_t buffer[9];
1236 	uint32_t calc_time;
1237 
1238 	struct tm ref, cur;
1239 	time_t r, c, now;
1240 
1241 	time(&now);	// retrieve current DST setting
1242 	memcpy(&ref, localtime(&now), sizeof(struct tm));
1243 
1244 	ref.tm_year = 1997 - 1900;
1245 	ref.tm_mon = 0;
1246 	ref.tm_yday = 0;
1247 	ref.tm_mday = 1;
1248 	ref.tm_wday = 3;
1249 	ref.tm_hour = 0;
1250 	ref.tm_min = 0;
1251 	ref.tm_sec = 0;
1252 	//ref.tm_isdst = 1;
1253 	r = mktime(&ref);
1254 	//printf("%s\n", asctime(&ref));
1255 
1256 	cur.tm_year = _clock->year - 1900;
1257 	cur.tm_mon = _clock->month - 1;
1258 	cur.tm_mday = _clock->day;
1259 	cur.tm_hour = _clock->hours;
1260 	cur.tm_min = _clock->minutes;
1261 	cur.tm_sec = _clock->seconds;
1262 	cur.tm_isdst = 1;
1263 	c = mktime(&cur);
1264 	//printf("%s\n", asctime(&cur));
1265 
1266 	calc_time = (uint32_t)difftime(c, r);
1267 
1268 	buffer[0] = 0;
1269 	buffer[1] = 0;
1270 	buffer[2] = MSB(MSW(calc_time));
1271 	buffer[3] = LSB(MSW(calc_time));
1272 	buffer[4] = MSB(LSW(calc_time));
1273 	buffer[5] = LSB(LSW(calc_time));
1274 	buffer[6] = _clock->date_format;
1275 	buffer[7] = _clock->time_format;
1276 	buffer[8] = 0xff;
1277 
1278 	ticalcs_strlcpy(update_->text, _("Setting clock..."), sizeof(update_->text));
1279 	update_label();
1280 
1281 	ret = SEND_RTS(handle, 13, TI73_CLK, "\0x08\0\0\0\0\0\0\0", 0x00, 0x00);
1282 	if (!ret)
1283 	{
1284 		ret = RECV_ACK(handle, NULL);
1285 		if (!ret)
1286 		{
1287 			ret = RECV_CTS(handle, 13);
1288 			if (!ret)
1289 			{
1290 				ret = SEND_ACK(handle);
1291 				if (!ret)
1292 				{
1293 					ret = SEND_XDP(handle, 9, buffer);
1294 					if (!ret)
1295 					{
1296 						ret = RECV_ACK(handle, NULL);
1297 						if (!ret)
1298 						{
1299 							ret = SEND_EOT(handle);
1300 						}
1301 					}
1302 				}
1303 			}
1304 		}
1305 	}
1306 
1307 	return ret;
1308 }
1309 
get_clock(CalcHandle * handle,CalcClock * _clock)1310 static int		get_clock	(CalcHandle* handle, CalcClock* _clock)
1311 {
1312 	int ret;
1313 	uint16_t varsize;
1314 	uint8_t vartype;
1315 	uint8_t varattr;
1316 	uint8_t version;
1317 	char varname[9];
1318 	uint8_t * buffer = handle->buffer2;
1319 	uint32_t calc_time;
1320 
1321 	struct tm ref, *cur;
1322 	time_t r, c, now;
1323 
1324 	ticalcs_strlcpy(update_->text, _("Getting clock..."), sizeof(update_->text));
1325 	update_label();
1326 
1327 	ret = SEND_REQ(handle, 0x0000, TI73_CLK, "\0x08\0\0\0\0\0\0\0", 0x00, 0x00);
1328 	if (!ret)
1329 	{
1330 		ret = RECV_ACK(handle, NULL);
1331 		if (!ret)
1332 		{
1333 			ret = RECV_VAR(handle, &varsize, &vartype, varname, &varattr, &version);
1334 			if (!ret)
1335 			{
1336 				ret = SEND_ACK(handle);
1337 				if (!ret)
1338 				{
1339 					ret = SEND_CTS(handle);
1340 					if (!ret)
1341 					{
1342 						ret = RECV_ACK(handle, NULL);
1343 						if (!ret)
1344 						{
1345 							ret = RECV_XDP(handle, &varsize, buffer);
1346 							if (!ret)
1347 							{
1348 								ret = SEND_ACK(handle);
1349 							}
1350 						}
1351 					}
1352 				}
1353 			}
1354 		}
1355 	}
1356 
1357 	if (!ret)
1358 	{
1359 		calc_time = (((uint32_t)(buffer[2])) << 24) | (((uint32_t)(buffer[3])) << 16) | (((uint32_t)(buffer[4])) << 8) | (uint32_t)(buffer[5]);
1360 		//printf("<%08x>\n", time);
1361 
1362 		time(&now);	// retrieve current DST setting
1363 		memcpy(&ref, localtime(&now), sizeof(struct tm));;
1364 		ref.tm_year = 1997 - 1900;
1365 		ref.tm_mon = 0;
1366 		ref.tm_yday = 0;
1367 		ref.tm_mday = 1;
1368 		ref.tm_wday = 3;
1369 		ref.tm_hour = 0;
1370 		ref.tm_min = 0;
1371 		ref.tm_sec = 0;
1372 		//ref.tm_isdst = 1;
1373 		r = mktime(&ref);
1374 		//printf("%s\n", asctime(&ref));
1375 
1376 		c = r + calc_time;
1377 		cur = localtime(&c);
1378 		//printf("%s\n", asctime(cur));
1379 
1380 		_clock->year = cur->tm_year + 1900;
1381 		_clock->month = cur->tm_mon + 1;
1382 		_clock->day = cur->tm_mday;
1383 		_clock->hours = cur->tm_hour;
1384 		_clock->minutes = cur->tm_min;
1385 		_clock->seconds = cur->tm_sec;
1386 
1387 		_clock->date_format = buffer[6];
1388 		_clock->time_format = buffer[7];
1389 	}
1390 
1391 	return ret;
1392 }
1393 
del_var(CalcHandle * handle,VarRequest * vr)1394 static int		del_var		(CalcHandle* handle, VarRequest* vr)
1395 {
1396 	int ret;
1397 	char *utf8;
1398 
1399 	utf8 = ticonv_varname_to_utf8(handle->model, vr->name, vr->type);
1400 	ticalcs_slprintf(update_->text, sizeof(update_->text), _("Deleting %s..."), utf8);
1401 	ticonv_utf8_free(utf8);
1402 	update_label();
1403 
1404 	ret = SEND_DEL(handle, (uint16_t)vr->size, vr->type, vr->name, vr->attr);
1405 	if (!ret)
1406 	{
1407 		ret = RECV_ACK(handle, NULL);
1408 		if (!ret)
1409 		{
1410 			ret = RECV_ACK(handle, NULL);
1411 		}
1412 	}
1413 
1414 	return ret;
1415 }
1416 
get_version(CalcHandle * handle,CalcInfos * infos)1417 static int		get_version	(CalcHandle* handle, CalcInfos* infos)
1418 {
1419 	int ret;
1420 	uint16_t length;
1421 	uint8_t buf[32];
1422 
1423 	ret = SEND_VER(handle);
1424 	if (!ret)
1425 	{
1426 		ret = RECV_ACK(handle, NULL);
1427 		if (!ret)
1428 		{
1429 			ret = SEND_CTS(handle);
1430 			if (!ret)
1431 			{
1432 				ret = RECV_ACK(handle, NULL);
1433 				if (!ret)
1434 				{
1435 					ret = RECV_XDP(handle, &length, buf);
1436 					if (!ret)
1437 					{
1438 						ret = SEND_ACK(handle);
1439 					}
1440 				}
1441 			}
1442 		}
1443 	}
1444 
1445 	if (!ret)
1446 	{
1447 		memset(infos, 0, sizeof(CalcInfos));
1448 		if (handle->model == CALC_TI73)
1449 		{
1450 			ticalcs_slprintf(infos->os_version, sizeof(infos->os_version), "%1x.%02x", buf[0], buf[1]);
1451 			ticalcs_slprintf(infos->boot_version, sizeof(infos->boot_version), "%1x.%02x", buf[2], buf[3]);
1452 		}
1453 		else
1454 		{
1455 			ticalcs_slprintf(infos->os_version, sizeof(infos->os_version), "%1i.%02i", buf[0], buf[1]);
1456 			ticalcs_slprintf(infos->boot_version, sizeof(infos->boot_version), "%1i.%02i", buf[2], buf[3]);
1457 		}
1458 		infos->battery = (buf[4] & 1) ? 0 : 1;
1459 		infos->hw_version = buf[5];
1460 		switch(buf[5])
1461 		{
1462 		case 0: infos->model = CALC_TI83P; break;
1463 		case 1: infos->model = CALC_TI83P; break;
1464 		case 2: infos->model = CALC_TI84P; break;
1465 		case 3: infos->model = CALC_TI84P; break;
1466 		case 5: infos->model = CALC_TI84PC; break;
1467 		default: infos->model = CALC_TI84PC; break; // If new models ever arise, they'll probably be 84+CSE or newer anyway.
1468 		}
1469 		infos->language_id = buf[6];
1470 		infos->sub_lang_id = buf[7];
1471 		infos->mask = INFOS_BOOT_VERSION | INFOS_OS_VERSION | INFOS_BATTERY | INFOS_HW_VERSION | INFOS_CALC_MODEL | INFOS_LANG_ID | INFOS_SUB_LANG_ID;
1472 
1473 		tifiles_hexdump(buf, length);
1474 		ticalcs_info(_("  OS: %s"), infos->os_version);
1475 		ticalcs_info(_("  BIOS: %s"), infos->boot_version);
1476 		ticalcs_info(_("  HW: %i"), infos->hw_version);
1477 		ticalcs_info(_("  Battery: %s"), infos->battery ? _("good") : _("low"));
1478 	}
1479 
1480 	return ret;
1481 }
1482 
send_cert(CalcHandle * handle,FlashContent * content)1483 static int		send_cert	(CalcHandle* handle, FlashContent* content)
1484 {
1485 	int ret = 0;
1486 	FlashContent *ptr;
1487 	int i, nblocks;
1488 	uint16_t size = 0xE8;
1489 
1490 	// search for cert header
1491 	for (ptr = content; ptr != NULL; ptr = ptr->next)
1492 	{
1493 		if (ptr->data_type == TI83p_CERT)
1494 		{
1495 			break;
1496 		}
1497 	}
1498 
1499 	if (ptr != NULL)
1500 	{
1501 		// send content
1502 		ticalcs_info(_("FLASH name: \"%s\""), ptr->name);
1503 		ticalcs_info(_("FLASH size: %i bytes."), ptr->data_length);
1504 
1505 		nblocks = ptr->data_length / size;
1506 		update_->max2 = nblocks;
1507 
1508 		ret = SEND_VAR2(handle, size, ptr->data_type, 0x04, 0x4000, 0x00);
1509 		if (!ret)
1510 		{
1511 			ret = RECV_ACK(handle, NULL);
1512 			if (!ret)
1513 			{
1514 				ret = RECV_CTS(handle, 10);
1515 				if (!ret)
1516 				{
1517 					ret = SEND_ACK(handle);
1518 				}
1519 			}
1520 		}
1521 
1522 		for (i = 0; !ret && i <= nblocks; i++)
1523 		{
1524 			uint16_t length = size;
1525 
1526 			ret = SEND_XDP(handle, length, (ptr->data_part) + length * i);
1527 			if (!ret)
1528 			{
1529 				ret = RECV_ACK(handle, NULL);
1530 				if (!ret)
1531 				{
1532 					ret = RECV_CTS(handle, size);
1533 					if (!ret)
1534 					{
1535 						ret = SEND_ACK(handle);
1536 						if (!ret)
1537 						{
1538 							update_->cnt2 = i;
1539 							update_->pbar();
1540 						}
1541 					}
1542 				}
1543 			}
1544 		}
1545 
1546 		if (!ret)
1547 		{
1548 			ret = SEND_EOT(handle);
1549 			ticalcs_info(_("Header sent completely."));
1550 		}
1551 	}
1552 
1553 	return ret;
1554 }
1555 
recv_cert(CalcHandle * handle,FlashContent * content)1556 static int		recv_cert	(CalcHandle* handle, FlashContent* content)
1557 {
1558 	int ret;
1559 	int i;
1560 	uint8_t buf[256];
1561 
1562 	ticalcs_strlcpy(update_->text, _("Receiving certificate"), sizeof(update_->text));
1563 	update_label();
1564 
1565 	content->model = handle->model;
1566 	content->name[0] = 0;
1567 	content->data_type = TI83p_CERT;
1568 	content->device_type = 0x73;
1569 	content->num_pages = 0;
1570 	content->data_part = (uint8_t *)tifiles_ve_alloc_data(2 * 1024 * 1024);	// 2MB max
1571 
1572 	ret = SEND_REQ2(handle, 0x00, TI83p_GETCERT, "\0\0\0\0\0\0\0", 0x00);
1573 	if (!ret)
1574 	{
1575 		ret = RECV_ACK(handle, NULL);
1576 		if (!ret)
1577 		{
1578 			ret = ticables_cable_recv(handle->cable, buf, 4);	//VAR w/ no header
1579 			if (!ret)
1580 			{
1581 				ticalcs_info(" TI->PC: VAR");
1582 				ret = SEND_ACK(handle);
1583 
1584 				for (i = 0, content->data_length = 0; !ret; i++)
1585 				{
1586 					uint16_t block_size;
1587 
1588 					ret = SEND_CTS(handle);
1589 					if (!ret)
1590 					{
1591 						ret = RECV_ACK(handle, NULL);
1592 						if (!ret)
1593 						{
1594 							ret = RECV_XDP(handle, &block_size, content->data_part);
1595 							if (!ret)
1596 							{
1597 								ret = SEND_ACK(handle);
1598 								if (!ret)
1599 								{
1600 									content->data_length += block_size;
1601 
1602 									update_->cnt2 += block_size;
1603 									update_->pbar();
1604 								}
1605 							}
1606 						}
1607 					}
1608 				}
1609 			}
1610 		}
1611 	}
1612 
1613 	return ret;
1614 }
1615 
1616 const CalcFncts calc_73 =
1617 {
1618 	CALC_TI73,
1619 	"TI73",
1620 	"TI-73",
1621 	"TI-73",
1622 	OPS_ISREADY | OPS_KEYS | OPS_SCREEN | OPS_DIRLIST | OPS_BACKUP | OPS_VARS |
1623 	OPS_FLASH | OPS_IDLIST | OPS_ROMDUMP | OPS_VERSION | OPS_OS |
1624 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH | FTS_BACKUP,
1625 	PRODUCT_ID_TI73,
1626 	{"",     /* is_ready */
1627 	 "",     /* send_key */
1628 	 "",     /* execute */
1629 	 "1P",   /* recv_screen */
1630 	 "1L",   /* get_dirlist */
1631 	 "",     /* get_memfree */
1632 	 "2P",   /* send_backup */
1633 	 "2P",   /* recv_backup */
1634 	 "2P1L", /* send_var */
1635 	 "1P1L", /* recv_var */
1636 	 "2P1L", /* send_var_ns */
1637 	 "1P1L", /* recv_var_ns */
1638 	 "2P1L", /* send_app */
1639 	 "2P1L", /* recv_app */
1640 	 "2P",   /* send_os */
1641 	 "1L",   /* recv_idlist */
1642 	 "2P",   /* dump_rom_1 */
1643 	 "2P",   /* dump_rom_2 */
1644 	 "",     /* set_clock */
1645 	 "",     /* get_clock */
1646 	 "1L",   /* del_var */
1647 	 "1L",   /* new_folder */
1648 	 "",     /* get_version */
1649 	 "1L",   /* send_cert */
1650 	 "1L",   /* recv_cert */
1651 	 "",     /* rename */
1652 	 "",     /* chattr */
1653 	 "",     /* send_all_vars_backup */
1654 	 ""      /* recv_all_vars_backup */ },
1655 	&is_ready,
1656 	&send_key,
1657 	&execute,
1658 	&recv_screen,
1659 	&get_dirlist,
1660 	&get_memfree,
1661 	&send_backup,
1662 	&recv_backup,
1663 	&send_var,
1664 	&recv_var,
1665 	&noop_send_var_ns,
1666 	&noop_recv_var_ns,
1667 	&send_flash,
1668 	&recv_flash,
1669 	&send_flash,
1670 	&recv_idlist,
1671 	&dump_rom_1,
1672 	&dump_rom_2,
1673 	&set_clock,
1674 	&get_clock,
1675 	&del_var,
1676 	&noop_new_folder,
1677 	&get_version,
1678 	&send_cert,
1679 	&recv_cert,
1680 	&noop_rename_var,
1681 	&noop_change_attr,
1682 	&noop_send_all_vars_backup,
1683 	&noop_recv_all_vars_backup
1684 };
1685 
1686 const CalcFncts calc_83p =
1687 {
1688 	CALC_TI83P,
1689 	"TI83+",
1690 	"TI-83 Plus",
1691 	"TI-83 Plus",
1692 	OPS_ISREADY | OPS_KEYS | OPS_SCREEN | OPS_DIRLIST | OPS_BACKUP | OPS_VARS |
1693 	OPS_FLASH | OPS_IDLIST | OPS_ROMDUMP | OPS_DELVAR | OPS_VERSION | OPS_OS |
1694 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH | FTS_CERT | FTS_BACKUP,
1695 	PRODUCT_ID_TI83P,
1696 	{"",     /* is_ready */
1697 	 "",     /* send_key */
1698 	 "",     /* execute */
1699 	 "1P",   /* recv_screen */
1700 	 "1L",   /* get_dirlist */
1701 	 "",     /* get_memfree */
1702 	 "2P",   /* send_backup */
1703 	 "2P",   /* recv_backup */
1704 	 "2P1L", /* send_var */
1705 	 "1P1L", /* recv_var */
1706 	 "2P1L", /* send_var_ns */
1707 	 "1P1L", /* recv_var_ns */
1708 	 "2P1L", /* send_app */
1709 	 "2P1L", /* recv_app */
1710 	 "2P",   /* send_os */
1711 	 "1L",   /* recv_idlist */
1712 	 "2P",   /* dump_rom_1 */
1713 	 "2P",   /* dump_rom_2 */
1714 	 "",     /* set_clock */
1715 	 "",     /* get_clock */
1716 	 "1L",   /* del_var */
1717 	 "1L",   /* new_folder */
1718 	 "",     /* get_version */
1719 	 "1L",   /* send_cert */
1720 	 "1L",   /* recv_cert */
1721 	 "",     /* rename */
1722 	 "",     /* chattr */
1723 	 "",     /* send_all_vars_backup */
1724 	 ""      /* recv_all_vars_backup */ },
1725 	&is_ready,
1726 	&send_key,
1727 	&execute,
1728 	&recv_screen,
1729 	&get_dirlist,
1730 	&get_memfree,
1731 	&send_backup,
1732 	&recv_backup,
1733 	&send_var,
1734 	&recv_var,
1735 	&noop_send_var_ns,
1736 	&noop_recv_var_ns,
1737 	&send_flash,
1738 	&recv_flash,
1739 	&send_flash,
1740 	&recv_idlist,
1741 	&dump_rom_1,
1742 	&dump_rom_2,
1743 	&set_clock,
1744 	&get_clock,
1745 	&del_var,
1746 	&noop_new_folder,
1747 	&get_version,
1748 	&send_cert,
1749 	&recv_cert,
1750 	&noop_rename_var,
1751 	&noop_change_attr,
1752 	&noop_send_all_vars_backup,
1753 	&noop_recv_all_vars_backup
1754 };
1755 
1756 const CalcFncts calc_84p =
1757 {
1758 	CALC_TI84P,
1759 	"TI84+",
1760 	"TI-84 Plus",
1761 	"TI-84 Plus",
1762 	OPS_ISREADY | OPS_KEYS | OPS_SCREEN | OPS_DIRLIST | OPS_BACKUP | OPS_VARS |
1763 	OPS_FLASH | OPS_IDLIST | OPS_ROMDUMP | OPS_CLOCK | OPS_DELVAR | OPS_VERSION | OPS_OS |
1764 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH | FTS_CERT | FTS_BACKUP,
1765 	PRODUCT_ID_TI84P,
1766 	{"",     /* is_ready */
1767 	 "",     /* send_key */
1768 	 "",     /* execute */
1769 	 "1P",   /* recv_screen */
1770 	 "1L",   /* get_dirlist */
1771 	 "",     /* get_memfree */
1772 	 "2P",   /* send_backup */
1773 	 "2P",   /* recv_backup */
1774 	 "2P1L", /* send_var */
1775 	 "1P1L", /* recv_var */
1776 	 "2P1L", /* send_var_ns */
1777 	 "1P1L", /* recv_var_ns */
1778 	 "2P1L", /* send_app */
1779 	 "2P1L", /* recv_app */
1780 	 "2P",   /* send_os */
1781 	 "1L",   /* recv_idlist */
1782 	 "2P",   /* dump_rom_1 */
1783 	 "2P",   /* dump_rom_2 */
1784 	 "",     /* set_clock */
1785 	 "",     /* get_clock */
1786 	 "1L",   /* del_var */
1787 	 "1L",   /* new_folder */
1788 	 "",     /* get_version */
1789 	 "1L",   /* send_cert */
1790 	 "1L",   /* recv_cert */
1791 	 "",     /* rename */
1792 	 "",     /* chattr */
1793 	 "",     /* send_all_vars_backup */
1794 	 ""      /* recv_all_vars_backup */ },
1795 	&is_ready,
1796 	&send_key,
1797 	&execute,
1798 	&recv_screen,
1799 	&get_dirlist,
1800 	&get_memfree,
1801 	&send_backup,
1802 	&recv_backup,
1803 	&send_var,
1804 	&recv_var,
1805 	&noop_send_var_ns,
1806 	&noop_recv_var_ns,
1807 	&send_flash,
1808 	&recv_flash,
1809 	&send_flash,
1810 	&recv_idlist,
1811 	&dump_rom_1,
1812 	&dump_rom_2,
1813 	&set_clock,
1814 	&get_clock,
1815 	&del_var,
1816 	&noop_new_folder,
1817 	&get_version,
1818 	&send_cert,
1819 	&recv_cert,
1820 	&noop_rename_var,
1821 	&noop_change_attr,
1822 	&noop_send_all_vars_backup,
1823 	&noop_recv_all_vars_backup
1824 };
1825 
1826 const CalcFncts calc_84pcse =
1827 {
1828 	CALC_TI84PC,
1829 	"TI84+CSE",
1830 	"TI-84 Plus Color Silver Edition",
1831 	"TI-84 Plus Color Silver Edition",
1832 	OPS_ISREADY | OPS_KEYS | OPS_SCREEN | OPS_DIRLIST | OPS_BACKUP | OPS_VARS |
1833 	OPS_FLASH | OPS_IDLIST | OPS_ROMDUMP | OPS_CLOCK | OPS_DELVAR | OPS_VERSION | OPS_OS |
1834 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH | FTS_CERT | FTS_BACKUP,
1835 	PRODUCT_ID_TI84PCSE,
1836 	{"",     /* is_ready */
1837 	 "",     /* send_key */
1838 	 "",     /* execute */
1839 	 "1P",   /* recv_screen */
1840 	 "1L",   /* get_dirlist */
1841 	 "",     /* get_memfree */
1842 	 "2P",   /* send_backup */
1843 	 "2P",   /* recv_backup */
1844 	 "2P1L", /* send_var */
1845 	 "1P1L", /* recv_var */
1846 	 "2P1L", /* send_var_ns */
1847 	 "1P1L", /* recv_var_ns */
1848 	 "2P1L", /* send_app */
1849 	 "2P1L", /* recv_app */
1850 	 "2P",   /* send_os */
1851 	 "1L",   /* recv_idlist */
1852 	 "2P",   /* dump_rom_1 */
1853 	 "2P",   /* dump_rom_2 */
1854 	 "",     /* set_clock */
1855 	 "",     /* get_clock */
1856 	 "1L",   /* del_var */
1857 	 "1L",   /* new_folder */
1858 	 "",     /* get_version */
1859 	 "1L",   /* send_cert */
1860 	 "1L",   /* recv_cert */
1861 	 "",     /* rename */
1862 	 "",     /* chattr */
1863 	 "",     /* send_all_vars_backup */
1864 	 ""      /* recv_all_vars_backup */ },
1865 	&is_ready,
1866 	&send_key,
1867 	&execute,
1868 	&recv_screen,
1869 	&get_dirlist,
1870 	&get_memfree,
1871 	&send_backup,
1872 	&recv_backup,
1873 	&send_var,
1874 	&recv_var,
1875 	&noop_send_var_ns,
1876 	&noop_recv_var_ns,
1877 	&send_flash,
1878 	&recv_flash,
1879 	&send_flash,
1880 	&recv_idlist,
1881 	&dump_rom_1,
1882 	&dump_rom_2,
1883 	&set_clock,
1884 	&get_clock,
1885 	&del_var,
1886 	&noop_new_folder,
1887 	&get_version,
1888 	&send_cert,
1889 	&recv_cert,
1890 	&noop_rename_var,
1891 	&noop_change_attr,
1892 	&noop_send_all_vars_backup,
1893 	&noop_recv_all_vars_backup
1894 };
1895