1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id: packets.c 1404 2005-07-20 20:39:39Z roms $ */
3 
4 /*  libticalcs - Ti Calculator library, a part of the TiLP project
5  *  Copyright (C) 2007 Romain Li�vin
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software Foundation,
19  *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /*
23 	This unit manages raw packets from/to NSpire thru DirectLink cable.
24 	Documentation & credits can be found at <http://hackspire.unsads.com/USB_Protocol>.
25 */
26 
27 #include <stdio.h>
28 #include <string.h>
29 
30 #include "ticalcs.h"
31 #include "internal.h"
32 #include "logging.h"
33 #include "error.h"
34 
35 #define VPKT_DBG	1	// 1 = verbose, 2 = more verbose
36 
37 // CRC implementation from O. Armand (ExtendeD)
compute_crc(uint8_t * data,uint32_t size)38 static uint16_t compute_crc(uint8_t *data, uint32_t size)
39 {
40 	uint16_t acc = 0;
41 	uint32_t i;
42 
43 	if (size == 0)
44 	{
45 		return 0;
46 	}
47 
48 	for (i = 0; i < size; i++)
49 	{
50 		uint16_t first, second, third;
51 
52 		first = (((uint16_t)data[i]) << 8) | (acc >> 8);
53 		acc &= 0xff;
54 		second = (((acc & 0x0f) << 4) ^ acc) << 8;
55 		third = second >> 5;
56 		acc = third >> 7;
57 		acc = (acc ^ first ^ second ^ third);
58 	}
59 
60 	return acc;
61 }
62 
hexdump(uint8_t * data,uint32_t size)63 static int hexdump(uint8_t *data, uint32_t size)
64 {
65 #if (VPKT_DBG == 1)
66 	char str[64];
67 	uint32_t i;
68 
69 	str[0] = 0;
70 	if (size <= 12)
71 	{
72 		str[0] = ' '; str[1] = ' '; str[2] = ' '; str[3] = ' ';
73 
74 		for (i = 0; i < size; i++)
75 		{
76 			sprintf(&str[3*i+4], "%02X ", data[i]);
77 		}
78 	}
79 	else
80 	{
81 		sprintf(str, "    %02X %02X %02X %02X %02X ..... %02X %02X %02X %02X %02X",
82 		             data[0], data[1], data[2], data[3], data[4],
83 		             data[size-5], data[size-4], data[size-3], data[size-2], data[size-1]);
84 	}
85 	ticalcs_info("%s", str);
86 #endif
87 #if (VPKT_DBG == 2)
88 	char *str = (char *)g_malloc(3*size + 8 + 10);
89 	uint32_t i, j, k;
90 	int step = 12;
91 
92 	for (k = 0; k < 4; k++)
93 	{
94 		str[k] = ' ';
95 	}
96 
97 	for (i = j = 0; i < size; i++, j++)
98 	{
99 		if (i && !(i % step))
100 		{
101 			ticalcs_info(str);
102 			j = 0;
103 		}
104 
105 		sprintf(&str[3*j+4], "%02X ", data[i]);
106 	}
107 	ticalcs_info("%s", str);
108 
109 	g_free(str);
110 #endif
111 	return 0;
112 }
113 
nsp_send(CalcHandle * handle,NSPRawPacket * pkt)114 TIEXPORT3 int TICALL nsp_send(CalcHandle* handle, NSPRawPacket* pkt)
115 {
116 	uint8_t buf[sizeof(NSPRawPacket)] = { 0 };
117 	uint32_t size;
118 	int ret;
119 
120 	VALIDATE_HANDLE(handle);
121 	VALIDATE_NONNULL(pkt);
122 
123 	size = pkt->data_size + NSP_HEADER_SIZE;
124 	pkt->data_sum = compute_crc(pkt->data, pkt->data_size);
125 
126 	if (pkt->src_port == 0x00fe || pkt->src_port == 0x00ff || pkt->src_port == 0x00d3)
127 	{
128 		pkt->ack = 0x0a;
129 		pkt->seq = handle->priv.nsp_seq;
130 	}
131 	else
132 	{
133 		if (!handle->priv.nsp_seq_pc)
134 		{
135 			handle->priv.nsp_seq_pc++;
136 		}
137 		pkt->seq = handle->priv.nsp_seq_pc;
138 	}
139 
140 	ticalcs_info("   %04x:%04x->%04x:%04x AK=%02x SQ=%02x HC=%02x DC=%04x (%i bytes)",
141 			pkt->src_addr, pkt->src_port, pkt->dst_addr, pkt->dst_port,
142 			pkt->ack, pkt->seq, pkt->hdr_sum, pkt->data_sum, pkt->data_size);
143 	if (pkt->data_size)
144 	{
145 		hexdump(pkt->data, pkt->data_size);
146 	}
147 
148 	buf[0] = 0x54;
149 	buf[1] = 0xFD;
150 	buf[2] = MSB(pkt->src_addr);
151 	buf[3] = LSB(pkt->src_addr);
152 	buf[4] = MSB(pkt->src_port);
153 	buf[5] = LSB(pkt->src_port);
154 	buf[6] = MSB(pkt->dst_addr);
155 	buf[7] = LSB(pkt->dst_addr);
156 	buf[8] = MSB(pkt->dst_port);
157 	buf[9] = LSB(pkt->dst_port);
158 	buf[10] = MSB(pkt->data_sum);
159 	buf[11] = LSB(pkt->data_sum);
160 	buf[12] = pkt->data_size;
161 	buf[13] = pkt->ack;
162 	buf[14] = pkt->seq;
163 	buf[15] = pkt->hdr_sum = tifiles_checksum(buf, NSP_HEADER_SIZE-1) & 0xff;
164 
165 	memcpy(buf + NSP_HEADER_SIZE, pkt->data, pkt->data_size);
166 
167 	ticables_progress_reset(handle->cable);
168 	ret = ticables_cable_send(handle->cable, buf, size);
169 	if (!ret)
170 	{
171 		if (size >= 128)
172 		{
173 			ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
174 		}
175 
176 		if (handle->updat->cancel)
177 		{
178 			ret = ERR_ABORT;
179 		}
180 	}
181 
182 	return ret;
183 }
184 
nsp_recv(CalcHandle * handle,NSPRawPacket * pkt)185 TIEXPORT3 int TICALL nsp_recv(CalcHandle* handle, NSPRawPacket* pkt)
186 {
187 	uint8_t buf[NSP_HEADER_SIZE];
188 	int ret;
189 
190 	VALIDATE_HANDLE(handle);
191 	VALIDATE_NONNULL(pkt);
192 
193 	ticables_progress_reset(handle->cable);
194 	ret = ticables_cable_recv(handle->cable, buf, NSP_HEADER_SIZE);
195 	while (!ret)
196 	{
197 		pkt->unused    = (((uint16_t)buf[0]) << 8) | buf[1];
198 		pkt->src_addr  = (((uint16_t)buf[2]) << 8) | buf[3];
199 		pkt->src_port  = (((uint16_t)buf[4]) << 8) | buf[5];
200 		pkt->dst_addr  = (((uint16_t)buf[6]) << 8) | buf[7];
201 		pkt->dst_port  = (((uint16_t)buf[8]) << 8) | buf[9];
202 		pkt->data_sum  = (((uint16_t)buf[10]) << 8) | buf[11];
203 		pkt->data_size = buf[12];
204 		pkt->ack       = buf[13];
205 		pkt->seq       = buf[14];
206 		pkt->hdr_sum   = buf[15];
207 
208 		if (pkt->src_port == 0x00fe || pkt->src_port == 0x00ff || pkt->src_port == 0x00d3)
209 		{
210 			handle->priv.nsp_seq_pc++;
211 		}
212 		else
213 		{
214 			handle->priv.nsp_seq = pkt->seq;
215 		}
216 
217 		// Next, follows data
218 		if (pkt->data_size)
219 		{
220 			ret = ticables_cable_recv(handle->cable, pkt->data, pkt->data_size);
221 			if (ret)
222 			{
223 				break;
224 			}
225 
226 			if (pkt->data_size >= 128)
227 			{
228 				ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
229 			}
230 		}
231 
232 		if (handle->updat->cancel)
233 		{
234 			ret = ERR_ABORT;
235 			break;
236 		}
237 
238 		ticalcs_info("   %04x:%04x->%04x:%04x AK=%02x SQ=%02x HC=%02x DC=%04x (%i bytes)",
239 		             pkt->src_addr, pkt->src_port, pkt->dst_addr, pkt->dst_port,
240 		             pkt->ack, pkt->seq, pkt->hdr_sum, pkt->data_sum, pkt->data_size);
241 		if (pkt->data_size)
242 		{
243 			hexdump(pkt->data, pkt->data_size);
244 		}
245 
246 		break;
247 	}
248 
249 	return ret;
250 }
251