Source file: /~heha/hs/UNI-T/dmm.zip/src/dmm.h

#pragma once
#include <windows.h>

#define nobreak
#define elemof(x) (sizeof(x)/sizeof(*(x)))
#define T(x) TEXT(x)

extern const __int64 _sNaN;	// signaling NaN
#define NaN (*(double*)&_sNaN)

#ifdef DMM_EXPORTS
# define FUNC(type) EXTERN_C type _declspec(dllexport) WINAPI
#else
# define FUNC(type) EXTERN_C type _declspec(dllimport) WINAPI
#endif

#ifdef __cplusplus
# define DEF(x) =(x)
#else
# define DEF(x)
typedef enum{false,true} bool;
#endif

struct INDATA{
 enum MMSG{null,conf,init,open,data,close,tout};
 MMSG msg;	// message code
 bool ok;	// return value
 BYTE idx;	// multi-purpose index (unused)
 LPARAM lParam;	// multi-purpose parameter
 BYTE *rbuf;	// received data
 void (_stdcall INDATA::*pHandler)();
 int rlen;	// size, in bytes, of data received - must be set to 0 after processing!
 int rmax;	// hint how long is recvbuf (default:400)
 int trto;	// total read time-out in milliseconds (maximum distance between two packets, default: 3000)
 int icto;	// inter-character read time-out, in ms (to detect a packet end, default: 20)
		// BUGBUG: Windows (COMM driver) cannot detect timeouts less than 50 ms safely!
		// So it cannot be used for general packet-end detection.
 int counts;	// maximum display value, default: 1999
 int baud;	// baud rate for interface, default: 9600
};

struct ENUMINFO {
 ENUMINFO *next;	// internal use
 char ManufName[32];	// UTF-8 - not used
 char ModelName[32];	// UTF-8
 int IconIndex;		// which icon should be shown
 int ExtraAlloc;	// Data bytes appended to INDATA structure
 void (_stdcall INDATA::*pHandler)();	// Procedure pointer
 LPARAM lParam;		// Initialization value for INDATA::lParam
};

// enumerator for built-in UNI-T instruments
bool _stdcall EnumUT(int n, ENUMINFO* ei);

/* For unified data transfer from plugins */
typedef enum{
// Range 1: Symbols contained in UniT-a2.ttf font and not in Unicode
 F_LowBat,	// Low battery symbol
 F_Beep,	// Symbol for continuity check
 F_Diode,	// Diode symbol for checking pn transitions
// Range 2: Symbols contained in UniT-a2.ttf font but alternatively in Unicode
 F_Delta,	// REL measurement (°C auto-changes to K)
 F_Sigma,	// Summation active (not seen)
 F_Beta,	// Transistor current amplification (not seen)
 F_Hold,	// Displayed value frozen (some multimeters send same data, some different, some nothing)
 F_Auto,	// Auto-Range mode
// Range 3: Symbols to paint by this software - until there is a .TTF with this symbols
 F_hFE,		// Same as F_Beta? (not seen)
 F_EF,		// Cable installation locator (not seen)
// Range 4: Text strings
 F_Man,		// DEPRECATED, opposite to F_Auto
 F_Min,		// Minimum value
 F_Max,		// Maximum value
// Range 5: Text strings, but may be handled separately (AC+DC or symbolic)
 F_AC,		// RMS (or True-RMS) measurement; without DC: capacitive coupling, with DC: direct coupling
 F_DC,		// Mean value measurement
// Range 6: New for UT233 (three-phase AC voltage meter + one-phase AC current clamp)
 F_Phase1,	// Phase 1 value
 F_Phase2,	// Phase 2 value
 F_Phase3,	// Phase 3 value
 F_LeftRot,	// left rotation
 F_RightRot,	// right (regular) rotation
 F_cosphi,	// cos-phi (power factor) display
 F_phi,		// phi display
 NUMFEATURES
}EFEATURE;

// unitprefix: As power of 10
// Allowed values: -18,-15,-12,-9(=n),-6(=µ),-3(=m),-2,-1,0,2,3(=k),6(=M),9,12,15,18

// unitcode: internal unit (low-nibble)
// 0 = none (hFE for example), use <unit> member
// 1 = V
// 2 = Ohm
// 3 = F
// 4 = Hz
// 5 = A
// 6 = °C
// 7 = °F
// 8 = W
// 9 = %
//10 = S (Siemens)
//11 = H (Henry, not seen yet)
//12 = K (Kelvin, for temperature difference in °C)
//13 = min^-1 (revolutions per minute)
//14 = s (seconds, internally used for scope)
//15 = VA
//16 = var
//17 = Wh
//18 = VAh	(not seen yet)
//19 = varh	(not seen yet)
//20 = °

typedef struct{
 double value;		// The measured value, without "unitprefix", -INF for underflow, +INF for overflow, NaN for unknown
 double min,max;	// The possible minimum and maximum values for current range, both 0.0 when unknown
 double ec,ev;		// constant and variable error (positive meaning ±), 0.0 when unknown
 char digits[13];	// with leading zeroes, decimal point and "error" letters as shown in multimeter display, ASCII
 char coupling;		// 1=DC, 2=AC (capacitive), 4=TrueRMS
 char unitprefix;	// the unit prefix shown, 0-based, as power of 10 (not 1000)
 char unitcode;		// the unit code for common units, perfectly handled ANSI conversion
 char unit[8];		// the unit string for uncommon units, UTF-8
 char desc[8];		// a short descriptive string for multi-readout meters, UTF-8
}READOUT;

typedef struct{
 char n;		// number of traces, i.e. following TRACEDATA structures, must be 1-4
 char datasize;		// number of bytes per sample (low-nibble), high bit set if unsigned and 80h
 char grid_x, grid_y;	// number of grid cells (div)
 int tracelen;		// trace data len, in samples (not bytes)
 int fullscale;		// this range of trace data value reaches from bottom to top of grid (UT81B: 128)
 char timebase;		// 0=1s, 1=2s, 2=5s; -1=500ms etc.
 char autorange;	// !=0 in auto range mode
 char xymode;		// X/Y mode (unspecified for != 2 traces)
 char tsource;		// trigger channel (low nibble), edge and mode (high nibble)
 int tx,ty;		// position of trigger, x=tx/tracelen, y=0.5+ty/fullscale
}SCOPEDATA;

typedef struct{		// follows SCOPEDATA
 char devicode;		// deviation coefficient in 1-2-5 steps, 0=1V, 1=2V, 2=5V; -1=500mV etc.
 char autorange;	// auto-range for deviation
 char unitcode;		// only built-in units supported
 char unused;		// alignment filler
 int ofs;		// vertical beam shift (may be horizontal in X/Y mode)
 const void *data;	// raw trace data, mostly <char> samples, -128..127, bytelength = (datasize&0x0F)*tracelen
}TRACEDATA;		// Interleaved trace data (as known from sound cards) is not supported

#define MAXREADOUT 4
#define MAXTRACE 4


// After succesful decode of a packet, finally call this function with:
// * <features> = bit field of EFEATURE bits
// * <readout> = one or more available numerical readouts
// * <num> = number of available readouts, currently, 0-4 supported
//   (different display arrangements for each count)
// * <scope> = oscilloscope data, NULL if not available
// This program has the option to display scope data without readouts,
// so it can act as (slow but resizeable) PC scope display without controls.
// With <num>=0 AND <scope>=NULL, unsuccessful decoding can be shown.
// In this case, <features> is a string resource ID (unspecified yet).
// However, it is recommended to do nothing on unsuccessful decode,
// DMM.EXE will handle this situation automatically.
// With <num>=0 and <features>=0, the icon flashes showing incoming data (erraneous packets)
FUNC(bool) SetData(DWORD features,
  const READOUT*readout,
  int num DEF(1),
  const SCOPEDATA* scope DEF(NULL));

/****************************************************************************************
 * The following functions are made to ease some common tasks generating <READOUT> data *
 ****************************************************************************************/

// scalebase: The unit for the smallest value
//      4 dig.	5 dig.	prefix
//  0 =	xxxx	xxxx.x
//  3 =	x.xxx	x.xxxx	p
//  4 =	xx.xx	xx.xxx	p
//  5 =	xxx.x	xxx.xx	p
//  6 =	x.xxx	x.xxxx	n
//  7 =	xx.xx	xx.xxx	n
//  8 =	xxx.x	xxx.xx	n
//  9 =	x.xxx	x.xxxx	µ
//  A =	xx.xx	xx.xxx	µ
//  B =	xxx.x	xxx.xx	µ
//  C =	x.xxx	x.xxxx	m
//  D =	xx.xx	xx.xxx	m
//  E =	xxx.x	xxx.xx	m
//  F =	x.xxx	x.xxxx
// 10 =	xx.xx	xx.xxx
// 11 =	xxx.x	xxx.xx
// 12 =	x.xxx	x.xxxx	k
// 13 =	xx.xx	xx.xxx	k
// 14 =	xxx.x	xxx.xx	k
// 15 =	x.xxx	x.xxxx	M
// 16 =	xx.xx	xx.xxx	M
// 17 =	xxx.x	xxx.xx	M
// 18 =	x.xxx	x.xxxx	G
// 19 =	xx.xx	xx.xxx	G
// 1A =	xxx.x	xxx.xx	G
// modifier (high 3 bits)
// 00= range has all prefixes
// 20= range has only one prefix
// 40= range has only two prefixes
// 60= range has only three prefixes
// 80= range starts with .xxxx instead of xxx.x and one unit prefix less, i.e.
//	.xxxx	.xxxxx	m	first
//	x.xxx	x.xxxx	m	second etc.

// Calculates the decimal point position and the right unit prefix.
// The "decimal point position" counts the digits _before_ decimal point.
// Needed for most of UNI-T multimeters.
FUNC(int) dp(char scalebase, char scaleadd, char*unitprefix);


// Collects bits, based by p, adresses in BitTable. NumBits=sizeof(BitTable)
// Does not invert bits while collecting.
// Skips bits marked with 0xFF (0377 octal) in BitTable.
// So this function works on datagrams shorter than 32 bytes, 16 WORDs or 8 DWORDs.
FUNC(DWORD) CollectBits(const void*p, const BYTE*BitTable, BYTE NumBits);

// Calculates minimum and maximum values out of unit, flags etc.
// This function clears the free-form ro->unit, so you must add this later if necessary.
FUNC(void) GenMinMax(READOUT *ro, DWORD features, int maxnumber, char expo);

FUNC(int) SendBytes(const void*, int);// sends data to serial or USB device

extern HINSTANCE ghInst;
double e10(char neg, int base, char expo);
void ptc(char*s);
char comma();
void GenLogUnit(LPSTR d, const READOUT*ro);
int DoubleToString(double v, int nk, LPTSTR buf, UINT buflen);
int _cdecl MBox(HWND Wnd, UINT id, UINT Type, ...);

#define CONFMAX 16	// Buffer sizes, in characters, for ConfName and descendants
extern HWND ghMainWnd;
extern DWORD gDdeInst;
extern TCHAR ConfName[CONFMAX];
extern TCHAR HelpName[];

struct DDECH{
 PTSTR ServiceTopicItem;
 bool Reconnect();
 int QueryInfo(char*buf,int blen,UINT cp,UINT what);
 int QueryValue(char*buf,int blen,UINT cp,UINT how);
 ~DDECH();
//private:
 HCONV hConv;
 HSZ hszItem;
 TCHAR buf[32];		// gets the request string from asynchronous REQUEST transaction
};

#define ECOLMAX 8	// Maximum extra columns

#include <stdio.h>

extern struct LOG{
 void OnOff(HWND Wnd, int sw);	// sw=switch: 1=on, 2=off, 3=toggle
 void Line(int col, const READOUT*ro, DWORD features, DWORD change);
 HDDEDATA DdeCallback(UINT uType,UINT uFmt,HCONV hConv,HSZ hsz1,HSZ hsz2,HDDEDATA hData);
private:
 FILE *f;
 __int64 starttime;	// start time, either system or (in case of recorded data) user given
 double T;		// accumulator used for equidistant time column
 double Interval;	// if nonzero: equal distance dictates sample rate, take last DMM value (TODO)
 int curcol;
 DWORD curfeatures;
 BYTE flags;		// Bit 0: UseTime, 1: UseHeader, 2: UseTimeCol, 3: UseDmmCol
 BYTE nExtra;		// Number of additional data channels
 DWORD Waiters;		// flag bits for current "asynchronous" DDE requests
 HANDLE WaitEvt;
 HWND hDlg;		// child dialog of GetSaveFileName()
 PCTSTR propose;	// string list of DDE channels, NULL = use standard
 DDECH*Extra[ECOLMAX];	// additional data channel list (array)
 TCHAR fname[MAX_PATH];
 static UINT_PTR CALLBACK OFNHookProc(HWND,UINT,WPARAM,LPARAM);
// static BOOL CALLBACK EnumWindowsProc(HWND,LPARAM);
 void ManageCombos(HWND Wnd, int was, int now);	// Create/delete combo boxes for extra columns
 double GetDiff();
}gLog;
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded