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
On 6/5/2019 1:58 PM, Brown, Garth via Tech-talk wrote:
Hi All,
I'm trying to use StreamDevice to talk to a device that is almost, but not quite, giving me data that the format converters (as I understand them) can convert.
It’s an ASCII representation of the IEEE 32 bit floating point format, e.g. the raw data for a value of 28.0 is
0x34 0x31 0x45 0x30 0x30 0x30 0x30 0x30
Which is the ASCII code for
41E00000
Which is the IEEE-754 floating point representation of 28.0.
I think that if the raw data were 0x41E00000, %R would be able to convert it. And if the raw data were
0x32 0x38 0x2E 0x30 (ASCII for 28.0)
then %f would be able to convert it.
Before I start writing calc records to convert the 32 bits to a float value, I figured I'd ask if someone had a less brute-force approach. Maybe a StreamDevice format converter trick I don't know about?
Thanks,
Garth
|
/*
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");
- References:
- StreamDevice for an odd float format Brown, Garth via Tech-talk
- Navigate by Date:
- Prev:
StreamDevice for an odd float format Brown, Garth via Tech-talk
- Next:
Re: StreamDevice for an odd float format Priller, John via Tech-talk
- 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
- Navigate by Thread:
- Prev:
StreamDevice for an odd float format Brown, Garth via Tech-talk
- Next:
Re: StreamDevice for an odd float format Priller, John via Tech-talk
- 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
|