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