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) 2006  Kevin Kofler
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 	TI89 Titanium 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 
45 #include "rom89t.h"
46 #include "romdump.h"
47 #include "keys89.h"
48 
49 // Screen coordinates of the Titanium
50 #define TI89T_ROWS			128
51 #define TI89T_COLS			240
52 #define TI89T_ROWS_VISIBLE	100
53 #define TI89T_COLS_VISIBLE	160
54 
is_ready(CalcHandle * handle)55 static int		is_ready	(CalcHandle* handle)
56 {
57 	int ret;
58 	static const DUSBModeSet mode = DUSB_MODE_NORMAL;
59 
60 	ret = dusb_cmd_s_mode_set(handle, mode);
61 	if (!ret)
62 	{
63 		ret = dusb_cmd_r_mode_ack(handle);
64 	}
65 
66 	return ret;
67 }
68 
send_key(CalcHandle * handle,uint32_t key)69 static int		send_key	(CalcHandle* handle, uint32_t key)
70 {
71 	int ret;
72 
73 	PAUSE(25);	// this pause is needed between 2 keys
74 	ret = dusb_cmd_s_execute(handle, "", "", DUSB_EID_KEY, "", (uint16_t)key);
75 	if (!ret)
76 	{
77 		ret = dusb_cmd_r_data_ack(handle);
78 	}
79 
80 	return ret;
81 }
82 
execute(CalcHandle * handle,VarEntry * ve,const char * args)83 static int		execute		(CalcHandle* handle, VarEntry *ve, const char *args)
84 {
85 	uint8_t action;
86 	int ret;
87 
88 	switch (ve->type)
89 	{
90 		case TI89t_ASM:  action = DUSB_EID_ASM; break;
91 		case TI89t_APPL: action = DUSB_EID_APP; break;
92 		default:         action = DUSB_EID_PRGM; break;
93 	}
94 
95 	ret = dusb_cmd_s_execute(handle, ve->folder, ve->name, action, args, 0);
96 	if (!ret)
97 	{
98 		ret = dusb_cmd_r_data_ack(handle);
99 	}
100 
101 	return ret;
102 }
103 
recv_screen(CalcHandle * handle,CalcScreenCoord * sc,uint8_t ** bitmap)104 static int		recv_screen	(CalcHandle* handle, CalcScreenCoord* sc, uint8_t** bitmap)
105 {
106 	static const uint16_t pid[] = { DUSB_PID_SCREENSHOT };
107 	const int size = 1;
108 	DUSBCalcParam **param;
109 	int ret;
110 
111 	*bitmap = (uint8_t *)ticalcs_alloc_screen(TI89T_COLS * TI89T_ROWS / 8);
112 	if (*bitmap == NULL)
113 	{
114 		return ERR_MALLOC;
115 	}
116 
117 	sc->width = TI89T_COLS;
118 	sc->height = TI89T_ROWS;
119 	sc->clipped_width = TI89T_COLS_VISIBLE;
120 	sc->clipped_height = TI89T_ROWS_VISIBLE;
121 	sc->pixel_format = CALC_PIXFMT_MONO;
122 
123 	param = dusb_cp_new_array(handle, size);
124 	ret = dusb_cmd_s_param_request(handle, size, pid);
125 	while (!ret)
126 	{
127 		ret = dusb_cmd_r_param_data(handle, size, param);
128 		if (!ret)
129 		{
130 			if (!param[0]->ok || param[0]->size != TI89T_COLS * TI89T_ROWS / 8)
131 			{
132 				ticalcs_free_screen(*bitmap);
133 				ret = ERR_INVALID_PACKET;
134 				break;
135 			}
136 
137 			memcpy(*bitmap, param[0]->data, TI89T_COLS * TI89T_ROWS / 8);
138 
139 			// Clip the unused part of the screen (nevertheless usable with asm programs)
140 			if (sc->format == SCREEN_CLIPPED)
141 			{
142 				int i, j, k;
143 
144 				for (i = 0, j = 0; j < TI89T_ROWS_VISIBLE; j++)
145 				{
146 					for (k = 0; k < (TI89T_COLS_VISIBLE >> 3); k++)
147 					{
148 						(*bitmap)[i++] = (*bitmap)[j * (TI89T_COLS >> 3) + k];
149 					}
150 				}
151 			}
152 		}
153 		break;
154 	}
155 	dusb_cp_del_array(handle, size, param);
156 
157 	return ret;
158 }
159 
get_dirlist(CalcHandle * handle,GNode ** vars,GNode ** apps)160 static int		get_dirlist	(CalcHandle* handle, GNode** vars, GNode** apps)
161 {
162 	static const uint16_t aids[] = { DUSB_AID_VAR_TYPE, DUSB_AID_ARCHIVED, DUSB_AID_4APPVAR, DUSB_AID_VAR_SIZE, DUSB_AID_LOCKED, DUSB_AID_UNKNOWN_42 };
163 	const int size = sizeof(aids) / sizeof(uint16_t);
164 	int ret;
165 	DUSBCalcAttr **attr;
166 	GNode *root, *folder = NULL;
167 	char fldname[40];
168 	char varname[40];
169 	char folder_name[40] = "";
170 	char *u1, *u2;
171 
172 	ret = dirlist_init_trees(handle, vars, apps);
173 	if (ret)
174 	{
175 		return ret;
176 	}
177 
178 	root = dirlist_create_append_node(NULL, apps);
179 	if (!root)
180 	{
181 		return ERR_MALLOC;
182 	}
183 
184 	ret = dusb_cmd_s_dirlist_request(handle, size, aids);
185 	if (!ret)
186 	{
187 		for (;;)
188 		{
189 			VarEntry *ve;
190 			GNode *node;
191 
192 			attr = dusb_ca_new_array(handle, size);
193 			ret = dusb_cmd_r_var_header(handle, fldname, varname, attr);
194 			if (ret)
195 			{
196 				// Not a real error.
197 				if (ret == ERR_EOT)
198 				{
199 					ret = 0;
200 				}
201 				dusb_ca_del_array(handle, size, attr);
202 				break;
203 			}
204 
205 			ve = tifiles_ve_create();
206 			ticalcs_strlcpy(ve->folder, fldname, sizeof(ve->folder));
207 			ticalcs_strlcpy(ve->name, varname, sizeof(ve->name));
208 			ve->size = (  (((uint32_t)(attr[3]->data[0])) << 24)
209 				    | (((uint32_t)(attr[3]->data[1])) << 16)
210 				    | (((uint32_t)(attr[3]->data[2])) <<  8)
211 				    | (((uint32_t)(attr[3]->data[3]))      ));
212 			ve->type = (uint32_t)(attr[0]->data[3]);
213 			ve->attr = attr[1]->data[0] ? ATTRB_ARCHIVED : attr[4]->data[0] ? ATTRB_LOCKED : ATTRB_NONE;
214 			dusb_ca_del_array(handle, size, attr);
215 
216 			if (ve->type == TI89_DIR)
217 			{
218 				ticalcs_strlcpy(folder_name, ve->folder, sizeof(folder_name));
219 				ticalcs_strlcpy(ve->name, ve->folder, sizeof(ve->name));
220 				ve->folder[0] = 0;
221 
222 				folder = dirlist_create_append_node(ve, vars);
223 			}
224 			else
225 			{
226 				if (!strcmp(ve->folder, "main") && (!strcmp(ve->name, "regcoef") || !strcmp(ve->name, "regeq")))
227 				{
228 					tifiles_ve_delete(ve);
229 				}
230 				else
231 				{
232 					node = dirlist_create_append_node(ve, (ve->type != TI89_APPL) ? &folder : &root);
233 					if (!node)
234 					{
235 						ret = ERR_MALLOC;
236 						break;
237 					}
238 				}
239 			}
240 	/*
241 			ticalcs_info(_("Name: %8s | Type: %8s | Attr: %i  | Size: %08X"),
242 				ve->name,
243 				tifiles_vartype2string(handle->model, ve->type),
244 				ve->attr,
245 				ve->size);
246 	*/
247 			u1 = ticonv_varname_to_utf8(handle->model, ((VarEntry *) (folder->data))->name, -1);
248 			u2 = ticonv_varname_to_utf8(handle->model, ve->name, ve->type);
249 			ticalcs_slprintf(update_->text, sizeof(update_->text), _("Parsing %s/%s"), u1, u2);
250 			ticonv_utf8_free(u2);
251 			ticonv_utf8_free(u1);
252 			update_label();
253 		}
254 	}
255 
256 	return ret;
257 }
258 
get_memfree(CalcHandle * handle,uint32_t * ram,uint32_t * flash)259 static int		get_memfree	(CalcHandle* handle, uint32_t* ram, uint32_t* flash)
260 {
261 	static const uint16_t pids[] = { DUSB_PID_FREE_RAM, DUSB_PID_FREE_FLASH };
262 	const int size = sizeof(pids) / sizeof(uint16_t);
263 	DUSBCalcParam **params;
264 	int ret;
265 
266 	params = dusb_cp_new_array(handle, size);
267 	if (params != NULL)
268 	{
269 		ret = dusb_cmd_s_param_request(handle, size, pids);
270 		if (!ret)
271 		{
272 			ret = dusb_cmd_r_param_data(handle, size, params);
273 			if (!ret)
274 			{
275 				if (params[0]->ok && params[0]->size == 8 && params[1]->ok && params[1]->size == 8)
276 				{
277 					*ram = (  (((uint32_t)(params[0]->data[4])) << 24)
278 						| (((uint32_t)(params[0]->data[5])) << 16)
279 						| (((uint32_t)(params[0]->data[6])) <<  8)
280 						| (((uint32_t)(params[0]->data[7]))      ));
281 					*flash = (  (((uint32_t)(params[1]->data[4])) << 24)
282 						  | (((uint32_t)(params[1]->data[5])) << 16)
283 						  | (((uint32_t)(params[1]->data[6])) <<  8)
284 						  | (((uint32_t)(params[1]->data[7]))      ));
285 				}
286 				else
287 				{
288 					ret = ERR_INVALID_PACKET;
289 				}
290 			}
291 		}
292 	}
293 	else
294 	{
295 		ret = ERR_MALLOC;
296 	}
297 	dusb_cp_del_array(handle, size, params);
298 
299 	return ret;
300 }
301 
send_var(CalcHandle * handle,CalcMode mode,FileContent * content)302 static int		send_var	(CalcHandle* handle, CalcMode mode, FileContent* content)
303 {
304 	unsigned int i;
305 	int ret = 0;
306 
307 	update_->cnt2 = 0;
308 	update_->max2 = content->num_entries;
309 
310 	for (i = 0; i < content->num_entries; i++)
311 	{
312 		DUSBCalcAttr **attrs;
313 		const int nattrs = 4;
314 		VarEntry * entry = content->entries[i];
315 		uint32_t pkt_size;
316 		uint32_t size;
317 		char varname[18];
318 
319 		if (!ticalcs_validate_varentry(entry))
320 		{
321 			ticalcs_critical("%s: skipping invalid content entry #%u", __FUNCTION__, i);
322 			continue;
323 		}
324 
325 		if (entry->action == ACT_SKIP)
326 		{
327 			ticalcs_info("%s: skipping variable #%u because requested", __FUNCTION__, i);
328 			continue;
329 		}
330 
331 		if (entry->folder[0])
332 		{
333 			tifiles_build_fullname(handle->model, varname, entry->folder, entry->name);
334 		}
335 		else
336 		{
337 			ticalcs_strlcpy(varname, entry->name, sizeof(varname));
338 		}
339 
340 		ticonv_varname_to_utf8_sn(handle->model, varname, update_->text, sizeof(update_->text), entry->type);
341 		update_label();
342 
343 		attrs = dusb_ca_new_array(handle, nattrs);
344 		attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE, 4);
345 		attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x0C;
346 		attrs[0]->data[2] = 0x00; attrs[0]->data[3] = entry->type;
347 		attrs[1] = dusb_ca_new(handle, DUSB_AID_ARCHIVED, 1);
348 		attrs[1]->data[0] = entry->attr == ATTRB_ARCHIVED ? 1 : 0;
349 		attrs[2] = dusb_ca_new(handle, DUSB_AID_VAR_VERSION, 4);
350 		attrs[2]->data[0] = 0;
351 		attrs[3] = dusb_ca_new(handle, DUSB_AID_LOCKED, 1);
352 		attrs[3]->data[0] = entry->attr == ATTRB_LOCKED ? 1 : 0;
353 
354 		size = entry->size;
355 		if (entry->size >= 65536U)
356 		{
357 			ticalcs_critical("%s: variable size %u is suspiciously large", __FUNCTION__, size);
358 		}
359 
360 		if (!(size & 1))
361 		{
362 			ret = is_ready(handle);
363 		}
364 
365 		if (ret)
366 		{
367 			dusb_ca_del_array(handle, nattrs, attrs);
368 			break;
369 		}
370 
371 		ret = dusb_cmd_s_rts(handle, entry->folder, entry->name, size, nattrs, CA(attrs));
372 		dusb_ca_del_array(handle, nattrs, attrs);
373 		if (ret)
374 		{
375 			break;
376 		}
377 		ret = dusb_cmd_r_data_ack(handle);
378 		if (ret)
379 		{
380 			break;
381 		}
382 		/*
383 			When sending variables with an odd varsize, bufer has to be negotiatied again with an even value.
384 			Moreover, buffer has to be smaller. Ti-Connect always use 0x3A which is very small for big variables.
385 			I prefer using an heuristic value to optimize data rate.
386 		*/
387 		if (size & 1)
388 		{
389 			pkt_size = size / 10;
390 			pkt_size >>= 1;
391 			pkt_size <<= 1;
392 
393 			if (pkt_size < 0x3a)
394 			{
395 				pkt_size = 0x3a;
396 			}
397 
398 			ret = dusb_send_buf_size_request(handle, pkt_size);
399 			if (ret)
400 			{
401 				break;
402 			}
403 			ret = dusb_recv_buf_size_alloc(handle, NULL);
404 			if (ret)
405 			{
406 				break;
407 			}
408 		}
409 
410 		ret = dusb_cmd_s_var_content(handle, size, entry->data);
411 		if (ret)
412 		{
413 			break;
414 		}
415 		ret = dusb_cmd_r_data_ack(handle);
416 		if (ret)
417 		{
418 			break;
419 		}
420 		ret = dusb_cmd_s_eot(handle);
421 		if (ret)
422 		{
423 			break;
424 		}
425 
426 		update_->cnt2 = i + 1;
427 		update_->max2 = content->num_entries;
428 		update_->pbar();
429 
430 		PAUSE(50);	// needed
431 	}
432 
433 	return ret;
434 }
435 
recv_var(CalcHandle * handle,CalcMode mode,FileContent * content,VarRequest * vr)436 static int		recv_var	(CalcHandle* handle, CalcMode mode, FileContent* content, VarRequest* vr)
437 {
438 	static const uint16_t aids[] = { DUSB_AID_ARCHIVED, DUSB_AID_VAR_VERSION, DUSB_AID_LOCKED };
439 	const int naids = sizeof(aids) / sizeof(uint16_t);
440 	DUSBCalcAttr **attrs;
441 	const int nattrs = 1;
442 	char fldname[40], varname[40];
443 	uint8_t *data;
444 	VarEntry *ve;
445 	int ret;
446 
447 	ticonv_varname_to_utf8_sn(handle->model, vr->name, update_->text, sizeof(update_->text), vr->type);
448 	update_label();
449 
450 	attrs = dusb_ca_new_array(handle, nattrs);
451 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
452 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x0C;
453 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = vr->type;
454 
455 	ret = dusb_cmd_s_var_request(handle, vr->folder, vr->name, naids, aids, nattrs, CA(attrs));
456 	dusb_ca_del_array(handle, nattrs, attrs);
457 	if (!ret)
458 	{
459 		attrs = dusb_ca_new_array(handle, naids);
460 		ret = dusb_cmd_r_var_header(handle, fldname, varname, attrs);
461 		if (!ret)
462 		{
463 			ret = dusb_cmd_r_var_content(handle, NULL, &data);
464 			if (!ret)
465 			{
466 				content->model = handle->model;
467 				ticalcs_strlcpy(content->comment, tifiles_comment_set_single(), sizeof(content->comment));
468 				content->num_entries = 1;
469 
470 				content->entries = tifiles_ve_create_array(1);
471 				ve = content->entries[0] = tifiles_ve_create();
472 				memcpy(ve, vr, sizeof(VarEntry));
473 
474 				ve->data = tifiles_ve_alloc_data(ve->size);
475 				memcpy(ve->data, data, ve->size);
476 				g_free(data);
477 			}
478 		}
479 
480 		dusb_ca_del_array(handle, naids, attrs);
481 	}
482 
483 	return ret;
484 }
485 
send_all_vars_backup(CalcHandle * handle,FileContent * content)486 static int		send_all_vars_backup	(CalcHandle* handle, FileContent* content)
487 {
488 	return send_var(handle, MODE_BACKUP, content);
489 }
490 
send_flash(CalcHandle * handle,FlashContent * content)491 static int		send_flash	(CalcHandle* handle, FlashContent* content)
492 {
493 	FlashContent *ptr;
494 	DUSBCalcAttr **attrs;
495 	const int nattrs = 4;
496 	int ret = 0;
497 
498 	// send all headers except license
499 	for (ptr = content; ptr != NULL; ptr = ptr->next)
500 	{
501 		if (ptr->data_type == TI89_LICENSE)
502 		{
503 			continue;
504 		}
505 
506 		ticalcs_info(_("FLASH name: \"%s\""), ptr->name);
507 		ticalcs_info(_("FLASH size: %i bytes."), ptr->data_length);
508 
509 		ticonv_varname_to_utf8_sn(handle->model, ptr->name, update_->text, sizeof(update_->text), ptr->data_type);
510 		update_label();
511 
512 		attrs = dusb_ca_new_array(handle, nattrs);
513 		attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE, 4);
514 		attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x0C;
515 		attrs[0]->data[2] = 0x00; attrs[0]->data[3] = ptr->data_type;
516 		attrs[1] = dusb_ca_new(handle, DUSB_AID_ARCHIVED, 1);
517 		attrs[1]->data[0] = 0;
518 		attrs[2] = dusb_ca_new(handle, DUSB_AID_VAR_VERSION, 4);
519 		attrs[2]->data[3] = 1;
520 		attrs[3] = dusb_ca_new(handle, DUSB_AID_LOCKED, 1);
521 		attrs[3]->data[0] = 0;
522 
523 		ret = dusb_cmd_s_rts(handle, "", ptr->name, ptr->data_length, nattrs, CA(attrs));
524 		dusb_ca_del_array(handle, nattrs, attrs);
525 		if (ret)
526 		{
527 			break;
528 		}
529 		ret = dusb_cmd_r_data_ack(handle);
530 		if (ret)
531 		{
532 			break;
533 		}
534 		ret = dusb_cmd_s_var_content(handle, ptr->data_length, ptr->data_part);
535 		if (ret)
536 		{
537 			break;
538 		}
539 		ret = dusb_cmd_r_data_ack(handle);
540 		if (ret)
541 		{
542 			break;
543 		}
544 		ret = dusb_cmd_s_eot(handle);
545 		if (ret)
546 		{
547 			break;
548 		}
549 	}
550 
551 	return ret;
552 }
553 
recv_flash(CalcHandle * handle,FlashContent * content,VarRequest * vr)554 static int		recv_flash	(CalcHandle* handle, FlashContent* content, VarRequest* vr)
555 {
556 	static const uint16_t aids[] = { DUSB_AID_ARCHIVED, DUSB_AID_VAR_VERSION, DUSB_AID_LOCKED };
557 	const int naids = sizeof(aids) / sizeof(uint16_t);
558 	DUSBCalcAttr **attrs;
559 	const int nattrs = 1;
560 	char fldname[40], varname[40];
561 	uint8_t *data;
562 	uint32_t data_length;
563 	int ret;
564 
565 	ticonv_varname_to_utf8_sn(handle->model, vr->name, update_->text, sizeof(update_->text), vr->type);
566 	update_label();
567 
568 	attrs = dusb_ca_new_array(handle, nattrs);
569 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
570 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x0C;
571 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = vr->type;
572 
573 	ret = dusb_cmd_s_var_request(handle, "", vr->name, naids, aids, nattrs, CA(attrs));
574 	dusb_ca_del_array(handle, nattrs, attrs);
575 	if (!ret)
576 	{
577 		attrs = dusb_ca_new_array(handle, naids);
578 		ret = dusb_cmd_r_var_header(handle, fldname, varname, attrs);
579 		if (!ret)
580 		{
581 			ret = dusb_cmd_r_var_content(handle, &data_length, &data);
582 			if (!ret)
583 			{
584 				content->model = handle->model;
585 				ticalcs_strlcpy(content->name, vr->name, sizeof(content->name));
586 				content->data_type = vr->type;
587 				content->device_type = DEVICE_TYPE_89;
588 				content->data_length = data_length;
589 				content->data_part = data; // Borrow this memory block.
590 				content->hw_id = handle->calc->product_id;
591 
592 				// Do NOT g_free(data);
593 			}
594 		}
595 		dusb_ca_del_array(handle, naids, attrs);
596 	}
597 
598 	return ret;
599 }
600 
send_os(CalcHandle * handle,FlashContent * content)601 static int		send_os    (CalcHandle* handle, FlashContent* content)
602 {
603 	DUSBModeSet mode = { 2, 1, 0, 0, 0x0fa0 }; //MODE_BASIC;
604 	uint32_t pkt_size = 0x3ff;
605 	uint32_t hdr_size = 0;
606 	uint32_t hdr_offset = 0;
607 	FlashContent *ptr;
608 	uint8_t *d;
609 	int i, r, q;
610 	int ret;
611 
612 	// search for data header
613 	for (ptr = content; ptr != NULL; ptr = ptr->next)
614 	{
615 		if (ptr->data_type == TI89_AMS || ptr->data_type == TI89_APPL)
616 		{
617 			break;
618 		}
619 	}
620 	if (ptr == NULL)
621 	{
622 		return ERR_INVALID_PARAMETER;
623 	}
624 	if (ptr->data_type != TI89_AMS)
625 	{
626 		return ERR_INVALID_PARAMETER;
627 	}
628 	if (ptr->data_part == NULL)
629 	{
630 		return ERR_INVALID_PARAMETER;
631 	}
632 
633 	// search for OS header (offset & size)
634 	hdr_offset = 2+4;
635 	for (i = hdr_offset, d = ptr->data_part; (d[i] != 0xCC) || (d[i+1] != 0xCC) || (d[i+2] != 0xCC) || (d[i+3] != 0xCC); i++);
636 	hdr_size = i - hdr_offset - 6;
637 
638 	do
639 	{
640 		// switch to BASIC mode
641 		ret = dusb_cmd_s_mode_set(handle, mode);
642 		if (ret)
643 		{
644 			break;
645 		}
646 		ret = dusb_cmd_r_mode_ack(handle);
647 		if (ret)
648 		{
649 			break;
650 		}
651 
652 		// start OS transfer
653 		ret = dusb_cmd_s_os_begin(handle, ptr->data_length);
654 		if (ret)
655 		{
656 			break;
657 		}
658 		ret = dusb_cmd_r_os_ack(handle, &pkt_size);
659 		if (ret)
660 		{
661 			break;
662 		}
663 
664 		// send OS header/signature
665 		ret = dusb_cmd_s_os_header_89(handle, hdr_size, ptr->data_part + hdr_offset);
666 		if (ret)
667 		{
668 			break;
669 		}
670 		ret = dusb_cmd_r_os_ack(handle, &pkt_size);
671 		if (ret)
672 		{
673 			break;
674 		}
675 
676 		// send OS data
677 		q = ptr->data_length / 0x2000;
678 		r = ptr->data_length % 0x2000;
679 
680 		update_->cnt2 = 0;
681 		update_->max2 = q;
682 
683 		for (i = 0; i < q; i++)
684 		{
685 			ret = dusb_cmd_s_os_data_89(handle, 0x2000, ptr->data_part + i*0x2000);
686 			if (ret)
687 			{
688 				goto end;
689 			}
690 			ret = dusb_cmd_r_data_ack(handle);
691 			if (ret)
692 			{
693 				goto end;
694 			}
695 
696 			update_->cnt2 = i;
697 			update_->pbar();
698 		}
699 
700 		ret = dusb_cmd_s_os_data_89(handle, r, ptr->data_part + i*0x2000);
701 		if (ret)
702 		{
703 			break;
704 		}
705 		ret = dusb_cmd_r_data_ack(handle);
706 		if (ret)
707 		{
708 			break;
709 		}
710 
711 		update_->cnt2 = i;
712 		update_->pbar();
713 
714 		ret = dusb_cmd_s_eot(handle);
715 		if (ret)
716 		{
717 			break;
718 		}
719 		PAUSE(500);
720 		ret = dusb_cmd_r_eot_ack(handle);
721 	} while (0);
722 end:
723 
724 	return ret;
725 }
726 
recv_idlist(CalcHandle * handle,uint8_t * id)727 static int		recv_idlist	(CalcHandle* handle, uint8_t* id)
728 {
729 	static const uint16_t pid[] = { DUSB_PID_FULL_ID };
730 	const int size = 1;
731 	DUSBCalcParam **params;
732 	int ret;
733 
734 	ticalcs_strlcpy(update_->text, "ID-LIST", sizeof(update_->text));
735 	update_label();
736 
737 	params = dusb_cp_new_array(handle, size);
738 	if (params != NULL)
739 	{
740 		ret = dusb_cmd_s_param_request(handle, size, pid);
741 		if (!ret)
742 		{
743 			ret = dusb_cmd_r_param_data(handle, size, params);
744 			if (!ret)
745 			{
746 				if (params[0]->ok && params[0]->size == 18)
747 				{
748 					memcpy(&id[0], &(params[0]->data[1]), 5);
749 					memcpy(&id[5], &(params[0]->data[7]), 5);
750 					memcpy(&id[10], &(params[0]->data[13]), 5);
751 					id[14] = '\0';
752 				}
753 				else
754 				{
755 					ret = ERR_INVALID_PACKET;
756 				}
757 			}
758 		}
759 	}
760 	else
761 	{
762 		ret = ERR_MALLOC;
763 	}
764 	dusb_cp_del_array(handle, size, params);
765 
766 	return ret;
767 }
768 
dump_rom_1(CalcHandle * handle)769 static int		dump_rom_1	(CalcHandle* handle)
770 {
771 	DUSBCalcParam *param;
772 	int ret;
773 
774 	// Go back to HOME screen
775 	param = dusb_cp_new(handle, DUSB_PID_HOMESCREEN, 1);
776 	param->data[0] = 1;
777 	ret = dusb_cmd_s_param_set(handle, param);
778 	dusb_cp_del(handle, param);
779 	if (!ret)
780 	{
781 		ret = dusb_cmd_r_data_ack(handle);
782 		if (!ret)
783 		{
784 			// Send dumping program
785 			ret = rd_send(handle, "romdump.89z", romDumpSize89t, romDump89t);
786 			PAUSE(1000);
787 		}
788 	}
789 
790 	return ret;
791 }
792 
dump_rom_2(CalcHandle * handle,CalcDumpSize size,const char * filename)793 static int		dump_rom_2	(CalcHandle* handle, CalcDumpSize size, const char *filename)
794 {
795 	int ret;
796 
797 	ret = dusb_cmd_s_execute(handle, "main", "romdump", DUSB_EID_ASM, "", 0);
798 	if (!ret)
799 	{
800 		ret = dusb_cmd_r_data_ack(handle);
801 		if (!ret)
802 		{
803 			// Get dump
804 			ret = rd_dump(handle, filename);
805 		}
806 	}
807 
808 	return ret;
809 }
810 
set_clock(CalcHandle * handle,CalcClock * _clock)811 static int		set_clock	(CalcHandle* handle, CalcClock* _clock)
812 {
813 	DUSBCalcParam *param;
814 	uint32_t calc_time;
815 	struct tm ref, cur;
816 	time_t r, c, now;
817 	int ret;
818 
819 	time(&now);
820 	memcpy(&ref, localtime(&now), sizeof(struct tm));
821 
822 	ref.tm_year = 1997 - 1900;
823 	ref.tm_mon = 0;
824 	ref.tm_yday = 0;
825 	ref.tm_mday = 1;
826 	ref.tm_wday = 3;
827 	ref.tm_hour = 0;
828 	ref.tm_min = 0;
829 	ref.tm_sec = 0;
830 	//ref.tm_isdst = 1;
831 	r = mktime(&ref);
832 
833 	cur.tm_year = _clock->year - 1900;
834 	cur.tm_mon = _clock->month - 1;
835 	cur.tm_mday = _clock->day;
836 	cur.tm_hour = _clock->hours;
837 	cur.tm_min = _clock->minutes;
838 	cur.tm_sec = _clock->seconds;
839 	cur.tm_isdst = 1;
840 	c = mktime(&cur);
841 
842 	calc_time = (uint32_t)difftime(c, r);
843 
844 	ticalcs_strlcpy(update_->text, _("Setting clock..."), sizeof(update_->text));
845 	update_label();
846 
847 	do
848 	{
849 		param = dusb_cp_new(handle, DUSB_PID_CLK_SEC_SINCE_1997, 4);
850 		param->data[0] = MSB(MSW(calc_time));
851 		param->data[1] = LSB(MSW(calc_time));
852 		param->data[2] = MSB(LSW(calc_time));
853 		param->data[3] = LSB(LSW(calc_time));
854 		ret = dusb_cmd_s_param_set(handle, param);
855 		dusb_cp_del(handle, param);
856 		if (ret)
857 		{
858 			break;
859 		}
860 
861 		ret = dusb_cmd_r_data_ack(handle);
862 		if (ret)
863 		{
864 			break;
865 		}
866 
867 		param = dusb_cp_new(handle, DUSB_PID_CLK_DATE_FMT, 1);
868 		param->data[0] = _clock->date_format == 3 ? 0 : _clock->date_format;
869 		ret = dusb_cmd_s_param_set(handle, param);
870 		dusb_cp_del(handle, param);
871 		if (ret)
872 		{
873 			break;
874 		}
875 
876 		ret = dusb_cmd_r_data_ack(handle);
877 		if (ret)
878 		{
879 			break;
880 		}
881 
882 		param = dusb_cp_new(handle, DUSB_PID_CLK_TIME_FMT, 1);
883 		param->data[0] = _clock->time_format == 24 ? 1 : 0;
884 		ret = dusb_cmd_s_param_set(handle, param);
885 		dusb_cp_del(handle, param);
886 		if (ret)
887 		{
888 			break;
889 		}
890 
891 		ret = dusb_cmd_r_data_ack(handle);
892 		if (ret)
893 		{
894 			break;
895 		}
896 
897 		param = dusb_cp_new(handle, DUSB_PID_CLK_ON, 1);
898 		param->data[0] = _clock->state;
899 		ret = dusb_cmd_s_param_set(handle, param);
900 		dusb_cp_del(handle, param);
901 		if (ret)
902 		{
903 			break;
904 		}
905 
906 		ret = dusb_cmd_r_data_ack(handle);
907 	} while (0);
908 
909 	return ret;
910 }
911 
get_clock(CalcHandle * handle,CalcClock * _clock)912 static int		get_clock	(CalcHandle* handle, CalcClock* _clock)
913 {
914 	static const uint16_t pids[5] = { DUSB_PID_CLASSIC_CLK_SUPPORT, DUSB_PID_CLK_SEC_SINCE_1997, DUSB_PID_CLK_DATE_FMT, DUSB_PID_CLK_TIME_FMT, DUSB_PID_CLK_ON };
915 	const int size = sizeof(pids) / sizeof(uint16_t);
916 	DUSBCalcParam **params;
917 	uint32_t calc_time;
918 	struct tm ref, *cur;
919 	time_t r, c, now;
920 	int ret;
921 
922 	// get raw clock
923 	ticalcs_strlcpy(update_->text, _("Getting clock..."), sizeof(update_->text));
924 	update_label();
925 
926 	params = dusb_cp_new_array(handle, size);
927 	ret = dusb_cmd_s_param_request(handle, size, pids);
928 	if (!ret)
929 	{
930 		ret = dusb_cmd_r_param_data(handle, size, params);
931 		if (!ret)
932 		{
933 			// It's not a fatal error if DUSB_PID_CLASSIC_CLK_SUPPORT is not handled.
934 			if (params[0]->ok && params[0]->size == 1)
935 			{
936 				if (!params[0]->data[0])
937 				{
938 					ret = ERR_UNSUPPORTED;
939 				}
940 			}
941 			else
942 			{
943 				if (   params[1]->ok && params[0]->size == 4
944 				    && params[2]->ok && params[1]->size == 1
945 				    && params[3]->ok && params[2]->size == 1
946 				    && params[4]->ok && params[3]->size == 1)
947 				{
948 					// and computes
949 					calc_time = (((uint32_t)params[0]->data[0]) << 24) | (((uint32_t)params[0]->data[1]) << 16) | (((uint32_t)params[0]->data[2]) <<  8) | (params[0]->data[3] <<  0);
950 
951 					time(&now);	// retrieve current DST setting
952 					memcpy(&ref, localtime(&now), sizeof(struct tm));
953 					ref.tm_year = 1997 - 1900;
954 					ref.tm_mon = 0;
955 					ref.tm_yday = 0;
956 					ref.tm_mday = 1;
957 					ref.tm_wday = 3;
958 					ref.tm_hour = 0;
959 					ref.tm_min = 0;
960 					ref.tm_sec = 0;
961 					//ref.tm_isdst = 1;
962 					r = mktime(&ref);
963 
964 					c = r + calc_time;
965 					cur = localtime(&c);
966 
967 					_clock->year = cur->tm_year + 1900;
968 					_clock->month = cur->tm_mon + 1;
969 					_clock->day = cur->tm_mday;
970 					_clock->hours = cur->tm_hour;
971 					_clock->minutes = cur->tm_min;
972 					_clock->seconds = cur->tm_sec;
973 
974 					_clock->date_format = params[1]->data[0] == 0 ? 3 : params[1]->data[0];
975 					_clock->time_format = params[2]->data[0] ? 24 : 12;
976 					_clock->state = params[3]->data[0];
977 				}
978 				else
979 				{
980 					ret = ERR_INVALID_PACKET;
981 				}
982 			}
983 		}
984 	}
985 	dusb_cp_del_array(handle, size, params);
986 
987 	return ret;
988 }
989 
del_var(CalcHandle * handle,VarRequest * vr)990 static int		del_var		(CalcHandle* handle, VarRequest* vr)
991 {
992 	DUSBCalcAttr **attr;
993 	const int size = 1;
994 	char varname[68];
995 	char *utf8;
996 	int ret;
997 
998 	tifiles_build_fullname(handle->model, varname, vr->folder, vr->name);
999 	utf8 = ticonv_varname_to_utf8(handle->model, varname, vr->type);
1000 	ticalcs_slprintf(update_->text, sizeof(update_->text), _("Deleting %s..."), utf8);
1001 	ticonv_utf8_free(utf8);
1002 	update_label();
1003 
1004 	attr = dusb_ca_new_array(handle, size);
1005 	attr[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
1006 	attr[0]->data[0] = 0xF0; attr[0]->data[1] = 0x0C;
1007 	attr[0]->data[2] = 0x00; attr[0]->data[3] = vr->type;
1008 
1009 	ret = dusb_cmd_s_var_delete(handle, vr->folder, vr->name, size, CA(attr));
1010 	dusb_ca_del_array(handle, size, attr);
1011 	if (!ret)
1012 	{
1013 		ret = dusb_cmd_r_data_ack(handle);
1014 	}
1015 
1016 	return ret;
1017 }
1018 
rename_var(CalcHandle * handle,VarRequest * oldname,VarRequest * newname)1019 static int		rename_var	(CalcHandle* handle, VarRequest* oldname, VarRequest* newname)
1020 {
1021 	DUSBCalcAttr **attrs;
1022 	const int size = 1;
1023 	char varname1[68], varname2[68];
1024 	char *utf81, *utf82;
1025 	int ret;
1026 
1027 	tifiles_build_fullname(handle->model, varname1, oldname->folder, oldname->name);
1028 	tifiles_build_fullname(handle->model, varname2, newname->folder, newname->name);
1029 	utf81 = ticonv_varname_to_utf8(handle->model, varname1, oldname->type);
1030 	utf82 = ticonv_varname_to_utf8(handle->model, varname2, newname->type);
1031 	ticalcs_slprintf(update_->text, sizeof(update_->text), _("Renaming %s to %s..."), utf81, utf82);
1032 	ticonv_utf8_free(utf82);
1033 	ticonv_utf8_free(utf81);
1034 	update_label();
1035 
1036 	attrs = dusb_ca_new_array(handle, size);
1037 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
1038 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x0C;
1039 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = oldname->type;
1040 
1041 	ret = dusb_cmd_s_var_modify(handle, oldname->folder, oldname->name, 1, CA(attrs), newname->folder, newname->name, 0, NULL);
1042 	dusb_ca_del_array(handle, size, attrs);
1043 	if (!ret)
1044 	{
1045 		ret = dusb_cmd_r_data_ack(handle);
1046 	}
1047 
1048 	return ret;
1049 }
1050 
change_attr(CalcHandle * handle,VarRequest * vr,FileAttr attr)1051 static int		change_attr	(CalcHandle* handle, VarRequest* vr, FileAttr attr)
1052 {
1053 	DUSBCalcAttr **srcattrs;
1054 	DUSBCalcAttr **dstattrs;
1055 	int ret = 0;
1056 	char *utf8;
1057 
1058 	utf8 = ticonv_varname_to_utf8(handle->model, vr->folder, -1);
1059 	ticalcs_slprintf(update_->text, sizeof(update_->text), _("Changing attributes of %s..."), utf8);
1060 	ticonv_utf8_free(utf8);
1061 	update_label();
1062 
1063 	srcattrs = dusb_ca_new_array(handle, 1);
1064 	srcattrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE2, 4);
1065 	srcattrs[0]->data[0] = 0xF0; srcattrs[0]->data[1] = 0x0C;
1066 	srcattrs[0]->data[2] = 0x00; srcattrs[0]->data[3] = vr->type;
1067 
1068 	dstattrs = dusb_ca_new_array(handle, 2);
1069 	dstattrs[0] = dusb_ca_new(handle, DUSB_AID_ARCHIVED, 1);
1070 	dstattrs[0]->data[0] = (attr == ATTRB_ARCHIVED ? 0x01 : 0x00);
1071 	dstattrs[1] = dusb_ca_new(handle, DUSB_AID_LOCKED, 1);
1072 	dstattrs[1]->data[0] = (attr == ATTRB_LOCKED ? 0x01 : 0x00);
1073 
1074 	ret = dusb_cmd_s_var_modify(handle, vr->folder, vr->name, 1, CA(srcattrs), vr->folder, vr->name, 2, CA(dstattrs));
1075 	dusb_ca_del_array(handle, 2, dstattrs);
1076 	dusb_ca_del_array(handle, 1, srcattrs);
1077 	if (!ret)
1078 	{
1079 		ret = dusb_cmd_r_data_ack(handle);
1080 	}
1081 
1082 	return ret;
1083 }
1084 
new_folder(CalcHandle * handle,VarRequest * vr)1085 static int		new_folder  (CalcHandle* handle, VarRequest* vr)
1086 {
1087 	uint8_t data[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x40, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23 };
1088 	char *fldname = vr->folder;
1089 	DUSBCalcParam *param;
1090 	DUSBCalcAttr **attrs;
1091 	const int nattrs = 4;
1092 	char *utf8;
1093 	int ret;
1094 
1095 	utf8 = ticonv_varname_to_utf8(handle->model, vr->folder, -1);
1096 	ticalcs_slprintf(update_->text, sizeof(update_->text), _("Creating %s..."), utf8);
1097 	ticonv_utf8_free(utf8);
1098 	update_label();
1099 
1100 	// send empty expression in specified folder
1101 	attrs = dusb_ca_new_array(handle, nattrs);
1102 	attrs[0] = dusb_ca_new(handle, DUSB_AID_VAR_TYPE, 4);
1103 	attrs[0]->data[0] = 0xF0; attrs[0]->data[1] = 0x0C;
1104 	attrs[0]->data[2] = 0x00; attrs[0]->data[3] = 0x00;
1105 	attrs[1] = dusb_ca_new(handle, DUSB_AID_ARCHIVED, 1);
1106 	attrs[1]->data[0] = 0;
1107 	attrs[2] = dusb_ca_new(handle, DUSB_AID_VAR_VERSION, 4);
1108 	attrs[2]->data[0] = 0;
1109 	attrs[3] = dusb_ca_new(handle, DUSB_AID_LOCKED, 1);
1110 	attrs[3]->data[0] = 0;
1111 
1112 	do
1113 	{
1114 		ret = dusb_cmd_s_rts(handle, fldname, "a1234567", sizeof(data), nattrs, CA(attrs));
1115 		dusb_ca_del_array(handle, nattrs, attrs);
1116 		if (ret)
1117 		{
1118 			break;
1119 		}
1120 
1121 		ret = dusb_cmd_r_data_ack(handle);
1122 		if (ret)
1123 		{
1124 			break;
1125 		}
1126 
1127 		ret = dusb_cmd_s_var_content(handle, sizeof(data), data);
1128 		if (ret)
1129 		{
1130 			break;
1131 		}
1132 
1133 		ret = dusb_cmd_r_data_ack(handle);
1134 		if (ret)
1135 		{
1136 			break;
1137 		}
1138 
1139 		ret = dusb_cmd_s_eot(handle);
1140 		if (ret)
1141 		{
1142 			break;
1143 		}
1144 
1145 		// go back to HOME screen
1146 		param = dusb_cp_new(handle, DUSB_PID_HOMESCREEN, 1);
1147 		param->data[0] = 1;
1148 		ret = dusb_cmd_s_param_set(handle, param);
1149 		dusb_cp_del(handle, param);
1150 		if (ret)
1151 		{
1152 			break;
1153 		}
1154 
1155 		ret = dusb_cmd_r_data_ack(handle);
1156 		if (ret)
1157 		{
1158 			break;
1159 		}
1160 
1161 		// delete 'a1234567' variable
1162 		ticalcs_strlcpy(vr->name, "a1234567", sizeof(vr->name));
1163 		ret = del_var(handle, vr);
1164 	} while (0);
1165 
1166 	return ret;
1167 }
1168 
get_version(CalcHandle * handle,CalcInfos * infos)1169 static int		get_version	(CalcHandle* handle, CalcInfos* infos)
1170 {
1171 	static const uint16_t pids1[] = {
1172 		DUSB_PID_PRODUCT_NAME, DUSB_PID_MAIN_PART_ID,
1173 		DUSB_PID_HW_VERSION, DUSB_PID_LANGUAGE_ID, DUSB_PID_SUBLANG_ID, DUSB_PID_DEVICE_TYPE,
1174 		DUSB_PID_BOOT_VERSION, DUSB_PID_OS_VERSION,
1175 		DUSB_PID_PHYS_RAM, DUSB_PID_USER_RAM, DUSB_PID_FREE_RAM,
1176 		DUSB_PID_PHYS_FLASH, DUSB_PID_FREE_FLASH, DUSB_PID_FREE_FLASH,
1177 		DUSB_PID_LCD_WIDTH, DUSB_PID_LCD_HEIGHT,
1178 	};
1179 	static const uint16_t pids2[] = {
1180 		DUSB_PID_BITS_PER_PIXEL, DUSB_PID_BATTERY, DUSB_PID_OS_MODE, DUSB_PID_CLASSIC_CLK_SUPPORT
1181 	};	// Titanium can't manage more than 16 parameters at a time
1182 	const int size1 = sizeof(pids1) / sizeof(uint16_t);
1183 	const int size2 = sizeof(pids2) / sizeof(uint16_t);
1184 	DUSBCalcParam **params1;
1185 	DUSBCalcParam **params2;
1186 	int i = 0;
1187 	int ret = 0;
1188 
1189 	ticalcs_strlcpy(update_->text, _("Getting version..."), sizeof(update_->text));
1190 	update_label();
1191 
1192 	memset(infos, 0, sizeof(CalcInfos));
1193 	params1 = dusb_cp_new_array(handle, size1);
1194 	params2 = dusb_cp_new_array(handle, size2);
1195 
1196 	do
1197 	{
1198 		ret = dusb_cmd_s_param_request(handle, size1, pids1);
1199 		if (!ret)
1200 		{
1201 			ret = dusb_cmd_r_param_data(handle, size1, params1);
1202 			if (!ret)
1203 			{
1204 				ret = dusb_cmd_s_param_request(handle, size2, pids2);
1205 				if (!ret)
1206 				{
1207 					ret = dusb_cmd_r_param_data(handle, size2, params2);
1208 				}
1209 			}
1210 		}
1211 
1212 		if (ret)
1213 		{
1214 			break;
1215 		}
1216 
1217 		if (params1[i]->ok)
1218 		{
1219 			ticalcs_strlcpy(infos->product_name, (char *)params1[i]->data, sizeof(infos->product_name));
1220 			infos->mask |= INFOS_PRODUCT_NAME;
1221 		}
1222 		i++;
1223 
1224 		if (params1[i]->ok && params1[i]->size >= 18)
1225 		{
1226 			strncpy(infos->main_calc_id, (char*)&(params1[i]->data[1]), 5);
1227 			strncpy(infos->main_calc_id+5, (char*)&(params1[i]->data[7]), 5);
1228 			strncpy(infos->main_calc_id+10, (char*)&(params1[i]->data[13]), 4);
1229 			infos->main_calc_id[14] = 0;
1230 			infos->mask |= INFOS_MAIN_CALC_ID;
1231 			ticalcs_strlcpy(infos->product_id, infos->main_calc_id, sizeof(infos->product_id));
1232 			infos->mask |= INFOS_PRODUCT_ID;
1233 		}
1234 		i++;
1235 
1236 		if (params1[i]->ok && params1[i]->size == 2)
1237 		{
1238 			infos->hw_version = ((((uint16_t)params1[i]->data[0]) << 8) | params1[i]->data[1]) + 1;
1239 			infos->mask |= INFOS_HW_VERSION; // hw version or model ?
1240 		}
1241 		i++;
1242 
1243 		if (params1[i]->ok && params1[i]->size == 1)
1244 		{
1245 			infos->language_id = params1[i]->data[0];
1246 			infos->mask |= INFOS_LANG_ID;
1247 		}
1248 		i++;
1249 
1250 		if (params1[i]->ok && params1[i]->size == 1)
1251 		{
1252 			infos->sub_lang_id = params1[i]->data[0];
1253 			infos->mask |= INFOS_SUB_LANG_ID;
1254 		}
1255 		i++;
1256 
1257 		if (params1[i]->ok && params1[i]->size == 2)
1258 		{
1259 			infos->device_type = params1[i]->data[1];
1260 			infos->mask |= INFOS_DEVICE_TYPE;
1261 		}
1262 		i++;
1263 
1264 		if (params1[i]->ok && params1[i]->size == 4)
1265 		{
1266 			ticalcs_slprintf(infos->boot_version, sizeof(infos->boot_version), "%1u.%02ub%u", params1[i]->data[1], params1[i]->data[2], params1[i]->data[3]);
1267 			infos->mask |= INFOS_BOOT_VERSION;
1268 		}
1269 		i++;
1270 
1271 		if (params1[i]->ok && params1[i]->size == 3)
1272 		{
1273 			ticalcs_slprintf(infos->os_version, sizeof(infos->os_version), "%1u.%02u", params1[i]->data[1], params1[i]->data[2]);
1274 			infos->mask |= INFOS_OS_VERSION;
1275 		}
1276 		i++;
1277 
1278 		if (params1[i]->ok && params1[i]->size == 8)
1279 		{
1280 			infos->ram_phys = (  (((uint64_t)(params1[i]->data[ 0])) << 56)
1281 			                   | (((uint64_t)(params1[i]->data[ 1])) << 48)
1282 			                   | (((uint64_t)(params1[i]->data[ 2])) << 40)
1283 			                   | (((uint64_t)(params1[i]->data[ 3])) << 32)
1284 			                   | (((uint64_t)(params1[i]->data[ 4])) << 24)
1285 			                   | (((uint64_t)(params1[i]->data[ 5])) << 16)
1286 			                   | (((uint64_t)(params1[i]->data[ 6])) <<  8)
1287 			                   | (((uint64_t)(params1[i]->data[ 7]))      ));
1288 			infos->mask |= INFOS_RAM_PHYS;
1289 		}
1290 		i++;
1291 		if (params1[i]->ok && params1[i]->size == 8)
1292 		{
1293 			infos->ram_user = (  (((uint64_t)(params1[i]->data[ 0])) << 56)
1294 			                   | (((uint64_t)(params1[i]->data[ 1])) << 48)
1295 			                   | (((uint64_t)(params1[i]->data[ 2])) << 40)
1296 			                   | (((uint64_t)(params1[i]->data[ 3])) << 32)
1297 			                   | (((uint64_t)(params1[i]->data[ 4])) << 24)
1298 			                   | (((uint64_t)(params1[i]->data[ 5])) << 16)
1299 			                   | (((uint64_t)(params1[i]->data[ 6])) <<  8)
1300 			                   | (((uint64_t)(params1[i]->data[ 7]))      ));
1301 			infos->mask |= INFOS_RAM_USER;
1302 		}
1303 		i++;
1304 		if (params1[i]->ok && params1[i]->size == 8)
1305 		{
1306 			infos->ram_free = (  (((uint64_t)(params1[i]->data[ 0])) << 56)
1307 			                   | (((uint64_t)(params1[i]->data[ 1])) << 48)
1308 			                   | (((uint64_t)(params1[i]->data[ 2])) << 40)
1309 			                   | (((uint64_t)(params1[i]->data[ 3])) << 32)
1310 			                   | (((uint64_t)(params1[i]->data[ 4])) << 24)
1311 			                   | (((uint64_t)(params1[i]->data[ 5])) << 16)
1312 			                   | (((uint64_t)(params1[i]->data[ 6])) <<  8)
1313 			                   | (((uint64_t)(params1[i]->data[ 7]))      ));
1314 			infos->mask |= INFOS_RAM_FREE;
1315 		}
1316 		i++;
1317 
1318 		if (params1[i]->ok && params1[i]->size == 8)
1319 		{
1320 			infos->flash_phys = (  (((uint64_t)(params1[i]->data[ 0])) << 56)
1321 			                     | (((uint64_t)(params1[i]->data[ 1])) << 48)
1322 			                     | (((uint64_t)(params1[i]->data[ 2])) << 40)
1323 			                     | (((uint64_t)(params1[i]->data[ 3])) << 32)
1324 			                     | (((uint64_t)(params1[i]->data[ 4])) << 24)
1325 			                     | (((uint64_t)(params1[i]->data[ 5])) << 16)
1326 			                     | (((uint64_t)(params1[i]->data[ 6])) <<  8)
1327 			                     | (((uint64_t)(params1[i]->data[ 7]))      ));
1328 			infos->mask |= INFOS_FLASH_PHYS;
1329 		}
1330 		i++;
1331 		if (params1[i]->ok && params1[i]->size == 8)
1332 		{
1333 			infos->flash_user = (  (((uint64_t)(params1[i]->data[ 0])) << 56)
1334 			                     | (((uint64_t)(params1[i]->data[ 1])) << 48)
1335 			                     | (((uint64_t)(params1[i]->data[ 2])) << 40)
1336 			                     | (((uint64_t)(params1[i]->data[ 3])) << 32)
1337 			                     | (((uint64_t)(params1[i]->data[ 4])) << 24)
1338 			                     | (((uint64_t)(params1[i]->data[ 5])) << 16)
1339 			                     | (((uint64_t)(params1[i]->data[ 6])) <<  8)
1340 			                     | (((uint64_t)(params1[i]->data[ 7]))      ));
1341 			infos->mask |= INFOS_FLASH_USER;
1342 		}
1343 		i++;
1344 		if (params1[i]->ok && params1[i]->size == 8)
1345 		{
1346 			infos->flash_free = (  (((uint64_t)(params1[i]->data[ 0])) << 56)
1347 			                     | (((uint64_t)(params1[i]->data[ 1])) << 48)
1348 			                     | (((uint64_t)(params1[i]->data[ 2])) << 40)
1349 			                     | (((uint64_t)(params1[i]->data[ 3])) << 32)
1350 			                     | (((uint64_t)(params1[i]->data[ 4])) << 24)
1351 			                     | (((uint64_t)(params1[i]->data[ 5])) << 16)
1352 			                     | (((uint64_t)(params1[i]->data[ 6])) <<  8)
1353 			                     | (((uint64_t)(params1[i]->data[ 7]))      ));
1354 			infos->mask |= INFOS_FLASH_FREE;
1355 		}
1356 		i++;
1357 
1358 		if (params1[i]->ok && params1[i]->size == 2)
1359 		{
1360 			infos->lcd_width = (  (((uint16_t)params1[i]->data[ 0]) <<  8)
1361 			                    | (((uint16_t)params1[i]->data[ 1])      ));
1362 			infos->mask |= INFOS_LCD_WIDTH;
1363 		}
1364 		i++;
1365 		if (params1[i]->ok && params1[i]->size == 2)
1366 		{
1367 			infos->lcd_height = (  (((uint16_t)params1[i]->data[ 0]) <<  8)
1368 			                     | (((uint16_t)params1[i]->data[ 1])      ));
1369 			infos->mask |= INFOS_LCD_HEIGHT;
1370 		}
1371 		i++;
1372 
1373 		i = 0;
1374 		if (params2[i]->ok && params2[i]->size == 1)
1375 		{
1376 			infos->bits_per_pixel = params2[i]->data[0];
1377 			infos->mask |= INFOS_BPP;
1378 		}
1379 
1380 		if (params2[i]->ok && params2[i]->size == 1)
1381 		{
1382 			infos->battery = params2[i]->data[0];
1383 			infos->mask |= INFOS_BATTERY;
1384 		}
1385 		i++;
1386 
1387 		if (params2[i]->ok && params2[i]->size == 1)
1388 		{
1389 			infos->run_level = params2[i]->data[0];
1390 			infos->mask |= INFOS_RUN_LEVEL;
1391 		}
1392 		i++;
1393 
1394 		if (params2[i]->ok && params2[i]->size == 1)
1395 		{
1396 			infos->clock_support = params2[i]->data[0];
1397 			infos->mask |= INFOS_CLOCK_SUPPORT;
1398 		}
1399 		i++;
1400 
1401 		infos->model = CALC_TI89T;
1402 		infos->mask |= INFOS_CALC_MODEL;
1403 	} while (0);
1404 
1405 	dusb_cp_del_array(handle, size2, params2);
1406 	dusb_cp_del_array(handle, size1, params1);
1407 
1408 	return ret;
1409 }
1410 
1411 const CalcFncts calc_89t_usb =
1412 {
1413 	CALC_TI89T_USB,
1414 	"Titanium",
1415 	"TI-89 Titanium",
1416 	N_("TI-89 Titanium thru DirectLink"),
1417 	OPS_ISREADY | OPS_SCREEN | OPS_DIRLIST | OPS_VARS | OPS_FLASH | OPS_OS | OPS_ROMDUMP |
1418 	OPS_IDLIST | OPS_CLOCK | OPS_DELVAR | OPS_NEWFLD | OPS_VERSION | OPS_BACKUP | OPS_KEYS |
1419 	OPS_RENAME | OPS_CHATTR |
1420 	FTS_SILENT | FTS_MEMFREE | FTS_FLASH | FTS_FOLDER,
1421 	PRODUCT_ID_TI89T,
1422 	{"",     /* is_ready */
1423 	 "",     /* send_key */
1424 	 "",     /* execute */
1425 	 "1P",   /* recv_screen */
1426 	 "1L",   /* get_dirlist */
1427 	 "",     /* get_memfree */
1428 	 "2P1L", /* send_backup */
1429 	 "2P1L", /* recv_backup */
1430 	 "2P1L", /* send_var */
1431 	 "1P1L", /* recv_var */
1432 	 "2P1L", /* send_var_ns */
1433 	 "1P1L", /* recv_var_ns */
1434 	 "2P1L", /* send_app */
1435 	 "2P1L", /* recv_app */
1436 	 "2P",   /* send_os */
1437 	 "1L",   /* recv_idlist */
1438 	 "2P",   /* dump_rom_1 */
1439 	 "2P",   /* dump_rom_2 */
1440 	 "",     /* set_clock */
1441 	 "",     /* get_clock */
1442 	 "1L",   /* del_var */
1443 	 "1L",   /* new_folder */
1444 	 "",     /* get_version */
1445 	 "1L",   /* send_cert */
1446 	 "1L",   /* recv_cert */
1447 	 "",     /* rename */
1448 	 "",     /* chattr */
1449 	 "2P1L", /* send_all_vars_backup */
1450 	 "2P1L"  /* recv_all_vars_backup */ },
1451 	&is_ready,
1452 	&send_key,
1453 	&execute,
1454 	&recv_screen,
1455 	&get_dirlist,
1456 	&get_memfree,
1457 	&noop_send_backup,
1458 	&noop_recv_backup,
1459 	&send_var,
1460 	&recv_var,
1461 	&noop_send_var_ns,
1462 	&noop_recv_var_ns,
1463 	&send_flash,
1464 	&recv_flash,
1465 	&send_os,
1466 	&recv_idlist,
1467 	&dump_rom_1,
1468 	&dump_rom_2,
1469 	&set_clock,
1470 	&get_clock,
1471 	&del_var,
1472 	&new_folder,
1473 	&get_version,
1474 	&noop_send_cert,
1475 	&noop_recv_cert,
1476 	&rename_var,
1477 	&change_attr,
1478 	&send_all_vars_backup,
1479 	&tixx_recv_all_vars_backup
1480 };
1481