LCOV - code coverage report
Current view: top level - apps/zaberLowLevel - za_serial.c (source / functions) Coverage Total Hit
Test: MagAOX Lines: 0.0 % 181 0
Test Date: 2026-01-03 21:03:39 Functions: 0.0 % 12 0

            Line data    Source code
       1              : /*
       2              :  * \file za_serial.c
       3              :  * \author Eric Dand
       4              :  * \version 1.0
       5              :  * \date 28 November 2014
       6              :  * \copyright Apache Software License Version 2.0
       7              :  *
       8              :  * Implementation file for ASCII portion of the Zaber Serial API in C.
       9              :  * See za_serial.h for documentation.
      10              :  */
      11              : #include <string.h>
      12              : #include <stdio.h>
      13              : #include <stdlib.h>
      14              : #include "za_serial.h"
      15              : 
      16              : static int za_verbose = 1;
      17              : 
      18            0 : void za_set_verbose(int value)
      19              : {
      20            0 :         za_verbose = value;
      21            0 : }
      22              : 
      23              : 
      24              : #include <fcntl.h>
      25              : #include <sys/stat.h>
      26              : #include <sys/types.h>
      27              : #include <termios.h>
      28              : #include <unistd.h>
      29              : 
      30              : #if defined(NDEBUG)
      31              : #define PRINT_ERROR(M)
      32              : #define PRINTF_ERROR(M, ...)
      33              : #define PRINT_SYSCALL_ERROR(M)
      34              : #else
      35              : #define PRINT_ERROR(M) do { if (za_verbose) { fprintf(stderr, "(%s: %d) " M\
      36              :                 "\n", __FILE__, __LINE__); } } while(0)
      37              : #define PRINTF_ERROR(M, ...) do { if (za_verbose) { fprintf(stderr,\
      38              :                 "(%s: %d) " M "\n", __FILE__, __LINE__,  __VA_ARGS__); } } while(0)
      39              : #include <errno.h>
      40              : #define PRINT_SYSCALL_ERROR(M) do { if (za_verbose) {\
      41              :                 fprintf(stderr, "(%s: %d) [ERROR] " M " failed: %s.\n",\
      42              :                 __FILE__, __LINE__, strerror(errno)); } } while(0)
      43              : #endif
      44              : /* A little sugar for checking return values from system calls.
      45              :  * I would have liked to use GNU/GCC's "statement expressions" so that one
      46              :  * do something like "z_port port = SYSCALL(open([parameters]))", but they're
      47              :  * a GNU extension, and therefore unfriendly to non-GCC compilers.
      48              :  * Workaround to avoid dependence on statement expressions for SYSCALL macro:
      49              :  * use SYSCALL on result of assignment instead. */
      50              : #define SYSCALL(F) do { if ((F) < 0) { PRINT_SYSCALL_ERROR(#F);\
      51              :                 return Z_ERROR_SYSTEM_ERROR; } } while(0)
      52              : 
      53            0 : int za_connect(z_port *port, const char *port_name)
      54              : {
      55              :         struct termios tio, orig_tio;
      56              : 
      57            0 :         if (port == NULL || port_name == NULL)
      58              :         {
      59              :                 PRINT_ERROR("[ERROR] port and port_name cannot be NULL.");
      60            0 :                 return Z_ERROR_NULL_PARAMETER;
      61              :         }
      62              : 
      63              :         /* blocking read/write */
      64            0 :         SYSCALL(*port = open(port_name, O_RDWR | O_NOCTTY));
      65            0 :         SYSCALL(tcgetattr(*port, &orig_tio));
      66            0 :         memcpy(&tio, &orig_tio, sizeof(struct termios)); /* copy padding too */
      67              : 
      68              :         /* cfmakeraw() without cfmakeraw() for cygwin compatibility */
      69            0 :         tio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR
      70              :                         | IGNCR | ICRNL | IXON);
      71            0 :         tio.c_oflag &= ~OPOST;
      72            0 :         tio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
      73            0 :         tio.c_cflag &= ~(CSIZE | PARENB);
      74              :         /* end cfmakeraw() */
      75            0 :         tio.c_cflag = CS8|CREAD|CLOCAL;
      76              : 
      77              :         /* READ_TIMEOUT is defined in za_serial.h */
      78              :         if (READ_TIMEOUT % 100 != 0)
      79              :         {
      80              :                 tio.c_cc[VTIME] = READ_TIMEOUT / 100 + 1; /* Round up */
      81              :         }
      82              :         else
      83              :         {
      84            0 :                 tio.c_cc[VTIME] = READ_TIMEOUT / 100;
      85              :         }
      86            0 :         tio.c_cc[VMIN] = 0;
      87              : 
      88            0 :         SYSCALL(cfsetospeed(&tio, B115200) & cfsetispeed(&tio, B115200));
      89              : 
      90            0 :         while(memcmp(&orig_tio, &tio, sizeof(struct termios)) != 0)
      91              :         { /* memcmp is only OK here because we used memcpy above */
      92            0 :                 SYSCALL(tcsetattr(*port, TCSAFLUSH, &tio));
      93            0 :                 SYSCALL(tcgetattr(*port, &orig_tio));
      94              :         }
      95              : 
      96            0 :         return Z_SUCCESS;
      97              : }
      98              : 
      99            0 : int za_disconnect(z_port port)
     100              : {
     101            0 :         SYSCALL(close(port));
     102            0 :         return Z_SUCCESS;
     103              : }
     104              : 
     105              : /* a subtle feature of za_send() that is implied but not explicitly documented:
     106              :  * if you pass a pointer to a 0-length string (ie. just a \0) for command,
     107              :  * za_send() will send the minimal command of "/\n" automagically, as it will
     108              :  * assume you are sending a command without content, and that you have
     109              :  * forgotten the leading '/' and trailing '\n'. Mention of this is probably
     110              :  * best left out of the official docs since it's a hacky way to use za_send().
     111              :  */
     112            0 : int za_send( z_port port,
     113              :              const char *command,
     114              :              size_t sMaxSz
     115              :            )
     116              : {
     117              :         int nlast,
     118              :                 length,
     119            0 :                 written = 0;
     120              : 
     121            0 :         if (command == NULL)
     122              :         {
     123              :                 PRINT_ERROR("[ERROR] command cannot be NULL.");
     124            0 :                 return Z_ERROR_NULL_PARAMETER;
     125              :         }
     126              : 
     127            0 :         if (command[0] != '/')
     128              :         { /* send a '/' if they forgot it */
     129            0 :                 SYSCALL(nlast = write(port, "/", 1));
     130            0 :                 written += nlast;
     131              :         }
     132            0 :         length = strnlen(command, sMaxSz);
     133            0 :         SYSCALL(nlast = write(port, command, length));
     134            0 :         written += nlast;
     135            0 :         if (nlast != length)
     136              :         { /* write can return a short write: test for it */
     137              :                 PRINTF_ERROR("[ERROR] write did not write entire message: "
     138              :                                 "could only write %d bytes of %d.", nlast, length);
     139            0 :                 return Z_ERROR_SYSTEM_ERROR;
     140              :         }
     141              : 
     142            0 :         if (length == 0 || command[length-1] != '\n')
     143              :         { /* send a newline if they forgot it */
     144            0 :                 SYSCALL(nlast = write(port, "\n", 1));
     145            0 :                 written += nlast;
     146              :         }
     147              : 
     148            0 :         return written;
     149              : }
     150              : 
     151            0 : int za_receive(z_port port, char *destination, int length)
     152              : {
     153            0 :         int nread = 0,
     154              :                 nlast;
     155              :         char c;
     156              : 
     157              :         for (;;)
     158              :         {
     159            0 :                 SYSCALL(nlast = (int) read(port, &c, 1));
     160              : 
     161            0 :                 if (nlast == 0) /* timed out */
     162              :                 {
     163              :                         //PRINTF_ERROR("[INFO] Read timed out after reading %d "
     164              :                         //              "bytes.", nread);
     165            0 :                         return Z_ERROR_TIMEOUT;
     166              :                 }
     167              : 
     168            0 :                 if (destination != NULL)
     169              :                 {
     170            0 :                         destination[nread] = c;
     171              :                 }
     172            0 :                 nread += nlast;
     173              : 
     174            0 :                 if (nread == length)
     175              :                 {
     176              :                         PRINTF_ERROR("[ERROR] Read destination buffer not large "
     177              :                                         "enough. Recommended size: 256B. Your size: %dB.",
     178              :                                         length);
     179            0 :                         return Z_ERROR_BUFFER_TOO_SMALL;
     180              :                 }
     181              : 
     182            0 :                 if (c == '\n')
     183              :                 {
     184            0 :                         nread -= 2; /* prepare to cut off the "\r\n" */
     185            0 :                         if (nread < 0)
     186              :                         {
     187              :                                 PRINT_ERROR("[ERROR] Reply too short. It is likely that "
     188              :                                                 "only a partial reply was read.");
     189            0 :                                 return Z_ERROR_SYSTEM_ERROR;
     190              :                         }
     191            0 :                         if (destination != NULL)
     192              :                         {
     193            0 :                                 destination[nread] = '\0'; /* chomp the "\r\n" */
     194              :                         }
     195            0 :                         return nread;
     196              :                 }
     197              :         }
     198              : }
     199              : 
     200            0 : int za_setbaud(z_port port, int baud)
     201              : {
     202              :         struct termios tio;
     203              :         speed_t tbaud;
     204            0 :         switch (baud)
     205              :         {
     206            0 :                 case 9600:
     207            0 :                         tbaud = B9600;
     208            0 :                         break;
     209            0 :                 case 19200:
     210            0 :                         tbaud = B19200;
     211            0 :                         break;
     212            0 :                 case 38400:
     213            0 :                         tbaud = B38400;
     214            0 :                         break;
     215            0 :                 case 57600:
     216            0 :                         tbaud = B57600;
     217            0 :                         break;
     218            0 :                 case 115200:
     219            0 :                         tbaud = B115200;
     220            0 :                         break;
     221            0 :                 default:
     222              :                         PRINTF_ERROR("[ERROR] Invalid baud rate. Valid rates are "
     223              :                                                 "9600, 19200, 38400, 57600, and 115200 (default).\n"
     224              :                                                 "Your rate: %d.", baud);
     225            0 :                         return Z_ERROR_INVALID_BAUDRATE;
     226              :         }
     227              : 
     228            0 :         SYSCALL(tcgetattr(port, &tio));
     229            0 :         SYSCALL(cfsetospeed(&tio, tbaud) & cfsetispeed(&tio, tbaud));
     230            0 :         SYSCALL(tcsetattr(port, TCSAFLUSH, &tio));
     231              : 
     232            0 :         return Z_SUCCESS;
     233              : }
     234              : 
     235            0 : int za_drain(z_port port)
     236              : {
     237              :         struct termios tio;
     238              :         int old_timeout;
     239              :         char c;
     240              : 
     241              :         /* set timeout to 0.1s */
     242            0 :         SYSCALL(tcgetattr(port, &tio));
     243            0 :         old_timeout = tio.c_cc[VTIME];
     244            0 :         tio.c_cc[VTIME] = 1;
     245            0 :         SYSCALL(tcsetattr(port, TCSANOW, &tio));
     246              : 
     247              :         /* flush and read whatever else comes in */
     248            0 :         SYSCALL(tcflush(port, TCIFLUSH));
     249            0 :         while(read(port, &c, 1) > 0);
     250              : 
     251              :         /* set timeout back to what it was */
     252            0 :         tio.c_cc[VTIME] = old_timeout;
     253            0 :         SYSCALL(tcsetattr(port, TCSANOW, &tio));
     254              : 
     255            0 :         return Z_SUCCESS;
     256              : }
     257              : 
     258              : 
     259              : /* A helper for za_decode. Copies from source to destination, until delim or
     260              :  * a '\0' is found, then null-terminates destination.
     261              :  *
     262              :  * Returns the number of bytes copied, including the added null-terminator. */
     263            0 : static size_t copy_until_delim(char *destination, const char *source,
     264              :                 const char delim, size_t destination_length)
     265              : {
     266              :         size_t i;
     267              : 
     268            0 :         for(i = 0; source[i] != delim && source[i] != '\0'
     269            0 :                         && i < destination_length - 1; i++)
     270              :         {
     271            0 :                 destination[i] = source[i];
     272              :         }
     273              : 
     274            0 :         destination[i] = '\0'; /* null-terminate instead of copying delim */
     275              : 
     276            0 :         return i + 1;
     277              : }
     278              : 
     279            0 : static int decode_reply( struct za_reply *destination,
     280              :                          const char *reply,
     281              :                          size_t sMaxSz
     282              :                        )
     283              : {
     284              :         char buffer[8]; /* needs to be at least 5B: set to 8 because
     285              :                                            it will be padded to 8 from 5 anyway. */
     286              :         size_t offset,
     287              :                    length;
     288              : 
     289            0 :         if (strnlen(reply, sMaxSz) < 18)
     290              :         {
     291              :                 PRINTF_ERROR("[ERROR] Reply could not be decoded: shorter than expected. "
     292              :                                 "It is likely that only a partial reply was read.\n"
     293              :                                 "Reply value: %s", reply);
     294            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     295              :         }
     296              : 
     297            0 :         destination->message_type = '@';
     298              : 
     299              :         /* device address: 2 digits, 00-99
     300              :          *
     301              :          * The device address is part of the same "token" as the message type,
     302              :          * so we call strtol on the same token, skipping the first char.
     303              :          *
     304              :          * We don't check the length here for future-proofing:
     305              :          * if we add support for more device addresses (ie. more digits),
     306              :          * this should handle it gracefully. */
     307            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     308            0 :         destination->device_address = (int) strtol(buffer + 1, NULL, 10);
     309            0 :         reply += offset;
     310              : 
     311              :         /* axis number: 1 digit, 0-9
     312              :          *
     313              :          * The axis number may be 2 digits (or more) in the future, but it's
     314              :          * unlikely to go over 2^31 - 1 any time soon, so we convert to
     315              :          * standard int and use that. */
     316            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     317            0 :         destination->axis_number = (int) strtol(buffer, NULL, 10);
     318            0 :         reply += offset;
     319              : 
     320              :         /* reply flags: 2 letters
     321              :          *
     322              :          * Only replies have reply flags. Value is either "OK" or "RJ". */
     323            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     324            0 :         if (offset > sizeof(destination->reply_flags))
     325              :         {
     326              :                 PRINTF_ERROR("[ERROR] Reply could not be decoded: reply flags too "
     327              :                                 "long. Maximum length: %zu. Your length: %zu. Reply flags "
     328              :                                 "value: %s\n.", sizeof(destination->reply_flags), offset,
     329              :                                 buffer);
     330            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     331              :         }
     332            0 :         strcpy(destination->reply_flags, buffer);
     333            0 :         reply += offset;
     334              : 
     335              :         /* device status: 4 letters
     336              :          *
     337              :          * Replies and alerts have a "status" field. Value is either "IDLE" or
     338              :          * "BUSY", depending on what the device is doing at the time. */
     339            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     340            0 :         if (offset > sizeof(destination->device_status))
     341              :         {
     342              :                 PRINTF_ERROR("[ERROR] Reply could not be decoded: device status too "
     343              :                                 "long. Expected length: %zu. Your length: %zu. Device status "
     344              :                                 "value: %s\n.", sizeof(destination->device_status), offset,
     345              :                                 buffer);
     346            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     347              :         }
     348            0 :         strcpy(destination->device_status, buffer);
     349            0 :         reply += offset;
     350              : 
     351              :         /* warning flags: 2 letters
     352              :          *
     353              :          * Replies and alerts have warning flags. Warning flags are typically
     354              :          * "--". All other possible warning flag values should be two
     355              :          * consecutive capital letters. */
     356            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     357            0 :         if (offset > sizeof(destination->warning_flags))
     358              :         {
     359              :                 PRINTF_ERROR("[ERROR] Reply could not be decoded: warning flags too "
     360              :                                 "long. Expected length: %zu. Your length: %zu. Warning flags "
     361              :                                 "value: %s\n.", sizeof(destination->warning_flags), offset,
     362              :                                 buffer);
     363            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     364              :         }
     365            0 :         strcpy(destination->warning_flags, buffer);
     366            0 :         reply += offset;
     367              : 
     368              :         /* data: 1+ characters, probably less than 128 characters
     369              :          *
     370              :          * Replies and info have data. This can be anything, including spaces,
     371              :          * numbers, and human-readable text. */
     372            0 :         length = strnlen(reply, sMaxSz); /* get length of remaining data */
     373            0 :         if (length > sizeof(destination->response_data))
     374              :         {
     375              :                 PRINTF_ERROR("[ERROR] Reply could not be decoded: response data too "
     376              :                                 "long. Maximum length: %zu. Your length: %zu. Data: %s.\n",
     377              :                                 sizeof(destination->response_data), length, reply);
     378            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     379              :         }
     380            0 :         strcpy(destination->response_data, reply);
     381              : 
     382            0 :         return Z_SUCCESS;
     383              : 
     384              : }
     385              : 
     386            0 : static int decode_alert( struct za_reply *destination,
     387              :                          const char *reply,
     388              :                          size_t sMaxSz
     389              :                        )
     390              : {
     391              :         size_t offset;
     392              :         char buffer[8]; /* needs to be at least 5B: set to 8 because
     393              :                                            it will be padded to 8 from 5 anyway. */
     394              : 
     395            0 :         if (strnlen(reply, sMaxSz) < 13)
     396              :         {
     397              :                 PRINTF_ERROR("[ERROR] Reply could not be decoded: shorter than expected. "
     398              :                                 "It is likely that only a partial reply was read.\n"
     399              :                                 "Reply value: %s", reply);
     400            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     401              :         }
     402              : 
     403            0 :         destination->message_type = '!';
     404              : 
     405              :         /* device address: 2 digits, 00-99
     406              :          *
     407              :          * The device address is part of the same "token" as the message type,
     408              :          * so we call strtol on the same token, skipping the first char.
     409              :          *
     410              :          * We don't check the length here for future-proofing:
     411              :          * if we add support for more device addresses (ie. more digits),
     412              :          * this should handle it gracefully. */
     413            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     414            0 :         destination->device_address = (int) strtol(buffer + 1, NULL, 10);
     415            0 :         reply += offset;
     416              : 
     417              :         /* axis number: 1 digit, 0-9
     418              :          *
     419              :          * The axis number may be 2 digits (or more) in the future, but it's
     420              :          * unlikely to go over 2^31 - 1 any time soon, so we convert to
     421              :          * standard int and use that. */
     422            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     423            0 :         destination->axis_number = (int) strtol(buffer, NULL, 10);
     424            0 :         reply += offset;
     425              : 
     426            0 :         destination->reply_flags[0] = '\0';
     427              : 
     428              :         /* device status: 4 letters
     429              :          *
     430              :          * Replies and alerts have a "status" field. Value is either "IDLE" or
     431              :          * "BUSY", depending on what the device is doing at the time. */
     432            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     433            0 :         if (offset > sizeof(destination->device_status))
     434              :         {
     435              :                 PRINTF_ERROR("[ERROR] Reply could not be decoded: device status too "
     436              :                                 "long. Expected length: %zu. Your length: %zu. Device status "
     437              :                                 "value: %s\n.", sizeof(destination->device_status), offset,
     438              :                                 buffer);
     439            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     440              :         }
     441            0 :         strcpy(destination->device_status, buffer);
     442            0 :         reply += offset;
     443              : 
     444              :         /* warning flags: 2 letters
     445              :          *
     446              :          * Replies and alerts have warning flags. Warning flags are typically
     447              :          * "--". All other possible warning flag values should be two
     448              :          * consecutive capital letters. */
     449            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     450            0 :         if (offset > sizeof(destination->warning_flags))
     451              :         {
     452              :                 PRINTF_ERROR("[ERROR] Reply could not be decoded: warning flags too "
     453              :                                 "long. Expected length: %zu. Your length: %zu. Warning flags "
     454              :                                 "value: %s\n.", sizeof(destination->warning_flags), offset,
     455              :                                 buffer);
     456            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     457              :         }
     458            0 :         strcpy(destination->warning_flags, buffer);
     459              : 
     460            0 :         destination->response_data[0] = '\0';
     461              : 
     462            0 :         return Z_SUCCESS;
     463              : }
     464              : 
     465            0 : static int decode_info( struct za_reply *destination,
     466              :                         const char *reply,
     467              :                         size_t sMaxSz
     468              :                       )
     469              : {
     470              :         size_t length,
     471              :                    offset;
     472              :         char buffer[8]; /* needs to be at least 5B: set to 8 because
     473              :                                            it will be padded to 8 from 5 anyway. */
     474              : 
     475            0 :         if (strnlen(reply, sMaxSz) < 7)
     476              :         {
     477              :                 PRINTF_ERROR("[ERROR] Reply could not be decoded: shorter than expected. "
     478              :                                 "It is likely that only a partial reply was read.\n"
     479              :                                 "Reply value: %s", reply);
     480            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     481              :         }
     482              : 
     483            0 :         destination->message_type = '#';
     484              : 
     485              :         /* device address: 2 digits, 00-99
     486              :          *
     487              :          * The device address is part of the same "token" as the message type,
     488              :          * so we call strtol on the same token, skipping the first char.
     489              :          *
     490              :          * We don't check the length here for future-proofing:
     491              :          * if we add support for more device addresses (ie. more digits),
     492              :          * this should handle it gracefully. */
     493            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     494            0 :         destination->device_address = (int) strtol(buffer + 1, NULL, 10);
     495            0 :         reply += offset;
     496              : 
     497              :         /* axis number: 1 digit, 0-9
     498              :          *
     499              :          * The axis number may be 2 digits (or more) in the future, but it's
     500              :          * unlikely to go over 2^31 - 1 any time soon, so we convert to
     501              :          * standard int and use that. */
     502            0 :         offset = copy_until_delim(buffer, reply, ' ', sizeof(buffer));
     503            0 :         destination->axis_number = (int) strtol(buffer, NULL, 10);
     504            0 :         reply += offset;
     505              : 
     506            0 :         destination->reply_flags[0] = '\0';
     507            0 :         destination->device_status[0] = '\0';
     508            0 :         destination->warning_flags[0] = '\0';
     509              : 
     510              :         /* data: 1+ characters, probably less than 128 characters
     511              :          *
     512              :          * Replies and info have data. This can be anything, including spaces,
     513              :          * numbers, and human-readable text. */
     514            0 :         length = strnlen(reply,sMaxSz); /* get length of remaining data */
     515            0 :         if (length > sizeof(destination->response_data))
     516              :         {
     517              :                 PRINTF_ERROR("[ERROR] Reply could not be decoded: response data too "
     518              :                                 "long. Maximum length: %zu. Your length: %zu. Data: %s.\n",
     519              :                                 sizeof(destination->response_data), length, reply);
     520            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     521              :         }
     522            0 :         strcpy(destination->response_data, reply);
     523              : 
     524            0 :         return Z_SUCCESS;
     525              : }
     526              : 
     527              : /* This function tokenizes using the above helper function to copy
     528              :  * token-by-token from reply into buffer, or directly into destination,
     529              :  * depending on the field in destination we are populating. It could probably
     530              :  * be prettier, more clever, or more efficient, but it's written to be
     531              :  * readable, reliable, and robust first.
     532              :  *
     533              :  * Note that we can safely use strcpy here because the above helper function is
     534              :  * guaranteed to write a NUL at the end of its destination string.
     535              :  *
     536              :  * See http://www.zaber.com/wiki/Manuals/ASCII_Protocol_Manual#Replies for
     537              :  * more info on replies.
     538              :  */
     539            0 : int za_decode( struct za_reply *destination,
     540              :                const char *reply,
     541              :                size_t sMaxSz
     542              :              )
     543              : {
     544              :         char message_type;
     545              : 
     546            0 :         if (destination == NULL || reply == NULL)
     547              :         {
     548              :                 PRINT_ERROR("[ERROR] decoding requires both a non-NULL destination "
     549              :                                 "and reply to decode.");
     550            0 :                 return Z_ERROR_NULL_PARAMETER;
     551              :         }
     552              : 
     553            0 :         if (strnlen(reply, sMaxSz) == 0)
     554              :         {
     555              :                 PRINT_ERROR("[ERROR] Reply could not be decoded: no data.");
     556            0 :                 return Z_ERROR_COULD_NOT_DECODE;
     557              :         }
     558            0 :         message_type = reply[0];
     559              : 
     560              :         /* most replies are 18 chars or longer: info and alerts can be shorter */
     561            0 :         switch(message_type)
     562              :         {
     563            0 :                 case '@':
     564            0 :                         return decode_reply(destination, reply, sMaxSz);
     565            0 :                 case '!':
     566            0 :                         return decode_alert(destination, reply, sMaxSz);
     567            0 :                 case '#':
     568            0 :                         return decode_info(destination, reply, sMaxSz);
     569            0 :                 default:
     570              :                         PRINTF_ERROR("[ERROR] Reply could not be decoded: unexpected "
     571              :                                         "message type. Valid types are '@' (reply), '!' (alert), "
     572              :                                         "and '#' (info). Your type: '%c'. \n", message_type);
     573            0 :                         return Z_ERROR_COULD_NOT_DECODE;
     574              :         }
     575              : }
        

Generated by: LCOV version 2.0-1