#define STRICT
#include "windows.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>  
#include <commdlg.h>
#include <time.h>       
#include <math.h>
#include "resource.h"      

/************************************************************************************/
/*	Programm für einen Peak-Level-Aussteuerungsmesser mit dem DSP-Modul DAM-1		*/
/*	Projekt der Zeitschrift Elrad 													*/
/*																					*/
/*	(C) R. Männel 1996 (außer anders gekennzeichneten Teilen)						*/
/************************************************************************************/


/************************************************************************************/                    
/*	Konstantendefinitionen															*/
/************************************************************************************/
// Strings
#define DAMSTR "RME DAM 1 Testprogramm"

// Farben
#define DAM_ROT RGB(255, 0, 0)
#define DAM_GRUEN RGB(0, 220, 0)                               
#define DAM_SCHWARZ RGB(0,0,0) 
#define DAM_WEISS RGB(255,255,255)

// Funktionsauswahl
#define NOP 0
#define LEVELPEAK 1

/************************************************************************************/                    
/*	Funktionsprototypen   															*/
/************************************************************************************/
int PASCAL WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
BOOL InitApplication(HANDLE);
BOOL InitInstance(HANDLE, int);
long FAR PASCAL __export MainWndProc(HWND, UINT, UINT, LONG);
BOOL DAM_Paint(HWND);
BOOL End_Funct(HWND);
void WindowText(HWND);
void Mw_draw(HWND);   
void FontSetup(HWND hWnd); 
BOOL FAR PASCAL __export About(HWND, unsigned, WORD, LONG);
BOOL FAR PASCAL __export HWSetup(HWND, unsigned, WORD, LONG); 
BOOL FAR PASCAL __export LMSetup(HWND, unsigned, WORD, LONG);
void MoveCenter(HWND);
void Paint_LevelPeak(HWND);                
void Rec_LevelPeak(HWND);
void Level_Bar(HDC, unsigned short, RECT);                                              
void Level_Text(HDC, unsigned short, short, short, short, BOOL);
void Level_Marker(HDC, unsigned short, RECT);
void Gen_Scal(HDC,short, RECT, short, BOOL);                                                       
void Sleep60(void);  
BOOL load_DSK(char *);   
unsigned int read4(char *);
void ixmit(int);  
void cxmit(char);
unsigned int StartCom(HWND);
void reset(void);
void EndComm(void);

/************************************************************************************/                    
/*	Globale Variablen     															*/
/************************************************************************************/
// Window-Variable
HWND hDAMWnd;					// Handle des Hauptfensters
HINSTANCE hInst;           		// Instance für Programm
HCURSOR hCross, hArrow, hHour;	// mögliche Cursor-Formen
short cxClient,cyClient;		// Größenkoordinaten des Hauptfensters
// Variable für Darstellung         
short texthight;   				// Höhe des Ausgabefensters für Texte (Fontabhängig)
short spacebr;               	// (angenommene) Leerzeichenbreite = texthight/4
short barbr;          			// Breite eines Balkens
RECT level_bars;   				// Lage der Pegelanzeigen im Fenster
RECT bars[2];					// Lage der einzelnen Balken
BOOL noyscd=FALSE,noxleg=FALSE;	// Flags für (Nicht-)Darstellung der Achsenbeschriftungen
LOGFONT lf;						// Font-Daten 
short LMyscmax=0,LMyscmin=-80;  // Anfang und Ende des Darstellungsbereiches in dB
short LMyswitch=-10;  			// Pegel für Farbumschaltung
// Steuerungs-Variable
unsigned short OverMax=2;		// Anzahl der Full-Scale-Werte, bis Over-Erkennung einsetzt
short HoldTime=40;				// Dauer der Maximum-Speicherung (in Empfangszyklen)
BOOL IgnErr=FALSE;				// Flag: Empfangsfehler ignorieren
UINT WatchdogCT=0;				// Watchdogzähler
short functsel=NOP;				// Speicher, welche Funktion gerade aktiv
short idComDev=0;				// Devicehandle für serielle Schnittstelle
BOOL RS232activ=FALSE;			// Flag: gibt an, daß DSP Daten senden müßte	
char COMPort[6]={"COM2"};		// COM-Port  
char COMBaud[6]={"19200"};		// Baudrate


/************************************************************************************/                    
/*	WinMain: Initialisiert Fenster-Daten und übergibt Messages                      */
/*  (nutzt Unterprogramme InitApplication und InitInstance)							*/
/*																					*/
/*	Standardlösung für MSVC															*/
/************************************************************************************/
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;

    if (!hPrevInstance)
    if (!InitApplication(hInstance))
        return (FALSE);

    if (!InitInstance(hInstance, nCmdShow))
        return (FALSE); 
        
	while (GetMessage(&msg, NULL, NULL, NULL)) 
	{
    	TranslateMessage(&msg);
    	DispatchMessage(&msg);
    }
    return (msg.wParam);
}


BOOL InitApplication(HANDLE hInstance)
{
    WNDCLASS  wc; 

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = MainWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(hInstance, "IDI_DAM");
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
    wc.lpszMenuName =  "MainMenu";
    wc.lpszClassName = "DAMClass";

    return (RegisterClass(&wc));
}

BOOL InitInstance(HANDLE hInstance, int nCmdShow)
{
    HWND            hWnd;

    hInst = hInstance;

    hWnd = CreateWindow(
        "DAMClass",
        DAMSTR,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if (!hWnd)
        return (FALSE);
	hDAMWnd=hWnd;
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    return (TRUE);
}


/************************************************************************************/                    
/*	MainWndProc: Haupt-Fensterprozedur, bearbeitet alle übergebenen Messages        */
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
long FAR PASCAL __export MainWndProc(HWND hWnd,UINT message, UINT wParam, LONG lParam)
{
    FARPROC lpProcAbout;
    FARPROC lpProcLMSetup; 
    FARPROC lpProcHWSetup;        
    static UINT ID_Watchdog;
    HMENU menu;       
    HFONT hFont;
    
    // Auswahl, welche Message vorliegt              
    switch (message) {
	    case WM_COMMAND: {		// Menü-Eingaben   
	    	menu = GetMenu(hWnd);                       
	        switch(wParam) {

	            case IDM_Exit: 
					EndComm();
					DestroyWindow(hWnd);
	                return 0;
		
				case IDM_LEVELPEAK:
					if(functsel!=LEVELPEAK)
					{                    
						functsel=LEVELPEAK;    
						CheckMenuItem(menu, (UINT)IDM_LEVELPEAK, MF_CHECKED); 
						if(StartCom(hWnd)==0)
						{             
						    // Hardwareoptionen abschalten
							EnableMenuItem(menu,(UINT)IDM_HardSetup,MF_DISABLED|MF_GRAYED);
							Paint_LevelPeak(hWnd); 
							WindowText(hWnd);
						}
						else End_Funct(hWnd);  
						SetCursor(hArrow);
					}	
					return 0;
		            
				case IDM_NOP:
					if(functsel!=NOP)                       
					{     
						End_Funct(hWnd);
						functsel=NOP;      
						SetCursor(hArrow);
					}	
					return 0;					
		            
	         	case IDM_IgnErr: 
	            	if (IgnErr)                   
	            	{
						CheckMenuItem(menu, (UINT)IDM_IgnErr, MF_UNCHECKED);
						IgnErr=FALSE;
					}
					else
					{
						CheckMenuItem(menu, (UINT)IDM_IgnErr, MF_CHECKED);
						IgnErr=TRUE;
					}	
					return 0;	
		
	            case IDM_LMSetup:                   
	                lpProcLMSetup = MakeProcInstance((FARPROC)LMSetup, hInst);
	                DialogBox(hInst,"LMSetup", hWnd,(DLGPROC)lpProcLMSetup);
	                FreeProcInstance(lpProcLMSetup);
	                DAM_Paint(hWnd);
	                return 0;
		
	            case IDM_HardSetup:                   
	                lpProcHWSetup = MakeProcInstance((FARPROC)HWSetup, hInst);
	                DialogBox(hInst,"HWSetup", hWnd,(DLGPROC)lpProcHWSetup);
	                FreeProcInstance(lpProcHWSetup);
	                return 0;         
		
				case IDM_FONTS:
					FontSetup(hWnd);
					return 0;
		
	            case IDM_ABOUT:
	                lpProcAbout = MakeProcInstance((FARPROC)About, hInst);
	                DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)lpProcAbout);
	                FreeProcInstance(lpProcAbout);
	                return 0;
		
	            default:
	                return (DefWindowProc(hWnd, message, wParam, lParam));
			}
        } 

	    case WM_CREATE:		// Erzeugung des Fensters (erster Aufruf)
	    	ID_Watchdog=SetTimer(NULL,0,100,NULL);
	    	SetTimer(hWnd,ID_Watchdog,500,NULL);
			hArrow = LoadCursor(NULL, IDC_ARROW);
	        hHour = LoadCursor(NULL, IDC_WAIT);
	        hFont=GetStockObject(SYSTEM_FONT);
	        GetObject(hFont, sizeof(LOGFONT), &lf); 
	        return 0;
	                            
	    case WM_PAINT:  	// Neuerstellen der Darstellung im Fenster
	    	if(DAM_Paint(hWnd)) return 0;
	    		else return (DefWindowProc(hWnd, message, wParam, lParam));

	    case WM_COMMNOTIFY: 	// RS-232-Empfangspuffer gefüllt
	    	if ((LOWORD(lParam)==CN_RECEIVE) && ((int)wParam==idComDev) 
	    		&& (functsel==LEVELPEAK)) {
	        		Rec_LevelPeak(hWnd); 
		        	return 0; 
			}		            
   			else return (DefWindowProc(hWnd, message, wParam, lParam));
	
	    case WM_TIMER:		// Timerstep
	   		if (WatchdogCT<254) WatchdogCT++;
	   		if ((WatchdogCT>3) && (functsel==LEVELPEAK) && (RS232activ)) { 
				SetCursor(hHour);
				EndComm();                            
				if(StartCom(hWnd)!=0) End_Funct(hWnd);
				SetCursor(hArrow);
           		return 0; 
			}
	        else
				return (DefWindowProc(hWnd, message, wParam, lParam));		                   
		
		case WM_CLOSE: 		// Fenster wird geschlossen (vor Programmende)
			EndComm();
			return (DefWindowProc(hWnd, message, wParam, lParam));

	    case WM_DESTROY:   	// Programmende
	    	EndComm();                   
	        PostQuitMessage(0);
	        return 0;
	
	    default:  	// jede andere Message wird mit Standardprozedur bearbeitet
	        return (DefWindowProc(hWnd, message, wParam, lParam));
    } 
}                                   

/************************************************************************************/                    
/*	DAM_Paint: 	ruft jeweile für jeweils laufende Funktion die Prozedur 			*/
/*  			zur Fensterverwaltung auf			            					*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
BOOL DAM_Paint(HWND hWnd)
{
	switch(functsel)
	{
		case NOP: 
			Mw_draw(hWnd); 
			return 1;
		
		case LEVELPEAK:	
			Paint_LevelPeak(hWnd);
	        return 1; 
	    
	    default: return 0;
	}
}	  

/************************************************************************************/                    
/*	End_Funct: beendet jeweils laufende Funktion und stellt Ausgangszustand her 	*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
BOOL End_Funct(HWND hWnd)
{
	HMENU menu;          
	
    SetCursor(hHour);    
    // Fenster in Ordnung bringen
	Mw_draw(hWnd); 				
	// Menü bearbeiten
	menu = GetMenu(hWnd);             
	// Funktionsausahlmenü rücksetzen
	CheckMenuItem(menu, (UINT)IDM_LEVELPEAK, MF_UNCHECKED);
	// Hardwareoptionen zuschalten
	EnableMenuItem(menu,(UINT)IDM_HardSetup,MF_ENABLED); 
	// evtuelle bisherige Kommunikation abschließen
	EndComm();   
	functsel=NOP;
	WindowText(hWnd);
	return 1;
}             

/************************************************************************************/                    
/*	WindowText: Gibt Text im Statusbar des Fenster aus                              */
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void WindowText(HWND hWnd) {

	char hilftext[255];
    
    strcpy(hilftext,DAMSTR);
    switch(functsel) {
    	case NOP:	
    		strcat(hilftext," - No Operation");
    		break;
		case LEVELPEAK:	
			strcat(hilftext," - Peak Level Meter");
    		break;     		
    }
	SendMessage(hWnd, WM_SETTEXT, sizeof(hilftext),
	    (LPARAM) ((LPSTR) hilftext));
}                                                   

/************************************************************************************/                    
/*	Mw_draw: "Zeichnet" (leeres) Hauptfenster bei NOP	                            */
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void Mw_draw(HWND hWnd)
{ 
	HDC hDC;                          
    PAINTSTRUCT ps;                   

    InvalidateRect(hWnd, NULL, TRUE); 
    hDC = BeginPaint(hWnd, &ps);

    EndPaint (hWnd, &ps);
	  	        
}

/************************************************************************************/                    
/*	FontSetup: Prozedur zum Aufruf der Dialogbox zur Schriftarteneinstellung		*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void FontSetup(HWND hWnd) 
{
	CHOOSEFONT cf;
	
	/* Set all structure fields to zero. */
	memset(&cf, 0, sizeof(CHOOSEFONT));
	
	cf.lStructSize = sizeof(CHOOSEFONT);
	cf.hwndOwner = hWnd;
	cf.lpLogFont = &lf;
	cf.Flags = CF_SCREENFONTS | CF_FORCEFONTEXIST|CF_INITTOLOGFONTSTRUCT|CF_ANSIONLY;
	cf.nFontType = SCREEN_FONTTYPE;
	if(ChooseFont(&cf))	DAM_Paint(hWnd);
}
     
/************************************************************************************/                    
/*	About: Dialogbox-Routine für Dialogbox mit Informationen zum Programm 			*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
BOOL FAR PASCAL __export About(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{    
	static HBRUSH hBK;   
	
    switch (message) {
	    case WM_INITDIALOG: 
			// in der Mitte anordnen
			MoveCenter(hDlg);               		
	        return (TRUE);
	
	    case WM_COMMAND:
	        if (wParam == IDOK
	                || wParam == IDCANCEL) {
	        EndDialog(hDlg, TRUE);
	        return (TRUE);
	        }
	        break;  
	    default: return (FALSE);
    }
    return (FALSE);
}

/************************************************************************************/                    
/*	HWSetup: Dialogbox-Routine für Einstellung der Hardwareoptionen					*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
BOOL FAR PASCAL __export HWSetup(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{     
	static DWORD COMIndex, BaudIndex;   
	static char COM_alt[10],Baud_alt[10];
		
    switch (message) 
    {
    	case WM_INITDIALOG:                    
            // Vorgaben in Listboxen schreiben             
            SendDlgItemMessage(hDlg, IDC_COMBO_COM,
    				CB_ADDSTRING, 0, (LPARAM) ((LPSTR) "COM1")); 
    		SendDlgItemMessage(hDlg, IDC_COMBO_COM,
    				CB_ADDSTRING, 0, (LPARAM) ((LPSTR) "COM2"));
            SendDlgItemMessage(hDlg, IDC_COMBO_COM,
    				CB_ADDSTRING, 0, (LPARAM) ((LPSTR) "COM3")); 
    		SendDlgItemMessage(hDlg, IDC_COMBO_COM,
    				CB_ADDSTRING, 0, (LPARAM) ((LPSTR) "COM4"));
			SendDlgItemMessage(hDlg, IDC_COMBO_Baud,
    				CB_ADDSTRING, 0, (LPARAM) ((LPSTR) "9600")); 
    		SendDlgItemMessage(hDlg, IDC_COMBO_Baud,
    				CB_ADDSTRING, 0, (LPARAM) ((LPSTR) "19200")); 
			// Bisherige Werte selektiern
 			COMIndex = SendDlgItemMessage(hDlg, IDC_COMBO_COM,
    			CB_FINDSTRING, 0, (LPARAM) ((LPSTR) COMPort));
			if (COMIndex != CB_ERR)
               	SendDlgItemMessage(hDlg, IDC_COMBO_COM,CB_SETCURSEL,(WPARAM)COMIndex,(LPARAM)0);      				
			BaudIndex = SendDlgItemMessage(hDlg, IDC_COMBO_Baud,
    			CB_FINDSTRING, 0, (LPARAM) ((LPSTR) COMBaud));
			if (BaudIndex != CB_ERR)
               	SendDlgItemMessage(hDlg, IDC_COMBO_Baud,CB_SETCURSEL,(WPARAM)BaudIndex,(LPARAM)0);      			
			// in der Mitte anordnen
			MoveCenter(hDlg);               		
			return TRUE;

    	case WM_COMMAND:
        	switch (wParam) 
        	{   
        		case IDOK: 
        			COMIndex=SendDlgItemMessage(hDlg, IDC_COMBO_COM, CB_GETCURSEL, 0, 0);
        			BaudIndex=SendDlgItemMessage(hDlg, IDC_COMBO_Baud, CB_GETCURSEL, 0, 0);
					if ((COMIndex != CB_ERR)&&(BaudIndex != CB_ERR)) {
    					SendDlgItemMessage(hDlg, IDC_COMBO_COM,
        					CB_GETLBTEXT, (WPARAM) COMIndex, (LPARAM) ((LPSTR) COMPort));
    					SendDlgItemMessage(hDlg, IDC_COMBO_Baud,
        					CB_GETLBTEXT, (WPARAM) BaudIndex, (LPARAM) ((LPSTR) COMBaud));
						EndDialog(hDlg, TRUE);
					}     
	                else {
	                	MessageBeep(MB_ICONEXCLAMATION);
						MessageBox(hDlg,"Wrong data selection!",NULL,MB_APPLMODAL|MB_OK|MB_ICONEXCLAMATION);	                
					}
            		break;
        		case IDCANCEL:
            		EndDialog(hDlg, TRUE);
            		break;
        	} 
        	return (0);
    }
    return (FALSE);
}
 
/************************************************************************************/                    
/*	LMSetup: Dialogbox-Routine für Einstellung der Pegelmesser-Darstellungsoptionen */
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
BOOL FAR PASCAL __export LMSetup(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{
    static int tempLMyscmax,tempLMyscmin,tempLMyswitch;
	static unsigned int tempovrmax;                          
	static BOOL IntOK;
	static short hilfint;
	
    switch (message) 
    {
    	case WM_INITDIALOG:  
			// in der Mitte anordnen
			MoveCenter(hDlg);               		
           	tempLMyscmax=LMyscmax;
        	tempLMyscmin=LMyscmin;                    
        	tempLMyswitch=LMyswitch;
        	tempovrmax=OverMax;
        	SetDlgItemInt(hDlg, IDC_EDIT_LMyscmax, tempLMyscmax,TRUE);
			SetDlgItemInt(hDlg, IDC_EDIT_LMyscmin, tempLMyscmin,TRUE);        	
			SetDlgItemInt(hDlg, IDC_EDIT_LMyswitch, tempLMyswitch,TRUE);   
			SetDlgItemInt(hDlg, IDC_EDIT_ovrmax, tempovrmax,TRUE);        	     	
        	return (TRUE);           
		
		case WM_VSCROLL: 
			switch (GetDlgCtrlID((HWND)HIWORD(lParam)))
			{ 
				case IDC_SCROLL_LMyscmax: 
					hilfint=GetDlgItemInt(hDlg, IDC_EDIT_LMyscmax, &IntOK,TRUE);    
					if(IntOK) tempLMyscmax=__max(-160,__min(((hilfint-10)/20)*20,0));  
					switch (wParam)
					{
			    		case SB_LINEUP:
			    			if (tempLMyscmax<0) tempLMyscmax=(tempLMyscmax/20+1)*20; 
                    		break;
                    	case SB_LINEDOWN:  
                    		if (tempLMyscmax>-140) tempLMyscmax=(tempLMyscmax/20-1)*20; 
                    }  
                    SetDlgItemInt(hDlg, IDC_EDIT_LMyscmax, tempLMyscmax, TRUE);       
                    break;
                    
            	case IDC_SCROLL_LMyscmin: 
					hilfint=GetDlgItemInt(hDlg, IDC_EDIT_LMyscmin, &IntOK,TRUE);    
					if(IntOK) tempLMyscmin=__max(-160,__min(((hilfint-10)/20)*20,-20));  
					switch (wParam)
					{
			    		case SB_LINEUP:                                                                
			    			if (-20>tempLMyscmin) tempLMyscmin=(tempLMyscmin/20+1)*20; 
        					break;
                    	case SB_LINEDOWN:
                    	 	if (tempLMyscmin>-160) tempLMyscmin=(tempLMyscmin/20-1)*20; 
                    } 
                    SetDlgItemInt(hDlg, IDC_EDIT_LMyscmin, tempLMyscmin,TRUE);                 
                    break;          
                    
               case IDC_SCROLL_LMyswitch: 
					hilfint=GetDlgItemInt(hDlg, IDC_EDIT_LMyswitch, &IntOK,TRUE);    
					if(IntOK) tempLMyswitch=__max(-160,__min(hilfint,0));  
					switch (wParam)
					{
			    		case SB_LINEUP:
			    			if (tempLMyswitch<0) tempLMyswitch++; 
        					break;
                    	case SB_LINEDOWN:
                    	 	if (tempLMyswitch>-160) tempLMyswitch--; 
                    } 
                    SetDlgItemInt(hDlg, IDC_EDIT_LMyswitch, tempLMyswitch,TRUE); 
					break;
               case IDC_SCROLL_ovrmax: 
					hilfint=GetDlgItemInt(hDlg, IDC_EDIT_ovrmax, &IntOK,TRUE);    
					if(IntOK) tempovrmax=__max(1,__min(hilfint,20));  
					switch (wParam)
					{
			    		case SB_LINEUP:
			    			if (tempovrmax<20) tempovrmax++; 
        					break;
                    	case SB_LINEDOWN:
                    	 	if (tempovrmax>1) tempovrmax--;
                    } 
                    SetDlgItemInt(hDlg, IDC_EDIT_ovrmax, tempovrmax,TRUE);    
            }  
			return 0;   

		case WM_COMMAND:
        	switch (wParam) 
        	{
        		case IDOK:    
					hilfint=GetDlgItemInt(hDlg, IDC_EDIT_LMyscmax, &IntOK,TRUE);    
					if(IntOK) tempLMyscmax=__max(-140,__min(((hilfint-10)/20)*20,0));  
					hilfint=GetDlgItemInt(hDlg, IDC_EDIT_LMyscmin, &IntOK,TRUE);    
					if(IntOK) tempLMyscmin=__max(-160,__min(((hilfint-10)/20)*20,0));  
					hilfint=GetDlgItemInt(hDlg, IDC_EDIT_LMyswitch, &IntOK,TRUE);    
					if(IntOK) tempLMyswitch=__max(-160,__min(hilfint,0));  
					hilfint=GetDlgItemInt(hDlg, IDC_EDIT_ovrmax, &IntOK,TRUE);    
					if(IntOK) tempovrmax=__max(1,__min(hilfint,20));  
            		EndDialog(hDlg, TRUE);
            		LMyscmax=tempLMyscmax;
            		LMyscmin=__max(-160,__min(((tempLMyscmin-10)/20)*20,LMyscmax-20));  
            		LMyswitch=__max(LMyscmin,__min(tempLMyswitch,LMyscmax));  
            		OverMax=tempovrmax;
            		break;
        		case IDCANCEL:
            		EndDialog(hDlg, TRUE);
            		break;
        	} 
        	return (0);
    }
    return (FALSE);
}


/************************************************************************************/                    
/*	MoveCenter: Ordnet Fenster in der Mitte des Hauptfensters an                    */
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void MoveCenter(HWND hwin)
{
	RECT lage,gesamt;                    
	short xlen,ylen;
	
	GetWindowRect(hwin,&lage);                                              
	xlen=lage.right-lage.left;
	ylen=lage.bottom-lage.top;
	GetWindowRect(hDAMWnd,&gesamt); 
	MoveWindow(hwin,__max(0,gesamt.left+(gesamt.right-gesamt.left-xlen)/2),
		__max(0,gesamt.top+(gesamt.bottom-gesamt.top-ylen)/2),xlen,ylen,TRUE);
}

/************************************************************************************/
/*	Paint_LevelPeak: Verwaltet das Fenster für die Pegelmesser-Funktion				*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void Paint_LevelPeak(HWND LMWnd)                
{
	HDC hDC;   
    PAINTSTRUCT ps; 
	HPEN hOldPen, hNewPen;         
	HFONT hFont,oldFont;	
	short i,j,yscbr,xlegbr;
	char szHilf[30];                                                         
	
    InvalidateRect(LMWnd, NULL, TRUE); 	// Gesamtes Fenster für Darstellung,
    hDC = BeginPaint(LMWnd, &ps);       // Zeichenfunktionen für Fenster initialisieren
    SetBkColor(hDC,GetSysColor(COLOR_BTNFACE));
    
    cxClient = ps.rcPaint.right - ps.rcPaint.left; // Bestimmung der Größe des Fensters
    cyClient = ps.rcPaint.bottom - ps.rcPaint.top;

    SetMapMode(hDC,MM_TEXT);	    	// Einstellung der Einheiten 
    SetViewportOrg (hDC, 0, cyClient);  
    SetTextColor(hDC,DAM_SCHWARZ);	// schwarzer Text
    // Font erzeugen
    hFont=CreateFontIndirect(&lf);
    if(hFont) oldFont=SelectObject(hDC,hFont);
    
    // Bildaufbau in Abhängigkeit von der Fenstergröße  
    strcpy(szHilf,"  -100 ");
    yscbr=LOWORD(GetTextExtent(hDC,szHilf,strlen(szHilf)));	// Breite Y-Beschriftung
    strcpy(szHilf," -188.8 ");
    xlegbr=2*LOWORD(GetTextExtent(hDC,szHilf,strlen(szHilf)));	
	texthight=HIWORD(GetTextExtent(hDC,szHilf,strlen(szHilf)));        
	spacebr=texthight/4;
	
	if (cxClient<yscbr+xlegbr) noxleg=TRUE;	// kein Platz für X-Beschriftung     
		else noxleg=FALSE;
	if (cxClient<yscbr+80) noyscd=TRUE;	// kein Platz für Y-Beschriftung
		else noyscd=FALSE;                                               
		                        
	if (cyClient<8*texthight) // zu flach
		noxleg=TRUE;
	// Lage in y-Richtung
    if (noxleg) {
    	level_bars.top=-cyClient+texthight;	// oberer Rand ohne Pegelangabe
    	level_bars.bottom=-texthight;		// unterer Rand ohne Legende
    }
    else {
    	level_bars.top=-cyClient+texthight*2;	// oberer Rand mit Platz für Pegelangabe	
    	level_bars.bottom=-texthight*2;			// unterer Rand mit Platz für Legende
    }                    
    // Lage in x-Richtung
    level_bars.right=cxClient-2*spacebr;	// rechter Rand
    if (noyscd) 
    	level_bars.left=2*spacebr;			// linker Rand ohne Skalierung
    else
    	level_bars.left=yscbr;			// linker Rand mit Skalierung
	// Begrenzung auf sinnvolle Breite
	if (level_bars.right-level_bars.left>xlegbr) {                                  
		if(noyscd) {
			level_bars.left=(cxClient-xlegbr)/2;
			level_bars.right=(cxClient+xlegbr)/2;
		}
		else {
			level_bars.left=(cxClient-xlegbr-yscbr)/2+yscbr;
			level_bars.right=(cxClient+xlegbr+yscbr)/2;
		}
	}   
	
	// Breite eines Balkens
	barbr=(level_bars.right-level_bars.left)/4;        
	
	// Festlegung Fenster für Balkenanzeigen
	for(i=0;i<2;i++) {
		bars[i].left=level_bars.left+((4*i+1)*barbr)/2; 
		bars[i].right=level_bars.left+((4*i+3)*barbr)/2;
		bars[i].top=level_bars.top;
		bars[i].bottom=level_bars.bottom;
	}
	// Skalierung ausgeben lassen
	Gen_Scal(hDC, 2, bars[0], barbr, !noyscd);
	// Ausgabe Legende                                      
	if(!noxleg) {
	// Legende y-Achse                                   
		SetTextAlign(hDC,TA_RIGHT);   	
		sprintf(szHilf, "dB ");
		TextOut(hDC, level_bars.left,level_bars.top-(texthight*3)/2,szHilf,strlen(szHilf));
		SetTextAlign(hDC,TA_CENTER);   	// Text auf Mitte
		strcpy(szHilf,"LEFT");
		TextOut(hDC, level_bars.left+(barbr*1),level_bars.bottom+texthight/2,szHilf,strlen(szHilf));
        strcpy(szHilf,"RIGHT");
        TextOut(hDC, level_bars.left+(barbr*3),level_bars.bottom+texthight/2,szHilf,strlen(szHilf));
	}                 
	// Schatten zeichnen - dunkle Linien 
	hNewPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
    hOldPen = SelectObject(hDC, hNewPen);
	for(j=1;j<4;j+=2) {
    	MoveTo(hDC,level_bars.left+((10*j-9)*barbr)/10,level_bars.bottom+texthight/3);  	
		LineTo(hDC,level_bars.left+((10*j-9)*barbr)/10,level_bars.top-texthight/2);
		LineTo(hDC,level_bars.left+((10*j+9)*barbr)/10,level_bars.top-texthight/2);  
	}
	SelectObject(hDC,hOldPen);
	DeleteObject(hNewPen);          
	// helle Linien
	hNewPen = CreatePen(PS_SOLID, 1, DAM_WEISS);
    hOldPen = SelectObject(hDC, hNewPen);
    for(j=1;j<4;j+=2) {
	    MoveTo(hDC,level_bars.left+((10*j+9)*barbr)/10,level_bars.top-texthight/2);  
	    LineTo(hDC,level_bars.left+((10*j+9)*barbr)/10,level_bars.bottom+texthight/3);
		LineTo(hDC,level_bars.left+((10*j-9)*barbr)/10,level_bars.bottom+texthight/3);
    }
    SelectObject(hDC,hOldPen);
	DeleteObject(hNewPen);          
	// Font entfernen
	if(hFont) SelectObject(hDC,oldFont);
	DeleteObject(hFont);

    EndPaint (LMWnd, &ps);
}

/************************************************************************************/
/*	Rec_LevelPeak:	Empfängt die RS232-Daten und stellt sie als Pegel dar 			*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void Rec_LevelPeak(HWND hWnd)
{
	unsigned char buff;
	HDC hDC;                
	HFONT hFont,oldFont;	    
	static unsigned char bytenum,chksum;
	static unsigned short peaklefthi, peakrighthi;
	static unsigned short peakleftmax, peakrightmax;
	static unsigned short peaklefthold, peakrighthold,peaklefthold1, peakrighthold1;
	static unsigned short Overleft,Overright;
	static unsigned short overlefthold=0,overrighthold=0;
	static short peakleftct,peakrightct;
	static BOOL  peakleftfall=TRUE, peakrightfall=TRUE;
	static unsigned char Error=0,ErCt=0;
	char szHilf[30];
	RECT textwin;
	
	GetCommError(idComDev,NULL);
	while(ReadComm(idComDev,&buff,1))
	{    
		if (bytenum<30) bytenum++;
		if (buff==255) {
			bytenum=0;
			chksum=0;
			peaklefthi=0,
			peakrighthi=0;
			Overleft=0;
			Overright=0;			
		}       
		if (buff<16) chksum+=buff;
		if ((bytenum>=1) && (bytenum<=4)) peaklefthi=peaklefthi/16+buff*4096;
		if ((bytenum>=5) && (bytenum<=8)) peakrighthi=peakrighthi/16+buff*4096; 
		if (bytenum==4)	{                                     
			if(peaklefthi) peaklefthi=(short)(log10(32768.0/(double)peaklefthi)*800+0.5);
				else peaklefthi=10000;
			if (peakleftmax+2>peaklefthi)	// Abarbeitung Peak (Bar-Anzeige)
			{
				peakleftmax=peaklefthi;     // größer als Anzeigewert -> neuer Wert
				peakleftfall=FALSE;
			}	
			else  
				peakleftfall=TRUE;          // sonst auf Rücklauf schalten
			if (peaklefthold+2>peaklefthi)  // Abarbeitung Max-Marker
			{
				peaklefthold=peaklefthi;    // neuer Maximalwert -> speichern 
				peakleftct=HoldTime;		// und "Zeitzähler" setzen
			}	
			else		                    // kein neuer Maximalwert
			{
				peakleftct--;               // -> Zeitzähler dekrementieren
				if (peakleftct==HoldTime/2) peaklefthold1=8000;    // wenn Zeitzähler /2
															// -> 2. Stufe aktivieren
				if (peakleftct<0) 			// Zeitzähler abgelaufen
				{
					peaklefthold=peaklefthold1;   // -> auf 2. Stufe gehen
					peakleftct=HoldTime;
				}	
			}
			if (peaklefthold1+2>peaklefthi)	peaklefthold1=peaklefthi;	// 2. Stufe
																// Maximum erkennen
		}
		if (bytenum==8) {                    
			if(peakrighthi) peakrighthi=(short)(log10(32768.0/(double)peakrighthi)*800+0.5);
				else peakrighthi=10000;
			if (peakrightmax+2>peakrighthi)	{
				peakrightmax=peakrighthi;
				peakrightfall=FALSE;
			}	
			else
				peakrightfall=TRUE;
			if (peakrighthold+2>peakrighthi) {
				peakrighthold=peakrighthi;
				peakrightct=HoldTime;
			}	
			else {
				peakrightct--;
				if (peakrightct==HoldTime/2) peakrighthold1=8000;
				if (peakrightct<0) {
					peakrighthold=peakrighthold1;
					peakrightct=HoldTime;
				}	
			}
			if (peakrighthold1+2>peakrighthi)	peakrighthold1=peakrighthi;		
		}
		if ((bytenum>=9) && (bytenum<=12)) Overleft=Overleft/16+buff*4096;
        if ((bytenum>=13) && (bytenum<=16)) Overright=Overright/16+buff*4096;
		if (bytenum==17) {   
			if ((buff!=0) && (buff!=4))	{
				if (ErCt<10) ErCt++;
				if (ErCt>5) Error=buff;
			}	
			else {
				if (ErCt>0) ErCt--;	
				if (ErCt<5) Error=0;
			}	                   
		}                    
		if ((bytenum==18) && ((buff&0x0f)==(chksum&0x0f))){   
			WatchdogCT=0;	//Watchdogzähler rücksetzen     
			// Erkennung und Speicherung von Overflows       
			if (Overleft>=OverMax) overlefthold=HoldTime;
				else 
					if(overlefthold>0) overlefthold--;
			if (Overright>=OverMax) overrighthold=HoldTime;
				else 
					if(overrighthold>0) overrighthold--;
			// Grafische Ausgabe
			hDC = GetDC(hWnd);
			if (hDC) {         
				SetBkColor(hDC,GetSysColor(COLOR_BTNFACE)); 
				SetMapMode(hDC,MM_TEXT);	  // Einstellung der Einheiten 
				SetViewportOrg (hDC, 0, cyClient);
				// Font erzeugen
				hFont=CreateFontIndirect(&lf);
				if(hFont) oldFont=SelectObject(hDC,hFont);                
				if(((Error!=5)&&(Error!=3)&&(Error!=7)) || (IgnErr)) {// Erkennung Fehler 
					// Ausgabe Text                  
					if(!noxleg) {
		                Level_Text(hDC, peaklefthold, level_bars.left+(1*barbr), level_bars.top-(texthight*3)/2, 2*barbr, (overlefthold>0 ? TRUE:FALSE));
		                Level_Text(hDC, peakrighthold, level_bars.left+(3*barbr), level_bars.top-(texthight*3)/2, 2*barbr, (overrighthold>0 ? TRUE:FALSE) );
					}
				}   
				else
				{
					// Ausgabe Fehlertext
					if(!noxleg) {
				    	if (Error==7)
				    		sprintf(szHilf, "<<< No Lock Error >>>");	
				    	else
				    		sprintf(szHilf, "<<< Receive Error >>>");		
						SetTextAlign(hDC,TA_CENTER);   	// Text auf Mitte				    	
						SetRect(&textwin,level_bars.left,level_bars.top-(texthight*1)/2,
							level_bars.right,level_bars.top-(texthight*3)/2);
						ExtTextOut(hDC, level_bars.left+(2*barbr),level_bars.top-(texthight*3)/2,
							ETO_CLIPPED|ETO_OPAQUE,&textwin,szHilf,strlen(szHilf),NULL);	  
					}
					peakleftmax=peaklefthold=10000;
					peakrightmax=peakrighthold=10000;
				}
				// Ausgabe Bars und Marker
				Level_Bar(hDC,peakleftmax,bars[0]);					
				Level_Marker(hDC,peaklefthold,bars[0]);
				Level_Bar(hDC,peakrightmax,bars[1]);
				Level_Marker(hDC,peakrighthold,bars[1]);					
				// Font entfernen
				if(hFont) SelectObject(hDC,oldFont);
				DeleteObject(hFont);
			}
			ReleaseDC (hWnd, hDC);
    	}
		if (peakleftfall) peakleftmax+=2;
		if (peakrightfall) peakrightmax+=2;	
	}    
}		    

/************************************************************************************/	            
/*	Level_Bar: gibt den Pegel level (dB*-40!) als Bar im RECT bar aus				*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void Level_Bar(HDC hDC, unsigned short level, RECT bar)
{
	long bar_max, bar_level, bar_switch,skal;
	HBRUSH NewBrush, OldBrush;
	
	// Skalierung berechnen	                                                   
	skal=(long)(LMyscmax-LMyscmin)*(long)40;	                                                   
	bar_max=(long)(bar.bottom-bar.top);
	// Umrechnung der Pegel in Abstand von bar.top		
	bar_level=(bar_max*((long)level+(long)LMyscmax*40))/skal;
	bar_level=__min(__max(0,bar_level),bar_max);
	bar_switch=(bar_max*(long)((-LMyswitch+LMyscmax)*40))/skal;
	bar_switch=__min(__max(0,bar_switch),bar_max);
    // Balken grün
	NewBrush = CreateSolidBrush(GetNearestColor(hDC,DAM_GRUEN));
    OldBrush = SelectObject(hDC, NewBrush);
	Rectangle(hDC,bar.left,bar.top+(short)(__max(bar_level,bar_switch)),bar.right,bar.bottom+1);	
	SelectObject(hDC, OldBrush);
    DeleteObject(NewBrush);                                                          
    // Balken rot
    if(bar_level<bar_switch) {
		NewBrush = CreateSolidBrush(GetNearestColor(hDC,DAM_ROT));
	    OldBrush = SelectObject(hDC, NewBrush);
		Rectangle(hDC,bar.left,bar.top+(short)bar_level,bar.right,bar.top+(short)bar_switch+1);	
		SelectObject(hDC, OldBrush);
	    DeleteObject(NewBrush);                                             
    }
    // Balken schwarz 
	NewBrush = CreateSolidBrush(GetNearestColor(hDC,DAM_SCHWARZ));
    OldBrush = SelectObject(hDC, NewBrush);
	Rectangle(hDC,bar.left,bar.top-texthight/4,bar.right,bar.top+(short)bar_level);	
	SelectObject(hDC, OldBrush);
    DeleteObject(NewBrush);        
}

/************************************************************************************/
/*	Level_Text:	gibt den Pegel level (dB*-40!) als Text an der Stelle x,y (Mitte, 	*/
/*	Unten) mit der maximalen Breite von textbr aus, wenn ovr=TRUE erscheint der 	*/
/*	Text OVR      																	*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void Level_Text(HDC hDC, unsigned short level, short x, short y, short textbr, BOOL ovr)
{
	RECT textwin;
    char hilfstr[30];              
    float dblevel;

	SetTextAlign(hDC,TA_CENTER);   	// Text auf Mitte
	if(ovr) sprintf(hilfstr,"OVR");
	else {
		if(level>6000) sprintf(hilfstr,"UFL");
			else {
				dblevel=(float)level/-40;
				if(dblevel>-0.06) dblevel=0;
				sprintf(hilfstr, "%.1f",dblevel);
			}
	}
	SetRect(&textwin,x-textbr/2,y+texthight,x+textbr/2,y);
	ExtTextOut(hDC, x,y,ETO_CLIPPED|ETO_OPAQUE,&textwin,hilfstr,strlen(hilfstr),NULL);	  
}

/************************************************************************************/
/*	Level_Marker:	gibt den Pegel level (dB*-40!) als Marker im RECT bar aus       */ 
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void Level_Marker(HDC hDC, unsigned short level, RECT bar)
{
	long bar_max, bar_level,skal;
	short barbr;
	HBRUSH NewBrush, OldBrush;
	POINT Mark[6]; 
	            
	barbr=bar.right-bar.left;                          
	// Test, ob Marker im Anzeigebereich
	if(level<=(unsigned short)(LMyscmin*-40)) {
		skal=(long)(LMyscmax-LMyscmin)*(long)40;	                                                   
		bar_max=(long)(bar.bottom-bar.top);
		// Lage im Bar ermitteln und begrenzen
		bar_level=(bar_max*((long)level+(long)LMyscmax*40))/skal;
		bar_level=__min(__max(0,bar_level),bar_max);
		// Test, ob rot oder grün
		if(level<=(unsigned int)(LMyswitch*-40)) NewBrush = CreateSolidBrush(GetNearestColor(hDC,DAM_ROT));
			else NewBrush = CreateSolidBrush(GetNearestColor(hDC,DAM_GRUEN));
		// Farbe einstellen
		OldBrush = SelectObject(hDC, NewBrush);
		// Eckpunkte des Markers einstellen		
		Mark[2].y=Mark[5].y=bar.top+(short)bar_level;
		Mark[0].x=Mark[4].x=bar.left+barbr/5;
		Mark[0].y=Mark[1].y=Mark[2].y-texthight/6;
		Mark[1].x=Mark[3].x=bar.right-barbr/5; 
		Mark[2].x=bar.right-1;
		Mark[3].y=Mark[4].y=__min(Mark[2].y+texthight/6,bar.bottom);
		Mark[5].x=bar.left+1;
		// Ausgeben
		Polygon(hDC,Mark,6);
		SelectObject(hDC, OldBrush);
	    DeleteObject(NewBrush);
	}	    
}

/************************************************************************************/
/* 	Gen_Scal: Erzeugt eine Skalierung für n Bars, wobei RECT firstbar die Lage des 	*/
/*	ersten Bars angibt und dist den Abstand zwischen 2 Bars (rechter Rand zu linkem */
/*	Rand!) angibt. text=FALSE schaltet die Ausgabe der Beschriftung ab              */  
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void Gen_Scal(HDC hDC, short n, RECT firstbar, short dist, BOOL text)
{       
	RECT bar;
	short barbr;
    float yscdst;                          
    short i,j,yshift; 
    char szHilf[20];
	HPEN hBlackPen,hOldPen;

	SetTextAlign(hDC,TA_RIGHT);   	// Text auf rechten Rand
	hBlackPen = CreatePen(PS_SOLID, 1, DAM_SCHWARZ);
   	hOldPen = SelectObject(hDC, hBlackPen);
    
    // Skalierung der y-Achse in Abhängigkeit von der Fenstergröße
 	yscdst=(float)(firstbar.top-firstbar.bottom)/(float)(LMyscmax-LMyscmin);
	bar.top=firstbar.top;
	bar.bottom=firstbar.bottom;	               
	barbr=firstbar.right-firstbar.left;
	
	for(j=0;j<n;j++)
	{
		bar.left=firstbar.left+j*(barbr+dist);
		bar.right=firstbar.right+j*(barbr+dist);
 		// Kennzeichnung der 10 und 20dB-Linien
		for(i=LMyscmin-LMyscmax;i<=0;i+=10)
		{                               
			if((j==0) && text) {
				sprintf(szHilf, "%i",i+LMyscmax);           
				yshift=texthight/2;
				if(i==LMyscmin-LMyscmax) yshift++;
				if(i==0) yshift--;  
				if((-yscdst*20>texthight*2)||(i%20==0))
					if((-yscdst*20>texthight) || (i==LMyscmin) || (i==LMyscmax))
						TextOut(hDC, bar.left-(barbr*7)/10,bar.top+(int)((float)i*yscdst)-yshift,szHilf,strlen(szHilf));
			}
	 		if(i!=LMyscmin-LMyscmax) {
	 			MoveTo(hDC,bar.left-dist/2,bar.top+(int)((float)i*yscdst));
	 			LineTo(hDC,bar.right+dist/2,bar.top+(int)((float)i*yscdst));  
	 		}
	 		else {
	 			MoveTo(hDC,bar.left-dist/2,bar.bottom);
	 			LineTo(hDC,bar.right+dist/2,bar.bottom);  
	 		}
		}
		// Kennzeichnung der 5db-Linien
		if(-yscdst*5>=5)		// mindestens 5 Pixel Abstand
			for(i=LMyscmin-LMyscmax+5;i<0;i+=5)	{                                 
				MoveTo(hDC,bar.left-dist/4,bar.top+(int)((float)i*yscdst));
	 			LineTo(hDC,bar.right+dist/4,bar.top+(int)((float)i*yscdst));  
         }
    	// Kennzeichnung der 1db-Linien
		if(-yscdst>=5)		// mindestens 5 Pixel Abstand
			for(i=LMyscmin-LMyscmax+1;i<0;i++) {
				MoveTo(hDC,bar.left-(dist*3)/20,bar.top+(int)((float)i*yscdst));
	 			LineTo(hDC,bar.right+(dist*3)/20,bar.top+(int)((float)i*yscdst));  
			}         	
	}
	SelectObject(hDC,hOldPen);
	DeleteObject(hBlackPen);          
}                                                               

/************************************************************************************/                    
/*	Sleep60: 	Wartet eine Pause von 60ms ab 											*/
/************************************************************************************/
void Sleep60(void)
{
    DWORD ende;

    ende=GetTickCount()+(DWORD)56;
    while (ende>GetTickCount());
}

/************************************************************************************/
/*	load_DKS: bootet DSP mit angegebenem Programm aus Datei							*/
/*	nutzt read4, cxmit, ixmit														*/
/*																					*/
/*	Quelle: Beispielprogramm zum DSK von Texas Instruments			 				*/
/************************************************************************************/
BOOL load_DSK(char *filename)
{
  FILE *in_file;
  char buf[512],*ptr;
  char hilfstr[256];
  unsigned int i, ENTRY;
  int ADDR;
  int boot_csum, boot_len=0;
  int pass;
  
  pass=0;
  if ((in_file = fopen(filename, "r")) == NULL)        // Is file available?
  {          
    sprintf(hilfstr,"Could not open file: %s\n",filename);
    MessageBox(hDAMWnd,hilfstr,DAMSTR,MB_OK);
    return(1);
  }

  reset();
  fseek(in_file,0,SEEK_SET);               	// reset to first line
  fscanf(in_file,"%s",&buf);               	// Read first line
  if(buf[0] != 'K')							// Test, ob "richtiges" File
  {
    sprintf(hilfstr,"Not a valid DSK file: %s\n",filename);
    fclose(in_file);                                          
    MessageBox(hDAMWnd,hilfstr,DAMSTR,MB_OK);
    return(1);
  }
  for(;pass<2;pass++)
  {
    boot_csum= 0;
    fseek(in_file,0,SEEK_SET);               // reset to first line
    fscanf(in_file,"%s",&buf);               // Read first line
    if(pass==1) 
    {
      boot_len--;
      ixmit((boot_len & 0x700)|0x8FF);   // STATUS and BAUD_DTCT
      ixmit(((boot_len & 0xFF)<<8)|0x80);// LENGTH and INT
      boot_len=0;
    }  
    while(!feof(in_file))
    {
      fscanf(in_file,"%s\r\n",buf);                // Read a line
      ptr = buf;
      switch(buf[0])
      {
	case '1': ENTRY = read4(ptr);              // 1=entry point
		  break;
	case '9': ADDR = read4(ptr);               // 9=address
		    while(buf[0] != '7')
		    {
		      i = read4(ptr);
		      if(pass==1)
			  ixmit(i);
		      fprintf(stdout,"\r%d words",boot_len);
		      boot_len++;
		      boot_csum += i;
		    }
		  break;
	case ':': break;
	default : sprintf(hilfstr,"Not a valid DSK file: %s\n",filename);
			  fclose(in_file);                                          
    		  MessageBox(hDAMWnd,hilfstr,DAMSTR,MB_OK);
    		  return(1);
      }
      if(buf[0]==':') break;
    }
  if(pass==1) 
    {
      ixmit(boot_csum);                   // CHECKSUM at EO 2nd pass
      cxmit((unsigned char)0xff);         // same for synch
    }
  }
  fclose(in_file);                        // close file when done
  return(0);
}
            
unsigned int read4(char *ptr)
{
  char val[200], *nptr;
  unsigned int i;
  strcpy(val,"0x");
  strcat(val,ptr+1);
  val[6] = 0;
  i = (unsigned)strtol(val,&nptr,16);
  strcpy(ptr,ptr+5);
  return(i);
}                     

void ixmit(int i)	
{
  cxmit((char)(i&255));    		// 1. Aufruf von cxmit (unteres Byte)
  cxmit((char)((i>>8)&255));	// 2. Aufruf von cxmit (oberes Byte)                  
}

void cxmit(char c)
{
	COMSTAT	comstat1;
	char hilf;
	
	hilf=c;
	WriteComm(idComDev,&hilf,1);
	GetCommError(idComDev,&comstat1);
	while (comstat1.cbOutQue>0)			//Warten, bis Byte wirklich gesendet
		 GetCommError(idComDev,&comstat1);
}

/************************************************************************************/                    
/*	StartCom: Startet DSP-Programm für Pegelmesser einschl. RS-232-Kommunikation	*/
/*																					*/
/*	geht auf Lösung aus dem DSP-Starterkit von Texas Instruments zurück				*/
/************************************************************************************/
unsigned int StartCom(HWND hWnd)
{   
	clock_t maxwait; 
	COMSTAT	comstat1;                  
	DCB comDCB;     
	short ComnNmb; 
	unsigned int err; 
	BOOL timeout;               
	char dsk_file[50];
	char buildstr[30];
	BOOL noFile;
    
	idComDev = OpenComm((LPSTR)COMPort, 4096, 16);
	if (idComDev < 0) 
	{                                                          
       	MessageBeep(MB_ICONEXCLAMATION);
		MessageBox(hWnd,"Selected COM-Port is not available.\nCheck setup or stop other applications\n using this port!"
			,NULL,MB_APPLMODAL|MB_OK|MB_ICONEXCLAMATION);
    	idComDev=0;
   		return 1;
	}
	
	timeout=TRUE;	
	err=0;
	while((err<2) && timeout)	// max. 2 Versuche
	{
		err++;
		strcpy(buildstr,COMPort);      
		strcat(buildstr,":");
		strcat(buildstr,COMBaud);
		strcat(buildstr,",n,8,2");
		BuildCommDCB((LPSTR)buildstr, &comDCB);                      
		SetCommState(&comDCB);                      
		strcpy(dsk_file,"level16.dsk"); 
		noFile=load_DSK(dsk_file); 
		if(noFile) return 1;
		ComnNmb=36;
		Sleep60();
		strcpy(buildstr,COMPort);
		strcat(buildstr,":4800,n,8,1");
		BuildCommDCB((LPSTR)buildstr, &comDCB); 
		SetCommState(&comDCB);   
		FlushComm(idComDev,1); 
	    // Test, ob erste Daten ankommen	
		timeout=FALSE;
    	maxwait = (clock_t)((float)0.06*CLOCKS_PER_SEC) + clock();	// Endzeit berechnen
		GetCommError(idComDev,&comstat1);
		while ((comstat1.cbInQue<2) && !timeout)			// Warten, bis 2 Byte empfangen
		{
			GetCommError(idComDev,&comstat1);
	 		if (maxwait <= clock()) timeout=TRUE;	// ( max. 20ms!)
		} 
	}	
	if (timeout)  
	{	                                                 
		EndComm();
       	MessageBeep(MB_ICONEXCLAMATION);
		MessageBox(hWnd,"DSP-Hardware does not respond.\nCheck power supply and RS232-cable!"
			,NULL,MB_APPLMODAL|MB_OK|MB_ICONEXCLAMATION);
		return 2;
	}
	else   
	{
		EnableCommNotification(idComDev,hWnd,ComnNmb,-1);
		GetCommError(idComDev,NULL);   	// Fehler rücksetzen
		WatchdogCT=0;	//Watchdogzähler rücksetzen
		RS232activ=TRUE;
    }
	return 0;
}

/************************************************************************************/                    
/*	reset: führt Reset des DSPs über DTR-Leitung aus               					*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void reset(void)
{   
	EscapeCommFunction(idComDev,CLRDTR);
	Sleep60();
	EscapeCommFunction(idComDev,SETDTR);
	Sleep60();
} 

/************************************************************************************/                    
/*	EndComm: Beendet Kommunikation über serielle Schnittstelle 						*/
/*																					*/
/*	(C) R. Männel 1996                                          					*/
/************************************************************************************/
void EndComm(void)
{   
	if (idComDev)
	{                   
		RS232activ=FALSE;
		reset();     
		CloseComm(idComDev);
		idComDev=0;
		Sleep60();
	}
}
