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