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

#include "vipsys3.h"
#include <windows.h>
#include <windowsx.h>
#include <setupapi.h>
#include <devguid.h>
//#include <shlwapi.h>
//#include <commctrl.h>
#include <stdio.h>
#include <tchar.h>
//#include "analyzer.h"
#include "tabdata.h"

/*******************
 * Hilfsfunktionen *
 *******************/

static const DCB DefDcb={
 sizeof(DefDcb),9600,
 1,0,1,0,1,0,1,0,0,0,0,2,1,0,
 0,2048,512,7,2,0,0x11,0x13,0,0,'\n',0};

static TCHAR stCom[]=T("COM%u");

void DLGCONFIG::SetDCB(DCB&dcb, BYTE cfg) {
 dcb=DefDcb;		// ganze Struktur kopieren!
 dcb.ByteSize=7+(cfg&1);
 dcb.StopBits=cfg&2;
 dcb.Parity=(cfg>>=2)&3;
 dcb.BaudRate=300<<(cfg>>=2);
 dcb.fParity=dcb.Parity?1:0;
}

static BYTE GetSerialConfigByte(const DCB&dcb) {
 BYTE cfg=0;
 int i=dcb.BaudRate/300;
 while (i>>=1) cfg++;
 cfg<<=2;
 cfg|=dcb.Parity&3;
 cfg<<=2;
 cfg|=dcb.StopBits&2;
 cfg|=(dcb.ByteSize-7)&1;
 return cfg;
}

void DLGCONFIG::ParameterDlg() {
 TCHAR ComName[8];
 COMMCONFIG cc;
 InitStruct(&cc,sizeof(cc));
 SetDCB(cc.dcb,serialCfg);
 _sntprintf(ComName,elemof(ComName),stCom,serialNo+1);
 if (!CommConfigDialog(ComName,Wnd,&cc)) return;
 serialCfg=GetSerialConfigByte(cc.dcb);
}

INT_PTR CALLBACK DLGCONFIG::DlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
 DLGCONFIG *p=(DLGCONFIG*)GetWindowLongPtr(Wnd,DWLP_USER);

 switch (Msg) {
  case WM_INITDIALOG: {
   SetWindowLongPtr(Wnd,DWLP_USER,lParam);
   p=(DLGCONFIG*)lParam;
   p->Wnd=Wnd;
   SetCheckboxGroup(Wnd,110,114,p->checkBits);
   SendMessage(Wnd,WM_TIMER,1,0);
  }return TRUE;

  case WM_DEVICECHANGE: SetTimer(Wnd,1,2500,NULL); break;
  
  case WM_TIMER: {
// serielle Schnittstellen (neu) listen (bei jedem WM_DEVICECHANGE bspw. für USB)
   HWND hCombo=GetDlgItem(Wnd,101);
   ComboBox_ResetContent(hCombo);
   HANDLE devs=SetupDiGetClassDevs((GUID*)&GUID_DEVCLASS_PORTS,NULL,0,DIGCF_PRESENT);
   if (devs!=INVALID_HANDLE_VALUE) {
    SP_DEVINFO_DATA devInfo;
    devInfo.cbSize=sizeof devInfo;
    for (UINT i=0; SetupDiEnumDeviceInfo(devs,i,&devInfo); i++) {
     HKEY hKey;
     TCHAR s[16];
     DWORD slen=sizeof s;
     *s=0;
     if ((hKey=SetupDiOpenDevRegKey(devs,&devInfo,DICS_FLAG_GLOBAL,0,DIREG_DEV,KEY_READ))
       ==INVALID_HANDLE_VALUE) continue;
     RegQueryValueEx(hKey,T("PortName"),NULL,NULL,(LPBYTE)s,&slen);
     RegCloseKey(hKey);
     if (*s=='C') {	// assume COMx, filter out LPTx
      int idx=ComboBox_AddString(hCombo,s);
      int num=_ttoi(s+3)-1;	// zero-based
      ComboBox_SetItemData(hCombo,idx,num);
      if (num==p->serialNo) ComboBox_SetCurSel(hCombo,idx);
     }
    }
    SetupDiDestroyDeviceInfoList(devs);
   }
  }break;

  case WM_COMMAND: switch (LOWORD(wParam)) {
   case 101: if (HIWORD(wParam)==CBN_SELCHANGE) {
    p->serialNo=(BYTE)ComboBox_GetItemData((HWND)lParam,ComboBox_GetCurSel((HWND)lParam));
   }break;

   case 102: p->ParameterDlg(); break;

   case 1: {
    p->checkBits=GetCheckboxGroup(Wnd,110,114);
   }nobreak;
   case 2: EndDialog(Wnd,wParam); break;
  }
 }
 return FALSE;
}

BOOL EnableDlgItem(HWND Wnd, UINT Id, BOOL Enable) {
 if (Enable) Enable=TRUE;
 return EnableWindow(GetDlgItem(Wnd,Id),Enable);
}

/************************************
 * Was gibt's denn alles überhaupt? *
 ************************************

ESC M:	Record-Nummer (null-basiert), wenn die Daten kommen (Zahlenbasis 62)
	Jedes weitere Tarifband 9 weitere Records

	1aptttt	2aptttt	3aptttt	Saptttt	N	D	(momentan - Average - Peak - Tarifband 1-4)
f				0
I	0	0	0	0	1
U	1	1	1	1		222
P	23I	23I	33I	34I
S	45J	45J	45J	45J
Q	56K	66K	67K	67K
d	77L	78L	78L	78L
c	88 MVen	89 MVen	89 MVen	89 MVen
t	 9 MVen	 9 MVen	 9 NVen	 A NWfo
W	A  NWfo	C  PYhq	E  Rajs	G  Tclu
X
Y	B  OXgp	D  QZir	F  Sbkt	H  Udmv
aux				H

ESC mn:	Welches n?

	1aptttt	2aptttt	3aptttt	Saptttt	N	D
U	2	3	4	1		555
I	2	3	4	1	5
P	2	3	4	1
	666	666	666	666			alternativ, 3 Records (1-basiert: 112 122 123 123)
S	777	777	777	777			3 Records
Q	888	888	888	888			3 Records
c	2A BCDE	3A BCDE	4A BCDE	1A BCDE			A = 9 Records (1 1 1 1)
t	 A BCDE	 A BCDE	 A BCDE	 A BCDE			A = 9 Records (1 1 2 2)
d	999	999	999	999			2 Records (112 112 112 112)
f				5
W	A  BCDE	A  BCDE	A  BCDE	A  BCDE			A = 9 Records (2 4 6 8)
X
Y	A  BCDE	A  BCDE	A  BCDE	A  BCDE			A = 9 Records (3 5 7 9)
aux				F

*/

union ESTIMATE{
 DWORD u;
 struct{
  BYTE requests;// number of different requests (ESC M and ESC mn) needed
  BYTE records;	// number of STRING records to transfer
  WORD ms;	// estimated time, for 9600-e-7-1
 };
 static DWORD estimate(BYTE prefer, VALUE3 val[], unsigned len);	// The val[] array must be LocalAlloc(LPTR)ed!
 BYTE best(VALUE3 val[], unsigned len);	// After function call, the array is compacted to type VALUE!
};

DWORD ESTIMATE::estimate(BYTE prefer, VALUE3 val[], unsigned len) {
 ESTIMATE r;
 r.u=0;
 BYTE *f=(BYTE*)LocalAlloc(LPTR,len);	// flag buffer for finished values
 BYTE q=prefer;
 do{
  BYTE records=0;
  for (unsigned i=0; i<len; i++) {
   if (!f[i]) for (unsigned j=0; j<val[i].info.count; j++) {
    if (val[i].loc[j].n!=q) continue;
    f[i]++;	// mark checked
    if (records<val[i].loc[j].record) records=val[i].loc[j].record;
   }
  }
  if (records) {
   r.requests++;
   r.records+=records;
  }
  q=(q+1)&0x0F;
 }while(q!=prefer);
 LocalFree(f);
 r.ms=r.records*80+r.requests*250;
 return r.u;
}

BYTE ESTIMATE::best(VALUE3 val[], unsigned len) {
 ESTIMATE e[16];
 WORD best_ms=0xFFFF;
 BYTE r;
 unsigned i;
// Now, pick-up an optimum retrieving (how to solve??)
// At first, calculate preferring ESC M. Then prefer ESC m1, etc.
 for (i=0; i<16; i++) {
  e[i].u=estimate(i,val,len);
// Then pick up best value
  if (best_ms>e[i].ms) {
   best_ms=e[i].ms;
   r=(BYTE)i;
  }
 }
 u=e[r].u;	// set member variable
 VALUE3*s=val;
 VALUE*d=(VALUE*)s;
 for (i=0; i<len; i++) {
  unsigned k;
  BYTE l=0xFF;
  for (unsigned j=0;j<s->info.count;j++) {
   if (l>s->loc[j].n-r) l=s->loc[j].n-r, k=j;	// Find the same record as in estimate() routine
  }
  d->info.u=s->info.u;
  d->info.count=0;
  d->loc.u=s->loc[k].u;
  d++, s++;
 }
 LocalReAlloc(val,len*sizeof(VALUE),0);
 return r;
}

bool ESCM::makebuffers(VALUE*v,unsigned lv) {
 unsigned i;
 for (i=0; i<16; i++) {
  if (data[i]) LocalFree(data[i]);
  data[i]=NULL;
  len[i]=0;
 }
 for (i=0; i<lv; i++, v++) {
  unsigned n=v->loc.n;
  unsigned l=v->loc.offset+(v->info.valsize&0x0F);
  if (len[n]<l) len[n]=l;
 }
 for (i=0; i<16; i++) {
  if (len[i]) {
   if (!(data[i]=(BYTE*)LocalAlloc(LPTR,len[i]))) return false;
  }
 }
 return true;
}

struct dlgDATASEL:DLGDATASEL{
 HWND Wnd;
 void HandleChange(DWORD) const;
 void EnableCheck(UINT,BOOL) const;
 void DisableCheck(UINT bit,BOOL dis) const {EnableCheck(bit,!dis);};
 void HandleCheck(UINT);
 void CalcLength() const;
 static INT_PTR CALLBACK UpDownEditProc(HWND,UINT,WPARAM,LPARAM);
 static void HandleScroll(HWND,int);
};

void dlgDATASEL::CalcLength() const{
 VALUE3 *val,*p;
 BYTE n=0;
 p=val=(VALUE3*)LocalAlloc(LPTR,256*sizeof(VALUE3));
 for (BYTE t=0; t<=sel.tariff; t++) {
  BYTE b=0x10;			// start with frequency (Hz)
  BYTE k,r;
  do{				// go all combinations
   BYTE add=1;
   k=b&0x0F;			// column
   r=b>>4;			// row (measure)
   if (t && (k&12)!=4) continue;// short-circuit, only averages for tariff bands available
   if (sel.u&1<<r) {		// allowed measure (row)
    if (k==12) {		// "special" column, for f, I, U, and a
     switch (r) {
      case 1: if (sel.u&0xF0000UL) break; continue;	// include if any of {1-2-3-S} is checked
      case 2: if (sel.n) break; continue;		// include if N column is checked
      case 3: add=3; if (sel.v) break; continue;	// include if D column is checked
      case 13:if (sel.u&0x70000UL) break; continue;	// include if any of {1-2-3} is checked
      default: continue;	// short-circuit for non-available items
     }
     if (!sel.inst) continue;	// These are all instanteous measures!
    }else{
     switch (r) {		// accumulated measures are always included, independent of inst/avg/peak selection
      case 10:
      case 11:
      case 12: break;
      default:
      if (!(1<<(k>>2) & sel.u>>24)) continue;	// (k>>2) -> 0=inst, 1=avg, 2=peak, 3 should not occur here
     }
     if (!(1<<(k&3) & sel.u>>16)) continue;	// (k&3) -> 0..3, channel nummer 1-2-3-S
    }
// Now, this measure is allowed by user, but is this available by VIPsys3 device?
    p->info.valcode=b;
    p->info.tariff=t;
    p->locate();
    if (p->info.count) {
     p++;			// Yes, it's available in at least one protocol, move pointer
     n+=add;			// count available measurements
    }
   }
  }while ((b+=k==12?4:1)<0xF0);		// end with reactive work (kvarh)
 }
 ESTIMATE e;
 e.best(val,int(p-val));		// now, val is a pointer to VALUE (not VALUE3) items
 char s[100];
 wsprintfA(s,"Anzahl Messwerte: %d\r\nAnfragen: %u, Records: %u\r\nGeschätzte Transferzeit: %u ms",
   n,e.requests,e.records,e.ms);
 SetDlgItemTextA(Wnd,48,s);
 LocalFree(val);
}

void dlgDATASEL::EnableCheck(UINT bit, BOOL ena) const{
 EnableDlgItem(Wnd,16+bit,ena);
 CheckDlgButton(Wnd,16+bit,ena?sel.u>>bit&1:0);	// remove checkmark for disabled buttons, and re-check on enabling
}

void dlgDATASEL::HandleChange(DWORD m) const{
 DWORD ch=1<<2|1<<24;		// Current on/off / inst. on/off?
 if (m&ch) DisableCheck(20,~sel.u&ch);	// Column for neutral current
 ch=1<<3|1<<24;			// Voltage on/off / inst. on/off?
 if (m&ch) DisableCheck(21,~sel.u&ch);
 ch=1<<24;
 if (m&ch) {			// inst./avg./peak values (column selection)
  EnableCheck(1,sel.u&ch);	// frequency: only inst.
  EnableCheck(2,sel.u&ch);	// current: only inst.
  EnableCheck(3,sel.u&ch);	// voltage: only inst.
  EnableCheck(13,sel.u&ch);	// Same for auxiliary values
 }
 ch=7<<24;
 if (m&ch) {
  EnableCheck(4,sel.u&ch);	// power: all
  EnableCheck(5,sel.u&ch);
  EnableCheck(6,sel.u&ch);
  EnableCheck(7,sel.u&ch);	// distortion: all
  EnableCheck(8,sel.u&3<<24);	// cos phi: no peak
  EnableCheck(9,sel.u&2<<24);	// tan phi: only avg.
 }
 if (m&0x7003FFEUL) {
  ch=((sel.u>>16)|~0x200)&sel.u&0x3FFEUL;	// AND the "avg" bit with the "tan phi" bit
  if (!(sel.u&0x7001400UL)) ch=0;		// nothing to check
  EnableCheck(16,ch);
  EnableCheck(17,ch);
  EnableCheck(18,ch);
  EnableCheck(19,ch);
 }
 if (m&0x2001700UL) {
  ch=((sel.u>>16)|~0x200)&sel.u&0x1700UL;	// AND the "avg" bit with the "tan phi" bit
  if (!(sel.u&0x2001400UL)) ch=0;		// nothing to check
  if (ch) {
   if (!IsWindowEnabled(GetDlgItem(Wnd,44))) {
    SetDlgItemInt(Wnd,44,sel.tariff,FALSE);
    EnableDlgItem(Wnd,44,ch);
   }
  }else{
   if (IsWindowEnabled(GetDlgItem(Wnd,44))) {
    EnableDlgItem(Wnd,44,ch);			// Solve recursion problem by disabling first
    SetDlgItemInt(Wnd,44,0,FALSE);		// show a zero if disabled
   }
  }
 }
 CalcLength();
}

void dlgDATASEL::HandleCheck(UINT id) {
 DWORD m=1L<<(id-16);
 BOOL sw=IsDlgButtonChecked(Wnd,id);
 if (sw) sel.u|=m;
 else sel.u&=~m;
 HandleChange(m);
}

void dlgDATASEL::HandleScroll(HWND Wnd, int dir) {
 dlgDATASEL *p=(dlgDATASEL*)GetWindowLongPtr(GetParent(Wnd),DWLP_USER);
 if (!p) return;
 dir+=p->sel.tariff;
 if (dir<0) dir=0;
 if (dir>4) dir=4;
 if (p->sel.tariff!=(unsigned)dir) {
  p->sel.tariff=dir;
  DWORD Sel[2];
  SendMessage(Wnd,EM_GETSEL,(WPARAM)Sel,(LPARAM)(Sel+1));
  SetDlgItemInt(GetParent(Wnd),44,dir,FALSE);
  Edit_SetSel(Wnd,Sel[0],Sel[1]);
 }else MessageBeep(MB_ICONEXCLAMATION);
}

static WNDPROC DefEditProc;

INT_PTR CALLBACK dlgDATASEL::UpDownEditProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
 switch (Msg) {
  case WM_VSCROLL: switch (LOBYTE(wParam)) {
   case SB_LINEUP:	HandleScroll(Wnd,1); break;
   case SB_LINEDOWN:	HandleScroll(Wnd,-1); break;
  }break;
  case WM_KEYDOWN: switch (wParam) {
   case VK_UP:		HandleScroll(Wnd,1); return 0;
   case VK_DOWN:	HandleScroll(Wnd,-1); return 0;
  }break;
 }
 return CallWindowProc(DefEditProc,Wnd,Msg,wParam,lParam);
}


INT_PTR CALLBACK DLGDATASEL::DlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
 dlgDATASEL *p=(dlgDATASEL*)GetWindowLongPtr(Wnd,DWLP_USER);

 switch (Msg) {
  case WM_INITDIALOG: {
   SetWindowLongPtr(Wnd,DWLP_USER,lParam);
   p=(dlgDATASEL*)lParam;
   p->Wnd=Wnd;
   DefEditProc=SubclassWindow(GetDlgItem(Wnd,44),dlgDATASEL::UpDownEditProc);
   SetCheckboxGroup(Wnd,16,16+27,p->sel.u);
   SetDlgItemInt(Wnd,44,p->sel.tariff,FALSE);
   p->HandleChange((DWORD)-1);
  }return TRUE;

  case WM_COMMAND: switch (LOBYTE(wParam)) {

   case 1:
   case 2: EndDialog(Wnd,wParam); break;

   case 44: switch (HIWORD(wParam)) {
    case EN_CHANGE: {	// even triggered by SetDlgItemInt() invoked by HandleScroll()
     if (!IsWindowEnabled((HWND)lParam)) break;
     BOOL b;
     DWORD t=GetDlgItemInt(Wnd,44,&b,FALSE);
     if (b && t<=4) {
      p->sel.tariff=t;
      p->CalcLength();
     }else MessageBeep(MB_ICONEXCLAMATION);
    }break;
   }break;

   case 64: {	// nothing (visible) checked (leaving phase bits)
    p->sel.u&=0x00FF0000UL;
    SetCheckboxGroup(Wnd,16,16+27,p->sel.u);
    SetDlgItemInt(Wnd,44,p->sel.tariff,FALSE);
    p->HandleChange((DWORD)-1);
   }break;

   case 65: {	// all checked
    p->sel.u=0x473F3FFE;
    SetCheckboxGroup(Wnd,16,16+27,p->sel.u);
    SetDlgItemInt(Wnd,44,p->sel.tariff,FALSE);
    p->HandleChange((DWORD)-1);
   }break;

   default: {
    p->HandleCheck(LOBYTE(wParam));
   }

  }
 }
 return FALSE;
}

Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded