1
2 #ifndef SS_IMP_H
3
4 /*
5 * Argyll Color Correction System
6 *
7 * Gretag Spectrolino and Spectroscan related
8 * defines and declarations - implementation.
9 *
10 * Author: Graeme W. Gill
11 * Date: 14/7/2005
12 *
13 * Copyright 2005 - 2013 Graeme W. Gill
14 * All rights reserved.
15 *
16 * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
17 * see the License2.txt file for licencing details.
18 *
19 * This is an alternative driver to spm/gretag.
20 */
21
22 /*
23 If you make use of the instrument driver code here, please note
24 that it is the author(s) of the code who take responsibility
25 for its operation. Any problems or queries regarding driving
26 instruments with the Argyll drivers, should be directed to
27 the Argyll's author(s), and not to any other party.
28
29 If there is some instrument feature or function that you
30 would like supported here, it is recommended that you
31 contact Argyll's author(s) first, rather than attempt to
32 modify the software yourself, if you don't have firm knowledge
33 of the instrument communicate protocols. There is a chance
34 that an instrument could be damaged by an incautious command
35 sequence, and the instrument companies generally cannot and
36 will not support developers that they have not qualified
37 and agreed to support.
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <ctype.h>
43 #include <string.h>
44 #include <time.h>
45 #ifndef SALONEINSTLIB
46 #include "copyright.h"
47 #include "aconfig.h"
48 #include "numlib.h"
49 #else /* SALONEINSTLIB */
50 #include "sa_config.h"
51 #include "numsup.h"
52 #endif /* SALONEINSTLIB */
53 #include "xspect.h"
54 #include "insttypes.h"
55 #include "conv.h"
56 #include "icoms.h"
57 #include "ss.h"
58
59 /* ------------------------------------------- */
60 /* Serialisation for different types functions */
61
62 /* QUERY: */
63
64 /* These add characters to the current send buffer, */
65 /* And set the status appropriately */
66
67 /* 4 bits to hex character conversion table */
68 static char b2h[16] = {
69 '0', '1', '2', '3', '4', '5', '6', '7',
70 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
71 };
72
73 /* Check that there is enough space to write size more characters */
74 #define CHWSPACE(size) \
75 if (p->snerr == ss_et_NoError \
76 && (p->sbufe - p->sbuf) < (size)) { \
77 p->snerr = ss_et_SendBufferFull; \
78 } \
79 if (p->snerr != ss_et_NoError) \
80 return;
81
82 /* Reset send buffer, and init with start character */
ss_init_send(ss * p)83 void ss_init_send(ss *p) {
84 p->snerr = ss_et_NoError;
85 p->sbuf = p->_sbuf;
86 CHWSPACE(1);
87 p->sbuf[0] = ';';
88 p->sbuf += 1;
89 }
90
91 /* Reset send buffer, and add an Spectrolino Request enum */
ss_add_soreq(ss * p,int rq)92 void ss_add_soreq(ss *p, int rq) {
93 ss_init_send(p);
94 CHWSPACE(2);
95 p->sbuf[0] = b2h[(rq >> 4) & 0xf];
96 p->sbuf[1] = b2h[(rq >> 0) & 0xf];
97 p->sbuf += 2;
98 }
99
100 /* Reset send buffer, and add an SpectroScan Request enum */
ss_add_ssreq(ss * p,int rq)101 void ss_add_ssreq(ss *p, int rq) {
102 ss_init_send(p);
103 CHWSPACE(4);
104 p->sbuf[0] = b2h[((int)ss_ReqPFX >> 4) & 0xf]; /* Prefix */
105 p->sbuf[1] = b2h[((int)ss_ReqPFX >> 0) & 0xf]; /* Prefix */
106 p->sbuf[2] = b2h[(rq >> 4) & 0xf];
107 p->sbuf[3] = b2h[(rq >> 0) & 0xf];
108 p->sbuf += 4;
109 }
110
111 /* Add an int/enum/char into one byte type */
ss_add_1(ss * p,int c)112 void ss_add_1(ss *p, int c) {
113 CHWSPACE(2);
114 p->sbuf[0] = b2h[(c >> 4) & 0xf];
115 p->sbuf[1] = b2h[(c >> 0) & 0xf];
116 p->sbuf += 2;
117 }
118
119 /* Add an int/enum into two byte type */
ss_add_2(ss * p,int s)120 void ss_add_2(ss *p, int s) {
121 CHWSPACE(4);
122 p->sbuf[0] = b2h[(s >> 4) & 0xf]; /* LSB */
123 p->sbuf[1] = b2h[(s >> 0) & 0xf];
124 p->sbuf[2] = b2h[(s >> 12) & 0xf]; /* MSB */
125 p->sbuf[3] = b2h[(s >> 8) & 0xf];
126 p->sbuf += 4;
127 }
128
129 /* Add an int/enum into four byte type */
ss_add_4(ss * p,int i)130 void ss_add_4(ss *p, int i) {
131 CHWSPACE(8);
132 p->sbuf[0] = b2h[(i >> 4) & 0xf]; /* LSB */
133 p->sbuf[1] = b2h[(i >> 0) & 0xf];
134 p->sbuf[2] = b2h[(i >> 12) & 0xf];
135 p->sbuf[3] = b2h[(i >> 8) & 0xf];
136 p->sbuf[4] = b2h[(i >> 20) & 0xf];
137 p->sbuf[5] = b2h[(i >> 16) & 0xf];
138 p->sbuf[6] = b2h[(i >> 28) & 0xf]; /* MSB */
139 p->sbuf[7] = b2h[(i >> 24) & 0xf];
140 p->sbuf += 8;
141 }
142
143 /* Add a double into four byte type */
ss_add_double(ss * p,double d)144 void ss_add_double(ss *p, double d) {
145 unsigned int id;
146
147 id = doubletoIEEE754(d);
148
149 ss_add_4(p, id);
150 }
151
152 /* Add an ASCII string into the send buffer. */
153 /* The string will be padded with nul's up to len. */
ss_add_string(ss * p,char * t,int len)154 void ss_add_string(ss *p, char *t, int len) {
155 int i;
156
157 CHWSPACE(2 * len);
158 for (i = 0; i < len; i++) {
159 p->sbuf[2 * i + 0] = b2h[(t[i] >> 4) & 0xf];
160 p->sbuf[2 * i + 1] = b2h[(t[i] >> 0) & 0xf];
161 if (t[i] == '\000')
162 break;
163 }
164 for (; i < len; i++) {
165 p->sbuf[2 * i + 0] = '0';
166 p->sbuf[2 * i + 1] = '0';
167 }
168 p->sbuf += 2 * len;
169 }
170
171 /* - - - - - - - - - - - - - - - - - - - - - */
172 /* ANSWER: */
173
174 /* Check that there is not already an error, */
175 /* and that there is enough space to read size more characters. */
176 /* Return nz if not. */
chrspace(ss * p,int size)177 static int chrspace(ss *p, int size) {
178
179 if (p->snerr != ss_et_NoError) /* Problem assembling request */
180 return 1;
181
182 if ((p->rbufe - p->rbuf) < (size)) {
183 p->snerr = ss_et_RecBufferEmpty;
184 return 1;
185 }
186 {
187 char *rr = p->rbuf, *re = p->rbuf + size;
188 while (rr < re && *rr != '\000')
189 rr++;
190 if (rr < re) {
191 p->snerr = ss_et_RecBufferEmpty;
192 return 1;
193 }
194 }
195 return 0;
196 }
197
198 /* Check that the read buffer is fully consumed. */
chended(ss * p)199 static void chended(ss *p) {
200 if (p->snerr == ss_et_NoError /* Don't overrite any existing error */
201 && p->rbufe != p->rbuf) {
202 p->snerr = ss_et_BadAnsFormat;
203 }
204 }
205
206 /* Convert an ASCII Hex character to an integer. */
h2b(ss * p,char c)207 static int h2b(ss *p, char c) {
208 if (c >= '0' && c <= '9')
209 return (c-(int)'0');
210 if (c >= 'A' && c <= 'F')
211 return (10 + c-(int)'A');
212 if (c >= 'a' && c <= 'f')
213 return (10 + c-(int)'a');
214 if (p->snerr == ss_et_NoError) /* Don't overrite any existing error */
215 p->snerr = ss_et_BadHexEncoding;
216 return 0;
217 }
218
219 /* Return the first enum from the recieve buffer without removing it. */
ss_peek_ans(ss * p)220 int ss_peek_ans(ss *p) {
221 int rv;
222
223 if (chrspace(p, 2))
224 return 0;
225 rv = (h2b(p, p->rbuf[0]) << 4)
226 | (h2b(p, p->rbuf[1]) << 0);
227
228 return rv;
229 }
230
231 /* Remove a Spectrolino answer enum from the revieve buffer, */
232 /* and check it is correct. */
ss_sub_soans(ss * p,int cv)233 void ss_sub_soans(ss *p, int cv) {
234 int rv;
235
236 if (chrspace(p, 2))
237 return;
238 rv = (h2b(p, p->rbuf[0]) << 4)
239 | (h2b(p, p->rbuf[1]) << 0);
240 p->rbuf += 2;
241 if (rv != cv) {
242 if (p->snerr == ss_et_NoError) /* Don't overrite any existing error */
243 p->snerr = ss_et_BadAnsFormat;
244 return;
245 }
246 return;
247 }
248
249 /* Remove a SpectroScan Prefix and answer enum from the revieve buffer, */
250 /* and check it is correct. */
ss_sub_ssans(ss * p,int cv)251 void ss_sub_ssans(ss *p, int cv) {
252 int rv;
253
254 if (chrspace(p, 4))
255 return;
256 if (p->rbuf[0] != 'D'
257 || p->rbuf[1] != '1') {
258 if (p->snerr == ss_et_NoError) /* Don't overrite any existing error */
259 p->snerr = ss_et_BadAnsFormat;
260 return;
261 }
262 rv = (h2b(p, p->rbuf[2]) << 4)
263 | (h2b(p, p->rbuf[3]) << 0);
264 p->rbuf += 4;
265 if (rv != cv) {
266 if (p->snerr == ss_et_NoError) /* Don't overrite any existing error */
267 p->snerr = ss_et_BadAnsFormat;
268 return;
269 }
270 return;
271 }
272
273 /* Remove an int/enum/char into one byte type */
ss_sub_1(ss * p)274 int ss_sub_1(ss *p) {
275 int rv;
276
277 if (chrspace(p, 2))
278 return 0;
279 rv = (h2b(p, p->rbuf[0]) << 4)
280 | (h2b(p, p->rbuf[1]) << 0);
281 p->rbuf += 2;
282
283 return rv;
284 }
285
286 /* Remove an int/enum into two byte type */
ss_sub_2(ss * p)287 int ss_sub_2(ss *p) {
288 int rv;
289
290 if (chrspace(p, 4))
291 return 0;
292 rv = (h2b(p, p->rbuf[0]) << 4)
293 | (h2b(p, p->rbuf[1]) << 0)
294 | (h2b(p, p->rbuf[2]) << 12)
295 | (h2b(p, p->rbuf[3]) << 8);
296 p->rbuf += 4;
297
298 return rv;
299 }
300
301 /* Remove an int/enum into four byte type */
ss_sub_4(ss * p)302 int ss_sub_4(ss *p) {
303 int rv;
304
305 if (chrspace(p, 8))
306 return 0;
307 rv = (h2b(p, p->rbuf[0]) << 4)
308 | (h2b(p, p->rbuf[1]) << 0)
309 | (h2b(p, p->rbuf[2]) << 12)
310 | (h2b(p, p->rbuf[3]) << 8)
311 | (h2b(p, p->rbuf[4]) << 20)
312 | (h2b(p, p->rbuf[5]) << 16)
313 | (h2b(p, p->rbuf[6]) << 28)
314 | (h2b(p, p->rbuf[7]) << 24);
315 p->rbuf += 8;
316
317 return rv;
318 }
319
320 /* Remove a double into four byte type */
ss_sub_double(ss * p)321 double ss_sub_double(ss *p) {
322 unsigned int ip;
323 double op;
324
325 ip = (unsigned int)ss_sub_4(p);
326
327 op = IEEE754todouble(ip);
328
329 return op;
330 }
331
332 /* Remove an ASCII string from the receive buffer. */
333 /* The string will be terminated with a nul, so a buffer */
334 /* of len+1 should be provided to return the string in. */
ss_sub_string(ss * p,char * t,int len)335 void ss_sub_string(ss *p, char *t, int len) {
336 int i;
337
338 if (chrspace(p, 2 * len))
339 return;
340 for (i = 0; i < len; i++) {
341 t[i] = (char)((h2b(p, p->rbuf[2 * i + 0]) << 4)
342 | (h2b(p, p->rbuf[2 * i + 1]) << 0));
343 }
344 t[i] = '\000';
345 p->rbuf += 2 * len;
346 }
347
348 /* - - - - - - - - - - - - - - - - - - - - - */
349 /* ERROR CODES: */
350
351 /* Convert an ss error into an inst_error */
ss_inst_err(ss * p)352 inst_code ss_inst_err(ss *p) {
353 ss_et ec = p->snerr;
354
355 switch(ec) {
356 case ss_et_NoError:
357 return inst_ok;
358
359 case ss_et_WhiteMeasOK:
360 case ss_et_ResetDone:
361 case ss_et_EmissionCalOK:
362 return inst_notify | ec;
363
364 case ss_et_WhiteMeasWarn:
365 return inst_warning | ec;
366
367 case ss_et_SendTimeout:
368 case ss_et_SerialFail:
369 return inst_coms_fail | ec;
370
371 case ss_et_StopButNoStart:
372 case ss_et_IllegalCharInRec:
373 case ss_et_IncorrectRecLen:
374 case ss_et_IllegalRecType:
375 case ss_et_NoTagField:
376 case ss_et_ConvError:
377 case ss_et_RecBufferEmpty:
378 case ss_et_BadAnsFormat:
379 case ss_et_BadHexEncoding:
380 case ss_et_RecBufferOverun:
381 case ss_et_OutOfRange:
382 case ss_et_NotAnSROrBoolean:
383 return inst_protocol_error | ec;
384
385 case ss_et_RemOverFlow:
386 case ss_et_MeasDisabled:
387 case ss_et_MeasurementError:
388 case ss_et_DorlOutOfRange:
389 case ss_et_ReflectanceOutOfRange:
390 case ss_et_Color1OutOfRange:
391 case ss_et_Color2OutOfRange:
392 case ss_et_Color3OutOfRange:
393 return inst_misread | ec;
394
395 case ss_et_NoValidCommand:
396 case ss_et_NoUserAccess:
397 return inst_unsupported | ec;
398
399 case ss_et_NotReady:
400 case ss_et_NoAccess:
401 return inst_other_error | ec;
402 break;
403
404 case ss_et_SendBufferFull:
405 return inst_internal_error | ec;
406
407 case ss_et_NoValidMeas:
408 case ss_et_OnlyEmission:
409 case ss_et_DensCalError:
410 case ss_et_NoTransmTable:
411 case ss_et_InvalidForEmission:
412 case ss_et_NotInTransmMode:
413 case ss_et_NotInReflectMode:
414 case ss_et_NoValidDStd:
415 case ss_et_NoValidWhite:
416 case ss_et_NoValidIllum:
417 case ss_et_NoValidObserver:
418 case ss_et_NoValidMaxLambda:
419 case ss_et_NoValidSpect:
420 case ss_et_NoValidColSysOrIndex:
421 case ss_et_NoValidChar:
422 case ss_et_NoValidValOrRef:
423 case ss_et_DeviceIsOffline:
424 case ss_et_NoDeviceFound:
425 return inst_wrong_setup | ec;
426
427 case ss_et_BackupError:
428 case ss_et_ProgramROMError:
429 case ss_et_CheckSumWrong:
430 case ss_et_MemoryError:
431 case ss_et_FullMemory:
432 case ss_et_EPROMFailure:
433 case ss_et_MemoryFailure:
434 case ss_et_PowerFailure:
435 case ss_et_LampFailure:
436 case ss_et_HardwareFailure:
437 case ss_et_DriveError:
438 case ss_et_FilterOutOfPos:
439 case ss_et_ProgrammingError:
440 return inst_hardware_fail | ec;
441 }
442 return inst_other_error | ec;
443 }
444
445 /* Incorporate a error into the snerr value */
ss_incorp_err(ss * p,ss_et se)446 void ss_incorp_err(ss *p, ss_et se) {
447 if (p->snerr != ss_et_NoError) /* Don't overrite any existing error */
448 return;
449 if (se == ss_set_NoError)
450 return;
451
452 p->snerr = se;
453 }
454
455 /* Incororate Remote Error Set values into snerr value */
456 /* Since ss_res is a bit mask, we just prioritize the errors. */
ss_incorp_remerrset(ss * p,ss_res es)457 void ss_incorp_remerrset(ss *p, ss_res es) {
458 int i, ii;
459 if (p->snerr != ss_et_NoError) /* Don't overrite any existing error */
460 return;
461 if (es == ss_res_NoError)
462 return;
463
464 for (i = ss_et_NoValidDStd, ii = 0x0001; ii < 0x10000; i++, ii <<= 1) {
465 if ((ii & es) != 0) {
466 break;
467 }
468 }
469 p->snerr = i;
470 }
471
472 /* Incorporate a scan error into the snerr value */
ss_incorp_scanerr(ss * p,ss_set se)473 void ss_incorp_scanerr(ss *p, ss_set se) {
474 if (p->snerr != ss_et_NoError) /* Don't overrite any existing error */
475 return;
476 if (se == ss_set_NoError)
477 return;
478
479 p->snerr = se + ss_et_DeviceIsOffline - 1;
480 }
481
482 /* Incorporate a device communication error into the snerr value */
ss_incorp_comerr(ss * p,ss_cet se)483 void ss_incorp_comerr(ss *p, ss_cet se) {
484 if (p->snerr != ss_et_NoError) /* Don't overrite any existing error */
485 return;
486 if (se == ss_cet_NoError)
487 return;
488
489 p->snerr = se + ss_et_StopButNoStart - 1;
490 }
491
492 /* - - - - - - - - - - - - - - - - - - - - - */
493 /* EXECUTION: */
494
495 /* Interpret an icoms error into a SS error */
icoms2ss_err(int se)496 int icoms2ss_err(int se) {
497 if (se != ICOM_OK)
498 return ss_et_SerialFail;
499 return ss_et_NoError;
500 }
501
502 /* Terminate the send buffer, and then do a */
503 /* send/receieve to the device. */
504 /* Leave any error in p->snerr */
ss_command(ss * p,double tmo)505 void ss_command(ss *p, double tmo) {
506 int se;
507
508 CHWSPACE(3);
509 p->sbuf[0] = '\r';
510 p->sbuf[1] = '\n';
511 p->sbuf[2] = '\00'; /* write_read terminates on nul */
512
513 p->rbuf = p->_rbuf; /* Reset read pointer */
514 if ((se = p->icom->write_read_ex(p->icom, p->_sbuf, 0, p->_rbuf, SS_MAX_RD_SIZE, NULL, "\n", 1, tmo, 1)) != 0) {
515 p->snerr = icoms2ss_err(se);
516 return;
517 }
518
519 /* Figure out receive size, and clean up termination. */
520 p->rbufe = p->_rbuf + strlen(p->_rbuf);
521 if ((p->rbufe - p->rbuf) >= 1 && p->rbufe[-1] == '\n') {
522 --p->rbufe;
523 *p->rbufe = '\000';
524 }
525 if ((p->rbufe - p->rbuf) >= 1 && p->rbufe[-1] == '\r') {
526 --p->rbufe;
527 *p->rbufe = '\000';
528 }
529
530 /* Check receive format and look for a COM error */
531 if ((p->rbufe - p->rbuf) < 1 || p->rbuf[0] != ':') {
532 p->snerr = ss_et_BadAnsFormat;
533 return;
534 }
535 p->rbuf++;
536
537 /* See if this is a Spectroscan COM error */
538 if ((p->rbufe - p->rbuf) >= 2
539 && p->rbuf[0] == 'D'
540 && p->rbuf[1] == '1') {
541
542 if ((p->rbufe - p->rbuf) >= 4
543 && p->rbuf[0] == 'A'
544 && p->rbuf[1] == '0') { /* COMM Error */
545 p->rbuf += 4;
546 ss_incorp_comerr(p, (ss_cet)ss_sub_1(p));
547 return;
548 }
549 }
550
551 /* See if it is a Spectrolino COMM error */
552 if ((p->rbufe - p->rbuf) >= 2
553 && p->rbuf[0] == '2'
554 && p->rbuf[1] == '6') { /* COMM Error */
555 p->rbuf += 2;
556 ss_incorp_comerr(p, (ss_cet)ss_sub_1(p));
557 return;
558 }
559 return;
560 }
561
562 /* =================================================================== */
563 /* Complete Spectrolino instructions. */
564 /* [This is less elegant than Neil Okamoto's */
565 /* table approach, but is more flexible, */
566 /* and it does the job.] */
567
568 /* - - - - - - - - - - - - - - - - - - - - */
569 /* Device Initialisation and configuration */
570
571 /* Reset instrument */
so_do_ResetStatusDownload(ss * p,ss_smt sm)572 inst_code so_do_ResetStatusDownload(
573 ss *p,
574 ss_smt sm /* Init all or all except communications */
575 ) {
576 ss_add_soreq(p, ss_ResetStatusDownload);
577 ss_add_1(p, 0x01);
578 ss_add_1(p, 0x04);
579 ss_add_1(p, sm);
580 ss_command(p, IT_TMO);
581 ss_sub_soans(p, ss_DownloadError);
582 ss_incorp_remerrset(p, ss_sub_2(p));
583 chended(p);
584 return ss_inst_err(p);
585 }
586
587 /* Load various parameters, such as: */
588 /* comm flow control, baud rate, speaker, */
589 /* reflective/tranmission/emmission mode, */
590 /* custom filter on/off */
so_do_MeasControlDownload(ss * p,ss_ctt ct)591 inst_code so_do_MeasControlDownload(
592 ss *p,
593 ss_ctt ct /* Control */
594 ) {
595 ss_add_soreq(p, ss_MeasControlDownload);
596 ss_add_1(p, ct);
597 ss_command(p, DF_TMO);
598 ss_sub_soans(p, ss_DownloadError);
599 ss_incorp_remerrset(p, ss_sub_2(p));
600 chended(p);
601
602 return ss_inst_err(p);
603 }
604
605 /* Query various current parameters, such as: */
606 /* comm flow control, baud rate, speaker, */
607 /* reflective/tranmission/emmission mode, */
608 /* custom filter on/off. */
so_do_MeasControlRequest(ss * p,ss_ctt ct,ss_ctt * rct)609 inst_code so_do_MeasControlRequest(
610 ss *p,
611 ss_ctt ct, /* Control to query */
612 ss_ctt *rct /* Return current state */
613 ) {
614 ss_add_soreq(p, ss_MeasControlRequest);
615 ss_add_1(p, ct);
616 ss_command(p, DF_TMO);
617 ss_sub_soans(p, ss_MeasControlAnswer);
618 ss_sub_1(p); /* Should be the same as ct */
619 *rct = ss_sub_1(p);
620 ss_incorp_remerrset(p, ss_sub_2(p));
621 chended(p);
622 return ss_inst_err(p);
623 }
624
625 /* Queries specific device data */
so_do_DeviceDataRequest(ss * p,char dn[19],ss_dnot * dno,char pn[9],unsigned int * sn,char sv[13])626 inst_code so_do_DeviceDataRequest(
627 ss *p,
628 char dn[19], /* Return the device name */
629 ss_dnot *dno, /* Return device number */
630 char pn[9], /* Return the part number */
631 unsigned int *sn, /* Return serial number */
632 char sv[13] /* Return software version */
633 ) {
634 char rsv[17]; /* Space for reserved field */
635 ss_add_soreq(p, ss_DeviceDataRequest);
636 ss_command(p, DF_TMO);
637 ss_sub_soans(p, ss_DeviceDataAnswer);
638 ss_sub_string(p, dn, 18);
639 *dno = ss_sub_1(p);
640 ss_sub_string(p, pn, 8);
641 *sn = (unsigned int)ss_sub_4(p);
642 ss_sub_string(p, sv, 12);
643 ss_sub_string(p, rsv, 16);
644 chended(p);
645 return ss_inst_err(p);
646 }
647
648 /* Query special device data */
so_do_TargetIdRequest(ss * p,char dn[19],int * sn,int * sr,int * yp,int * mp,int * dp,int * hp,int * np,ss_ttt * tt,int * fswl,int * nosw,int * dpsw)649 inst_code so_do_TargetIdRequest(
650 ss *p,
651 char dn[19], /* Return Device Name */
652 int *sn, /* Return Serial Number (1-65535) */
653 int *sr, /* Return Software Release */
654 int *yp, /* Return Year of production (e.g. 1996) */
655 int *mp, /* Return Month of production (1-12) */
656 int *dp, /* Return Day of production (1-31) */
657 int *hp, /* Return Hour of production (0-23) */
658 int *np, /* Return Minuite of production (0-59) */
659 ss_ttt *tt, /* Return Target Tech Type (SPM/Spectrolino etc.) */
660 int *fswl, /* Return First spectral wavelength (nm) */
661 int *nosw, /* Return Number of spectral wavelengths */
662 int *dpsw /* Return Distance between spectral wavelengths (nm) */
663 ) {
664 ss_add_soreq(p, ss_TargetIdRequest);
665 ss_command(p, DF_TMO);
666 ss_sub_soans(p, ss_TargetIdAnswer);
667 ss_sub_string(p, dn, 18);
668 *sn = ss_sub_2(p);
669 *sr = ss_sub_2(p);
670 *yp = ss_sub_2(p);
671 *mp = ss_sub_2(p);
672 *dp = ss_sub_2(p);
673 *hp = ss_sub_2(p);
674 *np = ss_sub_2(p);
675 *tt = ss_sub_1(p);
676 *fswl = ss_sub_2(p);
677 *nosw = ss_sub_2(p);
678 *dpsw = ss_sub_2(p);
679 chended(p);
680 return ss_inst_err(p);
681 }
682
683 /* - - - - - - - - - - - - - */
684 /* Measurement configuration */
685
686 /* Query the standard or user definable densitometric tables */
so_do_DensTabRequest(ss * p,ss_dst ds,ss_dst * rds,double sp[4][36])687 inst_code so_do_DensTabRequest(
688 ss *p,
689 ss_dst ds, /* Density standard (ANSI/DIN/User etc.) */
690 ss_dst *rds, /* Return Density standard (ANSI/DIN/User etc.) */
691 double sp[4][36] /* Return 4 * 36 spectral weighting values */
692 ) {
693 int n,i;
694 ss_add_soreq(p, ss_DensTabRequest);
695 ss_add_1(p, 0x00);
696 ss_add_1(p, ds);
697 ss_command(p, DF_TMO);
698 ss_sub_soans(p, ss_DensTabAnswer);
699 ss_sub_soans(p, 0x00);
700 *rds = ss_sub_1(p);
701 for (n = 0; n < 4; n++)
702 for (i = 0; i < 36; i++)
703 sp[n][i] = ss_sub_double(p);
704 ss_incorp_remerrset(p, ss_sub_2(p));
705 chended(p);
706 return ss_inst_err(p);
707 }
708
709 /* Download user definable densitometric tables */
so_do_DensTabDownload(ss * p,double sp[4][36])710 inst_code so_do_DensTabDownload(
711 ss *p,
712 double sp[4][36] /* 4 * 36 spectral weighting values */
713 ) {
714 int i, n;
715 ss_add_soreq(p, ss_DensTabDownload);
716 ss_add_1(p, 0x08);
717 for (n = 0; n < 4; n++)
718 for (i = 0; i < 36; i++)
719 ss_add_double(p, sp[n][i]);
720 ss_command(p, DF_TMO);
721 ss_sub_soans(p, ss_DownloadError);
722 ss_incorp_remerrset(p, ss_sub_2(p));
723 chended(p);
724 return ss_inst_err(p);
725 }
726
727 /* Set slope values for densitometry */
so_do_SlopeDownload(ss * p,double dv[4])728 inst_code so_do_SlopeDownload(
729 ss *p,
730 double dv[4] /* Db Dc Dm Dy density values */
731 ) {
732 int i;
733 ss_add_soreq(p, ss_SlopeDownload);
734 for (i = 0; i < 4; i++)
735 ss_add_double(p, dv[i]);
736 ss_command(p, DF_TMO);
737 ss_sub_soans(p, ss_DownloadError);
738 ss_incorp_remerrset(p, ss_sub_2(p));
739 chended(p);
740 return ss_inst_err(p);
741 }
742
743 /* Query slope values of densitometry */
so_do_SlopeRequest(ss * p,double dv[4])744 inst_code so_do_SlopeRequest(
745 ss *p,
746 double dv[4] /* Return Db Dc Dm Dy density values */
747 ) {
748 int i;
749 ss_add_soreq(p, ss_SlopeRequest);
750 ss_command(p, DF_TMO);
751 ss_sub_soans(p, ss_SlopeAnswer);
752 for (i = 0; i < 4; i++)
753 dv[i] = ss_sub_double(p);
754 chended(p);
755 return ss_inst_err(p);
756 }
757
758 /* Set the colorimetric parameters */
so_do_ParameterDownload(ss * p,ss_dst ds,ss_wbt wb,ss_ilt it,ss_ot ot)759 inst_code so_do_ParameterDownload(
760 ss *p,
761 ss_dst ds, /* Density standard (ANSI/DIN etc.) */
762 ss_wbt wb, /* White base (Paper/Absolute) */
763 ss_ilt it, /* Illuminant type (A/C/D65 etc.) */
764 ss_ot ot /* Observer type (2deg/10deg) */
765 ) {
766 ss_add_soreq(p, ss_ParameterDownload);
767 ss_add_1(p, ds);
768 ss_add_1(p, wb);
769 ss_add_1(p, it);
770 ss_add_1(p, ot);
771 ss_command(p, DF_TMO);
772 ss_sub_soans(p, ss_DownloadError);
773 ss_incorp_remerrset(p, ss_sub_2(p));
774 chended(p);
775 return ss_inst_err(p);
776 }
777
778 /* Query colorimetric parameters */
so_do_ParameterRequest(ss * p,ss_dst * ds,ss_wbt * wb,ss_ilt * it,ss_ot * ot,ss_aft * af)779 inst_code so_do_ParameterRequest(
780 ss *p,
781 ss_dst *ds, /* Return Density Standard */
782 ss_wbt *wb, /* Return White Base */
783 ss_ilt *it, /* Return Illuminant type (A/C/D65/User etc.) */
784 ss_ot *ot, /* Return Observer type (2deg/10deg) */
785 ss_aft *af /* Return Filter being used (None/Pol/D65/UV/custom */
786 ) {
787 ss_add_soreq(p, ss_ParameterRequest);
788 ss_command(p, DF_TMO);
789 ss_sub_soans(p, ss_ParameterAnswer);
790 *ds = ss_sub_1(p);
791 *wb = ss_sub_1(p);
792 *it = ss_sub_1(p);
793 *ot = ss_sub_1(p);
794 *af = ss_sub_1(p);
795 chended(p);
796 return ss_inst_err(p);
797 }
798
799 /* Query the standard or user defined illuminant tables (Colorimetry) */
so_do_IllumTabRequest(ss * p,ss_ilt it,ss_ilt * rit,double sp[36])800 inst_code so_do_IllumTabRequest(
801 ss *p,
802 ss_ilt it, /* Illuminant type (A/C/D65/User etc.) */
803 ss_ilt *rit, /* Return Illuminant type (A/C/D65/User etc.) */
804 double sp[36] /* Return 36 spectral values */
805 ) {
806 int i;
807 ss_add_soreq(p, ss_IllumTabRequest);
808 ss_add_1(p, 0x00);
809 ss_add_1(p, it);
810 ss_command(p, DF_TMO);
811 ss_sub_soans(p, ss_IllumTabAnswer);
812 ss_sub_soans(p, 0x00);
813 *rit = ss_sub_1(p);
814 for (i = 0; i < 36; i++)
815 sp[i] = ss_sub_double(p);
816 ss_incorp_remerrset(p, ss_sub_2(p));
817 chended(p);
818 return ss_inst_err(p);
819 }
820
821 /* Download user definable illuminant tables (Colorimetry) */
so_do_IllumTabDownload(ss * p,double sp[36])822 inst_code so_do_IllumTabDownload(
823 ss *p,
824 double sp[36] /* 36 spectral values to set */
825 ) {
826 int i;
827 ss_add_soreq(p, ss_IllumTabDownload);
828 ss_add_1(p, 0x08);
829 for (i = 0; i < 36; i++)
830 ss_add_double(p, sp[i]);
831 ss_command(p, DF_TMO);
832 ss_sub_soans(p, ss_DownloadError);
833 ss_incorp_remerrset(p, ss_sub_2(p));
834 chended(p);
835 return ss_inst_err(p);
836 }
837
838 /* Query for the color temperature of daylight illuminant Dxx */
so_do_GetValNr(ss * p,int * ct)839 inst_code so_do_GetValNr(
840 ss *p,
841 int *ct /* Return color temperature in deg K/100 */
842 ) {
843 ss_add_soreq(p, ss_GetValNr);
844 ss_add_1(p, 0x60);
845 ss_command(p, DF_TMO);
846 ss_sub_soans(p, ss_ValNrAnswer);
847 ss_sub_soans(p, 0x60);
848 *ct = ss_sub_1(p);
849 ss_incorp_remerrset(p, ss_sub_2(p));
850 chended(p);
851 return ss_inst_err(p);
852 }
853
854 /* Download user definable illuminant tables (Colorimetry) */
so_do_SetValNr(ss * p,int ct)855 inst_code so_do_SetValNr(
856 ss *p,
857 int ct /* Color temperature to set for illuminant Dxx in deg K/100 */
858 ) {
859 ss_add_soreq(p, ss_IllumTabDownload);
860 ss_add_1(p, 0x60);
861 ss_add_2(p, ct);
862 ss_command(p, DF_TMO);
863 ss_sub_soans(p, ss_DownloadError);
864 ss_incorp_remerrset(p, ss_sub_2(p));
865 chended(p);
866 return ss_inst_err(p);
867 }
868
869 /* Queries the spectra of the white tile reference for the desired filter */
so_do_WhiteReferenceRequest(ss * p,ss_aft af,ss_aft * raf,double sp[36],ss_owrt * owr,char dtn[19])870 inst_code so_do_WhiteReferenceRequest(
871 ss *p,
872 ss_aft af, /* Filter being queried (None/Pol/D65/UV/custom */
873 ss_aft *raf, /* Return filter being queried (None/Pol/D65/UV/custom */
874 double sp[36], /* Return 36 spectral values */
875 ss_owrt *owr, /* Return original white reference (i.e. factory/user) */
876 char dtn[19] /* Return name of data table */
877 ) {
878 int i;
879 ss_add_soreq(p, ss_WhiteReferenceRequest);
880 ss_add_1(p, af);
881 ss_command(p, DF_TMO);
882 ss_sub_soans(p, ss_WhiteReferenceAnswer);
883 *raf = ss_sub_1(p);
884 for (i = 0; i < 36; i++)
885 sp[i] = ss_sub_double(p);
886 *owr = ss_sub_1(p);
887 ss_sub_string(p, dtn, 18);
888 chended(p);
889 return ss_inst_err(p);
890 }
891
892 /* Load spectra of a user defined white reference for the desired filter. */
893 /* This lets the user override the factory white tile calibration */
894 /* A name can be given to the white reference. */
so_do_WhiteReferenceDownld(ss * p,ss_aft af,double sp[36],char dtn[19])895 inst_code so_do_WhiteReferenceDownld(
896 ss *p,
897 ss_aft af, /* Filter being set (None/Pol/D65/UV/custom */
898 double sp[36], /* 36 spectral values being set */
899 char dtn[19] /* Name for data table */
900 ) {
901 int i;
902 ss_add_soreq(p, ss_WhiteReferenceDownld);
903 ss_add_1(p, af);
904 for (i = 0; i < 36; i++)
905 ss_add_double(p, sp[i]);
906 ss_add_string(p, dtn, 18);
907 ss_command(p, DF_TMO);
908 ss_sub_soans(p, ss_DownloadError);
909 ss_incorp_remerrset(p, ss_sub_2(p));
910 chended(p);
911 return ss_inst_err(p);
912 }
913
914 /* Query the reference value for the relative photometric (emission) reference value */
so_do_FloatRequest(ss * p,ss_comft comf,ss_comft * rcomf,double * comfv)915 inst_code so_do_FloatRequest(
916 ss *p,
917 ss_comft comf, /* Choose common float type (PhotometricYRef) */
918 ss_comft *rcomf, /* Return common float type (PhotometricYRef) */
919 double *comfv /* Return the reference value */
920 ) {
921 ss_add_soreq(p, ss_FloatRequest);
922 ss_add_1(p, comf);
923 ss_command(p, DF_TMO);
924 ss_sub_soans(p, ss_FloatAnswer);
925 *rcomf = ss_sub_1(p);
926 *comfv = ss_sub_double(p);
927 chended(p);
928 return ss_inst_err(p);
929 }
930
931 /* Set the reference value for the relative photometric (emission) reference value */
so_do_FloatDownload(ss * p,ss_comft comf,double comfv)932 inst_code so_do_FloatDownload(
933 ss *p,
934 ss_comft comf, /* Choose common float type (PhotometricYRef) */
935 double comfv /* The reference value */
936 ) {
937 ss_add_soreq(p, ss_FloatDownload);
938 ss_add_1(p, comf);
939 ss_add_double(p, comfv);
940 ss_command(p, DF_TMO);
941 ss_sub_soans(p, ss_DownloadError);
942 ss_incorp_remerrset(p, ss_sub_2(p));
943 chended(p);
944 return ss_inst_err(p);
945 }
946
947 /* - - - - - - */
948 /* Calibration */
949
950 /* Reset the spectra of the respective white reference to the original data */
so_do_ExecWhiteRefToOrigDat(ss * p)951 inst_code so_do_ExecWhiteRefToOrigDat(
952 ss *p
953 ) {
954 ss_add_soreq(p, ss_ExecWhiteRefToOrigDat);
955 ss_command(p, DF_TMO);
956 ss_sub_soans(p, ss_DownloadError); /* Instrument behavour doesn't match doco. */
957 ss_incorp_remerrset(p, ss_sub_2(p));
958 chended(p);
959 return ss_inst_err(p);
960 }
961
962
963 /* Perform a Reference Measurement */
so_do_ExecRefMeasurement(ss * p,ss_mmt mm)964 inst_code so_do_ExecRefMeasurement(
965 ss *p,
966 ss_mmt mm /* Measurement Mode (Meas/Cal etc.) */
967 ) {
968 #ifdef EMSST
969 if (p->tmode != 0) {
970 ss_rvt rv;
971 double sp[36];
972 ss_nmt nm;
973 p->tmode = 0;
974 ss_do_MoveAndMeasure(p, 155.0, 230.0, sp, &rv);
975 so_do_NewMeasureRequest(p, &nm);
976 ss_do_MoveAbsolut(p, p->sbr, p->sbx, p->sby);
977 p->tmode = 1;
978 return (inst_notify | ss_et_WhiteMeasOK);
979 }
980 #endif
981 ss_add_soreq(p, ss_ExecRefMeasurement);
982 ss_add_1(p, 0x09);
983 ss_add_1(p, mm);
984 ss_command(p, 2.0 * DF_TMO);
985 ss_sub_soans(p, ss_ExecError);
986 ss_incorp_err(p, ss_sub_1(p));
987 chended(p);
988 return ss_inst_err(p);
989 }
990
991 /* Perform a White Measurement - not recommended */
992 /* (ExecRefMeasuremen is preferred instead) */
so_do_ExecWhiteMeasurement(ss * p)993 inst_code so_do_ExecWhiteMeasurement(
994 ss *p
995 ) {
996 ss_add_soreq(p, ss_ExecWhiteMeasurement);
997 ss_command(p, DF_TMO);
998 ss_sub_soans(p, ss_ExecError);
999 ss_incorp_err(p, ss_sub_1(p));
1000 chended(p);
1001 return ss_inst_err(p);
1002 }
1003
1004 /* - - - - - - - - - - - - */
1005 /* Performing measurements */
1006
1007
1008 /* Perform a Measurement */
so_do_ExecMeasurement(ss * p)1009 inst_code so_do_ExecMeasurement(
1010 ss *p
1011 ) {
1012 #ifdef EMSST
1013 if (p->tmode != 0) {
1014 inst_code rc;
1015 p->tmode = 0;
1016 ss_do_MoveAbsolut(p, ss_rt_SensorRef, 155.0, 230.0);
1017 ss_do_MoveDown(p);
1018 rc = so_do_ExecMeasurement(p);
1019 ss_do_MoveUp(p);
1020 ss_do_MoveAbsolut(p, p->sbr, p->sbx, p->sby);
1021 p->tmode = 1;
1022 return rc;
1023 }
1024 #endif
1025 ss_add_soreq(p, ss_ExecMeasurement);
1026 ss_command(p, 2.0 * DF_TMO);
1027 ss_sub_soans(p, ss_ExecError);
1028 ss_incorp_err(p, ss_sub_1(p));
1029 chended(p);
1030 return ss_inst_err(p);
1031 }
1032
1033 /* Define automatic output after each measurement */
1034 /* [Note that dealing with the resulting measurement replies */
1035 /* isn't directly supported, currently.] */
so_do_SetMeasurementOutput(ss * p,ss_ost os,ss_os o)1036 inst_code so_do_SetMeasurementOutput(
1037 ss *p,
1038 ss_ost os, /* Type of output to request */
1039 ss_os o /* bitmask of output */
1040 ) {
1041 ss_add_soreq(p, ss_SetMeasurementOutput);
1042 ss_add_1(p, os);
1043 ss_add_1(p, o.i);
1044 ss_command(p, DF_TMO);
1045 ss_sub_soans(p, ss_DownloadError);
1046 ss_incorp_remerrset(p, ss_sub_2(p));
1047 chended(p);
1048
1049 return ss_inst_err(p);
1050 }
1051
1052 /* - - - - - - - - */
1053 /* Getting results */
1054
1055 /* so_do_Printout isn't currently defined. */
1056 /* It needs to cope with the expected number of values that */
1057 /* will be returned. This could probably be figured out from */
1058 /* the string itself ? */
1059
1060 /* Query Density measurement results and associated parameters */
so_do_DensityParameterRequest(ss * p,ss_cst * rct,double dv[4],ss_sdft * sdf,ss_rvt * rv,ss_aft * af,ss_wbt * wb,ss_dst * ds,ss_ilt * rit,ss_ot * ot)1061 inst_code so_do_DensityParameterRequest(
1062 ss *p,
1063 ss_cst *rct, /* Return Color Type (Lab/XYZ etc.) */
1064 double dv[4], /* Return Db Dc Dm Dy density values */
1065 ss_sdft *sdf, /* Return Standard Density Filter (Db/Dc/Dm/Dy) */
1066 ss_rvt *rv, /* Return Reference Valid Flag */
1067 ss_aft *af, /* Return filter being used (None/Pol/D65/UV/custom */
1068 ss_wbt *wb, /* Return white base (Paper/Absolute) */
1069 ss_dst *ds, /* Return Density standard (ANSI/DIN/User etc.) */
1070 ss_ilt *rit, /* Return Illuminant type (A/C/D65/User etc.) */
1071 ss_ot *ot /* Return Observer type (2deg/10deg) */
1072 ) {
1073 int i;
1074 ss_add_soreq(p, ss_DensityParameterRequest);
1075 ss_add_1(p, 0x09);
1076 ss_command(p, DF_TMO);
1077 ss_sub_soans(p, ss_DensityParameterAnswer);
1078 ss_sub_soans(p, 0x09);
1079 for (i = 0; i < 4; i++)
1080 dv[i] = ss_sub_double(p);
1081 *sdf = ss_sub_1(p);
1082 *rv = ss_sub_1(p);
1083 *af = ss_sub_1(p);
1084 *wb = ss_sub_1(p);
1085 ss_sub_soans(p, 0x02);
1086 *ds = ss_sub_1(p);
1087 ss_incorp_remerrset(p, ss_sub_2(p));
1088 chended(p);
1089 return ss_inst_err(p);
1090 }
1091
1092 /* Query Densitometric measurement values - not recommended */
1093 /* (DensityParameterRequest is preferred instead) */
so_do_DensityRequest(ss * p,double dv[4],ss_sdft * sdf,ss_rvt * rv)1094 inst_code so_do_DensityRequest(
1095 ss *p,
1096 double dv[4], /* Return Db Dc Dm Dy density values */
1097 ss_sdft *sdf, /* Return Standard Density Filter (Db/Dc/Dm/Dy) */
1098 ss_rvt *rv /* Return Reference Valid */
1099 ) {
1100 int i;
1101 ss_add_soreq(p, ss_DensityRequest);
1102 ss_add_1(p, 0x09);
1103 ss_command(p, DF_TMO);
1104 ss_sub_soans(p, ss_DensityAnswer);
1105 ss_sub_soans(p, 0x09);
1106 for (i = 0; i < 4; i++)
1107 dv[i] = ss_sub_double(p);
1108 *sdf = ss_sub_1(p);
1109 *rv = ss_sub_1(p);
1110 ss_incorp_remerrset(p, ss_sub_2(p));
1111 chended(p);
1112 return ss_inst_err(p);
1113 }
1114
1115 /* Query maximum density reading */
so_do_DmaxRequest(ss * p,double * Dmax,int * lambda,ss_dmot * dmo,ss_rvt * rv)1116 inst_code so_do_DmaxRequest(
1117 ss *p,
1118 double *Dmax, /* Return Value of Maximum Density */
1119 int *lambda, /* Return wavelength where maximum density was found */
1120 ss_dmot *dmo, /* Return Dmax OK flag. */
1121 ss_rvt *rv /* Return Reference Valid Flag */
1122 ) {
1123 ss_add_soreq(p, ss_DmaxRequest);
1124 ss_add_1(p, 0x09);
1125 ss_command(p, DF_TMO);
1126 ss_sub_soans(p, ss_DmaxAnswer);
1127 ss_sub_soans(p, 0x09);
1128 *Dmax = ss_sub_double(p);
1129 *lambda = ss_sub_2(p);
1130 *dmo = ss_sub_1(p);
1131 *rv = ss_sub_1(p);
1132 ss_incorp_remerrset(p, ss_sub_2(p));
1133 chended(p);
1134 return ss_inst_err(p);
1135 }
1136
1137 /* Query Color measurement results and associated parameters */
so_do_CParameterRequest(ss * p,ss_cst ct,ss_cst * rct,double cv[3],ss_rvt * rv,ss_aft * af,ss_wbt * wb,ss_ilt * it,ss_ot * ot)1138 inst_code so_do_CParameterRequest(
1139 ss *p,
1140 ss_cst ct, /* Choose Color Type (Lab/XYZ etc.) */
1141 ss_cst *rct, /* Return Color Type (Lab/XYZ etc.) */
1142 double cv[3], /* Return 3 color values */
1143 ss_rvt *rv, /* Return Reference Valid Flag */
1144 ss_aft *af, /* Return filter being used (None/Pol/D65/UV/custom) */
1145 ss_wbt *wb, /* Return white base (Paper/Absolute) */
1146 ss_ilt *it, /* Return Illuminant type (A/C/D65/User etc.) */
1147 ss_ot *ot /* Return Observer type (2deg/10deg) */
1148 ) {
1149 int i;
1150 ss_add_soreq(p, ss_CParameterRequest);
1151 ss_add_1(p, 0x09);
1152 ss_add_1(p,ct);
1153 ss_command(p, DF_TMO);
1154
1155 ss_sub_soans(p, ss_CParameterAnswer);
1156 ss_sub_soans(p, 0x09);
1157 *rct = ss_sub_1(p);
1158 for (i = 0; i < 3; i++)
1159 cv[i] = ss_sub_double(p);
1160 *rv = ss_sub_1(p);
1161 *af = ss_sub_1(p);
1162 *wb = ss_sub_1(p);
1163 ss_sub_soans(p, 0x02);
1164 *it = ss_sub_1(p);
1165 *ot = ss_sub_1(p);
1166 ss_incorp_remerrset(p, ss_sub_2(p));
1167 chended(p);
1168 return ss_inst_err(p);
1169 }
1170
1171 /* Query Colorimetric measurement results - not recommended */
1172 /* (CParameterRequest is prefered instead) */
so_do_CRequest(ss * p,ss_cst * ct,double * cv[3],ss_rvt * rv)1173 inst_code so_do_CRequest(
1174 ss *p,
1175 ss_cst *ct, /* Return Color Type (Lab/XYZ etc.) */
1176 double *cv[3], /* Return 3 color values */
1177 ss_rvt *rv /* Return Reference Valid Flag */
1178 ) {
1179 int i;
1180 ss_add_soreq(p, ss_CRequest);
1181 ss_add_1(p, 0x09);
1182 ss_command(p, DF_TMO);
1183 ss_sub_soans(p, ss_CAnswer);
1184 ss_sub_soans(p, 0x09);
1185 *ct = ss_sub_1(p);
1186 for (i = 0; i < 3; i++)
1187 *cv[i] = ss_sub_double(p);
1188 *rv = ss_sub_1(p);
1189 ss_incorp_remerrset(p, ss_sub_2(p));
1190 chended(p);
1191 return ss_inst_err(p);
1192 }
1193
1194 /* Query Spectral measurement results and associated parameters */
so_do_SpecParameterRequest(ss * p,ss_st st,ss_st * rst,double sp[36],ss_rvt * rv,ss_aft * af,ss_wbt * wb)1195 inst_code so_do_SpecParameterRequest(
1196 ss *p,
1197 ss_st st, /* Choose Spectrum Type (Reflectance/Density) */
1198 ss_st *rst, /* Return Spectrum Type (Reflectance/Density) */
1199 double sp[36], /* Return 36 spectral values */
1200 ss_rvt *rv, /* Return Reference Valid Flag */
1201 ss_aft *af, /* Return filter being used (None/Pol/D65/UV/custom */
1202 ss_wbt *wb /* Return white base (Paper/Absolute) */
1203 ) {
1204 int i;
1205 ss_add_soreq(p, ss_SpecParameterRequest);
1206 ss_add_1(p, 0x09);
1207 ss_add_1(p,st);
1208 ss_command(p, DF_TMO);
1209 ss_sub_soans(p, ss_SpecParameterAnswer);
1210 ss_sub_soans(p, 0x09);
1211 *rst = ss_sub_1(p);
1212 for (i = 0; i < 36; i++)
1213 sp[i] = ss_sub_double(p);
1214 *rv = ss_sub_1(p);
1215 *af = ss_sub_1(p);
1216 *wb = ss_sub_1(p);
1217 ss_sub_soans(p, 0x02);
1218 ss_incorp_remerrset(p, ss_sub_2(p));
1219 chended(p);
1220 return ss_inst_err(p);
1221 }
1222
1223 /* Query Spectral measurement results - not recommended */
1224 /* (SpecParameterRequest is preferred instead) */
so_do_SpectrumRequest(ss * p,ss_st * st,double sp[36],ss_rvt * rv)1225 inst_code so_do_SpectrumRequest(
1226 ss *p,
1227 ss_st *st, /* Return Spectrum Type (Reflectance/Density) */
1228 double sp[36], /* Return 36 spectral values */
1229 ss_rvt *rv /* Return Reference Valid Flag */
1230 ) {
1231 int i;
1232 ss_add_soreq(p, ss_SpectrumRequest);
1233 ss_add_1(p, 0x09);
1234 ss_command(p, DF_TMO);
1235 ss_sub_soans(p, ss_SpectrumAnswer);
1236 ss_sub_soans(p, 0x09);
1237 *st = ss_sub_1(p);
1238 for (i = 0; i < 36; i++)
1239 sp[i] = ss_sub_double(p);
1240 *rv = ss_sub_1(p);
1241 ss_incorp_remerrset(p, ss_sub_2(p));
1242 chended(p);
1243 return ss_inst_err(p);
1244 }
1245
1246 /* - - - - - - */
1247 /* Miscelanious */
1248
1249 /* Query whether a new measurement was performed since the last access */
so_do_NewMeasureRequest(ss * p,ss_nmt * nm)1250 inst_code so_do_NewMeasureRequest(
1251 ss *p,
1252 ss_nmt *nm /* Return New Measurement (None/Meas/White etc.) */
1253 ) {
1254 ss_add_soreq(p, ss_NewMeasureRequest);
1255 ss_command(p, DF_TMO);
1256 ss_sub_soans(p, ss_NewMeasureAnswer);
1257 if (nm != NULL)
1258 *nm = ss_sub_1(p);
1259 ss_sub_soans(p, 0x09);
1260 chended(p);
1261 return ss_inst_err(p);
1262 }
1263
1264 /* Query whether a key was pressed since the last access */
so_do_NewKeyRequest(ss * p,ss_nkt * nk,ss_ks * k)1265 inst_code so_do_NewKeyRequest(
1266 ss *p,
1267 ss_nkt *nk, /* Return whether a new key was pressed */
1268 ss_ks *k /* Return the key that was pressed (none/meas) */
1269 ) {
1270 ss_add_soreq(p, ss_NewKeyRequest);
1271 ss_command(p, DF_TMO);
1272 ss_sub_soans(p, ss_NewKeyAnswer);
1273 *nk = ss_sub_1(p);
1274 *k = ss_sub_2(p);
1275 chended(p);
1276 return ss_inst_err(p);
1277 }
1278
1279 /* Query for the general error status */
so_do_ActErrorRequest(ss * p)1280 inst_code so_do_ActErrorRequest(
1281 ss *p
1282 ) {
1283 ss_add_soreq(p, ss_ActErrorRequest);
1284 ss_command(p, DF_TMO);
1285 ss_sub_soans(p, ss_ActErrorAnswer);
1286 ss_incorp_err(p, ss_sub_1(p));
1287 chended(p);
1288 return ss_inst_err(p);
1289 }
1290
1291 /* Set Target On/Off status (locks key function of device?) */
so_do_TargetOnOffStDownload(ss * p,ss_toost oo)1292 inst_code so_do_TargetOnOffStDownload(
1293 ss *p,
1294 ss_toost oo /* Activated/Deactivated */
1295 ) {
1296 ss_add_soreq(p, ss_TargetOnOffStDownload);
1297 ss_add_1(p, 0x00);
1298 ss_add_1(p, oo);
1299 ss_add_1(p, 0x00);
1300 ss_command(p, DF_TMO);
1301 ss_sub_soans(p, ss_DownloadError);
1302 ss_incorp_remerrset(p, ss_sub_2(p));
1303 chended(p);
1304 return ss_inst_err(p);
1305 }
1306
1307 /* =========================================== */
1308 /* SpectroScan/T specific commands and queries */
1309
1310 /* - - - - - - - - - - - - - - - - - - - - */
1311 /* Device Initialisation and configuration */
1312
1313 /* Initialise the device. Scans the Spectrolino */
1314 /* (Doesn't work when device is offline ) */
ss_do_ScanInitializeDevice(ss * p)1315 inst_code ss_do_ScanInitializeDevice(ss *p) {
1316 inst_code rv;
1317 ss_add_ssreq(p, ss_InitializeDevice);
1318 ss_command(p, IT_TMO);
1319 ss_sub_ssans(p, ss_ErrorAnswer);
1320 ss_incorp_scanerr(p, ss_sub_1(p));
1321 chended(p);
1322 rv = ss_inst_err(p);
1323
1324 if (rv != inst_ok)
1325 return rv;
1326
1327 /* Wait for Spectroscan to finish init. */
1328 msec_sleep(3000);
1329 return rv;
1330 }
1331
1332 /* Establish communications between the SpectroScan and Spectrolino */
1333 /* at the highest possible baud rate. */
1334 /* (Doesn't work when device is offline ) */
ss_do_ScanSpectrolino(ss * p)1335 inst_code ss_do_ScanSpectrolino(ss *p) {
1336 ss_add_ssreq(p, ss_ScanSpectrolino);
1337 ss_command(p, IT_TMO);
1338 ss_sub_ssans(p, ss_ErrorAnswer);
1339 ss_incorp_scanerr(p, ss_sub_1(p));
1340 chended(p);
1341 return ss_inst_err(p);
1342 }
1343
1344 /* Establish the zero position of the motors and set the position to 0,0 */
1345 /* (Doesn't work when device is offline ) */
ss_do_InitMotorPosition(ss * p)1346 inst_code ss_do_InitMotorPosition(ss *p) {
1347 ss_add_ssreq(p, ss_InitMotorPosition);
1348 ss_command(p, MV_TMO);
1349 ss_sub_ssans(p, ss_ErrorAnswer);
1350 ss_incorp_scanerr(p, ss_sub_1(p));
1351 chended(p);
1352 return ss_inst_err(p);
1353 }
1354
1355 /* Change the SpectroScan baud rate */
ss_do_ChangeBaudRate(ss * p,ss_bt br)1356 inst_code ss_do_ChangeBaudRate(
1357 ss *p,
1358 ss_bt br /* Baud rate (110 - 57600) */
1359 ) {
1360 ss_add_ssreq(p, ss_ChangeBaudRate);
1361 ss_add_1(p, br);
1362 ss_command(p, SH_TMO); /* Don't really expect an answer */
1363 ss_sub_ssans(p, ss_ErrorAnswer);
1364 ss_incorp_scanerr(p, ss_sub_1(p));
1365 chended(p);
1366 return ss_inst_err(p); /* Will probably bomb because comms will break down */
1367 }
1368
1369 /* Change the SpectroScan handshaking mode. */
ss_do_ChangeHandshake(ss * p,ss_hst hs)1370 inst_code ss_do_ChangeHandshake(
1371 ss *p,
1372 ss_hst hs /* Handshake type (None/XonXoff/HW) */
1373 ) {
1374 ss_add_ssreq(p, ss_ChangeHandshake);
1375 ss_add_1(p, hs);
1376 ss_command(p, DF_TMO);
1377 ss_sub_ssans(p, ss_ErrorAnswer);
1378 ss_incorp_scanerr(p, ss_sub_1(p));
1379 chended(p);
1380 return ss_inst_err(p);
1381 }
1382
1383 /* Query the type of XY table */
ss_do_OutputType(ss * p,char dt[19])1384 inst_code ss_do_OutputType(
1385 ss *p,
1386 char dt[19] /* Return Device Type ("SpectroScan", "SpectroScan " or "SpectroScanT") */
1387 ) {
1388 ss_add_ssreq(p, ss_OutputType);
1389 ss_command(p, DF_TMO);
1390 ss_sub_ssans(p, ss_TypeAnswer);
1391 ss_sub_string(p, dt, 18);
1392 chended(p);
1393 #ifdef EMSST
1394 if (strcmp(dt,"SpectroScan ") == 0
1395 || strcmp(dt,"SpectroScan") == 0)
1396 sprintf(dt,"SpectroScanT");
1397 #endif
1398 return ss_inst_err(p);
1399 }
1400
1401 /* Query the serial number of the XY table */
ss_do_OutputSerialNumber(ss * p,unsigned int * sn)1402 inst_code ss_do_OutputSerialNumber(
1403 ss *p,
1404 unsigned int *sn /* Return serial number */
1405 ) {
1406 ss_add_ssreq(p, ss_OutputSerialNumber);
1407 ss_command(p, DF_TMO);
1408 ss_sub_ssans(p, ss_SerialNumberAnswer);
1409 *sn = (unsigned int)ss_sub_4(p);
1410 chended(p);
1411 return ss_inst_err(p);
1412 }
1413
1414 /* Query the part number of the XY table */
ss_do_OutputArticleNumber(ss * p,char pn[9])1415 inst_code ss_do_OutputArticleNumber(
1416 ss *p,
1417 char pn[9] /* Return Part Number */
1418 ) {
1419 ss_add_ssreq(p, ss_OutputArticleNumber);
1420 ss_command(p, DF_TMO);
1421 ss_sub_ssans(p, ss_ArticleNumberAnswer);
1422 ss_sub_string(p, pn, 8);
1423 chended(p);
1424 return ss_inst_err(p);
1425 }
1426
1427 /* Query the production date of the XY table */
ss_do_OutputProductionDate(ss * p,int * yp,int * mp,int * dp)1428 inst_code ss_do_OutputProductionDate(
1429 ss *p,
1430 int *yp, /* Return Year of production (e.g. 1996) */
1431 int *mp, /* Return Month of production (1-12) */
1432 int *dp /* Return Day of production (1-31) */
1433 ) {
1434 ss_add_ssreq(p, ss_OutputProductionDate);
1435 ss_command(p, DF_TMO);
1436 ss_sub_ssans(p, ss_ProductionDateAnswer);
1437 *dp = ss_sub_2(p);
1438 *mp = ss_sub_2(p);
1439 *yp = ss_sub_2(p);
1440 chended(p);
1441 return ss_inst_err(p);
1442 }
1443
1444 /* Query the Software Version of the XY table */
ss_do_OutputSoftwareVersion(ss * p,char sv[13])1445 inst_code ss_do_OutputSoftwareVersion(
1446 ss *p,
1447 char sv[13] /* Return Software Version */
1448 ) {
1449 ss_add_ssreq(p, ss_OutputSoftwareVersion);
1450 ss_command(p, DF_TMO);
1451 ss_sub_ssans(p, ss_SoftwareVersionAnswer);
1452 ss_sub_string(p, sv, 12);
1453 chended(p);
1454 return ss_inst_err(p);
1455 }
1456
1457 /* - - - - - - - - - - - - - */
1458 /* Measurement configuration */
1459
1460 /* Set the SpectroScanT to reflectance or transmission. */
1461 /* The Spectrolino is also automatically set to the corresponding mode. */
1462 /* (Doesn't work when device is offline ) */
ss_do_SetTableMode(ss * p,ss_tmt tm)1463 inst_code ss_do_SetTableMode(
1464 ss *p,
1465 ss_tmt tm /* Table mode (Reflectance/Transmission) */
1466 ) {
1467 #ifdef EMSST
1468 if (tm == ss_tmt_Transmission) {
1469 if (p->tmode == 0) {
1470 ss_do_MoveAbsolut(p, p->sbr, p->sbx, p->sby); /* ?? */
1471 }
1472 p->tmode = 1;
1473 } else {
1474 if (p->tmode != 0) {
1475 p->tmode = 0;
1476 ss_do_MoveHome(p);
1477 }
1478 p->tmode = 0;
1479 }
1480 return inst_ok;
1481 #endif
1482 ss_add_ssreq(p, ss_SetTableMode);
1483 ss_add_1(p, tm);
1484 ss_command(p, IT_TMO);
1485 ss_sub_ssans(p, ss_ErrorAnswer);
1486 ss_incorp_scanerr(p, ss_sub_1(p));
1487 chended(p);
1488 return ss_inst_err(p);
1489 }
1490
1491 /* - - - - - - - - - - - - - */
1492 /* Table operation */
1493
1494 /* Set the SpectrScan to online. All moving keys are disabled. */
1495 /* (Only valid when device is in reflectance mode.) */
ss_do_SetDeviceOnline(ss * p)1496 inst_code ss_do_SetDeviceOnline(ss *p) {
1497 #ifdef EMSST
1498 if (p->tmode != 0)
1499 *((char *)0) = 55;
1500 // return inst_unsupported;
1501 #endif
1502 ss_add_ssreq(p, ss_SetDeviceOnline);
1503 ss_command(p, DF_TMO);
1504 ss_sub_ssans(p, ss_ErrorAnswer);
1505 ss_incorp_scanerr(p, ss_sub_1(p));
1506 chended(p);
1507 return ss_inst_err(p);
1508 }
1509
1510 /* Set the SpectrScan to offline. All moving keys are enabled. */
1511 /* (Only valid when device is in reflectance mode.) */
1512 /* (All remote commands to move the device will be ignored.) */
ss_do_SetDeviceOffline(ss * p)1513 inst_code ss_do_SetDeviceOffline(ss *p) {
1514 #ifdef EMSST
1515 if (p->tmode != 0)
1516 *((char *)0) = 55;
1517 #endif
1518 ss_add_ssreq(p, ss_SetDeviceOffline);
1519 ss_command(p, DF_TMO);
1520 ss_sub_ssans(p, ss_ErrorAnswer);
1521 ss_incorp_scanerr(p, ss_sub_1(p));
1522 chended(p);
1523 return ss_inst_err(p);
1524 }
1525
1526 /* Enable electrostatic paper hold. */
1527 /* (Not valid when device is offline) */
ss_do_HoldPaper(ss * p)1528 inst_code ss_do_HoldPaper(ss *p) {
1529 ss_add_ssreq(p, ss_HoldPaper);
1530 ss_command(p, DF_TMO);
1531 ss_sub_ssans(p, ss_ErrorAnswer);
1532 ss_incorp_scanerr(p, ss_sub_1(p));
1533 chended(p);
1534 return ss_inst_err(p);
1535 }
1536
1537 /* Disable electrostatic paper hold. */
1538 /* (Not valid when device is offline) */
ss_do_ReleasePaper(ss * p)1539 inst_code ss_do_ReleasePaper(ss *p) {
1540 ss_add_ssreq(p, ss_ReleasePaper);
1541 ss_command(p, DF_TMO);
1542 ss_sub_ssans(p, ss_ErrorAnswer);
1543 ss_incorp_scanerr(p, ss_sub_1(p));
1544 chended(p);
1545 return ss_inst_err(p);
1546 }
1547
1548 /* - - - - - - */
1549 /* Positioning */
1550
1551 /* Move either the sight or sensor to an absolute position. */
1552 /* (Doesn't work when device is offline or transmissioin mode.) */
ss_do_MoveAbsolut(ss * p,ss_rt r,double x,double y)1553 inst_code ss_do_MoveAbsolut(
1554 ss *p,
1555 ss_rt r, /* Reference (Sensor/Sight) */
1556 double x, /* X coord in mm, 0-310.0, accurate to 0.1mm */
1557 double y /* Y coord in mm, 0-230.0, accurate to 0.1mm */
1558 ) {
1559 #ifdef EMSST
1560 if (p->tmode != 0)
1561 *((char *)0) = 55;
1562 #endif
1563 ss_add_ssreq(p, ss_MoveAbsolut);
1564 ss_add_1(p, r);
1565 ss_add_2(p, (int)(x * 10 + 0.5));
1566 ss_add_2(p, (int)(y * 10 + 0.5));
1567 ss_command(p, MV_TMO);
1568 ss_sub_ssans(p, ss_ErrorAnswer);
1569 ss_incorp_scanerr(p, ss_sub_1(p));
1570 chended(p);
1571 return ss_inst_err(p);
1572 }
1573
1574 /* Move relative to current position. */
1575 /* (Doesn't work when device is offline or transmissioin mode.) */
ss_do_MoveRelative(ss * p,double x,double y)1576 inst_code ss_do_MoveRelative(
1577 ss *p,
1578 double x, /* X distance in mm, 0-310.0, accurate to 0.1mm */
1579 double y /* Y distance in mm, 0-230.0, accurate to 0.1mm */
1580 ) {
1581 #ifdef EMSST
1582 if (p->tmode != 0)
1583 *((char *)0) = 55;
1584 #endif
1585 ss_add_ssreq(p, ss_MoveRelative);
1586 ss_add_2(p, (int)(x * 10 + 0.5));
1587 ss_add_2(p, (int)(y * 10 + 0.5));
1588 ss_command(p, MV_TMO);
1589 ss_sub_ssans(p, ss_ErrorAnswer);
1590 ss_incorp_scanerr(p, ss_sub_1(p));
1591 chended(p);
1592 return ss_inst_err(p);
1593 }
1594
1595 /* Move to the home position (== 0,0). */
1596 /* (Doesn't work when device is offline or transmissioin mode.) */
ss_do_MoveHome(ss * p)1597 inst_code ss_do_MoveHome(
1598 ss *p
1599 ) {
1600 #ifdef EMSST
1601 if (p->tmode != 0)
1602 *((char *)0) = 55;
1603 #endif
1604 ss_add_ssreq(p, ss_MoveHome);
1605 ss_command(p, MV_TMO);
1606 ss_sub_ssans(p, ss_ErrorAnswer);
1607 ss_incorp_scanerr(p, ss_sub_1(p));
1608 chended(p);
1609 return ss_inst_err(p);
1610 }
1611
1612 /* Move to the sensor up. */
1613 /* (Doesn't work when device is offline or transmissioin mode.) */
ss_do_MoveUp(ss * p)1614 inst_code ss_do_MoveUp(
1615 ss *p
1616 ) {
1617 #ifdef EMSST
1618 if (p->tmode != 0)
1619 *((char *)0) = 55;
1620 #endif
1621 ss_add_ssreq(p, ss_MoveUp);
1622 ss_command(p, MV_TMO);
1623 ss_sub_ssans(p, ss_ErrorAnswer);
1624 ss_incorp_scanerr(p, ss_sub_1(p));
1625 chended(p);
1626 return ss_inst_err(p);
1627 }
1628
1629 /* Move to the sensor down. */
1630 /* (Doesn't work when device is offline or transmission mode.) */
ss_do_MoveDown(ss * p)1631 inst_code ss_do_MoveDown(
1632 ss *p
1633 ) {
1634 #ifdef EMSST
1635 if (p->tmode != 0)
1636 *((char *)0) = 55;
1637 #endif
1638 ss_add_ssreq(p, ss_MoveDown);
1639 ss_command(p, MV_TMO);
1640 ss_sub_ssans(p, ss_ErrorAnswer);
1641 ss_incorp_scanerr(p, ss_sub_1(p));
1642 chended(p);
1643 return ss_inst_err(p);
1644 }
1645
1646 /* Query the current absolute position of the sensor or sight. */
1647 /* (Doesn't work when device is offline or transmissioin mode.) */
ss_do_OutputActualPosition(ss * p,ss_rt r,ss_rt * rr,double * x,double * y,ss_zkt * zk)1648 inst_code ss_do_OutputActualPosition(
1649 ss *p,
1650 ss_rt r, /* Reference (Sensor/Sight) */
1651 ss_rt *rr, /* Return reference (Sensor/Sight) */
1652 double *x, /* Return the X coord in mm, 0-310.0, accurate to 0.1mm */
1653 double *y, /* Return the Y coord in mm, 0-230.0, accurate to 0.1mm */
1654 ss_zkt *zk /* Return the Z coordinate (Up/Down) */
1655 ) {
1656 #ifdef EMSST
1657 if (p->tmode != 0)
1658 *((char *)0) = 55;
1659 #endif
1660 ss_add_ssreq(p, ss_OutputActualPosition);
1661 ss_add_1(p, r);
1662 ss_command(p, DF_TMO);
1663 ss_sub_ssans(p, ss_PositionAnswer);
1664 *rr = ss_sub_1(p);
1665 ss_sub_soans(p, 0x00);
1666 ss_sub_soans(p, 0x00);
1667 *x = ss_sub_2(p)/10.0;
1668 *y = ss_sub_2(p)/10.0;
1669 *zk = ss_sub_1(p);
1670 chended(p);
1671 return ss_inst_err(p);
1672 }
1673
1674 /* Move to the white reference position */
1675 /* (Doesn't work when device is offline or transmissioin mode.) */
ss_do_MoveToWhiteRefPos(ss * p,ss_wrpt wrp)1676 inst_code ss_do_MoveToWhiteRefPos(
1677 ss *p,
1678 ss_wrpt wrp /* White Reference Position (Tile1/Tile2) */
1679 ) {
1680 #ifdef EMSST
1681 if (p->tmode != 0)
1682 *((char *)0) = 55;
1683 #endif
1684 ss_add_ssreq(p, ss_MoveToWhiteRefPos);
1685 ss_add_1(p, wrp);
1686 ss_command(p, MV_TMO);
1687 ss_sub_ssans(p, ss_ErrorAnswer);
1688 ss_incorp_scanerr(p, ss_sub_1(p));
1689 chended(p);
1690 return ss_inst_err(p);
1691 }
1692
1693 /* - - - - - - - - - - - - */
1694 /* Performing measurements */
1695
1696 /* Move the sensor to an absolute position, move the */
1697 /* sensor down, execute a measurement, move the head up, */
1698 /* and return spectral measuring results. */
ss_do_MoveAndMeasure(ss * p,double x,double y,double sp[36],ss_rvt * rv)1699 inst_code ss_do_MoveAndMeasure(
1700 ss *p,
1701 double x, /* X coord in mm, 0-310.0, accurate to 0.1mm */
1702 double y, /* Y coord in mm, 0-230.0, accurate to 0.1mm */
1703 double sp[36], /* Return 36 spectral values */
1704 ss_rvt *rv /* Return Reference Valid Flag */
1705 ) {
1706 #ifdef EMSST
1707 /* Not sure if this is valid on the SpectroScanT in trans mode ? */
1708 if (p->tmode != 0) {
1709 inst_code rc;
1710 p->tmode = 0;
1711 rc = ss_do_MoveAndMeasure(p, 155.0, 230.0, sp, rv);
1712 ss_do_MoveAbsolut(p, p->sbr, p->sbx, p->sby);
1713 p->tmode = 1;
1714 return rc;
1715 }
1716 #endif
1717 ss_add_ssreq(p, ss_MoveAndMeasure);
1718 ss_add_2(p, (int)(x * 10 + 0.5));
1719 ss_add_2(p, (int)(y * 10 + 0.5));
1720 ss_command(p, MV_TMO);
1721 if (ss_peek_ans(p) == ss_SpectrumAnswer) {
1722 int i;
1723 ss_sub_soans(p, ss_SpectrumAnswer);
1724 ss_sub_soans(p, 0x09);
1725 ss_sub_soans(p, 0x00);
1726 for (i = 0; i < 36; i++)
1727 sp[i] = ss_sub_double(p);
1728 *rv = ss_sub_1(p);
1729 ss_incorp_remerrset(p, ss_sub_2(p));
1730 } else {
1731 ss_sub_ssans(p, ss_ErrorAnswer);
1732 ss_incorp_scanerr(p, ss_sub_1(p));
1733 }
1734 chended(p);
1735 return ss_inst_err(p);
1736 }
1737
1738 /* - - - - - - */
1739 /* Miscelanious */
1740
1741 /* Set the SpectroScanT transmission light level during standby. */
1742 /* (Only valid on SpectroScanT in transmission mode) */
ss_do_SetLightLevel(ss * p,ss_llt ll)1743 inst_code ss_do_SetLightLevel(
1744 ss *p,
1745 ss_llt ll /* Transmission light level (Off/Surround/Low) */
1746 ) {
1747 #ifdef EMSST
1748 if (p->tmode != 0)
1749 return inst_ok;
1750 else
1751 *((char *)0) = 55;
1752 #endif
1753 ss_add_ssreq(p, ss_SetLightLevel);
1754 ss_add_1(p, ll);
1755 ss_command(p, DF_TMO);
1756 ss_sub_ssans(p, ss_ErrorAnswer);
1757 ss_incorp_scanerr(p, ss_sub_1(p));
1758 chended(p);
1759 return ss_inst_err(p);
1760 }
1761
1762 /* Set tranmission standby position. */
1763 /* (Only valid on SpectroScanT in transmission mode) */
ss_do_SetTransmStandbyPos(ss * p,ss_rt r,double x,double y)1764 inst_code ss_do_SetTransmStandbyPos(
1765 ss *p,
1766 ss_rt r, /* Reference (Sensor/Sight) */
1767 double x, /* X coord in mm, 0-310.0, accurate to 0.1mm */
1768 double y /* Y coord in mm, 0-230.0, accurate to 0.1mm */
1769 ) {
1770 #ifdef EMSST
1771 if (p->tmode != 0) {
1772 p->sbr = r;
1773 p->sbx = x;
1774 p->sby = y;
1775 return inst_ok;
1776 } else {
1777 *((char *)0) = 55;
1778 }
1779 #endif
1780 ss_add_ssreq(p, ss_SetTransmStandbyPos);
1781 ss_add_1(p, r);
1782 ss_add_2(p, (int)(x * 10 + 0.5));
1783 ss_add_2(p, (int)(y * 10 + 0.5));
1784 ss_command(p, DF_TMO);
1785 ss_sub_ssans(p, ss_ErrorAnswer);
1786 ss_incorp_scanerr(p, ss_sub_1(p));
1787 chended(p);
1788 return ss_inst_err(p);
1789 }
1790
1791 /* Set digitizing mode. Clears digitizing buffer, */
1792 /* and puts the device offline. The user can move */
1793 /* and enter positions. */
ss_do_SetDigitizingMode(ss * p)1794 inst_code ss_do_SetDigitizingMode(ss *p) {
1795 ss_add_ssreq(p, ss_SetDigitizingMode);
1796 ss_command(p, DF_TMO);
1797 ss_sub_ssans(p, ss_ErrorAnswer);
1798 ss_incorp_scanerr(p, ss_sub_1(p));
1799 chended(p);
1800 return ss_inst_err(p);
1801 }
1802
1803 /* Get last digitized position from memory. */
ss_do_OutputDigitizingValues(ss * p,ss_rt r,ss_rt * rr,int * nrp,double * x,double * y,ss_zkt * zk)1804 inst_code ss_do_OutputDigitizingValues(
1805 ss *p,
1806 ss_rt r, /* Reference (Sensor/Sight) */
1807 ss_rt *rr, /* Return reference (Sensor/Sight) */
1808 int *nrp,/* Return the number of remaining positions in memory. */
1809 double *x, /* Return the X coord in mm, 0-310.0, accurate to 0.1mm */
1810 double *y, /* Return the Y coord in mm, 0-230.0, accurate to 0.1mm */
1811 ss_zkt *zk /* Return the Z coordinate (Up/Down) */
1812 ) {
1813 ss_add_ssreq(p, ss_OutputDigitizingValues);
1814 ss_add_1(p, r);
1815 ss_command(p, DF_TMO);
1816 ss_sub_ssans(p, ss_PositionAnswer);
1817 *rr = ss_sub_1(p);
1818 *nrp = ss_sub_2(p); /* Should be unsigned ?? */
1819 *x = ss_sub_2(p)/10.0;
1820 *y = ss_sub_2(p)/10.0;
1821 *zk = ss_sub_1(p);
1822 chended(p);
1823 return ss_inst_err(p);
1824 }
1825
1826 /* Turn on key aknowledge mode. Causes a KeyAnswer message */
1827 /* to be generated whenever a key is pressed. */
1828 /* (KetAnswer isn't well supported here ?) */
ss_do_SetKeyAcknowlge(ss * p)1829 inst_code ss_do_SetKeyAcknowlge(ss *p) {
1830 ss_add_ssreq(p, ss_SetKeyAcknowlge);
1831 ss_command(p, DF_TMO);
1832 ss_sub_ssans(p, ss_ErrorAnswer);
1833 ss_incorp_scanerr(p, ss_sub_1(p));
1834 chended(p);
1835 return ss_inst_err(p);
1836 }
1837
1838 /* Turn off key aknowledge mode. */
ss_do_ResetKeyAcknowlge(ss * p)1839 inst_code ss_do_ResetKeyAcknowlge(ss *p) {
1840 ss_add_ssreq(p, ss_ResetKeyAcknowlge);
1841 ss_command(p, DF_TMO);
1842 ss_sub_ssans(p, ss_ErrorAnswer);
1843 ss_incorp_scanerr(p, ss_sub_1(p));
1844 chended(p);
1845 return ss_inst_err(p);
1846 }
1847
1848 /* Query the keys that are currently pressed */
ss_do_OutputActualKey(ss * p,ss_sks * sk,ss_ptt * pt)1849 inst_code ss_do_OutputActualKey(
1850 ss *p,
1851 ss_sks *sk, /* Return Scan Key Set (Key bitmask) */
1852 ss_ptt *pt /* Return press time (Short/Long) */
1853 ) {
1854 ss_add_ssreq(p, ss_OutputActualKey);
1855 ss_command(p, DF_TMO);
1856 ss_sub_ssans(p, ss_KeyAnswer);
1857 *sk = ss_sub_1(p);
1858 *pt = ss_sub_1(p);
1859 chended(p);
1860 return ss_inst_err(p);
1861 }
1862
1863 /* Query the keys that were last pressed */
ss_do_OutputLastKey(ss * p,ss_sks * sk,ss_ptt * pt)1864 inst_code ss_do_OutputLastKey(
1865 ss *p,
1866 ss_sks *sk, /* Return Scan Key bitmask (Keys) */
1867 ss_ptt *pt /* Return press time (Short/Long) */
1868 ) {
1869 ss_add_ssreq(p, ss_OutputLastKey);
1870 ss_command(p, DF_TMO);
1871 ss_sub_ssans(p, ss_KeyAnswer);
1872 *sk = ss_sub_1(p);
1873 *pt = ss_sub_1(p);
1874 chended(p);
1875 return ss_inst_err(p);
1876 }
1877
1878 /* Query the status register */
ss_do_OutputStatus(ss * p,ss_sts * st)1879 inst_code ss_do_OutputStatus(
1880 ss *p,
1881 ss_sts *st /* Return status bitmask (Enter key/Online/Digitize/KeyAck/Paper) */
1882 ) {
1883 ss_add_ssreq(p, ss_OutputStatus);
1884 ss_command(p, DF_TMO);
1885 ss_sub_ssans(p, ss_StatusAnswer);
1886 *st = ss_sub_1(p);
1887 chended(p);
1888 return ss_inst_err(p);
1889 }
1890
1891 /* Clear the status register */
ss_do_ClearStatus(ss * p,ss_sts st)1892 inst_code ss_do_ClearStatus(
1893 ss *p,
1894 ss_sts st /* Status to reset (Enter key/Online/Digitize/KeyAck/Paper) */
1895 ) {
1896 ss_add_ssreq(p, ss_ClearStatus);
1897 ss_add_1(p, st);
1898 ss_command(p, DF_TMO);
1899 ss_sub_ssans(p, ss_ErrorAnswer);
1900 ss_incorp_scanerr(p, ss_sub_1(p));
1901 chended(p);
1902 return ss_inst_err(p);
1903 }
1904
1905 /* Set the special status register */
1906 /* (Set to all 0 on reset) */
ss_do_SetSpecialStatus(ss * p,ss_sss sss)1907 inst_code ss_do_SetSpecialStatus(
1908 ss *p,
1909 ss_sss sss /* Status bits to set (HeadDwnOnMv/TableInTransMode/AllLightsOn) */
1910 ) {
1911 ss_add_ssreq(p, ss_SetSpecialStatus);
1912 ss_add_1(p, sss);
1913 ss_command(p, DF_TMO);
1914 ss_sub_ssans(p, ss_ErrorAnswer);
1915 ss_incorp_scanerr(p, ss_sub_1(p));
1916 chended(p);
1917 return ss_inst_err(p);
1918 }
1919
1920 /* Clear the special status register */
ss_do_ClearSpecialStatus(ss * p,ss_sss sss)1921 inst_code ss_do_ClearSpecialStatus(
1922 ss *p,
1923 ss_sss sss /* Status bits to clear (HeadDwnOnMv/TableInTransMode/AllLightsOn) */
1924 ) {
1925 ss_add_ssreq(p, ss_ClearSpecialStatus);
1926 ss_add_1(p, sss);
1927 ss_command(p, DF_TMO);
1928 ss_sub_ssans(p, ss_ErrorAnswer);
1929 ss_incorp_scanerr(p, ss_sub_1(p));
1930 chended(p);
1931 return ss_inst_err(p);
1932 }
1933
1934 /* Query the special status register */
ss_do_OutputSpecialStatus(ss * p,ss_sss * sss)1935 inst_code ss_do_OutputSpecialStatus(
1936 ss *p,
1937 ss_sss *sss /* Return Special Status bits */
1938 ) {
1939 ss_add_ssreq(p, ss_OutputSpecialStatus);
1940 ss_command(p, DF_TMO);
1941 ss_sub_ssans(p, ss_StatusAnswer);
1942 *sss = ss_sub_1(p);
1943 chended(p);
1944 return ss_inst_err(p);
1945 }
1946
1947
1948 #define SS_IMP_H
1949 #endif /* SS_IMP_H */
1950
1951
1952