1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 <2019> 2020 2021 2022 2023 2024 2025 | Index | 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 <2019> 2020 2021 2022 2023 2024 2025 |
<== Date ==> | <== Thread ==> |
---|
Subject: | Re: StreamDevice for an odd float format |
From: | "Davis, Mark via Tech-talk" <[email protected]> |
To: | "Brown, Garth" <[email protected]>, "[email protected]" <[email protected]> |
Date: | Wed, 5 Jun 2019 20:01:31 +0000 |
You can add your own format converters to StreamDevice. John Priller ([email protected]) at our lab has written the code for several odd format like this (see attached code). I believe the one you want is the %ZHF one. Mark Mark Davis NSCL/FRIB Control Systems Software Engineer
[email protected]
On 6/5/2019 1:58 PM, Brown, Garth via Tech-talk wrote:
|
/* NSCL StreamDevice format converters Uses 'Z' stream format character. The following are provided: %ZDC(s,n) decimal checksum (sum of bytes mod 256) s : starting position in read/write buffer, 0=beginning n : number of characters to calculate checksum for Needed by Pfeiffer vacuum protocol width and 0-pad format spec/flag are honored example: %03ZDC would be 3-character string, 0-padded %ZDS HA5/DS1820 thermocouple format (hex-coded "scratchpad" buffer) %ZHF Hex-coded 8-character float (4 bytes) %[-][size]ZHL Hex-coded long - : treat as signed (for < 8 chars, 8-char longs are always signed) size is number of chars to read, '0F1A' = 4 chars (2 hex-coded bytes) if size not specified goes to whichever encounters first 8 characters read (4 bytes) end of input first non hex-coded char pair %[#][size]ZHS Hex-coded ascii text string # : trim leading/trailing whitespace (on reads only) size is number of chars to read, '6533' = 4 chars (2 hex-coded bytes) if size not specified goes to whichever encounters first end of input first non hex-coded char pair hex-coded NULL (00 pair) (consumed) %ZSR(a,d,m) SMDP (Sycon Multi-drop Prococol) send or receive string for reading values a : 2-hex-char address of slave device (10 .. FE) d : 6-hex-char code for dictionary entry desired m : 2-hex-char message id to send/expect always returns a signed 32-bit integer %ZC8(s,n,p) Generic 1-byte CRC s : starting position in read/write buffer, 0=beginning n : number of characters to calculate CRC for p : 2-char hex polynomial ('18' = 0x18) History: 2015-02-26 J. Priller added ZDC 2012-11-16 J. Priller added zFormatData so not parsing every call to scan/print 2012-11-14 J. Priller added ZC8 2012-06-06 J. Priller added ZSR 2011-12-15 J. Priller original version */ #include <ctype.h> #include <stdlib.h> #include "StreamError.h" #include "StreamFormatConverter.h" #include <nsclfribCommon.h> #define IS_NAME_CHAR(cc) (((cc >= 'a') && (cc <= 'z')) || ((cc >= 'A') && (cc <= 'Z')) || ((cc >= '0') && (cc <= '9'))) // detect if Stream > 2.7, different types defined #include "devStream.h" #define STREAM_VERSION_LONG ( STREAM_MAJOR*10000 + STREAM_MINOR*100 + STREAM_PATCHLEVEL ) #if (STREAM_VERSION_LONG >= 20700) #define LONG_FORMAT signed_format #else #define LONG_FORMAT long_format #endif //---------------------------------------------------------------------- // internal routines //---------------------------------------------------------------------- static void trimString(char *str) { // eliminate leading whitespace int jj = 0; while ((str[jj] == ' ') || (str[jj] == 0x09)) jj++; if (jj > 0) memmove(str,str+jj,strlen(str)-jj+1); // eliminate trailing whitespace int xx = strlen(str) - 1; while ((xx >= 0) && ((str[xx] == ' ') || (str[xx] == 0x09))) { str[xx] = 0; xx--; } } //---------------------------------------------------------------------- static void toHex(unsigned char c, char *str) { int hsn = (c & 0x00F0) >> 4; int lsn = (c & 0x000F); str[0] = (hsn <= 9) ? (hsn + '0') : (hsn - 10 + 'A'); str[1] = (lsn <= 9) ? (lsn + '0') : (lsn - 10 + 'A'); str[2] = 0; } //---------------------------------------------------------------------- static int unhexChar(const char ch) { if ((ch >= '0') && (ch <= '9')) return(ch - '0'); if ((ch >= 'A') && (ch <= 'F')) return(ch - 'A' + 10); if ((ch >= 'a') && (ch <= 'f')) return(ch - 'a' + 10); return(-1); // error } //---------------------------------------------------------------------- static bool unhexString(const char *pc, int count, unsigned long *value) { (*value) = 0; unsigned long N = 0; for (int ii = 0; ii < count; ii++) { int cv = unhexChar(pc[ii]); if (cv < 0) { error("invalid hexcode char (%c) in input\n",pc[ii]); return(false); } N <<= 4; N |= cv; } (*value) = N; return(true); } //---------------------------------------------------------------------- static bool unhexPair(const char *pc, unsigned char *value) { unsigned long V; if (! unhexString(pc,2,&V)) return(false); (*value) = (V & 0x00FF); return(true); } //---------------------------------------------------------------------- static bool isHexPair(const char *pc) { if (unhexChar(*pc) < 0) return(false); pc++; if (unhexChar(*pc) < 0) return(false); return(true); } //---------------------------------------------------------------------- static void encodeHex(const char *pc, int count, StreamBuffer& info) { for (int ii = 0; ii < count; ii++) { char tmp[16]; toHex(pc[ii],tmp); info.append(tmp); } } //---------------------------------------------------------------------- static bool decodeHex(const StreamBuffer& info, int count, char *pc) { int idx = 0; int kk = 0; while (idx < count) { char hvCh = info[idx++]; char lvCh = info[idx++]; int HV = unhexChar(hvCh); if (HV < 0) { error("invalid hex nibble '%c' [%d]\n",hvCh,hvCh); return(false); } int LV = unhexChar(lvCh); if (LV < 0) { error("invalid hex nibble '%c' [%d]\n",lvCh,lvCh); return(false); } pc[kk++] = (char) (((HV << 4) | (LV & 0x0F)) & 0x00FF); } return(true); } //---------------------------------------------------------------------- static bool unnumString(const char *pc, unsigned long *value) { char *ei; (*value) = strtol(pc,&ei,0); return( ((*ei) == 0) ? true : false ); // okay if consumed all chars } //---------------------------------------------------------------------- static bool unnumStringDecimal(const char *pc, unsigned long *value) { char *ei; (*value) = strtol(pc,&ei,10); return( ((*ei) == 0) ? true : false ); // okay if consumed all chars } //---------------------------------------------------------------------- static unsigned char genericCRC8(char *pc, int startpos, int count, int poly) { unsigned char crc = 0; for (int ii = 0; ii < count; ii++) { unsigned char data = pc[startpos+ii]; for (int bb = 0; bb < 8; bb++) { if ((crc ^ data) & 0x01) { crc = crc ^ poly; crc = crc >> 1; crc = crc | 0x80; } else { crc = crc >> 1; crc = crc & 0x7f; } data = data >> 1; } } return(crc); } //---------------------------------------------------------------------- static unsigned char checksum256(char *pc, int startpos, int count) { unsigned int sum = 0; for (int ii = 0; ii < count; ii++) { unsigned char data = pc[startpos+ii]; sum += data; } return( (unsigned char) (sum % 256) ); } //---------------------------------------------------------------------- static void getFormatName(const char *str, char *name) { int kk = 0; while (IS_NAME_CHAR(str[kk])) { name[kk] = str[kk]; kk++; } name[kk] = 0; } //---------------------------------------------------------------------- #define ZFORMAT_FIRST 0x0aa00001 #define ZFORMAT_ZDS 0x0aa00001 #define ZFORMAT_ZHF 0x0aa00002 #define ZFORMAT_ZHL 0x0aa00003 #define ZFORMAT_ZHS 0x0aa00004 #define ZFORMAT_ZSR 0x0aa00005 #define ZFORMAT_ZC8 0x0aa00006 #define ZFORMAT_ZDC 0x0aa00007 #define ZFORMAT_LAST 0x0aa00007 typedef struct { unsigned char addr; unsigned long dict; unsigned char msgid; } ZSRData; typedef struct { int startpos; int count; int poly; } ZC8Data; typedef struct { int startpos; int count; } ZDCData; typedef struct { unsigned long zFormat; union { ZSRData zsr; ZC8Data zc8; ZDCData zdc; } U; } zFormatData; //---------------------------------------------------------------------- // NSCLConverter //---------------------------------------------------------------------- class NSCLConverter : public StreamFormatConverter { virtual int parse(const StreamFormat& fmt, StreamBuffer& info, const char*& source, bool scanFormat); virtual int scanLong(const StreamFormat& fmt, const char* input, long& value); virtual int scanDouble(const StreamFormat& fmt, const char* input, double& value); virtual int scanString(const StreamFormat& fmt, const char* input, char* value, size_t maxlen); virtual int scanPseudo(const StreamFormat& fmt, StreamBuffer& input, long& cursor); virtual bool printLong(const StreamFormat& fmt, StreamBuffer& output, long value); virtual bool printDouble(const StreamFormat& fmt, StreamBuffer& output, double value); virtual bool printString(const StreamFormat& fmt, StreamBuffer& output, const char* value); virtual bool printPseudo(const StreamFormat& fmt, StreamBuffer& output); private: bool parse_ZSR(const char *source, unsigned char *addr, unsigned long *dict, unsigned char *msgid, int *slen); bool parse_ZC8(const char *source, int *startpos, int *count, int *poly, int *slen); bool parse_ZDC(const char *source, int *startpos, int *count, int *slen); void putFormatData(StreamBuffer& info, zFormatData *zdata); bool getFormatData(const StreamBuffer& info, zFormatData *zdata); }; //---------------------------------------------------------------------- void NSCLConverter::putFormatData(StreamBuffer& info, zFormatData *zdata) { // clear info info.clear(); // add data from structure, coding so all chars are "printable" encodeHex((char *)zdata,sizeof(zFormatData),info); }; //---------------------------------------------------------------------- bool NSCLConverter::getFormatData(const StreamBuffer& info, zFormatData *zdata) { // size must be correct if (info.length() != sizeof(zFormatData)*2) { error("info length %ld expecting %d\n",info.length(),(int)sizeof(zFormatData)); nsclfrib_showBuffer((unsigned char *)info(0),info.length()); return(false); } // decode structure bytes if (! decodeHex(info,info.length(),(char *)zdata)) { error("decode hex failed\n"); nsclfrib_showBuffer((unsigned char *)info(0),info.length()); return(false); } // format id must be valid if ((zdata->zFormat < ZFORMAT_FIRST) || (zdata->zFormat > ZFORMAT_LAST)) { error("invalid Z format id 0x%08lx\n",zdata->zFormat); return(false); } // othewise we're good return(true); } //---------------------------------------------------------------------- bool NSCLConverter::parse_ZC8 (const char *source, int *startpos, int *count, int *poly, int *slen) { unsigned long UL; char buff[256]; strcpy(buff,source); (*slen) = 0; char *pc = buff; // must start with ( if ((*pc) != '(') { error("invalid ZC8 format '%s' : want (s,n,p)\n",source); return(false); } pc++; // find , char *idx = strchr(pc,','); if (! idx) { error("invalid ZC8 format '%s' : want (s,n,p)\n",source); return(false); } // get startpos (*idx) = 0; if (! unnumString(pc,&UL)) { error("invalid ZC8 format '%s' : want (s,n,p)\n",source); return(false); } (*startpos) = UL; pc = idx + 1; // find , idx = strchr(pc,','); if (! idx) { error("invalid ZC8 format '%s' : want (s,n,p)\n",source); return(false); } // get count (*idx) = 0; if (! unnumString(pc,&UL)) { error("invalid ZC8 format '%s' : want (s,n,p)\n",source); return(false); } (*count) = UL; pc = idx + 1; // find ')' idx = strchr(pc,')'); if (! idx) { error("invalid ZC8 format '%s' : want (s,n,p)\n",source); return(false); } // get polynomial (*idx) = 0; if (! unnumString(pc,&UL)) { error("invalid ZC8 format '%s' : want (s,n,p)\n",source); return(false); } (*poly) = UL; pc = idx + 1; // set slen (*slen) = (pc - buff); return(true); } //---------------------------------------------------------------------- bool NSCLConverter::parse_ZDC (const char *source, int *startpos, int *count, int *slen) { unsigned long UL; char buff[256]; strcpy(buff,source); (*startpos) = 0; (*count) = 0; (*slen) = 0; char *pc = buff; // if next char isn't '(', we're using just the defaults if ((*pc) != '(') return(true); // grab chars until we get a non-digit, this is startpos pc++; char *si = pc; while (isdigit(*pc)) pc++; char keep = *pc; (*pc) = 0; if (! unnumString(si,&UL)) { error("invalid ZDC format '%s' : want [(s[,n])]\n",source); return(false); } (*startpos) = UL; (*pc) = keep; // if char after number is a ')' we're done if ((*pc) == ')') { pc++; (*slen) = pc - buff; return(true); } // if char after number is NOT a comma is an error if ((*pc) != ',') { error("invalid ZDC format '%s' : want [(s[,n])]\n",source); return(false); } // grab chars until we get a non-digit, this is char count pc++; si = pc; while (isdigit(*pc)) pc++; keep = *pc; (*pc) = 0; if (! unnumString(si,&UL)) { error("invalid ZDC format '%s' : want [(s[,n])]\n",source); return(false); } (*count) = UL; (*pc) = keep; // if char after number is NOT a ')' is an error if ((*pc) != ')') { error("invalid ZDC format '%s' : want [(s[,n])]\n",source); return(false); } pc++; (*slen) = pc - buff; return(true); } //---------------------------------------------------------------------- bool NSCLConverter::parse_ZSR (const char *source, unsigned char *addr, unsigned long *dict, unsigned char *msgid, int *slen) { (*slen) = 0; // input must: 01234567890123 // be at least 14 chars long, (00,000000,00) // start with ( // have ) at pos 13 // have commas at pos 3 and 10 if ((strlen(source) != 14) || (source[0] != '(') || (source[13] != ')') || (source[3] != ',') || (source[10] != ',')) { error("invalid ZSR format '%s' : want (xx,xxxxxx,xx)\n",source); return(false); } // can now determine slen '(..)' (*slen) = 14; unsigned long UL; // get addr (2-char hex address if (! unhexString(source+1,2,&UL)) return(false); (*addr) = (UL & 0x000000FF); // get dict (6-char hex value) if (! unhexString(source+4,6,&UL)) return(false); (*dict) = (UL & 0x00FFFFFF); // get msgid (2-char hex value) if (! unhexString(source+11,2,&UL)) return(false); (*msgid) = (UL & 0x000000FF); return(true); } //---------------------------------------------------------------------- int NSCLConverter::parse(const StreamFormat& fmt, StreamBuffer& info, const char*& source, bool scanFormat) { #if 0 error("NSCLConverter::parse():\n" " fmt:\n" " conv : '%c'\n" " type : %u\n" " flags : %02X\n" " prec : %d\n" " width : %d\n" " infolen : %d\n" " info : '%s'\n" " source: '%s'\n", fmt.conv, fmt.type, fmt.flags, fmt.prec, fmt.width, fmt.infolen, fmt.info, source); #endif // zero out format data structure zFormatData zdata; memset(&zdata,0,sizeof(zdata)); // get format name (chars after 'Z') char name[128]; getFormatName(source,name); if (strcmp(name,"DC") == 0) { // width must be specified if (fmt.width <= 0) { error("ZDC format requires width specifier\n"); return(false); } int startpos; int count; int slen; if (! parse_ZDC(source+2,&startpos,&count,&slen)) return(false); zdata.zFormat = ZFORMAT_ZDC; zdata.U.zdc.startpos = startpos; zdata.U.zdc.count = count; putFormatData(info,&zdata); source += slen + 2; return(pseudo_format); } if (strcmp(name,"DS") == 0) { if (! scanFormat) { // DS is read-only, no printing error("ZDS format is read-only, no output\n"); return(false); } zdata.zFormat = ZFORMAT_ZDS; putFormatData(info,&zdata); source += 2; return(double_format); } if (strcmp(name,"HF") == 0) { zdata.zFormat = ZFORMAT_ZHF; putFormatData(info,&zdata); source += 2; return(double_format); } if (strcmp(name,"HL") == 0) { // if width specified, must be an even number if ((fmt.width) && (fmt.width & 0x01)) { error("%c%s format length must be an even number\n",fmt.conv,fmt.info); return(false); } zdata.zFormat = ZFORMAT_ZHL; putFormatData(info,&zdata); source += 2; return(LONG_FORMAT); } if (strcmp(name,"HS") == 0) { // if width specified, must be an even number if ((fmt.width) && (fmt.width & 0x01)) { error("%c%s format length must be an even number\n",fmt.conv,fmt.info); return(false); } zdata.zFormat = ZFORMAT_ZHS; putFormatData(info,&zdata); source += 2; return(string_format); } if (strcmp(name,"SR") == 0) { unsigned char addr; unsigned long dict; unsigned char msgid; int slen; if (! parse_ZSR(source+2,&addr,&dict,&msgid,&slen)) return(false); zdata.zFormat = ZFORMAT_ZSR; zdata.U.zsr.addr = addr; zdata.U.zsr.dict = dict; zdata.U.zsr.msgid = msgid; putFormatData(info,&zdata); source += slen + 2; return(LONG_FORMAT); } if (strcmp(name,"C8") == 0) { int startpos; int count; int poly; int slen; if (! parse_ZC8(source+2,&startpos,&count,&poly,&slen)) return(false); zdata.zFormat = ZFORMAT_ZC8; zdata.U.zc8.startpos = startpos; zdata.U.zc8.count = count; zdata.U.zc8.poly = poly; putFormatData(info,&zdata); source += slen + 2; return(pseudo_format); } // error if we get this far char infotxt[256]; if (fmt.infolen == 0) infotxt[0] = 0; else { memcpy(infotxt,fmt.info,fmt.infolen); infotxt[fmt.infolen] = 0; } error("NSCLConverter::parse() error:\n" "unknown characters after '%c': '%s'\n" " fmt:\n" " conv : '%c'\n" " type : %u\n" " flags : %02X\n" " prec : %d\n" " width : %d\n" " infolen : %d\n" " info : '%s'\n" " source: '%s'\n", fmt.conv, name, fmt.conv, fmt.type, fmt.flags, fmt.prec, fmt.width, fmt.infolen, infotxt, source); return(false); } //---------------------------------------------------------------------- int NSCLConverter::scanLong(const StreamFormat& fmt, const char* input, long& value) { // get previously parsed format data zFormatData zdata; if (! getFormatData(fmt.info,&zdata)) return(false); switch (zdata.zFormat) { case ZFORMAT_ZHL: { // determine how many bytes (hex-coded pairs) to read int ww = (fmt.width > 0) ? (fmt.width / 2) : 4; // if no width, stop when invalid hex pair occurs bool stopInvalid = (fmt.width > 0) ? false : true; // scan until error or done value = 0; const char *pc = input; for (int ii = 0; ii < ww; ii++) { if (! isHexPair(pc)) { // invalid hex pair, if stop on invalid we break if (stopInvalid) break; // if NOT stop on invalid, is an error error("invalid hex-coded character pair at '%s'\n",pc); value = 0; return(false); } // get value of hex-coded pair and add to value being built unsigned char d = 0; unhexPair(pc,&d); value <<= 8; value |= d; pc += 2; } // if '-' flag given, convert to signed if (fmt.flags & left_flag) { int nbytes = (pc - input) / 2; if (nbytes < 4) { unsigned long mask = 0x00000080; mask <<= (nbytes - 1) * 8; if (value & mask) { mask = 0xFF000000; for (int nn = 0; nn < 4-nbytes; nn++) { value |= mask; mask >>= 8; } } } } // return number of chars we consumed return( pc - input ); } // ZHL break; case ZFORMAT_ZSR: { // must start with STX char *pc = (char *) input; if ((*pc) != 0x02) { error("ZSR reply starts with 0x%02x, not STX\n",(*pc)); return(false); } pc++; // get remaining msg characters (13), un-converting escape-sequences // addr + func + 'c' + hexcode + data + msgid + chksum // count 1 1 1 3 4 1 2 = 13 // index 0 1 2 3,4,5 6,7,8,9 10 11,12 unsigned char unesc[64]; int unesc_len = 13; for (int kk = 0; kk < unesc_len; kk++) { if ((*pc) == 0x0d) { // hit CR prematurely, might be error reply, reset unesc_len unesc_len = kk; break; } else if ((*pc) != 0x07) { // regular char unesc[kk] = (*pc); pc++; } else { // 2-byte escape-sequence pc++; switch ((*pc)) { case 0x30: unesc[kk] = 0x02; pc++; break; case 0x31: unesc[kk] = 0x0d; pc++; break; case 0x32: unesc[kk] = 0x07; pc++; break; default: error("ZSR unknown escape-sequence 0x07+0x%02x\n",(*pc)); return(false); } } } // calculate desired checksum int chksum = 0; for (int kk = 0; kk < unesc_len-2; kk++) chksum += unesc[kk]; chksum &= 0x000000FF; // get checksum sent, must match int want_chksum = (unesc[unesc_len-2] & 0x0F); want_chksum <<= 4; want_chksum |= (unesc[unesc_len-1] & 0x0F); if (chksum != want_chksum) { error("ZSR checksum mismatch : 0x%02x, not 0x%02x\n",chksum,want_chksum); return(false); } // check for error reported unsigned char errval = unesc[1] & 0x07; if (errval != 0x01) { error("ZSR reply reports error : 0x%02x",errval); return(false); } // address must match if (unesc[0] != zdata.U.zsr.addr) { error("ZSR address mismatch : 0x%02x, not 0x%02x\n",unesc[0],zdata.U.zsr.addr); return(false); } // func nibble must match unsigned char func = unesc[1] & 0xF0; if (func != 0x80) { error("ZSR function mismatch : 0x%02x, not 0x80\n",func); return(false); } // get msgid, must match sent int reply_msgid = unesc[unesc_len-3]; if (reply_msgid != zdata.U.zsr.msgid) { error("ZSR reply msgid is 0x%02x, not 0x%02x\n",reply_msgid,zdata.U.zsr.msgid); return(false); } // 'c'+hexcode must match unsigned char reply_cmd = unesc[2]; unsigned long reply_dict = 0; for (int kk = 3; kk <= 5; kk++) { reply_dict <<= 8; reply_dict |= unesc[kk]; } if ((reply_cmd != 'c') || (reply_dict != zdata.U.zsr.dict)) { error("ZSR reply code mismatch (0x%02x/%06lx != 0x%02x/%06lx)\n", reply_cmd,reply_dict,'c',zdata.U.zsr.dict); return(false); } // get data value = 0; for (int kk = 6; kk <= 9; kk++) { value <<= 8; value |= unesc[kk]; } // return number of chars we consumed int consumed = (pc - input); return(consumed); } // ZSR break; } // switch // if we get this far is an error value = 0; return(false); } //---------------------------------------------------------------------- int NSCLConverter::scanDouble(const StreamFormat& fmt, const char* input, double& value) { // get previously parsed format data zFormatData zdata; if (! getFormatData(fmt.info,&zdata)) return(false); switch (zdata.zFormat) { case ZFORMAT_ZDS: { // length of string must be at least 18 bytes, size of DS1820 scratchpad int L = strlen(input); if (L < 18) { error("input string length (%d) shorter than DS1820 scratchpad length (18)\n",L); return(false); } // convert scratchpad string into data bytes // these are: // 0 : temp LSB // 1 : temp HSB // 2 : TH or User1 (ignored) // 3 : TL or User2 (ignored) // 4 : reserved (ignored) // 5 : reserved (ignored) // 6 : counts remaining // 7 : counts per degC // 8 : checksum (ignored) unsigned char data[9] = {0,0,0,0,0,0,0,0,0}; const char *pc = input; for (int ii = 0; ii < 9; ii++) { if (! unhexPair(pc,&data[ii])) return(false); pc += 2; } // get temperature data short tempD = data[1]; tempD <<= 8; tempD |= data[0]; tempD &= 0xFFFE; double count_rem = data[6]; double count_per = data[7]; // calculate temperature value = tempD * 0.5; if (count_per > 0) value = value - 0.25 + ((count_per - count_rem) / count_per); return(18); // scratchpad is always 18 bytes } // ZDS break; case ZFORMAT_ZHF: { // decode hex bytes union { long L; float F; } U; U.L = 0; const char *pc = input; for (int ii = 0; ii < 4; ii++) { unsigned char d; if (! unhexPair(pc,&d)) return(false); U.L <<= 8; U.L |= d; pc += 2; } // set value and we're done value = U.F; return(8); // always consumes 8 bytes } break; } // switch // if we get this far is an error value = 0; return(false); } //---------------------------------------------------------------------- int NSCLConverter::scanString(const StreamFormat& fmt, const char* input, char* value, size_t maxlen) { // get previously parsed format data zFormatData zdata; if (! getFormatData(fmt.info,&zdata)) return(false); switch (zdata.zFormat) { case ZFORMAT_ZHS: { // determine how many bytes (hex-coded pairs) to read int ww = (fmt.width > 0) ? (fmt.width / 2) : ((maxlen-1) & 0xFFFFFFFE); // if no width, we stop when an invalid pair occurs or a NULL (00 char pair) is read bool stopInvalid = (fmt.width > 0) ? false : true; bool stopNull = (fmt.width > 0) ? false : true; // scan until error or done const char *pc = input; int idx = 0; for (int ii = 0; ii < ww; ii++) { if (! isHexPair(pc)) { // invalid hex pair, if stop on invalid we break if (stopInvalid) break; // if NOT stop on invalid, is an error error("invalid hex-coded character pair at '%s'\n",pc); value[0] = 0; return(false); } // get value of hex-coded pair, add to string unsigned char d = 0; unhexPair(pc,&d); value[idx] = (char) d; idx++; pc += 2; // if we've read a NULL (chars 00, byte 0) and should stop on NULL, do so if ((d == 0) && (stopNull)) break; } // always NULL-terminate string value[idx] = 0; // if # flag given, trim string if (fmt.flags & alt_flag) trimString(value); // return number of chars we consumed return( pc - input ); } // ZHS break; } // switch // if we get this far is an error value[0] = 0; return(false); } //---------------------------------------------------------------------- int NSCLConverter::scanPseudo(const StreamFormat& fmt, StreamBuffer& input, long& cursor) { // get previously parsed format data zFormatData zdata; if (! getFormatData(fmt.info,&zdata)) return(false); switch (zdata.zFormat) { case ZFORMAT_ZDC: { // get checksum from reply char *pc = input(cursor); char str[256]; strncpy(str,pc,fmt.width); str[fmt.width] = 0; unsigned long UL; if (! unnumStringDecimal(str,&UL)) { error("ZDC: '%s' in reply is not a number\n",str); return(false); } unsigned long replySum = UL; // calculate checksum from message pc = input(0); int count = zdata.U.zdc.count; if (count <= 0) count = cursor - zdata.U.zdc.startpos; if (count <= 0) { error("ZDC: byte count (%ld) < startpos (%d)\n",cursor,zdata.U.zdc.startpos); return(false); } unsigned long calcSum = checksum256(pc,zdata.U.zdc.startpos,count); // checksums must match if (replySum != calcSum) { error("ZDC reply checksum is %ld, calculated is %ld\n",replySum,calcSum); return(false); } // return number of chars we consumed int consumed = fmt.width; return(consumed); } case ZFORMAT_ZC8: { /* printf("input:\n"); nsclfrib_showBuffer((unsigned char *)&input[0],input.length()); */ // get CRC from reply unsigned char replyCRC = (*input(cursor)); // calculate expected CRC char *pc = input(0); unsigned char calcCRC = genericCRC8(pc, zdata.U.zc8.startpos, zdata.U.zc8.count, zdata.U.zc8.poly); // CRCs must match if (replyCRC != calcCRC) { error("ZC8 reply crc is 0x%02X, calculated is 0x%02X\n",replyCRC,calcCRC); return(false); } // return number of chars we consumed int consumed = 2; return(consumed); } // ZC8 break; } // switch // if we get this far is an error return(0); } //---------------------------------------------------------------------- bool NSCLConverter::printLong(const StreamFormat& fmt, StreamBuffer& output, long value) { // get previously parsed format data zFormatData zdata; if (! getFormatData(fmt.info,&zdata)) return(false); switch (zdata.zFormat) { case ZFORMAT_ZHL: { // determine how many bytes (hex-coded pairs) to write int ww = (fmt.width > 0) ? (fmt.width / 2) : 4; for (int ii = 0; ii < ww; ii++) { unsigned char c = (unsigned char) ((value >> 8*(ww-ii-1)) & 0x00FF); char str[3]; toHex(c,str); output.append(str); } return(true); } // ZHL break; case ZFORMAT_ZSR: { // build part of message that is checksum-ed unsigned char body[64]; body[0] = zdata.U.zsr.addr; // address body[1] = 0x80; // function code = dictionary lookup body[2] = 'c'; // c=read (set would be 'a') body[3] = (zdata.U.zsr.dict >> 16) & 0x0000FF; body[4] = (zdata.U.zsr.dict >> 8) & 0x0000FF; body[5] = (zdata.U.zsr.dict >> 0) & 0x0000FF; body[6] = zdata.U.zsr.msgid; int body_len = 7; // calculate checksum unsigned int chksum = 0; for (int kk = 0; kk < body_len; kk++) chksum += body[kk]; chksum &= 0x000000FF; // build whole message, checking for needed escape-sequences unsigned char send[64]; int idx = 0; send[idx++] = 0x02; // STX, start of message for (int kk = 0; kk < body_len; kk++) { switch (body[kk]) { case 0x02: send[idx++] = 0x07; send[idx++] = 0x30; break; case 0x07: send[idx++] = 0x07; send[idx++] = 0x32; break; case 0x0d: send[idx++] = 0x07; send[idx++] = 0x31; break; default: send[idx++] = body[kk]; break; } } // add checksum + CR and we're done send[idx++] = 0x40 + ((chksum >> 4) & 0x00000F); send[idx++] = 0x40 + ((chksum >> 0) & 0x00000F); send[idx++] = 0x0d; output.append(send,idx); return(true); } // ZSR; break; } // switch // if we get this far is an error return(false); } //---------------------------------------------------------------------- bool NSCLConverter::printDouble(const StreamFormat& fmt, StreamBuffer& output, double value) { // get previously parsed format data zFormatData zdata; if (! getFormatData(fmt.info,&zdata)) return(false); switch (zdata.zFormat) { case ZFORMAT_ZHF: { // hex-coded float union { long L; float F; } U; U.F = (float) value; int ww = 4; for (int ii = 0; ii < ww; ii++) { unsigned char c = (unsigned char) ((U.L >> 8*(ww-ii-1)) & 0x00FF); char str[3]; toHex(c,str); output.append(str); } return(true); } // ZHF break; } // switch // if we get this far is an error return(false); } //---------------------------------------------------------------------- bool NSCLConverter::printString(const StreamFormat& fmt, StreamBuffer& output, const char* value) { // get previously parsed format data zFormatData zdata; if (! getFormatData(fmt.info,&zdata)) return(false); switch (zdata.zFormat) { case ZFORMAT_ZHS: { int strchars = strlen(value); int usechars = strchars; int padchars = 0; if (fmt.width > 0) { usechars = fmt.width / 2; if (usechars > strchars) { padchars = (usechars - strchars); usechars = strchars; } } for (int ii = 0; ii < usechars; ii++) { char c[3]; toHex(value[ii],c); output.append(c); } // pad w/spaces (if any needed) for (int ii = 0; ii < padchars; ii++) output.append("20"); // if no specified width, append hexcoded null if (fmt.width <= 0) output.append("00"); return(true); } // ZHS break; } // switch // if we get this far is an error return(false); } //---------------------------------------------------------------------- bool NSCLConverter::printPseudo(const StreamFormat& fmt, StreamBuffer& output) { // get previously parsed format data zFormatData zdata; if (! getFormatData(fmt.info,&zdata)) return(false); switch (zdata.zFormat) { case ZFORMAT_ZDC: { // calculate expected checksum char *pc = output(0); int count = zdata.U.zdc.count; if (count <= 0) count = output.length(); unsigned char calcSum = checksum256(pc,zdata.U.zdc.startpos,count); // format as a string char str[256]; if (fmt.flags & zero_flag) sprintf(str,"%0*d",fmt.width,calcSum); else sprintf(str,"%*d",fmt.width,calcSum); // add to output output.append(str); return(true); } case ZFORMAT_ZC8: { // calculate expected CRC char *pc = output(0); unsigned char calcCRC = genericCRC8(pc, zdata.U.zc8.startpos, zdata.U.zc8.count, zdata.U.zc8.poly); // add to output output.append(calcCRC); /* printf("output:\n"); nsclfrib_showBuffer((unsigned char *)&output[0],output.length()); */ return(true); } // ZC8 break; } // switch // if we get this far is an error return(false); } //---------------------------------------------------------------------- RegisterConverter(NSCLConverter, "Z");