LCOV - code coverage report
Current view: top level - mscb/src - mscb.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 2411 0
Test Date: 2025-11-11 10:26:08 Functions: 0.0 % 63 0

            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              : /*------------------------------------------------------------------*/
        

Generated by: LCOV version 2.0-1