-
Notifications
You must be signed in to change notification settings - Fork 1
/
coprocessorjs.c
708 lines (503 loc) · 23.4 KB
/
coprocessorjs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
#include <stdio.h>
#include <stdlib.h>
#include <Serial.h>
#include <math.h>
#include <Devices.h>
#include "string.h"
#include <stdbool.h>
#include <time.h>
#include "SerialHelper.h"
#include "coprocessorjs.h"
IOParam outgoingSerialPortReference;
IOParam incomingSerialPortReference;
// #define PRINT_ERRORS 1
// #define DEBUGGING 1
#define MAX_ATTEMPTS 10
#define RECEIVE_WINDOW_SIZE 32767 // receive in up to 32kb chunks
#define MAX_RECEIVE_SIZE 32767 // matching RECEIVE_WINDOW_SIZE for now
char *GlobalSerialInputBuffer;
char *tempOutput;
char *application_id;
int call_counter = 0;
// from: https://stackoverflow.com/questions/29847915/implementing-strtok-whose-delimiter-has-more-than-one-character
// basically multichar delimter strtok
char *strtokm(char *str, const char *delim) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: strtokm");
#endif
static char *tok;
static char *next;
char *m;
if (delim == NULL) return NULL;
tok = (str) ? str : next;
if (tok == NULL) return NULL;
m = strstr(tok, delim);
if (m) {
next = m + strlen(delim);
*m = '\0';
} else {
next = NULL;
}
return tok;
}
/*
// http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/Devices/Devices-320.html
Read more: http://stason.org/TULARC/os-macintosh/programming/7-1-How-do-I-get-at-the-serial-ports-Communications-and-N.html#ixzz4cIxU3Tob this one is only useful for enumerating ports
// https://developer.apple.com/library/archive/documentation/mac/pdf/Devices/Serial_Driver.pdf
Serial implementation:
https://opensource.apple.com/source/gdb/gdb-186.1/src/gdb/ser-mac.c?txt another example of a serial library
http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/Devices/Devices-320.html
*/
// notes from above article:
// You can use OpenDriver, SetReset, SetHShake, SetSetBuf, SerGetBuf and
// the other Serial Manager functions on these drivers.
// To write to the
// serial port, use FSWrite for synchronous writes that wait until all is
// written, or PBWrite asynchronously for queuing up data that is supposed
// to go out but you don't want to wait for it.
// At least once each time
// through your event loop, you should call SerGetBuf on the in driver
// reference number you got from OpenDriver, and call FSRead for that many
// bytes - neither more nor less.
// TODO: handle all OSErr - they are all unhandled at the moment
void setupPBControlForSerialPort(short serialPortShort) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: setupPBControlForSerialPort");
#endif
CntrlParam cb;
cb.ioCRefNum = serialPortShort; // TODO: this is always 0 - does it matter? should we hard code 0 here? research
cb.csCode = 8; // TODO: need to look up and document what csCode = 8 means
cb.csParam[0] = stop10 | noParity | data8 | baud28800; // 28.8k has been pretty reliable on my Macintosh Classic...
OSErr err = PBControl ((ParmBlkPtr) & cb, 0); // PBControl definition: http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/Networking/Networking-296.html
#ifdef PRINT_ERRORS
char errMessage[100];
sprintf(errMessage, "err:%d\n", err);
writeSerialPortDebug(boutRefNum, errMessage);
#endif
if (err < 0) {
return;
}
}
void setupSerialPort(const char *name) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: setupSerialPort");
#endif
#define MODEM_PORT_OUT "\p.AOut"
#define MODEM_PORT_IN "\p.AIn"
#define PRINTER_PORT_OUT "\p.BOut"
#define PRINTER_PORT_IN "\p.BIn"
const unsigned char* serialPortOutputName = "\p";
const unsigned char* serialPortInputName = "\p";
if (strcmp (name, "modem") == 0) {
serialPortOutputName = (const unsigned char *)MODEM_PORT_OUT;
serialPortInputName = (const unsigned char *)MODEM_PORT_IN;
} else if (strcmp (name, "printer") == 0) {
serialPortOutputName = (const unsigned char *)PRINTER_PORT_OUT;
serialPortInputName = (const unsigned char *)MODEM_PORT_IN;
} else {
return;
}
short serialPortOutput = 0; // TODO: why is this always 0? is this right?
short serialPortInput = 0; // TODO: not realy sure what this should be - just incrementing from the last item here
OSErr err = MacOpenDriver(serialPortOutputName, &serialPortOutput);
#ifdef PRINT_ERRORS
char errMessage[100];
sprintf(errMessage, "err:%d\n", err);
writeSerialPortDebug(boutRefNum, errMessage);
#endif
if (err < 0) {
return;
}
err = MacOpenDriver(serialPortInputName, &serialPortInput);
#ifdef PRINT_ERRORS
char errMessage[100];
sprintf(errMessage, "err:%d\n", err);
writeSerialPortDebug(boutRefNum, errMessage);
#endif
if (err < 0) {
return;
}
// From https://developer.apple.com/library/archive/documentation/mac/pdf/Devices/Serial_Driver.pdf
// Set baud rate and data format. Note that you only need to set the
// output driver; the settings are reflected on the input side
setupPBControlForSerialPort(serialPortOutput);
outgoingSerialPortReference.ioRefNum = serialPortOutput;
incomingSerialPortReference.ioRefNum = serialPortInput;
// the next 2 commands set up the receive window size to whatever we want, in bytes.
// as far as i can tell, this needs to be set before any data begins flowing, so it seemed
// like a good call to make the buffer a global that gets instantiated at serial port setup
incomingSerialPortReference.ioBuffer = (Ptr)GlobalSerialInputBuffer;
SerSetBuf(incomingSerialPortReference.ioRefNum, incomingSerialPortReference.ioBuffer, RECEIVE_WINDOW_SIZE);
}
void wait(float timeInSeconds) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: wait");
#endif
// from "Inside Macintosh: Macintosh Toolbox Essentials" pg 2-112
// You can use the TickCount function to get the current number of ticks (a tick is
// approximately 1/60 of a second) since the system last started up.
// FUNCTION TickCount: LongInt;
// previous implementation, which might work on more modern platforms (which is why this is left as a comment), was:
// note that this appeared to sometimes be off by as much as 1s on a Macintosh classic (using other normal C time functions to measure...)
// time_t start;
// time_t end;
// time(&start);
// do {
// time(&end);
// } while (difftime(end, start) <= timeInSeconds);
long start;
long end;
long waitTicks = (long)timeInSeconds * 60;
start = TickCount();
do {
end = TickCount();
} while (end - start <= waitTicks);
// char log[255];
// sprintf(log, "start time was %ld end time was %ld split was %ld and wait ticks were %ld, input was %f\n ", start, end, end - start, waitTicks, timeInSeconds);
// printf(log);
}
const int MAX_RECIEVE_LOOP_ITERATIONS = 1000;
// void because this function re-assigns respo
void readSerialPort(char* output) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: readSerialPort");
#endif
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "readSerialPort");
#endif
// make sure output variable is clear
memset(output, '\0', MAX_RECEIVE_SIZE);
memset(tempOutput, '\0', MAX_RECEIVE_SIZE);
bool done = false;
long int totalByteCount = 0;
incomingSerialPortReference.ioReqCount = 0;
int loopCounter = 0;
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "readSerialPort, enter loop");
#endif
// wait a moment for the buffer to fill
wait(0.01);
while (!done) {
if (loopCounter++ > MAX_RECIEVE_LOOP_ITERATIONS) {
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "coprocessor.readSerialPort MAX RECEIVE ITERATIONS");
#endif
char *errorMessage = "TIMEOUT_ERROR";
strncat(output, errorMessage, strlen(output) - 1);
// once we are done reading the buffer entirely, we need to clear it. i'm not sure if this is the best way or not but seems to work
memset(GlobalSerialInputBuffer, '\0', MAX_RECEIVE_SIZE);
return;
}
long int byteCount = 0;
long int lastByteCount = 0;
bool doByteCountsMatch = false;
// the byteCount != lastByteCount portion of the loop means that we want to wait
// for the byteCounts to match between SerGetBuf calls - this means that the buffer
// is full and ready to be read
while (!doByteCountsMatch || byteCount == 0) {
#ifdef DEBUGGING
char debugMessage[100];
sprintf(debugMessage, "receive loop: byteCount: %ld, lastByteCount: %ld\n", byteCount, lastByteCount);
writeSerialPortDebug(boutRefNum, debugMessage);
#endif
lastByteCount = (long int)byteCount;
wait(0.01); // give the buffer a moment to fill
#ifdef PRINT_ERRORS
short serGetBufStatus = SerGetBuf(incomingSerialPortReference.ioRefNum, &byteCount);
if (serGetBufStatus != 0) {
writeSerialPortDebug(boutRefNum, "potential problem with serGetBufStatus:\n");
char debugMessage[100];
sprintf(debugMessage, "serGetBufStatus: %d\n", serGetBufStatus);
writeSerialPortDebug(boutRefNum, debugMessage);
}
#else
SerGetBuf(incomingSerialPortReference.ioRefNum, &byteCount);
#endif
// basically, we're stating that if we have a stall for 2 iterations of the loop where the byteCounts are matching, then
// we assume we are no longer receiving communication. could have bugs? ie, we could be "done" reading before the data is all written
if (byteCount == lastByteCount && byteCount != 0 && lastByteCount != 0) {
#ifdef DEBUGGING
char debugMessage[100];
sprintf(debugMessage, "receive loop setting last doByteCountsMatch to true: byteCount: %ld, lastByteCount: %ld\n", byteCount, lastByteCount);
writeSerialPortDebug(boutRefNum, debugMessage);
#endif
doByteCountsMatch = true;
}
}
#ifdef DEBUGGING
char debugMessage[100];
sprintf(debugMessage, "receive loop complete: byteCount: %ld, lastByteCount: %ld", byteCount, lastByteCount);
writeSerialPortDebug(boutRefNum, debugMessage);
#endif
incomingSerialPortReference.ioReqCount = byteCount;
#ifdef PRINT_ERRORS
OSErr err = PBRead((ParmBlkPtr)&incomingSerialPortReference, 0);
char errMessage[100];
sprintf(errMessage, "err:%d", err);
writeSerialPortDebug(boutRefNum, errMessage);
#else
PBRead((ParmBlkPtr)&incomingSerialPortReference, 0);
#endif
memcpy(tempOutput, GlobalSerialInputBuffer, byteCount);
totalByteCount += byteCount;
if (strstr(tempOutput, ";;@@&&") != NULL) {
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "done building temp output");
writeSerialPortDebug(boutRefNum, tempOutput);
// char debugOutput[255];
// char tempString[MAX_RECEIVE_SIZE];
// strncat(tempString, tempOutput, totalByteCount);
// sprintf(debugOutput, "\n'%ld'\n", strlen(tempString));
// writeSerialPortDebug(boutRefNum, debugOutput);
// writeSerialPortDebug(boutRefNum, "\ndone with output\n");
// writeSerialPortDebug(boutRefNum, "\n");
#endif
done = true;
} else {
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "receive loop complete, but terminator is missing");
writeSerialPortDebug(boutRefNum, tempOutput);
#endif
done = true;
}
}
// attach the gathered up output from the buffer to the output variable
memcpy(output, tempOutput, totalByteCount);
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "coprocessor.readSerialPort complete, output:");
writeSerialPortDebug(boutRefNum, output);
#endif
// once we are done reading the buffer entirely, we need to clear it. i'm not sure if this is the best way or not but seems to work
memset(GlobalSerialInputBuffer, '\0', MAX_RECEIVE_SIZE);
return;
}
OSErr writeSerialPort(const char* stringToWrite) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: writeSerialPort");
#endif
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "writeSerialPort");
#endif
outgoingSerialPortReference.ioBuffer = (Ptr)stringToWrite;
outgoingSerialPortReference.ioReqCount = strlen(stringToWrite);
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "attempting to write string to serial port");
// writeSerialPortDebug(boutRefNum, stringToWrite);
#endif
// PBWrite Definition From Inside Macintosh Volume II-185:
// PBWrite takes ioReqCount bytes from the buffer pointed to by ioBuffer and attempts to write them to the device driver having the reference number ioRefNum.
// The drive number, if any, of the device to be written to is specified by ioVRefNum. After the write is completed, the position is returned in ioPosOffset and the number of bytes actually written is returned in ioActCount.
OSErr err = PBWrite((ParmBlkPtr)& outgoingSerialPortReference, 0);
#ifdef PRINT_ERRORS
char errMessage[100];
sprintf(errMessage, "err:%d\n", err);
writeSerialPortDebug(boutRefNum, errMessage);
#endif
return err;
}
void setupCoprocessor(char *applicationId, const char *serialDeviceName) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: setupCoprocessor");
#endif
GlobalSerialInputBuffer = malloc(sizeof(char) * MAX_RECEIVE_SIZE);
tempOutput = malloc(sizeof(char) * MAX_RECEIVE_SIZE);
application_id = malloc(sizeof(char) * 255);
strcpy(application_id, applicationId);
setupSerialPort(serialDeviceName);
return;
}
OSErr closeSerialPort() {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: closeSerialPort");
#endif
OSErr err = MacCloseDriver(outgoingSerialPortReference.ioRefNum);
#ifdef PRINT_ERRORS
char errMessage[100];
sprintf(errMessage, "err:%d\n", err);
writeSerialPortDebug(boutRefNum, errMessage);
#endif
return err;
}
// return value is char but this is only for error messages - final param is output variable that will be re-assigned within this function
char* _getReturnValueFromResponse(char* response, char* application_id, char* call_counter, char* operation, char* output) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: _getReturnValueFromResponse");
#endif
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "_getReturnValueFromResponse\n");
writeSerialPortDebug(boutRefNum, response);
writeSerialPortDebug(boutRefNum, "\n");
#endif
// get the first token in to memory
char *token = strtokm(response, ";;;");
// we need to track the token that we are on because the coprocessor.js responses are standardized
// so the tokens at specific positions will map to specific items in the response
int tokenCounter = 0;
// loop through the string to extract all other tokens
while (token != NULL) {
if (tokenCounter > MAX_ATTEMPTS) {
return "max attempts exceeded";
}
#ifdef DEBUGGING
char debugOutput[MAX_RECEIVE_SIZE];
sprintf(debugOutput, "inspect token %d: %s\n", tokenCounter, token);
writeSerialPortDebug(boutRefNum, debugOutput);
#endif
switch (tokenCounter) {
case 0: // APPLICATION ID
if (strcmp(token, application_id) != 0) {
return "application id mismatch"; // TODO figure out better error handling
}
break;
case 1: // CALL COUNTER
if (strcmp(token, call_counter) != 0) {
return "call counter mismatch"; // TODO figure out better error handling
}
break;
case 2: // OPERATION
if (strcmp(token, operation) != 0) {
return "operation mismatch"; // TODO figure out better error handling
}
break;
case 3: // STATUS
if (strcmp(token, "SUCCESS") != 0) {
return "operation failed"; // TODO figure out better error handling
}
break;
case 4:;
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "setting output to token:\n");
writeSerialPortDebug(boutRefNum, token);
char debugOutput[255];
sprintf(debugOutput, "\n'%ld'\n", strlen(token));
writeSerialPortDebug(boutRefNum, debugOutput);
writeSerialPortDebug(boutRefNum, "\ndone with output\n");
#endif
int lengthWithoutControlChars = strlen(token) - 6;
// writeSerialPortDebug(boutRefNum, "SETTING OUTPUT VARIABLE");
// char x[2555];
// sprintf(x, "%s: %d (%.*s)", token, lengthWithoutControlChars, lengthWithoutControlChars, token);
// writeSerialPortDebug(boutRefNum, x);
// this seems to be the location where we can sometimes mangle our response data
sprintf(output, "%.*s", lengthWithoutControlChars, token); // drop the ;;@@&& off the end of the response
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, output);
#endif
return NULL;
default:
break;
}
// get the next token. strtokm has some weird syntax
token = strtokm(NULL, ";;;");
tokenCounter++;
}
return NULL;
}
void writeToCoprocessor(char* operation, char* operand) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: writeToCoprocessor");
#endif
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "writeToCoprocessor\n");
#endif
const char* messageTemplate = "%s;;;%s;;;%s;;;%s;;@@&&"; // see: https://github.com/CamHenlin/coprocessor.js/blob/main/index.js#L25
char call_id[32];
// over-allocate by 1kb for the operand (which could be an entire nodejs app) + message template wrapper
// and other associated info. wasting a tiny bit of memory here, could get more precise if memory becomes a problem.
char messageToSend[strlen(operand) + 1024];
sprintf(call_id, "%d", call_counter++);
// application_id is globally defined for now, how will that work in a library?
sprintf(messageToSend, messageTemplate, application_id, call_id, operation, operand);
#ifdef PRINT_ERRORS
OSErr err = writeSerialPort(messageToSend);
char errMessage[100];
sprintf(errMessage, "writeToCoprocessor err:%d\n", err);
writeSerialPortDebug(boutRefNum, errMessage);
#else
writeSerialPort(messageToSend);
#endif
return;
}
// must be called after writeToCoprocessor and before other writeToCoprocessor
// operations because we depend on the location of call_counter
void getReturnValueFromResponse(char *response, char *operation, char *output) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: getReturnValueFromResponse");
#endif
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "getReturnValueFromResponse");
#endif
char call_id[32];
sprintf(call_id, "%d", call_counter - 1);
#ifdef PRINT_ERRORS
char *err = _getReturnValueFromResponse(response, application_id, call_id, operation, output);
if (err != NULL) {
writeSerialPortDebug(boutRefNum, "error getting return value from response:");
writeSerialPortDebug(boutRefNum, err);
}
#else
_getReturnValueFromResponse(response, application_id, call_id, operation, output);
#endif
}
// TODO: these should all bubble up and return legible errors
void sendProgramToCoprocessor(char* program, char *output) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: sendProgramToCoprocessor");
#endif
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "sendProgramToCoprocessor");
#endif
SetCursor(*GetCursor(watchCursor));
writeToCoprocessor("PROGRAM", program);
char serialPortResponse[MAX_RECEIVE_SIZE];
readSerialPort(serialPortResponse);
getReturnValueFromResponse(serialPortResponse, "PROGRAM", output);
SetCursor(&qd.arrow);
return;
}
void callFunctionOnCoprocessor(char* functionName, char* parameters, char* output) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: callFunctionOnCoprocessor");
#endif
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "callFunctionOnCoprocessor\n");
#endif
const char* functionTemplate = "%s&&&%s";
// over-allocate by 1kb for the operand (which could be whatever a programmer sends to this function) + message template wrapper
// and other associated info. wasting a tiny bit of memory here, could get more precise if memory becomes a problem.
char functionCallMessage[strlen(parameters) + 1024];
// delimeter for function paramters is &&& - user must do this on their own via sprintf call or other construct - this is easiest for us to deal with
sprintf(functionCallMessage, functionTemplate, functionName, parameters);
SetCursor(*GetCursor(watchCursor));
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, functionCallMessage);
#endif
writeToCoprocessor("FUNCTION", functionCallMessage);
char serialPortResponse[MAX_RECEIVE_SIZE];
readSerialPort(serialPortResponse);
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "Got response from serial port:");
writeSerialPortDebug(boutRefNum, serialPortResponse);
#endif
memset(output, '\0', RECEIVE_WINDOW_SIZE);
getReturnValueFromResponse(serialPortResponse, "FUNCTION", output);
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "Got return value from response");
writeSerialPortDebug(boutRefNum, output);
#endif
SetCursor(&qd.arrow);
return;
}
void callEvalOnCoprocessor(char* toEval, char* output) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: callEvalOnCoprocessor");
#endif
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "callEvalOnCoprocessor\n");
#endif
writeToCoprocessor("EVAL", toEval);
char serialPortResponse[MAX_RECEIVE_SIZE];
readSerialPort(serialPortResponse);
getReturnValueFromResponse(serialPortResponse, "EVAL", output);
return;
}