Source file: /~heha/mb-iwp/Kleinkram/radariq.zip/src/main.cpp

//----------------------------------------------------------------------------
// Created By  : A. Hülsmann
// Created Date: 24.07.2023
// Copyright: Ondosense GmbH 2023
// ---------------------------------------------------------------------------
/*/
Simple example scripts to connect an Ondosense sensor via a serial port (COMx) and to retrieve IQ data.
/*/
// ---------------------------------------------------------------------------

// Copyright (c) 2023 OndoSense GmbH
/*
import time
import ondopython.os_sensor as os_sensor
import ondopython.interfaces_python as ip
import os
from scipy.signal import ZoomFFT
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import datetime as dt
fig, axs = plt.subplots(2,1, layout='constrained')
//axs = plt.plot()

import json

import numpy as np
from scipy.signal import blackman   // Blackman is as good as best windowing function (Scherr)
from scipy.signal import hann
from scipy.signal import blackmanharris
import serial.tools.list_ports
com_ports = [comport.device for comport in serial.tools.list_ports.comports()]
print(com_ports)
*/
#include "plotxy/cplotxy.h"
#include "main.h"
#include <windowsx.h>
#include <stdio.h>
#include <tchar.h>

HWND ghMainWnd;

static void _stdcall outLog(const TCHAR*s) {
 HWND hEdit=GetDlgItem(ghMainWnd,105);
 DWORD selStart,selEnd;
 SendMessage(hEdit,EM_GETSEL,(WPARAM)&selStart,(LPARAM)&selEnd);
 Edit_SetSel(hEdit,-1,-1);
 Edit_ReplaceSel(hEdit,s);
 if (selStart==selEnd) Edit_ScrollCaret(hEdit);	// nichts markiert: Ans Ende scrollen
 else Edit_SetSel(hEdit,selStart,selEnd);	// Markierung wiederherstellen
}

void _cdecl print(const char*fmt,...) {	// ins Logfenster
 va_list va;
 va_start(va,fmt);
 vcbprint(outLog,fmt,va);
 va_end(va);
}

//static PlotXY*gPlot1,*gPlot2;
TCHAR MBoxTitle[64];
enum{
 MB_SOUND = 1<<23
};

ComSel comsel;

/* Meldungsfenster */
int _cdecl vMBox(UINT string_id, UINT uType, va_list va) {
 TCHAR s[256],t[256];
 LoadString(0,string_id,t,elemof(t));
 _vsntprintf(s,elemof(s),t,va);
 if (uType&MB_SOUND) MessageBeep(uType&MB_TYPEMASK);
 return MessageBox(ghMainWnd,s,MBoxTitle,uType&~MB_SOUND);
}

int _cdecl MBox(UINT string_id, UINT uType,...) {
 va_list va;
 va_start(va,uType);
 int ret=vMBox(string_id,uType,va);
 va_end(va);
 return ret;
}

static void startThread() {
 SetDlgItemText(ghMainWnd,105,0);	// Log löschen
 gEndThread = false;
 ghThread = CreateThread(0,0,worker::ThreadProc,0,0,&gThreadId);
 SetDlgItemText(ghMainWnd,10,TEXT("&Stop"));
}

static void endThread() {
 if (ghThread && WaitForSingleObject(ghThread,0)) {	// Noch nicht aufgeräumt
  gEndThread=true;	// Info an thread-interne Schleife via volatile-Variable
  EnableWindow(GetDlgItem(ghMainWnd,10),FALSE);
  SetTimer(ghMainWnd,21,1000,0);
 }
}

static void onEndThread() {
 KillTimer(ghMainWnd,21);
 HWND hButton = GetDlgItem(ghMainWnd,10); 
 EnableWindow(hButton,TRUE);
 SetWindowText(hButton,TEXT("&Start"));
 DWORD exitcode;
 GetExitCodeThread(ghThread,&exitcode);
 print("Thread mit Exitkode %u beendet",exitcode);
 CloseHandle(ghThread);
 ghThread=0;
}

static void killThread() {
 if (!ghThread) return;
 gEndThread=true;			// allerletzte Chance
 if (WaitForSingleObject(ghThread,100)	// liefert 0 wenn Thread beendet
 && TerminateThread(ghThread,99))	// töten
	print("Unkooperativer Thread getötet!");
 onEndThread();
}

POINT MinSize,WinSize;
HINSTANCE ghInstance;

static INT_PTR CALLBACK MainDlgProc(HWND Wnd,UINT msg, WPARAM wParam, LPARAM lParam) {
 switch (msg) {
  case WM_INITDIALOG: {	// So groß wie das Fenster in der Ressource definiert ist wird die minimale Größe angenommen
   ghMainWnd=Wnd;
   GetWindowText(Wnd,MBoxTitle,elemof(MBoxTitle));
   HICON icon=LoadIcon(ghInstance,MAKEINTRESOURCE(1));
   SetClassLongPtr(Wnd,GCLP_HICON,LPARAM(icon));
   SetClassLongPtr(Wnd,GCLP_HICONSM,LPARAM(icon));
   Rect<>r(Wnd);	// GetWindowRect
   MinSize.x=r.width();
   MinSize.y=r.height();
   new(&r) Rect<>(Wnd,true);	// GetClientRect
   WinSize.x=r.right;
   WinSize.y=r.bottom;
   CheckDlgButton(Wnd,106,BST_CHECKED);
   if (worker::LoadSettings()) CheckDlgButton(Wnd,33,BST_CHECKED);	// Subtrahieren ein
  }break;

  case WM_GETMINMAXINFO: {
   MINMAXINFO&mmi=*(MINMAXINFO*)lParam;
   mmi.ptMinTrackSize=MinSize;
  }return TRUE;

  case WM_SIZE: if (wParam==SIZE_MAXIMIZED || wParam==SIZE_RESTORED) {
   POINT delta = {GET_X_LPARAM(lParam)-WinSize.x,GET_Y_LPARAM(lParam)-WinSize.y};
   if (delta.x || delta.y) {
    BYTE vsize=2;	// erst mal ohne jeden Divider: Fenster abzählen
    HDWP dwp=BeginDeferWindowPos(10);
    for (HWND w=GetPrevSibling(GetDlgItem(Wnd,103));w;w=GetNextSibling(w)) {
     Rect<>r(w);
     r.right-=r.left;	// width
     r.bottom-=r.top;	// height
     ScreenToClient(Wnd,(POINT*)&r);
     r.right+=delta.x;
     if (vsize) r.bottom+=delta.y; else r.top+=delta.y;
     dwp=DeferWindowPos(dwp,w,0,r.left,r.top,r.right,r.bottom,SWP_NOZORDER);
     if (vsize) --vsize;
    }
    EndDeferWindowPos(dwp);
    WinSize.x += delta.x;
    WinSize.y += delta.y;
   }
  }break;

  case WM_TIMER: switch (wParam) {
   case 21: killThread(); break;
  }break;

  case WM_COMMAND: switch (wParam) {

   case 10: if (ghThread) endThread(); else startThread(); break;	// Thread starten oder abwürgen

   case IDCANCEL: killThread(); worker::SaveSettings(); break;
    // EndDialog(Wnd,0); macht ComSel::dialogHandler()

  }break;
 }
 comsel.dialogHandler(Wnd,msg,wParam,lParam);
 switch (msg) {
  case WM_INITDIALOG: {
// Traces werden bereits von der Ressource initialisiert!
//   startThread();
  }return TRUE;

 }
 return FALSE;
}

// Statische Konstruktoren aufrufbar machen
#pragma bss_seg(".CRT$XCA")
char ctor_start;	// Eine Null vor allen Konstruktorzeigern
// Eigentlich würde die Segmentadresse reichen, aber die ist in MSC/C++ nicht zu bekommen.
// In gcc geht das mit dem Linkerskript.
// Konstruktorzeiger landen in ".CRT$XCx" (x beliebig), wobei der Linker die Segmente alphabetisch sortiert
// und wegen Segmentausrichtung (bspw. 8 Byte) Nullen einfügt.
#pragma bss_seg(".CRT$XCZ")
char ctor_end;		// Eine Null nach allen Konstruktorzeigern
#pragma bss_seg()	// Standardverhalten reaktivieren
#pragma comment(linker,"/merge:.CRT=.data")	// beseitigt 2 Linker-Warnings und erzeugt eine neue.
#pragma comment(linker,"/merge:.rdata=.text")
// _initterm(a,e) ruft alle Zeiger zwischen <a> und <e> auf, die nicht Null sind.
// Die Konstruktorfunktionen legen ggf. Destruktorkode für atexit() ab,
// daher gibt es kein Pendant für statische Destruktoren.
extern "C" void _cdecl _initterm(const char&a,const char&e);

int WinMainCRTStartup() {
 _initterm(ctor_start,ctor_end);	// Alle statischen Konstruktorzeiger zwischen ctor_start und ctor_end aufrufen
 ghInstance=GetModuleHandle(0);
 PlotXY::init();
 ExitProcess(UINT(DialogBox(0,MAKEINTRESOURCE(100),0,MainDlgProc)));
}
Detected encoding: UTF-80