Esempio n. 1
0
int dusb_recv(CalcHandle* handle, RawPacket* pkt)
{
	uint8_t buf[5];

	// Any packet has always an header of 5 bytes (size & type)
	ticables_progress_reset(handle->cable);
	TRYF(ticables_cable_recv(handle->cable, buf, 5));

	pkt->size = buf[3] | (buf[2] << 8) | (buf[1] << 16) | (buf[0] << 24);
	pkt->type = buf[4];

	if(handle->model == CALC_TI84P_USB && pkt->size > 250)
		return ERR_INVALID_PACKET;
	if(handle->model == CALC_TI89T_USB && pkt->size > 1023)
		return ERR_INVALID_PACKET;

	//printf("dusb_send: pkt->size=%d\n", pkt->size);
	// Next, follows data
	TRYF(ticables_cable_recv(handle->cable, pkt->data, pkt->size));
	if(pkt->size >= 128)
		ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
			
	if (handle->updat->cancel)
		return ERR_ABORT;

	return 0;
}
Esempio n. 2
0
// Work around TI's OS behaviour: extra bulk read of 0 size required after the last raw packet in a transfer,
// when some conditions are met.
static void workaround_recv(CalcHandle *handle, DUSBRawPacket * raw, DUSBVirtualPacket * vtl)
{
	uint8_t buf[64];

	ticalcs_info("workaround_recv: vtl->size=%d\traw->size=%d", vtl->size, raw->size);

	if (handle->model == CALC_TI89T_USB)
	{
		if ((raw->size % 64) == 0)
		{
			ticalcs_info("XXX triggering an extra bulk read\n\tvtl->size=%d\traw->size=%d", vtl->size, raw->size);
			ticables_cable_recv(handle->cable, buf, 0);
		}
	}
	else if (handle->model == CALC_TI84P_USB || handle->model == CALC_TI84PC_USB || handle->model == CALC_TI82A_USB || handle->model == CALC_TI84PT_USB)
	{
		if (((raw->size + 5) % 64) == 0)
		{
			ticalcs_info("XXX triggering an extra bulk read\n\tvtl->size=%d\traw->size=%d", vtl->size, raw->size);
			ticables_cable_recv(handle->cable, buf, 0);
		}
	}
	else if (handle->model == CALC_TI83PCE_USB || handle->model == CALC_TI84PCE_USB)
	{
		// These models don't seem to need receive workarounds.
	}
	else
	{
		ticalcs_warning("XXX unhandled model in workaround_recv");
	}
}
Esempio n. 3
0
TIEXPORT3 int TICALL dbus_recv_header(CalcHandle *handle, uint8_t* host, uint8_t* cmd, uint16_t* length)
{
	int ret;
	uint8_t buf[4];

	VALIDATE_HANDLE(handle);
	VALIDATE_NONNULL(host);
	VALIDATE_NONNULL(cmd);
	VALIDATE_NONNULL(length);

	// Any packet has always at least 2 bytes (MID, CID)
	ret = ticables_cable_recv(handle->cable, buf, 2);
	if (!ret)
	{
		*host = buf[0];
		*cmd = buf[1];

		// Any non-TI-80 packet has a length; TI-80 data packets also have a length
		if (*host != DBUS_MID_TI80_PC || *cmd == DBUS_CMD_XDP)
		{
			ret = ticables_cable_recv(handle->cable, buf, 2);
			if (!ret)
			{
				*length = buf[0] | ((uint16_t)buf[1] << 8);
			}
		}
		else
		{
			*length = 0;
		}
	}

	return ret;
}
Esempio n. 4
0
TIEXPORT3 int TICALL dusb_recv(CalcHandle* handle, DUSBRawPacket* pkt)
{
	uint8_t buf[5];
	int ret;

	VALIDATE_HANDLE(handle);
	VALIDATE_NONNULL(pkt);

	// Any packet has always an header of 5 bytes (size & type)
	ticables_progress_reset(handle->cable);
	ret = ticables_cable_recv(handle->cable, buf, 5);
	while (!ret)
	{

		pkt->size = buf[3] | (((uint32_t)buf[2]) << 8) | (((uint32_t)buf[1]) << 16) | (((uint32_t)buf[0]) << 24);
		pkt->type = buf[4];

		if (   (handle->model == CALC_TI84P_USB || handle->model == CALC_TI84PC_USB || handle->model == CALC_TI82A_USB || handle->model == CALC_TI84PT_USB)
		    && pkt->size > 250)
		{
			ticalcs_warning("Raw packet is unexpectedly large: %u bytes", pkt->size);
		}
		else if (   (handle->model == CALC_TI83PCE_USB || handle->model == CALC_TI84PCE_USB)
		         && pkt->size > 1018)
		{
			ticalcs_warning("Raw packet is unexpectedly large: %u bytes", pkt->size);
		}
		else if (handle->model == CALC_TI89T_USB)
		{
			// Fall through.
		}
		// else do nothing for now.

		if (pkt->size > sizeof(pkt->data))
		{
			ticalcs_critical("Raw packet is too large: %u bytes", pkt->size);
			ret = ERR_INVALID_PACKET;
			break;
		}

		//printf("dusb_send: pkt->size=%d\n", pkt->size);
		// Next, follows data
		ret = ticables_cable_recv(handle->cable, pkt->data, pkt->size);
		if (!ret)
		{
			if (pkt->size >= 128)
			{
				ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
			}

			if (handle->updat->cancel)
			{
				ret = ERR_ABORT;
			}
		}
		break;
	}

	return ret;
}
Esempio n. 5
0
static int		recv_cert	(CalcHandle* handle, FlashContent* content)
{
	int ret;
	int i;
	uint8_t buf[256];

	ticalcs_strlcpy(handle->updat->text, _("Receiving certificate"), sizeof(handle->updat->text));
	ticalcs_update_label(handle);

	content->model = handle->model;
	content->name[0] = 0;
	content->data_type = TI83p_CERT;
	content->device_type = 0x73;
	content->num_pages = 0;
	content->data_part = (uint8_t *)tifiles_ve_alloc_data(2 * 1024 * 1024);	// 2MB max

	ret = SEND_REQ2(handle, 0x00, TI83p_GETCERT, "\0\0\0\0\0\0\0", 0x00);
	if (!ret)
	{
		ret = RECV_ACK(handle, NULL);
		if (!ret)
		{
			ret = ticables_cable_recv(handle->cable, buf, 4);	//VAR w/ no header
			if (!ret)
			{
				ticalcs_info(" TI->PC: VAR");
				ret = SEND_ACK(handle);

				for (i = 0, content->data_length = 0; !ret; i++)
				{
					uint16_t block_size;

					ret = SEND_CTS(handle);
					if (!ret)
					{
						ret = RECV_ACK(handle, NULL);
						if (!ret)
						{
							ret = RECV_XDP(handle, &block_size, content->data_part);
							if (!ret)
							{
								ret = SEND_ACK(handle);
								if (!ret)
								{
									content->data_length += block_size;

									handle->updat->cnt2 += block_size;
									ticalcs_update_pbar(handle);
								}
							}
						}
					}
				}
			}
		}
	}

	return ret;
}
Esempio n. 6
0
// Work around TI's OS behaviour: extra bulk read of 0 size required after the last raw packet in a transfer,
// when some conditions are met.
static void workaround_recv(CalcHandle *h, DUSBRawPacket * raw, DUSBVirtualPacket * vtl)
{
	uint8_t buf[64];

	ticalcs_info("workaround_recv: vtl->size=%d\traw->size=%d", vtl->size, raw->size);

	if (h->model == CALC_TI89T_USB)
	{
		if ((raw->size % 64) == 0)
		{
			ticalcs_info("XXX triggering an extra bulk read\n\tvtl->size=%d\traw->size=%d", vtl->size, raw->size);
			ticables_cable_recv(h->cable, buf, 0);
		}
	}
	else // if (h->model == CALC_TI84P_USB)
	{
		if (((raw->size + 5) % 64) == 0)
		{
			ticalcs_info("XXX triggering an extra bulk read\n\tvtl->size=%d\traw->size=%d", vtl->size, raw->size);
			ticables_cable_recv(h->cable, buf, 0);
		}
	}
}
int main(int argc, char **argv)
{
	CableHandle *handle;
	int err;
	//	int i, j;
	//	uint8_t buf[65536], data;
	//	int status, result;
	//	uint8_t scr[3840 + 6];
	//	int **probing = NULL;

 #if 0
	tiTIME ref, end;
	unsigned long k;

	to_START(ref);
	for(k = 0; k < 1000000; k++) printf(" ");
	to_START(end);
	printf("%lu %lu\n", ref, end);
	printf("%lu\n", to_CURRENT(ref));
	printf("%i\n", to_ELAPSED(ref, 60));

	return 0;
#endif

	printf("USB support: %i\n", ticables_is_usb_enabled());

	// init lib
	ticables_library_init();


print_lc_error(1);

#if 0
	ticables_probing_do(&probing, 5, PROBE_ALL);
	for(i = 1; i <= 7; i++) 
		printf("%i: %i %i %i %i\n", i, probing[i][1], probing[i][2], probing[i][3], probing[i][4]);
	ticables_probing_finish(&probing);
#endif

#if 0
	{
		int *list = NULL;
		int i, n;
		int *p;

		ticables_get_usb_devices(&list, &n);
		printf("List of devices:\n");
		for(i = 0; i < n; i++)
		    printf("%i: %04x\n", i, list[i]);
	}
#endif

	// set cable
	handle = ticables_handle_new(CABLE_PAR, PORT_1);
	if(handle == NULL)
	    return -1;

	ticables_options_set_timeout(handle, 15);
	ticables_options_set_delay(handle, 10);
	ticables_handle_show(handle);

	// open cable
	err = ticables_cable_open(handle);
	if(err) print_lc_error(err);
	if(err) return -1;
#if 0
	// simple test with DirectLink hand-helds (buf size req/neg)
	buf[0]=0x00; buf[1]=0x00; buf[2]=0x00; buf[3]=0x04;
	buf[4]=0x01;
	buf[5]=0x00; buf[6]=0x00; buf[7]=0x04; buf[8]=0x00;
	err = ticables_cable_send(handle, buf, 9);
        if(err) print_lc_error(err);

	// display answer
	memset(buf, 0, sizeof(buf));
	err = ticables_cable_recv(handle, buf, 9);
	if(err) print_lc_error(err);

	for(i = 0; i < 9; i++)
	    printf("%02x ", buf[i]);
	printf("\n");
#endif

#if 0
	// mode set
	i = 0;
	buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x10;
	buf[i++]=0x04;
	buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x0a;
	buf[i++]=0x00; buf[i++]=0x01;
	buf[i++]=0x00; buf[i++]=0x03; 
	buf[i++]=0x00; buf[i++]=0x01;
	buf[i++]=0x00; buf[i++]=0x00; 
	buf[i++]=0x00; buf[i++]=0x00; 
	buf[i++]=0x07; buf[i++]=0xd0;

	err = ticables_cable_send(handle, buf, i);
	if(err) print_lc_error(err);

	err = ticables_cable_recv(handle, buf, 7);
	if(err) print_lc_error(err);
	for(i = 0; i < 7; i++)
	    printf("%02x ", buf[i]);
	printf("\n");

	// mode ack
	err = ticables_cable_recv(handle, buf, 15);
	if(err) print_lc_error(err);
	for(i = 0; i < 15; i++)
		printf("%02x ", buf[i]);
	printf("\n");

	i = 0;
	buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x02;
	buf[i++]=0x05;
	buf[i++]=0xe0; buf[i++]=0x00;

	err = ticables_cable_send(handle, buf, i);
	if(err) print_lc_error(err);
	PAUSE(500);
#endif

#if 0
	// param req (TI84+ only)
	i = 0;
	buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0xa;
	buf[i++]=0x04;
	buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x04;
	buf[i++]=0x00; buf[i++]=0x07;
	buf[i++]=0x00; buf[i++]=0x01; 
	buf[i++]=0x00; buf[i++]=0x22;

	err = ticables_cable_send(handle, buf, i);
	if(err) print_lc_error(err);

	err = ticables_cable_recv(handle, buf, 7);
	if(err) print_lc_error(err);
	for(i = 0; i < 7; i++)
		printf("%02x ", buf[i]);
	printf("\n");

	// delay ack
	err = ticables_cable_recv(handle, buf, 15);
	if(err) print_lc_error(err);
	for(i = 0; i < 15; i++)
	    printf("%02x ", buf[i]);
	printf("\n");

	i = 0;
	buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x02;
	buf[i++]=0x05;
	buf[i++]=0xe0; buf[i++]=0x00;

	err = ticables_cable_send(handle, buf, i);
	if(err) print_lc_error(err);

	// param data
	for(j = 0; j < 3; j++)
	{
		err = ticables_cable_recv(handle, buf, 255);
		if(err) print_lc_error(err);
		for(i = 0; i < 16; i++)
			printf("%02x ", buf[i]);
		printf("\n");

		i = 0;
		buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x02;
		buf[i++]=0x05;
		buf[i++]=0xe0; buf[i++]=0x00;

		err = ticables_cable_send(handle, buf, i);
		if(err) print_lc_error(err);
	}
	{
		err = ticables_cable_recv(handle, buf, 36);
		if(err) print_lc_error(err);
		for(i = 0; i < 16; i++)
			printf("%02x ", buf[i]);
		printf("\n");

		i = 0;
		buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x00; buf[i++]=0x02;
		buf[i++]=0x05;
		buf[i++]=0xe0; buf[i++]=0x00;

		err = ticables_cable_send(handle, buf, i);
		if(err) print_lc_error(err);
	}
	PAUSE(500);
#endif

#if 0
	// do a simple test with a TI89/92+ calculator
	buf[0] = 0x08; buf[1] = 0x68; buf[2] = 0x00; buf[3] = 0x00;	// RDY
	err = ticables_cable_send(handle, buf, 4);
	if(err) print_lc_error(err);
	 
	// display answer
	memset(buf, 0xff, 4);
	err = ticables_cable_recv(handle, buf, 4);
	if(err) print_lc_error(err);

	for(i = 0; i < 4; i++)
		printf("%02x ", buf[i]);
	printf("\n");
#endif

#if 0
	// do a screendump
	buf[0] = 0x08;  buf[1] = 0x6D; buf[2] = 0x00; buf[3] = 0x00;	// SCR
	err = ticables_cable_send(handle, buf, 4);
	if(err) print_lc_error(err);
	
	memset(buf, 0xff, 4);
	err = ticables_cable_recv(handle, buf, 4);	// ACK
	if(err) print_lc_error(err);

	err = ticables_cable_recv(handle, scr, 0x0f00 + 6);	// XDP
	if(err) print_lc_error(err);
	printf("%02x %02x\n", scr[2], scr[3]);

	buf[0] = 0x08;  buf[1] = 0x56; buf[2] = 0x00; buf[3] = 0x00;	// ACK
	err = ticables_cable_send(handle, buf, 4);
	if(err) print_lc_error(err);
#endif

#if 0
	// simple test for data arrival detection
	buf[0] = 0x08;  buf[1] = 0x87; buf[2] = 'A'; buf[3] = 0x00;		// KEY
	err = ticables_cable_send(handle, buf, 4);
	if(err) print_lc_error(err);

	for(status = 0; !status;)
	{
		err = ticables_cable_check(handle, &status);
		if(err) print_lc_error(err);
	}

	// display answer
	memset(buf, 0xff, 4);
	err = ticables_cable_recv(handle, buf, 4);
	if(err) print_lc_error(err);

	for(i = 0; i < 4; i++)
		printf("%02x ", buf[i]);
	printf("\n");
#endif

#if 0
	for(status = 0; !status;)
	{
	    //fprintf(stdout, "$\n");
	    //fflush(stdout);
		err = ticables_cable_check(handle, &status);
		if(err) print_lc_error(err);
	}

	// display answer
	memset(buf, 0xff, 4);
	err = ticables_cable_recv(handle, buf, 4);
	if(err) print_lc_error(err);

	for(i = 0; i < 4; i++)
		printf("%02x ", buf[i]);
	printf("\n");
#endif

	// close cable
	ticables_cable_close(handle);
	// release handle
	ticables_handle_del(handle);
	
	// exit lib
	ticables_library_exit();
#ifdef __WIN32__
	while(!kbhit());
#endif
	return 0;
}
Esempio n. 8
0
static int recv_pkt(CalcHandle* handle, uint16_t* cmd, uint16_t* len, uint8_t* data)
{
	int i, r, q;
	uint16_t sum, chksum;

	// Any packet has always at least 4 bytes (cmd, len)
	TRYF(ticables_cable_recv(handle->cable, buf, 4));

	*cmd = (buf[1] << 8) | buf[0];
	*len = (buf[3] << 8) | buf[2];

	if(!cmd_is_valid(*cmd))
		return ERR_INVALID_CMD;

	if(*cmd == CMD_ERROR)
		return ERR_ROM_ERROR;

	// compute chunks
	BLK_SIZE = *len / 20;
	if(BLK_SIZE == 0) BLK_SIZE = 1;

	q = *len / BLK_SIZE;
	r = *len % BLK_SIZE;
	handle->updat->max1 = *len;
	handle->updat->cnt1 = 0;

	// recv full chunks
	for(i = 0; i < q; i++)
	{
		TRYF(ticables_cable_recv(handle->cable, &buf[i*BLK_SIZE + 4], BLK_SIZE));
		ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
		handle->updat->cnt1 += BLK_SIZE;
		if(*len > MIN_SIZE)
			handle->updat->pbar();
		//if (handle->updat->cancel) 
		//	return ERR_ABORT;
	}

	// recv last chunk
	{
		TRYF(ticables_cable_recv(handle->cable, &buf[i*BLK_SIZE + 4], (uint16_t)(r+2)));
		ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
		handle->updat->cnt1 += 1;
		if(*len > MIN_SIZE)
			handle->updat->pbar();
		if (handle->updat->cancel)
			return ERR_ABORT;
	}

	// verify checksum
	chksum = (buf[*len+4 + 1] << 8) | buf[*len+4 + 0];
	sum = tifiles_checksum(buf, *len + 4);
	//printf("<%04x %04x>\n", sum, chksum);

	if (chksum != sum)
		return ERR_CHECKSUM;

	if(data)
		memcpy(data, buf+4, *len);

	return 0;
}
Esempio n. 9
0
static int dbus_recv_(CalcHandle* handle, uint8_t* host, uint8_t* cmd, uint16_t* length, uint8_t* data, int host_check)
{
	int i;
	uint16_t chksum;
	uint8_t buf[4];
	int r, q;
	static int ref = 0;

	if (handle == NULL)
	{
		ticalcs_critical("%s: handle is NULL", __FUNCTION__);
		return ERR_INVALID_HANDLE;
	}
	if (host == NULL || cmd == NULL || length == NULL)
	{
		ticalcs_critical("%s: an argument is NULL", __FUNCTION__);
		return ERR_INVALID_PACKET;
	}

	// Any packet has always at least 2 bytes (MID, CID)
	TRYF(ticables_cable_recv(handle->cable, buf, 2));

	*host = buf[0];
	*cmd = buf[1];

	// Any non-TI80 packet has a length; TI80 data packets also have a length
	if(*host != TI80_PC || *cmd == CMD_XDP)
	{
		TRYF(ticables_cable_recv(handle->cable, buf, 2));

		*length = buf[0] | (buf[1] << 8);
	}
	else *length = 0;

	//removed for probing (pb here !)
	//if(host_check && (*host != host_ids(handle))) 
	//	return ERR_INVALID_HOST;

	if(*cmd == CMD_ERR || *cmd == CMD_ERR2)
		return ERR_CHECKSUM;

	switch (*cmd) 
	{
	case CMD_VAR:	// std packet ( data + checksum)
	case CMD_XDP:
	case CMD_SKP:
	case CMD_SID:
	case CMD_REQ:
	case CMD_IND:
	case CMD_RTS:
		if (data == NULL)
		{
			ticalcs_critical("%s: data is NULL", __FUNCTION__);
			return ERR_INVALID_CMD;
		}

		// compute chunks*
		MIN_SIZE = (handle->cable->model == CABLE_GRY) ? 512 : 2048;
		BLK_SIZE = *length / 20;
		if(BLK_SIZE == 0) BLK_SIZE = 1;

		q = *length / BLK_SIZE;
		r = *length % BLK_SIZE;
		handle->updat->max1 = *length;
		handle->updat->cnt1 = 0;

		// recv full chunks
		for(i = 0; i < q; i++)
		{
			TRYF(ticables_cable_recv(handle->cable, &data[i*BLK_SIZE], BLK_SIZE));
			ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);

			handle->updat->cnt1 += BLK_SIZE;
			if(*length > MIN_SIZE) 
				handle->updat->pbar();

			if (handle->updat->cancel)
				return ERR_ABORT;
		}

		// recv last chunk
		{
			TRYF(ticables_cable_recv(handle->cable, 
						 &data[i*BLK_SIZE], 
						 (uint16_t)r));
			ticables_progress_get(handle->cable, NULL, NULL, 
					      &handle->updat->rate);
			TRYF(ticables_cable_recv(handle->cable, buf, 2));

			handle->updat->cnt1 += 1;
			if(*length > MIN_SIZE) 
				handle->updat->pbar();

			if (handle->updat->cancel)
				return ERR_ABORT;
		}

		// verify checksum
		chksum = buf[0] | (buf[1] << 8);
		if (chksum != tifiles_checksum(data, *length))
			return ERR_CHECKSUM;

		break;
	case CMD_CTS:	// short packet (no data)
	case CMD_ACK:
	case CMD_ERR:
	case CMD_ERR2:
	case CMD_RDY:
	case CMD_SCR:
	case CMD_RID:
	case CMD_KEY:
	case CMD_EOT:
	case CMD_CNT:
		break;
	default:
		return ERR_INVALID_CMD;
	}

	// force periodic refresh
	if(!(ref++ % 4))
		handle->updat->refresh();

	return 0;
}
Esempio n. 10
0
TIEXPORT3 int TICALL dbus_recv_data(CalcHandle *handle, uint16_t* length, uint8_t* data)
{
	int ret;
	int i;
	uint16_t chksum;
	uint8_t buf[4];
	int r, q;

	VALIDATE_HANDLE(handle);
	VALIDATE_NONNULL(length);
	VALIDATE_NONNULL(data);

	// compute chunks
	handle->priv.progress_min_size = (handle->cable->model == CABLE_GRY) ? 512 : 2048;
	handle->priv.progress_blk_size = *length / 20;
	if (handle->priv.progress_blk_size == 0)
	{
		handle->priv.progress_blk_size = 1;
	}

	q = *length / handle->priv.progress_blk_size;
	r = *length % handle->priv.progress_blk_size;
	handle->updat->max1 = *length;
	handle->updat->cnt1 = 0;

	ret = 0;
	// recv full chunks
	for (i = 0; i < q; i++)
	{
		ret = ticables_cable_recv(handle->cable, &data[i*handle->priv.progress_blk_size], handle->priv.progress_blk_size);
		if (ret)
		{
			break;
		}
		ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);

		handle->updat->cnt1 += handle->priv.progress_blk_size;
		if (*length > handle->priv.progress_min_size)
		{
			handle->updat->pbar();
		}

		if (handle->updat->cancel)
		{
			ret = ERR_ABORT;
			break;
		}
	}

	// recv last chunk
	if (!ret)
	{
		ret = ticables_cable_recv(handle->cable, &data[i*handle->priv.progress_blk_size], (uint16_t)r);
		if (!ret)
		{
			ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
			ret = ticables_cable_recv(handle->cable, buf, 2);
			if (!ret)
			{
				handle->updat->cnt1++;
				if (*length > handle->priv.progress_min_size)
				{
					handle->updat->pbar();
				}

				if (handle->updat->cancel)
				{
					ret = ERR_ABORT;
				}
			}
		}
	}

	if (!ret)
	{
		// verify checksum
		chksum = buf[0] | ((uint16_t)buf[1] << 8);
		if (chksum != tifiles_checksum(data, *length))
		{
			ret = ERR_CHECKSUM;
		}
	}

	return ret;
}