1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id$ */
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  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software Foundation,
20  *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /*
24 	TI84+ support thru DirectUsb link.
25 */
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 
36 #include "ticalcs.h"
37 #include "gettext.h"
38 #include "internal.h"
39 #include "logging.h"
40 #include "error.h"
41 
42 #include "dusb_vpkt.h"
43 #include "dusb_cmd.h"
44 #include "rom84p.h"
45 #include "rom84pcu.h"
46 #include "rom834pceu.h"
47 #include "romdump.h"
48 #include "keys83p.h"
49 
50 // Screen coordinates of the TI83+
51 #define TI84P_ROWS  64
52 #define TI84P_COLS  96
53 #define TI84PC_ROWS 240
54 #define TI84PC_COLS 320
55 
is_ready(CalcHandle * handle)56 static int		is_ready	(CalcHandle* handle)
57 {
58 	int ret;
59 	static const DUSBModeSet mode = DUSB_MODE_NORMAL;
60 
61 	ret = dusb_cmd_s_mode_set(handle, mode);
62 	if (!ret)
63 	{
64 		// use PID_HOMESCREEN to return status ?
65 		ret = dusb_cmd_r_mode_ack(handle);
66 	}
67 
68 	return ret;
69 }
70 
send_key_noack(CalcHandle * handle,uint32_t key)71 static int		send_key_noack	(CalcHandle* handle, uint32_t key)
72 {
73 	int ret;
74 
75 	ret = dusb_cmd_s_execute(handle, "", "", DUSB_EID_KEY, "", (uint16_t)key);
76 	if (!ret)
77 	{
78 		ret = dusb_cmd_r_delay_ack(handle);
79 	}
80 
81 	return ret;
82 }
83 
send_key(CalcHandle * handle,uint32_t key)84 static int		send_key	(CalcHandle* handle, uint32_t key)
85 {
86 	int ret;
87 
88 	ret = send_key_noack(handle, key);
89 	if (!ret)
90 	{
91 		ret = dusb_cmd_r_data_ack(handle);
92 	}
93 
94 	return ret;
95 }
96 
execute(CalcHandle * handle,VarEntry * ve,const char * args)97 static int		execute		(CalcHandle* handle, VarEntry *ve, const char *args)
98 {
99 	uint8_t action;
100 	int ret;
101 
102 	switch (ve->type)
103 	{
104 		case TI84p_ASM:  action = DUSB_EID_ASM; break;
105 		case TI84p_APPL: action = DUSB_EID_APP; break;
106 		default:         action = DUSB_EID_PRGM; break;
107 	}
108 
109 	ret = dusb_cmd_s_execute(handle, ve->folder, ve->name, action, args, 0);
110 	if (!ret)
111 	{
112 		ret = dusb_cmd_r_data_ack(handle);
113 	}
114 
115 	return ret;
116 }
117 
recv_screen(CalcHandle * handle,CalcScreenCoord * sc,uint8_t ** bitmap)118 static int		recv_screen	(CalcHandle* handle, CalcScreenCoord* sc, uint8_t** bitmap)
119 {
120 	static const uint16_t pid[] = { DUSB_PID_SCREENSHOT };
121 	uint32_t size;
122 	uint8_t *data;
123 	int ret;
124 
125 	ret = dusb_cmd_s_param_request(handle, 1, pid);
126 	if (!ret)
127 	{
128 		ret = dusb_cmd_r_screenshot(handle, &size, &data);
129 		if (!ret)
130 		{
131 			switch (handle->model)
132 			{
133 			case CALC_TI84P_USB:
134 			case CALC_TI82A_USB:
135 			{
136 				if (size == TI84P_ROWS * TI84P_COLS / 8)
137 				{
138 					*bitmap = data;
139 					sc->width = TI84P_COLS;
140 					sc->height = TI84P_ROWS;
141 					sc->clipped_width = TI84P_COLS;
142 					sc->clipped_height = TI84P_ROWS;
143 					sc->pixel_format = CALC_PIXFMT_MONO;
144 				}
145 				else
146 				{
147 					g_free(data);
148 					*bitmap = NULL;
149 					ret = ERR_INVALID_SCREENSHOT;
150 				}
151 				break;
152 			}
153 			case CALC_TI84PC_USB:
154 			{
155 				size -= 4;
156 				*bitmap = ticalcs_alloc_screen(TI84PC_ROWS * TI84PC_COLS * 2);
157 				ret = ticalcs_screen_84pcse_rle_uncompress(data, size, *bitmap, TI84PC_ROWS * TI84PC_COLS * 2);
158 				g_free(data);
159 				if (ret)
160 				{
161 					ticalcs_free_screen(*bitmap);
162 					*bitmap = NULL;
163 					ret = ERR_INVALID_SCREENSHOT;
164 				}
165 				else
166 				{
167 					sc->width = TI84PC_COLS;
168 					sc->height = TI84PC_ROWS;
169 					sc->clipped_width = TI84PC_COLS;
170 					sc->clipped_height = TI84PC_ROWS;
171 					sc->pixel_format = CALC_PIXFMT_RGB_565_LE;
172 				}
173 				break;
174 			}
175 			case CALC_TI83PCE_USB:
176 			case CALC_TI84PCE_USB:
177 			{
178 				if (size == TI84PC_ROWS * TI84PC_COLS * 2)
179 				{
180 					// 83PCE, 84PCE
181 					*bitmap = data;
182 					sc->width = TI84PC_COLS;
183 					sc->height = TI84PC_ROWS;
184 					sc->clipped_width = TI84PC_COLS;
185 					sc->clipped_height = TI84PC_ROWS;
186 					sc->pixel_format = CALC_PIXFMT_RGB_565_LE;
187 					break;
188 				}
189 				// else fall through.
190 			}
191 			default:
192 			{
193 				g_free(data);
194 				*bitmap = NULL;
195 				ret = ERR_INVALID_SCREENSHOT;
196 				break;
197 			}
198 			}
199 		}
200 	}
201 
202 	return ret;
203 }
204 
get_dirlist(CalcHandle * handle,GNode ** vars,GNode ** apps)205 static int		get_dirlist	(CalcHandle* handle, GNode** vars, GNode** apps)
206 {
207 	static const uint16_t aids[] = { DUSB_AID_VAR_SIZE, DUSB_AID_VAR_TYPE, DUSB_AID_ARCHIVED };
208 	const int size = sizeof(aids) / sizeof(uint16_t);
209 	int ret;
210 	DUSBCalcAttr **attr;
211 	GNode *folder, *root, *node;
212 	char fldname[40], varname[40];
213 	char *utf8;
214 
215 	ret = dirlist_init_trees(handle, vars, apps);
216 	if (ret)
217 	{
218 		return ret;
219 	}
220 
221 	folder = dirlist_create_append_node(NULL, vars);
222 	if (!folder)
223 	{
224 		return ERR_MALLOC;
225 	}
226 	root = dirlist_create_append_node(NULL, apps);
227 	if (!root)
228 	{
229 		return ERR_MALLOC;
230 	}
231 
232 	// Add permanent variables (Window, RclWin / RclWindw, TblSet aka WINDW, ZSTO, TABLE)
233 	{
234 		VarEntry *ve;
235 
236 		ve = tifiles_ve_create();
237 		ticalcs_strlcpy(ve->name, "Window", sizeof(ve->name));
238 		ve->type = TI84p_WINDW;
239 		node = dirlist_create_append_node(ve, &folder);
240 		if (node != NULL)
241 		{
242 			ve = tifiles_ve_create();
243 			// Actually, "RclWindw" works even on an old 84+ running OS 2.43, but libticalcs
244 			// has been using "RclWin" successfully on TI-Z80 DUSB models since the beginning...
245 			ticalcs_strlcpy(ve->name, (handle->model == CALC_TI84PC_USB || handle->model == CALC_TI83PCE_USB || handle->model == CALC_TI84PCE_USB) ? "RclWindw" : "RclWin", sizeof(ve->name));
246 			ve->type = TI84p_ZSTO;
247 			node = dirlist_create_append_node(ve, &folder);
248 			if (node != NULL)
249 			{
250 				ve = tifiles_ve_create();
251 				ticalcs_strlcpy(ve->name, "TblSet", sizeof(ve->name));
252 				ve->type = TI84p_TABLE;
253 				node = dirlist_create_append_node(ve, &folder);
254 			}
255 		}
256 	}
257 
258 	if (!node)
259 	{
260 		return ERR_MALLOC;
261 	}
262 
263 	ret = dusb_cmd_s_dirlist_request(handle, size, aids);
264 	if (!ret)
265 	{
266 		for (;;)
267 		{
268 			VarEntry *ve;
269 
270 			attr = dusb_ca_new_array(handle, size);
271 			ret = dusb_cmd_r_var_header(handle, fldname, varname, attr);
272 			if (ret)
273 			{
274 				// Not a real error.
275 				if (ret == ERR_EOT)
276 				{
277 					ret = 0;
278 				}
279 				dusb_ca_del_array(handle, size, attr);
280 				break;
281 			}
282 
283 			ve = tifiles_ve_create();
284 			ticalcs_strlcpy(ve->name, varname, sizeof(ve->name));
285 			ve->size = (  (((uint32_t)(attr[0]->data[0])) << 24)
286 			            | (((uint32_t)(attr[0]->data[1])) << 16)
287 			            | (((uint32_t)(attr[0]->data[2])) <<  8)
288 			            | (((uint32_t)(attr[0]->data[3]))      ));
289 			ve->type = (uint32_t)(attr[1]->data[3]);
290 			ve->attr = attr[2]->data[0] ? ATTRB_ARCHIVED : ATTRB_NONE;
291 			dusb_ca_del_array(handle, size, attr);
292 
293 			node = dirlist_create_append_node(ve, (ve->type != TI73_APPL) ? &folder : &root);
294 			if (!node)
295 			{
296 				ret = ERR_MALLOC;
297 				break;
298 			}
299 
300 			utf8 = ticonv_varname_to_utf8(handle->model, ve->name, ve->type);
301 			ticalcs_slprintf(update_->text, sizeof(update_->text), _("Parsing %s"), utf8);
302 			ticonv_utf8_free(utf8);
303 			update_label();
304 		}
305 	}
306 
307 	return ret;
308 }
309 
get_memfree(CalcHandle * handle,uint32_t * ram,uint32_t * flash)310 static int		get_memfree	(CalcHandle* handle, uint32_t* ram, uint32_t* flash)
311 {
312 	static const uint16_t pids[] = { DUSB_PID_FREE_RAM, DUSB_PID_FREE_FLASH };
313 	const int size = sizeof(pids) / sizeof(uint16_t);
314 	DUSBCalcParam **params;
315 	int ret;
316 
317 	params = dusb_cp_new_array(handle, size);
318 	ret = dusb_cmd_s_param_request(handle, size, pids);
319 	if (!ret)
320 	{
321 		ret = dusb_cmd_r_param_data(handle, size, params);
322 		if (!ret)
323 		{
324 			*ram = (  (((uint32_t)(params[0]->data[4])) << 24)
325 			        | (((uint32_t)(params[0]->data[5])) << 16)
326 			        | (((uint32_t)(params[0]->data[6])) <<  8)
327 			        | (((uint32_t)(params[0]->data[7]))      ));
328 			*flash = (  (((uint32_t)(params[1]->data[4])) << 24)
329 			         | (((uint32_t)(params[1]->data[5])) << 16)
330 			         | (((uint32_t)(params[1]->data[6])) <<  8)
331 			         | (((uint32_t)(params[1]->data[7]))      ));
332 		}
333 	}
334 	dusb_cp_del_array(handle, size, params);
335 
336 	return ret;
337 }
338 
send_backup(CalcHandle * handle,BackupContent * content)339 static int		send_backup	(CalcHandle* handle, BackupContent* content)
340 {
341 	DUSBCalcAttr **attrs;
342 	const int nattrs = 3;
343 	uint32_t length;
344 	uint8_t *data, *p;
345 	int ret = 0;
346 	static const uint16_t keys[] = {
347 		KEY83P_Quit, KEY83P_LinkIO, KEY83P_Right, KEY83P_1
348 	};
349 	unsigned int i;
350 
351 	attrs = dusb_ca_new_array(handle, nattrs);
352 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE, 4);
353 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x07;
354 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = TI84p_BKUP;
355 
356 	attrs[1] = dusb_ca_new(handle, DUSB_AID_VAR_VERSION, 4);
357 	attrs[1]->data[0] = 0x00; attrs[1]->data[1] = 0x00;
358 	attrs[1]->data[2] = 0x00; attrs[1]->data[3] = content->version;
359 
360 	attrs[2] = dusb_ca_new(handle, DUSB_AID_BACKUP_HEADER, 8);
361 	attrs[2]->data[0] = MSB(content->data_length1);
362 	attrs[2]->data[1] = LSB(content->data_length1);
363 	attrs[2]->data[2] = MSB(content->data_length2);
364 	attrs[2]->data[3] = LSB(content->data_length2);
365 	attrs[2]->data[4] = MSB(content->data_length3);
366 	attrs[2]->data[5] = LSB(content->data_length3);
367 	attrs[2]->data[6] = MSB(content->mem_address);
368 	attrs[2]->data[7] = LSB(content->mem_address);
369 
370 	length = content->data_length1 + content->data_length2 + content->data_length3;
371 	data = p = g_malloc(length);
372 	memcpy(p, content->data_part1, content->data_length1);
373 	p += content->data_length1;
374 	memcpy(p, content->data_part2, content->data_length2);
375 	p += content->data_length2;
376 	memcpy(p, content->data_part3, content->data_length3);
377 
378 	// enter manual link mode
379 	for (i = 0; i < sizeof(keys) / sizeof(keys[0]) - 1; i++)
380 	{
381 		ret = send_key(handle, (uint32_t)(keys[i]));
382 		if (ret)
383 		{
384 			goto end;
385 		}
386 	}
387 	ret = send_key_noack(handle, (uint32_t)(keys[i]));
388 	if (ret)
389 	{
390 		goto end;
391 	}
392 
393 	// send backup header
394 	ret = dusb_cmd_s_rts_ns(handle, "", "!", length, 3, CA(attrs));
395 	if (ret)
396 	{
397 		goto end;
398 	}
399 	ret = dusb_cmd_r_delay_ack(handle);
400 	if (ret)
401 	{
402 		goto end;
403 	}
404 
405 	// press key to accept the backup
406 	ret = send_key_noack(handle, KEY83P_1);
407 	if (ret)
408 	{
409 		goto end;
410 	}
411 
412 	// acknowledgement of RTS
413 	ret = dusb_cmd_r_data_ack(handle);
414 	if (ret)
415 	{
416 		goto end;
417 	}
418 
419 	// send backup contents
420 	ret = dusb_cmd_s_var_content(handle, length, data);
421 	if (ret)
422 	{
423 		goto end;
424 	}
425 	ret = dusb_cmd_r_data_ack(handle);
426 	if (ret)
427 	{
428 		goto end;
429 	}
430 	ret = dusb_cmd_s_eot(handle);
431 
432  end:
433 	dusb_ca_del_array(handle, nattrs, attrs);
434 	g_free(data);
435 
436 	return ret;
437 }
438 
send_var(CalcHandle * handle,CalcMode mode,FileContent * content)439 static int		send_var	(CalcHandle* handle, CalcMode mode, FileContent* content)
440 {
441 	unsigned int i;
442 	int ret = 0;
443 
444 	for (i = 0; i < content->num_entries; i++)
445 	{
446 		DUSBCalcAttr **attrs;
447 		const int nattrs = 3;
448 		VarEntry *entry = content->entries[i];
449 		uint32_t size;
450 
451 		if (!ticalcs_validate_varentry(entry))
452 		{
453 			ticalcs_critical("%s: skipping invalid content entry #%u", __FUNCTION__, i);
454 			continue;
455 		}
456 
457 		if (entry->action == ACT_SKIP)
458 		{
459 			ticalcs_info("%s: skipping variable #%u because requested", __FUNCTION__, i);
460 			continue;
461 		}
462 
463 		ticonv_varname_to_utf8_sn(handle->model, entry->name, update_->text, sizeof(update_->text), entry->type);
464 		update_label();
465 
466 		attrs = dusb_ca_new_array(handle, nattrs);
467 		attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE, 4);
468 		attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x07;
469 		attrs[0]->data[2] = 0x00; attrs[0]->data[3] = entry->type;
470 		attrs[1] = dusb_ca_new(handle, DUSB_AID_ARCHIVED, 1);
471 		attrs[1]->data[0] = entry->attr == ATTRB_ARCHIVED ? 1 : 0;
472 		attrs[2] = dusb_ca_new(handle, DUSB_AID_VAR_VERSION, 4);
473 		attrs[2]->data[3] = entry->version;
474 
475 		size = entry->size;
476 		if (entry->size >= 65536U)
477 		{
478 			ticalcs_critical("%s: variable size %u is suspiciously large", __FUNCTION__, size);
479 		}
480 
481 		ret = dusb_cmd_s_rts(handle, "", entry->name, size, nattrs, CA(attrs));
482 		dusb_ca_del_array(handle, nattrs, attrs);
483 		if (ret)
484 		{
485 			break;
486 		}
487 		ret = dusb_cmd_r_data_ack(handle);
488 		if (ret)
489 		{
490 			break;
491 		}
492 		ret = dusb_cmd_s_var_content(handle, size, entry->data);
493 		if (ret)
494 		{
495 			break;
496 		}
497 		ret = dusb_cmd_r_data_ack(handle);
498 		if (ret)
499 		{
500 			break;
501 		}
502 		ret = dusb_cmd_s_eot(handle);
503 		if (ret)
504 		{
505 			break;
506 		}
507 
508 		update_->cnt2 = i + 1;
509 		update_->max2 = content->num_entries;
510 		update_->pbar();
511 
512 		PAUSE(50);	// needed
513 	}
514 
515 	return ret;
516 }
517 
recv_var(CalcHandle * handle,CalcMode mode,FileContent * content,VarRequest * vr)518 static int		recv_var	(CalcHandle* handle, CalcMode mode, FileContent* content, VarRequest* vr)
519 {
520 	static const uint16_t aids[] = { DUSB_AID_ARCHIVED, DUSB_AID_VAR_VERSION, DUSB_AID_VAR_SIZE };
521 	const int naids = sizeof(aids) / sizeof(uint16_t);
522 	DUSBCalcAttr **attrs;
523 	const int nattrs = 1;
524 	char fldname[40], varname[40];
525 	uint8_t *data;
526 	VarEntry *ve;
527 	int ret;
528 
529 	ticonv_varname_to_utf8_sn(handle->model, vr->name, update_->text, sizeof(update_->text), vr->type);
530 	update_label();
531 
532 	attrs = dusb_ca_new_array(handle, nattrs);
533 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
534 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x07;
535 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = vr->type;
536 
537 	ret = dusb_cmd_s_var_request(handle, "", vr->name, naids, aids, nattrs, CA(attrs));
538 	dusb_ca_del_array(handle, nattrs, attrs);
539 	if (!ret)
540 	{
541 		attrs = dusb_ca_new_array(handle, naids);
542 		ret = dusb_cmd_r_var_header(handle, fldname, varname, attrs);
543 		if (!ret)
544 		{
545 			ret = dusb_cmd_r_var_content(handle, NULL, &data);
546 			if (!ret)
547 			{
548 				content->model = handle->model;
549 				ticalcs_strlcpy(content->comment, tifiles_comment_set_single(), sizeof(content->comment));
550 				content->num_entries = 1;
551 
552 				content->entries = tifiles_ve_create_array(1);
553 				ve = content->entries[0] = tifiles_ve_create();
554 				memcpy(ve, vr, sizeof(VarEntry));
555 
556 				ve->size = (  (((uint32_t)(attrs[2]->data[0])) << 24)
557 					    | (((uint32_t)(attrs[2]->data[1])) << 16)
558 					    | (((uint32_t)(attrs[2]->data[2])) <<  8)
559 					    | (((uint32_t)(attrs[2]->data[3]))      ));
560 
561 				if (attrs[0]->size == 1)
562 				{
563 					ve->attr = (attrs[0]->data[0] ? ATTRB_ARCHIVED : 0);
564 				}
565 				if (attrs[1]->size == 4)
566 				{
567 					ve->version = attrs[1]->data[3];
568 				}
569 
570 				if (ve->type == TI83p_PIC)
571 				{
572 					if (ve->version >= 0xa)
573 					{
574 						content->model = CALC_TI84PC_USB;
575 					}
576 					else
577 					{
578 						content->model = CALC_TI84P_USB;
579 					}
580 				}
581 
582 				ve->data = tifiles_ve_alloc_data(ve->size);
583 				memcpy(ve->data, data, ve->size);
584 
585 				g_free(data);
586 			}
587 		}
588 		dusb_ca_del_array(handle, naids, attrs);
589 	}
590 
591 	return ret;
592 }
593 
send_all_vars_backup(CalcHandle * handle,FileContent * content)594 static int		send_all_vars_backup	(CalcHandle* handle, FileContent* content)
595 {
596 	return send_var(handle, MODE_BACKUP, content);
597 }
598 
send_flash(CalcHandle * handle,FlashContent * content)599 static int		send_flash	(CalcHandle* handle, FlashContent* content)
600 {
601 	FlashContent *ptr;
602 	unsigned int i;
603 	DUSBCalcAttr **attrs;
604 	const int nattrs = 2;
605 	int ret = 0;
606 
607 	uint8_t *data;
608 	uint32_t size;
609 
610 	// search for data header
611 	for (ptr = content; ptr != NULL; ptr = ptr->next)
612 	{
613 		if (ptr->data_type == TI83p_AMS || ptr->data_type == TI83p_APPL)
614 		{
615 			break;
616 		}
617 	}
618 	if (   ptr == NULL
619 	    || ptr->data_type != TI83p_APPL
620 	    || ptr->pages == NULL)
621 	{
622 		return ERR_INVALID_PARAMETER;
623 	}
624 
625 #if 0
626 	ticalcs_debug("#pages: %i", ptr->num_pages);
627 	ticalcs_debug("type: %02x", ptr->data_type);
628 	for (i = 0; i < ptr->num_pages; i++)
629 	{
630 		FlashPage *fp = ptr->pages[i];
631 
632 		ticalcs_debug("page #%i: %04x %02x %02x %04x", i, fp->addr, fp->page, fp->flag, fp->size);
633 	}
634 	ticalcs_debug("data length: %08x", ptr->data_length);
635 #endif
636 
637 	size = ptr->num_pages * FLASH_PAGE_SIZE;
638 	data = tifiles_fp_alloc_data(size);	// must be rounded-up
639 	if (data == NULL)
640 	{
641 		return ERR_MALLOC;
642 	}
643 
644 	update_->cnt2 = 0;
645 	update_->max2 = ptr->num_pages;
646 
647 	for (i = 0; i < ptr->num_pages; i++)
648 	{
649 		FlashPage *fp = ptr->pages[i];
650 		memcpy(data + i*FLASH_PAGE_SIZE, fp->data, FLASH_PAGE_SIZE);
651 
652 		update_->cnt2 = i;
653 		update_->pbar();
654 	}
655 	{
656 		FlashPage *fp = ptr->pages[--i];
657 		memset(data + i*FLASH_PAGE_SIZE + fp->size, 0x00, FLASH_PAGE_SIZE - fp->size);
658 
659 		update_->cnt2 = i;
660 		update_->pbar();
661 	}
662 
663 	// send
664 	ticonv_varname_to_utf8_sn(handle->model, ptr->name, update_->text, sizeof(update_->text), ptr->data_type);
665 	update_label();
666 
667 	attrs = dusb_ca_new_array(handle, nattrs);
668 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE, 4);
669 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x07;
670 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = ptr->data_type;
671 	attrs[1] = dusb_ca_new(handle, DUSB_AID_ARCHIVED, 1);
672 	attrs[1]->data[0] = 0;
673 
674 	ret = dusb_cmd_s_rts(handle, "", ptr->name, size, nattrs, CA(attrs));
675 	dusb_ca_del_array(handle, nattrs, attrs);
676 	if (!ret)
677 	{
678 		ret = dusb_cmd_r_data_ack(handle);
679 		if (!ret)
680 		{
681 			ret = dusb_cmd_s_var_content(handle, size, data);
682 			if (!ret)
683 			{
684 				ret = dusb_cmd_r_data_ack(handle);
685 				if (!ret)
686 				{
687 					ret = dusb_cmd_s_eot(handle);
688 				}
689 			}
690 		}
691 	}
692 
693 	g_free(data);
694 
695 	return ret;
696 }
697 
send_flash_834pce(CalcHandle * handle,FlashContent * content)698 static int		send_flash_834pce	(CalcHandle* handle, FlashContent* content)
699 {
700 	FlashContent *ptr;
701 	DUSBCalcAttr **attrs;
702 	const int nattrs = 2;
703 	int ret = 0;
704 
705 	uint8_t *data;
706 	uint32_t size;
707 
708 	// search for data header
709 	for (ptr = content; ptr != NULL; ptr = ptr->next)
710 	{
711 		if (ptr->data_type == TI83p_AMS || ptr->data_type == TI83p_APPL)
712 		{
713 			break;
714 		}
715 	}
716 	if (   ptr == NULL
717 	    || ptr->data_type != TI83p_APPL
718 	    || ptr->data_part == NULL)
719 	{
720 		return ERR_INVALID_PARAMETER;
721 	}
722 
723 	size = ptr->data_length;
724 	data = ptr->data_part;
725 
726 	update_->cnt2 = 0;
727 	update_->max2 = 0;
728 
729 	// send
730 	ticonv_varname_to_utf8_sn(handle->model, ptr->name, update_->text, sizeof(update_->text), ptr->data_type);
731 	update_label();
732 
733 	attrs = dusb_ca_new_array(handle, nattrs);
734 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE, 4);
735 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x0F;
736 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = ptr->data_type;
737 	attrs[1] = dusb_ca_new(handle, DUSB_AID_ARCHIVED, 1);
738 	attrs[1]->data[0] = 1;
739 
740 	ret = dusb_cmd_s_rts(handle, "", ptr->name, size, nattrs, CA(attrs));
741 	dusb_ca_del_array(handle, nattrs, attrs);
742 	if (!ret)
743 	{
744 		ret = dusb_cmd_r_data_ack(handle);
745 		if (!ret)
746 		{
747 			ret = dusb_cmd_s_var_content(handle, size, data);
748 			if (!ret)
749 			{
750 				ret = dusb_cmd_r_data_ack(handle);
751 				if (!ret)
752 				{
753 					ret = dusb_cmd_s_eot(handle);
754 				}
755 			}
756 		}
757 	}
758 
759 	return ret;
760 }
761 
recv_flash(CalcHandle * handle,FlashContent * content,VarRequest * vr)762 static int		recv_flash	(CalcHandle* handle, FlashContent* content, VarRequest* vr)
763 {
764 	static const uint16_t aids[] = { DUSB_AID_ARCHIVED, DUSB_AID_VAR_VERSION };
765 	const int naids = sizeof(aids) / sizeof(uint16_t);
766 	DUSBCalcAttr **attrs;
767 	const int nattrs = 1;
768 	char fldname[40], varname[40];
769 	uint8_t *data;
770 	uint32_t data_length;
771 	int page;
772 	uint16_t data_addr = 0x4000;
773 	uint16_t data_page = 0;
774 	int r, q;
775 	int ret;
776 
777 	ticonv_varname_to_utf8_sn(handle->model, vr->name, update_->text, sizeof(update_->text), vr->type);
778 	update_label();
779 
780 	attrs = dusb_ca_new_array(handle, nattrs);
781 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
782 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x07;
783 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = vr->type;
784 
785 	ret = dusb_cmd_s_var_request(handle, "", vr->name, naids, aids, nattrs, CA(attrs));
786 	dusb_ca_del_array(handle, nattrs, attrs);
787 	if (!ret)
788 	{
789 		attrs = dusb_ca_new_array(handle, naids);
790 		ret = dusb_cmd_r_var_header(handle, fldname, varname, attrs);
791 		if (!ret)
792 		{
793 			ret = dusb_cmd_r_var_content(handle, &data_length, &data);
794 			if (!ret)
795 			{
796 
797 				content->model = handle->model;
798 				ticalcs_strlcpy(content->name, vr->name, sizeof(content->name));
799 				content->data_type = vr->type;
800 				content->device_type = DEVICE_TYPE_83P;
801 
802 				q = data_length / FLASH_PAGE_SIZE;
803 				r = data_length % FLASH_PAGE_SIZE;
804 				content->num_pages = q + 1;
805 				content->pages = tifiles_fp_create_array(content->num_pages);
806 
807 				update_->cnt2 = 0;
808 				update_->max2 = q;
809 
810 				for (page = 0; page < q; page++)
811 				{
812 					FlashPage *fp = content->pages[page] = tifiles_fp_create();
813 
814 					fp->addr = data_addr;
815 					fp->page = data_page++;
816 					fp->flag = 0x80;
817 					fp->size = FLASH_PAGE_SIZE;
818 					fp->data = tifiles_fp_alloc_data(FLASH_PAGE_SIZE);
819 					memcpy(fp->data, data + FLASH_PAGE_SIZE*page, FLASH_PAGE_SIZE);
820 
821 					update_->cnt2 = page;
822 					update_->pbar();
823 				}
824 				{
825 					FlashPage *fp = content->pages[page] = tifiles_fp_create();
826 
827 					fp->addr = data_addr;
828 					fp->page = data_page++;
829 					fp->flag = 0x80;
830 					fp->size = r;
831 					fp->data = tifiles_fp_alloc_data(FLASH_PAGE_SIZE);
832 					memcpy(fp->data, data + FLASH_PAGE_SIZE*page, r);
833 
834 					update_->cnt2 = page;
835 					update_->pbar();
836 				}
837 				content->num_pages = page+1;
838 
839 				g_free(data);
840 			}
841 		}
842 		dusb_ca_del_array(handle, naids, attrs);
843 	}
844 
845 	return ret;
846 }
847 
recv_flash_834pce(CalcHandle * handle,FlashContent * content,VarRequest * vr)848 static int		recv_flash_834pce	(CalcHandle* handle, FlashContent* content, VarRequest* vr)
849 {
850 	static const uint16_t aids[] = { DUSB_AID_ARCHIVED, DUSB_AID_VAR_VERSION };
851 	const int naids = sizeof(aids) / sizeof(uint16_t);
852 	DUSBCalcAttr **attrs;
853 	const int nattrs = 1;
854 	char fldname[40], varname[40];
855 	uint8_t *data;
856 	uint32_t data_length;
857 	int ret;
858 
859 	ticonv_varname_to_utf8_sn(handle->model, vr->name, update_->text, sizeof(update_->text), vr->type);
860 	update_label();
861 
862 	attrs = dusb_ca_new_array(handle, nattrs);
863 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
864 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x0F;
865 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = vr->type;
866 
867 	ret = dusb_cmd_s_var_request(handle, "", vr->name, naids, aids, nattrs, CA(attrs));
868 	dusb_ca_del_array(handle, nattrs, attrs);
869 	if (!ret)
870 	{
871 		attrs = dusb_ca_new_array(handle, naids);
872 		ret = dusb_cmd_r_var_header(handle, fldname, varname, attrs);
873 		if (!ret)
874 		{
875 			ret = dusb_cmd_r_var_content(handle, &data_length, &data);
876 			if (!ret)
877 			{
878 
879 				content->model = handle->model;
880 				ticalcs_strlcpy(content->name, vr->name, sizeof(content->name));
881 				content->data_type = vr->type;
882 				content->device_type = DEVICE_TYPE_83P;
883 				content->data_length = data_length;
884 				content->data_part = data; // Borrow this memory block.
885 				content->hw_id = handle->calc->product_id;
886 
887 				// Do NOT g_free(data);
888 			}
889 		}
890 		dusb_ca_del_array(handle, naids, attrs);
891 	}
892 
893 	return ret;
894 }
895 
send_os(CalcHandle * handle,FlashContent * content)896 static int		send_os    (CalcHandle* handle, FlashContent* content)
897 {
898 	DUSBModeSet mode = { 2, 1, 0, 0, 0x0fa0 }; //MODE_BASIC;
899 	uint32_t pkt_size = 266;
900 	uint32_t os_size = 0;
901 	FlashContent *ptr;
902 	unsigned int i, j;
903 	int boot = 0;
904 	int ret;
905 
906 	// search for data header
907 	for (ptr = content; ptr != NULL; ptr = ptr->next)
908 	{
909 		if (ptr->data_type == TI83p_AMS || ptr->data_type == TI83p_APPL)
910 		{
911 			break;
912 		}
913 	}
914 	if (ptr == NULL)
915 	{
916 		return ERR_INVALID_PARAMETER;
917 	}
918 	if (ptr->data_type != TI83p_AMS)
919 	{
920 		return ERR_INVALID_PARAMETER;
921 	}
922 	if (ptr->pages == NULL)
923 	{
924 		return ERR_INVALID_PARAMETER;
925 	}
926 
927 #if 0
928 	ticalcs_debug("#pages: %i", ptr->num_pages);
929 	ticalcs_debug("type: %02x", ptr->data_type);
930 	for (i = 0; i < ptr->num_pages; i++)
931 	{
932 		FlashPage *fp = ptr->pages[i];
933 
934 		ticalcs_debug("page #%i: %04x %02x %02x %04x", i,
935 			fp->addr, fp->page, fp->flag, fp->size);
936 		//tifiles_hexdump(fp->data, 16);
937 	}
938 	ticalcs_debug("data length = %08x %i", ptr->data_length, ptr->data_length);
939 #endif
940 
941 	for (i = 0; i < ptr->num_pages; i++)
942 	{
943 		FlashPage *fp = ptr->pages[i];
944 
945 		if (fp->size < 256)
946 		{
947 			os_size += 4;
948 		}
949 		else
950 		{
951 			os_size += 4*(fp->size / 260);
952 		}
953 	}
954 	ticalcs_debug("os_size overhead = %i", os_size);
955 	os_size += ptr->data_length;
956 	ticalcs_debug("os_size new = %i", os_size);
957 
958 	do
959 	{
960 		static const uint16_t pids[] = { DUSB_PID_OS_MODE };
961 		const int size = sizeof(pids) / sizeof(uint16_t);
962 		DUSBCalcParam **params;
963 
964 		// switch to BASIC mode
965 		ret = dusb_cmd_s_mode_set(handle, mode);
966 		if (ret)
967 		{
968 			break;
969 		}
970 		ret = dusb_cmd_r_mode_ack(handle);
971 		if (ret)
972 		{
973 			break;
974 		}
975 
976 		// test for boot mode
977 		ret = dusb_cmd_s_param_request(handle, size, pids);
978 		if (ret)
979 		{
980 			break;
981 		}
982 		params = dusb_cp_new_array(handle, size);
983 		ret = dusb_cmd_r_param_data(handle, size, params);
984 		if (ret)
985 		{
986 			dusb_cp_del_array(handle, size, params);
987 			break;
988 		}
989 		boot = !params[0]->data[0];
990 		dusb_cp_del_array(handle, size, params);
991 
992 		// start OS transfer
993 		ret = dusb_cmd_s_os_begin(handle, os_size);
994 		if (ret)
995 		{
996 			break;
997 		}
998 		if (!boot)
999 		{
1000 			ret = dusb_recv_buf_size_request(handle, &pkt_size);
1001 			if (ret)
1002 			{
1003 				break;
1004 			}
1005 			ret = dusb_send_buf_size_alloc(handle, pkt_size);
1006 			if (ret)
1007 			{
1008 				break;
1009 			}
1010 		}
1011 		ret = dusb_cmd_r_os_ack(handle, &pkt_size);	// this pkt_size is important
1012 		if (ret)
1013 		{
1014 			break;
1015 		}
1016 
1017 		// send OS header/signature
1018 		ret = dusb_cmd_s_os_header(handle, 0x4000, 0x7A, 0x80, pkt_size-4, ptr->pages[0]->data);
1019 		if (ret)
1020 		{
1021 			break;
1022 		}
1023 		ret = dusb_cmd_r_os_ack(handle, &pkt_size);
1024 		if (ret)
1025 		{
1026 			break;
1027 		}
1028 
1029 		// send OS data
1030 		update_->cnt2 = 0;
1031 		update_->max2 = ptr->num_pages;
1032 
1033 		for (i = 0; i < ptr->num_pages; i++)
1034 		{
1035 			FlashPage *fp = ptr->pages[i];
1036 
1037 			fp->addr = 0x4000;
1038 
1039 			if (i == 0)	// need relocation
1040 			{
1041 				ret = dusb_cmd_s_os_data(handle, 0x4000, 0x7A, 0x80, pkt_size-4, fp->data);
1042 				if (ret)
1043 				{
1044 					goto end;
1045 				}
1046 				ret = dusb_cmd_r_data_ack(handle);
1047 				if (ret)
1048 				{
1049 					goto end;
1050 				}
1051 			}
1052 			else if (i == ptr->num_pages-1)	// idem
1053 			{
1054 				ret = dusb_cmd_s_os_data(handle, 0x4100, 0x7A, 0x80, pkt_size-4, fp->data);
1055 				if (ret)
1056 				{
1057 					goto end;
1058 				}
1059 				ret = dusb_cmd_r_data_ack(handle);
1060 				if (ret)
1061 				{
1062 					goto end;
1063 				}
1064 			}
1065 			else
1066 			{
1067 				for (j = 0; j < fp->size; j += 256)
1068 				{
1069 					ret = dusb_cmd_s_os_data(handle,
1070 						(uint16_t)(fp->addr + j), (uint8_t)fp->page, fp->flag,
1071 						pkt_size-4, fp->data + j);
1072 					if (ret)
1073 					{
1074 						goto end;
1075 					}
1076 					ret = dusb_cmd_r_data_ack(handle);
1077 					if (ret)
1078 					{
1079 						goto end;
1080 					}
1081 				}
1082 			}
1083 
1084 			update_->cnt2 = i;
1085 			update_->pbar();
1086 		}
1087 
1088 		ret = dusb_cmd_s_eot(handle);
1089 		if (ret)
1090 		{
1091 			break;
1092 		}
1093 		PAUSE(500);
1094 		ret = dusb_cmd_r_eot_ack(handle);
1095 	} while (0);
1096 end:
1097 
1098 	return ret;
1099 }
1100 
send_os_834pce(CalcHandle * handle,FlashContent * content)1101 static int		send_os_834pce    (CalcHandle* handle, FlashContent* content)
1102 {
1103 	DUSBModeSet mode = { 2, 1, 0, 0, 0x0fa0 }; //MODE_BASIC;
1104 	uint32_t pkt_size = 0x3ff;
1105 	uint32_t hdr_size = 0;
1106 	uint32_t hdr_offset = 0;
1107 	const uint32_t memory_offset = 0x30000U;
1108 	FlashContent *ptr;
1109 	uint8_t *d;
1110 	int i, r, q;
1111 	int ret;
1112 
1113 	// search for data header
1114 	for (ptr = content; ptr != NULL; ptr = ptr->next)
1115 	{
1116 		if (ptr->data_type == TI83p_AMS || ptr->data_type == TI83p_APPL)
1117 		{
1118 			break;
1119 		}
1120 	}
1121 	if (ptr == NULL)
1122 	{
1123 		return ERR_INVALID_PARAMETER;
1124 	}
1125 	if (ptr->data_type != TI83p_AMS)
1126 	{
1127 		return ERR_INVALID_PARAMETER;
1128 	}
1129 	if (ptr->data_part == NULL)
1130 	{
1131 		return ERR_INVALID_PARAMETER;
1132 	}
1133 
1134 	// search for OS header (offset & size)
1135 	hdr_offset = 0;
1136 	for (i = 0, d = ptr->data_part; (d[i] != 0xFF) || (d[i+1] != 0xFF) || (d[i+2] != 0xFF) || (d[i+3] != 0xFF); i++);
1137 	hdr_size = i - hdr_offset;
1138 
1139 	do
1140 	{
1141 		// switch to BASIC mode
1142 		ret = dusb_cmd_s_mode_set(handle, mode);
1143 		if (ret)
1144 		{
1145 			break;
1146 		}
1147 		ret = dusb_cmd_r_mode_ack(handle);
1148 		if (ret)
1149 		{
1150 			break;
1151 		}
1152 
1153 		// start OS transfer
1154 		ret = dusb_cmd_s_os_begin(handle, ptr->data_length);
1155 		if (ret)
1156 		{
1157 			break;
1158 		}
1159 		ret = dusb_cmd_r_os_ack(handle, &pkt_size);
1160 		if (ret)
1161 		{
1162 			break;
1163 		}
1164 
1165 		// send OS header/signature
1166 		ret = dusb_cmd_s_os_header_89(handle, hdr_size, ptr->data_part + hdr_offset);
1167 		if (ret)
1168 		{
1169 			break;
1170 		}
1171 		ret = dusb_cmd_r_os_ack(handle, &pkt_size);
1172 		if (ret)
1173 		{
1174 			break;
1175 		}
1176 
1177 		// send OS data
1178 		q = ptr->data_length / (pkt_size - 4);
1179 		r = ptr->data_length % (pkt_size - 4);
1180 
1181 		update_->cnt2 = 0;
1182 		update_->max2 = q;
1183 
1184 		for (i = 0; i < q; i++)
1185 		{
1186 			ret = dusb_cmd_s_os_data_834pce(handle, memory_offset + i*(pkt_size - 4), (pkt_size - 4), ptr->data_part + i*(pkt_size - 4));
1187 			if (ret)
1188 			{
1189 				goto end;
1190 			}
1191 			ret = dusb_cmd_r_data_ack(handle);
1192 			if (ret)
1193 			{
1194 				goto end;
1195 			}
1196 
1197 			update_->cnt2 = i;
1198 			update_->pbar();
1199 		}
1200 
1201 		ret = dusb_cmd_s_os_data_834pce(handle, memory_offset + q*(pkt_size - 4), r, ptr->data_part + i*(pkt_size - 4));
1202 		if (ret)
1203 		{
1204 			break;
1205 		}
1206 		ret = dusb_cmd_r_data_ack(handle);
1207 		if (ret)
1208 		{
1209 			break;
1210 		}
1211 
1212 		update_->cnt2 = i;
1213 		update_->pbar();
1214 
1215 		ret = dusb_cmd_s_eot(handle);
1216 		if (ret)
1217 		{
1218 			break;
1219 		}
1220 		PAUSE(500);
1221 		ret = dusb_cmd_r_eot_ack(handle);
1222 	} while (0);
1223 end:
1224 
1225 	return ret;
1226 }
1227 
recv_idlist(CalcHandle * handle,uint8_t * id)1228 static int		recv_idlist	(CalcHandle* handle, uint8_t* id)
1229 {
1230 	static const uint16_t aids[] = { DUSB_AID_ARCHIVED, DUSB_AID_VAR_VERSION };
1231 	const int naids = sizeof(aids) / sizeof(uint16_t);
1232 	DUSBCalcAttr **attrs;
1233 	const int nattrs = 1;
1234 	char folder[40], name[40];
1235 	uint8_t *data;
1236 	uint32_t i, varsize;
1237 	int ret;
1238 
1239 	ticalcs_strlcpy(update_->text, "ID-LIST", sizeof(update_->text));
1240 	update_label();
1241 
1242 	attrs = dusb_ca_new_array(handle, nattrs);
1243 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
1244 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x07;
1245 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = TI83p_IDLIST;
1246 
1247 	ret = dusb_cmd_s_var_request(handle, "", "IDList", naids, aids, nattrs, CA(attrs));
1248 	dusb_ca_del_array(handle, nattrs, attrs);
1249 	if (!ret)
1250 	{
1251 		attrs = dusb_ca_new_array(handle, naids);
1252 		ret = dusb_cmd_r_var_header(handle, folder, name, attrs);
1253 		if (!ret)
1254 		{
1255 			ret = dusb_cmd_r_var_content(handle, &varsize, &data);
1256 			if (!ret)
1257 			{
1258 				i = data[9];
1259 				data[9] = data[10];
1260 				data[10] = i;
1261 
1262 				for (i = 4; i < varsize && i < 16; i++)
1263 				{
1264 					sprintf((char *)&id[2 * (i-4)], "%02x", data[i]);
1265 				}
1266 				id[7*2] = '\0';
1267 
1268 				g_free(data);
1269 			}
1270 		}
1271 		dusb_ca_del_array(handle, naids, attrs);
1272 	}
1273 
1274 	return ret;
1275 }
1276 
1277 static int		get_version	(CalcHandle* handle, CalcInfos* infos);
1278 
dump_rom_1(CalcHandle * handle)1279 static int		dump_rom_1	(CalcHandle* handle)
1280 {
1281 	CalcInfos infos;
1282 	int ret;
1283 
1284 	ret = get_version(handle, &infos);
1285 	if (!ret)
1286 	{
1287 		PAUSE(100);
1288 		if (infos.model == CALC_TI84P_USB)
1289 		{
1290 			ret = rd_send(handle, "romdump.8Xp", romDumpSize84p, romDump84p);
1291 		}
1292 		else if (infos.model == CALC_TI84PC_USB)
1293 		{
1294 			ret = rd_send(handle, "romdump.8Xp", romDumpSize84pcu, romDump84pcu);
1295 		}
1296 		else if (infos.model == CALC_TI84PCE_USB || infos.model == CALC_TI83PCE_USB)
1297 		{
1298 			ret = rd_send(handle, "romdump.8Xp", romDumpSize834pceu, romDump834pceu);
1299 		}
1300 		else
1301 		{
1302 			ret = 0;
1303 		}
1304 	}
1305 
1306 	return ret;
1307 }
1308 
dump_rom_2(CalcHandle * handle,CalcDumpSize size,const char * filename)1309 static int		dump_rom_2	(CalcHandle* handle, CalcDumpSize size, const char *filename)
1310 {
1311 	CalcInfos infos;
1312 	int ret;
1313 
1314 	ret = get_version(handle, &infos);
1315 	if (!ret)
1316 	{
1317 		PAUSE(100);
1318 		if (infos.model == CALC_TI84PCE_USB || infos.model == CALC_TI83PCE_USB)
1319 		{
1320 			// The TI-eZ80 series does no longer provide direct remote program launch...
1321 			// Therefore, use a less sophisticated and more complicated way to queue keypresses.
1322 			unsigned int i;
1323 			unsigned int iterations;
1324 			static const uint16_t keys[] = {
1325 				0x40, 0x09, 0x09, 0xFC9C, /* Quit, Clear, Clear, Asm( */
1326 				0xDA, 0xAB, 0xA8, 0xA6,   /* prgm, R, O, M */
1327 				0x9D, 0xAE, 0xA6, 0xA9,   /* D, U, M, P */
1328 				0x86                      /* ) */
1329 			};
1330 			FILE *f;
1331 
1332 			f = fopen(filename, "wb");
1333 			if (f == NULL)
1334 			{
1335 				return ERR_OPEN_FILE;
1336 			}
1337 
1338 			// Launch program by remote control
1339 			PAUSE(200);
1340 			for (i = 0; i < sizeof(keys) / sizeof(keys[0]); i++)
1341 			{
1342 				ret = send_key(handle, (uint32_t)(keys[i]));
1343 				if (ret)
1344 				{
1345 					goto end;
1346 				}
1347 				PAUSE(100);
1348 			}
1349 
1350 			// Keep synchronized with the ROM dumper's source code, here and below. For now, it dumps 16 KB at a time.
1351 			iterations = (uint32_t)(infos.flash_phys / 0x4000);
1352 
1353 			for (i = 0; !ret && i < iterations; i++)
1354 			{
1355 				ret = dusb_cmd_s_execute(handle, "", "", DUSB_EID_KEY, "", 0x05);
1356 				if (!ret)
1357 				{
1358 					FileContent *content;
1359 					VarEntry ve;
1360 
1361 					ret = dusb_cmd_r_delay_ack(handle);
1362 					PAUSE(400);
1363 					ticables_cable_reset(handle->cable);
1364 
1365 					memset(&ve, 0, sizeof(VarEntry));
1366 					ticalcs_strlcpy(ve.name, "ROMDATA", sizeof(ve.name));
1367 					ve.type = 0x06; // PPRGM / ASM.
1368 
1369 					content = tifiles_content_create_regular(handle->model);
1370 					if (content == NULL)
1371 					{
1372 						ret = ERR_MALLOC;
1373 						break;
1374 					}
1375 
1376 					ret = is_ready(handle);
1377 					if (!ret)
1378 					{
1379 						ret = recv_var(handle, 0 /* MODE_NORMAL */, content, &ve);
1380 						PAUSE(200);
1381 						if (!ret)
1382 						{
1383 							if (content->num_entries == 1 && content->entries && content->entries[0] && content->entries[0]->size == 16386)
1384 							{
1385 								// Skip the two leading bytes.
1386 								if (fwrite(content->entries[0]->data + 2, content->entries[0]->size - 2, 1, f) < 1)
1387 								{
1388 									ret = ERR_SAVE_FILE;
1389 								}
1390 							}
1391 							else
1392 							{
1393 								ret = ERR_INVALID_PACKET;
1394 							}
1395 						}
1396 					}
1397 				}
1398 			}
1399 end:
1400 			fclose(f);
1401 
1402 		}
1403 		else
1404 		{
1405 			ret = dusb_cmd_s_execute(handle, "", "ROMDUMP", DUSB_EID_PRGM, "", 0);
1406 			if (!ret)
1407 			{
1408 				ret = dusb_cmd_r_data_ack(handle);
1409 				if (!ret)
1410 				{
1411 					PAUSE(3000);
1412 
1413 					// Get dump
1414 					ret = rd_dump(handle, filename);
1415 				}
1416 			}
1417 		}
1418 	}
1419 
1420 	return ret;
1421 }
1422 
set_clock(CalcHandle * handle,CalcClock * _clock)1423 static int		set_clock	(CalcHandle* handle, CalcClock* _clock)
1424 {
1425 	static const uint16_t pids[2] = { DUSB_PID_CLASSIC_CLK_SUPPORT, DUSB_PID_NEW_CLK_SUPPORT };
1426 	const int size = sizeof(pids) / sizeof(uint16_t);
1427 	DUSBCalcParam **params;
1428 	int ret;
1429 
1430 	// get raw clock
1431 	ticalcs_strlcpy(update_->text, _("Getting clock..."), sizeof(update_->text));
1432 	update_label();
1433 
1434 	params = dusb_cp_new_array(handle, size);
1435 	ret = dusb_cmd_s_param_request(handle, size, pids);
1436 	if (!ret)
1437 	{
1438 		ret = dusb_cmd_r_param_data(handle, size, params);
1439 		if (!ret)
1440 		{
1441 			int classic_clock = !!params[0]->ok && !!!params[1]->ok;
1442 			int new_clock = !!!params[0]->ok && !!params[1]->ok;
1443 			if (!classic_clock && !new_clock)
1444 			{
1445 				ticalcs_warning(_("Could not determine clock type: %u %u"), params[0]->ok, params[1]->ok);
1446 			}
1447 			else if (classic_clock)
1448 			{
1449 				uint32_t calc_time;
1450 				struct tm ref, cur;
1451 				time_t r, c, now;
1452 				uint8_t data[4];
1453 
1454 				ticalcs_info(_("Will set classic clock"));
1455 
1456 				time(&now);
1457 				memcpy(&ref, localtime(&now), sizeof(struct tm));
1458 
1459 				ref.tm_year = 1997 - 1900;
1460 				ref.tm_mon = 0;
1461 				ref.tm_yday = 0;
1462 				ref.tm_mday = 1;
1463 				ref.tm_wday = 3;
1464 				ref.tm_hour = 0;
1465 				ref.tm_min = 0;
1466 				ref.tm_sec = 0;
1467 				//ref.tm_isdst = 1;
1468 				r = mktime(&ref);
1469 
1470 				cur.tm_year = _clock->year - 1900;
1471 				cur.tm_mon = _clock->month - 1;
1472 				cur.tm_mday = _clock->day;
1473 				cur.tm_hour = _clock->hours;
1474 				cur.tm_min = _clock->minutes;
1475 				cur.tm_sec = _clock->seconds;
1476 				cur.tm_isdst = 1;
1477 				c = mktime(&cur);
1478 
1479 				calc_time = (uint32_t)difftime(c, r);
1480 
1481 				ticalcs_strlcpy(update_->text, _("Setting clock..."), sizeof(update_->text));
1482 				update_label();
1483 
1484 				data[0] = MSB(MSW(calc_time));
1485 				data[1] = LSB(MSW(calc_time));
1486 				data[2] = MSB(LSW(calc_time));
1487 				data[3] = LSB(LSW(calc_time));
1488 				ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_SEC_SINCE_1997, 4, data);
1489 				if (!ret)
1490 				{
1491 					data[0] = _clock->date_format == 3 ? 0 : _clock->date_format;
1492 					ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_DATE_FMT, 1, data);
1493 					if (!ret)
1494 					{
1495 						data[0] = _clock->time_format == 24 ? 1 : 0;
1496 						ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_TIME_FMT, 1, data);
1497 						if (!ret)
1498 						{
1499 							data[0] = _clock->state;
1500 							ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_ON, 1, data);
1501 						}
1502 					}
1503 				}
1504 			}
1505 			else if (new_clock)
1506 			{
1507 				uint8_t data[4];
1508 
1509 				ticalcs_info(_("Will set new clock"));
1510 
1511 				ticalcs_strlcpy(update_->text, _("Setting clock..."), sizeof(update_->text));
1512 				update_label();
1513 
1514 				data[0] = _clock->date_format == 3 ? 0 : _clock->date_format;
1515 				ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_DATE_FMT, 1, data);
1516 				if (!ret)
1517 				{
1518 					data[0] = _clock->time_format == 24 ? 0x81 : 0x80;
1519 					ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_TIME_FMT, 1, data);
1520 					if (!ret)
1521 					{
1522 						data[0] = (uint8_t)(_clock->year >> 8);
1523 						data[1] = _clock->year & 0xFF;
1524 						ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_YEAR, 2, data);
1525 						if (!ret)
1526 						{
1527 							data[0] = _clock->month;
1528 							ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_MONTH, 1, data);
1529 							if (!ret)
1530 							{
1531 								data[0] = _clock->day;
1532 								ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_DAY, 1, data);
1533 								if (!ret)
1534 								{
1535 									data[0] = _clock->hours;
1536 									ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_HOURS, 1, data);
1537 									if (!ret)
1538 									{
1539 										data[0] = _clock->minutes;
1540 										ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_MINUTES, 1, data);
1541 										if (!ret)
1542 										{
1543 											data[0] = _clock->seconds;
1544 											ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_SECONDS, 1, data);
1545 											if (!ret)
1546 											{
1547 												data[0] = _clock->state;
1548 												ret = dusb_cmd_s_param_set_r_data_ack(handle, DUSB_PID_CLK_ON, 1, data);
1549 											}
1550 										}
1551 									}
1552 								}
1553 							}
1554 						}
1555 					}
1556 				}
1557 			}
1558 			else
1559 			{
1560 				ret = ERR_INVALID_PACKET;
1561 			}
1562 		}
1563 	}
1564 	dusb_cp_del_array(handle, size, params);
1565 
1566 	return ret;
1567 }
1568 
get_clock(CalcHandle * handle,CalcClock * _clock)1569 static int		get_clock	(CalcHandle* handle, CalcClock* _clock)
1570 {
1571 	static const uint16_t pids[12] = {
1572 		DUSB_PID_CLASSIC_CLK_SUPPORT, DUSB_PID_NEW_CLK_SUPPORT,
1573 		DUSB_PID_CLK_ON, DUSB_PID_CLK_SEC_SINCE_1997, DUSB_PID_CLK_DATE_FMT, DUSB_PID_CLK_TIME_FMT,
1574 		DUSB_PID_CLK_SECONDS, DUSB_PID_CLK_MINUTES, DUSB_PID_CLK_HOURS, DUSB_PID_CLK_DAY, DUSB_PID_CLK_MONTH, DUSB_PID_CLK_YEAR
1575 	};
1576 	const int size = sizeof(pids) / sizeof(uint16_t);
1577 	DUSBCalcParam **params;
1578 	int ret;
1579 
1580 	// get raw clock
1581 	ticalcs_strlcpy(update_->text, _("Getting clock..."), sizeof(update_->text));
1582 	update_label();
1583 
1584 	params = dusb_cp_new_array(handle, size);
1585 	ret = dusb_cmd_s_param_request(handle, size, pids);
1586 	if (!ret)
1587 	{
1588 		ret = dusb_cmd_r_param_data(handle, size, params);
1589 		if (!ret)
1590 		{
1591 			int classic_clock = !!params[0]->ok && !!!params[1]->ok;
1592 			int new_clock = !!!params[0]->ok && !!params[1]->ok;
1593 			if (!classic_clock && !new_clock)
1594 			{
1595 				ticalcs_warning(_("Could not determine clock type: %u %u"), params[0]->ok, params[1]->ok);
1596 			}
1597 			else if (classic_clock)
1598 			{
1599 				if (params[2]->ok && params[3]->ok && params[4]->ok && params[5]->ok)
1600 				{
1601 					struct tm ref, *cur;
1602 					time_t r, c, now;
1603 					uint8_t * data = params[3]->data;
1604 					uint32_t calc_time = (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) | (((uint32_t)data[2]) << 8) | (data[3] << 0);
1605 
1606 					ticalcs_info(_("Found valid classic clock"));
1607 
1608 					time(&now);	// retrieve current DST setting
1609 					memcpy(&ref, localtime(&now), sizeof(struct tm));
1610 					ref.tm_year = 1997 - 1900;
1611 					ref.tm_mon = 0;
1612 					ref.tm_yday = 0;
1613 					ref.tm_mday = 1;
1614 					ref.tm_wday = 3;
1615 					ref.tm_hour = 0;
1616 					ref.tm_min = 0;
1617 					ref.tm_sec = 0;
1618 					//ref.tm_isdst = 1;
1619 					r = mktime(&ref);
1620 
1621 					c = r + calc_time;
1622 					cur = localtime(&c);
1623 
1624 					_clock->year = cur->tm_year + 1900;
1625 					_clock->month = cur->tm_mon + 1;
1626 					_clock->day = cur->tm_mday;
1627 					_clock->hours = cur->tm_hour;
1628 					_clock->minutes = cur->tm_min;
1629 					_clock->seconds = cur->tm_sec;
1630 
1631 					_clock->date_format = params[4]->data[0] == 0 ? 3 : params[4]->data[0];
1632 					_clock->time_format = params[5]->data[0] ? 24 : 12;
1633 					_clock->state = params[2]->data[0];
1634 				}
1635 				else
1636 				{
1637 					ticalcs_warning(_("Found classic clock but failed to retrieve its parameters: %u %u %u %u"),
1638 					                params[2]->ok, params[3]->ok, params[4]->ok, params[5]->ok);
1639 				}
1640 			}
1641 			else if (new_clock)
1642 			{
1643 				if (params[6]->ok && params[7]->ok && params[8]->ok && params[9]->ok && params[10]->ok && params[11]->ok)
1644 				{
1645 					uint8_t * data = params[11]->data;
1646 
1647 					ticalcs_info(_("Found valid new clock"));
1648 
1649 					_clock->year = (((uint16_t)data[0]) << 8) | (data[1] << 0);
1650 					_clock->month = params[10]->data[0];
1651 					_clock->day = params[9]->data[0];
1652 					_clock->hours = params[8]->data[0];
1653 					_clock->minutes = params[7]->data[0];
1654 					_clock->seconds = params[6]->data[0];
1655 
1656 					_clock->date_format = params[4]->data[0] == 0 ? 3 : params[4]->data[0];
1657 					_clock->time_format = params[5]->data[0] == 0x80 ? 12 : 24;
1658 					_clock->state = params[2]->data[0];
1659 				}
1660 				else
1661 				{
1662 					ticalcs_warning(_("Found new clock but failed to retrieve its parameters: %u %u %u %u %u %u"),
1663 					                params[6]->ok, params[7]->ok, params[8]->ok, params[9]->ok, params[10]->ok, params[11]->ok);
1664 				}
1665 			}
1666 			else
1667 			{
1668 				ret = ERR_INVALID_PACKET;
1669 			}
1670 		}
1671 	}
1672 	dusb_cp_del_array(handle, size, params);
1673 
1674 	return ret;
1675 }
1676 
del_var(CalcHandle * handle,VarRequest * vr)1677 static int		del_var		(CalcHandle* handle, VarRequest* vr)
1678 {
1679 	DUSBCalcAttr **attr;
1680 	const int size = 1;
1681 	char *utf8;
1682 	int ret;
1683 
1684 	utf8 = ticonv_varname_to_utf8(handle->model, vr->name, vr->type);
1685 	ticalcs_slprintf(update_->text, sizeof(update_->text), _("Deleting %s..."), utf8);
1686 	ticonv_utf8_free(utf8);
1687 	update_label();
1688 
1689 	attr = dusb_ca_new_array(handle, size);
1690 	attr[0] = dusb_ca_new(handle, 0x0011, 4);
1691 	attr[0]->data[0] = 0xF0; attr[0]->data[1] = 0x0B;
1692 	attr[0]->data[2] = 0x00; attr[0]->data[3] = vr->type;
1693 
1694 	ret = dusb_cmd_s_var_delete(handle, "", vr->name, size, CA(attr));
1695 	dusb_ca_del_array(handle, size, attr);
1696 	if (!ret)
1697 	{
1698 		ret = dusb_cmd_r_data_ack(handle);
1699 	}
1700 
1701 	return ret;
1702 }
1703 
rename_var(CalcHandle * handle,VarRequest * oldname,VarRequest * newname)1704 static int		rename_var	(CalcHandle* handle, VarRequest* oldname, VarRequest* newname)
1705 {
1706 	DUSBCalcAttr **attrs;
1707 	const int size = 1;
1708 	int ret;
1709 
1710 	attrs = dusb_ca_new_array(handle, size);
1711 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
1712 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x07;
1713 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = oldname->type;
1714 
1715 	ret = dusb_cmd_s_var_modify(handle, "", oldname->name, 1, CA(attrs), "", newname->name, 0, NULL);
1716 	dusb_ca_del_array(handle, size, attrs);
1717 	if (!ret)
1718 	{
1719 		ret = dusb_cmd_r_data_ack(handle);
1720 	}
1721 
1722 	return ret;
1723 }
1724 
change_attr(CalcHandle * handle,VarRequest * vr,FileAttr attr)1725 static int		change_attr	(CalcHandle* handle, VarRequest* vr, FileAttr attr)
1726 {
1727 	DUSBCalcAttr **srcattrs;
1728 	DUSBCalcAttr **dstattrs;
1729 	int ret;
1730 
1731 	srcattrs = dusb_ca_new_array(handle, 1);
1732 	srcattrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
1733 	srcattrs[0]->data[0] = 0xF0; srcattrs[0]->data[1] = 0x07;
1734 	srcattrs[0]->data[2] = 0x00; srcattrs[0]->data[3] = vr->type;
1735 
1736 	dstattrs = dusb_ca_new_array(handle, 1);
1737 	dstattrs[0] = dusb_ca_new(handle, DUSB_AID_ARCHIVED, 1);
1738 	/* use 0xff here rather than 0x01 to work around an OS bug */
1739 	dstattrs[0]->data[0] = (attr == ATTRB_ARCHIVED ? 0xff : 0x00);
1740 
1741 	ret = dusb_cmd_s_var_modify(handle, "", vr->name, 1, CA(srcattrs), "", vr->name, 1, CA(dstattrs));
1742 	dusb_ca_del_array(handle, 1, dstattrs);
1743 	dusb_ca_del_array(handle, 1, srcattrs);
1744 	if (!ret)
1745 	{
1746 		ret = dusb_cmd_r_data_ack(handle);
1747 	}
1748 
1749 	return ret;
1750 }
1751 
get_version(CalcHandle * handle,CalcInfos * infos)1752 static int		get_version	(CalcHandle* handle, CalcInfos* infos)
1753 {
1754 	static const uint16_t pids[] = {
1755 		DUSB_PID_OS_MODE, DUSB_PID_DEVICE_TYPE, DUSB_PID_PRODUCT_NAME, DUSB_PID_MAIN_PART_ID,
1756 		DUSB_PID_HW_VERSION, DUSB_PID_LANGUAGE_ID, DUSB_PID_SUBLANG_ID,
1757 		DUSB_PID_BOOT_BUILD_NUMBER, DUSB_PID_BOOT_VERSION, DUSB_PID_OS_BUILD_NUMBER, DUSB_PID_OS_VERSION,
1758 		DUSB_PID_PHYS_RAM, DUSB_PID_USER_RAM, DUSB_PID_FREE_RAM,
1759 		DUSB_PID_PHYS_FLASH, DUSB_PID_USER_FLASH, DUSB_PID_FREE_FLASH,
1760 		DUSB_PID_LCD_WIDTH, DUSB_PID_LCD_HEIGHT, DUSB_PID_BITS_PER_PIXEL, DUSB_PID_COLOR_AVAILABLE,
1761 		DUSB_PID_BATTERY, DUSB_PID_EXACT_MATH, DUSB_PID_CLASSIC_CLK_SUPPORT
1762 	};
1763 	const int size = sizeof(pids) / sizeof(uint16_t);
1764 	DUSBCalcParam **params;
1765 	int i = 0;
1766 	int ret;
1767 
1768 	ticalcs_strlcpy(update_->text, _("Getting version..."), sizeof(update_->text));
1769 	update_label();
1770 
1771 	memset(infos, 0, sizeof(CalcInfos));
1772 	params = dusb_cp_new_array(handle, size);
1773 
1774 	// TODO rewrite this function to ask for parameters in multiple phases, starting with 0x000A, then
1775 	// model-dependent sets of parameters. That's how TI-Connect CE 5.x does.
1776 	ret = dusb_cmd_s_param_request(handle, size, pids);
1777 	if (!ret)
1778 	{
1779 		ret = dusb_cmd_r_param_data(handle, size, params);
1780 		if (!ret)
1781 		{
1782 			uint8_t product_id = 0;
1783 			uint8_t has_boot_build_number = 0;
1784 			uint8_t has_os_build_number = 0;
1785 
1786 			if (params[i]->ok && params[i]->size == 1)
1787 			{
1788 				infos->run_level = params[i]->data[0];
1789 				infos->mask |= INFOS_RUN_LEVEL;
1790 			}
1791 			i++;
1792 
1793 			if (params[i]->ok && params[i]->size == 2)
1794 			{
1795 				infos->device_type = params[i]->data[1];
1796 				infos->mask |= INFOS_DEVICE_TYPE;
1797 			}
1798 			i++;
1799 
1800 			if (params[i]->ok)
1801 			{
1802 				ticalcs_strlcpy(infos->product_name, (char *)params[i]->data, sizeof(infos->product_name));
1803 				infos->mask |= INFOS_PRODUCT_NAME;
1804 			}
1805 			i++;
1806 
1807 			if (params[i]->ok && params[i]->size == 5)
1808 			{
1809 				product_id = params[i]->data[0];
1810 				ticalcs_slprintf(infos->main_calc_id, sizeof(infos->main_calc_id), "%02X%02X%02X%02X%02X",
1811 				                 product_id, params[i]->data[1], params[i]->data[2], params[i]->data[3], params[i]->data[4]);
1812 				infos->mask |= INFOS_MAIN_CALC_ID;
1813 				ticalcs_strlcpy(infos->product_id, infos->main_calc_id, sizeof(infos->product_id));
1814 				infos->mask |= INFOS_PRODUCT_ID;
1815 			}
1816 			i++;
1817 
1818 			if (params[i]->ok && params[i]->size == 2)
1819 			{
1820 				infos->hw_version = (((uint16_t)params[i]->data[0]) << 8) | params[i]->data[1];
1821 				infos->mask |= INFOS_HW_VERSION;
1822 			}
1823 			i++;
1824 
1825 			if (params[i]->ok && params[i]->size == 1)
1826 			{
1827 				infos->language_id = params[i]->data[0];
1828 				infos->mask |= INFOS_LANG_ID;
1829 			}
1830 			i++;
1831 
1832 			if (params[i]->ok && params[i]->size == 1)
1833 			{
1834 				infos->sub_lang_id = params[i]->data[0];
1835 				infos->mask |= INFOS_SUB_LANG_ID;
1836 			}
1837 			i++;
1838 
1839 			if (params[i]->ok && params[i]->size == 2)
1840 			{
1841 				has_boot_build_number = 1;
1842 			}
1843 			i++;
1844 
1845 			if (params[i]->ok && params[i]->size >= 3)
1846 			{
1847 				if (!has_boot_build_number)
1848 				{
1849 					ticalcs_slprintf(infos->boot_version, sizeof(infos->boot_version), "%1u.%02u", params[i]->data[1], params[i]->data[2]);
1850 					infos->mask |= INFOS_BOOT_VERSION;
1851 				}
1852 				else if (params[i]->size == 4)
1853 				{
1854 					ticalcs_slprintf(infos->boot_version, sizeof(infos->boot_version), "%1u.%1u.%1u.%04u",
1855 					                 params[i]->data[1], params[i]->data[2], params[i]->data[3],
1856 					                 (((uint16_t)(params[i - 1]->data[0])) << 8) | params[i - 1]->data[1]);
1857 					infos->mask |= INFOS_BOOT_VERSION;
1858 				}
1859 				// else do nothing.
1860 			}
1861 			i++;
1862 
1863 			if (params[i]->ok && params[i]->size == 2)
1864 			{
1865 				has_os_build_number = 1;
1866 			}
1867 			i++;
1868 
1869 			if (params[i]->ok && params[i]->size >= 3)
1870 			{
1871 				if (!has_os_build_number)
1872 				{
1873 					ticalcs_slprintf(infos->os_version, sizeof(infos->os_version), "%1u.%02u", params[i]->data[1], params[i]->data[2]);
1874 					infos->mask |= INFOS_OS_VERSION;
1875 				}
1876 				else if (params[i]->size == 4)
1877 				{
1878 					ticalcs_slprintf(infos->os_version, sizeof(infos->os_version), "%1u.%1u.%1u.%04u",
1879 					                 params[i]->data[1], params[i]->data[2], params[i]->data[3],
1880 					                 (((uint16_t)(params[i - 1]->data[0])) << 8) | params[i - 1]->data[1]);
1881 					infos->mask |= INFOS_OS_VERSION;
1882 				}
1883 				// else do nothing.
1884 			}
1885 			i++;
1886 
1887 			if (params[i]->ok && params[i]->size == 8)
1888 			{
1889 				infos->ram_phys = (  (((uint64_t)(params[i]->data[0])) << 56)
1890 				                   | (((uint64_t)(params[i]->data[1])) << 48)
1891 				                   | (((uint64_t)(params[i]->data[2])) << 40)
1892 				                   | (((uint64_t)(params[i]->data[3])) << 32)
1893 				                   | (((uint64_t)(params[i]->data[4])) << 24)
1894 				                   | (((uint64_t)(params[i]->data[5])) << 16)
1895 				                   | (((uint64_t)(params[i]->data[6])) <<  8)
1896 				                   | (((uint64_t)(params[i]->data[7]))      ));
1897 				infos->mask |= INFOS_RAM_PHYS;
1898 			}
1899 			i++;
1900 			if (params[i]->ok && params[i]->size == 8)
1901 			{
1902 				infos->ram_user = (  (((uint64_t)(params[i]->data[0])) << 56)
1903 				                   | (((uint64_t)(params[i]->data[1])) << 48)
1904 				                   | (((uint64_t)(params[i]->data[2])) << 40)
1905 				                   | (((uint64_t)(params[i]->data[3])) << 32)
1906 				                   | (((uint64_t)(params[i]->data[4])) << 24)
1907 				                   | (((uint64_t)(params[i]->data[5])) << 16)
1908 				                   | (((uint64_t)(params[i]->data[6])) <<  8)
1909 				                   | (((uint64_t)(params[i]->data[7]))      ));
1910 				infos->mask |= INFOS_RAM_USER;
1911 			}
1912 			i++;
1913 			if (params[i]->ok && params[i]->size == 8)
1914 			{
1915 				infos->ram_free = (  (((uint64_t)(params[i]->data[0])) << 56)
1916 				                   | (((uint64_t)(params[i]->data[1])) << 48)
1917 				                   | (((uint64_t)(params[i]->data[2])) << 40)
1918 				                   | (((uint64_t)(params[i]->data[3])) << 32)
1919 				                   | (((uint64_t)(params[i]->data[4])) << 24)
1920 				                   | (((uint64_t)(params[i]->data[5])) << 16)
1921 				                   | (((uint64_t)(params[i]->data[6])) <<  8)
1922 				                   | (((uint64_t)(params[i]->data[7]))      ));
1923 				infos->mask |= INFOS_RAM_FREE;
1924 			}
1925 			i++;
1926 
1927 			if (params[i]->ok && params[i]->size == 8)
1928 			{
1929 				infos->flash_phys = (  (((uint64_t)(params[i]->data[0])) << 56)
1930 				                     | (((uint64_t)(params[i]->data[1])) << 48)
1931 				                     | (((uint64_t)(params[i]->data[2])) << 40)
1932 				                     | (((uint64_t)(params[i]->data[3])) << 32)
1933 				                     | (((uint64_t)(params[i]->data[4])) << 24)
1934 				                     | (((uint64_t)(params[i]->data[5])) << 16)
1935 				                     | (((uint64_t)(params[i]->data[6])) <<  8)
1936 				                     | (((uint64_t)(params[i]->data[7]))      ));
1937 				infos->mask |= INFOS_FLASH_PHYS;
1938 			}
1939 			i++;
1940 			if (params[i]->ok && params[i]->size == 8)
1941 			{
1942 				infos->flash_user = (  (((uint64_t)(params[i]->data[0])) << 56)
1943 				                     | (((uint64_t)(params[i]->data[1])) << 48)
1944 				                     | (((uint64_t)(params[i]->data[2])) << 40)
1945 				                     | (((uint64_t)(params[i]->data[3])) << 32)
1946 				                     | (((uint64_t)(params[i]->data[4])) << 24)
1947 				                     | (((uint64_t)(params[i]->data[5])) << 16)
1948 				                     | (((uint64_t)(params[i]->data[6])) <<  8)
1949 				                     | (((uint64_t)(params[i]->data[7]))      ));
1950 				infos->mask |= INFOS_FLASH_USER;
1951 			}
1952 			i++;
1953 			if (params[i]->ok && params[i]->size == 8)
1954 			{
1955 				infos->flash_free = (  (((uint64_t)(params[i]->data[0])) << 56)
1956 				                     | (((uint64_t)(params[i]->data[1])) << 48)
1957 				                     | (((uint64_t)(params[i]->data[2])) << 40)
1958 				                     | (((uint64_t)(params[i]->data[3])) << 32)
1959 				                     | (((uint64_t)(params[i]->data[4])) << 24)
1960 				                     | (((uint64_t)(params[i]->data[5])) << 16)
1961 				                     | (((uint64_t)(params[i]->data[6])) <<  8)
1962 				                     | (((uint64_t)(params[i]->data[7]))      ));
1963 				infos->mask |= INFOS_FLASH_FREE;
1964 			}
1965 			i++;
1966 
1967 			if (params[i]->ok && params[i]->size == 2)
1968 			{
1969 				infos->lcd_width = (  (((uint16_t)(params[i]->data[ 0])) <<  8)
1970 				                    | (((uint16_t)(params[i]->data[ 1]))      ));
1971 				infos->mask |= INFOS_LCD_WIDTH;
1972 			}
1973 			i++;
1974 			if (params[i]->ok && params[i]->size == 2)
1975 			{
1976 				infos->lcd_height = (  (((uint16_t)(params[i]->data[ 0])) <<  8)
1977 				                     | (((uint16_t)(params[i]->data[ 1]))      ));
1978 				infos->mask |= INFOS_LCD_HEIGHT;
1979 			}
1980 			i++;
1981 
1982 			if (params[i]->ok && params[i]->size == 1)
1983 			{
1984 				infos->bits_per_pixel = params[i]->data[0];
1985 				infos->mask |= INFOS_BPP;
1986 			}
1987 			i++;
1988 
1989 			if (params[i]->ok && params[i]->size == 1)
1990 			{
1991 				infos->color_screen = params[i]->data[0];
1992 				infos->mask |= INFOS_COLOR_SCREEN;
1993 			}
1994 			i++;
1995 
1996 			if (params[i]->ok && params[i]->size == 1)
1997 			{
1998 				infos->battery = params[i]->data[0];
1999 				infos->mask |= INFOS_BATTERY;
2000 			}
2001 			i++;
2002 
2003 			if (params[i]->ok && params[i]->size == 1)
2004 			{
2005 				infos->exact_math = params[i]->data[0];
2006 				infos->mask |= INFOS_EXACT_MATH;
2007 			}
2008 			i++;
2009 
2010 			switch (product_id)
2011 			{
2012 				case PRODUCT_ID_TI84P:
2013 				{
2014 					infos->model = CALC_TI84P_USB;
2015 					if (infos->hw_version >= 4)
2016 					{
2017 						ticalcs_warning(_("Unhandled 84+ family member with product_id=%d hw_version=%d"), product_id, infos->hw_version);
2018 					}
2019 					break;
2020 				}
2021 				case PRODUCT_ID_TI82A:
2022 				{
2023 					infos->model = CALC_TI82A_USB;
2024 					if (infos->hw_version >= 4)
2025 					{
2026 						ticalcs_warning(_("Unhandled 84+ family member with product_id=%d hw_version=%d"), product_id, infos->hw_version);
2027 					}
2028 					break;
2029 				}
2030 				case PRODUCT_ID_TI84PCSE:
2031 				{
2032 					infos->model = CALC_TI84PC_USB;
2033 					if (infos->hw_version < 4)
2034 					{
2035 						ticalcs_warning(_("Unhandled 84+ family member with product_id=%d hw_version=%d"), product_id, infos->hw_version);
2036 					}
2037 					break;
2038 				}
2039 				case PRODUCT_ID_TI83PCE: // and case PRODUCT_ID_TI84PCE:
2040 				{
2041 					if (infos->exact_math)
2042 					{
2043 						infos->model = CALC_TI83PCE_USB;
2044 					}
2045 					else
2046 					{
2047 						infos->model = CALC_TI84PCE_USB;
2048 					}
2049 					if (infos->hw_version < 6)
2050 					{
2051 						ticalcs_warning(_("Unhandled 84+ family member with product_id=%d hw_version=%d"), product_id, infos->hw_version);
2052 					}
2053 					break;
2054 				}
2055 				default:
2056 				{
2057 					// Default to generic 84+(SE).
2058 					infos->model = CALC_TI84P_USB;
2059 					ticalcs_warning(_("Unhandled 84+ family member with product_id=%d hw_version=%d"), product_id, infos->hw_version);
2060 					break;
2061 				}
2062 			}
2063 			infos->mask |= INFOS_CALC_MODEL;
2064 		}
2065 	}
2066 	dusb_cp_del_array(handle, size, params);
2067 
2068 	return ret;
2069 }
2070 
2071 const CalcFncts calc_84p_usb =
2072 {
2073 	CALC_TI84P_USB,
2074 	"TI84+",
2075 	"TI-84 Plus",
2076 	N_("TI-84 Plus thru DirectLink"),
2077 	OPS_ISREADY | OPS_SCREEN | OPS_DIRLIST | OPS_VARS | OPS_FLASH | OPS_OS |
2078 	OPS_IDLIST | OPS_ROMDUMP | OPS_CLOCK | OPS_DELVAR | OPS_VERSION | OPS_BACKUP | OPS_KEYS |
2079 	OPS_RENAME | OPS_CHATTR |
2080 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH,
2081 	PRODUCT_ID_TI84P,
2082 	{"",     /* is_ready */
2083 	 "",     /* send_key */
2084 	 "",     /* execute */
2085 	 "1P",   /* recv_screen */
2086 	 "1L",   /* get_dirlist */
2087 	 "",     /* get_memfree */
2088 	 "1P",   /* send_backup */
2089 	 "",     /* recv_backup */
2090 	 "2P1L", /* send_var */
2091 	 "1P1L", /* recv_var */
2092 	 "",     /* send_var_ns */
2093 	 "",     /* recv_var_ns */
2094 	 "2P1L", /* send_app */
2095 	 "2P1L", /* recv_app */
2096 	 "2P",   /* send_os */
2097 	 "1L",   /* recv_idlist */
2098 	 "2P",   /* dump_rom_1 */
2099 	 "2P",   /* dump_rom_2 */
2100 	 "",     /* set_clock */
2101 	 "",     /* get_clock */
2102 	 "1L",   /* del_var */
2103 	 "1L",   /* new_folder */
2104 	 "",     /* get_version */
2105 	 "1L",   /* send_cert */
2106 	 "1L",   /* recv_cert */
2107 	 "",     /* rename */
2108 	 "",     /* chattr */
2109 	 "2P",   /* send_all_vars_backup */
2110 	 "2P",   /* recv_all_vars_backup */ },
2111 	&is_ready,
2112 	&send_key,
2113 	&execute,
2114 	&recv_screen,
2115 	&get_dirlist,
2116 	&get_memfree,
2117 	&send_backup,
2118 	&noop_recv_backup,
2119 	&send_var,
2120 	&recv_var,
2121 	&noop_send_var_ns,
2122 	&noop_recv_var_ns,
2123 	&send_flash,
2124 	&recv_flash,
2125 	&send_os,
2126 	&recv_idlist,
2127 	&dump_rom_1,
2128 	&dump_rom_2,
2129 	&set_clock,
2130 	&get_clock,
2131 	&del_var,
2132 	&noop_new_folder,
2133 	&get_version,
2134 	&noop_send_cert,
2135 	&noop_recv_cert,
2136 	&rename_var,
2137 	&change_attr,
2138 	&send_all_vars_backup,
2139 	&tixx_recv_all_vars_backup
2140 };
2141 
2142 const CalcFncts calc_84pcse_usb =
2143 {
2144 	CALC_TI84PC_USB,
2145 	"TI84+CSE",
2146 	"TI-84 Plus C Silver Edition",
2147 	N_("TI-84 Plus C Silver Edition thru DirectLink"),
2148 	OPS_ISREADY | OPS_SCREEN | OPS_DIRLIST | OPS_VARS | OPS_FLASH | OPS_OS |
2149 	OPS_IDLIST | OPS_ROMDUMP | OPS_CLOCK | OPS_DELVAR | OPS_VERSION | OPS_BACKUP | OPS_KEYS |
2150 	OPS_RENAME | OPS_CHATTR |
2151 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH,
2152 	PRODUCT_ID_TI84PCSE,
2153 	{"",     /* is_ready */
2154 	 "",     /* send_key */
2155 	 "",     /* execute */
2156 	 "1P",   /* recv_screen */
2157 	 "1L",   /* get_dirlist */
2158 	 "",     /* get_memfree */
2159 	 "1P",   /* send_backup */
2160 	 "",     /* recv_backup */
2161 	 "2P1L", /* send_var */
2162 	 "1P1L", /* recv_var */
2163 	 "",     /* send_var_ns */
2164 	 "",     /* recv_var_ns */
2165 	 "2P1L", /* send_app */
2166 	 "2P1L", /* recv_app */
2167 	 "2P",   /* send_os */
2168 	 "1L",   /* recv_idlist */
2169 	 "2P",   /* dump_rom_1 */
2170 	 "2P",   /* dump_rom_2 */
2171 	 "",     /* set_clock */
2172 	 "",     /* get_clock */
2173 	 "1L",   /* del_var */
2174 	 "1L",   /* new_folder */
2175 	 "",     /* get_version */
2176 	 "1L",   /* send_cert */
2177 	 "1L",   /* recv_cert */
2178 	 "",     /* rename */
2179 	 "",     /* chattr */
2180 	 "2P",   /* send_all_vars_backup */
2181 	 "2P",   /* recv_all_vars_backup */ },
2182 	&is_ready,
2183 	&send_key,
2184 	&execute,
2185 	&recv_screen,
2186 	&get_dirlist,
2187 	&get_memfree,
2188 	&send_backup,
2189 	&noop_recv_backup,
2190 	&send_var,
2191 	&recv_var,
2192 	&noop_send_var_ns,
2193 	&noop_recv_var_ns,
2194 	&send_flash,
2195 	&recv_flash,
2196 	&send_os,
2197 	&recv_idlist,
2198 	&dump_rom_1,
2199 	&dump_rom_2,
2200 	&set_clock,
2201 	&get_clock,
2202 	&del_var,
2203 	&noop_new_folder,
2204 	&get_version,
2205 	&noop_send_cert,
2206 	&noop_recv_cert,
2207 	&rename_var,
2208 	&change_attr,
2209 	&send_all_vars_backup,
2210 	&tixx_recv_all_vars_backup
2211 };
2212 
2213 const CalcFncts calc_83pce_usb =
2214 {
2215 	CALC_TI83PCE_USB,
2216 	"TI83PCE",
2217 	"TI-83 Premium CE",
2218 	N_("TI-83 Premium CE thru DirectLink"),
2219 	OPS_ISREADY | OPS_SCREEN | OPS_DIRLIST | OPS_VARS | OPS_FLASH | OPS_OS |
2220 	/*OPS_IDLIST |*/ OPS_ROMDUMP | OPS_CLOCK | OPS_DELVAR | OPS_VERSION | OPS_BACKUP | OPS_KEYS |
2221 	OPS_RENAME | OPS_CHATTR |
2222 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH,
2223 	PRODUCT_ID_TI83PCE,
2224 	{"",     /* is_ready */
2225 	 "",     /* send_key */
2226 	 "",     /* execute */
2227 	 "1P",   /* recv_screen */
2228 	 "1L",   /* get_dirlist */
2229 	 "",     /* get_memfree */
2230 	 "",     /* send_backup */
2231 	 "",     /* recv_backup */
2232 	 "2P1L", /* send_var */
2233 	 "1P1L", /* recv_var */
2234 	 "",     /* send_var_ns */
2235 	 "",     /* recv_var_ns */
2236 	 "2P1L", /* send_app */
2237 	 "2P1L", /* recv_app */
2238 	 "2P",   /* send_os */
2239 	 "1L",   /* recv_idlist */
2240 	 "2P",   /* dump_rom_1 */
2241 	 "2P",   /* dump_rom_2 */
2242 	 "",     /* set_clock */
2243 	 "",     /* get_clock */
2244 	 "1L",   /* del_var */
2245 	 "1L",   /* new_folder */
2246 	 "",     /* get_version */
2247 	 "1L",   /* send_cert */
2248 	 "1L",   /* recv_cert */
2249 	 "",     /* rename */
2250 	 "",     /* chattr */
2251 	 "2P",   /* send_all_vars_backup */
2252 	 "2P",   /* recv_all_vars_backup */ },
2253 	&is_ready,
2254 	&send_key,
2255 	&execute,
2256 	&recv_screen,
2257 	&get_dirlist,
2258 	&get_memfree,
2259 	&noop_send_backup,
2260 	&noop_recv_backup,
2261 	&send_var,
2262 	&recv_var,
2263 	&noop_send_var_ns,
2264 	&noop_recv_var_ns,
2265 	&send_flash_834pce,
2266 	&recv_flash_834pce,
2267 	&send_os_834pce,
2268 	&recv_idlist,
2269 	&dump_rom_1,
2270 	&dump_rom_2,
2271 	&set_clock,
2272 	&get_clock,
2273 	&del_var,
2274 	&noop_new_folder,
2275 	&get_version,
2276 	&noop_send_cert,
2277 	&noop_recv_cert,
2278 	&rename_var,
2279 	&change_attr,
2280 	&send_all_vars_backup,
2281 	&tixx_recv_all_vars_backup
2282 };
2283 
2284 const CalcFncts calc_84pce_usb =
2285 {
2286 	CALC_TI84PCE_USB,
2287 	"TI84+CE",
2288 	"TI-84 Plus CE",
2289 	N_("TI-84 Plus CE thru DirectLink"),
2290 	OPS_ISREADY | OPS_SCREEN | OPS_DIRLIST | OPS_VARS | OPS_FLASH | OPS_OS |
2291 	/*OPS_IDLIST |*/ OPS_ROMDUMP | OPS_CLOCK | OPS_DELVAR | OPS_VERSION | OPS_BACKUP | OPS_KEYS |
2292 	OPS_RENAME | OPS_CHATTR |
2293 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH,
2294 	PRODUCT_ID_TI84PCE,
2295 	{"",     /* is_ready */
2296 	 "",     /* send_key */
2297 	 "",     /* execute */
2298 	 "1P",   /* recv_screen */
2299 	 "1L",   /* get_dirlist */
2300 	 "",     /* get_memfree */
2301 	 "",     /* send_backup */
2302 	 "",     /* recv_backup */
2303 	 "2P1L", /* send_var */
2304 	 "1P1L", /* recv_var */
2305 	 "",     /* send_var_ns */
2306 	 "",     /* recv_var_ns */
2307 	 "2P1L", /* send_app */
2308 	 "2P1L", /* recv_app */
2309 	 "2P",   /* send_os */
2310 	 "1L",   /* recv_idlist */
2311 	 "2P",   /* dump_rom_1 */
2312 	 "2P",   /* dump_rom_2 */
2313 	 "",     /* set_clock */
2314 	 "",     /* get_clock */
2315 	 "1L",   /* del_var */
2316 	 "1L",   /* new_folder */
2317 	 "",     /* get_version */
2318 	 "1L",   /* send_cert */
2319 	 "1L",   /* recv_cert */
2320 	 "",     /* rename */
2321 	 "",     /* chattr */
2322 	 "2P",   /* send_all_vars_backup */
2323 	 "2P",   /* recv_all_vars_backup */ },
2324 	&is_ready,
2325 	&send_key,
2326 	&execute,
2327 	&recv_screen,
2328 	&get_dirlist,
2329 	&get_memfree,
2330 	&noop_send_backup,
2331 	&noop_recv_backup,
2332 	&send_var,
2333 	&recv_var,
2334 	&noop_send_var_ns,
2335 	&noop_recv_var_ns,
2336 	&send_flash_834pce,
2337 	&recv_flash_834pce,
2338 	&send_os_834pce,
2339 	&recv_idlist,
2340 	&dump_rom_1,
2341 	&dump_rom_2,
2342 	&set_clock,
2343 	&get_clock,
2344 	&del_var,
2345 	&noop_new_folder,
2346 	&get_version,
2347 	&noop_send_cert,
2348 	&noop_recv_cert,
2349 	&rename_var,
2350 	&change_attr,
2351 	&send_all_vars_backup,
2352 	&tixx_recv_all_vars_backup
2353 };
2354 
2355 const CalcFncts calc_82a_usb =
2356 {
2357 	CALC_TI82A_USB,
2358 	"TI82A",
2359 	"TI-82 Advanced",
2360 	N_("TI-82 Advanced thru DirectLink"),
2361 	OPS_ISREADY | OPS_SCREEN | OPS_DIRLIST | OPS_VARS | /*OPS_FLASH |*/ OPS_OS |
2362 	OPS_IDLIST | /*OPS_ROMDUMP |*/ OPS_CLOCK | OPS_DELVAR | OPS_VERSION | OPS_BACKUP | OPS_KEYS |
2363 	OPS_RENAME | OPS_CHATTR |
2364 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH,
2365 	PRODUCT_ID_TI82A,
2366 	{"",     /* is_ready */
2367 	 "",     /* send_key */
2368 	 "",     /* execute */
2369 	 "1P",   /* recv_screen */
2370 	 "1L",   /* get_dirlist */
2371 	 "",     /* get_memfree */
2372 	 "1P",   /* send_backup */
2373 	 "",     /* recv_backup */
2374 	 "2P1L", /* send_var */
2375 	 "1P1L", /* recv_var */
2376 	 "",     /* send_var_ns */
2377 	 "",     /* recv_var_ns */
2378 	 "2P1L", /* send_app */
2379 	 "2P1L", /* recv_app */
2380 	 "2P",   /* send_os */
2381 	 "1L",   /* recv_idlist */
2382 	 "2P",   /* dump_rom_1 */
2383 	 "2P",   /* dump_rom_2 */
2384 	 "",     /* set_clock */
2385 	 "",     /* get_clock */
2386 	 "1L",   /* del_var */
2387 	 "1L",   /* new_folder */
2388 	 "",     /* get_version */
2389 	 "1L",   /* send_cert */
2390 	 "1L",   /* recv_cert */
2391 	 "",     /* rename */
2392 	 "",     /* chattr */
2393 	 "2P",   /* send_all_vars_backup */
2394 	 "2P",   /* recv_all_vars_backup */ },
2395 	&is_ready,
2396 	&send_key,
2397 	&execute,
2398 	&recv_screen,
2399 	&get_dirlist,
2400 	&get_memfree,
2401 	&send_backup,
2402 	&noop_recv_backup,
2403 	&send_var,
2404 	&recv_var,
2405 	&noop_send_var_ns,
2406 	&noop_recv_var_ns,
2407 	&send_flash,
2408 	&recv_flash,
2409 	&send_os,
2410 	&recv_idlist,
2411 	&dump_rom_1,
2412 	&dump_rom_2,
2413 	&set_clock,
2414 	&get_clock,
2415 	&del_var,
2416 	&noop_new_folder,
2417 	&get_version,
2418 	&noop_send_cert,
2419 	&noop_recv_cert,
2420 	&rename_var,
2421 	&change_attr,
2422 	&send_all_vars_backup,
2423 	&tixx_recv_all_vars_backup
2424 };
2425 
2426 const CalcFncts calc_84pt_usb =
2427 {
2428 	CALC_TI84PT_USB,
2429 	"TI84PT",
2430 	"TI-84 Plus T",
2431 	N_("TI-84 Plus T thru DirectLink"),
2432 	OPS_ISREADY | OPS_SCREEN | OPS_DIRLIST | OPS_VARS | /*OPS_FLASH |*/ OPS_OS |
2433 	OPS_IDLIST | /*OPS_ROMDUMP |*/ OPS_CLOCK | OPS_DELVAR | OPS_VERSION | OPS_BACKUP | OPS_KEYS |
2434 	OPS_RENAME | OPS_CHATTR |
2435 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH,
2436 	PRODUCT_ID_TI84PT,
2437 	{"",     /* is_ready */
2438 	 "",     /* send_key */
2439 	 "",     /* execute */
2440 	 "1P",   /* recv_screen */
2441 	 "1L",   /* get_dirlist */
2442 	 "",     /* get_memfree */
2443 	 "1P",   /* send_backup */
2444 	 "",     /* recv_backup */
2445 	 "2P1L", /* send_var */
2446 	 "1P1L", /* recv_var */
2447 	 "",     /* send_var_ns */
2448 	 "",     /* recv_var_ns */
2449 	 "2P1L", /* send_app */
2450 	 "2P1L", /* recv_app */
2451 	 "2P",   /* send_os */
2452 	 "1L",   /* recv_idlist */
2453 	 "2P",   /* dump_rom_1 */
2454 	 "2P",   /* dump_rom_2 */
2455 	 "",     /* set_clock */
2456 	 "",     /* get_clock */
2457 	 "1L",   /* del_var */
2458 	 "1L",   /* new_folder */
2459 	 "",     /* get_version */
2460 	 "1L",   /* send_cert */
2461 	 "1L",   /* recv_cert */
2462 	 "",     /* rename */
2463 	 "",     /* chattr */
2464 	 "2P",   /* send_all_vars_backup */
2465 	 "2P",   /* recv_all_vars_backup */ },
2466 	&is_ready,
2467 	&send_key,
2468 	&execute,
2469 	&recv_screen,
2470 	&get_dirlist,
2471 	&get_memfree,
2472 	&send_backup,
2473 	&noop_recv_backup,
2474 	&send_var,
2475 	&recv_var,
2476 	&noop_send_var_ns,
2477 	&noop_recv_var_ns,
2478 	&send_flash,
2479 	&recv_flash,
2480 	&send_os,
2481 	&recv_idlist,
2482 	&dump_rom_1,
2483 	&dump_rom_2,
2484 	&set_clock,
2485 	&get_clock,
2486 	&del_var,
2487 	&noop_new_folder,
2488 	&get_version,
2489 	&noop_send_cert,
2490 	&noop_recv_cert,
2491 	&rename_var,
2492 	&change_attr,
2493 	&send_all_vars_backup,
2494 	&tixx_recv_all_vars_backup
2495 };
2496