Source file: /~heha/mb-iwp/Energiemessung/VIPsys3/vipsys3.zip/src/tabdata.cpp

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