All pastes #253066 Raw Edit

Miscellany

public text v1 · immutable
#253066 ·published 2006-11-20 07:55 UTC
rendered paste body
// Pam.cpp : Defines the entry point for the DLL application.
//

#include "stdAfx.h"
// Pam.cpp : Defines the entry point for the DLL application.
// Pam.cpp : Defines the class behaviors for the application.
//
// Waarschuwing bij debuggen: in een sessie wordt een key bepaald met een geldigheidsduur van X seconden. 
// Bij het verzenden van beschermde berichten moet deze key nog geldig zijn. Let hierop bij het plaatsen 
// van breakpoints.

#include "Pam.h"
#include "StandardDlg.h"
#include "DebugDlg.h"
#include "AboutDlg.h"
#include "ProgressDlg.h"

#include "url.h"
#include "GrabWininet.h"

#include "TaskBarApplet.hpp"
#define _MFC_TASKBAR_APPLET
#include "TaskBarAppletMain.hpp"

#ifdef USE_COM_PORTS
#include "serialWnd.h"
#else
#include "SiUSBXp.h"
#endif

#include "betronic.h"

#include <iostream>   // for XOR operator???
#include <iso646.h>   // for XOR operator???


BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    return TRUE;
}



#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


// Definieer de types die uit de WinHttp.dll nodig zijn:
#include <winhttp.h>
typedef BOOL (WINAPI *TFWinHttpReadData)(
    IN HINTERNET hRequest,
    IN LPVOID lpBuffer,
    IN DWORD dwNumberOfBytesToRead,
    OUT LPDWORD lpdwNumberOfBytesRead
	);
typedef HINTERNET (WINAPI *TFWinHttpOpen)(
    IN LPCWSTR pwszUserAgent,
    IN DWORD   dwAccessType,
    IN LPCWSTR pwszProxyName   OPTIONAL,
    IN LPCWSTR pwszProxyBypass OPTIONAL,
    IN DWORD   dwFlags
);
typedef HINTERNET (WINAPI *TFWinHttpConnect)(
    IN HINTERNET hSession,
    IN LPCWSTR pswzServerName,
    IN INTERNET_PORT nServerPort,
    IN DWORD dwReserved
);
typedef HINTERNET (WINAPI *TFWinHttpOpenRequest)(
	IN HINTERNET hConnect,
	IN LPCWSTR pwszVerb,
	IN LPCWSTR pwszObjectName,
	IN LPCWSTR pwszVersion,
	IN LPCWSTR pwszReferrer OPTIONAL,
	IN LPCWSTR FAR * ppwszAcceptTypes OPTIONAL,
	IN DWORD dwFlags
);
typedef BOOL (WINAPI *TFWinHttpSendRequest)(
    IN HINTERNET hRequest,
    IN LPCWSTR pwszHeaders OPTIONAL,
    IN DWORD dwHeadersLength,
    IN LPVOID lpOptional OPTIONAL,
    IN DWORD dwOptionalLength,
    IN DWORD dwTotalLength,
    IN DWORD_PTR dwContext
);
typedef BOOL (WINAPI *TFWinHttpReceiveResponse) (
    IN HINTERNET hRequest,
    IN LPVOID lpReserved
);
typedef BOOL (WINAPI *TFWinHttpQueryDataAvailable)(
    IN HINTERNET hRequest,
    OUT LPDWORD lpdwNumberOfBytesAvailable OPTIONAL
);


/////////////////////////////////////////////////////////////////////////////
// CPamTaskBar:
//

class CPamTaskBar : public CJBTaskBarApplet
{
public:
	//MFCApplet();

private:

	extern "C"  bool  __declspec(dllexport) __stdcall InitInstance(LPSTR lpCmdLine);

	extern "C"  void  __declspec(dllexport) __stdcall  OnLeftDoubleClick();
//	extern "C"  void  __declspec(dllexport) __stdcall  void SettingsDialog();
	extern "C"  void  __declspec(dllexport) __stdcall  AboutDialog();

	extern "C"  HICON  __declspec(dllexport) __stdcall GetIcon();

	extern "C"  HMENU __declspec(dllexport) __stdcall  GetMenu();
	extern "C"  void __declspec(dllexport) __stdcall HandleMenuCommand(int command);
	enum menuIDs { ID_CLOSE = 1, ID_OPEN, ID_ABOUT, ID_UPLOAD, ID_PAM };


	extern "C" bool ShowError __declspec(dllexport) __stdcall (LONG lError, LPCTSTR lptszMessage, BOOL bShowPopup);

	extern "C"  void  __declspec(dllexport) __stdcall  OnSerialMessage(WPARAM wParam);
	extern "C"  void  __declspec(dllexport) __stdcall OnTimerMessage(WPARAM wParam);

	CSerialWnd m_serial;

    extern "C" void __declspec(dllexport) __stdcall  NotifyUser(CString strMsg, BOOL bShow, BOOL bReset);
	ProgressDlg * m_pProgressDlg;
	CString m_TrayTip;
	extern "C"  LPCTSTR __declspec(dllexport) __stdcall  GetTrayTip();

#ifdef USE_COM_PORTS
	extern "C" bool   __stdcall  OpenComPort();
	extern "C" bool __declspec(dllexport) __stdcall  CloseComPort();
#else
	extern "C" bool __declspec(dllexport) __stdcall  OpenUSB();
	extern "C" bool __declspec(dllexport) __stdcall CloseUSB();
	extern "C" bool __declspec(dllexport) __stdcall ReadUSB();
	extern "C" bool __declspec(dllexport) __stdcall  PamStillThere();
#endif

	extern "C" bool __declspec(dllexport)  __stdcall PamToggleMode();
	extern "C" bool  __declspec(dllexport) __stdcall PamSetTime();
	extern "C" bool __declspec(dllexport)  __stdcall PamGetTime();
	extern "C" bool  __declspec(dllexport) __stdcall PamReadMode();
	extern "C" bool  __declspec(dllexport) __stdcall PamSetMode(BYTE mode, BYTE key_return);		// added by E. Damen for AM200
	extern "C" bool __declspec(dllexport)  __stdcall PamSetAux(BYTE CalorieperPam);			// added by E. Damen for AM200
	extern "C" bool __declspec(dllexport)  __stdcall PamStaticMode();
	extern "C" bool  __declspec(dllexport) __stdcall PamReadSerialNumber();
	extern "C" bool  __declspec(dllexport) __stdcall PamReadDockingDate();
	extern "C" bool  __declspec(dllexport) __stdcall PamReadCalibrationFactor();
	extern "C" bool  __declspec(dllexport) __stdcall PamReadEeprom();
	extern "C" bool  __declspec(dllexport) __stdcall PamReadToday();
	extern "C" bool  __declspec(dllexport) __stdcall PamReadEepromPage0(BYTE key_return); // added by E. Damen for AM102
	extern "C" bool  __declspec(dllexport) __stdcall PamReadEepromPage1(BYTE key_return); // added by E. Damen for AM102
	extern "C" bool  __declspec(dllexport) __stdcall PamReadEepromPage2(BYTE key_return); // added by E. Damen for AM102
	extern "C" bool  __declspec(dllexport) __stdcall PamReadEepromPage3(BYTE key_return); // added by E. Damen for AM102
	extern "C" bool  __declspec(dllexport) __stdcall PamUploadData();
	extern "C" bool  __declspec(dllexport) __stdcall PamReadRam(UINT address);
	extern "C" bool  __declspec(dllexport) __stdcall SendCommand(struct Message *message, BOOL bReading);

	extern "C" void   __declspec(dllexport) __stdcall StartHeartbeat();

	int m_State;
	int m_TimeOut;

    extern "C" void __declspec(dllexport)  __stdcall  ProcessBreak();

	extern "C" BOOL  __declspec(dllexport)  __stdcall ProcessMessage();
	BYTE m_Buffer[256];
	DWORD m_dwEob;
	BOOL m_DiscardInput;
	BOOL m_bSkipBreak;
	UINT m_bSkipCounter;
	
	UINT m_SerialNumber;
	struct { UINT Major; UINT Minor; UINT Build; } m_VersionNumber;
	DWORD m_Config;
	BYTE m_Key;
	BYTE m_Key_return;

	BYTE m_PamMode;
	BYTE m_CalorieperPam;	// Added by E. Damen for AM200
	BYTE m_UpdateDockDay;	// Added by E. Damen for AM200
	BYTE m_PamDayScore16;
	UINT m_PamLowScore;
	UINT m_PamMedScore;
	UINT m_PamHighScore;
	UINT m_PamDistanceTD;
	UINT m_PamFruitTD;
	BOOL m_ConsumerMode; // The real mode in which the docked Pam is running
	CTime m_Time;

	UINT m_Heartbeat;

	UINT m_GainAdjustMultiplier;
	UINT m_GainAdjustDivider;
	UINT m_TresholdHeavy;
	UINT m_TresholdLight;

	UINT m_Fifo; // The current pointer in the PAM data

	UINT m_Size;
	UINT m_Pam[512]; // changed by E. Damen for AM102
	UINT m_LightActivity[512]; // changed by E. Damen for AM102
	UINT m_MediumActivity[512]; // changed by E. Damen for AM102
	UINT m_HeavyActivity[512]; // changed by E. Damen for AM102
	UINT m_Distance[512];	   // added by E. Damen for AM200
	UINT m_Fruit[512];	   //  added by E. Damen for AM200
	UINT m_code1[512];	// added by E. Damen for AM200
	UINT m_code2[512];   // added by E. Damen for AM200
    	BOOL m_bMilitary;

	BYTE Eepromt[0x1FF]; // changed by E. Damen for AM102

	HANDLE m_hUSBDevice;

	// Dit zijn variabelen die de adressen naar de WinHTTP functies gaan bevatten:
   	TFWinHttpReadData FWinHttpReadData;
	TFWinHttpConnect FWinHttpConnect;
	TFWinHttpOpen FWinHttpOpen;
	TFWinHttpOpenRequest FWinHttpOpenRequest;
	TFWinHttpSendRequest FWinHttpSendRequest;
	TFWinHttpReceiveResponse FWinHttpReceiveResponse;
	TFWinHttpQueryDataAvailable FWinHttpQueryDataAvailable;

	// Hier komen onze varianten van de WinHTTP functies:
	extern "C"  BOOL __declspec(dllexport) __stdcall WinHttpReadData
	(
		IN HINTERNET hRequest,
		IN LPVOID lpBuffer,
		IN DWORD dwNumberOfBytesToRead,
		OUT LPDWORD lpdwNumberOfBytesRead
	);
	extern "C" HINTERNET __declspec(dllexport)  __stdcall WinHttpConnect
	(
		IN HINTERNET hSession,
		IN LPCWSTR pswzServerName,
		IN INTERNET_PORT nServerPort,
		IN DWORD dwReserved
	);
	extern "C" HINTERNET  __declspec(dllexport) __stdcall WinHttpOpen(
		IN LPCWSTR pwszUserAgent,
		IN DWORD   dwAccessType,
		IN LPCWSTR pwszProxyName   OPTIONAL,
		IN LPCWSTR pwszProxyBypass OPTIONAL,
		IN DWORD   dwFlags
	);
	extern "C" HINTERNET  __declspec(dllexport) __stdcall WinHttpOpenRequest(
		IN HINTERNET hConnect,
		IN LPCWSTR pwszVerb,
		IN LPCWSTR pwszObjectName,
		IN LPCWSTR pwszVersion,
		IN LPCWSTR pwszReferrer OPTIONAL,
		IN LPCWSTR FAR * ppwszAcceptTypes OPTIONAL,
		IN DWORD dwFlags
	);
	extern "C" BOOL __declspec(dllexport)  __stdcall WinHttpSendRequest(
		IN HINTERNET hRequest,
		IN LPCWSTR pwszHeaders OPTIONAL,
		IN DWORD dwHeadersLength,
		IN LPVOID lpOptional OPTIONAL,
		IN DWORD dwOptionalLength,
		IN DWORD dwTotalLength,
		IN DWORD_PTR dwContext
	);
	extern "C" BOOL __declspec(dllexport)  __stdcall WinHttpReceiveResponse(
		IN HINTERNET hRequest,
		IN LPVOID lpReserved
	);
	extern "C" BOOL  __declspec(dllexport) __stdcall WinHttpQueryDataAvailable(
		IN HINTERNET hRequest,
		OUT LPDWORD lpdwNumberOfBytesAvailable OPTIONAL
	);

	BOOL m_bUseWinHttp;

	extern "C" BOOL CPamTaskBar::GrabWinHttpFile(LPCWSTR strServer,
					 LPCWSTR strUrl,
					 CString &strBuffer,
					 LPCWSTR strAgentName);
};




#define STATE_NULL				  0
#define STATE_UNDOCKED			  1

#define STATE_RDSERNR			100
#define STATE_READMODE			101
#define STATE_READCAL_FACTOR		102
#define STATE_STATICMODE    		103
#define STATE_READEEP			104
#define STATE_READDAYSCORE		105
#define STATE_READMEDSCORE		106
#define STATE_READHEAVYSCORE		107
#define STATE_UPLOADDATA		108
#define STATE_VERIFYCLK        		111
#define STATE_READEEPP0			112 // added by E. Damen for AM102
#define STATE_READEEPP1			113 // added by E. Damen for AM102
#define STATE_READEEPP2			114 // added by E. Damen for AM102
#define STATE_READEEPP3			115 // added by E. Damen for AM102
#define STATE_READDAYSCORE102		116 // added by E. Damen for AM102
#define STATE_READMEDSCORE102		117 // added by E. Damen for AM102
#define STATE_READHEAVYSCORE102		118 // added by E. Damen for AM102
#define STATE_READTODAY			119 // added by E. Damen for AM200
#define STATE_SETMODE			120 // added by E. Damen for AM200
#define STATE_SETAUX			121 // added by E. Damen for AM200


#define STATE_READCLK			200
#define STATE_SETCLK			201

#define STATE_TOGGLEMODE        	300

#define STATE_DOCKED			800

/////////////////////////////////////////////////////////////////////////////
// Serial and USB communications.
//

bool __stdcall CPamTaskBar::ShowError (LONG lError, LPCTSTR lptszMessage, BOOL bShowPopup)
{
	// Generate a message text
	m_TrayTip = lptszMessage;

	if ( bShowPopup ) {
		CString msg;
		msg.Format(_T("%s\nError code %d"), lptszMessage, lError);
		// Display message-box and return with an error-code
		::MessageBox(0, msg, _T(DRIVER_NAME), MB_ICONSTOP|MB_OK);
	}

	TRACE("ERROR: %s (error code %d)\n", lptszMessage, lError);

	return FALSE;
}

#ifdef USE_COM_PORTS
bool   __stdcall CPamTaskBar::OpenComPort()
{
	LONG lLastError = ERROR_SUCCESS;

 	CWinApp* pApp = AfxGetApp();
	CString ComPort = pApp->GetProfileString(_T(PAM_VERSION), _T(REG_COM_PORT), _T("COM1"));

	m_bSkipBreak = TRUE;

    // Attempt to open the serial port.
	lLastError = m_serial.Open(ComPort, s_hWnd, WM_NULL, (LPARAM)m_nObjectIndex);
	if ( lLastError != ERROR_SUCCESS )
		return ShowError(m_serial.GetLastError(), _T("Unable to open COM-port"), TRUE);

	// Setup no handshaking (DTR high, CTS low).
    lLastError = m_serial.SetupHandshaking(CSerial::EHandshakePam);
	if ( lLastError != ERROR_SUCCESS )
		return ShowError(m_serial.GetLastError(), _T("Unable to set COM-port handshaking"), TRUE);

    // Setup the serial port (1200,N81).
    lLastError = m_serial.Setup(CSerial::EBaud1200,
							    CSerial::EData8,
								CSerial::EParNone,
								CSerial::EStop1);
	if ( lLastError != ERROR_SUCCESS )
		return ShowError(m_serial.GetLastError(), _T("Unable to set COM-port setting"), TRUE);

    // Register only for the receive event
	// lLastError = m_serial.SetMask(CSerial::EEventBreak | CSerial::EEventRecv);
    lLastError = m_serial.SetMask(CSerial::EEventRecv);
	if ( lLastError != ERROR_SUCCESS )
		return ShowError(m_serial.GetLastError(), _T("Unable to set COM-port event mask"), TRUE);

    // The serial port is now ready and we can send/receive data.
	return TRUE;
}
#else
bool __stdcall CPamTaskBar::OpenUSB()
{
	DWORD device = 0, dwNumDevices = 0;
	SI_STATUS status;
	
	status = SI_GetNumDevices(&dwNumDevices);
	if ( status != SI_SUCCESS || dwNumDevices == 0 )
	{
		return ShowError(status, _T("Undocked"), FALSE);
	}

	for (device = 0; device < dwNumDevices; device++)
	{
		SI_DEVICE_STRING devStr;

		// status = SI_GetProductString(device, devStr, SI_RETURN_SERIAL_NUMBER);

		status = SI_GetProductString(device, devStr, SI_RETURN_VID);
		if ( status != SI_SUCCESS || strcmp(devStr, "10c4") != 0 )
		{
			continue;
		}
		status = SI_GetProductString(device, devStr, SI_RETURN_PID);
		if ( status != SI_SUCCESS || strcmp(devStr, "82b0") != 0 )
		{
			continue;
		}

		// We ondersteunen alleen 1 Pam, en nemen dus altijd de eerste die we vinden.

		break; // We found one!!!
	}
	if ( device >= dwNumDevices ) {
		// Helaas, er hangen geen Pammetjes aan...
		return ShowError(status, _T("Undocked"), FALSE);
	}

	if ( m_hUSBDevice ) {
		// Driver already opened
		return TRUE;
	}

	status = SI_Open(device, &m_hUSBDevice);
	if ( status != SI_SUCCESS )
	{
		return ShowError(status, _T("Error: could not open Pam"), TRUE);
	}

    // Setup the serial port (2400) for USB. the old Pam used 1200 baud.
	status = SI_SetBaudRate(m_hUSBDevice, 2400);
	if ( status != SI_SUCCESS )
	{
		return ShowError(status, _T("Error: Failed to set baud rate"), TRUE);
	}

    // Setup the serial port (N81).
	status = SI_SetLineControl(m_hUSBDevice, 0x0800);
	if ( status != SI_SUCCESS )
	{
		return ShowError(status, _T("Error: Failed to set line control"), TRUE);
	}

	// Setup no handshaking (DTR high, CTS low).
	status = SI_SetFlowControl(m_hUSBDevice, 
							   /*bCTS_MaskCode */ SI_STATUS_INPUT, 
							   /*bRTS_MaskCode */ SI_HELD_INACTIVE, 
							   /*bDTR_MaskCode */ SI_HELD_INACTIVE, // SI_HELD_INACTIVE
							   /*bDSRMaskCode  */ SI_STATUS_INPUT,
							   /*bDCD_MaskCode */ SI_STATUS_INPUT, 
							   /*bFlowXonXoff  */ FALSE);
	if ( status != SI_SUCCESS )
	{
		return ShowError(status, _T("Error: Failed to set flow control"), TRUE);
	}

	// Maak reads non-blocking. Write time-out  seconde
	status = SI_SetTimeouts(0, /*DEFAULT_HEARTBEAT * 0.8*/0);
	if ( status != SI_SUCCESS )
	{
		return ShowError(status, _T("Error: Failed to write timeout Pam"), TRUE);
	}

	status = SI_FlushBuffers(m_hUSBDevice, TRUE, TRUE);
	if ( status != SI_SUCCESS )
	{
		return ShowError(status, _T("Error: Failed to purge Pam"), TRUE);
	}

	return TRUE;
}
#endif

#ifdef USE_COM_PORTS
bool __stdcall CPamTaskBar::CloseComPort()
{
	LONG lLastError = ERROR_SUCCESS;

    // Attempt to open the serial port.
	lLastError = m_serial.Close();
	if ( lLastError != ERROR_SUCCESS )
		return ShowError(m_serial.GetLastError(), _T("Unable to close COM-port"), TRUE);

	return TRUE;
}
#else
bool __stdcall CPamTaskBar::CloseUSB()
{
	if ( m_hUSBDevice )
	{
		SI_STATUS status = SI_Close(m_hUSBDevice);

		if ( status != SI_SUCCESS )
		{
			return ShowError(status, _T("Error: Failed to close Pam"), FALSE);
		}
		m_hUSBDevice = 0;
	}

	return TRUE;
}
#endif

#ifndef USE_COM_PORTS
bool __stdcall CPamTaskBar::PamStillThere()
{
	BYTE PartNum;
	SI_STATUS status = SI_GetPartNumber (m_hUSBDevice, &PartNum);

	return status == SI_SUCCESS;
}

bool  __stdcall CPamTaskBar::ReadUSB()
{
	bool DataAvailable;

	do
	{
		if ( m_dwEob >= sizeof m_Buffer ) {
			m_dwEob = 0; // should not occur, prevent buffer overflow
			TRACE("\nERROR: ######################### buffer overflow ########################\n");
		}

		DWORD dwBytesRead = 0;
		SI_STATUS status = SI_Read(m_hUSBDevice, m_Buffer + m_dwEob, sizeof m_Buffer - m_dwEob, &dwBytesRead);
		if ( status != SI_SUCCESS )
		{
			ShowError(status, _T("Error: Failed to read Pam"), TRUE);
			return false;
		}

		if ( 0 /* debugging */ )
		{
			unsigned int i;
			for ( i = 0 ; i < dwBytesRead ; i++ )
				TRACE(" [%02x]", m_Buffer[m_dwEob+i]);
		}

		m_dwEob += dwBytesRead;

		DataAvailable = (m_dwEob == sizeof m_Buffer);

		while ( ProcessMessage() ) {};
	}
	while ( DataAvailable );

	return true;
}
#endif


bool  __stdcall CPamTaskBar::SendCommand(struct Message *message, BOOL bReading)
{
#ifdef USE_COM_PORTS
	long lLastError = m_serial.Write(message->data, message->size);

	if ( lLastError != ERROR_SUCCESS ) {
		return ShowError(m_serial.GetLastError(), _T("Unable to send data"), TRUE);
	}
#else
	DWORD written;
	
	// Voorlopig een blocking write. Misschien later asynchroon.

	SI_STATUS status = SI_Write(m_hUSBDevice, message->data, message->size, &written);
	if ( status != SI_SUCCESS )
	{
		return ShowError(status, _T("Error: Failed to write to Pam"), TRUE);
	}
#endif

	CString msg(bReading ? _T("Reading ") : _T("Updating "));
	msg += PAM_NAME;
	NotifyUser(msg, TRUE, FALSE);

	return TRUE;
}

bool  __stdcall CPamTaskBar::PamGetTime()
{
	CWinApp* pApp = AfxGetApp();

#ifdef USE_COM_PORTS
	bool sync_clock = pApp->GetProfileInt(_T(PAM_VERSION), _T(REG_SYNC_CLOCK), 1) != 0;
#else
	bool sync_clock = TRUE;
#endif

	if ( sync_clock && m_State != STATE_VERIFYCLK )
	{
		m_Time = CTime::GetCurrentTime();

		if ( m_State == STATE_READCLK ) {
			m_State = STATE_SETCLK;
			TRACE("STATE: SETCLK\n");
		}

		return true;
	}
	else
	{
		struct Message message;

		if ( ! MakeGetClockMessage(&message) )
		{
			return ShowError(0, _T("Unable to get time"), TRUE);
		}

		return SendCommand(&message, TRUE);
	}
}

bool  __stdcall CPamTaskBar::PamSetTime()
{
	CWinApp* pApp = AfxGetApp();

	// Load the clock setting from the registry.
#ifdef USE_COM_PORTS
	int nClock = pApp->GetProfileInt(_T(PAM_VERSION), _T(REG_CLOCK_MODE), 0);
#else
	int nClock = m_bMilitary ? 0 : 1;
#endif

	struct Message message;

	m_Time = CTime::GetCurrentTime(); // Voorheen werd dit gedaan in PamGetTime(). Dit wordt niet meer gebruikt.

	if ( ! MakeSetClockMessage(&message, m_Time.GetHour(), m_Time.GetMinute(), nClock == 0) )
	{
		return ShowError(0, _T("Unable to set time"), TRUE);
	}

	return SendCommand(&message, FALSE);
}

bool  __stdcall CPamTaskBar::PamReadMode()
{
	struct Message message;

	if ( ! MakeReadModeMessage(&message) )
	{
		return ShowError(0, _T("Unable to read mode"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

bool  __stdcall CPamTaskBar::PamSetMode(BYTE mode, BYTE key_return)		// added by E. Damen for AM200
{
	struct Message message;

	if ( ! MakeSetModeMessage(&message, mode, key_return) )
	{
		return ShowError(0, _T("Unable to set mode"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

bool  __stdcall CPamTaskBar::PamSetAux(BYTE CalorieperPam)					// added by E. Damen for AM200
{
	struct Message message;

	if ( ! MakeSetAuxMessage(&message, CalorieperPam) )
	{
		return ShowError(0, _T("Unable to set Calorie per Pam unit"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

/* bool CPamTaskBar::PamStaticMode()
{
	struct Message message;
	
	CWinApp* pApp = AfxGetApp();

	if ( ! MakeSetModeMessage(&message, m_PamMode | BIT_MODE_INTEGRATOR) )
	{
		return ShowError(0, _T("Unable to set static mode"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

bool CPamTaskBar::PamReadDockingDate()
{
	struct Message message;

	if ( ! MakeReadDockingDateMessage(&message) )
	{
		return ShowError(0, _T("Unable to read docking date"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

bool CPamTaskBar::PamToggleMode()
{
	struct Message message;

	CWinApp* pApp = AfxGetApp();

	if ( ! MakeSetModeMessage(&message, m_PamMode ^ BIT_MODE_PAM_MODE) )
	{
		return ShowError(0, _T("Unable to set mode"), TRUE);
	}

	return SendCommand(&message, TRUE);
}
*/

bool  __stdcall CPamTaskBar::PamReadToday()
{
	struct Message message;

	if ( ! MakeReadTodayMessage(&message) )
	{
		return ShowError(0, _T("Unable to read today"), TRUE);
	}

	return SendCommand(&message, TRUE);
}


bool __stdcall  CPamTaskBar::PamReadEepromPage0(BYTE key_return)  // added by E. Damen for AM102
{
	struct Message message;

	if ( ! MakeReadEepromPage0Message(&message, key_return) )
	{
		return ShowError(0, _T("Unable to read eeprom"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

bool  __stdcall CPamTaskBar::PamReadEepromPage1(BYTE key_return)  // added by E. Damen for AM102
{
	struct Message message;

	if ( ! MakeReadEepromPage1Message(&message, key_return) )
	{
		return ShowError(0, _T("Unable to read eeprom"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

bool __stdcall  CPamTaskBar::PamReadEepromPage2(BYTE key_return)  // added by E. Damen for AM102
{
	struct Message message;

	if ( ! MakeReadEepromPage2Message(&message, key_return) )
	{
		return ShowError(0, _T("Unable to read eeprom"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

bool  __stdcall CPamTaskBar::PamReadEepromPage3(BYTE key_return)  // added by E. Damen for AM102
{
	struct Message message;

	if ( ! MakeReadEepromPage3Message(&message, key_return) )
	{
		return ShowError(0, _T("Unable to read eeprom"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

bool  __stdcall CPamTaskBar::PamReadCalibrationFactor()
{
	struct Message message;

	if ( ! MakeReadCalibrationFactorMessage(&message) )
	{
		return ShowError(0, _T("Unable to read calibration factor"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

bool  __stdcall CPamTaskBar::PamReadSerialNumber()
{
	struct Message message;

	if ( ! MakeReadSerialNumberMessage(&message) )
	{
		return ShowError(0, _T("Unable to read serial number"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

bool  __stdcall CPamTaskBar::PamReadRam(UINT address)
{
	struct Message message;

	if ( ! MakeReadRamMessage(&message, address) )
	{
		return ShowError(0, _T("Unable to read ram"), TRUE);
	}

	return SendCommand(&message, TRUE);
}

CString GetValueByKey(CString strBuffer, CString strKeyword)
{
	strKeyword += ": ";

	int pos = strBuffer.Find(strKeyword);
	
	if ( pos != -1 )
	{
		return strBuffer.Mid(pos + strKeyword.GetLength()).SpanExcluding("\n\r");
	}
	else
	{
		return "";
	}
}

BOOL  __stdcall CPamTaskBar::GrabWinHttpFile(LPCWSTR strServer,
								  LPCWSTR strUrl,
								  CString &strBuffer,
								  LPCWSTR strAgentName)
{
	DWORD dwSize = 0;
	DWORD dwDownloaded = 0;
	LPSTR pszOutBuffer;
	BOOL  bResults = FALSE;
	HINTERNET  hSession = NULL, 
			   hConnect = NULL,
			   hRequest = NULL;

	hSession = CPamTaskBar::WinHttpOpen(  strAgentName,  
										  WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
										  WINHTTP_NO_PROXY_NAME, 
										  WINHTTP_NO_PROXY_BYPASS, 
										  0 /*synchrone*/ );

	// Specify an HTTP server.
	if ( hSession )
	hConnect = CPamTaskBar::WinHttpConnect( hSession, 
										strServer,
									INTERNET_DEFAULT_HTTP_PORT, 0 );

	// Create an HTTP request handle.
	if( hConnect )
		hRequest = CPamTaskBar::WinHttpOpenRequest( hConnect, L"GET", 
								   strUrl,
                                   NULL, WINHTTP_NO_REFERER, 
                                   WINHTTP_DEFAULT_ACCEPT_TYPES, 
                                   WINHTTP_FLAG_REFRESH );

  // Send a request.
  if( hRequest ) {
    bResults = CPamTaskBar::WinHttpSendRequest( hRequest,
                                   WINHTTP_NO_ADDITIONAL_HEADERS, 0,
                                   WINHTTP_NO_REQUEST_DATA, 0,  /* voor een post*/
                                   0, 0 );
  }

  // End the request.
  if( bResults )
    bResults = CPamTaskBar::WinHttpReceiveResponse( hRequest, NULL );

  // Keep checking for data until there is nothing left.
  if( bResults )
  {
    do 
    {
      // Check for available data.
      dwSize = 0;
	  bResults = CPamTaskBar::WinHttpQueryDataAvailable( hRequest, &dwSize );
	  if( ! bResults )
        TRACE( "Error %u in WinHttpQueryDataAvailable.\n",
                GetLastError( ) );

      // Allocate space for the buffer.
      pszOutBuffer = new char[dwSize+1];
      if( !pszOutBuffer )
      {
        TRACE( "Out of memory\n" );
		bResults = FALSE;
      }
      else
      {
        // Read the data.
        ZeroMemory( pszOutBuffer, dwSize+1 );

        if( !CPamTaskBar::WinHttpReadData( hRequest, (LPVOID)pszOutBuffer, 
			dwSize, &dwDownloaded ) ) {
          TRACE( "Error %u in WinHttpReadData.\n", GetLastError( ) );
		  bResults = FALSE;
		}
		else {
          strBuffer += pszOutBuffer;
		}

        // Free the memory allocated to the buffer.
        delete [] pszOutBuffer;
      }
    } while( dwSize > 0 && bResults );
  }

  	if ( ! bResults ) {
		TRACE( "Error %u in GrabWinHttpFile.\n",
                GetLastError( ) );
	}

	return bResults;
}

bool  __stdcall CPamTaskBar::PamUploadData()
{
	CWinApp* pApp = AfxGetApp();

	NotifyUser(_T("Uploading data"), TRUE, FALSE);

	// Build the upload URL and add all Pam data to it.

	CString strServerUrl;

	strServerUrl.Format(_T(UPLOAD_PAGE "?software=%u&firmware=%u&sn=%u&days=%d&tz=%d&config=%u&ds=%u&living=%u&health=%u&sports=%u&distance=%u&fruit=%u"),
					    (VERSION_MAJOR << 8) | VERSION_MINOR,
						(m_VersionNumber.Major << 16) |
						(m_VersionNumber.Minor <<  8) |
						(m_VersionNumber.Build <<  0),
						m_SerialNumber,
						m_Size,
						/*_timezone*/ _get_timezone,
						m_Config,
						m_PamDayScore16,
						m_PamLowScore,
						m_PamMedScore,
						m_PamHighScore,
						m_PamDistanceTD,
						m_PamFruitTD
					   );

//	strServerUrl += "&eep=";

// The rest of the routine is written by E. Damen for AM102.
// Because a URL has a maximum length of 2023 bytes and the numbers of days in AM102
// in scientific mode is 4 times larger, data has to be compressed to fit in the URL

	for ( UINT day = 0 ; day < m_Size ; day++ ) 
	{
		CString strData;
//		long int code = m_Pam[day] *16777216;
//		code += m_LightActivity[day]*65536;
//		code += m_MediumActivity[day]*256;
//		code += m_HeavyActivity[day];			

		strData.Format(_T("&q[]=%06x%08x"), m_code2[day],m_code1[day]);

		strServerUrl += strData;
	}
	

//	m_State = STATE_READCLK;
//	TRACE("STATE: READCLK\n");

	m_State = STATE_SETMODE;
	TRACE("STATE: SETMODE\n");

	// if ( ::MessageBox(0, msg, _T("Pam mode"), MB_OKCANCEL|MB_ICONWARNING) != IDOK )

	CString message;
	do
	{
		INT_PTR rc = 0;
		CURL url;

#ifdef USE_ONE_WAY_COM
		rc = url.Open(_T("http://" + SITE_SERVER + strServerUrl, false);
#else
		// Connect to the upload server and expect the redirection URL back.

		CString strBuffer;
		BOOL bUploadedData;

		if ( !m_bUseWinHttp )
		{
			bUploadedData = GrabWinHttpFile(CT2CW(SITE_SERVER),
										    CT2CW( (LPCTSTR) strServerUrl),
											strBuffer,
											CT2CW(PAM_NAME " " PAM_VERSION));
		}
		else
		{
			bUploadedData = GrabWininetFile(_T("http://" SITE_SERVER) + strServerUrl,
											strBuffer,
											_T(PAM_NAME " " PAM_VERSION));
		}

		if ( bUploadedData )
		{
			// Parseer het van de server verkregen resultaat. Ondermeer de URL die we moeten tonen.
			CString strKeyword;

			strKeyword = GetValueByKey(strBuffer, "Calorie");
			m_CalorieperPam = atoi(strKeyword);

			strKeyword = GetValueByKey(strBuffer, "MilitaryClock");
			m_bMilitary = atoi(strKeyword);

			strKeyword = GetValueByKey(strBuffer, "Paid");
			m_UpdateDockDay = atoi(strKeyword);

			strKeyword = GetValueByKey(strBuffer, "Location");
			if ( strKeyword != "" ) {
				TRACE("INFO: launching %s\n", strKeyword);
				//strKeyword = "url:" + strKeyword;
				//::ShellExecute(NULL, NULL, strKeyword, NULL, NULL, SW_SHOWNORMAL);
				rc = url.Open(strKeyword, false);
//				if ( m_State == STATE_UPLOADINGDATA ) {
//					m_State = STATE_READCLK;
//					TRACE("STATE: READCLK\n");
//				} 
//			} else if ( m_State == STATE_UPLOADINGDATA ) {
//				m_State = STATE_READCLK;
//				TRACE("STATE: READCLK\n");
			}
		}
#endif

		if ( rc > 32 ) break; // No error, continue.

		message.Format(_T("Could not connect to the %s web site.\n\nMake sure that you have a working internet connection. In case you installed a firewall, make sure it allows the %s to access the internet.\n(error code %d)"),
					   PAM_NAME,
					   DRIVER_NAME,
					   rc);
	}
	while ( ::MessageBox(0, message, _T(DRIVER_NAME), MB_ICONWARNING|MB_RETRYCANCEL) == IDRETRY);

// Added by E. Damen for AM200: information comes back from server: 1) paid or not paid		
//																	2) Calories per Pam unit
// if paid then m_UpdateDockDay = 1 else m_UpdateDockDay=0
// Calories per Pam unit should be stored in m_CalorieperPam

	m_PamMode = (m_PamMode & 0xFE) + m_UpdateDockDay;	// Added by E. Damen for AM200

	return true;
}

void  __stdcall CPamTaskBar::StartHeartbeat()
{
	CWinApp* pApp = AfxGetApp();

#ifdef USE_COM_PORTS
	m_Heartbeat = pApp->GetProfileInt(_T(PAM_VERSION), _T(REG_HEARTBEAT), DEFAULT_HEARTBEAT);
#else
	m_Heartbeat = DEFAULT_HEARTBEAT;
#endif

	SetTimer(s_hWnd,						// hWnd of the Taskbar Applet
			 1,								// Timer identifier
			 m_Heartbeat,	   				// Timeout value in order to give the PAM time to process
		     (TIMERPROC)m_nObjectIndex);	// identifier of the taskbar instance

	TRACE("INFO: timer started (%u ms)\n", m_Heartbeat);
}

bool  __stdcall CPamTaskBar::InitInstance(LPSTR lpCmdLine)
{
	_tzset(); // Sets time environment variables.

	// http://groups.google.com/groups?q=CWnd::FindWindow&hl=nl&lr=&ie=UTF-8&selm=34353492.1572921%40msnews.microsoft.com&rnum=1
    // http://groups.google.com/groups?q=CWnd::FindWindow&hl=nl&lr=&ie=UTF-8&selm=8psnq1%24oco%241%40fe1.cs.interbusiness.it&rnum=10

	HANDLE hMutex = CreateMutex(NULL, FALSE, _T("MutexToEnforceSinglePamDriver"));

	if ( GetLastError() == ERROR_ALREADY_EXISTS )
	{
		return FALSE; // Leave quietly the application
	}

	m_DiscardInput = FALSE;

/*
	CWinApp* pApp = AfxGetApp();
	pApp->SetRegistryKey(COMPANY_NAME);
*/
	
	m_TrayTip = _T(DRIVER_NAME);

	m_SerialNumber = m_Config = 0;

	m_pProgressDlg = NULL;

	m_State = STATE_NULL;
	TRACE("STATE: NULL\n");

	m_bSkipBreak = TRUE;

#ifdef USE_COM_PORTS
	if ( OpenComPort() ) {
		m_State = STATE_UNDOCKED;
		m_SerialNumber = m_Config = 0;
		TRACE("STATE: UNDOCKED\n");
	}
#endif

	// Bepaal of we WinHTTP kunnen gebruiken
/*
	SystemInfo sysInfo;
	if ( sysInfo.GetMajorVersion() < 5 ) {
		// Windows ME en ouder ondersteunen geen WinHttp
		m_bUseWinHttp = FALSE;
	} else {
		switch ( sysInfo.GetMinorVersion() ) {
			case 0: // Windows 2000, SP 3 ondersteunt WinHttp
				m_bUseWinHttp = sysInfo.GetServicePackMajor() >= 3;
				break;
			case 1: // Windows XP, SP 1 ondersteunt WinHttp
				m_bUseWinHttp = sysInfo.GetServicePackMajor() >= 1;
				break;
			default: // Nieuwere OSsen
				m_bUseWinHttp = TRUE;
				break;
		}
	}
*/

	// Nu gaan we proberen om de WinHttp.dll dynamisch te laden. Als dat lukt:
	// - zetten we m_bUseWinHttp op TRUE;
	// - halen we de adressen op van de WinHttp functies.
	HINSTANCE hHandle;
	hHandle = ::LoadLibrary("WINHTTP.DLL");
	if ( hHandle != NULL ) {
		FWinHttpReadData = (TFWinHttpReadData)::GetProcAddress(hHandle, _T("WinHttpReadData"));
		FWinHttpConnect = (TFWinHttpConnect)::GetProcAddress(hHandle, _T("WinHttpConnect"));
		FWinHttpOpen = (TFWinHttpOpen)::GetProcAddress(hHandle, _T("WinHttpOpen"));
		FWinHttpOpenRequest = (TFWinHttpOpenRequest)::GetProcAddress(hHandle, _T("WinHttpOpenRequest"));
		FWinHttpSendRequest = (TFWinHttpSendRequest)::GetProcAddress(hHandle, _T("WinHttpSendRequest"));
		FWinHttpReceiveResponse = (TFWinHttpReceiveResponse)::GetProcAddress(hHandle, _T("WinHttpReceiveResponse"));
		FWinHttpQueryDataAvailable = (TFWinHttpQueryDataAvailable)::GetProcAddress(hHandle, _T("WinHttpQueryDataAvailable"));
	}
    m_bUseWinHttp = hHandle != NULL &&
		FWinHttpReadData != NULL && 
		FWinHttpConnect != NULL && 
		FWinHttpOpen != NULL && 
		FWinHttpOpenRequest != NULL && 
		FWinHttpSendRequest != NULL && 
		FWinHttpReceiveResponse != NULL && 
		FWinHttpQueryDataAvailable != NULL;

	ASSERT(s_hWnd != NULL);

	StartHeartbeat();
	
	return TRUE;
}

BOOL  __stdcall CPamTaskBar::WinHttpReadData
(
	IN HINTERNET hRequest,
	IN LPVOID lpBuffer,
	IN DWORD dwNumberOfBytesToRead,
	OUT LPDWORD lpdwNumberOfBytesRead
)
{
  ASSERT(FWinHttpReadData != NULL);
  if (FWinHttpReadData) 
      return FWinHttpReadData(hRequest,lpBuffer,dwNumberOfBytesToRead,lpdwNumberOfBytesRead);
  return FALSE;
}

HINTERNET  __stdcall CPamTaskBar::WinHttpConnect
(
	IN HINTERNET hSession,
	IN LPCWSTR pswzServerName,
	IN INTERNET_PORT nServerPort,
	IN DWORD dwReserved
)
{
  ASSERT(FWinHttpConnect != NULL);
  if (FWinHttpConnect) 
      return FWinHttpConnect(hSession,pswzServerName,nServerPort,dwReserved);
  return FALSE;
}

HINTERNET  __stdcall CPamTaskBar::WinHttpOpen(
	IN LPCWSTR pwszUserAgent,
	IN DWORD   dwAccessType,
	IN LPCWSTR pwszProxyName   OPTIONAL,
	IN LPCWSTR pwszProxyBypass OPTIONAL,
	IN DWORD   dwFlags
)
{
  ASSERT(FWinHttpOpen != NULL);
  if (FWinHttpOpen) 
      return FWinHttpOpen(pwszUserAgent,dwAccessType,pwszProxyName,pwszProxyBypass,dwFlags);
  return FALSE;
}

HINTERNET  __stdcall CPamTaskBar::WinHttpOpenRequest(
	IN HINTERNET hConnect,
	IN LPCWSTR pwszVerb,
	IN LPCWSTR pwszObjectName,
	IN LPCWSTR pwszVersion,
	IN LPCWSTR pwszReferrer OPTIONAL,
	IN LPCWSTR FAR * ppwszAcceptTypes OPTIONAL,
	IN DWORD dwFlags
)
{
  ASSERT(FWinHttpOpenRequest != NULL);
  if (FWinHttpOpenRequest) 
      return FWinHttpOpenRequest(hConnect,pwszVerb,pwszObjectName,pwszVersion,pwszReferrer,ppwszAcceptTypes,dwFlags);
  return FALSE;
}

BOOL  __stdcall CPamTaskBar::WinHttpSendRequest(
	IN HINTERNET hRequest,
	IN LPCWSTR pwszHeaders OPTIONAL,
	IN DWORD dwHeadersLength,
	IN LPVOID lpOptional OPTIONAL,
	IN DWORD dwOptionalLength,
	IN DWORD dwTotalLength,
	IN DWORD_PTR dwContext
)
{
  ASSERT(FWinHttpSendRequest != NULL);
  if (FWinHttpSendRequest) 
      return FWinHttpSendRequest(hRequest,pwszHeaders,dwHeadersLength,lpOptional,dwOptionalLength,dwTotalLength,dwContext);
  return FALSE;
}

BOOL  __stdcall CPamTaskBar::WinHttpReceiveResponse(
	IN HINTERNET hRequest,
	IN LPVOID lpReserved
){
  ASSERT(FWinHttpReceiveResponse != NULL);
  if (FWinHttpReceiveResponse) 
      return FWinHttpReceiveResponse(hRequest,lpReserved);
  return FALSE;
}

BOOL  __stdcall CPamTaskBar::WinHttpQueryDataAvailable(
	IN HINTERNET hRequest,
	OUT LPDWORD lpdwNumberOfBytesAvailable OPTIONAL
)
{
  ASSERT(FWinHttpQueryDataAvailable != NULL);
  if (FWinHttpQueryDataAvailable) 
      return FWinHttpQueryDataAvailable(hRequest,lpdwNumberOfBytesAvailable);
  return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// Instantiate the CPamTaskBar applet.
//

CPamTaskBar theApplet;

/////////////////////////////////////////////////////////////////////////////
// Define the methods of CPamTaskBar.
//

void  __stdcall CPamTaskBar::OnTimerMessage(WPARAM wParam)
{
	m_DiscardInput = FALSE; /* Start from scratch */

	TRACE("heartbeat: counter=%d\n", m_TimeOut);

#ifndef USE_COM_PORTS
	if ( m_State ==  STATE_NULL ) {
		if ( OpenUSB() ) {
			NotifyUser(_T("Pam found"), FALSE, TRUE);
			m_PamMode = -1;
			m_State = STATE_UNDOCKED;
			TRACE("STATE: UNDOCKED\n");
		}
	} else if ( m_State == STATE_DOCKED ) {
		// Kijk of de Pam er nog steeds aanhangt
		if ( ! PamStillThere() ) {
			CloseUSB();
			m_State = STATE_NULL;
			TRACE("STATE: NULL\n");
			NotifyUser(_T("Undocked"), FALSE, TRUE);
		}
	} else {
		// Kijk of er iets op te halen is. Vanwege de heartbeat, mag deze polling.
		if ( ReadUSB() ) {
			m_TimeOut = BREAK_RETRY * 1000 / m_Heartbeat + 1; // always round up
		}
	}
#endif

	switch ( m_State )
	{
	case STATE_UNDOCKED:
		// Hier mogen we eigenlijk niet meer komen met de USB variant...
		m_TimeOut = MSG_RETRY;	/* Start counting from now. */
		m_State = STATE_RDSERNR;
		TRACE("STATE: RDSERNR\n");
		// Fall through
	case STATE_RDSERNR:
		PamReadSerialNumber();
		break;
//	case STATE_READMODE:
//		PamReadMode();
//		break;
//	case STATE_STATICMODE:
//		PamStaticMode();
//		break;
//	case STATE_READCAL_FACTOR:
//		PamReadCalibrationFactor();
//		break;
//	case STATE_READEEP:
//		PamReadEeprom();
//		break;
	case STATE_READEEPP0:   // added by E. Damen for AM102
		PamReadEepromPage0(m_Key_return);
		break;
	case STATE_READEEPP1:   // added by E. Damen for AM102
		PamReadEepromPage1(m_Key_return);
		break;
	case STATE_READEEPP2:   // added by E. Damen for AM102
		PamReadEepromPage2(m_Key_return);
		break;
	case STATE_READEEPP3:   // added by E. Damen for AM102
		PamReadEepromPage3(m_Key_return);
		break;
	case STATE_UPLOADDATA:
		PamUploadData();
		break;
//	case STATE_READDAYSCORE:
//		PamReadRam(RAM_DAYSCORE);
//		break;
//	case STATE_READMEDSCORE:
//		PamReadRam(RAM_MEDSCORE);
//		break;
//	case STATE_READHEAVYSCORE:
//		PamReadRam(RAM_HEAVYSCORE);
//		break;
//	case STATE_READDAYSCORE102:   // added by E. Damen for AM102
//		PamReadRam(RAM_DAYSCORE102);
//		break;
//	case STATE_READMEDSCORE102:   // added by E. Damen for AM102
//		PamReadRam(RAM_MEDSCORE102);
//		break;
//	case STATE_READHEAVYSCORE102:   // added by E. Damen for AM102
//		PamReadRam(RAM_HEAVYSCORE102);
//		break;
	case STATE_READTODAY:   	// added for AM200
		PamReadToday();
		break;
//	case STATE_TOGGLEMODE:
//		PamToggleMode();
//		break;
	case STATE_SETMODE:		// added for AM200 to set UpdateDockDay
		PamSetMode(m_PamMode, m_Key_return);
		break;
	case STATE_SETAUX:		// added for AM200 to set Calories per Pam unit
		PamSetAux(m_CalorieperPam);
		break;
	case STATE_VERIFYCLK:
	case STATE_READCLK:
		PamGetTime();
		break;
	case STATE_SETCLK:
		PamSetTime();
		break;
	}

	/* Check the time out. */

	if ( m_State != STATE_NULL && 
		 m_State != STATE_UNDOCKED && 
		 m_State != STATE_DOCKED && 
		 m_TimeOut-- == 0 )
	{
		// We didn't get an event on time. Reset state to undocked.

		if ( m_State == STATE_DOCKED )
		{
			NotifyUser(_T("Undocked"), FALSE, TRUE);
		}
		else
		{
			CString msg(_T("Could not synchronize " PAM_NAME "..."));
			NotifyUser(msg, FALSE, TRUE);
 		}

		m_State = STATE_UNDOCKED;
		m_SerialNumber = m_Config = 0;
		TRACE("STATE: UNDOCKED\n");
	}
}

void  __stdcall CPamTaskBar::NotifyUser(CString strMsg, BOOL bShow, BOOL bReset)
{
	if ( m_pProgressDlg == NULL ) 
	{
		m_pProgressDlg = new ProgressDlg;
		m_pProgressDlg->Create(IDD_PROGRESS);

		m_pProgressDlg->m_ctlProgressBar.SetRange(0,12);
		m_pProgressDlg->m_ctlProgressBar.SetStep(1);
		m_pProgressDlg->m_ctlProgressBar.SetPos(0);

		m_pProgressDlg->SetIcon(LoadIcon(::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ICONBIG)), TRUE);

		m_pProgressDlg->m_bDismissed = FALSE;
	}

	if ( m_pProgressDlg != NULL )
	{
		m_pProgressDlg->m_strProgress = strMsg;
		m_pProgressDlg->UpdateData(FALSE);

		m_pProgressDlg->SetWindowText(strMsg);

		if ( bReset )
		{
			m_pProgressDlg->m_ctlProgressBar.SetPos(0);
			m_pProgressDlg->m_bDismissed = FALSE;
		}
		else
		{
			m_pProgressDlg->m_ctlProgressBar.StepIt();
		}

		if ( ! m_pProgressDlg->m_bDismissed )
		{
			m_pProgressDlg->ShowWindow(bShow ? SW_SHOW : SW_HIDE);
		}
	}

	m_TrayTip = strMsg;
	UpdateShellInfo();
}

void  __stdcall CPamTaskBar::ProcessBreak()
{
	if ( m_State == STATE_UNDOCKED )
	{
		if ( m_bSkipBreak ) {
			m_bSkipCounter += 1;
			if (m_bSkipCounter == 2) {
				m_bSkipBreak = FALSE;}
		} else {
//			m_dwEob = 0;    /* Flush the message buffer. */
			m_TimeOut = MSG_RETRY;	/* Start counting from now. */

			m_State = STATE_RDSERNR;  // Always first determine Pam version!
			TRACE("STATE: RDSERNR\n");
		}
	}
	else if ( m_State == STATE_DOCKED )
	{
		m_TimeOut = BREAK_RETRY * 1000 / m_Heartbeat + 1; // always round up
	}
}



void  __stdcall CPamTaskBar::OnSerialMessage(WPARAM wParam)
// Deze functie wordt aangeroepen indien er seriele communicatie binnenkomt. 
// In geval van een USB device, wordt dit niet gebruikt.
{
# ifdef USE_COM_PORTS
	const CSerialWnd::EEvent eEvent = CSerialWnd::EEvent(LOWORD(wParam));
	const CSerialWnd::EError eError = CSerialWnd::EError(HIWORD(wParam));
				
	if ( eEvent & CSerialWnd::EEventBreak ) {
		TRACE("\nRECEIVE: hardware break\n");
	}

	if ( eEvent & CSerialWnd::EEventRecv ) {
		bool DataAvailable;

		do
		{
			// Read data from the COM-port
			DWORD dwBytesRead = 0;
			if ( m_dwEob >= sizeof m_Buffer ) {
				m_dwEob = 0; // should not occur, prevent buffer overflow
				TRACE("\nERROR: ######################### buffer overflow ########################\n");
			}
			long lLastError = m_serial.Read(m_Buffer + m_dwEob,
					                        sizeof m_Buffer - m_dwEob,
											&dwBytesRead);

			if ( FALSE /* debugging */ )
			{
				unsigned int i;
				for ( i = 0 ; i < dwBytesRead ; i++ )
					TRACE(" [%02x]", m_Buffer[m_dwEob+i]);
			}

			m_dwEob += dwBytesRead;

			if ( lLastError != ERROR_SUCCESS )
			{
				ShowError(m_serial.GetLastError(), _T("Unable to read from COM-port."), TRUE);
				return;
			}

			DataAvailable = (m_dwEob == sizeof m_Buffer);

			while ( ProcessMessage() ) {};
		}
		while ( DataAvailable );
	}

	if ( eEvent & CSerialWnd::EEventError ) {
		switch ( eError )
		{
		case CSerial::EErrorBreak:		TRACE("\nERROR: serial break condition\n");			break;
		case CSerial::EErrorFrame:		TRACE("\nERROR: serial framing error\n");			break;
		case CSerial::EErrorIOE:		TRACE("\nERROR: serial IO device error\n");			break;
		case CSerial::EErrorMode:		TRACE("\nERROR: serial unsupported mode\n");		break;
		case CSerial::EErrorOverrun:	TRACE("\nERROR: serial buffer overrun\n");			break;
		case CSerial::EErrorRxOver:		TRACE("\nERROR: serial input buffer overflow\n");	break;
		case CSerial::EErrorParity:		TRACE("\nERROR: serial input parity error\n");		break;
		case CSerial::EErrorTxFull:		TRACE("\nERROR: serial output buffer full\n");		break;
		default:						TRACE("\nERROR: serial %d\n", eError);				break;
		}

	}

#endif
}

BOOL  __stdcall CPamTaskBar::ProcessMessage()
{
	if ( m_DiscardInput ) {
		if ( m_dwEob > 0 ) {
			TRACE("\nERROR: %d bytes dropped\n", m_dwEob);
		}
		m_dwEob = 0;
		return false;
	}

	while ( m_dwEob > 0 && m_Buffer[0] == 0x00 ) 
	{
		memmove(m_Buffer + 1, m_Buffer, --m_dwEob);

		TRACE("\nRECEIVE: software break\n");
		ProcessBreak();
	}

	if ( m_dwEob < 5 ) {
		return false; // Partial (or empty) message, wait for more.
	}		

	BYTE Length = m_Buffer[2];
	BYTE Command = m_Buffer[1];
	BYTE Checksum = 0;

	if ( m_Buffer[0] != PAM_STX ) {
		TRACE("\nERROR: ##################### STX missing (0x%02x) #####################\n", PAM_STX);
		m_DiscardInput = TRUE;

		return true;
	}

	if ( Length > 170 || Length < 5 ) {
		TRACE("##################### bad length (%d) #######################", Length);
		m_DiscardInput = TRUE;
		return true;
	}

	if ( m_dwEob < Length  ) {
		return false; // Partial message, wait for more.
	}

	TRACE("[");
	{
		unsigned int i;
		for ( i = 0 ; i < m_dwEob ; i++ )
			TRACE("%02x", m_Buffer[i]);
	}
	TRACE("] ");

	for ( int i = 0 ; i < Length - 2 ; i++ ) {
		Checksum += m_Buffer[i];
	}
	if ( m_Buffer[Length - 2] != Checksum ) {
		if ( m_VersionNumber.Major == 0 &&
			 m_VersionNumber.Minor == 1 &&
  		     (Command == ACK_READCLK || Command == ACK_READMODE) ) {
			// Work around Pam bug: ignore checksum failure
		} else if ( m_VersionNumber.Major == 0 &&
			        m_VersionNumber.Minor == 2 &&
  		            Command == ACK_READEEP ) {
			// Work around a new Pam bug: ignore checksum failure
		} else {
			TRACE("\nERROR: ##################### Checksum failure ##################### \n");
 			m_DiscardInput = TRUE;

			return true;
		}
	}

	if ( m_Buffer[Length - 1] != PAM_EOT ) {
		TRACE("\nERROR: ##################### EOT missing (0x%0x) #####################\n", m_Buffer[Length - 1]);

		if ( (m_VersionNumber.Major == 1 && m_VersionNumber.Minor == 0) || 
			 (m_VersionNumber.Major == 0) ) {
			if ( Command == ACK_READEEP ) {
				// Work around a new Pam bug: reset timer on checksum failure
				m_TimeOut = MSG_RETRY;	/* Start counting from now. */
			}
		}

		m_DiscardInput = TRUE;
		return true;
	}

	// Now we have a properly formatted message layout. So reset the passed-out counter.
	m_TimeOut = MSG_RETRY;

	switch ( Command ) {

	case NACK:
		// Negative acknowledgment, ignore it. Our app will retry in a second.

		TRACE("\nRECEIVE: NACK\n");

		break;
/*
	case ACK_READRAM:
		switch ( (m_Buffer[3] << 8) | m_Buffer[4] ) {
		case RAM_DAYSCORE:
			{
				m_PamDayScore16 = m_Buffer[5];
				TRACE("\nRECEIVE: ack READDAYSCORE: %u\n", m_PamDayScore16);

				m_State = STATE_READMEDSCORE;
				TRACE("STATE: READMEDSCORE\n");
				break;
			}
		case RAM_MEDSCORE:
			{
				m_PamMedScore = (m_Buffer[6] << 8) | m_Buffer[5];
				TRACE("\nRECEIVE: ack READMEDSCORE: %u\n", m_PamMedScore);

				m_State = STATE_READHEAVYSCORE;
				TRACE("STATE: READHEAVYSCORE\n");
				break;
			}
		case RAM_HEAVYSCORE:   // changed by E. Damen for AM102
			{
				if (m_VersionNumber.Major == 1 && m_VersionNumber.Minor < 3) 
				{
					m_PamHighScore = (m_Buffer[6] << 8) | m_Buffer[5];
				} else
				{
					m_PamHighScore = (m_Buffer[6] & 0xF0 << 4) | (m_Buffer[5] & 0x0F << 4) | (m_Buffer[5] & 0xF0 >> 4);
				}

				TRACE("\nRECEIVE: ack READHEAVYSCORE: %u\n", m_PamHighScore);

				m_State = STATE_UPLOADDATA;
				TRACE("STATE: UPLOADDATA\n");
				break;
			}
		case RAM_DAYSCORE102:   // added by E. Damen for AM102
			{
				m_PamDayScore16 = m_Buffer[5];
				TRACE("\nRECEIVE: ack READDAYSCORE: %u\n", m_PamDayScore16);

				m_State = STATE_READMEDSCORE102;
				TRACE("STATE: READMEDSCORE102\n");
				break;
			}
		case RAM_MEDSCORE102:   // added by E. Damen for AM102
			{
				m_PamMedScore = (m_Buffer[6] & 0xF0 << 4) | (m_Buffer[5] & 0x0F << 4) | (m_Buffer[5] & 0xF0 >> 4);
				TRACE("\nRECEIVE: ack READMEDSCORE: %u\n", m_PamMedScore);

				m_State = STATE_READHEAVYSCORE102;
				TRACE("STATE: READHEAVYSCORE102\n");
				break;
			}

		default:
			{
				TRACE("\nRECEIVE: ack READRAM unexpected address: 0x%04x\n",
					  (m_Buffer[3] << 8) | m_Buffer[4]);
				break;
			}
		}
		break;
*/
	case ACK_RDSERNR:   // Erik Damen: changed for AM200
		// m_Buffer contains unsigned values, so shifting is safe.
		// MSB and LSB swapped according to new specs
		m_SerialNumber = m_Buffer[6] | (m_Buffer[5] << 8) | (m_Buffer[4] << 16) | (m_Buffer[3] << 24);
		m_VersionNumber.Major = m_Buffer[7];
		m_VersionNumber.Minor = m_Buffer[8];
		m_VersionNumber.Build = m_Buffer[9];
		m_Key = m_Buffer[10] ;
		m_Key_return = m_Key ^ 0xAA ;  // key encryption for AM200 secured commands (^ means XOR)

		
		TRACE("\nRECEIVE: ack RDSERNR 0x%08x, version %d.%d.%d, key %d\n",
			  m_SerialNumber,
			  m_VersionNumber.Major, m_VersionNumber.Minor, m_VersionNumber.Build, m_Key);

		if ( m_State == STATE_RDSERNR ) {
			m_State = STATE_READEEPP0;  // Erik Damen: changed state machine
			TRACE("STATE: READEEPP0\n");
		}
		break;

	case ACK_READTODAY:   // Erik Damen: added for AM200
		m_PamDayScore16 = m_Buffer[3] + ((m_Buffer[4]&0x1F)<<8);
		m_PamLowScore = ((m_Buffer[4]&0xE0)>>5) + (m_Buffer[5]<<3);
		m_PamMedScore = m_Buffer[6] + ((m_Buffer[7]&0x03)<<8);
		m_PamHighScore = ((m_Buffer[7]&0xFC)>>2) + ((m_Buffer[8]&0x03)<<6);
		m_PamDistanceTD = ((m_Buffer[8]&0xFC)>>2) + ((m_Buffer[9]&0x0F)<<6);
		m_PamFruitTD = ((m_Buffer[9]&0xF0)>>4);
		
		TRACE("\nRECEIVE: ack READTODAY %d\n",
			  m_PamDayScore16 >> 4);

		if ( m_State == STATE_READTODAY ) {
			m_State = STATE_UPLOADDATA;  // Erik Damen: changed state machine
			TRACE("STATE: UPLOADDATA\n");
		}
		break;

	case ACK_READMODE:
		TRACE("\nRECEIVE: ack READMODE\n");
		
/*		m_PamMode = m_Buffer[3];
		m_ConsumerMode = (m_PamMode & BIT_MODE_PAM_MODE) == BIT_MODE_CONSUMER;

		TRACE("\nRECEIVE: ack %s 0x%02x (%s)\n",
			  m_State == STATE_READMODE ? "READMODE" : "SETMODE",
			  m_PamMode,
			  m_ConsumerMode ? "consumer" : "scientific");
		
		if ( m_State == STATE_READMODE || m_State == STATE_STATICMODE ) 
		{
			if ( (m_PamMode & BIT_MODE_INTEGRATOR) == 0 && m_VersionNumber.Major == 1 && m_VersionNumber.Minor < 3) {
				TRACE("WARNING: Pam in dynamic mode!\n");
					m_State = STATE_STATICMODE;
					TRACE("STATE: STATICMODE\n");
			} else {
				if (m_VersionNumber.Major == 1 && m_VersionNumber.Minor == 3) {
					m_State = STATE_READEEPP0;}
				else {
					m_State = STATE_READEEP;}
				TRACE("STATE: READEEP\n");
			}
		}
		else if ( m_State == STATE_TOGGLEMODE ) 
		{
			m_Fifo = 0x10; 
			m_State = STATE_READCLK;
			TRACE("STATE: READCLK\n");
		}
*/
		m_State = STATE_SETAUX;
		TRACE("STATE: SETAUX\n");

		break;

	case ACK_READAUX:
		TRACE("\nRECEIVE: ack READAUX\n");
		m_State = STATE_SETCLK;
		TRACE("STATE: STATE_SETCLK\n");
		break;

	case ACK_READCAL_FACTOR:
		// m_Buffer contains unsigned values, so shifting is safe.
		m_GainAdjustMultiplier = m_Buffer[3];
		m_GainAdjustDivider    = m_Buffer[4];
		m_TresholdLight        = m_Buffer[5] | (m_Buffer[6] << 8);
		m_TresholdHeavy        = m_Buffer[7] | (m_Buffer[8] << 8);

		TRACE("\nRECEIVE: ack READCL_FACTOR mult=%d, div=%d, light=%d, heavy=%d\n",
			  m_GainAdjustMultiplier,
			  m_GainAdjustDivider,
			  m_TresholdLight,
			  m_TresholdHeavy);

		if ( m_State == STATE_READCAL_FACTOR ) {
			//m_State = STATE_READDOCKINGDATE;
			TRACE("STATE: READDOCKINGDATE\n");
		}
		break;

	case ACK_READADDRESS:
		TRACE("\nWARNING : SHOULD NOT OCCUR!\n");
		
		if ( m_Buffer[3] == ADDRESS_FIFO &&
			 m_Buffer[4] == m_Fifo /*&&
			 m_State == STATE_SETDOCKINGDATE */ ) 
		{
			TRACE("\nRECEIVE: ack SETFIFO\n");

			m_Size = 0;

			m_State = STATE_READCLK;
			TRACE("STATE: READCLK\n");
		}
		else 
		{
			TRACE("\nRECEIVE: ack READADDRESS not asked for!");
			TRACE(" (0x%02x, 0x%02x)\n", m_Buffer[3], m_Buffer[4]);
		}
		break;


	case ACK_READCLK:
		if ( m_State == STATE_VERIFYCLK ) {
			if ( m_Buffer[3] != m_Time.GetMinute() || m_Buffer[4] != m_Time.GetHour() ) {
				TRACE("\nRECEIVE: ack READCLK, nok!!!");
				m_State = STATE_SETCLK;
				TRACE("STATE: SETCLK");
				break;
			}
		} 

		if ( m_State == STATE_READCLK ) {
			m_Time = CTime(2000, 1, 1, m_Buffer[4], m_Buffer[3], 0, 0);
		
			TRACE("\nRECEIVE: ack READCLK %d:%02d\n", m_Buffer[4], m_Buffer[3]);

			m_State = STATE_SETCLK;
			TRACE("STATE: SETCLK\n");
		} else if ( m_State == STATE_SETCLK ) {
			TRACE("\nRECEIVE: ack SETCLK\n");

			CString msg(_T(" docked"));
			msg = PAM_NAME + msg;
			NotifyUser(msg, FALSE, TRUE);
//			NotifyUser(_T("Pam docked"), FALSE, TRUE);

			m_State = STATE_DOCKED;
			TRACE("STATE: DOCKED\n");

			m_TimeOut = IDLE_RETRY * 1000 / m_Heartbeat + 1; /* Start counting from now. Within x seconds we expect a break signal. */
		} else if ( m_State == STATE_VERIFYCLK ) {
			TRACE("\nRECEIVE: ack READCLK, ok\n");

			CString msg(_T(" docked"));
			msg = PAM_NAME + msg;
			NotifyUser(msg, FALSE, TRUE);
//			NotifyUser(_T("Pam docked"), FALSE, TRUE);

			m_State = STATE_DOCKED;
			TRACE("STATE: DOCKED\n");

			m_TimeOut = IDLE_RETRY * 1000 / m_Heartbeat + 1; /* Start counting from now. Within x seconds we expect a break signal. */
		} else {
			TRACE("\nRECEIVE: ack READCLK not asked for!\n");
		}
		break;

	}

	if (m_VersionNumber.Major == 1 && m_VersionNumber.Minor < 3)   // changed by E. Damen for AM102
	{switch ( Command ) {
			case ACK_READEEP:
		{
			BYTE *Eeprom = m_Buffer + 3;
			m_Fifo = Eeprom[0x0f];

			TRACE("\nRECEIVE: ack READEEP ");

			m_Config = Eeprom[0x0a] | (Eeprom[0x09] << 8) | (Eeprom[0x08] << 16) | (Eeprom[0x07] << 24);

			if ( ! m_ConsumerMode ) {
				_ASSERTE((m_Fifo - 0x10) % RAM_BYTES_PER_DAY == 0);
			}

			m_Size = 0;
			UINT Fifo = m_Fifo;
			do {
				m_Pam[m_Size] = Eeprom[Fifo++];
				if ( ! m_ConsumerMode )
				{
					m_LightActivity[m_Size]  = (Eeprom[Fifo + 1] << 8) | Eeprom[Fifo]; Fifo += 2;
					m_MediumActivity[m_Size] = (Eeprom[Fifo + 1] << 8) | Eeprom[Fifo]; Fifo += 2;
					m_HeavyActivity[m_Size]  = (Eeprom[Fifo + 1] << 8) | Eeprom[Fifo]; Fifo += 2;
				}
				if ( Fifo >= 0x80 ) Fifo = 0x10; // Modulo de geheugen grootte.
				TRACE("%d ", m_Pam[m_Size]);
				m_Size++;
			}
			while ( Fifo != m_Fifo );

			TRACE("\n%d days, fifo=0x%02x\n", m_Size, m_Fifo);

			if ( m_State == STATE_READEEP ) {
				m_State = STATE_READDAYSCORE;
				TRACE("STATE: READDAYSCORE\n");
			}
			break;
		}

	}}
	else
	{switch ( Command ) {
		case ACK_READEEPPAGE0:
		{
			BYTE *Eeprom = m_Buffer + 3;
			for (int i=0;i<128;i++) {
				Eepromt[i] = m_Buffer[i+3];}

			TRACE("\nRECEIVE: ack READEEPPAGE0 ");

//			m_Fifo = Eeprom[0x0f] +256*Eeprom[0x10];  // fifo is 2 bytes long in AM102
//
//			TRACE("\nm_Fifo = %d ",m_Fifo);
//
//			m_Config = Eeprom[0x0a] | (Eeprom[0x09] << 8) | (Eeprom[0x08] << 16) | (Eeprom[0x07] << 24);

			m_Fifo = (Eeprom[0x30] - 1) * RAM_BYTES_PER_DAY + RAM_START_DAY_ADDR; // Today_index times 7 + offset

			m_PamMode = Eeprom[0x05];

			m_Config = Eeprom[0x0B] | (Eeprom[0x07] << 8) | (Eeprom[0x06] << 16) | (Eeprom[0x05] << 24);
			// for AM200: GCorr, Calories per Pam unit, Last Docking Day Index, Mode setting

			if ( m_State == STATE_READEEPP0 ) {
				m_State = STATE_READEEPP1;
				TRACE("STATE: READEEPPAGE1\n");
			}
			break;
		}

		case ACK_READEEPPAGE1:
		{
			for (int i=0;i<128;i++) {
				Eepromt[i+0x80] = m_Buffer[i+3];}

			TRACE("\nRECEIVE: ack READEEPPAGE1 ");
			if ( m_State == STATE_READEEPP1 ) {
				m_State = STATE_READEEPP2;
				TRACE("STATE: READEEPPAGE2\n");
			}
			break;
		}


		case ACK_READEEPPAGE2:
		{
			for (int i=0;i<128;i++) {
				Eepromt[i+0x100] = m_Buffer[i+3];}

			TRACE("\nRECEIVE: ack READEEPPAGE2 ");
			if ( m_State == STATE_READEEPP2 ) {
				m_State = STATE_READEEPP3;
				TRACE("STATE: READEEPPAGE3\n");
			}
			break;
		}

		
		case ACK_READEEPPAGE3:
		{
			for (int i=0;i<128;i++) {
				Eepromt[i+0x180] = m_Buffer[i+3];}


			TRACE("\nm_Fifo = %d ",m_Fifo);

			TRACE("\nRECEIVE: ack READEEPPAGE3 ");


			if ( ! m_ConsumerMode ) {
				_ASSERTE((m_Fifo - RAM_START_DAY_ADDR) % RAM_BYTES_PER_DAY == 0);
			}

			m_Size = 0;
			UINT Fifo = m_Fifo;
			do {
				m_Pam[m_Size] = Eepromt[Fifo]; // Erik, check dit: // Fifo++;
//				if ( ! m_ConsumerMode )
//				{
//					m_LightActivity[m_Size]  = Eepromt[Fifo]; Fifo++; 
//					m_MediumActivity[m_Size] = Eepromt[Fifo]; Fifo++;
//					m_HeavyActivity[m_Size]  = Eepromt[Fifo]; Fifo++;
//				}

//				For the AM200, the day is stored in a different way from the AM102:

//				Pam Score: 13 bits
//				Low activity minutes: 11 bits
//				Medium activity minutes: 10 bits
//				High activity minutes: 8 bits
//				Distance: 10 bits
//				Fruit: 4 bits

//				m_Pam[m_Size] = Eepromt[Fifo] + (Eepromt[Fifo+1]&0x1F)<<8;
//				m_LightActivity[m_Size] = (Eepromt[Fifo+1]&0xE0)>>5 + Eepromt[Fifo+2]<<3;
//				m_MediumActivity[m_Size] = Eepromt[Fifo+3] + (Eepromt[Fifo+4]&0x03)<<8;
//				m_HeavyActivity[m_Size] = (Eepromt[Fifo+4]&0xFC)>>2 + (Eepromt[Fifo+5]&0x03)<<6;
//				m_Distance[m_Size] = (Eepromt[Fifo+5]&0xFC)>>2 + (Eepromt[Fifo+6]&0x0F)<<6;
//				m_Fruit[m_Size] = (Eepromt[Fifo+6]&0xF0)>>4;

				m_code1[m_Size] = Eepromt[Fifo] + (Eepromt[Fifo+1]<<8) + (Eepromt[Fifo+2]<<16) + (Eepromt[Fifo+3]<<24);
				m_code2[m_Size] = Eepromt[Fifo+4] + (Eepromt[Fifo+5]<<8) + (Eepromt[Fifo+6]<<16);
				
				Fifo = Fifo + RAM_BYTES_PER_DAY;

				if ( Fifo >= RAM_END_DAY_ADDR ) Fifo = RAM_START_DAY_ADDR; // Modulo memory size
				m_Size++;
			}
			while ( Fifo != m_Fifo );

			TRACE("\n%d days, fifo=0x%02x\n", m_Size, m_Fifo);

			if ( m_State == STATE_READEEPP3 ) {
				m_State = STATE_READTODAY;
				TRACE("STATE: READTODAY\n");
			}
			break;
		}

	}}

	m_dwEob -= Length;

	return true;
}


//////////////////////////////////////////////////////////////////

void  __stdcall CPamTaskBar::OnLeftDoubleClick()
{
#ifdef USE_COM_PORTS
	SettingsDialog();
#else
	AboutDialog();
#endif
}

void  __stdcall CPamTaskBar::AboutDialog()
{
	CAboutDlg dlgAbout;
	if ( m_SerialNumber == 0 ) {
		CString msg;
		msg.Format(_T("Serial number unknown (%s not docked)"), PAM_NAME);
		dlgAbout.m_strSerial = msg;
	} else {
		int country = m_SerialNumber >> 24;
		dlgAbout.m_strSerial.Format(IDS_ABOUT_SERIAL_FIRMWARE,
				                    m_SerialNumber & 0x00ffffff,
									country == COUNTRY_US ? " (US)" : (country == COUNTRY_UK ? " (UK)": ""),
									m_VersionNumber.Major,
									m_VersionNumber.Minor,
									m_VersionNumber.Build,
									PAM_NAME,
									m_PamDayScore16 >> 4);
	}
	if ( m_Config == 0 ) {
		dlgAbout.m_strConfig = m_bUseWinHttp ? "WinHTTP mode" : "WinINet mode";
	} else {
		dlgAbout.m_strConfig.Format(IDS_ABOUT_CONFIG_FIRMWARE,
				                    m_Config,
									m_bUseWinHttp ? "WinHTTP" : "WinINet");
	}

	CString Msg;
	Msg.Format(_T("%s Version %d.%d"), DRIVER_NAME, VERSION_MAJOR, VERSION_MINOR); 
	dlgAbout.m_strVersion = Msg;

	dlgAbout.DoModal();
}

/*
void CPamTaskBar::SettingsDialog()
{
	//IDC_STATIC_PAMMODE

	CString Msg;
	Msg.Format(_T("%s Settings"), DRIVER_NAME);
	CPropertySheet dlg(Msg);

	StandardDlg dlgStandard;
	DebugDlg    dlgDebug;

	CWinApp* pApp = AfxGetApp();

	// Load the settings from the registry.

	CString strComPort
		= pApp->GetProfileString(_T(PAM_VERSION), _T(REG_COM_PORT), _T("COM1"));
	LONG nClock
		= pApp->GetProfileInt(_T(PAM_VERSION), _T(REG_CLOCK_MODE), 0);
	BOOL bSyncToPC 
		= pApp->GetProfileInt(_T(PAM_VERSION), _T(REG_SYNC_CLOCK), 1) != 0;

	int nPamMode;
	if ( m_State != STATE_DOCKED ) {
		nPamMode = -1;
	} else if ( ((m_VersionNumber.Major << 16) |
				 (m_VersionNumber.Minor <<  8) |
				 (m_VersionNumber.Build <<  0)) < 0x010200 ) {
		// version < 1.2.0
		nPamMode = -1;
	} else {
		nPamMode = m_ConsumerMode ? 0 : 1;
	}

	dlgStandard.m_pSerial     = &m_serial;
	dlgStandard.m_strComPort  = strComPort;
	dlgStandard.m_bSyncToPC   = bSyncToPC;
	dlgStandard.m_nClock      = nClock;
	dlgStandard.m_nPamMode    = nPamMode;
	dlgStandard.m_bModeSwitchAllowed = TRUE; // functie wordt niet gebruikt

	Msg.Format(_T("%s mode:"), PAM_NAME);
	dlgStandard.m_PamModeLabel = Msg;

	dlgDebug.m_strUploadServer = pApp->GetProfileString(_T(PAM_VERSION),
		                                                _T(REG_SERVER_URL),
			                                            _T(UPLOAD_URL));
	dlgDebug.m_lHeartbeat = pApp->GetProfileInt(_T(PAM_VERSION), _T(REG_HEARTBEAT), DEFAULT_HEARTBEAT);

	dlg.AddPage(&dlgStandard);

	if ( pApp->GetProfileInt(_T(PAM_VERSION), _T(REG_GODDESS), 0) != 0 ) {
		dlg.AddPage(&dlgDebug);
	}

	INT_PTR nResponse = dlg.DoModal();

	if ( nResponse == IDOK )
	{
		if ( dlgStandard.m_nPamMode != nPamMode ) {
			CString msg;
			msg = _T("Are you sure you want to set your ");
			msg += PAM_NAME;
			if ( m_ConsumerMode ) {
				msg += " to Advanced Mode?";
			} else {
				msg += " to Memory Mode?";
			}
			if ( ::MessageBox(0, msg, _T("Pam mode"), MB_OKCANCEL|MB_ICONWARNING) != IDOK )
			 {
				// Restore old value
				dlgStandard.m_nPamMode = nPamMode;
			 }
		}

		// Save the settings to the registry.
#ifdef USE_COM_PORTS
		pApp->WriteProfileString(_T(PAM_VERSION), _T(REG_COM_PORT),     dlgStandard.m_strComPort);
		pApp->WriteProfileInt   (_T(PAM_VERSION), _T(REG_CLOCK_MODE),   dlgStandard.m_nClock);
		pApp->WriteProfileInt   (_T(PAM_VERSION), _T(REG_SYNC_CLOCK),   dlgStandard.m_bSyncToPC);
		pApp->WriteProfileString(_T(PAM_VERSION), _T(REG_SERVER_URL),   dlgDebug.m_strUploadServer);
		pApp->WriteProfileInt   (_T(PAM_VERSION), _T(REG_HEARTBEAT),    dlgDebug.m_lHeartbeat);
#endif

		if ( dlgDebug.m_lHeartbeat != m_Heartbeat ) {
			StartHeartbeat();
		}

# ifdef USE_COM_PORTS
		if ( dlgStandard.m_strComPort != strComPort || m_State == STATE_NULL ) {
			// Close the current com port and open the newly selected one.
			m_State = STATE_NULL;
			TRACE("STATE: NULL\n");
			CloseComPort();
			if ( OpenComPort() ) {
				NotifyUser(_T("Undocked"), TRUE, TRUE);
				m_State = STATE_UNDOCKED;
				m_PamMode = -1;
				TRACE("STATE: UNDOCKED\n");
			}
		} else 
# endif
		if ( dlgStandard.m_nPamMode != nPamMode && m_State == STATE_DOCKED ) {
			// The user has toggled the Pammode setting.
			m_State = STATE_TOGGLEMODE;
			TRACE("STATE: TOGGLEMODE\n");
		} else if ( dlgStandard.m_bSyncToPC != bSyncToPC &&
			        m_State == STATE_DOCKED &&
			        dlgStandard.m_bSyncToPC ) {
			// The user checked the synchronise button, so set the time again.
			m_State = STATE_READCLK;
			TRACE("STATE: READCLK\n");
		} else if ( dlgStandard.m_nClock != nClock && m_State == STATE_DOCKED ) {
			// The user has toggled the clock setting, so set the time again.
			m_State = STATE_READCLK;
			TRACE("STATE: READCLK\n");
		}
	}
	else if (nResponse == IDCANCEL)
	{
	}
}
*/

LPCTSTR  __stdcall CPamTaskBar::GetTrayTip()
{
	return m_TrayTip;
}


HICON  __stdcall CPamTaskBar::GetIcon()
{
	return ::LoadIcon(::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ICONSMALL));
}


HMENU  __stdcall CPamTaskBar::GetMenu()
{
   HMENU hMenu = CreatePopupMenu();

   MENUITEMINFO item;

   memset(&item, 0, sizeof(MENUITEMINFO));

   item.cbSize = sizeof(MENUITEMINFO);

   ///////////////////////////////////////
#ifdef USE_COM_PORTS
   item.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;

   item.wID = ID_OPEN;

   item.fType = MFT_STRING;

   item.dwTypeData = _T("&Settings");

   item.fState = MFS_DEFAULT;

   InsertMenuItem(hMenu, 0, FALSE, &item);
#endif
   ///////////////////////////////////////
   item.fMask = MIIM_TYPE | MIIM_ID;

   item.wID = ID_PAM;

   item.fType = MFT_STRING;

   item.dwTypeData = _T("&Open " PAM_NAME " site");

   InsertMenuItem(hMenu, 0, FALSE, &item);
   ///////////////////////////////////////
/*
   item.fMask = MIIM_TYPE | MIIM_ID;

   item.wID = ID_UPLOAD;

   item.fType = MFT_STRING;

   item.dwTypeData = _T("&Upload Data");

   InsertMenuItem(hMenu, 0, FALSE, &item);
*/
   ///////////////////////////////////////

   item.wID = ID_ABOUT;

   item.fType = MFT_STRING;

   item.dwTypeData = _T("&About");

#ifdef USE_COM_PORTS
   item.fMask = MIIM_TYPE | MIIM_ID;
#else
   item.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
   item.fState = MFS_DEFAULT;
#endif

   InsertMenuItem(hMenu, 0, FALSE, &item);
   ///////////////////////////////////////
   item.fMask = MIIM_TYPE | MIIM_ID;
   item.fType =  MFT_SEPARATOR;

   InsertMenuItem(hMenu, 0, FALSE, &item);
   ///////////////////////////////////////
   item.wID = ID_CLOSE;

   item.fType = MFT_STRING;

   item.dwTypeData = _T("E&xit");

   InsertMenuItem(hMenu, 0, FALSE, &item);
   ///////////////////////////////////////

   return hMenu;
}


void  __stdcall CPamTaskBar::HandleMenuCommand(int command)
{
	switch (command)
	{
	case ID_CLOSE:
		{
			CloseApplet();
			break;
		}
    case ID_ABOUT:
		{
			AboutDialog();
			break;
		}
    case ID_UPLOAD:
		{
			if ( m_State == STATE_DOCKED ) {
				NotifyUser(_T(DRIVER_NAME), TRUE, TRUE);
				m_State = STATE_NULL;
				m_PamMode = -1;
			} else if ( m_State == STATE_NULL ) {
#ifdef USE_COM_PORTS
				CloseComPort();
				if ( OpenComPort() ) {
					NotifyUser(_T("Undocked"), TRUE, TRUE);
					m_State = STATE_UNDOCKED;
					//m_State = STATE_RDSERNR;
					m_PamMode = -1;
					TRACE("STATE: UNDOCKED\n");
				}
#else
/*
CloseUSB();
				if ( OpenUSB() ) {
					NotifyUser(_T("Undocked"), TRUE, TRUE);
					m_State = STATE_UNDOCKED;
					//m_State = STATE_RDSERNR;
					m_PamMode = -1;
					TRACE("STATE: UNDOCKED\n");
				}
*/
#endif
			}
			break;
		}
/*
case ID_OPEN:
		{
			SettingsDialog();
			break;
		}
*/
	case ID_OPEN:
	case ID_PAM:
		{
		    CURL url;
			url.Open(_T(SITE_URL), false);
			break;
		}
	}
}