1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id$ */
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 packets from/to D-BUS.
24 */
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "ticalcs.h"
30 #include "internal.h"
31 #include "dbus_pkt.h"
32 #include "logging.h"
33 #include "error.h"
34
35 // We split packets into chunks to get control regularly and update statistics.
36
37 /*
38 Send a packet from PC (host) to TI (target):
39 - target [in] : a machine ID uint8_t
40 - cmd [in] : a command ID uint8_t
41 - length [in] : length of buffer
42 - data [in] : data to send (or 0x00 if NULL)
43 - int [out] : an error code
44 */
dbus_send(CalcHandle * handle,uint8_t target,uint8_t cmd,uint16_t len,const uint8_t * data)45 TIEXPORT3 int TICALL dbus_send(CalcHandle* handle, uint8_t target, uint8_t cmd, uint16_t len, const uint8_t* data)
46 {
47 int i;
48 uint16_t sum;
49 uint32_t length = (len == 0x0000) ? 65536 : len; // wrap around
50 uint8_t *buf;
51 int r, q;
52 static int ref = 0;
53 int ret;
54
55 VALIDATE_HANDLE(handle);
56
57 buf = (uint8_t *)handle->buffer; //[65536+6];
58 if (buf == NULL)
59 {
60 ticalcs_critical("%s: handle->buffer is NULL", __FUNCTION__);
61 return ERR_INVALID_HANDLE;
62 }
63
64 ticables_progress_reset(handle->cable);
65
66 if (data == NULL)
67 {
68 // short packet (no data)
69 buf[0] = target;
70 buf[1] = cmd;
71 buf[2] = 0x00;
72 buf[3] = 0x00;
73
74 // The TI-80 does not use length
75 ret = ticables_cable_send(handle->cable, buf, (target == DBUS_MID_PC_TI80) ? 2 : 4);
76 }
77 else
78 {
79 // std packet (data + checksum)
80 buf[0] = target;
81 buf[1] = cmd;
82 buf[2] = LSB(length);
83 buf[3] = MSB(length);
84
85 // copy data
86 memcpy(buf+4, data, length);
87
88 // add checksum of packet
89 sum = tifiles_checksum(data, length);
90 buf[length+4+0] = LSB(sum);
91 buf[length+4+1] = MSB(sum);
92
93 // compute chunks
94 handle->priv.progress_min_size = (handle->cable->model == CABLE_GRY) ? 512 : 2048;
95 handle->priv.progress_blk_size = (length + 6) / 20; // 5%
96 if (handle->priv.progress_blk_size == 0)
97 {
98 handle->priv.progress_blk_size = length + 6;
99 }
100 if (handle->priv.progress_blk_size < 32)
101 {
102 handle->priv.progress_blk_size = 128; // SilverLink doesn't like small block (< 32)
103 }
104
105 q = (length + 6) / handle->priv.progress_blk_size;
106 r = (length + 6) % handle->priv.progress_blk_size;
107
108 handle->updat->max1 = length + 6;
109 handle->updat->cnt1 = 0;
110
111 ret = 0;
112
113 // send full chunks
114 for (i = 0; i < q; i++)
115 {
116 ret = ticables_cable_send(handle->cable, &buf[i*handle->priv.progress_blk_size], handle->priv.progress_blk_size);
117 if (ret)
118 {
119 break;
120 }
121 ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
122
123 handle->updat->cnt1 += handle->priv.progress_blk_size;
124 if (length > handle->priv.progress_min_size)
125 {
126 handle->updat->pbar();
127 }
128
129 if (handle->updat->cancel)
130 {
131 ret = ERR_ABORT;
132 break;
133 }
134 }
135
136 // send last chunk
137 if (!ret)
138 {
139 ret = ticables_cable_send(handle->cable, &buf[i*handle->priv.progress_blk_size], (uint16_t)r);
140 if (!ret)
141 {
142 ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
143
144 handle->updat->cnt1 += 1;
145 if (length > handle->priv.progress_min_size)
146 {
147 handle->updat->pbar();
148 }
149
150 if (handle->updat->cancel)
151 {
152 ret = ERR_ABORT;
153 }
154 }
155 }
156 }
157
158 // force periodic refresh
159 if (!ret && !(ref++ % 4))
160 {
161 handle->updat->refresh();
162 }
163
164 return ret;
165 }
166
dbus_recv_header(CalcHandle * handle,uint8_t * host,uint8_t * cmd,uint16_t * length)167 TIEXPORT3 int TICALL dbus_recv_header(CalcHandle *handle, uint8_t* host, uint8_t* cmd, uint16_t* length)
168 {
169 int ret;
170 uint8_t buf[4];
171
172 VALIDATE_HANDLE(handle);
173 VALIDATE_NONNULL(host);
174 VALIDATE_NONNULL(cmd);
175 VALIDATE_NONNULL(length);
176
177 // Any packet has always at least 2 bytes (MID, CID)
178 ret = ticables_cable_recv(handle->cable, buf, 2);
179 if (!ret)
180 {
181 *host = buf[0];
182 *cmd = buf[1];
183
184 // Any non-TI-80 packet has a length; TI-80 data packets also have a length
185 if (*host != DBUS_MID_TI80_PC || *cmd == DBUS_CMD_XDP)
186 {
187 ret = ticables_cable_recv(handle->cable, buf, 2);
188 if (!ret)
189 {
190 *length = buf[0] | ((uint16_t)buf[1] << 8);
191 }
192 }
193 else
194 {
195 *length = 0;
196 }
197 }
198
199 return ret;
200 }
201
dbus_recv_data(CalcHandle * handle,uint16_t * length,uint8_t * data)202 TIEXPORT3 int TICALL dbus_recv_data(CalcHandle *handle, uint16_t* length, uint8_t* data)
203 {
204 int ret;
205 int i;
206 uint16_t chksum;
207 uint8_t buf[4];
208 int r, q;
209
210 VALIDATE_HANDLE(handle);
211 VALIDATE_NONNULL(length);
212 VALIDATE_NONNULL(data);
213
214 // compute chunks
215 handle->priv.progress_min_size = (handle->cable->model == CABLE_GRY) ? 512 : 2048;
216 handle->priv.progress_blk_size = *length / 20;
217 if (handle->priv.progress_blk_size == 0)
218 {
219 handle->priv.progress_blk_size = 1;
220 }
221
222 q = *length / handle->priv.progress_blk_size;
223 r = *length % handle->priv.progress_blk_size;
224 handle->updat->max1 = *length;
225 handle->updat->cnt1 = 0;
226
227 ret = 0;
228 // recv full chunks
229 for (i = 0; i < q; i++)
230 {
231 ret = ticables_cable_recv(handle->cable, &data[i*handle->priv.progress_blk_size], handle->priv.progress_blk_size);
232 if (ret)
233 {
234 break;
235 }
236 ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
237
238 handle->updat->cnt1 += handle->priv.progress_blk_size;
239 if (*length > handle->priv.progress_min_size)
240 {
241 handle->updat->pbar();
242 }
243
244 if (handle->updat->cancel)
245 {
246 ret = ERR_ABORT;
247 break;
248 }
249 }
250
251 // recv last chunk
252 if (!ret)
253 {
254 ret = ticables_cable_recv(handle->cable, &data[i*handle->priv.progress_blk_size], (uint16_t)r);
255 if (!ret)
256 {
257 ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
258 ret = ticables_cable_recv(handle->cable, buf, 2);
259 if (!ret)
260 {
261 handle->updat->cnt1++;
262 if (*length > handle->priv.progress_min_size)
263 {
264 handle->updat->pbar();
265 }
266
267 if (handle->updat->cancel)
268 {
269 ret = ERR_ABORT;
270 }
271 }
272 }
273 }
274
275 if (!ret)
276 {
277 // verify checksum
278 chksum = buf[0] | ((uint16_t)buf[1] << 8);
279 if (chksum != tifiles_checksum(data, *length))
280 {
281 ret = ERR_CHECKSUM;
282 }
283 }
284
285 return ret;
286 }
287
288 /*
289 Receive a packet from TI (target) to PC (host):
290 - host [out] : a machine ID uint8_t
291 - cmd [out] : a command ID uint8_t
292 - length [out] : length of buffer
293 - data [out] : received data (depending on command)
294 - int [out] : an error code
295 */
dbus_recv(CalcHandle * handle,uint8_t * host,uint8_t * cmd,uint16_t * length,uint8_t * data)296 TIEXPORT3 int TICALL dbus_recv(CalcHandle* handle, uint8_t* host, uint8_t* cmd, uint16_t* length, uint8_t* data)
297 {
298 static int ref = 0;
299 int ret;
300
301 ret = dbus_recv_header(handle, host, cmd, length);
302 if (!ret)
303 {
304 if (*cmd == DBUS_CMD_ERR || *cmd == DBUS_CMD_ERR2)
305 {
306 return ERR_CHECKSUM; // THIS RETURNS !
307 }
308
309 switch (*cmd)
310 {
311 case DBUS_CMD_VAR: // std packet ( data + checksum)
312 case DBUS_CMD_XDP:
313 case DBUS_CMD_SKP:
314 case DBUS_CMD_SID:
315 case DBUS_CMD_REQ:
316 case DBUS_CMD_IND:
317 case DBUS_CMD_RTS:
318 ret = dbus_recv_data(handle, length, data);
319 break;
320 case DBUS_CMD_CTS: // short packet (no data)
321 case DBUS_CMD_ACK:
322 case DBUS_CMD_ERR:
323 case DBUS_CMD_ERR2:
324 case DBUS_CMD_RDY:
325 case DBUS_CMD_SCR:
326 case DBUS_CMD_RID:
327 case DBUS_CMD_KEY:
328 case DBUS_CMD_EOT:
329 case DBUS_CMD_CNT:
330 break;
331 default:
332 return ERR_INVALID_CMD; // THIS RETURNS !
333 }
334
335 if (!ret && !(ref++ % 4))
336 {
337 // force periodic refresh
338 handle->updat->refresh();
339 }
340 }
341
342 return ret;
343 }
344