/*======================================================================*
* Optimized measurement data transfer in table form *
* heha, 100807 *
*======================================================================*/
/*
Column 0 1 2 3 4 5 6 7 8 9 a b c d e f = low nibble
Column's meaning 1i 2i 3i Si 1a 2a 3a Sa 1p 2p 3p Sp *i - - -
1,2,3 = phase
S = sum (overall value)
i = immediate
a = accumulated
p = peak
* = special meaning, dependent on row:
f (row=1) = colspan 1i..Si
I (row=2) = column Ni
U (row=3) = column Di
a (row=d) = colspan 1i..3i
Row 0 1 2 3 4 5 6 7 8 9 a b c d e f = high nibble
Row's measurement - f I U P S Q d c t W X Y a - -
c = cos phi
t = tan phi
P,W = real power/work
S,X = apparent power/work
Q,Y = reactive power/work
a = auxiliary channel (two values from "black box")
*/
#include "tabdata.h"
#include "analyzer.h"
BYTE SizeOfCode(BYTE valcode) {
static const BYTE SizeOfRow[0x10]={0,0xE2,0x03,0x03,0x03,0x03,0x03,0xE2,0xD2,0x03,0x09,0x09,0x09,0x03,0,0};
return valcode==0x3c ? 7 : SizeOfRow[valcode>>4]; // The 3 delta voltages with shared exponent are special
}
static const BYTE InfoListT[]={ // List of data for one tariff band (tail of ESC M or one ESC m<10>..m<14>)
0x84,0x85,0x86,0x87, // avg. c 1-2-3-S (cos phi)
0x94,0x95,0x96,0x97, // avg. t 1-2-3-S (tan phi)
0xa4,0xc4,0xa5,0xc5, // "avg" W-Y (active and reactive energy)
0xa6,0xc6,0xa7,0xc7, // 1-2-3-S
0}; // terminator
static const BYTE InfoList0[]={ // Descriptive list of data of <ESC M>
0x1c, // inst. f {1-2-3-S} (frequency) {} means "colspan"
0x20,0x21,0x22,0x23,0x2c, // inst. I 1-2-3-S-N
0x30,0x31,0x32,0x33,0x3c, // inst. U 1-2-3-S-D
0x40,0x41,0x42,0x43, // inst. P 1-2-3-S
0x44,0x45,0x46,0x47, // avg. P 1-2-3-S
0x50,0x51,0x52,0x53, // inst. S 1-2-3-S
0x54,0x55,0x56,0x57, // avg. S 1-2-3-S
0x60,0x61,0x62,0x63, // inst. Q 1-2-3-S
0x64,0x65,0x66,0x67, // avg. Q 1-2-3-S
0x70,0x71,0x72,0x73, // inst. d 1-2-3-S (distortion)
0x74,0x75,0x76,0x77, // avg. d 1-2-3-S
0x80,0x81,0x82,0x83, // inst. c 1-2-3-S (cos phi)
0x84,0x85,0x86,0x87, // avg. c 1-2-3-S
0x94,0x95,0x96,0x97, // avg. t 1-2-3-S (tan phi)
0xa4,0xc4,0xa5,0xc5, // "avg" W-Y (active and reactive energy)
0xa6,0xc6,0xa7,0xc7, // 1-2-3-S
0xd3,0xdc, // inst. a S-{1-2-3} (auxiliary data)
0x48,0x49,0x4a,0x4b, // peak P 1-2-3-S
0x58,0x59,0x5a,0x5b, // peak S 1-2-3-S
0x68,0x69,0x6a,0x6b, // peak Q 1-2-3-S
0x78,0x79,0x7a,0x7b, // peak t 1-2-3-S (tan phi)
0}; // terminator
static const BYTE InfoList1[]={ // Generic list for ESC m1, m2, m3, and m4 (one for column 1i,2i,3i,Si)
0x30,0x20,0x40,0x80, // inst. U-I-P-c (substitute zero low nibbles by 0,1,2,3)
0}; // terminator
static const BYTE InfoList5[]={
0x3c,0x2c,0x1c, // inst U(DDD)-I(N)-f{1-2-3-S}
0}; // terminator
static const BYTE InfoList6[]={ // Generic list for ESC m6, m7, m8, and m9 (one for row P, S, Q, d)
0x00,0x01,0x02,0x03, // inst. 1-2-3-S (substitute zero high nibbles by 4,5,6,7)
0x04,0x05,0x06,0x07, // avg. 1-2-3-S
0x08,0x09,0x0a,0x0b, // peak 1-2-3-S
0}; // terminator
static const BYTE InfoListF[]={ // Descriptive list of data of ESC m<15>
0xd3,0xdc, // inst. a S-{1-2-3} (auxiliary data)
0}; // terminator
// Calculates the needed records to reach the offset <o>
static BYTE OffsetToRecord(const BYTE*l, WORD o) {
BYTE r=(BYTE)offsettorecord(l,o);
#ifdef _DEBUG
if (!r) OutputDebugStringA("OffsetToRecord: Murks!\r\n"); // (it's an internal bug!)
#endif
return r;
}
// Locate the requested value in ESC M (i=0) or ESC mn (i=1..15) data
// Returns the four-byte VALUELOC record, otherwise, returns 0
static DWORD LocateValue(DWORD i, VALUEINFO vi) {
const BYTE *p; // pointer to InfoList
BYTE subst=0; // substitution into InfoList
BYTE s; // length of each item in InfoList
const BYTE *r=NULL; // pointer to packed list of record sizes (NULL = only one record)
VALUELOC vl;
vl.u=i;
if (vi.tariff) {
if (vi.tariff>4) return 0; // cannot find
if (vl.n && vl.n!=10U+vi.tariff) return 0; // cannot find there
if (!vl.n) {
vl.offset=274+(vi.tariff-1)*92; // length of data before
vl.record=22+(vi.tariff-1)*9; // number of records before
}
p=InfoListT;
r=RecordListT;
}else switch (vl.n) {
case 0: r=RecordList0; p=InfoList0; break;
case 1:
case 2:
case 3:
case 4: p=InfoList1; subst=vl.n-1; break;
case 5: p=InfoList5; break;
case 6:
case 7:
case 8: r=RecordList6; goto set6;
case 9: r=RecordList9; set6: p=InfoList6; subst=(vl.n-2)<<4; break;
case 0x0A: r=RecordListT; p=InfoListT; break;
case 0x0F: p=InfoListF; break;
default: return 0; // cannot find in this (undefined) table
}
WORD o=0; // offset for OffsetToRecord
for (;;) { // Now scan the list
BYTE b=*p++;
if (!b) return 0; // reached end of list: not found
b|=subst; // apply modification
s=SizeOfCode(b)&0x0F; // get size
if (b==vi.valcode) break; // found a match!
vl.offset+=s; // advance data offset
o+=s;
}
vl.record+=r?OffsetToRecord(r,o+s):1;
return vl.u;
}
// Finds up to 3 positions for the requested value code
// Returns the count, 0 if not available
static int LocateValue(VALUEINFO vi, VALUELOC* vl) {
int j=0;
for (DWORD i=0; i<16; i++) {
DWORD loc=LocateValue(i,vi);
if (loc) vl->u=loc, vl++, j++;
}
return j;
}
void VALUE3::locate() {
info.valsize=SizeOfCode(info.valcode); // attach size and fixed-exponent information
info.count=LocateValue(info,loc); // scan all ESC M / ESC mx records for this value
}
int ESCM::readall(int(*sendrecv)(const char*,int,char*,int)) const{
unsigned i;
int r=0;
for (i=0; i<16; i++) {
if (len[i]) {
if (!data[i]) return no_buffer;
char s[6],t[6];
int l=wsprintfA(s,i?"\027m%c\r\n":"\027M\r\n",i);
int e=sendrecv(s,l,t,sizeof(t));
if (e<0) return e+sendrecv_errors;
if (e!=l || *(DWORD*)s!=*(DWORD*)t) return wrong_echo; // check only 4 characters, should be safe enough
e=string_recv(data[i],len[i],sendrecv);
if (e<0) return e+sendrecv_errors;
if (e!=(int)len[i]) return incomplete;
r+=e;
}
}
return r; // return total number of decoded bytes read
}
bool ESCM::extract(const VALUE*v, char s[10]) const{
char e;
BYTE *pb=data[v->loc.n]+v->loc.offset;
switch (v->info.valsize&0x0F) {
case 2: e=(char)v->info.valsize>>4; goto e1; // get fixed exponent
case 3: e=(char)pb[2]; goto e1; // get exponent
case 7: e=(char)pb[2]; switch (v->info.count) {
case 2: pb+=2; /*nobreak;*/
case 1: pb+=3;
}e1:{ // 2-byte mantissa and 1-byte exponent
char up=0; // unit prefix
if (e<-3) up='m', e+=3;
if (e>=0) up='k', e-=3;
if (e>=0) up='M', e-=3; // e should be <0 now
if (e>=0 || e<-3) return false;
int l=wsprintfA(s,"%d%c",*(short*)pb,up);
MoveMemory(s+l+e+1,s+l+e,2-e);
s[l+e-1]='.';
}return true;
case 9: { // packed BCD? I believe not.
CopyMemory(s,pb,9);
s[9]=0;
}return true;
}
return false;
}
// Takes a value out of buffer, makes a string and a float value
//EXTERN_C double GetValue(VALUEINFO vi,VALUELOC vl,const void*p,char*s) {
//}
| Detected encoding: ASCII (7 bit) | 2
|