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) 1999-2005 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 D-USB (DirectLink).
24 */
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "ticalcs.h"
30 #include "internal.h"
31 #include "dusb_rpkt.h"
32 #include "dusb_vpkt.h"
33 #include "logging.h"
34 #include "error.h"
35
36 typedef struct
37 {
38 uint8_t id;
39 uint8_t data_hdr;
40 uint8_t data;
41 const char* name;
42 } DUSBRawPacketInfo;
43
44 static const DUSBRawPacketInfo dusbrawpackets[] =
45 {
46 { DUSB_RPKT_BUF_SIZE_REQ, 0, 4, "Buffer Size Request" },
47 { DUSB_RPKT_BUF_SIZE_ALLOC, 0, 4, "Buffer Size Allocation" },
48 { DUSB_RPKT_VIRT_DATA, 1, 6, "Virtual Packet Data with Continuation" },
49 { DUSB_RPKT_VIRT_DATA_LAST, 1, 6, "Virtual Packet Data Final" },
50 { DUSB_RPKT_VIRT_DATA_ACK, 0, 2, "Virtual Packet Data Acknowledgement" }
51 };
52
dusb_rpkt_type2name(uint8_t id)53 TIEXPORT3 const char* TICALL dusb_rpkt_type2name(uint8_t id)
54 {
55 unsigned int i;
56
57 for (i = 0; i < sizeof(dusbrawpackets) / sizeof(dusbrawpackets[0]); i++)
58 {
59 if (id == dusbrawpackets[i].id)
60 {
61 return dusbrawpackets[i].name;
62 }
63 }
64
65 return "";
66 }
67
dusb_send(CalcHandle * handle,DUSBRawPacket * pkt)68 TIEXPORT3 int TICALL dusb_send(CalcHandle* handle, DUSBRawPacket* pkt)
69 {
70 uint8_t buf[sizeof(pkt->data) + 5];
71 uint32_t size;
72 int ret;
73
74 VALIDATE_HANDLE(handle);
75 VALIDATE_NONNULL(pkt);
76
77 memset(buf, 0, sizeof(buf));
78 size = pkt->size;
79
80 if (size > sizeof(pkt->data))
81 {
82 size = sizeof(pkt->data);
83 }
84
85 buf[0] = MSB(MSW(size));
86 buf[1] = LSB(MSW(size));
87 buf[2] = MSB(LSW(size));
88 buf[3] = LSB(LSW(size));
89 buf[4] = pkt->type;
90 memcpy(buf + 5, pkt->data, size);
91
92 //printf("dusb_send: pkt->size=%d\n", pkt->size);
93 ticables_progress_reset(handle->cable);
94 ret = ticables_cable_send(handle->cable, buf, size + 5);
95 if (!ret)
96 {
97 if (size >= 128)
98 {
99 ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
100 }
101
102 if (handle->updat->cancel)
103 {
104 ret = ERR_ABORT;
105 }
106 }
107
108 return ret;
109 }
110
dusb_recv(CalcHandle * handle,DUSBRawPacket * pkt)111 TIEXPORT3 int TICALL dusb_recv(CalcHandle* handle, DUSBRawPacket* pkt)
112 {
113 uint8_t buf[5];
114 int ret;
115
116 VALIDATE_HANDLE(handle);
117 VALIDATE_NONNULL(pkt);
118
119 // Any packet has always an header of 5 bytes (size & type)
120 ticables_progress_reset(handle->cable);
121 ret = ticables_cable_recv(handle->cable, buf, 5);
122 while (!ret)
123 {
124
125 pkt->size = buf[3] | (((uint32_t)buf[2]) << 8) | (((uint32_t)buf[1]) << 16) | (((uint32_t)buf[0]) << 24);
126 pkt->type = buf[4];
127
128 if ( (handle->model == CALC_TI84P_USB || handle->model == CALC_TI84PC_USB || handle->model == CALC_TI82A_USB || handle->model == CALC_TI84PT_USB)
129 && pkt->size > 250)
130 {
131 ticalcs_warning("Raw packet is unexpectedly large: %u bytes", pkt->size);
132 }
133 else if ( (handle->model == CALC_TI83PCE_USB || handle->model == CALC_TI84PCE_USB)
134 && pkt->size > 1018)
135 {
136 ticalcs_warning("Raw packet is unexpectedly large: %u bytes", pkt->size);
137 }
138 else if (handle->model == CALC_TI89T_USB)
139 {
140 // Fall through.
141 }
142 // else do nothing for now.
143
144 if (pkt->size > sizeof(pkt->data))
145 {
146 ticalcs_critical("Raw packet is too large: %u bytes", pkt->size);
147 ret = ERR_INVALID_PACKET;
148 break;
149 }
150
151 //printf("dusb_send: pkt->size=%d\n", pkt->size);
152 // Next, follows data
153 ret = ticables_cable_recv(handle->cable, pkt->data, pkt->size);
154 if (!ret)
155 {
156 if (pkt->size >= 128)
157 {
158 ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
159 }
160
161 if (handle->updat->cancel)
162 {
163 ret = ERR_ABORT;
164 }
165 }
166 break;
167 }
168
169 return ret;
170 }
171
ep_way(uint8_t ep)172 static const char* ep_way(uint8_t ep)
173 {
174 if (ep == 0x01)
175 {
176 return "TI>PC";
177 }
178 else if (ep == 0x02)
179 {
180 return "PC>TI";
181 }
182 else
183 {
184 return "XX>XX";
185 }
186 }
187
dusb_dissect(CalcModel model,FILE * f,const uint8_t * data,uint32_t len,uint8_t ep,uint8_t * first)188 TIEXPORT3 int TICALL dusb_dissect(CalcModel model, FILE * f, const uint8_t * data, uint32_t len, uint8_t ep, uint8_t * first)
189 {
190 int ret = 0;
191 uint32_t raw_size;
192 uint8_t raw_type;
193
194 VALIDATE_NONNULL(f);
195 VALIDATE_NONNULL(data);
196 VALIDATE_NONNULL(first);
197
198 if (len < 5 || len > sizeof(((DUSBRawPacket *)0)->data))
199 {
200 ticalcs_critical("Length %lu (%lX) is too small or too large for a valid DUSB raw packet", (unsigned long)len, (unsigned long)len);
201 return ERR_INVALID_PACKET;
202 }
203
204 raw_size = (((uint32_t)(data[0])) << 24) | (((uint32_t)(data[1])) << 16) | (((uint32_t)(data[2])) << 8) | ((uint32_t)(data[3]));
205 raw_type = data[4];
206
207 fprintf(f, "%08lX (%02X)\t\t\t\t\t\t\t| %s: %s\n", (unsigned long)raw_size, (unsigned int)raw_type, ep_way(ep), dusb_rpkt_type2name(raw_type));
208
209 if (raw_size > sizeof(((DUSBRawPacket *)0)->data) - 5)
210 {
211 ticalcs_critical("Raw size %lu (%lX) is too large for a valid DUSB raw packet", (unsigned long)raw_size, (unsigned long)raw_size);
212 return ERR_INVALID_PACKET;
213 }
214
215 if (raw_type < 1 || raw_type > 5)
216 {
217 ticalcs_critical("Raw type unknown in DUSB raw packet");
218 return ERR_INVALID_PACKET;
219 }
220
221 if (len < 5U + dusbrawpackets[raw_type - 1].data)
222 {
223 ticalcs_critical("Length %ld is too small for a valid data part in DUSB raw packet of type %u", (unsigned long)len, raw_type);
224 return ERR_INVALID_PACKET;
225 }
226
227 switch (raw_type)
228 {
229 case DUSB_RPKT_BUF_SIZE_REQ:
230 case DUSB_RPKT_BUF_SIZE_ALLOC:
231 {
232 uint32_t tmp = (((uint32_t)(data[5])) << 24) | (((uint32_t)(data[6])) << 16) | (((uint32_t)(data[7])) << 8) | ((uint32_t)(data[8]));
233 fprintf(f, "\t[%08lX]\n", (unsigned long)tmp);
234 if (len != 5U + 4)
235 {
236 fputs("(unexpected size for a packet of that type)\n", f);
237 }
238 }
239 break;
240
241 case DUSB_RPKT_VIRT_DATA:
242 case DUSB_RPKT_VIRT_DATA_LAST:
243 {
244 if (*first)
245 {
246 uint32_t vtl_size = (((uint32_t)(data[5])) << 24) | (((uint32_t)(data[6])) << 16) | (((uint32_t)(data[7])) << 8) | ((uint32_t)(data[8]));
247 uint16_t vtl_type = (((uint16_t)(data[9])) << 8) | ((uint16_t)(data[10]));
248 fprintf(f, "\t%08lX {%04X}\t\t\t\t\t\t| CMD: %s\n", (unsigned long)vtl_size, vtl_type, dusb_vpkt_type2name(vtl_type));
249
250 if (vtl_size != raw_size - 6)
251 {
252 fputs("(unexpected size for a packet of that type)\n", f);
253 }
254
255 if (!vtl_size)
256 {
257 fputs("(no data to dissect)\n", f);
258 }
259 else
260 {
261 uint32_t i;
262 data += 11;
263 len -= 11;
264 if (len < vtl_size)
265 {
266 fputs("(packet truncated: insufficient given length)\n", f);
267 }
268 else if (len > vtl_size)
269 {
270 fputs("(given length larger than length in packet)\n", f);
271 }
272 fprintf(f, "\t\t");
273 for (i = 0; i < len;)
274 {
275 fprintf(f, "%02X ", *data++);
276 if (!(++i & 15))
277 {
278 fprintf(f, "\n\t\t");
279 }
280 }
281 data -= vtl_size;
282 fputc('\n', f);
283 ret = dusb_dissect_cmd_data(model, f, data, len, vtl_size, vtl_type);
284 if (ret)
285 {
286 fputs("(inner data dissection had a problem with the packet)\n", f);
287 }
288 }
289 }
290 else
291 {
292 uint32_t i;
293 fprintf(f, "\t%02X %02X %02X ", data[5], data[6], data[7]);
294 data += 8;
295 len -= 8;
296 if (len < raw_size - 3)
297 {
298 fputs("(packet truncated: insufficient given length)\n", f);
299 raw_size = len;
300 }
301 else if (len > raw_size - 3)
302 {
303 fputs("(given length larger than length in packet)\n", f);
304 }
305 for (i = 0; i < len;)
306 {
307 fprintf(f, "%02X ", *data++);
308 if (!(++i & 15))
309 {
310 fprintf(f, "\n\t\t");
311 }
312 }
313 fputc('\n', f);
314 }
315 *first = (raw_type == DUSB_RPKT_VIRT_DATA) ? 0 : 1;
316 }
317 break;
318
319
320 case DUSB_RPKT_VIRT_DATA_ACK:
321 {
322 uint16_t tmp = (((uint16_t)(data[5])) << 8) | ((uint16_t)(data[6]));
323 fprintf(f, "\t[%04X]\n", tmp);
324 if (len != 5 + 2)
325 {
326 fputs("(unexpected size for a packet of that type)\n", f);
327 }
328 }
329 break;
330 }
331
332 return ret;
333 }
334