1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id$ */
3 
4 /*  libticalcs2 - hand-helds support 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 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #if defined(__WIN32__)
31 #include <windows.h>
32 #endif
33 #include <locale.h>
34 
35 #include "gettext.h"
36 #include "ticalcs.h"
37 #include "internal.h"
38 #include "logging.h"
39 #include "error.h"
40 #include "calc_xx.h"
41 
42 /*****************/
43 /* Internal data */
44 /*****************/
45 
46 extern const CalcUpdate default_update;
47 
48 static CalcFncts const *const calcs[] =
49 {
50 	&calc_00,
51 #ifndef NO_TI73
52 	&calc_73,
53 #endif
54 #ifndef NO_TI82
55 	&calc_82,
56 #endif
57 #ifndef NO_TI83
58 	&calc_83,
59 #endif
60 #ifndef NO_TI83P
61 	&calc_83p,
62 #endif
63 #ifndef NO_TI84P
64 	&calc_84p,
65 #endif
66 #ifndef NO_TI85
67 	&calc_85,
68 #endif
69 #ifndef NO_TI86
70 	&calc_86,
71 #endif
72 #ifndef NO_TI89
73 	&calc_89,
74 #endif
75 #ifndef NO_TI89T
76 	&calc_89t,
77 #endif
78 #ifndef NO_TI92
79 	&calc_92,
80 #endif
81 #ifndef NO_TI92P
82 	&calc_92p,
83 #endif
84 #ifndef NO_V200
85 	&calc_v2,
86 #endif
87 #ifndef NO_TI84P_USB
88 	&calc_84p_usb,
89 #endif
90 #ifndef NO_TI89T_USB
91 	&calc_89t_usb,
92 #endif
93 #ifndef NO_NSPIRE
94 	&calc_nsp,
95 #endif
96 #ifndef NO_TI80
97 	&calc_80,
98 #endif
99 #ifndef NO_TI84PC
100 	&calc_84pcse,
101 #endif
102 #ifndef NO_TI84PC_USB
103 	&calc_84pcse_usb,
104 #endif
105 #ifndef NO_TI83PCE_USB
106 	&calc_83pce_usb,
107 #endif
108 #ifndef NO_TI84PCE_USB
109 	&calc_84pce_usb,
110 #endif
111 #ifndef NO_TI82A_USB
112 	&calc_82a_usb,
113 #endif
114 #ifndef NO_TI84PT_USB
115 	&calc_84pt_usb,
116 #endif
117 	NULL
118 };
119 
120 static const uint32_t supported_calcs =
121 	  (1U << CALC_NONE)
122 #ifndef NO_TI73
123 	| (1U << CALC_TI73)
124 #endif
125 #ifndef NO_TI82
126 	| (1U << CALC_TI82)
127 #endif
128 #ifndef NO_TI83
129 	| (1U << CALC_TI83)
130 #endif
131 #ifndef NO_TI83P
132 	| (1U << CALC_TI83P)
133 #endif
134 #ifndef NO_TI84P
135 	| (1U << CALC_TI84P)
136 #endif
137 #ifndef NO_TI85
138 	| (1U << CALC_TI85)
139 #endif
140 #ifndef NO_TI86
141 	| (1U << CALC_TI86)
142 #endif
143 #ifndef NO_TI89
144 	| (1U << CALC_TI89)
145 #endif
146 #ifndef NO_TI89T
147 	| (1U << CALC_TI89T)
148 #endif
149 #ifndef NO_TI92
150 	| (1U << CALC_TI92)
151 #endif
152 #ifndef NO_TI92P
153 	| (1U << CALC_TI92P)
154 #endif
155 #ifndef NO_V200
156 	| (1U << CALC_V200)
157 #endif
158 #ifndef NO_TI84P_USB
159 	| (1U << CALC_TI84P_USB)
160 #endif
161 #ifndef NO_TI89T_USB
162 	| (1U << CALC_TI89T_USB)
163 #endif
164 #ifndef NO_NSPIRE
165 	| (1U << CALC_NSPIRE)
166 #endif
167 #ifndef NO_TI80
168 	| (1U << CALC_TI80)
169 #endif
170 #ifndef NO_TI84PC
171 	| (1U << CALC_TI84PC)
172 #endif
173 #ifndef NO_TI84PC_USB
174 	| (1U << CALC_TI84PC_USB)
175 #endif
176 #ifndef NO_TI83PCE_USB
177 	| (1U << CALC_TI83PCE_USB)
178 #endif
179 #ifndef NO_TI84PCE_USB
180 	| (1U << CALC_TI84PCE_USB)
181 #endif
182 #ifndef NO_TI82A_USB
183 	| (1U << CALC_TI82A_USB)
184 #endif
185 #ifndef NO_TI84PT_USB
186 	| (1U << CALC_TI84PT_USB)
187 #endif
188 ;
189 
190 /****************/
191 /* Entry points */
192 /****************/
193 
194 // not static, must be shared between instances
195 int ticalcs_instance = 0;	// counts # of instances
196 
197 /**
198  * ticalcs_library_init:
199  *
200  * This function must be the first one to call. It inits library internals.
201  *
202  * Return value: the instance count.
203  **/
ticalcs_library_init(void)204 TIEXPORT3 int TICALL ticalcs_library_init(void)
205 {
206 	char locale_dir[65536 + 20];
207 
208 #ifdef __WIN32__
209 	HANDLE hDll;
210 	int i;
211 
212 	hDll = GetModuleHandle("libticalcs2-12.dll");
213 	GetModuleFileName(hDll, locale_dir, sizeof(locale_dir) - 21);
214 
215 	for (i = strlen(locale_dir); i >= 0; i--)
216 	{
217 		if (locale_dir[i] == '\\')
218 		{
219 			break;
220 		}
221 	}
222 	locale_dir[i] = '\0';
223 
224 #ifdef __MINGW32__
225 	strcat(locale_dir, "\\..\\share\\locale");
226 #else
227 	strcat(locale_dir, "\\locale");
228 #endif
229 #else
230 	strncpy(locale_dir, LOCALEDIR, sizeof(locale_dir) - 21);
231 	locale_dir[sizeof(locale_dir) - 21] = 0;
232 #endif
233 
234 	if (ticalcs_instance)
235 	{
236 		return (++ticalcs_instance);
237 	}
238 	ticalcs_info(_("ticalcs library version %s"), LIBCALCS_VERSION);
239 	errno = 0;
240 
241 #if defined(ENABLE_NLS)
242 	ticalcs_info("setlocale: %s", setlocale(LC_ALL, ""));
243 	ticalcs_info("bindtextdomain: %s", bindtextdomain(PACKAGE, locale_dir));
244 	bind_textdomain_codeset(PACKAGE, "UTF-8"/*"ISO-8859-15"*/);
245 	ticalcs_info("textdomain: %s", textdomain(NULL));
246 #endif
247 
248 	return (++ticalcs_instance);
249 }
250 
251 
252 /**
253  * ticalcs_library_exit:
254  *
255  * This function must be the last one to call. Used to release internal resources.
256  *
257  * Return value: the instance count.
258  **/
ticalcs_library_exit(void)259 TIEXPORT3 int TICALL ticalcs_library_exit(void)
260 {
261 	return (--ticalcs_instance);
262 }
263 
264 /***********/
265 /* Methods */
266 /***********/
267 
268 /**
269  * ticalcs_version_get:
270  *
271  * This function returns the library version like "X.Y.Z".
272  *
273  * Return value: a string.
274  **/
ticalcs_version_get(void)275 TIEXPORT3 const char *TICALL ticalcs_version_get(void)
276 {
277 	return LIBCALCS_VERSION;
278 }
279 
280 /**
281  * ticalcs_supported_calcs:
282  *
283  * This function returns the calcs built into the current binary.
284  *
285  * Return value: an integer containing a binary OR of (1 << CALC_*) values,
286  * where CALC_* values are defined in enum CalcModel.
287  **/
ticalcs_supported_calcs(void)288 TIEXPORT3 uint32_t TICALL ticalcs_supported_calcs (void)
289 {
290 	return supported_calcs;
291 }
292 
293 /**
294  * ticalcs_handle_new:
295  * @model: a hand-held model
296  *
297  * Create a new handle associated with the given cable on the given port.
298  * Must be freed with ticables_handle_del when no longer needed.
299  * Note: the handle is a pointer on an opaque structure and should not be modified.
300  *
301  * Return value: NULL if error, an handle otherwise.
302  **/
ticalcs_handle_new(CalcModel model)303 TIEXPORT3 CalcHandle* TICALL ticalcs_handle_new(CalcModel model)
304 {
305 	CalcHandle *handle = NULL;
306 	CalcFncts * calc = NULL;
307 	unsigned int i;
308 
309 	for (i = 0; i < sizeof(calcs) / sizeof(calcs[0]) - 1; i++) // - 1 for the terminating NULL.
310 	{
311 		if (calcs[i]->model == (int const)model)
312 		{
313 			calc = (CalcFncts *)calcs[i];
314 			break;
315 		}
316 	}
317 
318 	if (calc != NULL)
319 	{
320 		handle = (CalcHandle *)g_malloc0(sizeof(CalcHandle));
321 		if (handle != NULL)
322 		{
323 			handle->model = model;
324 			handle->calc = calc;
325 			handle->updat = (CalcUpdate *)&default_update;
326 
327 			handle->priv.nsp_src_port = 0x8001;
328 			handle->priv.nsp_dst_port = 0x4003; // NSP_PORT_ADDR_REQUEST
329 
330 			handle->buffer = (uint8_t *)g_malloc(65536 + 6);
331 			if (handle->buffer == NULL)
332 			{
333 				g_free(handle);
334 				handle = NULL;
335 			}
336 			handle->buffer2 = (uint8_t *)g_malloc(65536 + 6);
337 			if (handle->buffer2 == NULL)
338 			{
339 				g_free(handle->buffer);
340 				g_free(handle);
341 				handle = NULL;
342 			}
343 		}
344 	}
345 
346 	return handle;
347 }
348 
349 /**
350  * ticalcs_handle_del:
351  * @handle: the handle
352  *
353  * Release the cable and free the associated resources.
354  * If cable has not been detached with #ticalcs_cable_detach,
355  * it will be detached.
356  *
357  * Return value: always 0.
358  **/
ticalcs_handle_del(CalcHandle * handle)359 TIEXPORT3 int TICALL ticalcs_handle_del(CalcHandle* handle)
360 {
361 	VALIDATE_HANDLE(handle);
362 
363 	if (handle->attached)
364 	{
365 		ticalcs_cable_detach(handle);
366 	}
367 
368 	if (handle->buffer2)
369 	{
370 		g_free(handle->buffer2);
371 	}
372 
373 	if (handle->buffer)
374 	{
375 		g_free(handle->buffer);
376 	}
377 
378 	memset((void *)handle, 0, sizeof(*handle));
379 	g_free(handle);
380 
381 	return 0;
382 }
383 
384 /**
385  * ticalcs_handle_show:
386  * @handle: the handle
387  *
388  * Show information stored in the handle.
389  *
390  * Return value: always 0.
391  **/
ticalcs_handle_show(CalcHandle * handle)392 TIEXPORT3 int TICALL ticalcs_handle_show(CalcHandle* handle)
393 {
394 	VALIDATE_HANDLE(handle);
395 
396 	ticalcs_info(_("Link calc handle details:"));
397 	ticalcs_info(_("  model   : %s"), ticalcs_model_to_string(handle->model));
398 
399 	return 0;
400 }
401 
402 /**
403  * ticalcs_cable_attach:
404  * @handle: the handle
405  * @cable: a cable to use
406  *
407  * Attach and open the given cable for use with the hand-held.
408  *
409  * Return value: 0 if successful, an error code otherwise.
410  **/
ticalcs_cable_attach(CalcHandle * handle,CableHandle * cable)411 TIEXPORT3 int TICALL ticalcs_cable_attach(CalcHandle* handle, CableHandle* cable)
412 {
413 	int ret;
414 
415 	VALIDATE_HANDLE(handle);
416 
417 	handle->cable = cable;
418 	handle->attached = !0;
419 
420 	ret = ticables_cable_open(cable);
421 	if (!ret)
422 	{
423 		handle->open = !0;
424 	}
425 
426 	return ret;
427 }
428 
429 /**
430  * ticalcs_cable_detach:
431  * @handle: the handle
432  * @cable: a cable to use
433  *
434  * Close and detach the cable associated with the hand-held.
435  *
436  * Return value: 0 if successful, an error code otherwise.
437  **/
ticalcs_cable_detach(CalcHandle * handle)438 TIEXPORT3 int TICALL ticalcs_cable_detach(CalcHandle* handle)
439 {
440 	int ret;
441 
442 	VALIDATE_HANDLE(handle);
443 
444 	ret = ticables_cable_close(handle->cable);
445 	if (!ret)
446 	{
447 		handle->open = 0;
448 
449 		handle->attached = 0;
450 		handle->cable = NULL;
451 	}
452 
453 	return ret;
454 }
455 
456 /**
457  * ticalcs_update_set:
458  * @handle: the handle
459  * @update: the callbacks to use
460  *
461  * Set the callbacks to use for the given handle.
462  *
463  * Return value: 0 if successful, an error code otherwise.
464  **/
ticalcs_update_set(CalcHandle * handle,CalcUpdate * upd)465 TIEXPORT3 int TICALL ticalcs_update_set(CalcHandle* handle, CalcUpdate* upd)
466 {
467 	VALIDATE_HANDLE(handle);
468 
469 	handle->updat = upd;
470 	return 0;
471 
472 }
473 
474 /**
475  * ticalcs_model_supports_dbus:
476  * @model: a calculator model taken in #CalcModel.
477  *
478  * Returns whether the given calculator model supports the protocol dubbed DBUS by libticalcs.
479  * That is, the standard protocol used by TI-Z80 and TI-68k calculators over the legacy I/O.
480  *
481  * Return value: nonzero if the calculator supports the DBUS protocol, zero if it doesn't.
482  */
ticalcs_model_supports_dbus(CalcModel model)483 TIEXPORT3 int TICALL ticalcs_model_supports_dbus(CalcModel model)
484 {
485 	return (   /*model <  CALC_MAX
486 	        &&*/ ( model == CALC_TI73
487 	            || model == CALC_TI82
488 	            || model == CALC_TI83
489 	            || model == CALC_TI83P
490 	            || model == CALC_TI84P
491 	            || model == CALC_TI85
492 	            || model == CALC_TI86
493 	            || model == CALC_TI89
494 	            || model == CALC_TI89T
495 	            || model == CALC_TI92
496 	            || model == CALC_TI92P
497 	            || model == CALC_V200
498 	            || model == CALC_TI80
499 	            || model == CALC_TI84PC));
500 }
501 
502 /**
503  * ticalcs_model_supports_dusb:
504  * @model: a calculator model taken in #CalcModel.
505  *
506  * Returns whether the given calculator model supports the protocol dubbed DUSB by libticalcs.
507  * That is, the standard protocol used by TI-Z80, TI-eZ80 and TI-68k calculators over the USB port.
508  *
509  * Return value: nonzero if the calculator supports the DUSB protocol, zero if it doesn't.
510  */
ticalcs_model_supports_dusb(CalcModel model)511 TIEXPORT3 int TICALL ticalcs_model_supports_dusb(CalcModel model)
512 {
513 	return (   /*model <  CALC_MAX
514 	        &&*/ ( model == CALC_TI84P_USB
515 	            || model == CALC_TI89T_USB
516 	            || model == CALC_TI84PC_USB
517 	            || model == CALC_TI83PCE_USB
518 	            || model == CALC_TI84PCE_USB
519 	            || model == CALC_TI82A_USB
520 	            || model == CALC_TI84PT_USB));
521 }
522 
523 /**
524  * ticalcs_model_supports_nsp:
525  * @model: a calculator model taken in #CalcModel.
526  *
527  * Returns whether the given calculator model supports the protocol dubbed NSP by libticalcs.
528  * That is, the standard protocol used by TI-Nspire calculators over the USB port.
529  *
530  * Return value: nonzero if the calculator supports the NSP protocol, zero if it doesn't.
531  */
ticalcs_model_supports_nsp(CalcModel model)532 TIEXPORT3 int TICALL ticalcs_model_supports_nsp(CalcModel model)
533 {
534 	return (   /*model <  CALC_MAX
535 	        &&*/ ( model == CALC_NSPIRE));
536 }
537