Line data Source code
1 : /********************************************************************\
2 :
3 : Name: mscb.c
4 : Created by: Stefan Ritt
5 :
6 : Contents: Midas Slow Control Bus communication functions
7 :
8 : $Id$
9 :
10 : \********************************************************************/
11 :
12 : #include <map>
13 : #include <string>
14 : #include "mscb.h"
15 : #include "mscbrpc.h"
16 : #include "mstrlcpy.h"
17 :
18 : #define MSCB_LIBRARY_VERSION "2.7.0"
19 : #define MSCB_PROTOCOL_VERSION 5
20 :
21 : #undef DEBUG_ETH
22 :
23 : #ifdef OS_WINNT
24 :
25 : #pragma warning(disable:4996)
26 :
27 : #include <windows.h>
28 : #include <conio.h>
29 : #include <sys/timeb.h>
30 : #include <time.h>
31 : #include <io.h>
32 : #include <fcntl.h>
33 :
34 : #elif defined(OS_DARWIN)
35 :
36 : #define O_BINARY 0
37 :
38 : #include <unistd.h>
39 : #include <string.h>
40 : #include <stdlib.h>
41 : #include <ctype.h>
42 : #include <sys/types.h>
43 : #include <sys/ioctl.h>
44 : #include <sys/time.h>
45 : #include <fcntl.h>
46 : #include <sys/sem.h>
47 : #include <errno.h>
48 : #include <netinet/in.h>
49 : #include <netdb.h>
50 : #include <arpa/inet.h>
51 : #include <pthread.h>
52 :
53 : #include <assert.h>
54 : #include <mach/mach.h>
55 : #include <IOKit/IOKitLib.h>
56 : #include <IOKit/IOCFPlugIn.h>
57 :
58 : #elif defined(OS_LINUX) // Linux includes
59 :
60 : #define O_BINARY 0
61 :
62 : #include <errno.h>
63 : #include <unistd.h>
64 : #include <stdarg.h>
65 : #include <string.h>
66 : #include <stdlib.h>
67 : #include <ctype.h>
68 : #include <time.h>
69 : #include <sys/socket.h>
70 : #include <sys/types.h>
71 : #include <sys/ioctl.h>
72 : #include <sys/time.h>
73 : #include <sys/timeb.h>
74 : #include <sys/sem.h>
75 : #include <fcntl.h>
76 : #include <netinet/in.h>
77 : #include <arpa/inet.h>
78 : #include <netdb.h>
79 : #include <pthread.h>
80 :
81 : #endif
82 :
83 : #include <stdio.h>
84 : #include <assert.h>
85 :
86 : #include "mstrlcpy.h"
87 :
88 : /*------------------------------------------------------------------*/
89 :
90 : MSCB_FD mscb_fd[MSCB_MAX_FD];
91 :
92 : /* constants */
93 :
94 : #define TO_SHORT 10 /* 10 ms for ping */
95 : #define TO_LONG 1000 /* 1 s for flash */
96 : #define TO_VERYLONG 5000 /* 5 s for first UDP packet */
97 :
98 : int _debug_flag = -1; /* global debug flag */
99 : void debug_log(const char *format, int write, ...);
100 :
101 : /* RS485 flags for submaster */
102 : #define RS485_FLAG_BIT9 (1<<0)
103 : #define RS485_FLAG_NO_ACK (1<<1)
104 : #define RS485_FLAG_SHORT_TO (1<<2) /* short timeout for ping */
105 : #define RS485_FLAG_LONG_TO (1<<3) /* long timeout for flash */
106 : #define RS485_FLAG_CMD (1<<4)
107 : #define RS485_FLAG_ADR_CYCLE (1<<5)
108 : #define RS485_FLAG_NO_RETRY (1<<6) /* for mscb_scan_udp */
109 : #define RS485_FLAG_VERYLONG_TO (1<<7) /* very long timeout for first UDP packet */
110 :
111 : /* header for UDP communication */
112 : typedef struct {
113 : unsigned short size;
114 : unsigned short seq_num;
115 : unsigned char flags;
116 : unsigned char version;
117 : } UDP_HEADER;
118 :
119 : /*------------------------------------------------------------------*/
120 :
121 : /* cache definitions for mscb_link */
122 :
123 : typedef struct {
124 : int fd;
125 : unsigned short adr;
126 : unsigned char index;
127 : void *data;
128 : unsigned char size;
129 : unsigned long last;
130 : } CACHE_ENTRY;
131 :
132 : CACHE_ENTRY *cache;
133 : int n_cache;
134 :
135 : #define CACHE_PERIOD 500 // update cache every 500 ms
136 :
137 : /*------------------------------------------------------------------*/
138 :
139 : /* cache definitions for mscb_info_var */
140 :
141 : typedef struct {
142 : int fd;
143 : unsigned short adr;
144 : unsigned char index;
145 : MSCB_INFO_VAR info;
146 : } CACHE_INFO_VAR;
147 :
148 : CACHE_INFO_VAR *cache_info_var = NULL;
149 : int n_cache_info_var;
150 :
151 : void mscb_clear_info_cache();
152 :
153 : /*------------------------------------------------------------------*/
154 :
155 : std::map<int, std::string> g_prefixMap = {
156 : {PRFX_PICO, "pico"},
157 : {PRFX_NANO, "nano"},
158 : {PRFX_MICRO, "micro"},
159 : {PRFX_MILLI, "milli"},
160 : {PRFX_NONE, ""},
161 : {PRFX_KILO, "kilo"},
162 : {PRFX_MEGA, "mega"},
163 : {PRFX_GIGA, "giga"},
164 : {PRFX_TERA, "tera"}
165 : };
166 :
167 : std::map<int, std::string> g_prefixMapShort = {
168 : {PRFX_PICO, "p"},
169 : {PRFX_NANO, "n"},
170 : {PRFX_MICRO, "u"},
171 : {PRFX_MILLI, "m"},
172 : {PRFX_NONE, ""},
173 : {PRFX_KILO, "k"},
174 : {PRFX_MEGA, "M"},
175 : {PRFX_GIGA, "G"},
176 : {PRFX_TERA, "T"}
177 : };
178 :
179 : std::map<int, std::string> g_unitTable = {
180 : {UNIT_METER, "meter"},
181 : {UNIT_GRAM, "gram"},
182 : {UNIT_SECOND, "second"},
183 : {UNIT_MINUTE, "minute"},
184 : {UNIT_HOUR, "hour"},
185 : {UNIT_AMPERE, "ampere"},
186 : {UNIT_KELVIN, "kelvin"},
187 : {UNIT_CELSIUS, "deg. celsius"},
188 : {UNIT_FARENHEIT, "deg. farenheit"},
189 :
190 : {UNIT_HERTZ, "hertz"},
191 : {UNIT_PASCAL, "pascal"},
192 : {UNIT_BAR, "bar"},
193 : {UNIT_WATT, "watt"},
194 : {UNIT_VOLT, "volt"},
195 : {UNIT_OHM, "ohm"},
196 : {UNIT_TESLA, "tesla"},
197 : {UNIT_LITERPERSEC, "liter/sec"},
198 : {UNIT_RPM, "RPM"},
199 : {UNIT_FARAD, "farad"},
200 :
201 : {UNIT_BOOLEAN, "boolean"},
202 : {UNIT_BYTE, "byte"},
203 : {UNIT_WORD, "word"},
204 : {UNIT_DWORD, "dword"},
205 : {UNIT_ASCII, "ascii"},
206 : {UNIT_STRING, "string"},
207 : {UNIT_BAUD, "baud"},
208 :
209 : {UNIT_PERCENT, "percent"},
210 : {UNIT_PPM, "RPM"},
211 : {UNIT_COUNT, "counts"},
212 : {UNIT_FACTOR, "factor"}
213 : };
214 :
215 : std::map<int, std::string> g_unitTableShort = {
216 : {UNIT_METER, "m"},
217 : {UNIT_GRAM, "g"},
218 : {UNIT_SECOND, "s"},
219 : {UNIT_MINUTE, "m"},
220 : {UNIT_HOUR, "h"},
221 : {UNIT_AMPERE, "A"},
222 : {UNIT_KELVIN, "K"},
223 : {UNIT_CELSIUS, "C"},
224 : {UNIT_FARENHEIT, "F"},
225 :
226 : {UNIT_HERTZ, "Hz"},
227 : {UNIT_PASCAL, "Pa"},
228 : {UNIT_BAR, "bar"},
229 : {UNIT_WATT, "W"},
230 : {UNIT_VOLT, "V"},
231 : {UNIT_OHM, "O"},
232 : {UNIT_TESLA, "T"},
233 : {UNIT_LITERPERSEC, "l/s"},
234 : {UNIT_RPM, "RPM"},
235 : {UNIT_FARAD, "F"},
236 :
237 : {UNIT_BOOLEAN, "boolean"},
238 : {UNIT_BYTE, "B"},
239 : {UNIT_WORD, "W"},
240 : {UNIT_DWORD, "DW"},
241 : {UNIT_ASCII, "ASC"},
242 : {UNIT_STRING, "str"},
243 : {UNIT_BAUD, "bd"},
244 :
245 : {UNIT_PERCENT, "%"},
246 : {UNIT_PPM, "RPM"},
247 : {UNIT_COUNT, "cot"},
248 : {UNIT_FACTOR, "factor"}
249 : };
250 :
251 : /*------------------------------------------------------------------*/
252 :
253 : /* missing linux functions */
254 :
255 : #if defined(OS_LINUX)
256 :
257 0 : int kbhit() {
258 : int n;
259 :
260 0 : ioctl(0, FIONREAD, &n);
261 0 : return (n > 0);
262 : }
263 :
264 : #endif
265 :
266 : /*------------------------------------------------------------------*/
267 :
268 0 : unsigned long millitime() {
269 : #ifdef _MSC_VER
270 : return (int) GetTickCount();
271 : #else
272 : {
273 : struct timeval tv;
274 :
275 0 : gettimeofday(&tv, NULL);
276 :
277 0 : return tv.tv_sec * 1000 + tv.tv_usec / 1000;
278 : }
279 : #endif
280 : }
281 :
282 : /*------------------------------------------------------------------*/
283 :
284 0 : int mscb_thread_get_name(char *str, int size) {
285 : #if defined(__linux__) || defined(__APPLE__)
286 0 : pthread_t thread = pthread_self();
287 0 : pthread_getname_np(thread, str, size);
288 0 : return 1;
289 : #else
290 : return 0;
291 : #endif
292 : }
293 :
294 : /*------------------------------------------------------------------*/
295 :
296 0 : void debug_log(const char *format, int write_flag, ...) {
297 : int fh;
298 : char str[2000], line[2000];
299 : va_list argptr;
300 :
301 0 : if (_debug_flag == 0 || (_debug_flag == 1 && !write_flag))
302 0 : return;
303 :
304 0 : line[0] = 0;
305 : #if defined(OS_WINNT)
306 : struct timespec ts;
307 : timespec_get(&ts, TIME_UTC);
308 : mstrlcpy(line, ctime(&ts.tv_sec) + 11, sizeof(line));
309 : sprintf(line + 8, ".%03d ", (int)ts.tv_nsec / 1000000);
310 : #else
311 : struct timeval tv;
312 0 : gettimeofday(&tv, NULL);
313 0 : mstrlcpy(line, ctime(&tv.tv_sec) + 11, sizeof(line));
314 0 : snprintf(line + 8, sizeof(line)-8, ".%03d ", (int)tv.tv_usec / 1000);
315 : #endif
316 :
317 0 : mscb_thread_get_name(str, sizeof(str));
318 0 : mstrlcat(line, str, sizeof(line));
319 0 : mstrlcat(line, " ", sizeof(line));
320 :
321 0 : va_start(argptr, write_flag);
322 0 : vsnprintf(str, sizeof(str), (char *) format, argptr);
323 0 : va_end(argptr);
324 :
325 0 : mstrlcat(line, str, sizeof(line));
326 0 : mstrlcat(line, "\n", sizeof(line));
327 :
328 : /* if debug flag equals 3, write to stdout */
329 0 : if (_debug_flag == 3)
330 0 : write(fileno(stdout), line, strlen(line));
331 : else {
332 : /* write to file */
333 0 : fh = open("mscb_debug.log", O_CREAT | O_WRONLY | O_APPEND, 0644);
334 0 : if (fh < 0)
335 0 : return;
336 :
337 0 : write(fh, line, strlen(line));
338 0 : close(fh);
339 : }
340 : }
341 :
342 : /*------------------------------------------------------------------*/
343 :
344 : unsigned char crc8_data[] = {
345 : 0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83,
346 : 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41,
347 : 0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e,
348 : 0x5f, 0x01, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc,
349 : 0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0,
350 : 0xe1, 0xbf, 0x5d, 0x03, 0x80, 0xde, 0x3c, 0x62,
351 : 0xbe, 0xe0, 0x02, 0x5c, 0xdf, 0x81, 0x63, 0x3d,
352 : 0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff,
353 : 0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5,
354 : 0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x07,
355 : 0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x06, 0x58,
356 : 0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a,
357 : 0x65, 0x3b, 0xd9, 0x87, 0x04, 0x5a, 0xb8, 0xe6,
358 : 0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24,
359 : 0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b,
360 : 0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x05, 0xe7, 0xb9,
361 : 0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0x0f,
362 : 0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd,
363 : 0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92,
364 : 0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0x0e, 0x50,
365 : 0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c,
366 : 0x6d, 0x33, 0xd1, 0x8f, 0x0c, 0x52, 0xb0, 0xee,
367 : 0x32, 0x6c, 0x8e, 0xd0, 0x53, 0x0d, 0xef, 0xb1,
368 : 0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73,
369 : 0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49,
370 : 0x08, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b,
371 : 0x57, 0x09, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4,
372 : 0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16,
373 : 0xe9, 0xb7, 0x55, 0x0b, 0x88, 0xd6, 0x34, 0x6a,
374 : 0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8,
375 : 0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7,
376 : 0xb6, 0xe8, 0x0a, 0x54, 0xd7, 0x89, 0x6b, 0x35,
377 : };
378 :
379 0 : unsigned char crc8(unsigned char *data, int len)
380 : /********************************************************************\
381 :
382 : Routine: crc8
383 :
384 : Purpose: Calculate 8-bit cyclic redundancy checksum
385 :
386 : Input:
387 : unsigned char *data data buffer
388 : int len data length in bytes
389 :
390 :
391 : Function value:
392 : unsighend char CRC-8 code
393 :
394 : \********************************************************************/
395 : {
396 : int i;
397 : unsigned char crc8_code, index;
398 :
399 0 : crc8_code = 0;
400 0 : for (i = 0; i < len; i++) {
401 0 : index = data[i] ^ crc8_code;
402 0 : crc8_code = crc8_data[index];
403 : }
404 :
405 0 : return crc8_code;
406 : }
407 :
408 : /*------------------------------------------------------------------*/
409 :
410 0 : int strieq(const char *str1, const char *str2) {
411 0 : if (str1 == NULL && str2 != NULL)
412 0 : return 0;
413 0 : if (str1 != NULL && str2 == NULL)
414 0 : return 0;
415 0 : if (str1 == NULL && str2 == NULL)
416 0 : return 1;
417 :
418 0 : while (*str1)
419 0 : if (toupper(*str1++) != toupper(*str2++))
420 0 : return 0;
421 :
422 0 : if (*str2)
423 0 : return 0;
424 :
425 0 : return 1;
426 : }
427 :
428 : /*------------------------------------------------------------------*/
429 :
430 0 : int host2ip(const char *hostname, char *ip, int size) {
431 : struct hostent *he;
432 : struct in_addr **addr_list;
433 : char host[256];
434 : #ifdef _MSC_VER
435 : {
436 : WSADATA WSAData;
437 :
438 : /* Start windows sockets */
439 : if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
440 : return -1;
441 : }
442 : #endif
443 :
444 0 : memset(ip, 0, size);
445 :
446 0 : mstrlcpy(host, hostname, sizeof(host));
447 0 : if (strchr(host, ':'))
448 0 : *strchr(host, ':') = 0;
449 0 : he = gethostbyname(host);
450 0 : if (he == NULL) {
451 0 : if (h_errno == HOST_NOT_FOUND)
452 0 : printf("Host \"%s\" not found\n", hostname);
453 : else
454 0 : printf("gethostbyname: error %d\n", h_errno);
455 0 : return 0;
456 : }
457 :
458 0 : addr_list = (struct in_addr **) he->h_addr_list;
459 :
460 0 : if (addr_list[0] != NULL) {
461 : //Return the first one;
462 0 : mstrlcpy(ip, inet_ntoa(*addr_list[0]), size);
463 0 : return 1;
464 : }
465 :
466 0 : return 0;
467 : }
468 :
469 : /*----retries and timeouts------------------------------------------*/
470 :
471 : static int mscb_max_retry = 10;
472 :
473 0 : int mscb_get_max_retry()
474 : /********************************************************************\
475 :
476 : Routine: mscb_get_max_retry
477 :
478 : Purpose: Get the current setting of the MSCB maximum retry limit
479 :
480 : Return value:
481 : current value of the MSCB maximum retry limit
482 :
483 : \********************************************************************/
484 : {
485 0 : return mscb_max_retry;
486 : }
487 :
488 0 : int EXPRT mscb_set_max_retry(int max_retry)
489 : /********************************************************************\
490 :
491 : Routine: mscb_set_max_retry
492 :
493 : Purpose: Set the limit for retrying MSCB operations
494 :
495 : Input:
496 : int max_retry new value of the mscb maximum retry limit
497 :
498 : Function value:
499 : old value of the maximum retry limit
500 :
501 : \********************************************************************/
502 : {
503 0 : int old_retry = mscb_max_retry;
504 0 : mscb_max_retry = max_retry;
505 0 : return old_retry;
506 : }
507 :
508 0 : int mscb_get_eth_max_retry(int fd)
509 : /********************************************************************\
510 :
511 : Routine: mscb_get_eth_max_retry
512 :
513 : Purpose: Get the current setting of the MSCB ethernet retry limit
514 :
515 : Input:
516 : inf fd file descriptor for mscb connection
517 :
518 : Return value:
519 : current value of the MSCB ethernet retry limit
520 :
521 : \********************************************************************/
522 : {
523 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
524 0 : return MSCB_INVAL_PARAM;
525 :
526 0 : return mscb_fd[fd - 1].eth_max_retry;
527 : }
528 :
529 0 : int EXPRT mscb_set_eth_max_retry(int fd, int eth_max_retry)
530 : /********************************************************************\
531 :
532 : Routine: mscb_set_eth_max_retry
533 :
534 : Purpose: Set retry limit for MSCB ethernet communications
535 :
536 : Input:
537 : inf fd file descriptor for mscb connection
538 : int eth_max_retry new value for ethernet retry limit
539 :
540 : Function value:
541 : old value of the ethernet maximum retry limit
542 :
543 : \********************************************************************/
544 : {
545 : int old_retry;
546 :
547 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
548 0 : return MSCB_INVAL_PARAM;
549 :
550 0 : old_retry = mscb_fd[fd - 1].eth_max_retry;
551 0 : mscb_fd[fd - 1].eth_max_retry = eth_max_retry;
552 0 : return old_retry;
553 : }
554 :
555 0 : unsigned int mscb_get_eth_pause(int fd)
556 : /********************************************************************\
557 :
558 : Routine: mscb_get_eth_pause
559 :
560 : Purpose: Get the current pause time of the MSCB ethernet communication
561 :
562 : Input:
563 : inf fd file descriptor for mscb connection
564 :
565 : Return value:
566 : current value of the MSCB paus time in ms
567 :
568 : \********************************************************************/
569 : {
570 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
571 0 : return MSCB_INVAL_PARAM;
572 :
573 0 : return mscb_fd[fd - 1].eth_comm_pause;
574 : }
575 :
576 0 : int EXPRT mscb_set_eth_pause(int fd, unsigned int pause)
577 : /********************************************************************\
578 :
579 : Routine: mscb_set_eth_pause
580 :
581 : Purpose: Get the current pause time of the MSCB ethernet communication
582 :
583 : Input:
584 : inf fd file descriptor for mscb connection
585 : int eth_max_retry new value in ms
586 :
587 : Function value:
588 : MSCB_SUCCESS Successful completion
589 :
590 : \********************************************************************/
591 : {
592 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
593 0 : return MSCB_INVAL_PARAM;
594 :
595 0 : mscb_fd[fd - 1].eth_comm_pause = pause;
596 0 : return MSCB_SUCCESS;
597 : }
598 :
599 : /*---- mutex functions ------------------------------------------*/
600 :
601 : #ifdef _MSC_VER
602 : HANDLE mscb_mutex_create(const char *)
603 : #else
604 0 : MUTEX_T *mscb_mutex_create(const char *device)
605 : #endif
606 : {
607 : #ifdef _MSC_VER
608 : return CreateMutex(NULL, FALSE, device);
609 : #elif defined(OS_LINUX)
610 :
611 : pthread_mutex_t *mutex;
612 : int status;
613 :
614 0 : mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
615 0 : assert(mutex);
616 :
617 0 : status = pthread_mutex_init(mutex, NULL);
618 0 : if (status != 0) {
619 0 : fprintf(stderr, "ss_mutex_create: pthread_mutex_init() for device %s returned errno %d (%s), aborting...\n",
620 : device, status, strerror(status));
621 0 : abort(); // does not return
622 : }
623 :
624 0 : return mutex;
625 : #endif // OS_LINUX
626 : }
627 :
628 : /*------------------------------------------------------------------*/
629 :
630 0 : int mscb_lock(int fd) {
631 : #ifdef _MSC_VER
632 : int status;
633 :
634 : /* wait with a timeout of 10 seconds */
635 : status = WaitForSingleObject(mscb_fd[fd - 1].mutex, 10000);
636 :
637 : if (status == WAIT_FAILED)
638 : return 0;
639 : if (status == WAIT_TIMEOUT)
640 : return 0;
641 :
642 : #elif defined(OS_LINUX)
643 :
644 : int status;
645 :
646 0 : if (mscb_fd[fd - 1].type == MSCB_TYPE_ETH) {
647 : #ifdef DEBUG_ETH
648 : debug_log("mutex %p try lock", 0, mscb_fd[fd - 1].mutex);
649 : #endif
650 0 : status = pthread_mutex_lock(mscb_fd[fd - 1].mutex);
651 0 : if (status != 0) {
652 0 : fprintf(stderr, "pthread_mutex_lock: %s, aborting...\n", strerror(status));
653 0 : abort();
654 : }
655 : #ifdef DEBUG_ETH
656 : debug_log("mutex %p locked", 0, mscb_fd[fd - 1].mutex);
657 : #endif
658 : }
659 :
660 : #endif // OS_LINUX
661 0 : return MSCB_SUCCESS;
662 : }
663 :
664 : /*------------------------------------------------------------------*/
665 :
666 0 : int mscb_release(int fd) {
667 : #ifdef _MSC_VER
668 : int status;
669 :
670 : status = ReleaseMutex(mscb_fd[fd - 1].mutex);
671 : if (status == FALSE)
672 : return 0;
673 :
674 : #elif defined(OS_LINUX)
675 :
676 0 : if (mscb_fd[fd - 1].type == MSCB_TYPE_ETH) {
677 :
678 0 : debug_log("mutex %p released", 0, mscb_fd[fd - 1].mutex);
679 :
680 : int status;
681 0 : status = pthread_mutex_unlock(mscb_fd[fd - 1].mutex);
682 0 : if (status != 0) {
683 0 : fprintf(stderr, "pthread_mutex_unlock: %s, aborting...\n", strerror(status));
684 0 : abort(); // does not return
685 : }
686 : }
687 :
688 : #endif // OS_LINUX
689 :
690 0 : return MSCB_SUCCESS;
691 : }
692 :
693 : /*---- Low level routines for UDP communication --------------------*/
694 :
695 0 : int msend_udp(int index, unsigned char *buffer, int size) {
696 : int count;
697 :
698 0 : count = sendto(mscb_fd[index - 1].fd, (const char *) buffer, size, 0,
699 0 : (struct sockaddr *) &mscb_fd[index - 1].eth_addr,
700 : sizeof(struct sockaddr));
701 :
702 0 : return count;
703 : }
704 :
705 : /*------------------------------------------------------------------*/
706 :
707 0 : int mrecv_udp(int index, unsigned char *buf, int *size, int millisec) {
708 : int n, status;
709 : unsigned char buffer[1500];
710 : fd_set readfds;
711 : struct timeval timeout;
712 : UDP_HEADER *pudp;
713 :
714 : /* receive buffer in UDP mode */
715 :
716 0 : memset(buf, 0, *size);
717 :
718 0 : FD_ZERO(&readfds);
719 0 : FD_SET(mscb_fd[index - 1].fd, &readfds);
720 0 : memset(buffer, 0, sizeof(buffer));
721 :
722 0 : timeout.tv_sec = millisec / 1000;
723 0 : timeout.tv_usec = (millisec % 1000) * 1000;
724 :
725 : do {
726 0 : status = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
727 0 : } while (status == -1); /* don't return if an alarm signal was caught */
728 :
729 0 : if (!FD_ISSET(mscb_fd[index - 1].fd, &readfds)) {
730 0 : *size = 0;
731 0 : return MSCB_TIMEOUT;
732 : }
733 :
734 0 : n = recv(mscb_fd[index - 1].fd, (char *) buffer, sizeof(buffer), 0);
735 :
736 0 : pudp = (UDP_HEADER *) buffer;
737 :
738 : /* check version */
739 0 : if (pudp->version != MSCB_PROTOCOL_VERSION) {
740 0 : *size = 0;
741 0 : return MSCB_SUBM_ERROR;
742 : }
743 :
744 : /* check size */
745 0 : if (ntohs(pudp->size) + (int) sizeof(UDP_HEADER) != n) {
746 0 : *size = 0;
747 0 : return MSCB_FORMAT_ERROR;
748 : }
749 :
750 0 : n = ntohs(pudp->size);
751 :
752 : /* check for timeout on remote RS485 bus */
753 0 : if (n == 1 && *((unsigned char *)(pudp + 1)) == 0xFF) {
754 0 : memcpy(buf, pudp + 1, n);
755 0 : *size = n;
756 : // printf("mrecv_udp: timeout on remote RS485 bus\n");
757 0 : return MSCB_TIMEOUT;
758 : }
759 :
760 : /* check sequence number */
761 0 : if (ntohs(pudp->seq_num) != mscb_fd[index - 1].seq_nr) {
762 0 : printf("mrecv_udp: received wrong sequence number %d instead %d, fd=%d\n",
763 0 : ntohs(pudp->seq_num), mscb_fd[index - 1].seq_nr, index);
764 : /* try again */
765 0 : return mrecv_udp(index, buf, size, millisec);
766 : }
767 :
768 : /* check size */
769 0 : if (n > *size) {
770 0 : *size = 0;
771 0 : return MSCB_INVAL_PARAM;
772 : }
773 :
774 0 : memcpy(buf, pudp + 1, n);
775 0 : *size = n;
776 :
777 0 : return MSCB_SUCCESS;
778 : }
779 :
780 : /*------------------------------------------------------------------*/
781 :
782 0 : int mscb_exchg(int fd, unsigned char *buffer, int *size, int len, int flags)
783 : /********************************************************************\
784 :
785 : Routine: mscb_exchg
786 :
787 : Purpose: Exchange one data backe with MSCB submaster through
788 : UDP or RPC
789 :
790 : Input:
791 : int fd file descriptor
792 : char *buffer data buffer
793 : int len number of bytes in buffer
794 : int *size total size of buffer
795 : int flags bit combination of:
796 : RS485_FLAG_BIT9 node arressing
797 : RS485_FLAG_NO_ACK no acknowledge
798 : RS485_FLAG_SHORT_TO short/
799 : RS485_FLAG_LONG_TO long timeout
800 : RS485_FLAG_CMD direct submaster command
801 :
802 : Output:
803 : int *size number of bytes in buffer returned
804 :
805 : Function value:
806 : MSCB_INVAL_PARAM Invalid parameter
807 : MSCB_SUCCESS Successful completion
808 : MSCB_TIMEOUT Timeout
809 :
810 : \********************************************************************/
811 : {
812 : int i, n, retry, timeout, status;
813 : unsigned char eth_buf[1500], ret_buf[1500];
814 : UDP_HEADER *pudp;
815 :
816 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
817 0 : return MSCB_INVAL_PARAM;
818 :
819 0 : status = mscb_lock(fd);
820 0 : if (status != MSCB_SUCCESS)
821 0 : return MSCB_MUTEX;
822 :
823 : /*---- Ethernet code ----*/
824 :
825 0 : if (mscb_fd[fd - 1].type == MSCB_TYPE_ETH) {
826 0 : if (len >= 1500 || len < 1) {
827 0 : mscb_release(fd);
828 0 : return MSCB_INVAL_PARAM;
829 : }
830 :
831 : // check for communication pause
832 : // do this inside the lock to also pause other possible threads
833 0 : if (mscb_fd[fd - 1].eth_comm_pause) {
834 0 : while (millitime() - mscb_fd[fd - 1].eth_last_comm < mscb_fd[fd - 1].eth_comm_pause)
835 0 : Sleep(10);
836 : }
837 0 : mscb_fd[fd - 1].eth_last_comm = millitime();
838 :
839 0 : status = 0;
840 :
841 : /* try several times according to eth_max_retry, in case packets got lost */
842 0 : for (retry = 0; retry < mscb_fd[fd - 1].eth_max_retry; retry++) {
843 : /* increment and write sequence number */
844 0 : mscb_fd[fd - 1].seq_nr = (mscb_fd[fd - 1].seq_nr + 1) % 0x10000;
845 :
846 : /* fill UDP header */
847 0 : pudp = (UDP_HEADER *) eth_buf;
848 0 : pudp->size = htons((short) len);
849 0 : pudp->seq_num = htons((short) mscb_fd[fd - 1].seq_nr);
850 0 : pudp->flags = flags;
851 0 : pudp->version = MSCB_PROTOCOL_VERSION;
852 :
853 0 : memcpy(pudp + 1, buffer, len);
854 :
855 : #ifdef DEBUG_ETH
856 : if (_debug_flag) {
857 : char str[10000];
858 : snprintf(str, sizeof(str), "mscb_exchg(seq=%d,size=%d) %d bytes: ", mscb_fd[fd - 1].seq_nr, len, len);
859 :
860 : for (int j = 0; j < len; j++) {
861 : if (strlen(str) > sizeof(str) - 20) {
862 : mstrlcat(str, "...", sizeof(str));
863 : break;
864 : }
865 : snprintf(str + strlen(str), sizeof(str)-strlen(str), "0x%02X ",
866 : *(((unsigned char *) buffer) + j));
867 : if (isalnum(*(((unsigned char *) buffer) + j)))
868 : snprintf(str + strlen(str), sizeof(str)-strlen(str), "('%c') ",
869 : *(((unsigned char *) buffer) + j));
870 : }
871 : debug_log(str, 0);
872 : }
873 : #endif
874 :
875 : /* send over UDP link */
876 0 : i = msend_udp(fd, eth_buf, len + sizeof(UDP_HEADER));
877 :
878 : #ifdef DEBUG_ETH
879 : debug_log("mscb_exchg sent %d bytes on socket %d", 0, i, mscb_fd[fd - 1].fd);
880 : #endif
881 :
882 0 : if (i != len + (int) sizeof(UDP_HEADER)) {
883 0 : if (size && *size)
884 0 : memset(buffer, 0, *size);
885 0 : mscb_release(fd);
886 0 : debug_log("mscb_exchg return MSCB_TIMEOUT", 0);
887 0 : return MSCB_TIMEOUT;
888 : }
889 :
890 0 : if (flags & RS485_FLAG_NO_ACK) {
891 0 : if (size && *size)
892 0 : memset(buffer, 0, *size);
893 0 : mscb_release(fd);
894 0 : debug_log("mscb_exchg return MSCB_SUCCESS (RS485_FLAG_NO_ACK)", 0);
895 0 : return MSCB_SUCCESS;
896 : }
897 :
898 0 : if (size == NULL) {
899 0 : if (size && *size)
900 0 : memset(buffer, 0, *size);
901 0 : mscb_release(fd);
902 0 : debug_log("mscb_exchg return MSCB_INVAL_PARAM", 0);
903 0 : return MSCB_INVAL_PARAM;
904 : }
905 :
906 0 : memset(ret_buf, 0, sizeof(ret_buf));
907 :
908 : /* increase timeout with each retry 0.3s, 0.6s, ... */
909 0 : timeout = 300 * (retry + 1);
910 :
911 0 : if (flags & RS485_FLAG_LONG_TO)
912 0 : timeout = TO_LONG; // increased timeout for flash programming
913 :
914 0 : if ((flags & RS485_FLAG_VERYLONG_TO) && retry > 0)
915 0 : timeout = TO_VERYLONG; // increased timeout for first UDP packet
916 :
917 : /* few retries are common, so only print warning starting from 5th retry */
918 0 : if ((retry > 1 || ((flags & RS485_FLAG_VERYLONG_TO) && retry > 1)) && status == MSCB_TIMEOUT)
919 0 : printf("mscb_exchg: retry %d out of %d with %d ms timeout, fd = %d\n",
920 0 : retry, mscb_fd[fd - 1].eth_max_retry, timeout, fd);
921 :
922 : /* receive result on IN pipe */
923 0 : n = sizeof(ret_buf);
924 0 : status = mrecv_udp(fd, ret_buf, &n, timeout);
925 :
926 : #ifdef DEBUG_ETH
927 : debug_log("mscb_exchg received %d bytes on socket %d", n, mscb_fd[fd - 1].fd);
928 : #endif
929 :
930 : /* return if invalid version */
931 0 : if (status == MSCB_SUBM_ERROR) {
932 0 : if (size && *size)
933 0 : memset(buffer, 0, *size);
934 0 : mscb_release(fd);
935 0 : *size = 0;
936 0 : debug_log("mscb_exchg return EMSCB_PROTOCOL_VERSION", 0);
937 0 : return EMSCB_PROTOCOL_VERSION;
938 : }
939 :
940 0 : if (n > 0) {
941 : /* check if return data fits into buffer */
942 0 : if (n > *size) {
943 0 : memcpy(buffer, ret_buf, *size);
944 : } else {
945 0 : memset(buffer, 0, *size);
946 0 : memcpy(buffer, ret_buf, n);
947 0 : *size = n;
948 : }
949 :
950 0 : mscb_release(fd);
951 0 : debug_log("mscb_exchg return MSCB_SUCCESS %d bytes", 0, *size);
952 0 : return MSCB_SUCCESS;
953 : }
954 :
955 :
956 0 : if (flags & RS485_FLAG_NO_RETRY) {
957 0 : *size = 0;
958 0 : break;
959 : }
960 :
961 0 : if (flags & RS485_FLAG_VERYLONG_TO && retry > 1)
962 0 : break;
963 :
964 0 : debug_log("mscb_exchg RETRY %d: dev=%s, status=%d, n=%d", 0, retry, mscb_fd[fd - 1].device, status, n);
965 : }
966 :
967 : /* no reply after all the retries, so return error */
968 0 : if (size && *size)
969 0 : memset(buffer, 0, *size);
970 0 : if (size)
971 0 : *size = 0;
972 0 : mscb_release(fd);
973 0 : debug_log("mscb_exchg return MSCB_TIMEOUT", 0);
974 0 : return MSCB_TIMEOUT;
975 : }
976 :
977 0 : mscb_release(fd);
978 :
979 : #ifdef DEBUG_ETH
980 : debug_log("mscb_exchg return MSCB_SUCCESS %d bytes", 0, *size);
981 : #endif
982 :
983 0 : return MSCB_SUCCESS;
984 : }
985 :
986 : /*------------------------------------------------------------------*/
987 :
988 0 : void mscb_get_version(char *lib_version, char *prot_version) {
989 0 : strcpy(lib_version, MSCB_LIBRARY_VERSION);
990 0 : snprintf(prot_version, 16, "%d", MSCB_PROTOCOL_VERSION);
991 0 : }
992 :
993 : /*------------------------------------------------------------------*/
994 :
995 0 : int mrpc_connected(int fd) {
996 0 : return mscb_fd[fd - 1].type == MSCB_TYPE_RPC;
997 : }
998 :
999 : /*------------------------------------------------------------------*/
1000 :
1001 0 : int mscb_init(char *device, int bufsize, const char *password, int debug)
1002 : /********************************************************************\
1003 :
1004 : Routine: mscb_init
1005 :
1006 : Purpose: Initialize and open MSCB
1007 :
1008 : Input:
1009 : char *device "<host>:device" for RPC connection
1010 : mscbxxx for Ethernet connection
1011 :
1012 : int bufsize Size of "device" string, in case no device
1013 : is specified from the caller and this function
1014 : returns the chosen device
1015 : int password Optional password, used for ethernet submasters
1016 : int debug Debug flag:
1017 : 1: all writes are logged to mscb_write.log
1018 : 2: all writes and read are logged to mscb_debug.log
1019 : 3: debug output is written to screen
1020 :
1021 : Function value:
1022 : int fd device descriptor for connection, negative
1023 : number in case of error:
1024 :
1025 : EMSCB_NO_MEM Out of memory for file descriptors
1026 : EMSCB_RPC_ERROR Cannot talk to RPC server
1027 : EMSCB_COMM_ERROR Submaster does not reply on echo
1028 : EMSCB_LOCKED MSCB system locked by other user
1029 : EMSCB_NO_ACCESS No access to submaster
1030 : EMSCB_INVAL_PARAM Invalid parameter
1031 : EMSCB_NOT_FOUND Submaster not found
1032 : EMSCB_NO_WRITE_ACCESS No write access under linux
1033 : EMSCB_WRONG_PASSWORD Wrong password
1034 : EMSCB_SUMB_VERSION Submaster has wrong protocol version
1035 :
1036 : \********************************************************************/
1037 : {
1038 : int index, i, n;
1039 : int status;
1040 : char dev3[256];
1041 : unsigned char buf[64];
1042 : struct hostent *phe;
1043 : struct sockaddr_in *psa_in;
1044 :
1045 0 : status = 0;
1046 :
1047 : /* search for open file descriptor for same device, used by LabView */
1048 0 : for (index = 0; index < MSCB_MAX_FD; index++)
1049 0 : if (mscb_fd[index].fd != 0 && strcmp(mscb_fd[index].device, device) == 0)
1050 0 : return index + 1;
1051 :
1052 : /* search for new file descriptor */
1053 0 : for (index = 0; index < MSCB_MAX_FD; index++)
1054 0 : if (mscb_fd[index].fd == 0)
1055 0 : break;
1056 :
1057 0 : if (index == MSCB_MAX_FD) {
1058 0 : printf("mscb_init: limit of open devices exceeded, aborting.\n");
1059 0 : abort();
1060 : return EMSCB_NO_MEM;
1061 : }
1062 :
1063 : /* set global debug flag */
1064 0 : if (_debug_flag == -1)
1065 0 : _debug_flag = debug;
1066 :
1067 0 : debug_log("mscb_init(device=\"%s\",bufsize=%d,password=\"%s\",debug=%d)", 1, device, bufsize, password, debug);
1068 :
1069 : /* clear caches */
1070 0 : for (i = 0; i < n_cache; i++)
1071 0 : free(cache[i].data);
1072 0 : free(cache);
1073 0 : n_cache = 0;
1074 :
1075 0 : free(cache_info_var);
1076 0 : cache_info_var = NULL;
1077 0 : n_cache_info_var = 0;
1078 :
1079 : /* check for RPC connection */
1080 : #ifdef HAVE_MRPC
1081 : if (strchr(device, ':')) {
1082 : char remote_device[256], host[256];
1083 :
1084 : mstrlcpy(mscb_fd[index].device, device, sizeof(mscb_fd[index].device));
1085 : mscb_fd[index].type = MSCB_TYPE_RPC;
1086 :
1087 : strcpy(remote_device, strchr(device, ':') + 1);
1088 : strcpy(host, device);
1089 : *strchr(host, ':') = 0;
1090 :
1091 : mscb_fd[index].fd = mrpc_connect(host, MSCB_RPC_PORT);
1092 :
1093 : if (mscb_fd[index].fd < 0) {
1094 : mscb_fd[index].fd = 0;
1095 : return EMSCB_RPC_ERROR;
1096 : }
1097 :
1098 : mscb_fd[index].remote_fd = mrpc_call(mscb_fd[index].fd, RPC_MSCB_INIT, remote_device, bufsize, password, debug);
1099 : if (mscb_fd[index].remote_fd < 0) {
1100 : mrpc_disconnect(mscb_fd[index].fd);
1101 : mscb_fd[index].fd = 0;
1102 : return EMSCB_RPC_ERROR;
1103 : }
1104 :
1105 : snprintf(device, sizeof(device), "%s:%s", host, remote_device);
1106 :
1107 : debug_log("mscb_init return %d", 1, index + 1);
1108 : return index + 1;
1109 : }
1110 : #endif
1111 :
1112 : /* check which device type */
1113 0 : strcpy(dev3, device);
1114 0 : dev3[3] = 0;
1115 0 : strcpy(mscb_fd[index].device, device);
1116 0 : mscb_fd[index].type = MSCB_TYPE_ETH; // default is ethernet
1117 :
1118 : /* MSCBxxx */
1119 0 : if (strieq(dev3, "msc") || (atoi(device) > 0 && strchr(device, '.')))
1120 0 : mscb_fd[index].type = MSCB_TYPE_ETH;
1121 :
1122 0 : dev3[2] = 0;
1123 : /* WDxxx*/
1124 0 : if (strieq(dev3, "wd") || (atoi(device) > 0 && strchr(device, '.')))
1125 0 : mscb_fd[index].type = MSCB_TYPE_ETH;
1126 :
1127 0 : if (mscb_fd[index].type == 0)
1128 0 : return EMSCB_INVAL_PARAM;
1129 :
1130 : /*---- initialize submaster ----*/
1131 :
1132 0 : if (mscb_fd[index].mutex == 0)
1133 0 : mscb_fd[index].mutex = mscb_mutex_create(device);
1134 :
1135 0 : if (mscb_fd[index].type == MSCB_TYPE_ETH) {
1136 :
1137 : #ifdef _MSC_VER
1138 : {
1139 : WSADATA WSAData;
1140 :
1141 : /* Start windows sockets */
1142 : if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
1143 : return -1;
1144 : }
1145 : #endif
1146 :
1147 : /* retrieve destination address */
1148 0 : short port = (short) MSCB_NET_PORT;
1149 : char host[256];
1150 0 : if (strchr(mscb_fd[index].device, ':')) {
1151 0 : mstrlcpy(host, mscb_fd[index].device, sizeof(host));
1152 0 : *strchr(host, ':') = 0;
1153 0 : port = atoi(strchr(mscb_fd[index].device, ':') + 1);
1154 : } else
1155 0 : mstrlcpy(host, mscb_fd[index].device, sizeof(host));
1156 :
1157 0 : phe = gethostbyname(host);
1158 0 : if (phe == NULL) {
1159 0 : debug_log("mscb_init return EMSCB_RPC_ERROR", 1);
1160 0 : return EMSCB_RPC_ERROR;
1161 : }
1162 0 : memset(&mscb_fd[index].eth_addr, 0, sizeof(mscb_fd[index].eth_addr));
1163 0 : psa_in = (struct sockaddr_in *) mscb_fd[index].eth_addr;
1164 0 : memcpy((char *) &(psa_in->sin_addr), phe->h_addr, phe->h_length);
1165 0 : psa_in->sin_port = htons(port);
1166 0 : psa_in->sin_family = AF_INET;
1167 :
1168 0 : mscb_fd[index].fd = socket(AF_INET, SOCK_DGRAM, 0);
1169 0 : if (mscb_fd[index].fd == -1) {
1170 0 : debug_log("mscb_init return EMSCB_RPC_ERROR", 1);
1171 0 : return EMSCB_RPC_ERROR;
1172 : }
1173 :
1174 0 : if (!mscb_lock(index + 1)) {
1175 0 : memset(&mscb_fd[index], 0, sizeof(MSCB_FD));
1176 0 : debug_log("mscb_init return EMSCB_LOCKED", 1);
1177 0 : return EMSCB_LOCKED;
1178 : }
1179 0 : mscb_release(index + 1);
1180 :
1181 : /* set default number of retries */
1182 0 : mscb_fd[index].eth_max_retry = 10;
1183 :
1184 : /* check if submaster alive, use long timeout for ARP */
1185 0 : buf[0] = MCMD_ECHO;
1186 0 : n = sizeof(buf);
1187 0 : status = mscb_exchg(index + 1, buf, &n, 1,
1188 : RS485_FLAG_CMD | RS485_FLAG_VERYLONG_TO);
1189 :
1190 0 : if (status == EMSCB_PROTOCOL_VERSION) {
1191 0 : mscb_exit(index + 1);
1192 0 : debug_log("mscb_init return EMSCB_PROTOCOL_VERSION", 1);
1193 0 : return EMSCB_PROTOCOL_VERSION;
1194 : }
1195 :
1196 0 : if (status == MSCB_TIMEOUT || n < 2) {
1197 0 : mscb_exit(index + 1);
1198 0 : debug_log("mscb_init return EMSCB_RPC_ERROR", 1);
1199 0 : return EMSCB_RPC_ERROR;
1200 : }
1201 :
1202 0 : if (n < 4 || buf[1] != MSCB_PROTOCOL_VERSION) {
1203 : /* invalid version */
1204 0 : debug_log("mscb_init return EMSCB_PROTOCOL_VERSION", 1);
1205 0 : memset(&mscb_fd[index], 0, sizeof(MSCB_FD));
1206 0 : return EMSCB_PROTOCOL_VERSION;
1207 : }
1208 :
1209 : /* authenticate */
1210 0 : memset(buf, 0, sizeof(buf));
1211 0 : buf[0] = MCMD_TOKEN;
1212 0 : if (password)
1213 0 : strcpy((char *) (buf + 1), password);
1214 : else
1215 0 : buf[1] = 0;
1216 :
1217 0 : n = sizeof(buf);
1218 0 : mscb_exchg(index + 1, buf, &n, 21, RS485_FLAG_CMD);
1219 :
1220 0 : if (n != 1 || (buf[0] != MCMD_ACK && buf[0] != 0xFF)) {
1221 0 : mscb_exit(index + 1);
1222 0 : memset(&mscb_fd[index], 0, sizeof(MSCB_FD));
1223 0 : debug_log("mscb_init return EMSCB_COMM_ERROR", 1);
1224 0 : return EMSCB_COMM_ERROR;
1225 : }
1226 :
1227 0 : if (buf[0] == 0xFF) {
1228 0 : mscb_exit(index + 1);
1229 0 : memset(&mscb_fd[index], 0, sizeof(MSCB_FD));
1230 0 : debug_log("mscb_init return EMSCB_WRONG_PASSWORD", 1);
1231 0 : return EMSCB_WRONG_PASSWORD;
1232 : }
1233 :
1234 0 : debug_log("mscb_init return %d", 1, index + 1);
1235 0 : return index + 1;
1236 : }
1237 :
1238 0 : debug_log("mscb_init return %d\n", 1, index + 1);
1239 0 : return index + 1;
1240 : }
1241 :
1242 : /*------------------------------------------------------------------*/
1243 :
1244 0 : int mscb_exit(int fd)
1245 : /********************************************************************\
1246 :
1247 : Routine: mscb_exit
1248 :
1249 : Purpose: Close a MSCB interface
1250 :
1251 : Input:
1252 : int fd file descriptor for connection
1253 :
1254 : Function value:
1255 : MSCB_SUCCESS Successful completion
1256 :
1257 : \********************************************************************/
1258 : {
1259 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
1260 0 : return MSCB_INVAL_PARAM;
1261 :
1262 : #ifdef HAVE_MRPC
1263 : if (mrpc_connected(fd)) {
1264 : mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_EXIT, mscb_fd[fd - 1].remote_fd);
1265 : mrpc_disconnect(mscb_fd[fd - 1].fd);
1266 : }
1267 : #endif
1268 :
1269 : #ifdef HAVE_MRPC
1270 : if (mscb_fd[fd - 1].type == MSCB_TYPE_ETH)
1271 : mrpc_disconnect(mscb_fd[fd - 1].fd);
1272 : #endif
1273 :
1274 0 : memset(&mscb_fd[fd - 1], 0, sizeof(MSCB_FD));
1275 :
1276 0 : return MSCB_SUCCESS;
1277 : }
1278 :
1279 :
1280 : /*------------------------------------------------------------------*/
1281 :
1282 0 : int mscb_debug(int flag)
1283 : /* set global debug flag */
1284 : {
1285 0 : _debug_flag = flag;
1286 :
1287 0 : return MSCB_SUCCESS;
1288 : }
1289 :
1290 : /*------------------------------------------------------------------*/
1291 :
1292 0 : void mscb_cleanup(int sock)
1293 : /* Called by mrpc_server_loop to remove stale fd's on broken connection */
1294 : {
1295 : int i;
1296 :
1297 0 : for (i = 0; i < MSCB_MAX_FD; i++)
1298 0 : if (mscb_fd[i].fd && mscb_fd[i].remote_fd == sock)
1299 0 : memset(&mscb_fd[i], 0, sizeof(MSCB_FD));
1300 0 : }
1301 :
1302 : /*------------------------------------------------------------------*/
1303 :
1304 0 : void mscb_get_device(int fd, char *device, int bufsize)
1305 : /********************************************************************\
1306 :
1307 : Routine: mscb_get_device
1308 :
1309 : Purpose: Return device name for fd
1310 :
1311 : Input:
1312 : int fd File descriptor obtained via mscb_init()
1313 : int bufsize Size of device string
1314 : char *device device name, "" if invalid fd
1315 :
1316 : \********************************************************************/
1317 : {
1318 0 : if (!device)
1319 0 : return;
1320 :
1321 0 : *device = 0;
1322 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
1323 0 : return;
1324 :
1325 : #ifdef HAVE_MRPC
1326 : if (mrpc_connected(fd)) {
1327 : mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_GET_DEVICE,
1328 : mscb_fd[fd - 1].remote_fd, device, bufsize);
1329 : }
1330 : #endif
1331 :
1332 0 : mstrlcpy(device, mscb_fd[fd - 1].device, bufsize);
1333 : }
1334 :
1335 : /*------------------------------------------------------------------*/
1336 :
1337 0 : int mscb_addr(int fd, int cmd, unsigned short adr, int quick, int retry)
1338 : /********************************************************************\
1339 :
1340 : Routine: mscb_addr
1341 :
1342 : Purpose: Address node or nodes, only used internall from read and
1343 : write routines. A MSCB lock has to be obtained outside
1344 : of this routine!
1345 :
1346 : Input:
1347 : int fd File descriptor for connection
1348 : int cmd Addressing mode, one of
1349 : MCMD_ADDR_BC
1350 : MCMD_ADDR_NODE8
1351 : MCMD_ADDR_GRP8
1352 : MCMD_PING8
1353 : MCMD_ADDR_NODE16
1354 : MCMD_ADDR_GRP16
1355 : MCMD_PING16
1356 :
1357 : unsigned short adr Node or group address
1358 : int quick Quick ping (short timeout)
1359 : int retry Number of retries
1360 :
1361 : Function value:
1362 : MSCB_SUCCESS Successful completion
1363 : MSCB_TIMEOUT Timeout receiving ping acknowledge
1364 : MSCB_MUTEX Cannot obtain mutex for mscb
1365 :
1366 : \********************************************************************/
1367 : {
1368 : unsigned char buf[64];
1369 : int n, size, status;
1370 :
1371 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
1372 0 : return MSCB_INVAL_PARAM;
1373 :
1374 : #ifdef HAVE_MRPC
1375 : if (mrpc_connected(fd))
1376 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_ADDR, mscb_fd[fd - 1].remote_fd, cmd, adr, retry);
1377 : #endif
1378 :
1379 0 : for (n = 0; n < retry; n++) {
1380 0 : buf[0] = (unsigned char) cmd;
1381 0 : size = sizeof(buf);
1382 0 : if (cmd == MCMD_ADDR_NODE8 || cmd == MCMD_ADDR_GRP8) {
1383 0 : buf[1] = (unsigned char) adr;
1384 0 : buf[2] = crc8(buf, 2);
1385 0 : status = mscb_exchg(fd, buf, &size, 3, RS485_FLAG_BIT9 | RS485_FLAG_SHORT_TO | RS485_FLAG_NO_ACK);
1386 0 : } else if (cmd == MCMD_PING8) {
1387 0 : buf[1] = (unsigned char) adr;
1388 0 : buf[2] = crc8(buf, 2);
1389 0 : status = mscb_exchg(fd, buf, &size, 3, RS485_FLAG_BIT9 | RS485_FLAG_SHORT_TO);
1390 0 : } else if (cmd == MCMD_ADDR_NODE16 || cmd == MCMD_ADDR_GRP16) {
1391 0 : buf[1] = (unsigned char) (adr >> 8);
1392 0 : buf[2] = (unsigned char) (adr & 0xFF);
1393 0 : buf[3] = crc8(buf, 3);
1394 0 : status = mscb_exchg(fd, buf, &size, 4, RS485_FLAG_BIT9 | RS485_FLAG_SHORT_TO | RS485_FLAG_NO_ACK);
1395 0 : } else if (cmd == MCMD_PING16) {
1396 0 : buf[1] = (unsigned char) (adr >> 8);
1397 0 : buf[2] = (unsigned char) (adr & 0xFF);
1398 0 : buf[3] = crc8(buf, 3);
1399 0 : if (quick)
1400 0 : status = mscb_exchg(fd, buf, &size, 4, RS485_FLAG_BIT9 | RS485_FLAG_SHORT_TO);
1401 : else
1402 0 : status = mscb_exchg(fd, buf, &size, 4, RS485_FLAG_BIT9);
1403 : } else {
1404 0 : buf[1] = crc8(buf, 1);
1405 0 : status = mscb_exchg(fd, buf, &size, 2, RS485_FLAG_BIT9 | RS485_FLAG_SHORT_TO | RS485_FLAG_NO_ACK);
1406 : }
1407 :
1408 0 : if (status != MSCB_SUCCESS)
1409 0 : return MSCB_SUBM_ERROR;
1410 :
1411 0 : if (cmd == MCMD_PING8 || cmd == MCMD_PING16) {
1412 0 : if (buf[0] == MCMD_ACK)
1413 0 : return MSCB_SUCCESS;
1414 :
1415 0 : if (retry > 1) {
1416 : /* send 0's to overflow partially filled node receive buffer */
1417 0 : memset(buf, 0, sizeof(buf));
1418 0 : mscb_exchg(fd, buf, NULL, 10, RS485_FLAG_BIT9 | RS485_FLAG_NO_ACK);
1419 :
1420 : /* wait some time */
1421 0 : Sleep(10);
1422 : }
1423 :
1424 : /* try again.... */
1425 : } else
1426 0 : return MSCB_SUCCESS;
1427 : }
1428 :
1429 0 : return MSCB_TIMEOUT;
1430 : }
1431 :
1432 : /*------------------------------------------------------------------*/
1433 :
1434 0 : int mscb_reboot(int fd, int addr, int gaddr, int broadcast)
1435 : /********************************************************************\
1436 :
1437 : Routine: mscb_reboot
1438 :
1439 : Purpose: Reboot node by sending MCMD_INIT
1440 :
1441 : Input:
1442 : int fd File descriptor for connection
1443 : int addr Node address
1444 : int gaddr Group address
1445 : int broadcast Broadcast flag
1446 :
1447 : Function value:
1448 : MSCB_SUCCESS Successful completion
1449 : MSCB_MUTEX Cannot obtain mutex for mscb
1450 : MSCB_TIMEOUT Timeout receiving ping acknowledge
1451 :
1452 : \********************************************************************/
1453 : {
1454 : int size;
1455 : unsigned char buf[64];
1456 :
1457 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
1458 0 : return MSCB_INVAL_PARAM;
1459 :
1460 : #ifdef HAVE_MRPC
1461 : if (mrpc_connected(fd))
1462 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_REBOOT, mscb_fd[fd - 1].remote_fd, addr, gaddr, broadcast);
1463 : #endif
1464 :
1465 0 : size = sizeof(buf);
1466 0 : if (addr >= 0) {
1467 0 : buf[0] = MCMD_ADDR_NODE16;
1468 0 : buf[1] = (unsigned char) (addr >> 8);
1469 0 : buf[2] = (unsigned char) (addr & 0xFF);
1470 0 : buf[3] = crc8(buf, 3);
1471 :
1472 0 : buf[4] = MCMD_INIT;
1473 0 : buf[5] = crc8(buf + 4, 1);
1474 0 : mscb_exchg(fd, buf, &size, 6, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
1475 0 : } else if (gaddr >= 0) {
1476 0 : buf[0] = MCMD_ADDR_GRP16;
1477 0 : buf[1] = (unsigned char) (gaddr >> 8);
1478 0 : buf[2] = (unsigned char) (gaddr & 0xFF);
1479 0 : buf[3] = crc8(buf, 3);
1480 :
1481 0 : buf[4] = MCMD_INIT;
1482 0 : buf[5] = crc8(buf + 4, 1);
1483 0 : mscb_exchg(fd, buf, &size, 6, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
1484 0 : } else if (broadcast) {
1485 0 : buf[0] = MCMD_ADDR_BC;
1486 0 : buf[1] = crc8(buf, 1);
1487 :
1488 0 : buf[2] = MCMD_INIT;
1489 0 : buf[3] = crc8(buf + 2, 1);
1490 0 : mscb_exchg(fd, buf, &size, 4, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
1491 : }
1492 :
1493 0 : mscb_clear_info_cache();
1494 :
1495 0 : return MSCB_SUCCESS;
1496 : }
1497 :
1498 : /*------------------------------------------------------------------*/
1499 :
1500 0 : int mscb_subm_reset(int fd)
1501 : /********************************************************************\
1502 :
1503 : Routine: mscb_subm_reset
1504 :
1505 : Purpose: Reset submaster via hardware reset
1506 :
1507 : Input:
1508 : int fd File descriptor for connection
1509 :
1510 : Function value:
1511 : MSCB_SUCCESS Successful completion
1512 : MSCB_SEMPHORE Cannot obtain semaphore for mscb
1513 :
1514 : \********************************************************************/
1515 : {
1516 : unsigned char buf[10];
1517 : int size;
1518 :
1519 0 : debug_log("mscb_subm_reset(fd=%d)", 1, fd);
1520 :
1521 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type) {
1522 0 : debug_log("mscb_subm_reset return MSCB_INVAL_PARAM", 1);
1523 0 : return MSCB_INVAL_PARAM;
1524 : }
1525 :
1526 : #ifdef HAVE_MRPC
1527 : if (mrpc_connected(fd))
1528 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_SUBM_RESET, mscb_fd[fd - 1].remote_fd);
1529 : #endif
1530 :
1531 0 : if (mscb_fd[fd - 1].type == MSCB_TYPE_ETH) {
1532 :
1533 0 : buf[0] = MCMD_INIT;
1534 0 : mscb_exchg(fd, buf, NULL, 1, RS485_FLAG_CMD | RS485_FLAG_NO_ACK);
1535 :
1536 0 : Sleep(5000); // let submaster obtain IP address
1537 :
1538 : /* check if submaster alive */
1539 0 : size = sizeof(buf);
1540 0 : buf[0] = MCMD_ECHO;
1541 0 : mscb_exchg(fd, buf, &size, 1, RS485_FLAG_CMD);
1542 0 : if (size < 2) {
1543 0 : debug_log("mscb_subm_reset return MSCB_SUBM_ERROR (mrpc_connect)", 1);
1544 0 : return MSCB_SUBM_ERROR;
1545 : }
1546 :
1547 : }
1548 :
1549 : /* send 0's to overflow partially filled node receive buffer */
1550 0 : memset(buf, 0, sizeof(buf));
1551 0 : mscb_exchg(fd, buf, NULL, 10, RS485_FLAG_BIT9 | RS485_FLAG_NO_ACK);
1552 0 : Sleep(10);
1553 :
1554 0 : debug_log("mscb_subm_reset return MSCB_SUCCESS", 1);
1555 0 : return MSCB_SUCCESS;
1556 : }
1557 :
1558 : /*------------------------------------------------------------------*/
1559 :
1560 0 : int mscb_ping(int fd, unsigned short adr, int quick, int retry)
1561 : /********************************************************************\
1562 :
1563 : Routine: mscb_ping
1564 :
1565 : Purpose: Ping node to see if it's alive
1566 :
1567 : Input:
1568 : int fd File descriptor for connection
1569 : unsigned short adr Node address
1570 : int quick If 1, do a quick ping (short timeout)
1571 : int retry If 1, retry if no response (slow)
1572 :
1573 : Output:
1574 : none
1575 :
1576 : Function value:
1577 : MSCB_SUCCESS Successful completion
1578 : MSCB_TIMEOUT Timeout receiving data
1579 : MSCB_MUTEX Cannot obtain mutex for mscb
1580 :
1581 : \********************************************************************/
1582 : {
1583 : int status;
1584 :
1585 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
1586 0 : return MSCB_INVAL_PARAM;
1587 :
1588 : #ifdef HAVE_MRPC
1589 : if (mrpc_connected(fd))
1590 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_PING, mscb_fd[fd - 1].remote_fd, adr);
1591 : #endif
1592 :
1593 : /* call mscb_addr with/without retries */
1594 0 : status = mscb_addr(fd, MCMD_PING16, adr, quick, retry ? mscb_fd[fd - 1].eth_max_retry : 1);
1595 :
1596 0 : return status;
1597 : }
1598 :
1599 : /*------------------------------------------------------------------*/
1600 :
1601 0 : void mscb_clear_info_cache()
1602 : /* called internally when a node gets upgraded or address changed */
1603 : {
1604 0 : free(cache_info_var);
1605 0 : cache_info_var = NULL;
1606 0 : n_cache_info_var = 0;
1607 0 : }
1608 :
1609 : /*------------------------------------------------------------------*/
1610 :
1611 0 : int mscb_info(int fd, unsigned short adr, MSCB_INFO *info)
1612 : /********************************************************************\
1613 :
1614 : Routine: mscb_info
1615 :
1616 : Purpose: Retrieve info on addressd node
1617 :
1618 : Input:
1619 : int fd File descriptor for connection
1620 : unsigned short adr Node address
1621 :
1622 : Output:
1623 : MSCB_INFO *info Info structure defined in mscb.h
1624 :
1625 : Function value:
1626 : MSCB_SUCCESS Successful completion
1627 : MSCB_TIMEOUT Timeout receiving data
1628 : MSCB_CRC_ERROR CRC error
1629 : MSCB_MUTEX Cannot obtain mutex for mscb
1630 :
1631 : \********************************************************************/
1632 : {
1633 0 : int size = 0, retry;
1634 : unsigned char buf[256];
1635 :
1636 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
1637 0 : return MSCB_INVAL_PARAM;
1638 :
1639 0 : debug_log("mscb_info(fd=%d,adr=%d)", 0, fd, adr);
1640 :
1641 : #ifdef HAVE_MRPC
1642 : if (mrpc_connected(fd))
1643 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_INFO, mscb_fd[fd - 1].remote_fd, adr, info);
1644 : #endif
1645 :
1646 0 : memset(info, 0, sizeof(MSCB_INFO));
1647 0 : for (retry = 0; retry < mscb_max_retry; retry++) {
1648 0 : buf[0] = MCMD_ADDR_NODE16;
1649 0 : buf[1] = (unsigned char) (adr >> 8);
1650 0 : buf[2] = (unsigned char) (adr & 0xFF);
1651 0 : buf[3] = crc8(buf, 3);
1652 :
1653 0 : buf[4] = MCMD_GET_INFO;
1654 0 : buf[5] = crc8(buf + 4, 1);
1655 :
1656 0 : size = sizeof(buf);
1657 0 : mscb_exchg(fd, buf, &size, 6, RS485_FLAG_ADR_CYCLE);
1658 :
1659 0 : if (size == (int) sizeof(MSCB_INFO) + 3)
1660 0 : break;
1661 :
1662 0 : if (size == (int) sizeof(MSCB_INFO) + 3 - 52) // "old" format with buffer size
1663 0 : break;
1664 :
1665 0 : if (size == (int) sizeof(MSCB_INFO) + 3 - 2 - 52) // old format without buffer size
1666 0 : break;
1667 :
1668 0 : if (size == (int) sizeof(MSCB_INFO) + 3 - 2 - 6 - 52) // old format without RTC
1669 0 : break;
1670 :
1671 0 : debug_log("mscb_info retry %d", 0, retry + 1);
1672 : }
1673 :
1674 0 : if (size < (int) sizeof(MSCB_INFO) + 3 - 2 - 6 - 52)
1675 0 : return MSCB_TIMEOUT;
1676 :
1677 0 : memcpy(info, buf + 2, size - 3);
1678 :
1679 : /* do CRC check */
1680 0 : if (crc8(buf, size - 1) != buf[size - 1]) {
1681 0 : debug_log("mscb_info return MSCB_CRC_ERROR", 0);
1682 0 : return MSCB_CRC_ERROR;
1683 : }
1684 :
1685 0 : WORD_SWAP(&info->node_address);
1686 0 : WORD_SWAP(&info->group_address);
1687 0 : WORD_SWAP(&info->revision);
1688 0 : WORD_SWAP(&info->buf_size);
1689 :
1690 0 : WORD_SWAP(&info->pinExt_resets);
1691 0 : WORD_SWAP(&info->SW_resets);
1692 0 : WORD_SWAP(&info->int_WD_resets);
1693 0 : DWORD_SWAP(&info->systemLoad);
1694 0 : DWORD_SWAP(&info->peakSystemLoad);
1695 0 : DWORD_SWAP(&info->pcbTemp);
1696 0 : DWORD_SWAP(&info->Supply1V8);
1697 0 : DWORD_SWAP(&info->Supply3V3);
1698 0 : DWORD_SWAP(&info->Supply5V0);
1699 0 : DWORD_SWAP(&info->Supply24V0);
1700 0 : DWORD_SWAP(&info->Supply5V0Ext);
1701 0 : DWORD_SWAP(&info->Supply24V0Ext);
1702 0 : DWORD_SWAP(&info->Supply24V0Current);
1703 0 : DWORD_SWAP(&info->Vbat);
1704 :
1705 0 : debug_log("mscb_info return MSCB_SUCCESS", 0);
1706 :
1707 0 : return MSCB_SUCCESS;
1708 : }
1709 :
1710 : /*------------------------------------------------------------------*/
1711 :
1712 0 : int mscb_uptime(int fd, unsigned short adr, unsigned int *uptime)
1713 : /********************************************************************\
1714 :
1715 : Routine: mscb_uptime
1716 :
1717 : Purpose: Retrieve uptime of node in seconds
1718 :
1719 : Input:
1720 : int fd File descriptor for connection
1721 : unsigned short adr Node address
1722 :
1723 : Output:
1724 : unsigned long *uptime Uptime in seconds
1725 :
1726 : Function value:
1727 : MSCB_SUCCESS Successful completion
1728 : MSCB_TIMEOUT Timeout receiving data
1729 : MSCB_CRC_ERROR CRC error
1730 : MSCB_MUTEX Cannot obtain mutex for mscb
1731 :
1732 : \********************************************************************/
1733 : {
1734 : int size;
1735 : unsigned char buf[256];
1736 : unsigned long u;
1737 :
1738 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
1739 0 : return MSCB_INVAL_PARAM;
1740 :
1741 : #ifdef HAVE_MRPC
1742 : if (mrpc_connected(fd))
1743 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_UPTIME, mscb_fd[fd - 1].remote_fd, adr, uptime);
1744 : #endif
1745 :
1746 0 : buf[0] = MCMD_ADDR_NODE16;
1747 0 : buf[1] = (unsigned char) (adr >> 8);
1748 0 : buf[2] = (unsigned char) (adr & 0xFF);
1749 0 : buf[3] = crc8(buf, 3);
1750 :
1751 0 : buf[4] = MCMD_GET_UPTIME;
1752 0 : buf[5] = crc8(buf + 4, 1);
1753 0 : size = sizeof(buf);
1754 0 : mscb_exchg(fd, buf, &size, 6, RS485_FLAG_ADR_CYCLE);
1755 :
1756 0 : if (size < 6)
1757 0 : return MSCB_TIMEOUT;
1758 :
1759 : /* do CRC check */
1760 0 : if (crc8(buf, size - 1) != buf[size - 1])
1761 0 : return MSCB_CRC_ERROR;
1762 :
1763 0 : u = (buf[4] << 0) + (buf[3] << 8) + (buf[2] << 16) + (buf[1] << 24);
1764 :
1765 0 : *uptime = u;
1766 :
1767 0 : return MSCB_SUCCESS;
1768 : }
1769 :
1770 : /*------------------------------------------------------------------*/
1771 :
1772 0 : int mscb_info_variable(int fd, unsigned short adr, unsigned char index, MSCB_INFO_VAR *info)
1773 : /********************************************************************\
1774 :
1775 : Routine: mscb_info_variable
1776 :
1777 : Purpose: Retrieve info on a specific node variable
1778 :
1779 : Input:
1780 : int fd File descriptor for connection
1781 : unsigned short adr Node address
1782 : int index Variable index 0..255
1783 :
1784 : Output:
1785 : MSCB_INFO_VAR *info Info structure defined in mscb.h
1786 :
1787 : Function value:
1788 : MSCB_SUCCESS Successful completion
1789 : MSCB_TIMEOUT Timeout receiving data
1790 : MSCB_CRC_ERROR CRC error
1791 : MSCB_MUTEX Cannot obtain mutex for mscb
1792 :
1793 : \********************************************************************/
1794 : {
1795 0 : int i, size = 0, retry;
1796 : unsigned char buf[80];
1797 :
1798 0 : debug_log("mscb_info_variable(fd=%d,adr=%d,index=%d)", 0, fd, adr, index);
1799 :
1800 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type) {
1801 0 : debug_log("mscb_info_variable return MSCB_INVAL_PARAM", 1);
1802 0 : return MSCB_INVAL_PARAM;
1803 : }
1804 :
1805 : /* check if info in cache */
1806 0 : for (i = 0; i < n_cache_info_var; i++)
1807 0 : if (cache_info_var[i].fd == fd && cache_info_var[i].adr == adr &&
1808 0 : cache_info_var[i].index == index)
1809 0 : break;
1810 :
1811 0 : if (i < n_cache_info_var) {
1812 : /* copy from cache */
1813 0 : if (cache_info_var[i].info.name[0] == 0)
1814 0 : return MSCB_NO_VAR;
1815 :
1816 0 : memcpy(info, &cache_info_var[i].info, sizeof(MSCB_INFO_VAR));
1817 :
1818 0 : debug_log("mscb_info_variable return info from cache", 0);
1819 : } else {
1820 : /* add new entry in cache */
1821 0 : if (n_cache_info_var == 0) {
1822 0 : cache_info_var = (CACHE_INFO_VAR *) malloc(sizeof(CACHE_INFO_VAR));
1823 0 : memset(cache_info_var, 0, sizeof(CACHE_INFO_VAR));
1824 : } else {
1825 0 : cache_info_var = (CACHE_INFO_VAR *) realloc(cache_info_var, sizeof(CACHE_INFO_VAR) * (n_cache_info_var + 1));
1826 0 : memset(cache_info_var, 0, sizeof(CACHE_INFO_VAR) * (n_cache_info_var + 1));
1827 : }
1828 :
1829 0 : if (cache_info_var == NULL)
1830 0 : return MSCB_NO_MEM;
1831 :
1832 0 : cache_info_var[n_cache_info_var].fd = fd;
1833 0 : cache_info_var[n_cache_info_var].adr = adr;
1834 0 : cache_info_var[n_cache_info_var].index = index;
1835 :
1836 : #ifdef HAVE_MRPC
1837 : if (mrpc_connected(fd))
1838 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_INFO_VARIABLE,
1839 : mscb_fd[fd - 1].remote_fd, adr, index, info);
1840 : #endif
1841 :
1842 0 : for (retry = 0; retry < 2; retry++) {
1843 0 : buf[0] = MCMD_ADDR_NODE16;
1844 0 : buf[1] = (unsigned char) (adr >> 8);
1845 0 : buf[2] = (unsigned char) (adr & 0xFF);
1846 0 : buf[3] = crc8(buf, 3);
1847 :
1848 0 : buf[4] = MCMD_GET_INFO + 1;
1849 0 : buf[5] = index;
1850 0 : buf[6] = crc8(buf + 4, 2);
1851 0 : size = sizeof(buf);
1852 0 : mscb_exchg(fd, buf, &size, 7, RS485_FLAG_ADR_CYCLE);
1853 :
1854 : // support for 16 bytes name field
1855 0 : if (size == (int) sizeof(MSCB_INFO_VAR) + 3 || size == (int) sizeof(MSCB_INFO_VAR) + 3 - 8)
1856 : break;
1857 : }
1858 :
1859 0 : if (size < (int) sizeof(MSCB_INFO_VAR) + 3 - 8) {
1860 0 : if (size == 2) // negative acknowledge
1861 0 : cache_info_var[n_cache_info_var].info.name[0] = 0;
1862 0 : return MSCB_NO_VAR;
1863 : }
1864 :
1865 : /* do CRC check */
1866 0 : if (crc8(buf, size - 1) != buf[size - 1])
1867 0 : return MSCB_CRC_ERROR;
1868 :
1869 0 : memcpy(info, buf + 2, size - 3);
1870 0 : memcpy(&cache_info_var[n_cache_info_var++].info, info, size - 3);
1871 :
1872 0 : debug_log("mscb_info_variable return info from MSCB node", 0);
1873 : }
1874 :
1875 0 : return MSCB_SUCCESS;
1876 : }
1877 :
1878 : /*------------------------------------------------------------------*/
1879 :
1880 0 : int mscb_set_node_addr(int fd, int addr, int gaddr, int broadcast,
1881 : unsigned short new_addr)
1882 : /********************************************************************\
1883 :
1884 : Routine: mscb_set_node_addr
1885 :
1886 : Purpose: Set node address of an node. Only set high byte if addressed
1887 : in group or broadcast mode
1888 :
1889 : Input:
1890 : int fd File descriptor for connection
1891 : int addr Node address
1892 : int gaddr Group address
1893 : int broadcast Broadcast flag
1894 : unsigned short new_addr New node address
1895 :
1896 : Function value:
1897 : MSCB_SUCCESS Successful completion
1898 : MSCB_MUTEX Cannot obtain mutex for mscb
1899 :
1900 : \********************************************************************/
1901 : {
1902 : unsigned char buf[64];
1903 : int status;
1904 :
1905 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
1906 0 : return MSCB_INVAL_PARAM;
1907 :
1908 : #ifdef HAVE_MRPC
1909 : if (mrpc_connected(fd))
1910 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_SET_NODE_ADDR, mscb_fd[fd - 1].remote_fd,
1911 : addr, gaddr, broadcast, new_addr);
1912 : #endif
1913 :
1914 0 : if (addr >= 0) { // individual node
1915 :
1916 : /* check if destination address is alive */
1917 0 : if (addr >= 0) {
1918 0 : status = mscb_ping(fd, new_addr, 0, 1);
1919 0 : if (status == MSCB_SUCCESS)
1920 0 : return MSCB_ADDR_EXISTS;
1921 : }
1922 :
1923 0 : buf[0] = MCMD_ADDR_NODE16;
1924 0 : buf[1] = (unsigned char) (addr >> 8);
1925 0 : buf[2] = (unsigned char) (addr & 0xFF);
1926 0 : buf[3] = crc8(buf, 3);
1927 :
1928 0 : buf[4] = MCMD_SET_ADDR;
1929 0 : buf[5] = ADDR_SET_NODE;
1930 0 : buf[6] = (unsigned char) (new_addr >> 8);
1931 0 : buf[7] = (unsigned char) (new_addr & 0xFF);
1932 0 : buf[8] = crc8(buf + 4, 4);
1933 0 : mscb_exchg(fd, buf, NULL, 9, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
1934 :
1935 0 : } else if (gaddr >= 0) {
1936 0 : buf[0] = MCMD_ADDR_GRP16;
1937 0 : buf[1] = (unsigned char) (gaddr >> 8);
1938 0 : buf[2] = (unsigned char) (gaddr & 0xFF);
1939 0 : buf[3] = crc8(buf, 3);
1940 :
1941 0 : buf[4] = MCMD_SET_ADDR;
1942 0 : buf[5] = ADDR_SET_HIGH;
1943 0 : buf[6] = (unsigned char) (new_addr >> 8);
1944 0 : buf[7] = (unsigned char) (new_addr & 0xFF);
1945 0 : buf[8] = crc8(buf + 4, 4);
1946 0 : mscb_exchg(fd, buf, NULL, 9, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
1947 :
1948 0 : } else if (broadcast) {
1949 0 : buf[0] = MCMD_ADDR_BC;
1950 0 : buf[1] = crc8(buf, 1);
1951 :
1952 0 : buf[2] = MCMD_SET_ADDR;
1953 0 : buf[3] = ADDR_SET_HIGH;
1954 0 : buf[4] = (unsigned char) (new_addr >> 8);
1955 0 : buf[5] = (unsigned char) (new_addr & 0xFF);
1956 0 : buf[6] = crc8(buf + 2, 4);
1957 0 : mscb_exchg(fd, buf, NULL, 7, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
1958 :
1959 : }
1960 :
1961 0 : mscb_clear_info_cache();
1962 :
1963 0 : return MSCB_SUCCESS;
1964 : }
1965 :
1966 : /*------------------------------------------------------------------*/
1967 :
1968 0 : int mscb_set_group_addr(int fd, int addr, int gaddr, int broadcast, unsigned short new_addr)
1969 : /********************************************************************\
1970 :
1971 : Routine: mscb_set_gaddr
1972 :
1973 : Purpose: Set group address of addressed node(s)
1974 :
1975 : Input:
1976 : int fd File descriptor for connection
1977 : int addr Node address
1978 : int gaddr Group address
1979 : int broadcast Broadcast flag
1980 : unsigned short new_addr New group address
1981 :
1982 : Function value:
1983 : MSCB_SUCCESS Successful completion
1984 : MSCB_MUTEX Cannot obtain mutex for mscb
1985 :
1986 : \********************************************************************/
1987 : {
1988 : unsigned char buf[64];
1989 :
1990 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
1991 0 : return MSCB_INVAL_PARAM;
1992 :
1993 : #ifdef HAVE_MRPC
1994 : if (mrpc_connected(fd))
1995 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_SET_GROUP_ADDR, mscb_fd[fd - 1].remote_fd,
1996 : gaddr, new_addr);
1997 : #endif
1998 :
1999 0 : if (broadcast > 0) {
2000 0 : buf[0] = MCMD_ADDR_BC;
2001 0 : buf[1] = crc8(buf, 1);
2002 :
2003 0 : buf[2] = MCMD_SET_ADDR;
2004 0 : buf[3] = ADDR_SET_GROUP;
2005 0 : buf[4] = (unsigned char) (new_addr >> 8);
2006 0 : buf[5] = (unsigned char) (new_addr & 0xFF);
2007 0 : buf[6] = crc8(buf + 2, 4);
2008 0 : mscb_exchg(fd, buf, NULL, 7, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
2009 :
2010 0 : } else if (gaddr >= 0) {
2011 0 : buf[0] = MCMD_ADDR_GRP16;
2012 0 : buf[1] = (unsigned char) (gaddr >> 8);
2013 0 : buf[2] = (unsigned char) (gaddr & 0xFF);
2014 0 : buf[3] = crc8(buf, 3);
2015 :
2016 0 : buf[4] = MCMD_SET_ADDR;
2017 0 : buf[5] = ADDR_SET_GROUP;
2018 0 : buf[6] = (unsigned char) (new_addr >> 8);
2019 0 : buf[7] = (unsigned char) (new_addr & 0xFF);
2020 0 : buf[8] = crc8(buf + 4, 4);
2021 0 : mscb_exchg(fd, buf, NULL, 9, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
2022 :
2023 0 : } else if (addr >= 0) {
2024 0 : buf[0] = MCMD_ADDR_NODE16;
2025 0 : buf[1] = (unsigned char) (addr >> 8);
2026 0 : buf[2] = (unsigned char) (addr & 0xFF);
2027 0 : buf[3] = crc8(buf, 3);
2028 :
2029 0 : buf[4] = MCMD_SET_ADDR;
2030 0 : buf[5] = ADDR_SET_GROUP;
2031 0 : buf[6] = (unsigned char) (new_addr >> 8);
2032 0 : buf[7] = (unsigned char) (new_addr & 0xFF);
2033 0 : buf[8] = crc8(buf + 4, 4);
2034 0 : mscb_exchg(fd, buf, NULL, 9, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
2035 :
2036 : }
2037 :
2038 0 : mscb_clear_info_cache();
2039 :
2040 0 : return MSCB_SUCCESS;
2041 : }
2042 :
2043 : /*------------------------------------------------------------------*/
2044 :
2045 0 : int mscb_set_name(int fd, unsigned short adr, char *name)
2046 : /********************************************************************\
2047 :
2048 : Routine: mscb_set_name
2049 :
2050 : Purpose: Set node name
2051 :
2052 : Input:
2053 : int fd File descriptor for connection
2054 : unsigned short adr Node address
2055 : char *name New node name, up to 16 characters
2056 :
2057 : Function value:
2058 : MSCB_SUCCESS Successful completion
2059 : MSCB_MUTEX Cannot obtain mutex for mscb
2060 :
2061 : \********************************************************************/
2062 : {
2063 : unsigned char buf[256];
2064 : int i;
2065 :
2066 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
2067 0 : return MSCB_INVAL_PARAM;
2068 :
2069 : #ifdef HAVE_MRPC
2070 : if (mrpc_connected(fd))
2071 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_SET_NAME, mscb_fd[fd - 1].remote_fd, adr, name);
2072 : #endif
2073 :
2074 0 : buf[0] = MCMD_ADDR_NODE16;
2075 0 : buf[1] = (unsigned char) (adr >> 8);
2076 0 : buf[2] = (unsigned char) (adr & 0xFF);
2077 0 : buf[3] = crc8(buf, 3);
2078 :
2079 0 : buf[4] = MCMD_SET_NAME;
2080 0 : for (i = 0; i < 16 && name[i]; i++)
2081 0 : buf[6 + i] = name[i];
2082 :
2083 0 : if (i < 16)
2084 0 : buf[6 + (i++)] = 0;
2085 :
2086 0 : buf[5] = (unsigned char) i; /* varibale buffer length */
2087 :
2088 0 : buf[6 + i] = crc8(buf + 4, 2 + i);
2089 0 : mscb_exchg(fd, buf, NULL, 7 + i, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
2090 :
2091 0 : mscb_clear_info_cache();
2092 :
2093 0 : return MSCB_SUCCESS;
2094 : }
2095 :
2096 : /*------------------------------------------------------------------*/
2097 :
2098 0 : int mscb_write_group(int fd, unsigned short adr, unsigned char index, void *data, int size)
2099 : /********************************************************************\
2100 :
2101 : Routine: mscb_write_group
2102 :
2103 : Purpose: Write data to channels on group of nodes
2104 :
2105 : Input:
2106 : int fd File descriptor for connection
2107 : unsigned short adr group address
2108 : unsigned char index Variable index 0..255
2109 : unsigned int data Data to send
2110 : int size Data size in bytes 1..4 for byte, word,
2111 : and dword
2112 :
2113 : Function value:
2114 : MSCB_SUCCESS Successful completion
2115 : MSCB_MUTEX Cannot obtain mutex for mscb
2116 :
2117 : \********************************************************************/
2118 : {
2119 : int i;
2120 : unsigned char *d;
2121 : unsigned char buf[256];
2122 :
2123 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
2124 0 : return MSCB_INVAL_PARAM;
2125 :
2126 : #ifdef HAVE_MRPC
2127 : if (mrpc_connected(fd))
2128 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_WRITE_GROUP,
2129 : mscb_fd[fd - 1].remote_fd, adr, index, data, size);
2130 : #endif
2131 :
2132 0 : if (size > 4 || size < 1)
2133 0 : return MSCB_INVAL_PARAM;
2134 :
2135 0 : buf[0] = MCMD_ADDR_GRP16;
2136 0 : buf[1] = (unsigned char) (adr >> 8);
2137 0 : buf[2] = (unsigned char) (adr & 0xFF);
2138 0 : buf[3] = crc8(buf, 3);
2139 :
2140 0 : buf[4] = (unsigned char) (MCMD_WRITE_NA + size + 1);
2141 0 : buf[5] = index;
2142 :
2143 0 : for (i = 0, d = (unsigned char *) data; i < size; i++)
2144 0 : buf[6 + size - 1 - i] = *d++;
2145 :
2146 0 : buf[6 + i] = crc8(buf, 6 + i);
2147 0 : mscb_exchg(fd, buf, NULL, 7 + i, RS485_FLAG_ADR_CYCLE | RS485_FLAG_NO_ACK);
2148 :
2149 0 : return MSCB_SUCCESS;
2150 : }
2151 :
2152 : /*------------------------------------------------------------------*/
2153 :
2154 0 : int mscb_write(int fd, unsigned short adr, unsigned char index, void *data, int size)
2155 : /********************************************************************\
2156 :
2157 : Routine: mscb_write
2158 :
2159 : Purpose: Write data to variable on single node
2160 :
2161 : Input:
2162 : int fd File descriptor for connection
2163 : unsigned short adr Node address
2164 : unsigned char index Variable index 0..255
2165 : void *data Data to send
2166 : int size Data size in bytes 1..4 for byte, word,
2167 : and dword
2168 :
2169 : Function value:
2170 : MSCB_SUCCESS Successful completion
2171 : MSCB_TIMEOUT Timeout receiving acknowledge
2172 : MSCB_CRC_ERROR CRC error
2173 : MSCB_INVAL_PARAM Parameter "size" has invalid value
2174 : MSCB_MUTEX Cannot obtain mutex for mscb
2175 :
2176 : \********************************************************************/
2177 : {
2178 : int i, len, retry, status;
2179 : unsigned char buf[256], crc;
2180 : unsigned char *d;
2181 : unsigned int dw;
2182 : unsigned long qw;
2183 : float f;
2184 :
2185 0 : dw = 0;
2186 0 : f = 0;
2187 0 : if (size == 1)
2188 0 : dw = *((unsigned char *) data);
2189 0 : else if (size == 2)
2190 0 : dw = *((unsigned short *) data);
2191 0 : else if (size == 4) {
2192 0 : dw = *((unsigned int *) data);
2193 0 : f = *((float *) data);
2194 0 : } else if (size == 8) {
2195 0 : qw = *((unsigned long *) data);
2196 : }
2197 :
2198 0 : if (size == 8)
2199 0 : debug_log("mscb_write(fd=%d,adr=%d,index=%d,data=0x%lX,size=%d)", 1, fd, adr, index, qw, size);
2200 0 : else if (size == 4)
2201 0 : debug_log("mscb_write(fd=%d,adr=%d,index=%d,data=%lf/0x%X,size=%d)", 1, fd, adr, index, f, dw, size);
2202 0 : else if (size < 4)
2203 0 : debug_log("mscb_write(fd=%d,adr=%d,index=%d,data=0x%X,size=%d)", 1, fd, adr, index, dw, size);
2204 : else
2205 0 : debug_log("mscb_write(fd=%d,adr=%d,index=%d,data=\"%s\",size=%d)", 1, fd, adr, index, (char *) data, size);
2206 :
2207 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type) {
2208 0 : debug_log("mscb_write return MSCB_INVAL_PARAM", 1);
2209 0 : return MSCB_INVAL_PARAM;
2210 : }
2211 :
2212 : #ifdef HAVE_MRPC
2213 : if (mrpc_connected(fd))
2214 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_WRITE, mscb_fd[fd - 1].remote_fd, adr, index, data, size);
2215 : #endif
2216 :
2217 0 : if (size < 1) {
2218 0 : debug_log("mscb_write return MSCB_INVAL_PARAM", 1);
2219 0 : return MSCB_INVAL_PARAM;
2220 : }
2221 :
2222 : /* retry several times */
2223 0 : status = 0;
2224 0 : for (retry = 0; retry < mscb_max_retry; retry++) {
2225 :
2226 0 : buf[0] = MCMD_ADDR_NODE16;
2227 0 : buf[1] = (unsigned char) (adr >> 8);
2228 0 : buf[2] = (unsigned char) (adr & 0xFF);
2229 0 : buf[3] = crc8(buf, 3);
2230 :
2231 0 : if (size < 6) {
2232 0 : buf[4] = (unsigned char) (MCMD_WRITE_ACK + size + 1);
2233 0 : buf[5] = index;
2234 :
2235 : /* reverse order for WORD & DWORD */
2236 0 : if (size < 5)
2237 0 : for (i = 0, d = (unsigned char *) data; i < size; i++)
2238 0 : buf[6 + size - 1 - i] = *d++;
2239 : else
2240 0 : for (i = 0, d = (unsigned char *) data; i < size; i++)
2241 0 : buf[6 + i] = *d++;
2242 :
2243 0 : crc = crc8(buf + 4, 2 + i);
2244 0 : buf[6 + i] = crc;
2245 0 : len = sizeof(buf);
2246 0 : status = mscb_exchg(fd, buf, &len, 7 + i, RS485_FLAG_ADR_CYCLE);
2247 : } else {
2248 0 : buf[4] = MCMD_WRITE_ACK + 7;
2249 0 : buf[5] = (unsigned char) (size + 1);
2250 0 : buf[6] = index;
2251 :
2252 0 : for (i = 0, d = (unsigned char *) data; i < size; i++)
2253 0 : buf[7 + i] = *d++;
2254 :
2255 0 : crc = crc8(buf + 4, 3 + i);
2256 0 : buf[7 + i] = crc;
2257 0 : len = sizeof(buf);
2258 0 : status = mscb_exchg(fd, buf, &len, 8 + i, RS485_FLAG_ADR_CYCLE);
2259 : }
2260 :
2261 0 : if (len == 1) {
2262 0 : debug_log("Timeout from RS485 bus at %s:%d", 1, mscb_fd[fd - 1].device, adr);
2263 : // printf("## Timeout from RS485 bus at %s:%d, retry %d\n", mscb_fd[fd - 1].device, adr, retry);
2264 0 : status = MSCB_TIMEOUT;
2265 :
2266 0 : debug_log("Flush node communication at %s:%d", 1, mscb_fd[fd - 1].device, adr);
2267 0 : memset(buf, 0, sizeof(buf));
2268 0 : mscb_exchg(fd, buf, NULL, 10, RS485_FLAG_BIT9 | RS485_FLAG_NO_ACK);
2269 0 : Sleep(100 + retry*100);
2270 :
2271 0 : continue;
2272 : }
2273 :
2274 0 : if (status == MSCB_TIMEOUT) {
2275 0 : debug_log("return MSCB_TIMEOUT", 1);
2276 0 : status = MSCB_TIMEOUT;
2277 0 : continue;
2278 : }
2279 :
2280 0 : if (buf[0] != MCMD_ACK || buf[1] != crc) {
2281 0 : debug_log("return MSCB_CRC_ERROR", 1);
2282 0 : status = MSCB_CRC_ERROR;
2283 0 : continue;
2284 : }
2285 :
2286 0 : status = MSCB_SUCCESS;
2287 0 : debug_log("return MSCB_SUCCESS", 1);
2288 0 : break;
2289 : }
2290 :
2291 0 : return status;
2292 : }
2293 :
2294 : /*------------------------------------------------------------------*/
2295 :
2296 0 : int mscb_write_no_retries(int fd, unsigned short adr, unsigned char index, void *data, int size)
2297 : /********************************************************************\
2298 :
2299 : Routine: mscb_write
2300 :
2301 : Purpose: Same as mscb_write, but without retries
2302 :
2303 : Input:
2304 : int fd File descriptor for connection
2305 : unsigned short adr Node address
2306 : unsigned char index Variable index 0..255
2307 : void *data Data to send
2308 : int size Data size in bytes 1..4 for byte, word,
2309 : and dword
2310 :
2311 : Function value:
2312 : MSCB_SUCCESS Successful completion
2313 : MSCB_TIMEOUT Timeout receiving acknowledge
2314 : MSCB_CRC_ERROR CRC error
2315 : MSCB_INVAL_PARAM Parameter "size" has invalid value
2316 : MSCB_MUTEX Cannot obtain mutex for mscb
2317 :
2318 : \********************************************************************/
2319 : {
2320 : int i, len;
2321 : unsigned char buf[256], crc;
2322 : unsigned char *d;
2323 : unsigned int dw;
2324 :
2325 0 : dw = 0;
2326 0 : if (size == 1)
2327 0 : dw = *((unsigned char *) data);
2328 0 : else if (size == 2)
2329 0 : dw = *((unsigned short *) data);
2330 0 : else if (size == 4)
2331 0 : dw = *((unsigned int *) data);
2332 :
2333 0 : if (size <= 4)
2334 0 : debug_log("mscb_write(fd=%d,adr=%d,index=%d,data=0x%X,size=%d)", 1, fd, adr, index, dw, size);
2335 : else
2336 0 : debug_log("mscb_write(fd=%d,adr=%d,index=%d,data=\"%s\",size=%d)", 1, fd, adr, index, (char *) data, size);
2337 :
2338 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type) {
2339 0 : debug_log("mscb_write return MSCB_INVAL_PARAM", 1);
2340 0 : return MSCB_INVAL_PARAM;
2341 : }
2342 :
2343 : #ifdef HAVE_MRPC
2344 : if (mrpc_connected(fd))
2345 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_WRITE_NO_RETRIES, mscb_fd[fd - 1].remote_fd, adr, index, data, size);
2346 : #endif
2347 :
2348 0 : if (size < 1) {
2349 0 : debug_log("mscb_write return MSCB_INVAL_PARAM", 1);
2350 0 : return MSCB_INVAL_PARAM;
2351 : }
2352 :
2353 0 : buf[0] = MCMD_ADDR_NODE16;
2354 0 : buf[1] = (unsigned char) (adr >> 8);
2355 0 : buf[2] = (unsigned char) (adr & 0xFF);
2356 0 : buf[3] = crc8(buf, 3);
2357 :
2358 0 : if (size < 6) {
2359 0 : buf[4] = (unsigned char) (MCMD_WRITE_ACK + size + 1);
2360 0 : buf[5] = index;
2361 :
2362 : /* reverse order for WORD & DWORD */
2363 0 : if (size < 5)
2364 0 : for (i = 0, d = (unsigned char *) data; i < size; i++)
2365 0 : buf[6 + size - 1 - i] = *d++;
2366 : else
2367 0 : for (i = 0, d = (unsigned char *) data; i < size; i++)
2368 0 : buf[6 + i] = *d++;
2369 :
2370 0 : crc = crc8(buf + 4, 2 + i);
2371 0 : buf[6 + i] = crc;
2372 0 : len = sizeof(buf);
2373 0 : mscb_exchg(fd, buf, &len, 7 + i, RS485_FLAG_ADR_CYCLE);
2374 : } else {
2375 0 : buf[4] = MCMD_WRITE_ACK + 7;
2376 0 : buf[5] = (unsigned char) (size + 1);
2377 0 : buf[6] = index;
2378 :
2379 0 : for (i = 0, d = (unsigned char *) data; i < size; i++)
2380 0 : buf[7 + i] = *d++;
2381 :
2382 0 : crc = crc8(buf + 4, 3 + i);
2383 0 : buf[7 + i] = crc;
2384 0 : len = sizeof(buf);
2385 0 : mscb_exchg(fd, buf, &len, 8 + i, RS485_FLAG_ADR_CYCLE);
2386 : }
2387 :
2388 0 : if (len < 2) {
2389 0 : debug_log("mscb_write return MSCB_TIMEOUT", 1);
2390 0 : return MSCB_TIMEOUT;
2391 : }
2392 :
2393 0 : if (buf[0] != MCMD_ACK || buf[1] != crc) {
2394 0 : debug_log("mscb_write return MSCB_CRC_ERROR", 1);
2395 0 : return MSCB_CRC_ERROR;
2396 : }
2397 :
2398 0 : debug_log("mscb_write return MSCB_SUCCESS", 1);
2399 0 : return MSCB_SUCCESS;
2400 : }
2401 :
2402 : /*------------------------------------------------------------------*/
2403 :
2404 0 : int mscb_write_range(int fd, unsigned short adr, unsigned char index1, unsigned char index2, void *data, int size)
2405 : /********************************************************************\
2406 :
2407 : Routine: mscb_write_range
2408 :
2409 : Purpose: Write data to multiple indices on node
2410 :
2411 : Input:
2412 : int fd File descriptor for connection
2413 : unsigned short adr Node address
2414 : unsigned char index1 First variable index 0..255 to write
2415 : unsigned char index2 Last variable index 0..255 to write
2416 : void *data Data to send
2417 : int size Data size in bytes
2418 :
2419 : Function value:
2420 : MSCB_SUCCESS Successful completion
2421 : MSCB_TIMEOUT Timeout receiving acknowledge
2422 : MSCB_CRC_ERROR CRC error
2423 : MSCB_INVAL_PARAM Parameter "size" has invalid value
2424 : MSCB_MUTEX Cannot obtain mutex for mscb
2425 :
2426 : \********************************************************************/
2427 : {
2428 : int i, len, status, retry;
2429 : unsigned char buf[256], crc;
2430 :
2431 0 : debug_log("mscb_write_range(fd=%d,adr=%d,index1=%d,index2=%d,size=%d)",
2432 : 1, fd, adr, index1, index2, size);
2433 :
2434 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type) {
2435 0 : debug_log("mscb_write_range return MSCB_INVAL_PARAM", 1);
2436 0 : return MSCB_INVAL_PARAM;
2437 : }
2438 :
2439 : #ifdef HAVE_MRPC
2440 : if (mrpc_connected(fd))
2441 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_WRITE_RANGE,
2442 : mscb_fd[fd - 1].remote_fd, adr, index1, index2, data, size);
2443 : #endif
2444 :
2445 0 : if (size < 1 || size + 10 > (int) sizeof(buf)) {
2446 0 : debug_log("mscb_write_range return MSCB_INVAL_PARAM", 1);
2447 0 : return MSCB_INVAL_PARAM;
2448 : }
2449 :
2450 : /* retry several times */
2451 0 : status = 0;
2452 0 : for (retry = 0; retry < mscb_max_retry; retry++) {
2453 :
2454 0 : buf[0] = MCMD_ADDR_NODE16;
2455 0 : buf[1] = (unsigned char) (adr >> 8);
2456 0 : buf[2] = (unsigned char) (adr & 0xFF);
2457 0 : buf[3] = crc8(buf, 3);
2458 :
2459 0 : buf[4] = MCMD_WRITE_RANGE | 0x07;
2460 :
2461 0 : if (size < 128) {
2462 0 : buf[5] = size + 2;
2463 0 : buf[6] = index1;
2464 0 : buf[7] = index2;
2465 :
2466 0 : for (i = 0; i < size; i++)
2467 0 : buf[8 + i] = ((char *) data)[i];
2468 :
2469 0 : crc = crc8(buf + 4, 4 + i);
2470 0 : buf[8 + i] = crc;
2471 0 : len = sizeof(buf);
2472 0 : status = mscb_exchg(fd, buf, &len, 9 + i, RS485_FLAG_ADR_CYCLE);
2473 : } else {
2474 0 : buf[5] = 0x80 | ((size + 2) >> 8);
2475 0 : buf[6] = (size + 2) & 0xFF;
2476 0 : buf[7] = index1;
2477 0 : buf[8] = index2;
2478 :
2479 0 : for (i = 0; i < size; i++)
2480 0 : buf[9 + i] = ((char *) data)[i];
2481 :
2482 0 : crc = crc8(buf + 4, 5 + i);
2483 0 : buf[9 + i] = crc;
2484 0 : len = sizeof(buf);
2485 0 : status = mscb_exchg(fd, buf, &len, 10 + i, RS485_FLAG_ADR_CYCLE);
2486 : }
2487 :
2488 0 : if (len == 1) {
2489 0 : debug_log("mscb_write_range timeout from RS485 bus at %s:%d", 1, mscb_fd[fd - 1].device, adr);
2490 0 : status = MSCB_TIMEOUT;
2491 :
2492 0 : debug_log("mscb_write_range flush node communication at %s:%d\n", 1, mscb_fd[fd - 1].device, adr);
2493 0 : memset(buf, 0, sizeof(buf));
2494 0 : mscb_exchg(fd, buf, NULL, 10, RS485_FLAG_BIT9 | RS485_FLAG_NO_ACK);
2495 0 : Sleep(100);
2496 :
2497 0 : continue;
2498 : }
2499 :
2500 0 : if (status == MSCB_TIMEOUT) {
2501 0 : debug_log("mscb_write_range return MSCB_TIMEOUT", 1);
2502 0 : status = MSCB_TIMEOUT;
2503 0 : continue;
2504 : }
2505 :
2506 0 : if (buf[0] != MCMD_ACK || buf[1] != crc) {
2507 0 : debug_log("mscb_write_range return MSCB_CRC_ERROR", 1);
2508 0 : status = MSCB_CRC_ERROR;
2509 0 : continue;
2510 : }
2511 :
2512 0 : status = MSCB_SUCCESS;
2513 0 : debug_log("mscb_write_range return MSCB_SUCCESS", 1);
2514 0 : break;
2515 : }
2516 :
2517 0 : return status;
2518 : }
2519 :
2520 : /*------------------------------------------------------------------*/
2521 :
2522 0 : int mscb_flash(int fd, int addr, int gaddr, int broadcast)
2523 : /********************************************************************\
2524 :
2525 : Routine: mscb_flash
2526 :
2527 : Purpose: Flash node variables to EEPROM
2528 :
2529 :
2530 : Input:
2531 : int fd File descriptor for connection
2532 : int addr Node address
2533 : int gaddr Group address
2534 : int broadcast Broadcast flag
2535 :
2536 : Function value:
2537 : MSCB_SUCCESS Successful completion
2538 : MSCB_TIMEOUT Timeout receiving acknowledge
2539 : MSCB_CRC_ERROR CRC error
2540 : MSCB_INVAL_PARAM Parameter "size" has invalid value
2541 : MSCB_MUTEX Cannot obtain mutex for mscb
2542 :
2543 : \********************************************************************/
2544 : {
2545 : unsigned char buf[64];
2546 :
2547 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
2548 0 : return MSCB_INVAL_PARAM;
2549 :
2550 : #ifdef HAVE_MRPC
2551 : if (mrpc_connected(fd))
2552 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_FLASH, mscb_fd[fd - 1].remote_fd, addr, gaddr, broadcast);
2553 : #endif
2554 :
2555 0 : if (addr >= 0) {
2556 0 : buf[0] = MCMD_ADDR_NODE16;
2557 0 : buf[1] = (unsigned char) (addr >> 8);
2558 0 : buf[2] = (unsigned char) (addr & 0xFF);
2559 0 : buf[3] = crc8(buf, 3);
2560 :
2561 0 : buf[4] = MCMD_FLASH;
2562 0 : buf[5] = crc8(buf + 4, 1);
2563 0 : mscb_exchg(fd, buf, NULL, 6, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
2564 0 : } else if (gaddr >= 0) {
2565 0 : buf[0] = MCMD_ADDR_GRP16;
2566 0 : buf[1] = (unsigned char) (gaddr >> 8);
2567 0 : buf[2] = (unsigned char) (gaddr & 0xFF);
2568 0 : buf[3] = crc8(buf, 3);
2569 :
2570 0 : buf[4] = MCMD_FLASH;
2571 0 : buf[5] = crc8(buf + 4, 1);
2572 0 : mscb_exchg(fd, buf, NULL, 6, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
2573 0 : } else if (broadcast) {
2574 0 : buf[0] = MCMD_ADDR_BC;
2575 0 : buf[1] = crc8(buf, 1);
2576 :
2577 0 : buf[2] = MCMD_FLASH;
2578 0 : buf[3] = crc8(buf + 2, 1);
2579 0 : mscb_exchg(fd, buf, NULL, 4, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
2580 : }
2581 :
2582 : /* wait until flash has finished, otherwise nodes cannot continue
2583 : to receive further commands */
2584 0 : Sleep(500);
2585 :
2586 0 : return MSCB_SUCCESS;
2587 : }
2588 :
2589 : /*------------------------------------------------------------------*/
2590 :
2591 0 : int mscb_set_baud(int fd, int baud)
2592 : /********************************************************************\
2593 :
2594 : Routine: mscb_set_baud
2595 :
2596 : Purpose: Set baud rate of a whole MSCB bus
2597 :
2598 :
2599 : Input:
2600 : int fd File descriptor for connection
2601 : int baud Baud rate:
2602 : 1: 2400
2603 : 2: 4800
2604 : 3: 9600
2605 : 4: 19200
2606 : 5: 28800
2607 : 6: 38400
2608 : 7: 57600
2609 : 8: 115200
2610 : 9: 172800
2611 : 10: 345600
2612 :
2613 : Function value:
2614 : MSCB_SUCCESS Successful completion
2615 : MSCB_TIMEOUT Timeout receiving acknowledge
2616 : MSCB_CRC_ERROR CRC error
2617 : MSCB_INVAL_PARAM Parameter "size" has invalid value
2618 : MSCB_MUTEX Cannot obtain mutex for mscb
2619 :
2620 : \********************************************************************/
2621 : {
2622 : unsigned char buf[64];
2623 :
2624 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
2625 0 : return MSCB_INVAL_PARAM;
2626 :
2627 : #ifdef HAVE_MRPC
2628 : if (mrpc_connected(fd))
2629 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_SET_BAUD, mscb_fd[fd - 1].remote_fd, baud);
2630 : #endif
2631 :
2632 0 : buf[0] = MCMD_ADDR_BC;
2633 0 : buf[1] = crc8(buf, 1);
2634 :
2635 0 : buf[2] = MCMD_SET_BAUD;
2636 0 : buf[3] = baud;
2637 0 : buf[4] = crc8(buf + 2, 2);
2638 0 : mscb_exchg(fd, buf, NULL, 5, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
2639 :
2640 0 : return MSCB_SUCCESS;
2641 : }
2642 :
2643 : /*------------------------------------------------------------------*/
2644 :
2645 0 : int mscb_interprete_file(const char *filename, unsigned char **image, unsigned int *size, unsigned char **header,
2646 : unsigned int *header_size, unsigned char *bitfile_header)
2647 : /* file interpreter used by mscb_upload */
2648 : {
2649 : int fh, i;
2650 : unsigned char *line, *p;
2651 : unsigned int d, ofs, len, imagesize, ofh, ofl, type;
2652 : char str[256];
2653 : XIL_FW_HEADER *fw_header;
2654 : XIL_SW_HEADER *sw_header;
2655 :
2656 : /* check if file exists */
2657 0 : fh = open(filename, O_RDONLY | O_BINARY);
2658 0 : if (fh <= 0)
2659 0 : return MSCB_NOT_FOUND;
2660 :
2661 : /* read file to buffer */
2662 0 : size_t filesize = lseek(fh, 0, SEEK_END);
2663 0 : lseek(fh, 0, SEEK_SET);
2664 0 : unsigned char* buffer = (unsigned char *) malloc(filesize + 1);
2665 0 : memset(buffer, 0, filesize + 1);
2666 0 : ssize_t rd = read(fh, buffer, filesize);
2667 0 : if (rd < 0) {
2668 0 : fprintf(stderr, "Error reading \"%s\", read(%zu) returned %zu, errno %d (%s)\n", filename, filesize, rd, errno, strerror(errno));
2669 0 : exit(1);
2670 : }
2671 0 : if ((size_t)rd != filesize) {
2672 0 : fprintf(stderr, "Error reading \"%s\", read(%zu) returned %zu, short read\n", filename, filesize, rd);
2673 0 : exit(1);
2674 : }
2675 0 : close(fh);
2676 0 : *size = imagesize = 0;
2677 0 : if (header_size)
2678 0 : *header_size = 0;
2679 0 : if (bitfile_header)
2680 0 : memset(bitfile_header, 0, sizeof(XIL_FW_HEADER));
2681 :
2682 : /* interprete hex file */
2683 0 : if (strstr(filename, ".hex") || strstr(filename, ".HEX")) { //----------------------------
2684 0 : *image = (unsigned char *) malloc(0x10000);
2685 0 : memset(*image, 0xFF, 0x10000);
2686 0 : line = buffer;
2687 0 : imagesize = 0;
2688 : do {
2689 0 : if (line[0] == ':') {
2690 0 : sscanf((const char *) line + 1, "%02x%02x%02x%02x", &len, &ofh, &ofl, &type);
2691 0 : ofs = (unsigned short) ((ofh << 8) | ofl);
2692 :
2693 0 : for (i = 0; i < (int) len; i++) {
2694 0 : sscanf((const char *) line + 9 + i * 2, "%02x", &d);
2695 0 : *((*image) + ofs + i) = (unsigned char) d;
2696 : }
2697 :
2698 0 : imagesize += len;
2699 0 : line = (unsigned char *) strchr((char *) line, '\n');
2700 0 : if (line == NULL)
2701 0 : break;
2702 :
2703 : /* skip CR/LF */
2704 0 : while (*line == '\r' || *line == '\n')
2705 0 : line++;
2706 : } else {
2707 0 : free(buffer);
2708 0 : return MSCB_FORMAT_ERROR;
2709 : }
2710 :
2711 0 : } while (*line);
2712 :
2713 : }
2714 :
2715 : /* interprete Xilinx firmware bit file */
2716 0 : else if (strstr(filename, ".bit") || strstr(filename, ".BIT")) { //----------------------------
2717 0 : fw_header = (XIL_FW_HEADER *) bitfile_header;
2718 0 : p = buffer;
2719 0 : printf("Bit file header:\n");
2720 :
2721 0 : len = (p[0] << 8) | p[1];
2722 0 : p += 2;
2723 0 : p += len;
2724 :
2725 0 : len = (p[0] << 8) | p[1];
2726 0 : p += 2;
2727 0 : if (*p != 'a' || len != 1) {
2728 0 : free(buffer);
2729 0 : return MSCB_FORMAT_ERROR;
2730 : }
2731 0 : p += len;
2732 :
2733 0 : len = (p[0] << 8) | p[1];
2734 0 : p += 2;
2735 0 : memcpy(str, p, len);
2736 0 : if (fw_header)
2737 0 : fw_header->name_offs = p - buffer;
2738 0 : printf("Flags : %s\n", str);
2739 0 : p += len;
2740 :
2741 0 : if (*p != 'b') {
2742 0 : free(buffer);
2743 0 : return MSCB_FORMAT_ERROR;
2744 : }
2745 0 : p += 1;
2746 0 : len = (p[0] << 8) | p[1];
2747 0 : p += 2;
2748 0 : memcpy(str, p, len);
2749 0 : if (fw_header)
2750 0 : fw_header->fpga_offs = p - buffer;
2751 0 : printf("Device : %s\n", str);
2752 0 : p += len;
2753 :
2754 0 : if (*p != 'c') {
2755 0 : free(buffer);
2756 0 : return MSCB_FORMAT_ERROR;
2757 : }
2758 0 : p += 1;
2759 0 : len = (p[0] << 8) | p[1];
2760 0 : p += 2;
2761 0 : memcpy(str, p, len);
2762 0 : if (fw_header)
2763 0 : fw_header->date_offs = p - buffer;
2764 0 : printf("Date : %s\n", str);
2765 0 : p += len;
2766 :
2767 0 : if (*p != 'd') {
2768 0 : free(buffer);
2769 0 : return MSCB_FORMAT_ERROR;
2770 : }
2771 0 : p += 1;
2772 0 : len = (p[0] << 8) | p[1];
2773 0 : p += 2;
2774 0 : memcpy(str, p, len);
2775 0 : if (fw_header)
2776 0 : fw_header->time_offs = p - buffer;
2777 0 : printf("Time : %s\n", str);
2778 0 : p += len;
2779 :
2780 0 : if (*p != 'e') {
2781 0 : free(buffer);
2782 0 : return MSCB_FORMAT_ERROR;
2783 : }
2784 0 : p += 1;
2785 0 : len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
2786 0 : p += 4;
2787 :
2788 0 : imagesize = filesize - (p - buffer);
2789 0 : if (fw_header)
2790 0 : fw_header->data_len = imagesize;
2791 0 : printf("Image size : %d\n\n", len);
2792 :
2793 0 : if (len != imagesize) {
2794 0 : free(buffer);
2795 0 : return MSCB_FORMAT_ERROR;
2796 : }
2797 :
2798 0 : if (fw_header) {
2799 0 : fw_header->head_len = p - buffer;
2800 0 : fw_header->head_id = XIL_BITFILE_HEADER_ID;
2801 0 : fw_header->checksum = ~(fw_header->name_offs +
2802 0 : fw_header->fpga_offs +
2803 0 : fw_header->date_offs +
2804 0 : fw_header->time_offs +
2805 0 : fw_header->data_len +
2806 0 : fw_header->head_len +
2807 0 : fw_header->head_id);
2808 :
2809 0 : DWORD_SWAP(&(fw_header->name_offs));
2810 0 : DWORD_SWAP(&(fw_header->fpga_offs));
2811 0 : DWORD_SWAP(&(fw_header->date_offs));
2812 0 : DWORD_SWAP(&(fw_header->time_offs));
2813 0 : DWORD_SWAP(&(fw_header->data_len));
2814 0 : DWORD_SWAP(&(fw_header->head_len));
2815 0 : DWORD_SWAP(&(fw_header->head_id));
2816 0 : DWORD_SWAP(&(fw_header->checksum));
2817 : }
2818 :
2819 0 : if (header_size) {
2820 0 : *header_size = p - buffer;
2821 0 : *header = (unsigned char *) malloc(*header_size);
2822 0 : memcpy(*header, buffer, *header_size);
2823 : }
2824 :
2825 0 : *image = (unsigned char *) malloc(imagesize);
2826 0 : memcpy(*image, p, imagesize);
2827 0 : }
2828 :
2829 : /* interprete Xilinx software file */
2830 0 : else if (strstr(filename, ".srec") || strstr(filename, ".SREC")) { //----------------------------
2831 0 : sw_header = (XIL_SW_HEADER *) bitfile_header;
2832 0 : sw_header->name_offs = 16;
2833 0 : sw_header->data_len = filesize;
2834 0 : sw_header->head_len = 17;
2835 0 : sw_header->checksum = ~(sw_header->name_offs +
2836 0 : sw_header->data_len +
2837 0 : sw_header->head_len);
2838 0 : DWORD_SWAP(&(sw_header->name_offs));
2839 0 : DWORD_SWAP(&(sw_header->data_len));
2840 0 : DWORD_SWAP(&(sw_header->head_len));
2841 0 : DWORD_SWAP(&(sw_header->checksum));
2842 :
2843 0 : imagesize = filesize;
2844 0 : *image = (unsigned char *) malloc(filesize);
2845 0 : memcpy(*image, buffer, imagesize);
2846 0 : }
2847 :
2848 : /* plain binary file */
2849 0 : else if (strstr(filename, ".bin") || strstr(filename, ".BIN")) {
2850 0 : imagesize = filesize;
2851 0 : *image = (unsigned char *) malloc(imagesize);
2852 0 : memcpy(*image, buffer, imagesize);
2853 : } else {
2854 0 : free(buffer);
2855 0 : return MSCB_FORMAT_ERROR;
2856 : }
2857 :
2858 0 : free(buffer);
2859 0 : *size = imagesize;
2860 :
2861 0 : return MSCB_SUCCESS;
2862 : }
2863 :
2864 : /*------------------------------------------------------------------*/
2865 :
2866 0 : int mscb_legacy_upload(int fd, unsigned short adr, unsigned char *image, unsigned int flash_size, int flag)
2867 : /* legacy upload for nodes not supporting the new CMD_WRITE_MEM / CMD_READ_MEM */
2868 : {
2869 : unsigned char buf[256], crc;
2870 : unsigned int buflen;
2871 : int i, page, subpage, n_page, retry, sretry, protected_page, n_page_disp;
2872 : int page_cont[128];
2873 :
2874 : /* count pages and bytes */
2875 0 : for (page = 0; page < (int) (sizeof(page_cont) / sizeof(int)); page++)
2876 0 : page_cont[page] = FALSE;
2877 :
2878 0 : for (page = n_page = 0; page < (int) (sizeof(page_cont) / sizeof(int)); page++) {
2879 : /* check if page contains data */
2880 0 : for (i = 0; i < 512; i++) {
2881 0 : if (image[page * 512 + i] != 0xFF) {
2882 0 : page_cont[page] = TRUE;
2883 0 : n_page++;
2884 0 : break;
2885 : }
2886 : }
2887 : }
2888 :
2889 : /* reduce number of "="'s if too many */
2890 0 : n_page_disp = (n_page / 70) + 1;
2891 :
2892 0 : protected_page = 128;
2893 :
2894 0 : if (flag == 1)
2895 0 : printf("Found %d valid pages (%d bytes) in HEX file\n", n_page, flash_size);
2896 :
2897 : /* enter exclusive mode */
2898 0 : buf[0] = MCMD_FREEZE;
2899 0 : buf[1] = 1;
2900 0 : buflen = sizeof(buf);
2901 0 : mscb_exchg(fd, buf, (int *) &buflen, 2, RS485_FLAG_CMD);
2902 :
2903 : /* wait for acknowledge */
2904 0 : if (buflen != 1) {
2905 0 : free(image);
2906 0 : printf("Error: cannot request exlusive access to submaster\n");
2907 0 : return MSCB_TIMEOUT;
2908 : }
2909 :
2910 0 : if (flag == 1)
2911 0 : printf("Send upgrade command to remote node\n");
2912 :
2913 : /* send upgrade command */
2914 0 : buf[0] = MCMD_ADDR_NODE16;
2915 0 : buf[1] = (unsigned char) (adr >> 8);
2916 0 : buf[2] = (unsigned char) (adr & 0xFF);
2917 0 : buf[3] = crc8(buf, 3);
2918 0 : buf[4] = MCMD_UPGRADE;
2919 0 : buf[5] = crc8(buf + 4, 1);
2920 0 : buflen = sizeof(buf);
2921 0 : mscb_exchg(fd, buf, (int *) &buflen, 6, RS485_FLAG_LONG_TO | RS485_FLAG_ADR_CYCLE);
2922 :
2923 : /* wait for acknowledge */
2924 0 : if (buflen != 3) {
2925 0 : free(image);
2926 0 : printf("Error: timeout receiving acknowledge from remote node\n");
2927 0 : return MSCB_TIMEOUT;
2928 : }
2929 :
2930 0 : if (flag == 1)
2931 0 : printf("Received upgrade acknowlege \"%d\" from remote node\n", buf[1]);
2932 :
2933 0 : if (buf[1] == 2) {
2934 0 : free(image);
2935 0 : return MSCB_SUBADDR;
2936 : }
2937 :
2938 0 : if (buf[1] == 3) {
2939 0 : free(image);
2940 0 : return MSCB_NOTREADY;
2941 : }
2942 :
2943 : /* let main routine enter upgrade() */
2944 0 : Sleep(500);
2945 :
2946 0 : if (flag == 1)
2947 0 : printf("Sending echo test to remote node\n");
2948 :
2949 : /* send echo command */
2950 0 : buf[0] = UCMD_ECHO;
2951 0 : buflen = sizeof(buf);
2952 0 : mscb_exchg(fd, buf, (int *) &buflen, 1, RS485_FLAG_LONG_TO);
2953 :
2954 : /* wait for ready */
2955 0 : if (buflen != 2) {
2956 0 : printf("Error: timeout receiving upgrade echo test from remote node\n");
2957 :
2958 : /* send exit upgrade command, in case node gets to upgrade routine later */
2959 0 : buf[0] = UCMD_RETURN;
2960 0 : mscb_exchg(fd, buf, NULL, 1, RS485_FLAG_NO_ACK);
2961 :
2962 0 : free(image);
2963 0 : return MSCB_TIMEOUT;
2964 : }
2965 :
2966 0 : if (flag == 1)
2967 0 : printf("Received acknowledge for upgrade command\n");
2968 :
2969 0 : if (flag == 0) {
2970 0 : printf("\n[");
2971 0 : for (i = 0; i < n_page / n_page_disp + 1; i++)
2972 0 : printf(" ");
2973 0 : printf("]\r[");
2974 : }
2975 :
2976 : /* erase pages up to 64k */
2977 0 : for (page = 0; page < 128; page++) {
2978 :
2979 : /* check if page contains data */
2980 0 : if (!page_cont[page])
2981 0 : continue;
2982 :
2983 0 : for (retry = 0; retry < mscb_max_retry; retry++) {
2984 :
2985 0 : if (flag == 1)
2986 0 : printf("Erase page 0x%04X - ", page * 512);
2987 0 : fflush(stdout);
2988 :
2989 : /* erase page */
2990 0 : buf[0] = UCMD_ERASE;
2991 0 : buf[1] = (unsigned char) page;
2992 0 : buflen = sizeof(buf);
2993 0 : mscb_exchg(fd, buf, (int *) &buflen, 2, RS485_FLAG_LONG_TO);
2994 :
2995 0 : if (buflen != 2) {
2996 0 : printf("\nError: timeout from remote node for erase page 0x%04X\n", page * 512);
2997 0 : continue;
2998 : }
2999 :
3000 0 : if (buf[1] == 0xFF) {
3001 : /* protected page, so finish */
3002 0 : if (flag == 1)
3003 0 : printf("found protected page, exit\n");
3004 : else
3005 0 : printf("] ");
3006 0 : fflush(stdout);
3007 0 : protected_page = page;
3008 0 : goto prog_pages;
3009 : }
3010 :
3011 0 : if (buf[0] != MCMD_ACK) {
3012 0 : printf("\nError: received wrong acknowledge for erase page 0x%04X\n", page * 512);
3013 0 : continue;
3014 : }
3015 :
3016 0 : if (flag == 1)
3017 0 : printf("ok\n");
3018 :
3019 0 : break;
3020 : }
3021 :
3022 : /* check retries */
3023 0 : if (retry == mscb_max_retry) {
3024 0 : printf("\nToo many retries, aborting\n");
3025 0 : goto prog_error;
3026 : break;
3027 : }
3028 :
3029 0 : if (flag == 0)
3030 0 : if (page % n_page_disp == 0)
3031 0 : printf("-");
3032 0 : fflush(stdout);
3033 : }
3034 :
3035 0 : prog_pages:
3036 :
3037 0 : if (flag == 0)
3038 0 : printf("\r[");
3039 :
3040 : /* program pages up to 64k */
3041 0 : for (page = 0; page < protected_page; page++) {
3042 :
3043 : /* check if page contains data */
3044 0 : if (!page_cont[page])
3045 0 : continue;
3046 :
3047 : /* build CRC of page */
3048 0 : for (i = crc = 0; i < 512; i++)
3049 0 : crc += image[page * 512 + i];
3050 :
3051 0 : for (retry = 0; retry < mscb_max_retry; retry++) {
3052 :
3053 0 : if (flag == 1)
3054 0 : printf("Program page 0x%04X - ", page * 512);
3055 0 : fflush(stdout);
3056 :
3057 : /* chop down page in 32 byte segments */
3058 0 : for (subpage = 0; subpage < 16; subpage++) {
3059 :
3060 0 : for (sretry = 0; sretry < mscb_max_retry; sretry++) {
3061 : /* program page */
3062 0 : buf[0] = UCMD_PROGRAM;
3063 0 : buf[1] = (unsigned char) page;
3064 0 : buf[2] = (unsigned char) subpage;
3065 :
3066 : /* extract page from image */
3067 0 : for (i = 0; i < 32; i++)
3068 0 : buf[i + 3] = image[page * 512 + subpage * 32 + i];
3069 :
3070 0 : buflen = sizeof(buf);
3071 0 : mscb_exchg(fd, buf, (int *) &buflen, 32 + 3, RS485_FLAG_LONG_TO);
3072 :
3073 : /* read acknowledge */
3074 0 : if (buflen != 2 || buf[0] != MCMD_ACK) {
3075 0 : printf("\nError: timeout from remote node for program page 0x%04X, chunk %d\n", page * 512, i);
3076 : } else
3077 : break; // successful
3078 : }
3079 :
3080 : /* check retries */
3081 0 : if (sretry == mscb_max_retry) {
3082 0 : printf("\nToo many retries, aborting\n");
3083 0 : goto prog_error;
3084 : break;
3085 : }
3086 : }
3087 :
3088 : /* test if successful completion */
3089 0 : if (buf[0] != MCMD_ACK)
3090 0 : continue;
3091 :
3092 0 : if (flag == 1)
3093 0 : printf("ok\n");
3094 :
3095 : /* verify page */
3096 0 : if (flag == 1)
3097 0 : printf("Verify page 0x%04X - ", page * 512);
3098 0 : fflush(stdout);
3099 :
3100 : /* verify page */
3101 0 : buf[0] = UCMD_VERIFY;
3102 0 : buf[1] = (unsigned char) page;
3103 0 : buflen = sizeof(buf);
3104 0 : mscb_exchg(fd, buf, (int *) &buflen, 2, RS485_FLAG_LONG_TO);
3105 :
3106 0 : if (buflen != 2) {
3107 0 : printf("\nError: timeout from remote node for verify page 0x%04X\n", page * 512);
3108 0 : goto prog_error;
3109 : }
3110 :
3111 : /* compare CRCs */
3112 0 : if (buf[1] == crc) {
3113 0 : if (flag == 1)
3114 0 : printf("ok (CRC = 0x%02X)\n", crc);
3115 0 : break;
3116 : }
3117 :
3118 0 : if (flag == 1)
3119 0 : printf("CRC error (0x%02X != 0x%02X)\n", crc, buf[1]);
3120 : }
3121 :
3122 : /* check retries */
3123 0 : if (retry == mscb_max_retry) {
3124 0 : printf("\nToo many retries, aborting\n");
3125 0 : goto prog_error;
3126 : break;
3127 : }
3128 :
3129 0 : if (flag == 0)
3130 0 : if (page % n_page_disp == 0)
3131 0 : printf("=");
3132 0 : fflush(stdout);
3133 : }
3134 :
3135 0 : printf("\n");
3136 :
3137 : /* reboot node */
3138 0 : buf[0] = UCMD_REBOOT;
3139 0 : mscb_exchg(fd, buf, NULL, 1, RS485_FLAG_NO_ACK);
3140 :
3141 0 : if (flag == 1)
3142 0 : printf("Reboot node\n");
3143 :
3144 0 : mscb_clear_info_cache();
3145 :
3146 0 : prog_error:
3147 :
3148 : /* exit exclusive mode */
3149 0 : buf[0] = MCMD_FREEZE;
3150 0 : buf[1] = 0;
3151 0 : buflen = sizeof(buf);
3152 0 : mscb_exchg(fd, buf, (int *) &buflen, 2, RS485_FLAG_CMD);
3153 :
3154 : /* wait for acknowledge */
3155 0 : if (buflen != 1)
3156 0 : printf("Error: cannot exit exlusive access at submaster\n");
3157 :
3158 0 : free(image);
3159 :
3160 0 : return MSCB_SUCCESS;
3161 : }
3162 :
3163 : /*------------------------------------------------------------------*/
3164 :
3165 0 : int mscb_upload(int fd, unsigned short node_adr, short sub_adr, const char *filename, int flags)
3166 : /********************************************************************\
3167 :
3168 : Routine: mscb_upload
3169 :
3170 : Purpose: Upload new firmware to node
3171 :
3172 :
3173 : Input:
3174 : int fd File descriptor for connection
3175 : unsigned short adr Node address
3176 : short sub_adr Subaddress of WaveDAQ crate (slot)
3177 : char *buffer Buffer with Intel HEX file
3178 : int flags MSCB_UPLOAD_DEBUG: produce detailed debugging output
3179 : MSCB_UPLOAD_VERIFY: only verify image
3180 : MSCB_UPLOAD_SUBADDR: upload using subaddress
3181 :
3182 : Function value:
3183 : MSCB_SUCCESS Successful completion
3184 : MSCB_TIMEOUT Timeout receiving acknowledge
3185 : MSCB_CRC_ERROR CRC error
3186 : MSCB_INVAL_PARAM Parameter "size" has invalid value
3187 : MSCB_MUTEX Cannot obtain mutex for mscb
3188 : MSCB_FORMAT_ERROR Error in HEX file format
3189 : MSCB_NOT_FOUND File 'filename' not found
3190 :
3191 : \********************************************************************/
3192 : {
3193 0 : unsigned char *image, buf[1500], *header = NULL, data_crc;
3194 : unsigned int flash_size, header_size, mem_adr, size, buflen, percent;
3195 : int i, j, retry, status;
3196 : MSCB_INFO info;
3197 : XIL_FW_HEADER fw_header;
3198 : XIL_SW_HEADER *sw_header;
3199 :
3200 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
3201 0 : return MSCB_INVAL_PARAM;
3202 :
3203 : #ifdef HAVE_MRPC
3204 : if (mrpc_connected(fd))
3205 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_UPLOAD, mscb_fd[fd - 1].remote_fd, node_adr, filename, flags);
3206 : #endif
3207 :
3208 0 : if (flags & MSCB_UPLOAD_SUBADDR) {
3209 0 : status = mscb_interprete_file(filename, &image, &flash_size, &header, &header_size, (unsigned char *) &fw_header);
3210 0 : if (status != MSCB_SUCCESS) {
3211 0 : if (header)
3212 0 : free(header);
3213 0 : return status;
3214 : }
3215 0 : memset(&info, 0, sizeof(info));
3216 0 : info.buf_size = 256;
3217 :
3218 : } else {
3219 : /* check if node alive */
3220 0 : status = mscb_ping(fd, node_adr, 0, 1);
3221 0 : if (status != MSCB_SUCCESS) {
3222 0 : printf("Error: cannot ping node #%d\n", node_adr);
3223 0 : return status;
3224 : }
3225 :
3226 0 : status = mscb_interprete_file(filename, &image, &flash_size, &header, &header_size, (unsigned char *) &fw_header);
3227 0 : if (status != MSCB_SUCCESS)
3228 0 : return status;
3229 :
3230 : /* check if node supports memory transfer */
3231 0 : mscb_info(fd, node_adr, &info);
3232 :
3233 : /* if not, go to legacy upload */
3234 0 : if (info.buf_size == 0) {
3235 0 : if (header)
3236 0 : free(header);
3237 0 : return mscb_legacy_upload(fd, node_adr, image, flash_size, flags);
3238 : }
3239 : }
3240 :
3241 0 : if ((strstr(filename, ".bit") || strstr(filename, ".BIT"))) {
3242 : // upload firmware header to FPGA
3243 0 : mem_adr = (XIL_FW_HEADER_ADDR | MSCB_BASE_FLASH) & 0xFFFF0000;
3244 0 : size = 1;
3245 :
3246 : // force flash page erase by writing to start of page
3247 0 : buf[0] = MCMD_ADDR_NODE16;
3248 0 : buf[1] = (unsigned char) (node_adr >> 8);
3249 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3250 0 : buf[3] = crc8(buf, 3);
3251 :
3252 0 : buf[4] = MCMD_WRITE_MEM;
3253 0 : buf[5] = 0x80 | ((size + 5) >> 8);
3254 0 : buf[6] = (size + 5) & 0xFF;
3255 0 : buf[7] = (unsigned char) sub_adr;
3256 0 : buf[8] = (mem_adr >> 24) & 0xFF;
3257 0 : buf[9] = (mem_adr >> 16) & 0xFF;
3258 0 : buf[10] = (mem_adr >> 8) & 0xFF;
3259 0 : buf[11] = (mem_adr >> 0) & 0xFF;
3260 0 : buf[12 + size] = crc8(buf + 4, 8 + size);
3261 0 : data_crc = crc8(buf + 12, size);
3262 0 : buflen = size + 13;
3263 0 : mscb_exchg(fd, buf, (int *) &buflen, buflen, RS485_FLAG_LONG_TO | RS485_FLAG_ADR_CYCLE);
3264 0 : if (buflen == 3 && buf[1] == 2) {
3265 0 : printf("\nError: No board present in WD slot %d\n", sub_adr);
3266 0 : return 2;
3267 0 : } else if (buflen != 2 || buf[1] != data_crc) {
3268 0 : printf("\nError: Transmission error (CRC %02X vs %02X), re-sending data\n", data_crc, buf[1]);
3269 : }
3270 :
3271 : // write header
3272 0 : mem_adr = XIL_FW_HEADER_ADDR | MSCB_BASE_FLASH;
3273 0 : size = sizeof(fw_header) + header_size;
3274 :
3275 0 : buf[0] = MCMD_ADDR_NODE16;
3276 0 : buf[1] = (unsigned char) (node_adr >> 8);
3277 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3278 0 : buf[3] = crc8(buf, 3);
3279 :
3280 0 : buf[4] = MCMD_WRITE_MEM;
3281 0 : buf[5] = 0x80 | ((size + 5) >> 8);
3282 0 : buf[6] = (size + 5) & 0xFF;
3283 0 : buf[7] = (unsigned char) sub_adr;
3284 0 : buf[8] = (mem_adr >> 24) & 0xFF;
3285 0 : buf[9] = (mem_adr >> 16) & 0xFF;
3286 0 : buf[10] = (mem_adr >> 8) & 0xFF;
3287 0 : buf[11] = (mem_adr >> 0) & 0xFF;
3288 0 : memcpy(buf + 12, &fw_header, sizeof(fw_header));
3289 0 : memcpy(buf + 12 + sizeof(fw_header), header, header_size);
3290 0 : buf[12 + size] = crc8(buf + 4, 8 + size);
3291 :
3292 0 : data_crc = crc8(buf + 12, size);
3293 0 : buflen = size + 13;
3294 :
3295 0 : mscb_exchg(fd, buf, (int *) &buflen, buflen, RS485_FLAG_LONG_TO | RS485_FLAG_ADR_CYCLE);
3296 :
3297 : // read acknowledge
3298 0 : if (buflen != 2 || buf[1] != data_crc) {
3299 0 : printf("\nError: Transmission error (CRC %02X vs %02X), re-sending data\n", data_crc, buf[1]);
3300 : }
3301 : }
3302 :
3303 0 : if ((strstr(filename, ".srec") || strstr(filename, ".SREC"))) {
3304 : // upload firmware header to FPGA
3305 0 : sw_header = (XIL_SW_HEADER *) (&fw_header);
3306 0 : mem_adr = (XIL_SW_HEADER_ADDR | MSCB_BASE_FLASH) & 0xFFFF0000;
3307 0 : size = 1;
3308 :
3309 : // force flash page erase by writing to start of page
3310 0 : buf[0] = MCMD_ADDR_NODE16;
3311 0 : buf[1] = (unsigned char) (node_adr >> 8);
3312 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3313 0 : buf[3] = crc8(buf, 3);
3314 :
3315 0 : buf[4] = MCMD_WRITE_MEM;
3316 0 : buf[5] = 0x80 | ((size + 5) >> 8);
3317 0 : buf[6] = (size + 5) & 0xFF;
3318 0 : buf[7] = (unsigned char) sub_adr;
3319 0 : buf[8] = (mem_adr >> 24) & 0xFF;
3320 0 : buf[9] = (mem_adr >> 16) & 0xFF;
3321 0 : buf[10] = (mem_adr >> 8) & 0xFF;
3322 0 : buf[11] = (mem_adr >> 0) & 0xFF;
3323 0 : buf[12 + size] = crc8(buf + 4, 8 + size);
3324 0 : data_crc = crc8(buf + 12, size);
3325 0 : buflen = size + 13;
3326 0 : mscb_exchg(fd, buf, (int *) &buflen, buflen, RS485_FLAG_LONG_TO | RS485_FLAG_ADR_CYCLE);
3327 0 : if (buflen != 2 || buf[1] != data_crc) {
3328 0 : printf("\nError: Transmission error (CRC %02X vs %02X), re-sending data\n", data_crc, buf[1]);
3329 : }
3330 :
3331 : // write header
3332 0 : mem_adr = XIL_SW_HEADER_ADDR | MSCB_BASE_FLASH;
3333 0 : size = sizeof(XIL_SW_HEADER);
3334 :
3335 0 : buf[0] = MCMD_ADDR_NODE16;
3336 0 : buf[1] = (unsigned char) (node_adr >> 8);
3337 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3338 0 : buf[3] = crc8(buf, 3);
3339 :
3340 0 : buf[4] = MCMD_WRITE_MEM;
3341 0 : buf[5] = 0x80 | ((size + 5) >> 8);
3342 0 : buf[6] = (size + 5) & 0xFF;
3343 0 : buf[7] = (unsigned char) sub_adr;
3344 0 : buf[8] = (mem_adr >> 24) & 0xFF;
3345 0 : buf[9] = (mem_adr >> 16) & 0xFF;
3346 0 : buf[10] = (mem_adr >> 8) & 0xFF;
3347 0 : buf[11] = (mem_adr >> 0) & 0xFF;
3348 0 : memcpy(buf + 12, sw_header, sizeof(XIL_SW_HEADER));
3349 0 : buf[12 + size] = crc8(buf + 4, 8 + size);
3350 :
3351 0 : data_crc = crc8(buf + 12, size);
3352 0 : buflen = size + 13;
3353 :
3354 0 : mscb_exchg(fd, buf, (int *) &buflen, buflen, RS485_FLAG_LONG_TO | RS485_FLAG_ADR_CYCLE);
3355 :
3356 : // read acknowledge
3357 0 : if (buflen != 2 || buf[1] != data_crc) {
3358 0 : printf("\nError: Transmission error (CRC %02X vs %02X), re-sending data\n", data_crc, buf[1]);
3359 : }
3360 : }
3361 :
3362 0 : if ((flags & MSCB_UPLOAD_DEBUG) == 0)
3363 0 : printf(" [ ]\r");
3364 :
3365 0 : for (i = 0; i < (int) (flash_size / info.buf_size + 1); i++) {
3366 :
3367 0 : for (retry = 0; retry < mscb_max_retry; retry++) {
3368 0 : size = info.buf_size;
3369 0 : if (i * info.buf_size + size > flash_size) // last chunk
3370 0 : size = flash_size - i * info.buf_size;
3371 0 : percent = i * 100 / (flash_size / info.buf_size);
3372 :
3373 0 : if (flags & MSCB_UPLOAD_DEBUG)
3374 0 : printf("Write page 0x%08X - 0x%08X\n", i * info.buf_size, i * info.buf_size + size - 1);
3375 : else {
3376 0 : printf("\r%3d%% [", percent);
3377 0 : for (j = 0; j < (int) percent / 2; j++)
3378 0 : printf("=");
3379 0 : fflush(stdout);
3380 : }
3381 :
3382 0 : if (info.bootBank != 0) // check if it's an SCS3000
3383 0 : mem_adr = (i * info.buf_size) | MSCB_BASE_CODE;
3384 : else {
3385 0 : if (strstr(filename, ".bit") || strstr(filename, ".BIT"))
3386 0 : mem_adr = (XIL_FW_ADDR + (i * info.buf_size)) | MSCB_BASE_FLASH;
3387 0 : else if (strstr(filename, ".srec") || strstr(filename, ".SREC"))
3388 0 : mem_adr = (XIL_SW_ADDR + (i * info.buf_size)) | MSCB_BASE_FLASH;
3389 0 : else if (strstr(filename, ".hex") || strstr(filename, ".HEX"))
3390 0 : mem_adr = (i * info.buf_size) | MSCB_BASE_FLASH;
3391 : }
3392 :
3393 : // address node
3394 0 : buf[0] = MCMD_ADDR_NODE16;
3395 0 : buf[1] = (unsigned char) (node_adr >> 8);
3396 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3397 0 : buf[3] = crc8(buf, 3);
3398 :
3399 0 : buf[4] = MCMD_WRITE_MEM;
3400 0 : buf[5] = 0x80 | ((size + 5) >> 8);
3401 0 : buf[6] = (size + 5) & 0xFF;
3402 0 : buf[7] = (unsigned char) sub_adr;
3403 0 : buf[8] = (mem_adr >> 24) & 0xFF;
3404 0 : buf[9] = (mem_adr >> 16) & 0xFF;
3405 0 : buf[10] = (mem_adr >> 8) & 0xFF;
3406 0 : buf[11] = (mem_adr >> 0) & 0xFF;
3407 0 : memcpy(buf + 12, image + i * info.buf_size, size);
3408 0 : buf[12 + size] = crc8(buf + 4, 8 + size);
3409 :
3410 0 : data_crc = crc8(buf + 12, size);
3411 0 : buflen = size + 13;
3412 :
3413 0 : mscb_exchg(fd, buf, (int *) &buflen, buflen, RS485_FLAG_LONG_TO | RS485_FLAG_ADR_CYCLE);
3414 :
3415 : /* read acknowledge */
3416 0 : if (buflen != 2 || buf[1] != data_crc) {
3417 0 : printf("\nError: Transmission error (CRC %02X vs %02X), re-sending data\n", data_crc, buf[1]);
3418 : } else
3419 : break; // successful
3420 : }
3421 :
3422 : /* check retries */
3423 0 : if (retry == mscb_max_retry) {
3424 0 : printf("\nToo many retries, aborting\n");
3425 0 : free(image);
3426 0 : return MSCB_TIMEOUT;
3427 : }
3428 :
3429 0 : if (kbhit()) {
3430 : int c;
3431 0 : while (kbhit())
3432 0 : getch();
3433 0 : printf("Abort? (y/[n]) ");
3434 0 : c = getch();
3435 0 : if (c == 'y')
3436 0 : break;
3437 : }
3438 : }
3439 :
3440 0 : if ((flags & MSCB_UPLOAD_DEBUG) == 0)
3441 0 : printf("\n");
3442 :
3443 : // indicate end of upload
3444 0 : mscb_ping(fd, node_adr, 0, 1);
3445 :
3446 : // reboot node after software upload
3447 0 : if ((flags & MSCB_UPLOAD_SUBADDR) == 0 && header == NULL) {
3448 0 : printf("\nReboot node\n");
3449 0 : mscb_reboot(fd, node_adr, -1, -1);
3450 : }
3451 :
3452 0 : if (header)
3453 0 : free(header);
3454 0 : free(image);
3455 0 : return MSCB_SUCCESS;
3456 : }
3457 :
3458 : /*------------------------------------------------------------------*/
3459 :
3460 0 : int mscb_download(int fd, unsigned short node_adr, short sub_adr, const char *filename)
3461 : /********************************************************************\
3462 :
3463 : Routine: mscb_download
3464 :
3465 : Purpose: Download firmware from node to file
3466 :
3467 : Input:
3468 : int fd File descriptor for connection
3469 : unsigned short adr Node address
3470 : short sub_adr Subaddress of WaveDAQ crate (slot)
3471 : char *filename Filename
3472 :
3473 : Function value:
3474 : MSCB_SUCCESS Successful completion
3475 : MSCB_TIMEOUT Timeout receiving acknowledge
3476 : MSCB_CRC_ERROR CRC error
3477 : MSCB_INVAL_PARAM Parameter "size" has invalid value
3478 : MSCB_MUTEX Cannot obtain mutex for mscb
3479 : MSCB_NOT_FOUND File 'filename' exists alread
3480 :
3481 : \********************************************************************/
3482 : {
3483 : unsigned char buf[1500], *ph;
3484 : unsigned int flash_size, header_size, size, mem_adr, buflen, percent;
3485 : int i, j, fh;
3486 : MSCB_INFO info;
3487 : XIL_FW_HEADER *fw_header;
3488 : XIL_SW_HEADER *sw_header;
3489 :
3490 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
3491 0 : return MSCB_INVAL_PARAM;
3492 :
3493 0 : fh = open(filename, O_RDONLY, 0644);
3494 0 : close(fh);
3495 0 : if (fh > 0) {
3496 0 : return MSCB_NOT_FOUND;
3497 : }
3498 0 : fh = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0644);
3499 :
3500 0 : mscb_info(fd, node_adr, &info);
3501 :
3502 : // retrieve pre-header
3503 0 : if (strstr(filename, ".bit") || strstr(filename, ".BIT")) { //------------------
3504 0 : mem_adr = XIL_FW_HEADER_ADDR | MSCB_BASE_FLASH;
3505 :
3506 : // address node
3507 0 : buf[0] = MCMD_ADDR_NODE16;
3508 0 : buf[1] = (unsigned char) (node_adr >> 8);
3509 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3510 0 : buf[3] = crc8(buf, 3);
3511 :
3512 0 : buf[4] = MCMD_READ_MEM;
3513 0 : buf[5] = 0x07; // 7 parameters to follow
3514 0 : buf[6] = sizeof(XIL_FW_HEADER) >> 8;
3515 0 : buf[7] = sizeof(XIL_FW_HEADER) & 0xFF;
3516 0 : buf[8] = (unsigned char) sub_adr;
3517 0 : buf[9] = (mem_adr >> 24) & 0xFF;
3518 0 : buf[10] = (mem_adr >> 16) & 0xFF;
3519 0 : buf[11] = (mem_adr >> 8) & 0xFF;
3520 0 : buf[12] = (mem_adr >> 0) & 0xFF;
3521 0 : buf[13] = crc8(buf + 4, 9);
3522 :
3523 0 : buflen = sizeof(XIL_FW_HEADER) + 4;
3524 0 : mscb_exchg(fd, buf, (int *) &buflen, 14, RS485_FLAG_ADR_CYCLE);
3525 0 : fw_header = (XIL_FW_HEADER *) (buf + 3);
3526 0 : header_size = fw_header->head_len;
3527 0 : DWORD_SWAP(&header_size);
3528 0 : flash_size = fw_header->data_len;
3529 0 : DWORD_SWAP(&flash_size);
3530 :
3531 : // retrieve header
3532 0 : mem_adr = XIL_FW_HEADER_ADDR | MSCB_BASE_FLASH;
3533 :
3534 : // address node
3535 0 : buf[0] = MCMD_ADDR_NODE16;
3536 0 : buf[1] = (unsigned char) (node_adr >> 8);
3537 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3538 0 : buf[3] = crc8(buf, 3);
3539 :
3540 0 : buf[4] = MCMD_READ_MEM;
3541 0 : buf[5] = 0x07; // 7 parameters to follow
3542 0 : buf[6] = (header_size + sizeof(XIL_FW_HEADER)) >> 8;
3543 0 : buf[7] = (header_size + sizeof(XIL_FW_HEADER)) & 0xFF;
3544 0 : buf[8] = (unsigned char) sub_adr;
3545 0 : buf[9] = (mem_adr >> 24) & 0xFF;
3546 0 : buf[10] = (mem_adr >> 16) & 0xFF;
3547 0 : buf[11] = (mem_adr >> 8) & 0xFF;
3548 0 : buf[12] = (mem_adr >> 0) & 0xFF;
3549 0 : buf[13] = crc8(buf + 4, 9);
3550 :
3551 0 : buflen = header_size + sizeof(XIL_FW_HEADER) + 4;
3552 0 : mscb_exchg(fd, buf, (int *) &buflen, 14, RS485_FLAG_ADR_CYCLE);
3553 0 : ph = buf + 3 + sizeof(XIL_FW_HEADER);
3554 :
3555 0 : i = write(fh, ph, header_size);
3556 0 : if (i < (int) header_size) {
3557 0 : close(fh);
3558 0 : return MSCB_NO_MEM;
3559 : }
3560 :
3561 0 : printf(" [ ]\r");
3562 :
3563 0 : for (i = 0; i < (int) (flash_size / info.buf_size + 1); i++) {
3564 :
3565 0 : size = info.buf_size;
3566 0 : if (i * info.buf_size + size > flash_size) // last chunk
3567 0 : size = flash_size - i * info.buf_size;
3568 0 : percent = i * 100 / (flash_size / info.buf_size);
3569 :
3570 0 : printf("\r%3d%% [", percent);
3571 0 : for (j = 0; j < (int) percent / 2; j++)
3572 0 : printf("=");
3573 0 : fflush(stdout);
3574 :
3575 0 : if (info.bootBank != 0) // check if it's an SCS3000
3576 0 : mem_adr = (i * info.buf_size) | MSCB_BASE_CODE;
3577 : else
3578 0 : mem_adr = (i * info.buf_size) | MSCB_BASE_FLASH;
3579 :
3580 : // address node
3581 0 : buf[0] = MCMD_ADDR_NODE16;
3582 0 : buf[1] = (unsigned char) (node_adr >> 8);
3583 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3584 0 : buf[3] = crc8(buf, 3);
3585 :
3586 0 : buf[4] = MCMD_READ_MEM;
3587 0 : buf[5] = 0x07; // 7 parameters to follow
3588 0 : buf[6] = size >> 8;
3589 0 : buf[7] = size & 0xFF;
3590 0 : buf[8] = (unsigned char) sub_adr;
3591 0 : buf[9] = (mem_adr >> 24) & 0xFF;
3592 0 : buf[10] = (mem_adr >> 16) & 0xFF;
3593 0 : buf[11] = (mem_adr >> 8) & 0xFF;
3594 0 : buf[12] = (mem_adr >> 0) & 0xFF;
3595 0 : buf[13] = crc8(buf + 4, 9);
3596 :
3597 0 : mem_adr = i * info.buf_size;
3598 :
3599 0 : buflen = size + 4;
3600 :
3601 : // read data
3602 0 : mscb_exchg(fd, buf, (int *) &buflen, 14, RS485_FLAG_ADR_CYCLE);
3603 :
3604 0 : if (buflen != size + 4 || buf[size + 3] != crc8(buf, size + 3)) {
3605 0 : printf("\nError: Transmission error (CRC %02X vs %02X)\n", buf[size + 3], crc8(buf, size + 3));
3606 : } else {
3607 0 : j = write(fh, buf + 3, size);
3608 0 : if (j < (int) size) {
3609 0 : close(fh);
3610 0 : return MSCB_NO_MEM;
3611 : }
3612 :
3613 : }
3614 :
3615 0 : if (kbhit()) {
3616 : int c;
3617 0 : while (kbhit())
3618 0 : getch();
3619 0 : printf("Abort? (y/[n]) ");
3620 0 : c = getch();
3621 0 : if (c == 'y')
3622 0 : break;
3623 : }
3624 : }
3625 :
3626 0 : } else if (strstr(filename, ".srec") || strstr(filename, ".SREC")) { //------------------
3627 :
3628 0 : mem_adr = XIL_SW_HEADER_ADDR | MSCB_BASE_FLASH;
3629 :
3630 : // address node
3631 0 : buf[0] = MCMD_ADDR_NODE16;
3632 0 : buf[1] = (unsigned char) (node_adr >> 8);
3633 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3634 0 : buf[3] = crc8(buf, 3);
3635 :
3636 0 : buf[4] = MCMD_READ_MEM;
3637 0 : buf[5] = 0x07; // 7 parameters to follow
3638 0 : buf[6] = sizeof(XIL_SW_HEADER) >> 8;
3639 0 : buf[7] = sizeof(XIL_SW_HEADER) & 0xFF;
3640 0 : buf[8] = (unsigned char) sub_adr;
3641 0 : buf[9] = (mem_adr >> 24) & 0xFF;
3642 0 : buf[10] = (mem_adr >> 16) & 0xFF;
3643 0 : buf[11] = (mem_adr >> 8) & 0xFF;
3644 0 : buf[12] = (mem_adr >> 0) & 0xFF;
3645 0 : buf[13] = crc8(buf + 4, 9);
3646 :
3647 0 : buflen = sizeof(XIL_SW_HEADER) + 4;
3648 0 : mscb_exchg(fd, buf, (int *) &buflen, 14, RS485_FLAG_ADR_CYCLE);
3649 0 : sw_header = (XIL_SW_HEADER *) (buf + 3);
3650 0 : header_size = sw_header->head_len;
3651 0 : DWORD_SWAP(&header_size);
3652 0 : flash_size = sw_header->data_len;
3653 0 : DWORD_SWAP(&flash_size);
3654 :
3655 0 : printf(" [ ]\r");
3656 :
3657 0 : for (i = 0; i < (int) (flash_size / info.buf_size + 1); i++) {
3658 :
3659 0 : size = info.buf_size;
3660 0 : if (i * info.buf_size + size > flash_size) // last chunk
3661 0 : size = flash_size - i * info.buf_size;
3662 0 : percent = i * 100 / (flash_size / info.buf_size);
3663 :
3664 0 : printf("\r%3d%% [", percent);
3665 0 : for (j = 0; j < (int) percent / 2; j++)
3666 0 : printf("=");
3667 0 : fflush(stdout);
3668 :
3669 0 : mem_adr = (XIL_SW_ADDR + (i * info.buf_size)) | MSCB_BASE_FLASH;
3670 :
3671 : // address node
3672 0 : buf[0] = MCMD_ADDR_NODE16;
3673 0 : buf[1] = (unsigned char) (node_adr >> 8);
3674 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3675 0 : buf[3] = crc8(buf, 3);
3676 :
3677 0 : buf[4] = MCMD_READ_MEM;
3678 0 : buf[5] = 0x07; // 7 parameters to follow
3679 0 : buf[6] = size >> 8;
3680 0 : buf[7] = size & 0xFF;
3681 0 : buf[8] = (unsigned char) sub_adr;
3682 0 : buf[9] = (mem_adr >> 24) & 0xFF;
3683 0 : buf[10] = (mem_adr >> 16) & 0xFF;
3684 0 : buf[11] = (mem_adr >> 8) & 0xFF;
3685 0 : buf[12] = (mem_adr >> 0) & 0xFF;
3686 0 : buf[13] = crc8(buf + 4, 9);
3687 :
3688 0 : mem_adr = i * info.buf_size;
3689 :
3690 0 : buflen = size + 4;
3691 :
3692 : // read data
3693 0 : mscb_exchg(fd, buf, (int *) &buflen, 14, RS485_FLAG_ADR_CYCLE);
3694 :
3695 0 : if (buflen != size + 4 || buf[size + 3] != crc8(buf, size + 3)) {
3696 0 : printf("\nError: Transmission error (CRC %02X vs %02X)\n", buf[size + 3], crc8(buf, size + 3));
3697 : } else {
3698 0 : j = write(fh, buf + 3, size);
3699 0 : if (j < (int) size) {
3700 0 : close(fh);
3701 0 : return MSCB_NO_MEM;
3702 : }
3703 :
3704 : }
3705 :
3706 0 : if (kbhit()) {
3707 : int c;
3708 0 : while (kbhit())
3709 0 : getch();
3710 0 : printf("Abort? (y/[n]) ");
3711 0 : c = getch();
3712 0 : if (c == 'y')
3713 0 : break;
3714 : }
3715 : }
3716 :
3717 0 : } else
3718 0 : printf("File type not supported\n");
3719 :
3720 0 : printf("\n");
3721 0 : close(fh);
3722 0 : return MSCB_SUCCESS;
3723 : }
3724 :
3725 : /*------------------------------------------------------------------*/
3726 :
3727 0 : int mscb_verify(int fd, unsigned short node_adr, short sub_adr, const char *filename, int flags)
3728 : /********************************************************************\
3729 :
3730 : Routine: mscb_verify
3731 :
3732 : Purpose: Verify firmware on node
3733 :
3734 : Input:
3735 : int fd File descriptor for connection
3736 : unsigned short adr Node address
3737 : short sub_adr Subaddress of WaveDAQ crate (slot)
3738 : char *buffer Buffer with Intel HEX file
3739 : int flags MSCB_UPLOAD_DEBUG: produce detailed debugging output
3740 : MSCB_UPLOAD_VERIFY: only verify image
3741 : MSCB_UPLOAD_SUBADDR: upload using subaddress
3742 :
3743 : Function value:
3744 : MSCB_SUCCESS Successful completion
3745 : MSCB_TIMEOUT Timeout receiving acknowledge
3746 : MSCB_CRC_ERROR CRC error
3747 : MSCB_INVAL_PARAM Parameter "size" has invalid value
3748 : MSCB_MUTEX Cannot obtain mutex for mscb
3749 : MSCB_FORMAT_ERROR Error in HEX file format
3750 : MSCB_NOT_FOUND File 'filename' not found
3751 :
3752 : \********************************************************************/
3753 : {
3754 0 : unsigned char *image, buf[1500], *header = NULL, *ph, *pf;
3755 : unsigned int flash_size, header_size, mem_base, mem_adr, size, preheader_size, buflen, last, percent;
3756 0 : int i, j, status, col, row, n_err = 0;
3757 : MSCB_INFO info;
3758 : XIL_FW_HEADER fw_header;
3759 :
3760 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
3761 0 : return MSCB_INVAL_PARAM;
3762 :
3763 0 : if (flags & MSCB_UPLOAD_SUBADDR) {
3764 0 : status = mscb_interprete_file(filename, &image, &flash_size, &header, &header_size, (unsigned char *) &fw_header);
3765 0 : if (status != MSCB_SUCCESS) {
3766 0 : if (header)
3767 0 : free(header);
3768 0 : return status;
3769 : }
3770 0 : memset(&info, 0, sizeof(info));
3771 0 : info.buf_size = 256;
3772 :
3773 : } else {
3774 : /* check if node alive */
3775 0 : status = mscb_ping(fd, node_adr, 0, 1);
3776 0 : if (status != MSCB_SUCCESS) {
3777 0 : printf("Error: cannot ping node #%d\n", node_adr);
3778 0 : return status;
3779 : }
3780 :
3781 0 : status = mscb_interprete_file(filename, &image, &flash_size, &header, &header_size, (unsigned char *) &fw_header);
3782 0 : if (status != MSCB_SUCCESS) {
3783 0 : if (header)
3784 0 : free(header);
3785 0 : return status;
3786 : }
3787 :
3788 : /* check if node supports memory transfer */
3789 0 : mscb_info(fd, node_adr, &info);
3790 :
3791 : /* if not, go to legacy upload */
3792 0 : if (info.buf_size == 0) {
3793 0 : if (header)
3794 0 : free(header);
3795 0 : return mscb_legacy_verify(fd, node_adr, image);
3796 : }
3797 : }
3798 :
3799 : // check header
3800 0 : if (strstr(filename, ".bit") || strstr(filename, ".BIT")) {
3801 0 : mem_base = XIL_FW_HEADER_ADDR | MSCB_BASE_FLASH;
3802 0 : size = header_size + sizeof(XIL_FW_HEADER);
3803 0 : preheader_size = sizeof(XIL_FW_HEADER);
3804 0 : } else if (strstr(filename, ".srec") || strstr(filename, ".SREC")) {
3805 0 : mem_base = XIL_SW_HEADER_ADDR | MSCB_BASE_FLASH;
3806 0 : size = sizeof(XIL_SW_HEADER);
3807 0 : preheader_size = sizeof(XIL_SW_HEADER);
3808 : } else {
3809 0 : mem_base = 0;
3810 0 : size = preheader_size = 0;
3811 : }
3812 :
3813 0 : if (size) {
3814 : // address node
3815 0 : buf[0] = MCMD_ADDR_NODE16;
3816 0 : buf[1] = (unsigned char) (node_adr >> 8);
3817 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3818 0 : buf[3] = crc8(buf, 3);
3819 :
3820 0 : buf[4] = MCMD_READ_MEM;
3821 0 : buf[5] = 0x07; // 7 parameters to follow
3822 0 : buf[6] = size >> 8;
3823 0 : buf[7] = size & 0xFF;
3824 0 : buf[8] = (unsigned char) sub_adr;
3825 0 : buf[9] = (mem_base >> 24) & 0xFF;
3826 0 : buf[10] = (mem_base >> 16) & 0xFF;
3827 0 : buf[11] = (mem_base >> 8) & 0xFF;
3828 0 : buf[12] = (mem_base >> 0) & 0xFF;
3829 0 : buf[13] = crc8(buf + 4, 9);
3830 :
3831 0 : buflen = size + 4;
3832 0 : mscb_exchg(fd, buf, (int *) &buflen, 14, RS485_FLAG_ADR_CYCLE);
3833 0 : ph = (unsigned char *) buf + 3;
3834 0 : pf = (unsigned char *) &fw_header;
3835 :
3836 0 : if (preheader_size) {
3837 0 : if (memcmp(pf, ph, preheader_size) != 0) {
3838 0 : printf("\nPre-Header mismatch. Flash contents:\n");
3839 0 : for (i = 0; i < (int) preheader_size; i++) {
3840 0 : if (i % 16 == 0)
3841 0 : printf("\n%08X: ", i);
3842 :
3843 0 : if (ph[i] != pf[i])
3844 0 : printf("%02X<", ph[i]);
3845 : else
3846 0 : printf("%02X ", ph[i]);
3847 : }
3848 0 : printf("\n\nFile contents:\n");
3849 0 : for (i = 0; i < (int) preheader_size; i++) {
3850 0 : if (i % 16 == 0)
3851 0 : printf("\n%08X: ", i);
3852 :
3853 0 : if (ph[i] != pf[i])
3854 0 : printf("%02X<", pf[i]);
3855 : else
3856 0 : printf("%02X ", pf[i]);
3857 : }
3858 0 : printf("\n");
3859 : }
3860 : }
3861 :
3862 0 : if (strstr(filename, ".bit") || strstr(filename, ".BIT")) {
3863 0 : ph += sizeof(XIL_FW_HEADER);
3864 0 : pf = (unsigned char *) header;
3865 0 : if (memcmp(pf, ph, header_size) != 0) {
3866 0 : printf("\nHeader mismatch. Flash contents:\n");
3867 0 : for (i = 0; i < (int) header_size; i++) {
3868 0 : if (i % 16 == 0)
3869 0 : printf("\n%08X: ", i);
3870 :
3871 0 : if (ph[i] != pf[i]) {
3872 0 : printf("%02X<", ph[i]);
3873 0 : n_err++;
3874 : } else
3875 0 : printf("%02X ", ph[i]);
3876 : }
3877 0 : printf("\n\nFile contents:\n");
3878 0 : for (i = 0; i < (int) header_size; i++) {
3879 0 : if (i % 16 == 0)
3880 0 : printf("\n%08X: ", i);
3881 :
3882 0 : if (ph[i] != pf[i]) {
3883 0 : printf("%02X<", pf[i]);
3884 0 : n_err++;
3885 : } else
3886 0 : printf("%02X ", pf[i]);
3887 : }
3888 0 : printf("\n");
3889 : }
3890 : }
3891 : }
3892 :
3893 0 : if ((flags & MSCB_UPLOAD_DEBUG) == 0)
3894 0 : printf(" [ ]\r");
3895 :
3896 : // check file
3897 0 : if (strstr(filename, ".bit") || strstr(filename, ".BIT")) {
3898 0 : mem_base = MSCB_BASE_FLASH;
3899 0 : } else if (strstr(filename, ".srec") || strstr(filename, ".SREC")) {
3900 0 : mem_base = XIL_SW_ADDR | MSCB_BASE_FLASH;
3901 : } else {
3902 0 : if (info.bootBank != 0) // check if it's an SCS3000
3903 0 : mem_base = MSCB_BASE_CODE;
3904 : else
3905 0 : mem_base = MSCB_BASE_FLASH;
3906 : }
3907 :
3908 0 : for (i = 0; i < (int) (flash_size / info.buf_size + 1); i++) {
3909 :
3910 0 : size = info.buf_size;
3911 0 : if (i * info.buf_size + size > flash_size) // last chunk
3912 0 : size = flash_size - i * info.buf_size;
3913 0 : percent = i * 100 / (flash_size / info.buf_size);
3914 :
3915 0 : printf("\r%3d%% [", percent);
3916 0 : for (j = 0; j < (int) percent / 2; j++)
3917 0 : printf("=");
3918 0 : fflush(stdout);
3919 :
3920 0 : mem_adr = (i * info.buf_size);
3921 :
3922 : // address node
3923 0 : buf[0] = MCMD_ADDR_NODE16;
3924 0 : buf[1] = (unsigned char) (node_adr >> 8);
3925 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
3926 0 : buf[3] = crc8(buf, 3);
3927 :
3928 0 : buf[4] = MCMD_READ_MEM;
3929 0 : buf[5] = 0x07; // 7 parameters to follow
3930 0 : buf[6] = size >> 8;
3931 0 : buf[7] = size & 0xFF;
3932 0 : buf[8] = (unsigned char) sub_adr;
3933 0 : buf[9] = ((mem_base + mem_adr) >> 24) & 0xFF;
3934 0 : buf[10] = ((mem_base + mem_adr) >> 16) & 0xFF;
3935 0 : buf[11] = ((mem_base + mem_adr) >> 8) & 0xFF;
3936 0 : buf[12] = ((mem_base + mem_adr) >> 0) & 0xFF;
3937 0 : buf[13] = crc8(buf + 4, 9);
3938 :
3939 0 : mem_adr = i * info.buf_size;
3940 0 : last = i * info.buf_size + size;
3941 :
3942 0 : buflen = size + 4;
3943 :
3944 0 : mscb_exchg(fd, buf, (int *) &buflen, 14, RS485_FLAG_ADR_CYCLE);
3945 :
3946 : /* read data */
3947 0 : if (buflen != size + 4 || buf[size + 3] != crc8(buf, size + 3)) {
3948 0 : printf("\nError: Transmission error (CRC %02X vs %02X)\n", buf[size + 3], crc8(buf, size + 3));
3949 : } else {
3950 0 : for (j = 0; j < (int) size; j++)
3951 0 : if (buf[3 + j] != image[i * info.buf_size + j])
3952 0 : break;
3953 0 : if (j < (int) size) {
3954 0 : printf("\nVerify mismatch. Flash contents:\n");
3955 :
3956 0 : for (row = 0; row < (int) ((size - 1) / 16 + 1); row++) {
3957 0 : for (col = 0; col < 16; col++)
3958 0 : if (mem_adr + row * 16 + col < last)
3959 0 : if (buf[3 + row * 16 + col] != image[i * info.buf_size + row * 16 + col])
3960 0 : break;
3961 0 : if (col < 16) {
3962 0 : printf("%08X: ", mem_adr + row * 16);
3963 0 : for (col = 0; col < 16; col++) {
3964 0 : if (mem_adr + row * 16 + col < last) {
3965 0 : if (buf[3 + row * 16 + col] != image[i * info.buf_size + row * 16 + col]) {
3966 0 : printf("%02X<", buf[3 + row * 16 + col]);
3967 0 : n_err++;
3968 : } else
3969 0 : printf("%02X ", buf[3 + row * 16 + col]);
3970 : } else
3971 0 : printf(" ");
3972 : }
3973 0 : for (col = 0; col < 16; col++) {
3974 0 : if (mem_adr + row * 16 + col < last)
3975 0 : printf("%c", isprint(3 + buf[3 + row * 16 + col]) ? buf[3 + row * 16 + col] : '.');
3976 : }
3977 0 : printf("\n");
3978 : }
3979 :
3980 : }
3981 :
3982 0 : printf("File contents:\n");
3983 :
3984 0 : for (row = 0; row < (int) ((size - 1) / 16 + 1); row++) {
3985 0 : for (col = 0; col < 16; col++)
3986 0 : if (mem_adr + row * 16 + col < last)
3987 0 : if (buf[3 + row * 16 + col] != image[i * info.buf_size + row * 16 + col])
3988 0 : break;
3989 0 : if (col < 16) {
3990 0 : printf("%08X: ", mem_adr + row * 16);
3991 0 : for (col = 0; col < 16; col++) {
3992 0 : if (mem_adr + row * 16 + col < last) {
3993 0 : if (buf[3 + row * 16 + col] != image[i * info.buf_size + row * 16 + col])
3994 0 : printf("%02X<", image[i * info.buf_size + row * 16 + col]);
3995 : else
3996 0 : printf("%02X ", image[i * info.buf_size + row * 16 + col]);
3997 :
3998 : } else
3999 0 : printf(" ");
4000 : }
4001 0 : for (col = 0; col < 16; col++) {
4002 0 : if (mem_adr + row * 16 + col < last)
4003 0 : printf("%c",
4004 0 : isprint(image[i * info.buf_size + row * 16 + col]) ? image[i * info.buf_size + row * 16 +
4005 0 : col] : '.');
4006 : }
4007 0 : printf("\n");
4008 : }
4009 : }
4010 : }
4011 : }
4012 :
4013 0 : if (kbhit()) {
4014 : int c;
4015 0 : while (kbhit())
4016 0 : getch();
4017 0 : printf("Abort? (y/[n]) ");
4018 0 : c = getch();
4019 0 : if (c == 'y')
4020 0 : break;
4021 : }
4022 : }
4023 :
4024 0 : if ((flags & MSCB_UPLOAD_DEBUG) == 0)
4025 0 : printf("\n");
4026 :
4027 0 : if (n_err)
4028 0 : printf("\nVerify finished, %d bytes mismatch\n", n_err);
4029 : else
4030 0 : printf("\nVerify finished, no errors found\n");
4031 :
4032 0 : if (header)
4033 0 : free(header);
4034 0 : free(image);
4035 0 : return MSCB_SUCCESS;
4036 : }
4037 :
4038 : /*------------------------------------------------------------------*/
4039 :
4040 0 : int mscb_legacy_verify(int fd, unsigned short adr, unsigned char *image)
4041 : /********************************************************************\
4042 :
4043 : Routine: mscb_legacy_verify
4044 :
4045 : Purpose: Compare remote firmware with buffer contents
4046 :
4047 :
4048 : Input:
4049 : int fd File descriptor for connection
4050 : unsigend short adr Node address
4051 : char *buffer Buffer with Intel HEX file
4052 : int size Size of buffer
4053 :
4054 : Function value:
4055 : MSCB_SUCCESS Successful completion
4056 : MSCB_TIMEOUT Timeout receiving acknowledge
4057 : MSCB_CRC_ERROR CRC error
4058 : MSCB_INVAL_PARAM Parameter "size" has invalid value
4059 : MSCB_MUTEX Cannot obtain mutex for mscb
4060 : MSCB_FORMAT_ERROR Error in HEX file format
4061 :
4062 : \********************************************************************/
4063 : {
4064 : unsigned char buf[64], crc;
4065 : unsigned int buflen;
4066 : int i, j, retry, n_error, status, page, subpage;
4067 :
4068 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
4069 0 : return MSCB_INVAL_PARAM;
4070 :
4071 : #ifdef HAVE_MRPC
4072 : if (mrpc_connected(fd))
4073 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_UPLOAD, mscb_fd[fd - 1].remote_fd, adr, buffer, size);
4074 : #endif
4075 :
4076 : /* check if node alive */
4077 0 : status = mscb_ping(fd, adr, 0, 1);
4078 0 : if (status != MSCB_SUCCESS) {
4079 0 : printf("Error: cannot ping node #%d\n", adr);
4080 0 : return status;
4081 : }
4082 :
4083 : /* enter exclusive mode */
4084 0 : buf[0] = MCMD_FREEZE;
4085 0 : buf[1] = 1;
4086 0 : buflen = sizeof(buf);
4087 0 : mscb_exchg(fd, buf, (int *) &buflen, 2, RS485_FLAG_CMD);
4088 :
4089 : /* wait for acknowledge */
4090 0 : if (buflen != 1) {
4091 0 : printf("Error: cannot request exlusive access to submaster\n");
4092 0 : return MSCB_TIMEOUT;
4093 : }
4094 :
4095 : /* send upgrade command */
4096 0 : buf[0] = MCMD_ADDR_NODE16;
4097 0 : buf[1] = (unsigned char) (adr >> 8);
4098 0 : buf[2] = (unsigned char) (adr & 0xFF);
4099 0 : buf[3] = crc8(buf, 3);
4100 0 : buf[4] = MCMD_UPGRADE;
4101 0 : buf[5] = crc8(buf + 4, 1);
4102 0 : buflen = sizeof(buf);
4103 0 : mscb_exchg(fd, buf, (int *) &buflen, 6, RS485_FLAG_LONG_TO | RS485_FLAG_ADR_CYCLE);
4104 :
4105 : /* wait for acknowledge */
4106 0 : if (buflen != 3) {
4107 0 : printf("Error: timeout receiving acknowledge from remote node\n");
4108 0 : return MSCB_TIMEOUT;
4109 : }
4110 :
4111 : /* let main routine enter upgrade() */
4112 0 : Sleep(500);
4113 :
4114 : /* send echo command */
4115 0 : buf[0] = UCMD_ECHO;
4116 0 : buflen = sizeof(buf);
4117 0 : mscb_exchg(fd, buf, (int *) &buflen, 1, RS485_FLAG_LONG_TO);
4118 :
4119 : /* wait for ready, 1 sec timeout */
4120 0 : if (buflen != 2) {
4121 0 : printf("Error: timeout receiving upgrade acknowledge from remote node\n");
4122 :
4123 : /* send exit upgrade command, in case node gets to upgrade routine later */
4124 0 : buf[0] = UCMD_RETURN;
4125 0 : mscb_exchg(fd, buf, NULL, 1, RS485_FLAG_NO_ACK);
4126 :
4127 0 : return MSCB_TIMEOUT;
4128 : }
4129 :
4130 : /* compare pages up to 64k */
4131 0 : for (page = 0; page < 128; page++) {
4132 :
4133 : /* check if page contains data */
4134 0 : for (i = 0; i < 512; i++)
4135 0 : if (image[page * 512 + i] != 0xFF)
4136 0 : break;
4137 0 : if (i == 512)
4138 0 : continue;
4139 :
4140 : /* verify page */
4141 0 : printf("Verify page 0x%04X - ", page * 512);
4142 0 : fflush(stdout);
4143 0 : n_error = 0;
4144 :
4145 : /* compare page in 32-byte blocks */
4146 0 : for (subpage = 0; subpage < 16; subpage++) {
4147 :
4148 : /* build CRC of page */
4149 0 : for (i = crc = 0; i < 512; i++)
4150 0 : crc += image[page * 512 + i];
4151 :
4152 : /* read page */
4153 0 : for (retry = 0; retry < 5; retry++) {
4154 0 : buf[0] = UCMD_READ;
4155 0 : buf[1] = (unsigned char) page;
4156 0 : buf[2] = (unsigned char) subpage;
4157 0 : buflen = sizeof(buf);
4158 0 : status = mscb_exchg(fd, buf, (int *) &buflen, 3, RS485_FLAG_LONG_TO);
4159 0 : if (status != MSCB_SUCCESS || buflen != 32 + 3) {
4160 0 : if (retry == 4) {
4161 0 : printf("\nError: timeout from remote node for verify page 0x%04X\n", page * 512);
4162 0 : goto ver_error;
4163 : }
4164 : } else
4165 : break;
4166 : }
4167 :
4168 : /* compare data */
4169 0 : for (j = 0; j < 32; j++) {
4170 0 : if (buf[j + 2] != image[page * 512 + subpage * 32 + j]) {
4171 0 : n_error++;
4172 0 : printf("\nError at 0x%04X: file=0x%02X != remote=0x%02X", page * 512 + subpage * 32 + j,
4173 0 : image[page * 512 + subpage * 32 + j], buf[j]);
4174 : }
4175 : }
4176 : }
4177 :
4178 0 : if (n_error == 0)
4179 0 : printf("OK\n");
4180 : else
4181 0 : printf("\n - %d errors\n", n_error);
4182 : }
4183 :
4184 0 : ver_error:
4185 :
4186 : /* send exit code */
4187 0 : buf[0] = UCMD_RETURN;
4188 0 : mscb_exchg(fd, buf, NULL, 1, RS485_FLAG_NO_ACK);
4189 :
4190 : /* exit exclusive mode */
4191 0 : buf[0] = MCMD_FREEZE;
4192 0 : buf[1] = 0;
4193 0 : buflen = sizeof(buf);
4194 0 : mscb_exchg(fd, buf, (int *) &buflen, 2, RS485_FLAG_CMD);
4195 :
4196 0 : printf("Verify finished\n");
4197 :
4198 0 : return MSCB_SUCCESS;
4199 : }
4200 :
4201 : /*------------------------------------------------------------------*/
4202 :
4203 0 : int mscb_read(int fd, unsigned short adr, unsigned char index, void *data, int *size)
4204 : /********************************************************************\
4205 :
4206 : Routine: mscb_read
4207 :
4208 : Purpose: Read data from variable on node
4209 :
4210 : Input:
4211 : int fd File descriptor for connection
4212 : unsigend short adr Node address
4213 : unsigned char index Variable index 0..255
4214 : int size Buffer size for data
4215 :
4216 : Output:
4217 : void *data Received data
4218 : int *size Number of received bytes
4219 :
4220 : Function value:
4221 : MSCB_SUCCESS Successful completion
4222 : MSCB_TIMEOUT Timeout receiving acknowledge
4223 : MSCB_CRC_ERROR CRC error
4224 : MSCB_INVAL_PARAM Parameter "size" has invalid value
4225 : MSCB_MUTEX Cannot obtain mutex for mscb
4226 : MSCB_INVALID_INDEX index parameter too large
4227 :
4228 : \********************************************************************/
4229 : {
4230 : int i, j, len, n, status;
4231 : unsigned char buf[256], crc;
4232 : char str[1000];
4233 :
4234 0 : debug_log("mscb_read(fd=%d,adr=%d,index=%d,size=%d)", 0, fd, adr, index, *size);
4235 :
4236 0 : if (*size > 256)
4237 0 : return MSCB_INVAL_PARAM;
4238 :
4239 0 : memset(data, 0, *size);
4240 0 : status = 0;
4241 :
4242 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type) {
4243 0 : debug_log("mscb_read return MSCB_INVAL_PARAM", 0);
4244 0 : return MSCB_INVAL_PARAM;
4245 : }
4246 :
4247 : #ifdef HAVE_MRPC
4248 : if (mrpc_connected(fd))
4249 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_READ, mscb_fd[fd - 1].remote_fd, adr, index, data, size);
4250 : #endif
4251 :
4252 : /* try ten times */
4253 0 : for (n = i = 0; n < mscb_max_retry; n++) {
4254 :
4255 0 : if (n > 0)
4256 0 : debug_log("mscb_read retry %d\n", n);
4257 :
4258 0 : buf[0] = MCMD_ADDR_NODE16;
4259 0 : buf[1] = (unsigned char) (adr >> 8);
4260 0 : buf[2] = (unsigned char) (adr & 0xFF);
4261 0 : buf[3] = crc8(buf, 3);
4262 :
4263 0 : buf[4] = MCMD_READ + 1;
4264 0 : buf[5] = index;
4265 0 : buf[6] = crc8(buf + 4, 2);
4266 0 : len = sizeof(buf);
4267 0 : status = mscb_exchg(fd, buf, &len, 7, RS485_FLAG_ADR_CYCLE);
4268 :
4269 0 : if (status == MSCB_TIMEOUT) {
4270 0 : debug_log("mscb_read timeout writing to submaster %s:%d", 0, mscb_fd[fd - 1].device, adr);
4271 0 : continue;
4272 : }
4273 0 : if (status == MSCB_SUBM_ERROR) {
4274 0 : debug_log("mscb_read connection to submaster %s:%d broken", 0, mscb_fd[fd - 1].device, adr);
4275 0 : break;
4276 : }
4277 :
4278 0 : if (len == 1 && buf[0] == MCMD_ACK) {
4279 : /* variable has been deleted on node, so refresh cache */
4280 0 : if (n > 5) {
4281 0 : mscb_clear_info_cache();
4282 0 : return MSCB_INVALID_INDEX;
4283 : }
4284 0 : continue;
4285 : }
4286 :
4287 0 : if (len == 1) {
4288 0 : debug_log("mscb_read timeout from RS485 bus at %s:%d", 0, mscb_fd[fd - 1].device, adr);
4289 0 : status = MSCB_TIMEOUT;
4290 :
4291 0 : debug_log("mscb_read flush node communication at %s:%d", 0, mscb_fd[fd - 1].device, adr);
4292 0 : memset(buf, 0, sizeof(buf));
4293 0 : mscb_exchg(fd, buf, NULL, 10, RS485_FLAG_BIT9 | RS485_FLAG_NO_ACK);
4294 0 : Sleep(100);
4295 :
4296 0 : continue;
4297 : }
4298 :
4299 0 : if (len < 2) {
4300 : #ifndef _USRDLL
4301 : /* show error, but repeat request */
4302 0 : printf("mscb_read: Timeout reading from submaster %s:%d\n", mscb_fd[fd - 1].device, adr);
4303 : #endif
4304 0 : status = MSCB_TIMEOUT;
4305 0 : continue;
4306 : }
4307 :
4308 0 : crc = crc8(buf, len - 1);
4309 :
4310 0 : if (buf[0] != MCMD_ACK + len - 2 && buf[0] != MCMD_ACK + 7) {
4311 0 : status = MSCB_FORMAT_ERROR;
4312 : #ifndef _USRDLL
4313 : /* show error, but repeat */
4314 0 : printf("mscb_read: Read error on RS485 bus at %s:%d\n", mscb_fd[fd - 1].device, adr);
4315 : #endif
4316 0 : continue;
4317 : }
4318 :
4319 0 : if (buf[len - 1] != crc) {
4320 0 : status = MSCB_CRC_ERROR;
4321 : #ifndef _USRDLL
4322 : /* show error, but repeat */
4323 0 : printf("mscb_read: CRC error on RS485 bus at %s:%d\n", mscb_fd[fd - 1].device, adr);
4324 : #endif
4325 0 : continue;
4326 : }
4327 :
4328 0 : if (buf[0] == MCMD_ACK + 7) {
4329 0 : if (len - 3 > *size) {
4330 0 : *size = 0;
4331 0 : debug_log("mscb_read return MSCB_NO_MEM, len=%d, *size=%d", 0, len, *size);
4332 0 : return MSCB_NO_MEM;
4333 : }
4334 :
4335 0 : memcpy(data, buf + 2, len - 3); // variable length
4336 0 : *size = len - 3;
4337 : } else {
4338 0 : if (len - 2 > *size) {
4339 0 : *size = 0;
4340 0 : debug_log("mscb_read return MSCB_NO_MEM, len=%d, *size=%d", 0, len, *size);
4341 0 : return MSCB_NO_MEM;
4342 : }
4343 :
4344 0 : memcpy(data, buf + 1, len - 2);
4345 0 : *size = len - 2;
4346 : }
4347 :
4348 0 : if (len - 2 == 2) WORD_SWAP(data);
4349 0 : if (len - 2 == 4) DWORD_SWAP(data);
4350 :
4351 0 : if (_debug_flag) {
4352 0 : snprintf(str, sizeof(str), "mscb_read return %d bytes: ", *size);
4353 0 : for (j = 0; j < *size; j++) {
4354 0 : snprintf((char *) str + strlen(str), sizeof(str) - strlen(str), "0x%02X ",
4355 0 : *(((unsigned char *) data) + j));
4356 0 : if (isalnum(*(((unsigned char *) data) + j)))
4357 0 : snprintf(str + strlen(str), sizeof(str) - strlen(str), "('%c') ",
4358 0 : *(((unsigned char *) data) + j));
4359 : }
4360 0 : debug_log(str, 0);
4361 : }
4362 :
4363 0 : return MSCB_SUCCESS;
4364 : }
4365 :
4366 0 : if (status == MSCB_TIMEOUT)
4367 0 : debug_log("mscb_read return MSCB_TIMEOUT\n", 0);
4368 0 : if (status == MSCB_CRC_ERROR)
4369 0 : debug_log("mscb_read return MSCB_CRC_ERROR\n", 0);
4370 0 : if (status == MSCB_FORMAT_ERROR)
4371 0 : debug_log("mscb_read return MSCB_FORMAT_ERROR\n", 0);
4372 0 : if (status == MSCB_SUBM_ERROR)
4373 0 : debug_log("mscb_read return MSCB_SUBM_ERROR\n", 0);
4374 :
4375 0 : return status;
4376 : }
4377 :
4378 : /*------------------------------------------------------------------*/
4379 :
4380 0 : int mscb_read_no_retries(int fd, unsigned short adr, unsigned char index, void *data, int *size)
4381 : /********************************************************************\
4382 :
4383 : Routine: mscb_read_no_retries
4384 :
4385 : Purpose: Same as mscb_read, but without retries
4386 :
4387 : Input:
4388 : int fd File descriptor for connection
4389 : unsigend short adr Node address
4390 : unsigned char index Variable index 0..255
4391 : int size Buffer size for data
4392 :
4393 : Output:
4394 : void *data Received data
4395 : int *size Number of received bytes
4396 :
4397 : Function value:
4398 : MSCB_SUCCESS Successful completion
4399 : MSCB_TIMEOUT Timeout receiving acknowledge
4400 : MSCB_CRC_ERROR CRC error
4401 : MSCB_INVAL_PARAM Parameter "size" has invalid value
4402 : MSCB_MUTEX Cannot obtain mutex for mscb
4403 :
4404 : \********************************************************************/
4405 : {
4406 : int j, len, status;
4407 : char str[1000];
4408 : unsigned char buf[256], crc;
4409 :
4410 0 : debug_log("mscb_read_no_retries(fd=%d,adr=%d,index=%d,size=%d)", 0, fd, adr, index, *size);
4411 :
4412 0 : if (*size > 256)
4413 0 : return MSCB_INVAL_PARAM;
4414 :
4415 0 : memset(data, 0, *size);
4416 0 : status = 0;
4417 :
4418 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type) {
4419 0 : debug_log("mscb_read_no_retries return MSCB_INVAL_PARAM", 0);
4420 0 : return MSCB_INVAL_PARAM;
4421 : }
4422 :
4423 : #ifdef HAVE_MRPC
4424 : if (mrpc_connected(fd))
4425 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_READ_NO_RETRIES, mscb_fd[fd - 1].remote_fd, adr, index, data, size);
4426 : #endif
4427 :
4428 0 : buf[0] = MCMD_ADDR_NODE16;
4429 0 : buf[1] = (unsigned char) (adr >> 8);
4430 0 : buf[2] = (unsigned char) (adr & 0xFF);
4431 0 : buf[3] = crc8(buf, 3);
4432 :
4433 0 : buf[4] = MCMD_READ + 1;
4434 0 : buf[5] = index;
4435 0 : buf[6] = crc8(buf + 4, 2);
4436 0 : len = sizeof(buf);
4437 0 : status = mscb_exchg(fd, buf, &len, 7, RS485_FLAG_ADR_CYCLE);
4438 0 : if (status == MSCB_TIMEOUT) {
4439 : #ifndef _USRDLL
4440 : /* show error, but continue repeating */
4441 0 : printf("mscb_read_no_retries: Timeout writing to submaster %s:%d\n", mscb_fd[fd - 1].device, adr);
4442 : #endif
4443 0 : return MSCB_TIMEOUT;
4444 : }
4445 :
4446 0 : if (len == 1) {
4447 : #ifndef _USRDLL
4448 0 : printf("mscb_read_no_retries: Timeout from RS485 bus at %s:%d\n", mscb_fd[fd - 1].device, adr);
4449 : #endif
4450 0 : memset(buf, 0, sizeof(buf));
4451 0 : mscb_exchg(fd, buf, NULL, 10, RS485_FLAG_BIT9 | RS485_FLAG_NO_ACK);
4452 0 : return MSCB_TIMEOUT;
4453 : }
4454 :
4455 0 : if (len < 2) {
4456 : #ifndef _USRDLL
4457 : /* show error, but repeat request */
4458 0 : printf("mscb_read_no_retries: Timeout reading from submaster %s:%d\n", mscb_fd[fd - 1].device, adr);
4459 : #endif
4460 0 : return MSCB_TIMEOUT;
4461 : }
4462 :
4463 0 : crc = crc8(buf, len - 1);
4464 :
4465 0 : if ((buf[0] != MCMD_ACK + len - 2 && buf[0] != MCMD_ACK + 7)
4466 0 : || buf[len - 1] != crc) {
4467 : #ifndef _USRDLL
4468 : /* show error, but continue repeating */
4469 0 : printf("mscb_read_no_retries: CRC error on RS485 bus at %s:%d\n", mscb_fd[fd - 1].device, adr);
4470 : #endif
4471 0 : return MSCB_CRC_ERROR;
4472 : }
4473 :
4474 0 : if (buf[0] == MCMD_ACK + 7) {
4475 0 : if (len - 3 > *size) {
4476 0 : *size = 0;
4477 0 : debug_log("mscb_read_no_retries return MSCB_NO_MEM, len=%d, *size=%d", len, *size);
4478 0 : return MSCB_NO_MEM;
4479 : }
4480 :
4481 0 : memcpy(data, buf + 2, len - 3); // variable length
4482 0 : *size = len - 3;
4483 : } else {
4484 0 : if (len - 2 > *size) {
4485 0 : *size = 0;
4486 0 : debug_log("mscb_read_no_retries return MSCB_NO_MEM, len=%d, *size=%d", len, *size);
4487 0 : return MSCB_NO_MEM;
4488 : }
4489 :
4490 0 : memcpy(data, buf + 1, len - 2);
4491 0 : *size = len - 2;
4492 : }
4493 :
4494 0 : if (len - 2 == 2) WORD_SWAP(data);
4495 0 : if (len - 2 == 4) DWORD_SWAP(data);
4496 :
4497 0 : if (_debug_flag) {
4498 0 : snprintf(str, sizeof(str), "mscb_read_no_retries return %d bytes: ", *size);
4499 0 : for (j = 0; j < *size; j++) {
4500 0 : snprintf(str + strlen(str), sizeof(str) - strlen(str), "0x%02X ",
4501 0 : *(((unsigned char *) data) + j));
4502 0 : if (isalnum(*(((unsigned char *) data) + j)))
4503 0 : snprintf(str + strlen(str), sizeof(str) - strlen(str), "('%c') ",
4504 0 : *(((unsigned char *) data) + j));
4505 : }
4506 0 : debug_log(str, 0);
4507 : }
4508 :
4509 0 : return MSCB_SUCCESS;
4510 : }
4511 :
4512 : /*------------------------------------------------------------------*/
4513 :
4514 0 : int mscb_read_range(int fd, unsigned short adr, unsigned char index1, unsigned char index2, void *data, int *size)
4515 : /********************************************************************\
4516 :
4517 : Routine: mscb_read_range
4518 :
4519 : Purpose: Read data from multiple channels on node
4520 :
4521 : Input:
4522 : int fd File descriptor for connection
4523 : unsigend short adr Node address
4524 : unsigned char index1 First index to read
4525 : unsigned char index2 Last index to read
4526 : int size Buffer size for data
4527 :
4528 : Output:
4529 : void *data Received data
4530 : int *size Number of received bytes
4531 :
4532 : Function value:
4533 : MSCB_SUCCESS Successful completion
4534 : MSCB_TIMEOUT Timeout receiving acknowledge
4535 : MSCB_CRC_ERROR CRC error
4536 : MSCB_INVAL_PARAM Parameter "size" has invalid value
4537 : MSCB_MUTEX Cannot obtain mutex for mscb
4538 :
4539 : \********************************************************************/
4540 : {
4541 : int i, j, n, len, status;
4542 : char str[1000];
4543 : // buffer size = 1400 equals roughly the ethernet maximum transfer unit
4544 : unsigned char buf[1400], crc;
4545 :
4546 0 : debug_log("mscb_read_range(fd=%d,adr=%d,index1=%d,index2=%d,size=%d)",
4547 : 0, fd, adr, index1, index2, *size);
4548 :
4549 0 : if (*size > 1400)
4550 0 : return MSCB_INVAL_PARAM;
4551 :
4552 0 : memset(data, 0, *size);
4553 0 : status = 0;
4554 :
4555 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type) {
4556 0 : debug_log("mscb_read_range return MSCB_INVAL_PARAM", 0);
4557 0 : return MSCB_INVAL_PARAM;
4558 : }
4559 :
4560 : #ifdef HAVE_MRPC
4561 : if (mrpc_connected(fd))
4562 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_READ_RANGE,
4563 : mscb_fd[fd - 1].remote_fd, adr, index1, index2, data, size);
4564 : #endif
4565 :
4566 : /* retry several times as specified with mscb_max_retry */
4567 0 : for (n = i = 0; n < mscb_max_retry; n++) {
4568 :
4569 0 : buf[0] = MCMD_ADDR_NODE16;
4570 0 : buf[1] = (unsigned char) (adr >> 8);
4571 0 : buf[2] = (unsigned char) (adr & 0xFF);
4572 0 : buf[3] = crc8(buf, 3);
4573 :
4574 0 : buf[4] = MCMD_READ + 2;
4575 0 : buf[5] = index1;
4576 0 : buf[6] = index2;
4577 0 : buf[7] = crc8(buf + 4, 3);
4578 0 : len = sizeof(buf);
4579 :
4580 0 : if (n > 0)
4581 0 : debug_log("mscb_read_range retry %d", 0, n);
4582 :
4583 0 : status = mscb_exchg(fd, buf, &len, 8, RS485_FLAG_ADR_CYCLE | RS485_FLAG_LONG_TO);
4584 0 : if (status == MSCB_TIMEOUT) {
4585 0 : debug_log("mscb_read_range timeout writing to submaster %s:%d", 0, mscb_fd[fd - 1].device, adr);
4586 0 : continue;
4587 : }
4588 0 : if (status == MSCB_SUBM_ERROR) {
4589 0 : debug_log("mscb_read_range connection to submaster %s:%d broken", 0, mscb_fd[fd - 1].device, adr);
4590 0 : break;
4591 : }
4592 :
4593 0 : if (len == 1 && buf[0] == MCMD_ACK) {
4594 : /* variable has been deleted on node, so refresh cache */
4595 0 : if (n > 5) {
4596 0 : mscb_clear_info_cache();
4597 0 : return MSCB_INVALID_INDEX;
4598 : }
4599 0 : continue;
4600 : }
4601 :
4602 0 : if (len == 1) {
4603 0 : debug_log("mscb_read_range timeout from RS485 bus at %s:%d", 0, mscb_fd[fd - 1].device, adr);
4604 0 : status = MSCB_TIMEOUT;
4605 :
4606 0 : Sleep(300);
4607 0 : debug_log("mscb_read_range flush node communication at %s:%d", 0, mscb_fd[fd - 1].device, adr);
4608 0 : memset(buf, 0, sizeof(buf));
4609 0 : mscb_exchg(fd, buf, NULL, 10, RS485_FLAG_BIT9 | RS485_FLAG_NO_ACK);
4610 0 : Sleep(300);
4611 :
4612 0 : continue;
4613 : }
4614 :
4615 0 : if (len < 2) {
4616 : /* show error, but repeat request */
4617 0 : debug_log("mscb_read_range: Timeout reading from submaster %s:%d\n", 0, mscb_fd[fd - 1].device, adr);
4618 0 : status = MSCB_TIMEOUT;
4619 0 : continue;
4620 : }
4621 :
4622 0 : crc = crc8(buf, len - 1);
4623 :
4624 0 : if (buf[0] != MCMD_ACK + len - 2 && buf[0] != MCMD_ACK + 7) {
4625 0 : status = MSCB_FORMAT_ERROR;
4626 :
4627 : /* show error, but repeat */
4628 0 : debug_log("mscb_read_range: Read error on RS485 bus at %s:%d\n", 0, mscb_fd[fd - 1].device, adr);
4629 0 : continue;
4630 : }
4631 :
4632 0 : if (buf[len - 1] != crc) {
4633 0 : status = MSCB_CRC_ERROR;
4634 : /* show error, but repeat */
4635 0 : debug_log("mscb_read_range: CRC error on RS485 bus at %s:%d\n", 0, mscb_fd[fd - 1].device, adr);
4636 0 : continue;
4637 : }
4638 :
4639 0 : if (buf[0] == MCMD_ACK + 7) {
4640 0 : if (len - 4 > *size) {
4641 0 : *size = 0;
4642 0 : debug_log("mscb_read_range return MSCB_NO_MEM, len=%d, *size=%d", 0, len, *size);
4643 0 : return MSCB_NO_MEM;
4644 : }
4645 :
4646 0 : if (buf[1] & 0x80) {
4647 0 : memcpy(data, buf + 3, len - 4); // variable length with size in two byte
4648 0 : *size = len - 4;
4649 : } else {
4650 0 : memcpy(data, buf + 2, len - 3); // variable length with size in one byte
4651 0 : *size = len - 3;
4652 : }
4653 : } else {
4654 0 : if (len - 2 > *size) {
4655 0 : *size = 0;
4656 0 : debug_log("mscb_read_range return MSCB_NO_MEM, len=%d, *size=%d", len, *size);
4657 0 : return MSCB_NO_MEM;
4658 : }
4659 :
4660 0 : memcpy(data, buf + 1, len - 2);
4661 0 : *size = len - 2;
4662 : }
4663 :
4664 0 : if (_debug_flag) {
4665 0 : snprintf(str, sizeof(str), "mscb_read_range return %d bytes: ", *size);
4666 0 : for (j = 0; j < *size; j++) {
4667 0 : if (strlen(str) > sizeof(str) - 20) {
4668 0 : mstrlcat(str, "...", sizeof(str));
4669 0 : break;
4670 : }
4671 0 : snprintf(str + strlen(str), sizeof(str) - strlen(str), "0x%02X ",
4672 0 : *(((unsigned char *) data) + j));
4673 0 : if (isalnum(*(((unsigned char *) data) + j)))
4674 0 : snprintf(str + strlen(str), sizeof(str) - strlen(str), "('%c') ",
4675 0 : *(((unsigned char *) data) + j));
4676 : }
4677 0 : debug_log(str, 0);
4678 : }
4679 :
4680 0 : return MSCB_SUCCESS;
4681 : }
4682 :
4683 0 : if (status == MSCB_TIMEOUT)
4684 0 : debug_log("mscb_read_range return MSCB_TIMEOUT", 0);
4685 0 : if (status == MSCB_CRC_ERROR)
4686 0 : debug_log("mscb_read_range return MSCB_CRC_ERROR", 0);
4687 0 : if (status == MSCB_FORMAT_ERROR)
4688 0 : debug_log("mscb_read_range return MSCB_FORMAT_ERROR", 0);
4689 0 : if (status == MSCB_SUBM_ERROR)
4690 0 : debug_log("mscb_read_range return MSCB_SUBM_ERROR", 0);
4691 :
4692 0 : return status;
4693 : }
4694 :
4695 : /*------------------------------------------------------------------*/
4696 :
4697 0 : int mscb_write_mem(int fd, unsigned short node_adr, int sub_adr, unsigned int mem_adr, void *buffer, int size)
4698 : /********************************************************************\
4699 :
4700 : Routine: mscb_write_mem
4701 :
4702 : Purpose: Write block of data to memory
4703 :
4704 : Input:
4705 : int fd File descriptor for connection
4706 : unsigned short node_adr Node address
4707 : int sub_adr Slot number
4708 : unsigned int mem_adr Memory address
4709 : void *buffer Data buffer
4710 : int size Number of bytes in buffer
4711 :
4712 :
4713 : Function value:
4714 : MSCB_INVAL_PARAM Invalid parameter
4715 : MSCB_SUCCESS Successful completion
4716 : MSCB_TIMEOUT Timeout
4717 : MSCB_CRC_ERROR CRC error
4718 : MSCB_MUTEX Cannot obtain mutex for mscb
4719 :
4720 : \********************************************************************/
4721 : {
4722 : unsigned char buf[256 + 13], crc;
4723 : int buflen, status;
4724 :
4725 0 : if (size > 256) {
4726 0 : debug_log("mscb_write_mem buffer size of %d larger than maximum size of 256", 1, size);
4727 0 : return MSCB_INVAL_PARAM;
4728 : }
4729 :
4730 : // address node
4731 0 : buf[0] = MCMD_ADDR_NODE16;
4732 0 : buf[1] = (unsigned char) (node_adr >> 8);
4733 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
4734 0 : buf[3] = crc8(buf, 3);
4735 :
4736 0 : buf[4] = MCMD_WRITE_MEM;
4737 0 : buf[5] = 0x80 | ((size + 5) >> 8);
4738 0 : buf[6] = (size + 5) & 0xFF;
4739 0 : buf[7] = (unsigned char) sub_adr;
4740 0 : buf[8] = (mem_adr >> 24) & 0xFF;
4741 0 : buf[9] = (mem_adr >> 16) & 0xFF;
4742 0 : buf[10] = (mem_adr >> 8) & 0xFF;
4743 0 : buf[11] = (mem_adr >> 0) & 0xFF;
4744 0 : memcpy(buf + 12, buffer, size);
4745 0 : buf[12 + size] = crc8(buf + 4, 8 + size);
4746 :
4747 0 : crc = crc8(buf + 12, size);
4748 0 : buflen = size + 13;
4749 :
4750 0 : status = mscb_exchg(fd, buf, (int *) &buflen, buflen, RS485_FLAG_ADR_CYCLE | RS485_FLAG_LONG_TO);
4751 :
4752 0 : if (buflen == 1 && buf[0] == 0xFF) {
4753 0 : debug_log("mscb_write_mem timeout from RS485 bus at %s:%d", 1, mscb_fd[fd - 1].device, node_adr);
4754 0 : return MSCB_TIMEOUT;
4755 : }
4756 :
4757 0 : if (buflen != 2 || buf[0] != MCMD_ACK || buf[1] != crc) {
4758 0 : debug_log("mscb_write_mem returns MSCB_CRC_ERROR (CRC %02X vs %02X)", 0, crc, buf[1]);
4759 0 : status = MSCB_CRC_ERROR;
4760 : }
4761 :
4762 0 : debug_log("mscb_write_mem return MSCB_SUCCESS", 1);
4763 :
4764 0 : return status;
4765 : }
4766 :
4767 : /*------------------------------------------------------------------*/
4768 :
4769 0 : int mscb_read_mem(int fd, unsigned short node_adr, int sub_adr, unsigned int mem_adr, void *buffer, int size)
4770 : /********************************************************************\
4771 :
4772 : Routine: mscb_read_mem
4773 :
4774 : Purpose: Read block of data to memory
4775 :
4776 : Input:
4777 : int fd File descriptor for connection
4778 : unsigned short node_adr Node address
4779 : int sub_adr Slot number
4780 : unsigned int mem_adr Memory address
4781 : void *buffer Data buffer
4782 : int size Number of bytes to read
4783 :
4784 :
4785 : Function value:
4786 : MSCB_INVAL_PARAM Invalid parameter
4787 : MSCB_SUCCESS Successful completion
4788 : MSCB_TIMEOUT Timeout
4789 : MSCB_CRC_ERROR CRC error
4790 : MSCB_MUTEX Cannot obtain mutex for mscb
4791 :
4792 : \********************************************************************/
4793 : {
4794 : unsigned char buf[256 + 3];
4795 : int buflen, status;
4796 :
4797 0 : memset(buffer, 0, size);
4798 :
4799 0 : if (size > 256) {
4800 0 : debug_log("mscb_read_mem buffer size of %d larger than maximum size of 256", 1, size);
4801 0 : return MSCB_INVAL_PARAM;
4802 : }
4803 :
4804 : // address node
4805 0 : buf[0] = MCMD_ADDR_NODE16;
4806 0 : buf[1] = (unsigned char) (node_adr >> 8);
4807 0 : buf[2] = (unsigned char) (node_adr & 0xFF);
4808 0 : buf[3] = crc8(buf, 3);
4809 :
4810 0 : buf[4] = MCMD_READ_MEM;
4811 0 : buf[5] = 0x07; // 7 parameters to follow
4812 0 : buf[6] = size >> 8;
4813 0 : buf[7] = size & 0xFF;
4814 0 : buf[8] = (unsigned char) sub_adr;
4815 0 : buf[9] = (mem_adr >> 24) & 0xFF;
4816 0 : buf[10] = (mem_adr >> 16) & 0xFF;
4817 0 : buf[11] = (mem_adr >> 8) & 0xFF;
4818 0 : buf[12] = (mem_adr >> 0) & 0xFF;
4819 0 : buf[13] = crc8(buf + 4, 9);
4820 :
4821 0 : buflen = size + 4;
4822 0 : status = mscb_exchg(fd, buf, (int *) &buflen, 14, RS485_FLAG_ADR_CYCLE | RS485_FLAG_LONG_TO);
4823 :
4824 0 : if (buflen == 1 && buf[0] == 0xFF) {
4825 0 : debug_log("mscb_read_mem timeout from RS485 bus at %s:%d\n", 0, mscb_fd[fd - 1].device, node_adr);
4826 0 : return MSCB_TIMEOUT;
4827 : }
4828 :
4829 0 : if (buflen != size + 4 || buf[size + 3] != crc8(buf, size + 3)) {
4830 0 : debug_log("mscb_read_mem transmission error (CRC %02X vs %02X)", 0,
4831 0 : crc8(buf, size + 3), buf[size + 3]);
4832 0 : status = MSCB_CRC_ERROR;
4833 : }
4834 :
4835 0 : memcpy(buffer, buf + 3, size);
4836 :
4837 0 : return status;
4838 : }
4839 :
4840 : /*------------------------------------------------------------------*/
4841 :
4842 0 : int mscb_user(int fd, unsigned short adr, void *param, int size, void *result, int *rsize)
4843 : /********************************************************************\
4844 :
4845 : Routine: mscb_user
4846 :
4847 : Purpose: Call user function on node
4848 :
4849 : Input:
4850 : int fd File descriptor for connection
4851 : unsigned short adr Node address
4852 : char *param Parameters passed to user function, no CRC code
4853 : int size Size of parameters in bytes
4854 : int *rsize Size of result buffer
4855 :
4856 : Output:
4857 : char *result Optional return parameters
4858 : int *rsize Number of returned size
4859 :
4860 : Function value:
4861 : MSCB_SUCCESS Successful completion
4862 : MSCB_TIMEOUT Timeout receiving data
4863 : MSCB_CRC_ERROR CRC error
4864 : MSCB_MUTEX Cannot obtain mutex for mscb
4865 : MSCB_FORMAT_ERROR "size" parameter too large
4866 :
4867 : \********************************************************************/
4868 : {
4869 : int i, len, status;
4870 : unsigned char buf[80];
4871 :
4872 0 : memset(result, 0, *rsize);
4873 :
4874 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
4875 0 : return MSCB_INVAL_PARAM;
4876 :
4877 0 : if (size > 4 || size < 0) {
4878 0 : return MSCB_FORMAT_ERROR;
4879 : }
4880 :
4881 : #ifdef HAVE_MRPC
4882 : if (mrpc_connected(fd))
4883 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_USER,
4884 : mscb_fd[fd - 1].remote_fd, adr, param, size, result, rsize);
4885 : #endif
4886 :
4887 0 : buf[0] = MCMD_ADDR_NODE16;
4888 0 : buf[1] = (unsigned char) (adr >> 8);
4889 0 : buf[2] = (unsigned char) (adr & 0xFF);
4890 0 : buf[3] = crc8(buf, 3);
4891 :
4892 0 : buf[4] = (unsigned char) (MCMD_USER + size);
4893 :
4894 0 : for (i = 0; i < size; i++)
4895 0 : buf[5 + i] = ((char *) param)[i];
4896 :
4897 : /* add CRC code and send data */
4898 0 : buf[5 + i] = crc8(buf + 4, 1 + i);
4899 0 : len = sizeof(buf);
4900 0 : status = mscb_exchg(fd, buf, &len, 6 + i, RS485_FLAG_ADR_CYCLE);
4901 :
4902 0 : if (status != MSCB_SUCCESS)
4903 0 : return status;
4904 :
4905 0 : if (result == NULL)
4906 0 : return MSCB_SUCCESS;
4907 :
4908 0 : if (len < 2)
4909 0 : return MSCB_TIMEOUT;
4910 :
4911 0 : if (rsize)
4912 0 : *rsize = len - 2;
4913 0 : for (i = 0; i < len - 2; i++)
4914 0 : ((char *) result)[i] = buf[1 + i];
4915 :
4916 0 : if (buf[len - 1] != crc8(buf, len - 1))
4917 0 : return MSCB_CRC_ERROR;
4918 :
4919 0 : return MSCB_SUCCESS;
4920 : }
4921 :
4922 : /*------------------------------------------------------------------*/
4923 :
4924 0 : int mscb_echo(int fd, unsigned short adr, unsigned char d1, unsigned char *d2)
4925 : /********************************************************************\
4926 :
4927 : Routine: mscb_echo
4928 :
4929 : Purpose: Send byte and receive echo, useful for testing
4930 :
4931 : Input:
4932 : int fd File descriptor for connection
4933 : int adr Node address
4934 : unsigned char d1 Byte to send
4935 :
4936 : Output:
4937 : unsigned char *d2 Received byte
4938 :
4939 : Function value:
4940 : MSCB_SUCCESS Successful completion
4941 : MSCB_TIMEOUT Timeout receiving data
4942 : MSCB_CRC_ERROR CRC error
4943 : MSCB_MUTEX Cannot obtain mutex for mscb
4944 : MSCB_FORMAT_ERROR "size" parameter too large
4945 :
4946 : \********************************************************************/
4947 : {
4948 : int len, status;
4949 : unsigned char buf[64];
4950 :
4951 0 : *d2 = 0xFF;
4952 :
4953 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
4954 0 : return MSCB_INVAL_PARAM;
4955 :
4956 : #ifdef HAVE_MRPC
4957 : if (mrpc_connected(fd))
4958 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_ECHO, mscb_fd[fd - 1].remote_fd, adr, d1, d2);
4959 : #endif
4960 :
4961 0 : buf[0] = MCMD_ADDR_NODE16;
4962 0 : buf[1] = (unsigned char) (adr >> 8);
4963 0 : buf[2] = (unsigned char) (adr & 0xFF);
4964 0 : buf[3] = crc8(buf, 3);
4965 :
4966 0 : buf[4] = MCMD_ECHO;
4967 0 : buf[5] = d1;
4968 :
4969 : /* add CRC code and send data */
4970 0 : buf[6] = crc8(buf + 4, 2);
4971 0 : len = sizeof(buf);
4972 0 : status = mscb_exchg(fd, buf, &len, 7, RS485_FLAG_ADR_CYCLE);
4973 0 : if (status != MSCB_SUCCESS)
4974 0 : return status;
4975 :
4976 0 : *d2 = buf[1];
4977 :
4978 0 : if (len == 1 && buf[0] == 0xFF)
4979 0 : return MSCB_TIMEOUT_BUS; // timeout RS485 bus
4980 :
4981 0 : if (buf[len - 1] != crc8(buf, len - 1))
4982 0 : return MSCB_CRC_ERROR;
4983 :
4984 0 : return MSCB_SUCCESS;
4985 : }
4986 :
4987 : /*------------------------------------------------------------------*/
4988 :
4989 0 : int mscb_link(int fd, unsigned short adr, unsigned char index, void *data, int size)
4990 : /********************************************************************\
4991 :
4992 : Routine: mscb_link
4993 :
4994 : Purpose: Used by LabView to link controls to MSCB variables
4995 :
4996 : Input:
4997 : int fd File descriptor for connection
4998 : int adr Node address
4999 : unsigned char index Variable index
5000 : void *data Pointer to data
5001 : int size Size of data
5002 :
5003 : Output:
5004 : void *data Readback data
5005 :
5006 : Function value:
5007 : MSCB_SUCCESS Successful completion
5008 : MSCB_TIMEOUT Timeout receiving data
5009 : MSCB_CRC_ERROR CRC error
5010 : MSCB_MUTEX Cannot obtain mutex for mscb
5011 : MSCB_FORMAT_ERROR "size" parameter too large
5012 : MSCB_NO_MEM Out of memory
5013 :
5014 : \********************************************************************/
5015 : {
5016 : int i, s, status;
5017 : MSCB_INFO_VAR info;
5018 :
5019 0 : debug_log("mscb_link( %d %d %d * %d)", 0, fd, adr, index, size);
5020 :
5021 : /* check if variable in cache */
5022 0 : for (i = 0; i < n_cache; i++)
5023 0 : if (cache[i].fd == fd && cache[i].adr == adr && cache[i].index == index)
5024 0 : break;
5025 :
5026 0 : if (i < n_cache) {
5027 0 : if (memcmp(data, cache[i].data, cache[i].size) != 0) {
5028 : /* data has changed, send update */
5029 0 : memcpy(cache[i].data, data, cache[i].size);
5030 0 : mscb_write(fd, adr, index, data, cache[i].size);
5031 : } else {
5032 : /* retrieve data from node */
5033 0 : if (millitime() > cache[i].last + CACHE_PERIOD) {
5034 0 : cache[i].last = millitime();
5035 :
5036 0 : s = cache[i].size;
5037 0 : status = mscb_read(fd, adr, index, cache[i].data, &s);
5038 0 : if (status != MSCB_SUCCESS)
5039 0 : return status;
5040 :
5041 0 : memcpy(data, cache[i].data, size);
5042 : }
5043 : }
5044 : } else {
5045 : /* add new entry in cache */
5046 0 : if (n_cache == 0)
5047 0 : cache = (CACHE_ENTRY *) malloc(sizeof(CACHE_ENTRY));
5048 : else
5049 0 : cache = (CACHE_ENTRY *) realloc(cache, sizeof(CACHE_ENTRY) * (n_cache + 1));
5050 :
5051 0 : if (cache == NULL)
5052 0 : return MSCB_NO_MEM;
5053 :
5054 : /* get variable size from node */
5055 0 : status = mscb_info_variable(fd, adr, index, &info);
5056 0 : if (status != MSCB_SUCCESS)
5057 0 : return status;
5058 :
5059 : /* setup cache entry */
5060 0 : i = n_cache;
5061 0 : n_cache++;
5062 :
5063 0 : cache[i].fd = fd;
5064 0 : cache[i].adr = adr;
5065 0 : cache[i].index = index;
5066 0 : cache[i].last = 0;
5067 0 : cache[i].size = info.width;
5068 :
5069 : /* allocate at least 4 bytes */
5070 0 : s = info.width;
5071 0 : if (s < 4)
5072 0 : s = 4;
5073 0 : cache[i].data = malloc(s);
5074 0 : if (cache[i].data == NULL)
5075 0 : return MSCB_NO_MEM;
5076 0 : memset(cache[i].data, 0, s);
5077 :
5078 : /* read initial value */
5079 0 : s = cache[i].size;
5080 0 : status = mscb_read(fd, adr, index, cache[i].data, &s);
5081 0 : if (status != MSCB_SUCCESS)
5082 0 : return status;
5083 :
5084 0 : memcpy(data, cache[i].data, size);
5085 : }
5086 :
5087 0 : debug_log("mscb_link return MSCB_SUCCESS", 0);
5088 :
5089 0 : return MSCB_SUCCESS;
5090 : }
5091 :
5092 :
5093 : /*------------------------------------------------------------------*/
5094 :
5095 : typedef struct {
5096 : char host_name[20];
5097 : char password[20];
5098 : unsigned char eth_mac_addr[6];
5099 : unsigned short magic;
5100 : } SUBM_CFG;
5101 :
5102 0 : int set_mac_address(int fd)
5103 : /********************************************************************\
5104 :
5105 : Routine: set_mac_address
5106 :
5107 : Purpose: Ask for hostname/password and set MAC configuration of
5108 : subm_260 interface over ethernet
5109 :
5110 : Input:
5111 : int fd File descriptor for connection
5112 : <parameters are asked interactively>
5113 :
5114 : Output:
5115 : None
5116 :
5117 : Function value:
5118 : MSCB_SUCCESS Successful completion
5119 : 0 Error
5120 :
5121 : \********************************************************************/
5122 : {
5123 : char str[256];
5124 : unsigned char buf[64];
5125 : SUBM_CFG cfg;
5126 : int n;
5127 : char *s;
5128 :
5129 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
5130 0 : return 0;
5131 :
5132 0 : if (mscb_fd[fd - 1].type != MSCB_TYPE_ETH) {
5133 0 : printf("This command only works on ethernet submasters.\n");
5134 0 : return 0;
5135 : }
5136 :
5137 0 : printf("Hostname (should be \"MSCBxxx\") : MSCB");
5138 0 : s = fgets(str, sizeof(str), stdin);
5139 0 : if (s == NULL) {
5140 0 : printf("Please enter hostname in the range MSCB000 to MSCB999\n");
5141 0 : return 0;
5142 : }
5143 0 : n = atoi(str);
5144 0 : if (n < 0 || n > 999) {
5145 0 : printf("Hostname must be in the range MSCB000 to MSCB999\n");
5146 0 : return 0;
5147 : }
5148 0 : snprintf(cfg.host_name, sizeof(cfg.host_name), "MSCB%03d", n);
5149 :
5150 0 : if (n < 500) {
5151 : /* PSI MAC pool */
5152 0 : cfg.eth_mac_addr[0] = 0x00;
5153 0 : cfg.eth_mac_addr[1] = 0x50;
5154 0 : cfg.eth_mac_addr[2] = 0xC2;
5155 0 : cfg.eth_mac_addr[3] = 0x46;
5156 0 : cfg.eth_mac_addr[4] = (unsigned char) (0xD0 | (n >> 8));
5157 0 : cfg.eth_mac_addr[5] = (unsigned char) (n & 0xFF);
5158 :
5159 0 : printf("MAC Address is 00-50-C2-46-%02X-%02X\n",
5160 0 : cfg.eth_mac_addr[4], cfg.eth_mac_addr[5]);
5161 : } else {
5162 : /* TRIUMF MAC pool */
5163 0 : cfg.eth_mac_addr[0] = 0x00;
5164 0 : cfg.eth_mac_addr[1] = 0x50;
5165 0 : cfg.eth_mac_addr[2] = 0xC2;
5166 0 : cfg.eth_mac_addr[3] = 0x6B;
5167 0 : cfg.eth_mac_addr[4] = (unsigned char) (0x50 | ((n - 500) >> 8));
5168 0 : cfg.eth_mac_addr[5] = (unsigned char) ((n - 500) & 0xFF);
5169 :
5170 0 : printf("MAC Address is 00-50-C2-6B-%02X-%02X\n",
5171 0 : cfg.eth_mac_addr[4], cfg.eth_mac_addr[5]);
5172 : }
5173 :
5174 0 : printf("Enter optional password : ");
5175 0 : s = fgets(str, sizeof(str), stdin);
5176 0 : if (s == NULL) {
5177 0 : printf("Null password?\n");
5178 0 : str[0] = 0;
5179 : }
5180 0 : if (strlen(str) > sizeof(cfg.password) - 1) {
5181 0 : printf("Password too long\n");
5182 0 : return 0;
5183 : }
5184 0 : while (strlen(str) > 0 &&
5185 0 : (str[strlen(str) - 1] == '\r' || str[strlen(str) - 1] == '\n'))
5186 0 : str[strlen(str) - 1] = 0;
5187 0 : strcpy(cfg.password, str);
5188 :
5189 0 : cfg.magic = 0x3412;
5190 :
5191 0 : buf[0] = MCMD_FLASH;
5192 0 : memcpy(buf + 1, &cfg, sizeof(cfg));
5193 0 : n = sizeof(buf);
5194 0 : mscb_exchg(fd, buf, &n, 1 + sizeof(cfg), RS485_FLAG_CMD);
5195 0 : if (n == 2 && buf[0] == MCMD_ACK) {
5196 0 : printf("\nConfiguration successfully downloaded.\n");
5197 0 : return MSCB_SUCCESS;
5198 : }
5199 :
5200 0 : printf("Error downloading configuration.\n");
5201 :
5202 0 : return 0;
5203 : }
5204 :
5205 : /*------------------------------------------------------------------*/
5206 :
5207 0 : void mscb_scan_udp()
5208 : /********************************************************************\
5209 :
5210 : Routine: mscb_scan_udp
5211 :
5212 : Purpose: Scan network for running ethernet submasters
5213 :
5214 : \********************************************************************/
5215 : {
5216 : char str[256];
5217 : unsigned char buf[256];
5218 : int i, n, rev, uptime;
5219 : struct hostent *phe;
5220 : struct sockaddr_in *psa_in;
5221 :
5222 : #ifdef _MSC_VER
5223 : {
5224 : WSADATA WSAData;
5225 :
5226 : /* Start windows sockets */
5227 : if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
5228 : return;
5229 : }
5230 : #endif
5231 :
5232 0 : mscb_fd[0].type = MSCB_TYPE_ETH;
5233 0 : mscb_fd[0].mutex = mscb_mutex_create("mscb");
5234 0 : mscb_fd[0].eth_max_retry = 5;
5235 0 : mscb_fd[0].fd = socket(AF_INET, SOCK_DGRAM, 0);
5236 0 : if (mscb_fd[0].fd == -1) {
5237 0 : printf("cannot create socket\n");
5238 0 : return;
5239 : }
5240 :
5241 0 : for (i = 0; i < 1000; i++) {
5242 0 : if (kbhit())
5243 0 : break;
5244 :
5245 0 : snprintf(str, sizeof(str), "MSCB%03d", i);
5246 0 : printf("Checking %s...\r", str);
5247 0 : fflush(stdout);
5248 :
5249 : /* retrieve destination address */
5250 0 : phe = gethostbyname(str);
5251 0 : if (phe == NULL)
5252 0 : continue;
5253 :
5254 0 : memset(&mscb_fd[0].eth_addr, 0, sizeof(mscb_fd[0].eth_addr));
5255 0 : psa_in = (struct sockaddr_in *) mscb_fd[0].eth_addr;
5256 0 : memcpy((char *) &(psa_in->sin_addr), phe->h_addr, phe->h_length);
5257 0 : psa_in->sin_port = htons((short) MSCB_NET_PORT);
5258 0 : psa_in->sin_family = AF_INET;
5259 :
5260 0 : buf[0] = MCMD_ECHO;
5261 0 : n = sizeof(buf);
5262 0 : mscb_exchg(1, buf, &n, 1, RS485_FLAG_CMD | RS485_FLAG_NO_RETRY);
5263 :
5264 0 : if (n >= 4) {
5265 0 : rev = (buf[2] << 8) + buf[3];
5266 0 : printf("Found %s, PV %d, Rev. 0x%04X", str, buf[1], rev);
5267 0 : if (n >= 8) {
5268 0 : uptime = (buf[7] << 0) + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
5269 0 : printf(", UT %dd %02dh %02dm %02ds",
5270 : uptime / (3600 * 24),
5271 0 : (uptime % (3600 * 24)) / 3600, (uptime % 3600) / 60,
5272 : (uptime % 60));
5273 : }
5274 0 : printf("\n");
5275 : }
5276 : }
5277 :
5278 0 : printf(" \n");
5279 0 : while (kbhit())
5280 0 : getch();
5281 : }
5282 :
5283 : /*------------------------------------------------------------------*/
5284 :
5285 0 : int mscb_subm_info(int fd)
5286 : /********************************************************************\
5287 :
5288 : Routine: mscb_subm_info
5289 :
5290 : Purpose: Show info for submaster
5291 :
5292 : \********************************************************************/
5293 : {
5294 : unsigned char buf[10];
5295 : int n, rev, uptime;
5296 :
5297 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type) {
5298 0 : debug_log("mscb_subm_info return MSCB_INVAL_PARAM", 0);
5299 0 : return MSCB_INVAL_PARAM;
5300 : }
5301 :
5302 0 : if (mscb_fd[fd - 1].type == MSCB_TYPE_ETH) {
5303 : int status;
5304 :
5305 0 : buf[0] = MCMD_ECHO;
5306 0 : n = sizeof(buf);
5307 0 : status = mscb_exchg(1, buf, &n, 1, RS485_FLAG_CMD | RS485_FLAG_NO_RETRY);
5308 :
5309 0 : if (status != MSCB_SUCCESS)
5310 0 : return status;
5311 :
5312 0 : if (n >= 4) {
5313 0 : rev = (buf[2] << 8) + buf[3];
5314 0 : printf("Submaster : %s\n", mscb_fd[fd - 1].device);
5315 0 : printf("Address : %s\n", inet_ntoa(((struct sockaddr_in *) mscb_fd[fd - 1].eth_addr)->sin_addr));
5316 0 : printf("Protocol version : %d\n", buf[1]);
5317 0 : printf("Revision : 0x%04X\n", rev);
5318 :
5319 0 : if (n == 8) {
5320 0 : uptime = (buf[7] << 0) + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
5321 0 : printf("Uptime : %dd %02dh %02dm %02ds\n",
5322 : uptime / (3600 * 24),
5323 0 : (uptime % (3600 * 24)) / 3600, (uptime % 3600) / 60,
5324 : (uptime % 60));
5325 : }
5326 : }
5327 :
5328 : }
5329 :
5330 0 : debug_log("mscb_subm_info return MSCB_SUCCESS", 0);
5331 0 : return MSCB_SUCCESS;
5332 : }
5333 :
5334 : /*------------------------------------------------------------------*/
5335 :
5336 0 : int mscb_set_time(int fd, int addr, int gaddr, int broadcast)
5337 : /********************************************************************\
5338 :
5339 : Routine: mscb_set_time
5340 :
5341 : Purpose: Set time of node equal to local time
5342 :
5343 : Input:
5344 : int fd File descriptor for connection
5345 : int addr Node address
5346 : int gaddr Group address
5347 : int broadcast Broadcast flag
5348 :
5349 : Function value:
5350 : MSCB_SUCCESS Successful completion
5351 : MSCB_MUTEX Cannot obtain mutex for mscb
5352 : MSCB_TIMEOUT Timeout receiving ping acknowledge
5353 :
5354 : \********************************************************************/
5355 : {
5356 : int i, size, status;
5357 : unsigned char buf[64], dt[10];
5358 : struct tm *ptm;
5359 : time_t now;
5360 :
5361 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
5362 0 : return MSCB_INVAL_PARAM;
5363 :
5364 : #ifdef HAVE_MRPC
5365 : if (mrpc_connected(fd))
5366 : return mrpc_call(mscb_fd[fd - 1].fd, RPC_MSCB_SET_TIME, mscb_fd[fd - 1].remote_fd, addr, gaddr, broadcast);
5367 : #endif
5368 :
5369 0 : tzset();
5370 0 : now = time(NULL);
5371 0 : ptm = localtime(&now);
5372 0 : dt[0] = (ptm->tm_mday / 10) * 0x10 + (ptm->tm_mday % 10);
5373 0 : dt[1] = ((ptm->tm_mon + 1) / 10) * 0x10 + ((ptm->tm_mon + 1) % 10);
5374 0 : dt[2] = ((ptm->tm_year - 100) / 10) * 0x10 + ((ptm->tm_year - 100) % 10);
5375 0 : dt[3] = (ptm->tm_hour / 10) * 0x10 + (ptm->tm_hour % 10);
5376 0 : dt[4] = (ptm->tm_min / 10) * 0x10 + (ptm->tm_min % 10);
5377 0 : dt[5] = (ptm->tm_sec / 10) * 0x10 + (ptm->tm_sec % 10);
5378 :
5379 0 : size = sizeof(buf);
5380 0 : if (addr >= 0) {
5381 0 : buf[0] = MCMD_ADDR_NODE16;
5382 0 : buf[1] = (unsigned char) (addr >> 8);
5383 0 : buf[2] = (unsigned char) (addr & 0xFF);
5384 0 : buf[3] = crc8(buf, 3);
5385 :
5386 0 : buf[4] = MCMD_SET_TIME;
5387 0 : for (i = 0; i < 6; i++)
5388 0 : buf[5 + i] = dt[i];
5389 0 : buf[11] = crc8(buf + 4, 7);
5390 0 : status = mscb_exchg(fd, buf, &size, 12, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
5391 0 : } else if (gaddr >= 0) {
5392 0 : buf[0] = MCMD_ADDR_GRP16;
5393 0 : buf[1] = (unsigned char) (gaddr >> 8);
5394 0 : buf[2] = (unsigned char) (gaddr & 0xFF);
5395 0 : buf[3] = crc8(buf, 3);
5396 :
5397 0 : buf[4] = MCMD_SET_TIME;
5398 0 : for (i = 0; i < 6; i++)
5399 0 : buf[5 + i] = dt[i];
5400 0 : buf[11] = crc8(buf + 4, 7);
5401 0 : status = mscb_exchg(fd, buf, &size, 12, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
5402 0 : } else if (broadcast) {
5403 0 : buf[0] = MCMD_ADDR_BC;
5404 0 : buf[1] = crc8(buf, 1);
5405 :
5406 0 : buf[2] = MCMD_SET_TIME;
5407 0 : for (i = 0; i < 6; i++)
5408 0 : buf[3 + i] = dt[i];
5409 0 : buf[9] = crc8(buf + 2, 7);
5410 0 : status = mscb_exchg(fd, buf, &size, 10, RS485_FLAG_NO_ACK | RS485_FLAG_ADR_CYCLE);
5411 : } else
5412 0 : status = MSCB_INVAL_PARAM;
5413 :
5414 0 : return status;
5415 : }
5416 :
5417 : /*------------------------------------------------------------------*/
5418 :
5419 0 : int mscb_clear_log(int fd, unsigned short adr)
5420 : /********************************************************************\
5421 :
5422 : Routine: mscb_clear_log
5423 :
5424 : Purpose: Clears the log on the addressed node
5425 :
5426 : Input:
5427 : int fd File descriptor for connection
5428 : unsigned short adr Node address
5429 :
5430 : Output:
5431 : None
5432 :
5433 : Function value:
5434 : MSCB_SUCCESS Successful completion
5435 : MSCB_TIMEOUT Timeout receiving data
5436 : MSCB_CRC_ERROR CRC error
5437 : MSCB_MUTEX Cannot obtain mutex for mscb
5438 : MSCB_INVAL_PARAM Invalid parameters
5439 :
5440 : \********************************************************************/
5441 : {
5442 0 : int size = 0, retry;
5443 : unsigned char buf[256];
5444 :
5445 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
5446 0 : return MSCB_INVAL_PARAM;
5447 :
5448 0 : for (retry = 0; retry < mscb_max_retry; retry++) {
5449 0 : buf[0] = MCMD_ADDR_NODE16;
5450 0 : buf[1] = (unsigned char) (adr >> 8);
5451 0 : buf[2] = (unsigned char) (adr & 0xFF);
5452 0 : buf[3] = crc8(buf, 3);
5453 :
5454 0 : buf[4] = MCMD_LOG;
5455 0 : buf[5] = 1; // clear log
5456 0 : buf[6] = crc8(buf + 4, 2);
5457 :
5458 0 : size = sizeof(buf);
5459 0 : mscb_exchg(fd, buf, &size, 7, RS485_FLAG_ADR_CYCLE);
5460 :
5461 0 : if (size == 2 && buf[0] == MCMD_ACK)
5462 0 : break;
5463 : }
5464 :
5465 0 : if (size < 2)
5466 0 : return MSCB_TIMEOUT;
5467 :
5468 : /* do CRC check */
5469 0 : if (crc8(buf, size - 1) != buf[size - 1])
5470 0 : return MSCB_CRC_ERROR;
5471 :
5472 0 : return MSCB_SUCCESS;
5473 : }
5474 :
5475 : /*------------------------------------------------------------------*/
5476 :
5477 0 : int mscb_read_log(int fd, unsigned short adr, void *dataBuf, int bufsize)
5478 : /********************************************************************\
5479 :
5480 : Routine: mscb_ReadLog
5481 :
5482 : Purpose: Reads the log from the addressed node
5483 :
5484 : Input:
5485 : int fd File descriptor for connection
5486 : unsigned short adr Node address
5487 :
5488 : Output:
5489 : void* dataBuf log data
5490 : int bufsize buffersize
5491 :
5492 : Function value:
5493 : MSCB_SUCCESS Successful completion
5494 : MSCB_TIMEOUT Timeout receiving data
5495 : MSCB_CRC_ERROR CRC error
5496 : MSCB_MUTEX Cannot obtain mutex for mscb
5497 : MSCB_INVAL_PARAM Invalid parameters
5498 :
5499 : \********************************************************************/
5500 : {
5501 : int retry;
5502 0 : unsigned char *buf = (unsigned char *) dataBuf;
5503 :
5504 0 : if (fd > MSCB_MAX_FD || fd < 1 || !mscb_fd[fd - 1].type)
5505 0 : return MSCB_INVAL_PARAM;
5506 :
5507 0 : for (retry = 0; retry < mscb_max_retry; retry++) {
5508 0 : buf[0] = MCMD_ADDR_NODE16;
5509 0 : buf[1] = (unsigned char) (adr >> 8);
5510 0 : buf[2] = (unsigned char) (adr & 0xFF);
5511 0 : buf[3] = crc8(buf, 3);
5512 :
5513 0 : buf[4] = MCMD_LOG;
5514 0 : buf[5] = 0; // read log
5515 0 : buf[6] = crc8(buf + 4, 2);
5516 :
5517 0 : mscb_exchg(fd, buf, &bufsize, 7, RS485_FLAG_ADR_CYCLE);
5518 :
5519 0 : if (bufsize > 0 && buf[0] == (MCMD_ACK + 7))
5520 0 : break;
5521 : }
5522 :
5523 0 : if (bufsize < 2)
5524 0 : return MSCB_TIMEOUT;
5525 :
5526 : /* do CRC check */
5527 0 : if (crc8(buf, bufsize - 1) != buf[bufsize - 1])
5528 0 : return MSCB_CRC_ERROR;
5529 :
5530 0 : return MSCB_SUCCESS;
5531 : }
5532 :
5533 : /*------------------------------------------------------------------*/
|