// USBRadioDlg.cpp : implementation file
//

#include "stdafx.h"
#include "USBRadio.h"
#include "USBRadioDlg.h"
#include "ToolbarDlg.h"

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

/////////////////////////////////////////////////////////////////////////////
// CUSBRadioDlg dialog

CUSBRadioDlg::CUSBRadioDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CUSBRadioDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CUSBRadioDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_hSmallIcon = (HICON)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 16, 16, 0); 
	m_pToolTip = NULL;
}

void CUSBRadioDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CUSBRadioDlg)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CUSBRadioDlg, CDialog)
	//{{AFX_MSG_MAP(CUSBRadioDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_MESSAGE(WM_TRAY_ICON_NOTIFY_MESSAGE, OnTrayNotify)
	ON_BN_CLICKED(IDC_BUTTON_MINIMIZE, OnMinimize)
	ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp) 
	ON_BN_CLICKED(IDC_BUTTON_PRESET1, OnPreset1)
	ON_BN_CLICKED(IDC_BUTTON_PRESET2, OnPreset2)
	ON_BN_CLICKED(IDC_BUTTON_PRESET3, OnPreset3)
	ON_BN_CLICKED(IDC_BUTTON_PRESET4, OnPreset4)
	ON_BN_CLICKED(IDC_BUTTON_PRESET5, OnPreset5)
	ON_BN_CLICKED(IDC_BUTTON_PRESET6, OnPreset6)
	ON_BN_CLICKED(IDC_BUTTON_PRESET7, OnPreset7)
	ON_BN_CLICKED(IDC_BUTTON_PRESET8, OnPreset8)
	ON_BN_CLICKED(IDC_BUTTON_PRESET9, OnPreset9)
	ON_BN_CLICKED(IDC_BUTTON_PRESET10, OnPreset10)
	ON_BN_CLICKED(IDC_BUTTON_PRESET11, OnPreset11)
	ON_BN_CLICKED(IDC_BUTTON_PRESET12, OnPreset12)
	ON_WM_TIMER()
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_BN_CLICKED(IDC_BUTTON_SCANUP, OnSeekup)
	ON_BN_CLICKED(IDC_BUTTON_SCANDOWN, OnSeekdown)
	ON_BN_CLICKED(IDC_BUTTON_PRESETSCANUP, OnPresetScanUp)
	ON_BN_CLICKED(IDC_BUTTON_PRESETSCANDOWN, OnPresetScanDown)
	ON_BN_CLICKED(IDC_BUTTON_TUNEUP, OnTuneup)
	ON_BN_CLICKED(IDC_BUTTON_TUNEDOWN, OnTunedown)
	ON_BN_CLICKED(IDC_BUTTON_MUTE, OnMute)
	ON_COMMAND(ID_SHOWRADIO, OnShowradio)
	ON_BN_CLICKED(IDC_BUTTON_SETTINGS, OnSettings)
	ON_BN_CLICKED(IDC_BUTTON_FMTUNERLINK, OnFMTunerLink)
	ON_BN_CLICKED(IDC_BUTTON_USBMCULINK, OnUSBMCULink)
	ON_BN_CLICKED(IDC_BUTTON_SILABSLINK, OnSilabsLink)
	ON_BN_CLICKED(IDC_BUTTON_SCANUP_DOWN, OnSeekup)
	ON_BN_CLICKED(IDC_BUTTON_SCANDOWN_DOWN, OnSeekdown)
	ON_BN_CLICKED(IDC_BUTTON_PRESETSCANUP_DOWN, OnPresetScanUp)
	ON_BN_CLICKED(IDC_BUTTON_PRESETSCANDOWN_DOWN, OnPresetScanDown)
	ON_BN_CLICKED(IDC_BUTTON_STEREOMONO, OnStereoMono)
	ON_BN_CLICKED(IDC_BUTTON_STEREOMONO_DOWN, OnStereoMono)
	ON_BN_CLICKED(IDC_BUTTON_MUTE_DOWN, OnMute)
	ON_BN_CLICKED(IDC_BUTTON_CLOSE, OnCancel)
	ON_COMMAND(ID_PRESET1, OnPreset1)
	ON_COMMAND(ID_PRESET2, OnPreset2)
	ON_COMMAND(ID_PRESET3, OnPreset3)
	ON_COMMAND(ID_PRESET4, OnPreset4)
	ON_COMMAND(ID_PRESET5, OnPreset5)
	ON_COMMAND(ID_PRESET6, OnPreset6)
	ON_COMMAND(ID_PRESET7, OnPreset7)
	ON_COMMAND(ID_PRESET8, OnPreset8)
	ON_COMMAND(ID_PRESET9, OnPreset9)
	ON_COMMAND(ID_PRESET10, OnPreset10)
	ON_COMMAND(ID_PRESET11, OnPreset11)
	ON_COMMAND(ID_PRESET12, OnPreset12)
	ON_COMMAND(ID_EXIT, OnCancel)
	ON_COMMAND(ID_SEEKUP, OnSeekup)
	ON_COMMAND(ID_SEEKDOWN, OnSeekdown)
	ON_COMMAND(ID_PREFERENCES, OnSettings)
	ON_WM_LBUTTONDBLCLK()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CUSBRadioDlg message handlers

BOOL CUSBRadioDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hSmallIcon, FALSE);		// Set small icon
	
	//Store the handle of this window in the App class, used to override keystrokes
	((CUSBRadioApp*)AfxGetApp())->m_hwndDialog = m_hWnd;

	//Set the current window text
	SetWindowText(TITLE);

	//Set up the tooltips
	m_pToolTip = new CToolTipCtrl;
	m_pToolTip->Create(this);
	m_pToolTip->SetDelayTime(TTDT_INITIAL, 350);
	m_pToolTip->SetDelayTime(TTDT_RESHOW, 0);
	m_pToolTip->EnableToolTips(TRUE);
	
	//Load the bitmaps of character sets and display icons
	LoadBitmaps();

	//Center the window
	SetWindowPos(this, 0, 0, m_bmpBackgroundImage.GetBitmapDimension().cx, m_bmpBackgroundImage.GetBitmapDimension().cy, SWP_SHOWWINDOW);
	
	//Display all the bitmap butttons
	DisplayButtons();

	//Initialize the tray data structure
	m_TrayData.cbSize = sizeof(NOTIFYICONDATA);
	m_TrayData.hWnd  = this->m_hWnd;
	m_TrayData.uID = 1;
	m_TrayData.uCallbackMessage  = WM_TRAY_ICON_NOTIFY_MESSAGE;
	m_TrayData.hIcon = this->m_hSmallIcon;
	m_TrayData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
	strcpy(m_TrayData.szTip, TITLE);

	//Initialize the tray menu
	m_TrayMenu.LoadMenu(IDR_TRAYMENU);

	//Add to the tray
	Shell_NotifyIcon(NIM_ADD, &m_TrayData);
	
	//Inistialize state variables
	m_AlwaysOnTop = false;
	m_VolumeToggle = false;
	m_Muting = false;
	m_DownPoint = CPoint(-1, -1);
	m_KeyDown = 0x00;
	m_Scanning = false;
	m_ScanJustPressed = false;
	m_CurrentPreset.presetNum = 0;
	m_CurrentPreset.onPreset = false;

	m_MissedRDSCalls = 0;

	m_CurrentRDSDisplayIndex = 0;
	BYTE m_Status = 0;
	BYTE m_tmpRSSI = 0;
	BYTE m_tmpMonoStereo = 0;
	CString m_tmpRDSText = "";

	//Initialize the volume
	m_Volume = m_FMRadioDevice.GetWaveOutVolume();

	//Start the poll to find a device
	SetTimer(TIMER_FIND_DEVICE, 1, NULL);
			
	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CUSBRadioDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();

		DrawBackground();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CUSBRadioDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CUSBRadioDlg::OnTrayNotify(WPARAM wParam, LPARAM lParam)
{
	//When the tray is clicked do something
	if (wParam == 1)
	{
		CPoint pt;
		GetCursorPos(&pt);

		//On Double click, show the radio, and on single click, show the menu
		switch (lParam) 
		{ 
		case WM_LBUTTONDBLCLK	:	OnShowradio();	break;
		case WM_RBUTTONDOWN		:
		case WM_CONTEXTMENU		:	ShowTrayMenu(pt);	break;
		default					:	break;
		}
	}
}

void CUSBRadioDlg::OnShowradio()
{  
	//Show the window in the foreground and delete the tray icon
	ShowWindow(SW_SHOWDEFAULT);
	SetForegroundWindow();
	//Shell_NotifyIcon(NIM_DELETE, &m_TrayData);
}
  
void CUSBRadioDlg::ShowTrayMenu(CPoint pt)
{  
	//Popup the tray menu
	SetForegroundWindow();
	m_TrayMenu.GetSubMenu(0)->TrackPopupMenu(TPM_BOTTOMALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, pt.x, pt.y, this);    
}

void CUSBRadioDlg::DrawBackground()
{
	//Get the current DC and make a memory DC compatible containing the background image
	CDC *pDC = GetDC();
	CDC memDC;
	memDC.CreateCompatibleDC(pDC);
	CClientDC dc(this);

	//Draw the background image
	DrawBitmapOnDC(&memDC, &dc, &m_bmpBackgroundImage, 0, 0);
	
	//If streaming, then Draw the LED
	if (m_FMRadioDevice.IsStreaming())
		DrawLED(&memDC, &dc);
	
	//If we are not muting, show the volume slide
	if (!m_Muting)
		DrawVolumeSlide(&memDC, &dc);

	ReleaseDC(pDC);
}

void CUSBRadioDlg::DrawLED(CDC* memDC, CClientDC* dc)
{
	//If we are streaming
	if (m_FMRadioDevice.IsStreaming())
	{
		//Draw the station Text, mono/stereo status, RSSI state
		DrawStation(memDC, dc, m_RadioData.currentStation);
		DrawMonoStereo(memDC, dc, m_RDSData.monoStereo);
		DrawRSSI(memDC, dc, m_RDSData.recievedSignalStrength);
		DrawBitmapOnDC(memDC, dc, &m_bmpMHz, 355, 94);
		DrawRDS(memDC, dc, m_RDSData.rdsText);
	}
}

void CUSBRadioDlg::DrawRDS(CDC* memDC, CClientDC* dc, CString rdsText)
{
	//RDS is displayed scrolling if it doesnt fit in the GUI. This is determined
	//by checking the length, and keeping track of the scroll position. If the
	//current RDS display index is negative, then it will fit on the screen and the
	//offset from the left of the GUI is the absolute value of this display index.
	//Otherwise, the display index is 0 or above, and it is the current starting index
	//of the string. The rest of the string is diplayed as long as it fits, and if there
	//is extra room, it will wrap back to the beginning of the string.

	int i = 0;
	int x = RDS_X;
	CBitmap* pBmp = NULL;	
	bool filledDisplay = false;

	//If the current display index is negative, then make x the offset value, and i - 0, 
	//otherwise, leave x at the far left, and set i to the current display index
	if (m_CurrentRDSDisplayIndex < 0)
	{
		x = x - m_CurrentRDSDisplayIndex;
		i = 0;
	}
	else
	{
		i = m_CurrentRDSDisplayIndex;
	}
	
	//Loop while the display is not filled up
	while (!filledDisplay)
	{
		//Loop through the string starting at i (defined above) until the end of
		//the string is reached
		for (/*i assinged above*/; (i < rdsText.GetLength()) ; i++)
		{
			//Get the bitmap for the current character
			pBmp = GetAlphanumericSmallBitmap(rdsText[i]);

			//Ensure it is a valid bitmap
			if (pBmp) 
			{
				//If the bitmap will fit in the display region, draw it and increment
				//the x drawing position to the next position for a character. If
				//it doesn't fit, then set filledDisplay to true, and i to the end of the loop
				if ((x + pBmp->GetBitmapDimension().cx) < RDS_MAX_X)
				{
					DrawBitmapOnDC(memDC, dc, pBmp, x, RDS_Y);
					x = x + pBmp->GetBitmapDimension().cx;
				}
				else
				{
					filledDisplay = true;
					i = rdsText.GetLength();
				}
			}
		}

		//If the current display index is negative, then it fits so set filled display to true
		//since the display loop above finished
		if (m_CurrentRDSDisplayIndex < 0)
			filledDisplay = true;

		//If the display is not filled yet, then set i to 0 to wrap the text, then start displaying again
		if (!filledDisplay)
		{
			i = 0;
		}
	}
}

void CUSBRadioDlg::DrawStation(CDC* memDC, CClientDC* dc, double station)
{
	int x = STATION_X;
	CString stationString;
	stationString.Format("%0.2f", station);

	//Draw the station on the GUI from the x starting point
	for (int i = stationString.GetLength() - 1; i >= 0; i--)
	{
		CBitmap* pBmp = GetAlphanumericLargeBitmap(stationString[i]);

		if (pBmp)
		{
			x = x - pBmp->GetBitmapDimension().cx;
			DrawBitmapOnDC(memDC, dc, pBmp, x, STATION_Y);
		}
	}
}

void CUSBRadioDlg::DrawRSSI(CDC* memDC, CClientDC* dc, BYTE rssi)
{
	//Determine what the RSSI is, and then draw the bars on the radio
	CBitmap* pBmp;

	if ((rssi >= 11) && (rssi <= 20))
		pBmp = &m_bmpRSSI1;
	else if ((rssi >= 21) && (rssi <= 30))
		pBmp = &m_bmpRSSI2;
	else if ((rssi >= 31) && (rssi <= 40))
		pBmp = &m_bmpRSSI3;
	else if ((rssi >= 41) && (rssi <= 50))
		pBmp = &m_bmpRSSI4;
	else if ((rssi >= 51) && (rssi <= 255))
		pBmp = &m_bmpRSSI5;
	else
		pBmp = &m_bmpRSSI0;

	DrawBitmapOnDC(memDC, dc, pBmp, 99, 78);
}

void CUSBRadioDlg::DrawMonoStereo(CDC* memDC, CClientDC* dc, BYTE stereoMono)
{
	//Determine if the audio is in stereo or mono and display the correct image
	if (stereoMono)
		DrawBitmapOnDC(memDC, dc, &m_bmpStereo, 33, 77);
	else
		DrawBitmapOnDC(memDC, dc, &m_bmpMono, 33, 77);
}

void CUSBRadioDlg::DrawVolumeSlide(CDC* memDC, CClientDC* dc)
{
	//Determine the volume position and draw the slide on the GUI
	int x = (int)(((double)m_Volume / (double)VOLUME_MAX) * (double)(VOLUME_MAX_X - VOLUME_MIN_X)) + VOLUME_MIN_X;
	x = x - (m_bmpVolumeSlide.GetBitmapDimension().cx / 2);

	DrawBitmapOnDC(memDC, dc, &m_bmpVolumeSlide, x, 157, TRANSPARENT_COLOR);
}

void CUSBRadioDlg::DrawBitmapOnDC(CDC* memDC, CClientDC* cDC, CBitmap* bmp, int x, int y)
{
	//Select the bitmap, and draw it at point x and y with it's current size
	memDC->SelectObject(*bmp);
	cDC->BitBlt(x, y, bmp->GetBitmapDimension().cx, bmp->GetBitmapDimension().cy, memDC, 0, 0, SRCCOPY);
}

void CUSBRadioDlg::DrawBitmapOnDC(CDC* memDC, CClientDC* cDC, CBitmap* bmp, int x, int y, UINT transparentColor)
{
	//Select the bitmap, and draw it at point x and y with it's current size
	memDC->SelectObject(*bmp);
	TransparentBlt(cDC->m_hDC, x, y, bmp->GetBitmapDimension().cx, bmp->GetBitmapDimension().cy, memDC->m_hDC, 0, 0, bmp->GetBitmapDimension().cx, bmp->GetBitmapDimension().cy, transparentColor);
}

void CUSBRadioDlg::UpdateRadioLED()
{
	CDC *pDC = GetDC();
	CDC memDC;
	memDC.CreateCompatibleDC(pDC);
	CClientDC dc(this);

	InvalidateRect(CRect(CPoint(18, 58), CPoint(537, 141)), FALSE);
	UpdateWindow();
	DrawLED(&memDC, &dc);

	ReleaseDC(pDC);
}

void CUSBRadioDlg::UpdateStationLED()
{
	CDC *pDC = GetDC();
	CDC memDC;
	memDC.CreateCompatibleDC(pDC);
	CClientDC dc(this);

	InvalidateRect(CRect(CPoint(165, 68), CPoint(353, 105)), FALSE);
	UpdateWindow();
	DrawStation(&memDC, &dc, m_RadioData.currentStation);

	ReleaseDC(pDC);
}

void CUSBRadioDlg::UpdateRSSILED()
{
	CDC *pDC = GetDC();
	CDC memDC;
	memDC.CreateCompatibleDC(pDC);
	CClientDC dc(this);

	InvalidateRect(CRect(CPoint(97, 75), CPoint(165, 108)), FALSE);
	UpdateWindow();
	DrawRSSI(&memDC, &dc, m_RDSData.recievedSignalStrength);

	ReleaseDC(pDC);
}

void CUSBRadioDlg::UpdateMonoStereoLED()
{
	CDC *pDC = GetDC();
	CDC memDC;
	memDC.CreateCompatibleDC(pDC);
	CClientDC dc(this);

	InvalidateRect(CRect(CPoint(30, 75), CPoint(165, 108)), FALSE);
	UpdateWindow();
	DrawMonoStereo(&memDC, &dc, m_RDSData.monoStereo);

	ReleaseDC(pDC);
}

void CUSBRadioDlg::UpdateRDSDisplay()
{
	CDC *pDC = GetDC();
	CDC memDC;
	memDC.CreateCompatibleDC(pDC);
	CClientDC dc(this);

	InvalidateRect(CRect(CPoint(29, 118), CPoint(540, 134)), FALSE);
	UpdateWindow();
	DrawRDS(&memDC, &dc, m_RDSData.rdsText);

	ReleaseDC(pDC);
}

void CUSBRadioDlg::UpdateStationToolTips(bool enableTips)
{	
	//If tips are being enabled, then get all the presets, and store them in the tooltips
	//Otherwise reset the tooltips to the generic strings
	if (enableTips)
	{
		CString stationString;

		stationString.Format("%0.2f", m_RadioData.preset[0]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET1));
		m_TrayMenu.ModifyMenu(ID_PRESET1, MF_BYCOMMAND | MF_STRING, ID_PRESET1, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[1]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET2));
		m_TrayMenu.ModifyMenu(ID_PRESET2, MF_BYCOMMAND | MF_STRING, ID_PRESET2, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[2]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET3));
		m_TrayMenu.ModifyMenu(ID_PRESET3, MF_BYCOMMAND | MF_STRING, ID_PRESET3, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[3]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET4));
		m_TrayMenu.ModifyMenu(ID_PRESET4, MF_BYCOMMAND | MF_STRING, ID_PRESET4, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[4]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET5));
		m_TrayMenu.ModifyMenu(ID_PRESET5, MF_BYCOMMAND | MF_STRING, ID_PRESET5, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[5]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET6));
		m_TrayMenu.ModifyMenu(ID_PRESET6, MF_BYCOMMAND | MF_STRING, ID_PRESET6, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[6]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET7));
		m_TrayMenu.ModifyMenu(ID_PRESET7, MF_BYCOMMAND | MF_STRING, ID_PRESET7, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[7]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET8));
		m_TrayMenu.ModifyMenu(ID_PRESET8, MF_BYCOMMAND | MF_STRING, ID_PRESET8, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[8]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET9));
		m_TrayMenu.ModifyMenu(ID_PRESET9, MF_BYCOMMAND | MF_STRING, ID_PRESET9, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[9]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET10));
		m_TrayMenu.ModifyMenu(ID_PRESET10, MF_BYCOMMAND | MF_STRING, ID_PRESET10, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[10]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET11));
		m_TrayMenu.ModifyMenu(ID_PRESET11, MF_BYCOMMAND | MF_STRING, ID_PRESET11, stationString);
		stationString.Format("%0.2f", m_RadioData.preset[11]);
		m_pToolTip->UpdateTipText(stationString, (CWnd*)GetDlgItem(IDC_BUTTON_PRESET12));
		m_TrayMenu.ModifyMenu(ID_PRESET12, MF_BYCOMMAND | MF_STRING, ID_PRESET12, stationString);
	}
	else
	{
		m_pToolTip->UpdateTipText("1", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET1));
		m_TrayMenu.ModifyMenu(ID_PRESET1, MF_BYCOMMAND | MF_STRING, ID_PRESET1, "Preset 1");
		m_pToolTip->UpdateTipText("2", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET2));
		m_TrayMenu.ModifyMenu(ID_PRESET2, MF_BYCOMMAND | MF_STRING, ID_PRESET2, "Preset 2");
		m_pToolTip->UpdateTipText("3", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET3));
		m_TrayMenu.ModifyMenu(ID_PRESET3, MF_BYCOMMAND | MF_STRING, ID_PRESET3, "Preset 3");
		m_pToolTip->UpdateTipText("4", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET4));
		m_TrayMenu.ModifyMenu(ID_PRESET4, MF_BYCOMMAND | MF_STRING, ID_PRESET4, "Preset 4");
		m_pToolTip->UpdateTipText("5", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET5));
		m_TrayMenu.ModifyMenu(ID_PRESET5, MF_BYCOMMAND | MF_STRING, ID_PRESET5, "Preset 5");
		m_pToolTip->UpdateTipText("6", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET6));
		m_TrayMenu.ModifyMenu(ID_PRESET6, MF_BYCOMMAND | MF_STRING, ID_PRESET6, "Preset 6");
		m_pToolTip->UpdateTipText("7", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET7));
		m_TrayMenu.ModifyMenu(ID_PRESET7, MF_BYCOMMAND | MF_STRING, ID_PRESET7, "Preset 7");
		m_pToolTip->UpdateTipText("8", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET8));
		m_TrayMenu.ModifyMenu(ID_PRESET8, MF_BYCOMMAND | MF_STRING, ID_PRESET8, "Preset 8");
		m_pToolTip->UpdateTipText("9", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET9));
		m_TrayMenu.ModifyMenu(ID_PRESET9, MF_BYCOMMAND | MF_STRING, ID_PRESET9, "Preset 9");
		m_pToolTip->UpdateTipText("10", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET10));
		m_TrayMenu.ModifyMenu(ID_PRESET10, MF_BYCOMMAND | MF_STRING, ID_PRESET10, "Preset 10");
		m_pToolTip->UpdateTipText("11", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET11));
		m_TrayMenu.ModifyMenu(ID_PRESET11, MF_BYCOMMAND | MF_STRING, ID_PRESET11, "Preset 11");
		m_pToolTip->UpdateTipText("12", (CWnd*)GetDlgItem(IDC_BUTTON_PRESET12));
		m_TrayMenu.ModifyMenu(ID_PRESET12, MF_BYCOMMAND | MF_STRING, ID_PRESET12, "Preset 12");
	}
}

CBitmap* CUSBRadioDlg::GetAlphanumericLargeBitmap(char c)
{
	CBitmap* pBmp = NULL;

	switch (toupper(c))
	{
	case '0'	:	pBmp = &m_bmp0Large;	break;
	case '1'	:	pBmp = &m_bmp1Large;	break;
	case '2'	:	pBmp = &m_bmp2Large;	break;
	case '3'	:	pBmp = &m_bmp3Large;	break;
	case '4'	:	pBmp = &m_bmp4Large;	break;
	case '5'	:	pBmp = &m_bmp5Large;	break;
	case '6'	:	pBmp = &m_bmp6Large;	break;
	case '7'	:	pBmp = &m_bmp7Large;	break;
	case '8'	:	pBmp = &m_bmp8Large;	break;
	case '9'	:	pBmp = &m_bmp9Large;	break;
	case 'A'	:	pBmp = &m_bmpALarge;	break;
	case 'B'	:	pBmp = &m_bmpBLarge;	break;
	case 'C'	:	pBmp = &m_bmpCLarge;	break;
	case 'D'	:	pBmp = &m_bmpDLarge;	break;
	case 'E'	:	pBmp = &m_bmpELarge;	break;
	case 'F'	:	pBmp = &m_bmpFLarge;	break;
	case 'G'	:	pBmp = &m_bmpGLarge;	break;
	case 'H'	:	pBmp = &m_bmpHLarge;	break;
	case 'I'	:	pBmp = &m_bmpILarge;	break;
	case 'J'	:	pBmp = &m_bmpJLarge;	break;
	case 'K'	:	pBmp = &m_bmpKLarge;	break;
	case 'L'	:	pBmp = &m_bmpLLarge;	break;
	case 'M'	:	pBmp = &m_bmpMLarge;	break;
	case 'N'	:	pBmp = &m_bmpNLarge;	break;
	case 'O'	:	pBmp = &m_bmpOLarge;	break;
	case 'P'	:	pBmp = &m_bmpPLarge;	break;
	case 'Q'	:	pBmp = &m_bmpQLarge;	break;
	case 'R'	:	pBmp = &m_bmpRLarge;	break;
	case 'S'	:	pBmp = &m_bmpSLarge;	break;
	case 'T'	:	pBmp = &m_bmpTLarge;	break;
	case 'U'	:	pBmp = &m_bmpULarge;	break;
	case 'V'	:	pBmp = &m_bmpVLarge;	break;
	case 'W'	:	pBmp = &m_bmpWLarge;	break;
	case 'X'	:	pBmp = &m_bmpXLarge;	break;
	case 'Y'	:	pBmp = &m_bmpYLarge;	break;
	case 'Z'	:	pBmp = &m_bmpZLarge;	break;
	case '.'	:	pBmp = &m_bmpDotLarge;	break;
	default		:	pBmp = &m_bmpSpaceLarge;	break;
	}

	return pBmp;
}

CBitmap* CUSBRadioDlg::GetAlphanumericSmallBitmap(char c)
{
	CBitmap* pBmp = NULL;

	switch (toupper(c))
	{
	case '0'	:	pBmp = &m_bmp0Small;	break;
	case '1'	:	pBmp = &m_bmp1Small;	break;
	case '2'	:	pBmp = &m_bmp2Small;	break;
	case '3'	:	pBmp = &m_bmp3Small;	break;
	case '4'	:	pBmp = &m_bmp4Small;	break;
	case '5'	:	pBmp = &m_bmp5Small;	break;
	case '6'	:	pBmp = &m_bmp6Small;	break;
	case '7'	:	pBmp = &m_bmp7Small;	break;
	case '8'	:	pBmp = &m_bmp8Small;	break;
	case '9'	:	pBmp = &m_bmp9Small;	break;
	case 'A'	:	pBmp = &m_bmpASmall;	break;
	case 'B'	:	pBmp = &m_bmpBSmall;	break;
	case 'C'	:	pBmp = &m_bmpCSmall;	break;
	case 'D'	:	pBmp = &m_bmpDSmall;	break;
	case 'E'	:	pBmp = &m_bmpESmall;	break;
	case 'F'	:	pBmp = &m_bmpFSmall;	break;
	case 'G'	:	pBmp = &m_bmpGSmall;	break;
	case 'H'	:	pBmp = &m_bmpHSmall;	break;
	case 'I'	:	pBmp = &m_bmpISmall;	break;
	case 'J'	:	pBmp = &m_bmpJSmall;	break;
	case 'K'	:	pBmp = &m_bmpKSmall;	break;
	case 'L'	:	pBmp = &m_bmpLSmall;	break;
	case 'M'	:	pBmp = &m_bmpMSmall;	break;
	case 'N'	:	pBmp = &m_bmpNSmall;	break;
	case 'O'	:	pBmp = &m_bmpOSmall;	break;
	case 'P'	:	pBmp = &m_bmpPSmall;	break;
	case 'Q'	:	pBmp = &m_bmpQSmall;	break;
	case 'R'	:	pBmp = &m_bmpRSmall;	break;
	case 'S'	:	pBmp = &m_bmpSSmall;	break;
	case 'T'	:	pBmp = &m_bmpTSmall;	break;
	case 'U'	:	pBmp = &m_bmpUSmall;	break;
	case 'V'	:	pBmp = &m_bmpVSmall;	break;
	case 'W'	:	pBmp = &m_bmpWSmall;	break;
	case 'X'	:	pBmp = &m_bmpXSmall;	break;
	case 'Y'	:	pBmp = &m_bmpYSmall;	break;
	case 'Z'	:	pBmp = &m_bmpZSmall;	break;
	case '.'	:	pBmp = &m_bmpDotSmall;	break;
	case '-'	:	pBmp = &m_bmpDashSmall;	break;
	case ','	:	pBmp = &m_bmpCommaSmall;		break;
	case '\''	:	pBmp = &m_bmpApostropheSmall;	break;
	case '!'	:	pBmp = &m_bmpExclamationSmall;	break;
	case '&'	:	pBmp = &m_bmpAmpersandSmall;	break;
	case ' '	:	pBmp = &m_bmpSpaceSmall;		break;
	default		:	pBmp = &m_bmpSpaceSmall;		break;
	}

	return pBmp;
}

void CUSBRadioDlg::DisplayButtons()
{
	//Create each button for the GUI
	CreateBitmapButton(&m_Minimize, 511, 6, IDB_BITMAP_MINIMIZE_UP, IDB_BITMAP_MINIMIZE_DOWN, IDC_BUTTON_MINIMIZE, "Minimize");
	CreateBitmapButton(&m_Restore, 526, 6, IDB_BITMAP_RESTORE_UP, IDB_BITMAP_RESTORE_DOWN, IDC_BUTTON_RESTORE, "Window Shade Toggle");
	CreateBitmapButton(&m_Close, 541, 6, IDB_BITMAP_CLOSE_UP, IDB_BITMAP_CLOSE_DOWN, IDC_BUTTON_CLOSE, "Close");
	CreateBitmapButton(&m_PresetScanDown, 30, 31, IDB_BITMAP_PRESETSCANDOWN_UP, IDB_BITMAP_PRESETSCANDOWN_DOWN, IDC_BUTTON_PRESETSCANDOWN, "Scan Presets Down");
	CreateBitmapButton(&m_PresetScanUp, 511, 31, IDB_BITMAP_PRESETSCANUP_UP, IDB_BITMAP_PRESETSCANUP_DOWN, IDC_BUTTON_PRESETSCANUP, "Scan Presets Up");
	CreateBitmapButton(&m_PresetScanUpDown, 511, 31, IDB_BITMAP_PRESETSCANUP_DOWN, IDB_BITMAP_PRESETSCANUP_UP, IDC_BUTTON_PRESETSCANUP_DOWN, "Stop Scanning Presets Up");
	CreateBitmapButton(&m_PresetScanDownDown, 30, 31, IDB_BITMAP_PRESETSCANDOWN_DOWN, IDB_BITMAP_PRESETSCANDOWN_UP, IDC_BUTTON_PRESETSCANDOWN_DOWN, "Stop Scanning Presets Down");
	CreateBitmapButton(&m_Preset1, 67, 31, IDB_BITMAP_PRESET1_UP, IDB_BITMAP_PRESET1_DOWN, IDC_BUTTON_PRESET1, "1");
	CreateBitmapButton(&m_Preset2, 104, 31, IDB_BITMAP_PRESET2_UP, IDB_BITMAP_PRESET2_DOWN, IDC_BUTTON_PRESET2, "2");
	CreateBitmapButton(&m_Preset3, 141, 31, IDB_BITMAP_PRESET3_UP, IDB_BITMAP_PRESET3_DOWN, IDC_BUTTON_PRESET3, "3");
	CreateBitmapButton(&m_Preset4, 178, 31, IDB_BITMAP_PRESET4_UP, IDB_BITMAP_PRESET4_DOWN, IDC_BUTTON_PRESET4, "4");
	CreateBitmapButton(&m_Preset5, 215, 31, IDB_BITMAP_PRESET5_UP, IDB_BITMAP_PRESET5_DOWN, IDC_BUTTON_PRESET5, "5");
	CreateBitmapButton(&m_Preset6, 252, 31, IDB_BITMAP_PRESET6_UP, IDB_BITMAP_PRESET6_DOWN, IDC_BUTTON_PRESET6, "6");
	CreateBitmapButton(&m_Preset7, 289, 31, IDB_BITMAP_PRESET7_UP, IDB_BITMAP_PRESET7_DOWN, IDC_BUTTON_PRESET7, "7");
	CreateBitmapButton(&m_Preset8, 326, 31, IDB_BITMAP_PRESET8_UP, IDB_BITMAP_PRESET8_DOWN, IDC_BUTTON_PRESET8, "8");
	CreateBitmapButton(&m_Preset9, 363, 31, IDB_BITMAP_PRESET9_UP, IDB_BITMAP_PRESET9_DOWN, IDC_BUTTON_PRESET9, "9");
	CreateBitmapButton(&m_Preset10, 400, 31, IDB_BITMAP_PRESET10_UP, IDB_BITMAP_PRESET10_DOWN, IDC_BUTTON_PRESET10, "10");
	CreateBitmapButton(&m_Preset11, 437, 31, IDB_BITMAP_PRESET11_UP, IDB_BITMAP_PRESET11_DOWN, IDC_BUTTON_PRESET11, "11");
	CreateBitmapButton(&m_Preset12, 474, 31, IDB_BITMAP_PRESET12_UP, IDB_BITMAP_PRESET12_DOWN, IDC_BUTTON_PRESET12, "12");
	CreateBitmapButton(&m_Mute, 328, 158, IDB_BITMAP_MUTE_UP, IDB_BITMAP_MUTE_DOWN, IDC_BUTTON_MUTE, "Mute");
	CreateBitmapButton(&m_MuteDown, 328, 158, IDB_BITMAP_MUTE_DOWN, IDB_BITMAP_MUTE_UP, IDC_BUTTON_MUTE_DOWN, "Unmute");
	CreateBitmapButton(&m_TuneDown, 128, 152, IDB_BITMAP_TUNEDOWN_UP, IDB_BITMAP_TUNEDOWN_DOWN, IDC_BUTTON_TUNEDOWN, "Tune Down");
	CreateBitmapButton(&m_TuneUp, 192, 152, IDB_BITMAP_TUNEUP_UP, IDB_BITMAP_TUNEUP_DOWN, IDC_BUTTON_TUNEUP, "Tune Up");
	CreateBitmapButton(&m_ScanDown, 64, 152, IDB_BITMAP_SCANDOWN_UP, IDB_BITMAP_SCANDOWN_DOWN, IDC_BUTTON_SCANDOWN, "Seek/Scan Down, (Hold down 3 seconds to scan)");
	CreateBitmapButton(&m_ScanUp, 256, 152, IDB_BITMAP_SCANUP_UP, IDB_BITMAP_SCANUP_DOWN, IDC_BUTTON_SCANUP, "Seek/Scan Up, (Hold down 3 seconds to scan)");
	CreateBitmapButton(&m_ScanDownDown, 64, 152, IDB_BITMAP_SCANDOWN_DOWN, IDB_BITMAP_SCANDOWN_UP, IDC_BUTTON_SCANDOWN_DOWN, "Stop Scan Up");
	CreateBitmapButton(&m_ScanUpDown, 256, 152, IDB_BITMAP_SCANUP_DOWN, IDB_BITMAP_SCANUP_UP, IDC_BUTTON_SCANUP_DOWN, "Stop Scan Down");
	CreateBitmapButton(&m_Settings, 464, 155, IDB_BITMAP_SETTINGS_UP, IDB_BITMAP_SETTINGS_DOWN, IDC_BUTTON_SETTINGS, "Settings");
	CreateBitmapButton(&m_StereoMono, 20, 154, IDB_BITMAP_STEREOMONO_UP, IDB_BITMAP_STEREOMONO_DOWN, IDC_BUTTON_STEREOMONO, "Stereo/Mono Select");
	CreateBitmapButton(&m_StereoMonoDown, 20, 154, IDB_BITMAP_STEREOMONO_DOWN, IDB_BITMAP_STEREOMONO_UP, IDC_BUTTON_STEREOMONO_DOWN, "Stereo/Mono Select");
	CreateBitmapButton(&m_FMTunerLink, 218, 194, IDB_BITMAP_FMTUNERLINK_UP, IDB_BITMAP_FMTUNERLINK_DOWN, IDC_BUTTON_FMTUNERLINK, "FM Tuner Link");
	CreateBitmapButton(&m_USBMCULink, 409, 194, IDB_BITMAP_USBMCULINK_UP, IDB_BITMAP_USBMCULINK_DOWN, IDC_BUTTON_USBMCULINK, "USB MCU Link");
	CreateBitmapButton(&m_SilabsLink, 17, 194, IDB_BITMAP_SILABSLINK_UP, IDB_BITMAP_SILABSLINK_DOWN, IDC_BUTTON_SILABSLINK, "Silicon Laboratories Link");

	GetDlgItem(IDC_BUTTON_PRESETSCANUP_DOWN)->ShowWindow(FALSE);
	GetDlgItem(IDC_BUTTON_PRESETSCANDOWN_DOWN)->ShowWindow(FALSE);
	GetDlgItem(IDC_BUTTON_SCANUP_DOWN)->ShowWindow(FALSE);
	GetDlgItem(IDC_BUTTON_SCANDOWN_DOWN)->ShowWindow(FALSE);
	GetDlgItem(IDC_BUTTON_MUTE_DOWN)->ShowWindow(FALSE);
	GetDlgItem(IDC_BUTTON_STEREOMONO_DOWN)->ShowWindow(FALSE);
}

void CUSBRadioDlg::CreateBitmapButton(CBitmapButton* bitmapButton, int left, int top, UINT upResource, UINT downresource, UINT buttonResource, CString toolTipText)
{
	//Creates a new BitmapButton
	bitmapButton = new CBitmapButton;

	//Creates a button at the point desired (left, top)
	bitmapButton->Create(NULL, WS_CHILD | WS_VISIBLE | BS_OWNERDRAW | BS_NOTIFY, CRect(left, top, left, top), this, buttonResource);

	//Loads the up/down bitmaps for the button (disabled and focus not defined)
	bitmapButton->LoadBitmaps(upResource, downresource/*, 0, 0*/);

	//Since we specified a point, size the buttons to the bitmap image
	bitmapButton->SizeToContent();

	//Add specified tooltip text to the button
	m_pToolTip->AddTool((CWnd*)GetDlgItem(buttonResource), toolTipText);

	//Enable the buttons tooltips
	bitmapButton->EnableToolTips(TRUE);
}

void CUSBRadioDlg::LoadBitmaps()
{
	LoadBitmapAndCoordinates(&m_bmpBackgroundImage, IDB_BITMAP_BACKGROUND);
	LoadBitmapAndCoordinates(&m_bmpMHz, IDB_BITMAP_MHZ);
	LoadBitmapAndCoordinates(&m_bmpDotLarge, IDB_BITMAP_DOT_LARGE);
	LoadBitmapAndCoordinates(&m_bmpSpaceLarge, IDB_BITMAP_SPACE_LARGE);
	LoadBitmapAndCoordinates(&m_bmp0Large, IDB_BITMAP_0_LARGE);
	LoadBitmapAndCoordinates(&m_bmp1Large, IDB_BITMAP_1_LARGE);
	LoadBitmapAndCoordinates(&m_bmp2Large, IDB_BITMAP_2_LARGE);
	LoadBitmapAndCoordinates(&m_bmp3Large, IDB_BITMAP_3_LARGE);
	LoadBitmapAndCoordinates(&m_bmp4Large, IDB_BITMAP_4_LARGE);
	LoadBitmapAndCoordinates(&m_bmp5Large, IDB_BITMAP_5_LARGE);
	LoadBitmapAndCoordinates(&m_bmp6Large, IDB_BITMAP_6_LARGE);
	LoadBitmapAndCoordinates(&m_bmp7Large, IDB_BITMAP_7_LARGE);
	LoadBitmapAndCoordinates(&m_bmp8Large, IDB_BITMAP_8_LARGE);
	LoadBitmapAndCoordinates(&m_bmp9Large, IDB_BITMAP_9_LARGE);
	LoadBitmapAndCoordinates(&m_bmpALarge, IDB_BITMAP_A_LARGE);
	LoadBitmapAndCoordinates(&m_bmpBLarge, IDB_BITMAP_B_LARGE);
	LoadBitmapAndCoordinates(&m_bmpCLarge, IDB_BITMAP_C_LARGE);
	LoadBitmapAndCoordinates(&m_bmpDLarge, IDB_BITMAP_D_LARGE);
	LoadBitmapAndCoordinates(&m_bmpELarge, IDB_BITMAP_E_LARGE);
	LoadBitmapAndCoordinates(&m_bmpFLarge, IDB_BITMAP_F_LARGE);
	LoadBitmapAndCoordinates(&m_bmpGLarge, IDB_BITMAP_G_LARGE);
	LoadBitmapAndCoordinates(&m_bmpHLarge, IDB_BITMAP_H_LARGE);
	LoadBitmapAndCoordinates(&m_bmpILarge, IDB_BITMAP_I_LARGE);
	LoadBitmapAndCoordinates(&m_bmpJLarge, IDB_BITMAP_J_LARGE);
	LoadBitmapAndCoordinates(&m_bmpKLarge, IDB_BITMAP_K_LARGE);
	LoadBitmapAndCoordinates(&m_bmpLLarge, IDB_BITMAP_L_LARGE);
	LoadBitmapAndCoordinates(&m_bmpMLarge, IDB_BITMAP_M_LARGE);
	LoadBitmapAndCoordinates(&m_bmpNLarge, IDB_BITMAP_N_LARGE);
	LoadBitmapAndCoordinates(&m_bmpOLarge, IDB_BITMAP_O_LARGE);
	LoadBitmapAndCoordinates(&m_bmpPLarge, IDB_BITMAP_P_LARGE);
	LoadBitmapAndCoordinates(&m_bmpQLarge, IDB_BITMAP_Q_LARGE);
	LoadBitmapAndCoordinates(&m_bmpRLarge, IDB_BITMAP_R_LARGE);
	LoadBitmapAndCoordinates(&m_bmpSLarge, IDB_BITMAP_S_LARGE);
	LoadBitmapAndCoordinates(&m_bmpTLarge, IDB_BITMAP_T_LARGE);
	LoadBitmapAndCoordinates(&m_bmpULarge, IDB_BITMAP_U_LARGE);
	LoadBitmapAndCoordinates(&m_bmpVLarge, IDB_BITMAP_V_LARGE);
	LoadBitmapAndCoordinates(&m_bmpWLarge, IDB_BITMAP_W_LARGE);
	LoadBitmapAndCoordinates(&m_bmpXLarge, IDB_BITMAP_X_LARGE);
	LoadBitmapAndCoordinates(&m_bmpYLarge, IDB_BITMAP_Y_LARGE);
	LoadBitmapAndCoordinates(&m_bmpZLarge, IDB_BITMAP_Z_LARGE);
	LoadBitmapAndCoordinates(&m_bmpDotSmall, IDB_BITMAP_DOT_SMALL);
	LoadBitmapAndCoordinates(&m_bmpDashSmall, IDB_BITMAP_DASH_SMALL);
	LoadBitmapAndCoordinates(&m_bmpApostropheSmall, IDB_BITMAP_APOSTROPHE_SMALL);
	LoadBitmapAndCoordinates(&m_bmpExclamationSmall, IDB_BITMAP_EXCLAMATION_SMALL);
	LoadBitmapAndCoordinates(&m_bmpAmpersandSmall, IDB_BITMAP_AMPERSAND_SMALL);
	LoadBitmapAndCoordinates(&m_bmpCommaSmall, IDB_BITMAP_COMMA_SMALL);
	LoadBitmapAndCoordinates(&m_bmpSpaceSmall, IDB_BITMAP_SPACE_SMALL);
	LoadBitmapAndCoordinates(&m_bmp0Small, IDB_BITMAP_0_SMALL);
	LoadBitmapAndCoordinates(&m_bmp1Small, IDB_BITMAP_1_SMALL);
	LoadBitmapAndCoordinates(&m_bmp2Small, IDB_BITMAP_2_SMALL);
	LoadBitmapAndCoordinates(&m_bmp3Small, IDB_BITMAP_3_SMALL);
	LoadBitmapAndCoordinates(&m_bmp4Small, IDB_BITMAP_4_SMALL);
	LoadBitmapAndCoordinates(&m_bmp5Small, IDB_BITMAP_5_SMALL);
	LoadBitmapAndCoordinates(&m_bmp6Small, IDB_BITMAP_6_SMALL);
	LoadBitmapAndCoordinates(&m_bmp7Small, IDB_BITMAP_7_SMALL);
	LoadBitmapAndCoordinates(&m_bmp8Small, IDB_BITMAP_8_SMALL);
	LoadBitmapAndCoordinates(&m_bmp9Small, IDB_BITMAP_9_SMALL);
	LoadBitmapAndCoordinates(&m_bmpASmall, IDB_BITMAP_A_SMALL);
	LoadBitmapAndCoordinates(&m_bmpBSmall, IDB_BITMAP_B_SMALL);
	LoadBitmapAndCoordinates(&m_bmpCSmall, IDB_BITMAP_C_SMALL);
	LoadBitmapAndCoordinates(&m_bmpDSmall, IDB_BITMAP_D_SMALL);
	LoadBitmapAndCoordinates(&m_bmpESmall, IDB_BITMAP_E_SMALL);
	LoadBitmapAndCoordinates(&m_bmpFSmall, IDB_BITMAP_F_SMALL);
	LoadBitmapAndCoordinates(&m_bmpGSmall, IDB_BITMAP_G_SMALL);
	LoadBitmapAndCoordinates(&m_bmpHSmall, IDB_BITMAP_H_SMALL);
	LoadBitmapAndCoordinates(&m_bmpISmall, IDB_BITMAP_I_SMALL);
	LoadBitmapAndCoordinates(&m_bmpJSmall, IDB_BITMAP_J_SMALL);
	LoadBitmapAndCoordinates(&m_bmpKSmall, IDB_BITMAP_K_SMALL);
	LoadBitmapAndCoordinates(&m_bmpLSmall, IDB_BITMAP_L_SMALL);
	LoadBitmapAndCoordinates(&m_bmpMSmall, IDB_BITMAP_M_SMALL);
	LoadBitmapAndCoordinates(&m_bmpNSmall, IDB_BITMAP_N_SMALL);
	LoadBitmapAndCoordinates(&m_bmpOSmall, IDB_BITMAP_O_SMALL);
	LoadBitmapAndCoordinates(&m_bmpPSmall, IDB_BITMAP_P_SMALL);
	LoadBitmapAndCoordinates(&m_bmpQSmall, IDB_BITMAP_Q_SMALL);
	LoadBitmapAndCoordinates(&m_bmpRSmall, IDB_BITMAP_R_SMALL);
	LoadBitmapAndCoordinates(&m_bmpSSmall, IDB_BITMAP_S_SMALL);
	LoadBitmapAndCoordinates(&m_bmpTSmall, IDB_BITMAP_T_SMALL);
	LoadBitmapAndCoordinates(&m_bmpUSmall, IDB_BITMAP_U_SMALL);
	LoadBitmapAndCoordinates(&m_bmpVSmall, IDB_BITMAP_V_SMALL);
	LoadBitmapAndCoordinates(&m_bmpWSmall, IDB_BITMAP_W_SMALL);
	LoadBitmapAndCoordinates(&m_bmpXSmall, IDB_BITMAP_X_SMALL);
	LoadBitmapAndCoordinates(&m_bmpYSmall, IDB_BITMAP_Y_SMALL);
	LoadBitmapAndCoordinates(&m_bmpZSmall, IDB_BITMAP_Z_SMALL);
	LoadBitmapAndCoordinates(&m_bmpRSSI0, IDB_BITMAP_RSSI0);
	LoadBitmapAndCoordinates(&m_bmpRSSI1, IDB_BITMAP_RSSI1);
	LoadBitmapAndCoordinates(&m_bmpRSSI2, IDB_BITMAP_RSSI2);
	LoadBitmapAndCoordinates(&m_bmpRSSI3, IDB_BITMAP_RSSI3);
	LoadBitmapAndCoordinates(&m_bmpRSSI4, IDB_BITMAP_RSSI4);
	LoadBitmapAndCoordinates(&m_bmpRSSI5, IDB_BITMAP_RSSI5);
	LoadBitmapAndCoordinates(&m_bmpMono, IDB_BITMAP_MONO);
	LoadBitmapAndCoordinates(&m_bmpStereo, IDB_BITMAP_STEREO);
	LoadBitmapAndCoordinates(&m_bmpVolumeSlide, IDB_BITMAP_VOLUMESLIDE);
}

void CUSBRadioDlg::LoadBitmapAndCoordinates(CBitmap* bmp, UINT resourceID)
{
	BITMAP bitmap;
	
	bmp->LoadBitmap(resourceID);
	bmp->GetBitmap(&bitmap);
	bmp->SetBitmapDimension(bitmap.bmWidth, bitmap.bmHeight);
}

void CUSBRadioDlg::RemoveButtons()
{
	delete GetDlgItem(IDC_BUTTON_MINIMIZE);
	delete GetDlgItem(IDC_BUTTON_RESTORE);
	delete GetDlgItem(IDC_BUTTON_CLOSE);
	delete GetDlgItem(IDC_BUTTON_PRESETSCANDOWN);
	delete GetDlgItem(IDC_BUTTON_PRESETSCANUP);
	delete GetDlgItem(IDC_BUTTON_PRESETSCANDOWN_DOWN);
	delete GetDlgItem(IDC_BUTTON_PRESETSCANUP_DOWN);
	delete GetDlgItem(IDC_BUTTON_PRESET1);
	delete GetDlgItem(IDC_BUTTON_PRESET2);
	delete GetDlgItem(IDC_BUTTON_PRESET3);
	delete GetDlgItem(IDC_BUTTON_PRESET4);
	delete GetDlgItem(IDC_BUTTON_PRESET5);
	delete GetDlgItem(IDC_BUTTON_PRESET6);
	delete GetDlgItem(IDC_BUTTON_PRESET7);
	delete GetDlgItem(IDC_BUTTON_PRESET8);
	delete GetDlgItem(IDC_BUTTON_PRESET9);
	delete GetDlgItem(IDC_BUTTON_PRESET10);
	delete GetDlgItem(IDC_BUTTON_PRESET11);
	delete GetDlgItem(IDC_BUTTON_PRESET12);
	delete GetDlgItem(IDC_BUTTON_MUTE);
	delete GetDlgItem(IDC_BUTTON_MUTE_DOWN);
	delete GetDlgItem(IDC_BUTTON_TUNEDOWN);
	delete GetDlgItem(IDC_BUTTON_TUNEUP);
	delete GetDlgItem(IDC_BUTTON_SCANDOWN);
	delete GetDlgItem(IDC_BUTTON_SCANUP);
	delete GetDlgItem(IDC_BUTTON_SCANDOWN_DOWN);
	delete GetDlgItem(IDC_BUTTON_SCANUP_DOWN);
	delete GetDlgItem(IDC_BUTTON_SETTINGS);
	delete GetDlgItem(IDC_BUTTON_STEREOMONO);
	delete GetDlgItem(IDC_BUTTON_STEREOMONO_DOWN);
	delete GetDlgItem(IDC_BUTTON_FMTUNERLINK);
	delete GetDlgItem(IDC_BUTTON_USBMCULINK);
	delete GetDlgItem(IDC_BUTTON_SILABSLINK);
}

void CUSBRadioDlg::KeyUp(BYTE key) 
{
	//Determine which key came up and handle it
	switch (key)
	{
	case KEY_F1		:	OnPreset1();	break;
	case KEY_F2		:	OnPreset2();	break;
	case KEY_F3		:	OnPreset3();	break;
	case KEY_F4		:	OnPreset4();	break;
	case KEY_F5		:	OnPreset5();	break;
	case KEY_F6		:	OnPreset6();	break;
	case KEY_F7		:	OnPreset7();	break;
	case KEY_F8		:	OnPreset8();	break;
	case KEY_F9		:	OnPreset9();	break;
	case KEY_F10	:	OnPreset10();	break;
	case KEY_F11	:	OnPreset11();	break;
	case KEY_F12	:	OnPreset12();	break;
	case KEY_RIGHT	:	OnSeekup();		break;
	case KEY_LEFT	:	OnSeekdown();	break;
	case KEY_UP		:	OnTuneup();		break;
	case KEY_DOWN	:	OnTunedown();	break;
	default	:							break;
	}
}

void CUSBRadioDlg::OnCancel()
{
	//If scanning, end the scan
	if (m_Scanning)
		EndScan();

	//Delete the tray icon
	Shell_NotifyIcon(NIM_DELETE, &m_TrayData);

	KillTimer(TIMER_FIND_DEVICE);
	KillTimer(TIMER_AUDIO_STREAM);
	KillTimer(TIMER_POLL_DEVICE);

	m_FMRadioDevice.SaveRadioSettings(&m_RadioData);

	//Close the FM Radio Device
	m_FMRadioDevice.CloseFMRadio();

	//Cleanup the tooltips
	delete(m_pToolTip);

	//Remove the buttons
	RemoveButtons();

	//Set the handle in the App to null
	((CUSBRadioApp*)AfxGetApp())->m_hwndDialog = NULL;

	CDialog::OnCancel();
}

void CUSBRadioDlg::OnMinimize()
{
	//Add the icon and minimize and hide the window
	ShowWindow(SW_MINIMIZE);
	
	//if (m_RadioData.showInTray)
	//	Shell_NotifyIcon(NIM_ADD, &m_TrayData);

	//ShowWindow(SW_HIDE);
}

LRESULT CUSBRadioDlg::OnCommandHelp(WPARAM wParam, LPARAM lParam)
{
	//Override the F1 Help to allow F1 to be a preset
	return true;
}

bool CUSBRadioDlg::TuneStation(bool tuneUp)
{
	//This function allows the GUI to continuously tune up
	//or down without calling a tune to the device (tunedevice)
	//by setting a timer that when timesout, actually does the
	//tune on the device

	//Kill the polling timers
	KillTimer(TIMER_TUNE_DELAY);
	KillTimer(TIMER_POLL_DEVICE);

	//Stop the stream
	m_FMRadioDevice.StopStream(true);

	//Determine the spacing, min and max band
	double spacing, maxBand, minBand;

	switch (m_RadioData.spacing)
	{
	case DATA_SPACING_200KHZ	:	spacing = .200;	break;
	case DATA_SPACING_100KHZ	:	spacing = .100;	break;
	case DATA_SPACING_50KHZ		:	spacing = .050;	break;
	}

	if (m_RadioData.band == DATA_BAND_875_108MHZ)
	{
		maxBand = 108.00;
		minBand = 87.50;
	}
	else
	{
		maxBand = 90.00;
		minBand = 76.00;
	}

	//Tune up or down
	if (tuneUp == TUNE_UP)
		m_RadioData.currentStation += spacing;
	else
		m_RadioData.currentStation -= spacing;

	//If we have exceeded either end of the band, wrap around
	if (m_RadioData.currentStation > maxBand)
		m_RadioData.currentStation = minBand;
	else if (m_RadioData.currentStation < minBand)
		m_RadioData.currentStation = maxBand;

	//Update the radio LED with the new station
	UpdateRadioLED();

	return true;
}

bool CUSBRadioDlg::TuneDevice(bool tuneUp)
{
	//Stop polling the device, and reset the RDS
	KillTimer(TIMER_POLL_DEVICE);
	ResetRDSText();

	//Tune the device up or down
	bool status = m_FMRadioDevice.Tune(tuneUp);

	//If the tune is successful, then wait for the new RDS,
	//then begin polling again
	if (status)
	{
		while (m_FMRadioDevice.GetRDSData(&m_RDSData));
		SetTimer(TIMER_POLL_DEVICE, 1, NULL);
	}

	return status;
}

bool CUSBRadioDlg::TuneDevice(double frequency)
{
	//Stop polling the device, and reset the RDS
	KillTimer(TIMER_POLL_DEVICE);
	ResetRDSText();

	//Tune the device to the desired frequency
	bool status = m_FMRadioDevice.Tune(frequency);

	//If the tune is successful, then wait for the new RDS,
	//then begin polling again
	if (status)
	{
		while (m_FMRadioDevice.GetRDSData(&m_RDSData));
		SetTimer(TIMER_POLL_DEVICE, 1, NULL);
	}

	return status;
}

bool CUSBRadioDlg::SeekDevice(bool seekUp)
{
	//Stop polling the device, and reset the RDS
	KillTimer(TIMER_POLL_DEVICE);
	ResetRDSText();

	//Seek on the device
	bool status = m_FMRadioDevice.Seek(seekUp);

	//If the seek is successful, then wait for the new RDS,
	//then begin polling again
	if (status)
	{
		while (m_FMRadioDevice.GetRDSData(&m_RDSData));
		SetTimer(TIMER_POLL_DEVICE, 1, NULL);
	}

	return status;
}

void CUSBRadioDlg::ResetRDSText()
{
	//Set the rds text back to default, set the display index to 0, reset the RDS text
	//and begin scrolling the default text again
	KillTimer(TIMER_SCROLL_RDS);
	m_RDSData.rdsText = DEFAULT_RDS_TEXT;
	m_CurrentRDSDisplayIndex = 0;
	m_FMRadioDevice.ResetRDSText();
	SetTimer(TIMER_SCROLL_RDS, TIMER_SCROLL_RDS_0_TIME, NULL);
}

void CUSBRadioDlg::OnPreset1()
{
	TunePreset(0);
}

void CUSBRadioDlg::OnPreset2()
{
	TunePreset(1);
}

void CUSBRadioDlg::OnPreset3()
{
	TunePreset(2);
}

void CUSBRadioDlg::OnPreset4()
{
	TunePreset(3);
}

void CUSBRadioDlg::OnPreset5()
{
	TunePreset(4);
}

void CUSBRadioDlg::OnPreset6()
{
	TunePreset(5);
}
void CUSBRadioDlg::OnPreset7()
{
	TunePreset(6);
}

void CUSBRadioDlg::OnPreset8()
{
	TunePreset(7);
}

void CUSBRadioDlg::OnPreset9()
{
	TunePreset(8);
}

void CUSBRadioDlg::OnPreset10()
{
	TunePreset(9);
}

void CUSBRadioDlg::OnPreset11()
{
	TunePreset(10);
}

void CUSBRadioDlg::OnPreset12()
{
	TunePreset(11);
}

void CUSBRadioDlg::TunePreset(int preset)
{
	//Check that the preset is in range
	if (preset < PRESET_NUM)
	{
		//If scanning, end the scan
		if (m_Scanning)
		{
			EndScan();
		}

		//If the current station isn't the preset trying to be tuned, then tune the device
		//and update the current preset structure and LED
		if (m_RadioData.currentStation != m_RadioData.preset[preset])
		{
			if (TuneDevice(m_RadioData.preset[preset]))
			{
				m_CurrentPreset.presetNum = preset;
				m_CurrentPreset.onPreset = true;
				UpdateStationLED();
			}
		}
	}
}
	
void CUSBRadioDlg::OnSeekup() 
{
	//If we aren't coming up on this button from a scan, then either end
	//a previous scan, or seek up on the device. Otherwise set the button
	//into scan mode (depressed)
	if (!m_ScanJustPressed)
	{
		if (m_Scanning)
		{
			EndScan();
		}
		else
		{
			SeekDevice(SEEK_UP);
		}
	}
	else
	{
		GetDlgItem(IDC_BUTTON_SCANUP)->ShowWindow(FALSE);
		GetDlgItem(IDC_BUTTON_SCANUP_DOWN)->ShowWindow(TRUE);
		m_ScanJustPressed = false;
		UpdateStationLED();
	}
}

void CUSBRadioDlg::OnSeekdown() 
{
	//If we aren't coming up on this button from a scan, then either end
	//a previous scan, or seek up on the device. Otherwise set the button
	//into scan mode (depressed)
	if (!m_ScanJustPressed)
	{
		if (m_Scanning)
		{
			EndScan();
		}
		else
		{
			SeekDevice(SEEK_DOWN);
		}
	}
	else
	{
		GetDlgItem(IDC_BUTTON_SCANDOWN)->ShowWindow(FALSE);
		GetDlgItem(IDC_BUTTON_SCANDOWN_DOWN)->ShowWindow(TRUE);
		m_ScanJustPressed = false;
		UpdateStationLED();
	}
}

void CUSBRadioDlg::OnPresetScanUp() 
{
	//If scanning end the scan
	if (m_Scanning)
	{
		EndScan();
	}
	else
	{
		//If the device is streaming start the scan up
		if (m_FMRadioDevice.IsStreaming())
		{
			GetDlgItem(IDC_BUTTON_PRESETSCANUP)->ShowWindow(FALSE);
			GetDlgItem(IDC_BUTTON_PRESETSCANUP_DOWN)->ShowWindow(TRUE);
			UpdateWindow();

			if (m_CurrentPreset.onPreset)
			{
				m_CurrentPreset.presetNum++;
				if (m_CurrentPreset.presetNum >= PRESET_NUM)
					m_CurrentPreset.presetNum = 0;
				m_CurrentPreset.onPreset = true;
			}
			else
			{
				m_CurrentPreset.presetNum = 0;
				m_CurrentPreset.onPreset = true;
			}

			m_Scanning = true;
			sndPlaySound("SystemAsterisk", SND_ASYNC);
			TuneDevice(m_RadioData.preset[m_CurrentPreset.presetNum]);
			UpdateStationLED();
			SetTimer(TIMER_SCANPRESET_UP, m_RadioData.scanTime * 1000, NULL);
		}
	}
}

void CUSBRadioDlg::OnPresetScanDown() 
{
	//If scanning end the scan
	if (m_Scanning)
	{
		EndScan();
	}
	else
	{
		//If the device is streaming start the scan up
		if (m_FMRadioDevice.IsStreaming())
		{
			GetDlgItem(IDC_BUTTON_PRESETSCANDOWN)->ShowWindow(FALSE);
			GetDlgItem(IDC_BUTTON_PRESETSCANDOWN_DOWN)->ShowWindow(TRUE);
			UpdateWindow();

			if (m_CurrentPreset.onPreset)
			{
				m_CurrentPreset.presetNum--;
				if (m_CurrentPreset.presetNum < 0)
					m_CurrentPreset.presetNum = PRESET_NUM - 1;
				m_CurrentPreset.onPreset = true;
			}
			else
			{
				m_CurrentPreset.presetNum = PRESET_NUM - 1;
				m_CurrentPreset.onPreset = true;
			}

			m_Scanning = true;
			sndPlaySound("SystemAsterisk", SND_ASYNC);
			TuneDevice(m_RadioData.preset[m_CurrentPreset.presetNum]);
			UpdateStationLED();
			SetTimer(TIMER_SCANPRESET_DOWN, m_RadioData.scanTime * 1000, NULL);
		}
	}
}

void CUSBRadioDlg::OnTuneup() 
{
	//If we were scanning, simply end the scan
	if (m_Scanning)
	{
		EndScan();
	}
	else
	{
		//Call the tune station
		TuneStation(TUNE_UP);

		//Set the new timer to ensure no further tune is being done
		SetTimer(TIMER_TUNE_DELAY, TIMER_TUNE_DELAY_TIME, NULL);
	}
}

void CUSBRadioDlg::OnTunedown() 
{
	//If we were scanning, simply end the scan
	if (m_Scanning)
	{
		EndScan();
	}
	else
	{
		//Call the tune station
		TuneStation(TUNE_DOWN);

		//Set the new timer to ensure no further tune is being done
		SetTimer(TIMER_TUNE_DELAY, TIMER_TUNE_DELAY_TIME, NULL);
	}
}

void CUSBRadioDlg::EndScan()
{
	//End scan will kill all scan timers
	KillTimer(TIMER_SCAN_UP);
	KillTimer(TIMER_SCAN_DOWN);
	KillTimer(TIMER_SCANPRESET_UP);
	KillTimer(TIMER_SCANPRESET_DOWN);

	//Reset any depressed buttons to their original state
	if (GetDlgItem(IDC_BUTTON_PRESETSCANUP_DOWN)->IsWindowVisible())
	{
		GetDlgItem(IDC_BUTTON_PRESETSCANUP_DOWN)->ShowWindow(FALSE);
		GetDlgItem(IDC_BUTTON_PRESETSCANUP)->ShowWindow(TRUE);		
	}
	if (GetDlgItem(IDC_BUTTON_PRESETSCANDOWN_DOWN)->IsWindowVisible())
	{
		GetDlgItem(IDC_BUTTON_PRESETSCANDOWN_DOWN)->ShowWindow(FALSE);
		GetDlgItem(IDC_BUTTON_PRESETSCANDOWN)->ShowWindow(TRUE);
	}
	if (GetDlgItem(IDC_BUTTON_SCANUP_DOWN)->IsWindowVisible())
	{
		GetDlgItem(IDC_BUTTON_SCANUP_DOWN)->ShowWindow(FALSE);
		GetDlgItem(IDC_BUTTON_SCANUP)->ShowWindow(TRUE);
	}
	if (GetDlgItem(IDC_BUTTON_SCANDOWN_DOWN)->IsWindowVisible())
	{
		GetDlgItem(IDC_BUTTON_SCANDOWN_DOWN)->ShowWindow(FALSE);
		GetDlgItem(IDC_BUTTON_SCANDOWN)->ShowWindow(TRUE);
	}

	//Update the window since buttons changed
	UpdateWindow();

	//Set scanning to false
	m_Scanning = false;
}

void CUSBRadioDlg::OnMute()
{
	//Determine if we are muting or unmuting, then perform the action on
	//the device, and update the window to draw or "un" draw the volume slide
	//and mute button
	if (!m_Muting)
	{
		m_Muting = true;
		m_FMRadioDevice.Mute(m_Muting);
		GetDlgItem(IDC_BUTTON_MUTE)->ShowWindow(FALSE);
		GetDlgItem(IDC_BUTTON_MUTE_DOWN)->ShowWindow(TRUE);
		UpdateWindow();
	}
	else
	{
		m_Muting = false;
		m_FMRadioDevice.Mute(m_Muting);
		GetDlgItem(IDC_BUTTON_MUTE_DOWN)->ShowWindow(FALSE);
		GetDlgItem(IDC_BUTTON_MUTE)->ShowWindow(TRUE);
		UpdateWindow();
	}

	UpdateRadioLED();
}

void CUSBRadioDlg::OnStereoMono()
{
	//Determine if whether we are switching to mono or stereo,
	//then perform the action on the device, and update the buttons
	//in the window
	if (m_RadioData.monoStereo == DATA_MONOSTEREO_MONO)
	{
		m_RadioData.monoStereo = DATA_MONOSTEREO_STEREO;
		GetDlgItem(IDC_BUTTON_STEREOMONO_DOWN)->ShowWindow(FALSE);
		GetDlgItem(IDC_BUTTON_STEREOMONO)->ShowWindow(TRUE);
		UpdateWindow();
	}
	else
	{
		m_RadioData.monoStereo = DATA_MONOSTEREO_MONO;
		GetDlgItem(IDC_BUTTON_STEREOMONO)->ShowWindow(FALSE);
		GetDlgItem(IDC_BUTTON_STEREOMONO_DOWN)->ShowWindow(TRUE);
		UpdateWindow();
	}

	//Since this is a saveable setting, save it
	m_FMRadioDevice.SaveRadioSettings(&m_RadioData);
}

void CUSBRadioDlg::OnSettings()
{
	// Remember the station tuned to before settings are changed
	double oldStation = m_RadioData.currentStation;
	double newStation = 0;

	//If we are streaming, then the settings dialog can be shown
	if (m_FMRadioDevice.IsStreaming())
	{
		CSettingsDlg	settingsDlg;

		settingsDlg.m_RadioData = m_RadioData;
		settingsDlg.m_RadioIndex = m_FMRadioDevice.GetLastKnownRadioIndex();

		//If OK is pressed, update the radio data and new index (if changed)
		//and then update the settings and radio LED
		if (settingsDlg.DoModal() == IDOK)
		{
			m_RadioData = settingsDlg.m_RadioData;
			m_FMRadioDevice.SetNewRadioIndex(settingsDlg.m_RadioIndex);
			
			UpdateSettings();
			UpdateRadioLED();

			// Re-tune to the old station, making sure that the new station is still valid
			newStation = oldStation;

			double minBand = 87.5, maxBand = 108.0, spacing = 0.2;

			// Determine the new minimum and maximum frequencies
			switch (m_RadioData.band)
			{
			case DATA_BAND_875_108MHZ:	minBand = 87.5;
										maxBand = 108;		break;
			case DATA_BAND_76_90MHZ:	minBand = 76.0;
										maxBand = 90.0;		break;
			default:					minBand = 87.5;
										maxBand = 108;		break;
			}
			
			// Determine the new frequency spacing
			switch (m_RadioData.spacing)
			{
			case DATA_SPACING_200KHZ:	spacing = 0.2;		break;
			case DATA_SPACING_100KHZ:	spacing = 0.1;		break;
			case DATA_SPACING_50KHZ:	spacing = 0.05;		break;
			default:					spacing = 0.1;		break;
			}

			// Make sure that the station we are tuning to is within the frequency range specified
			if ((oldStation >= minBand) && (oldStation <= maxBand))
			{
				// Make sure that if the spacing is 200 KHz and the min freqeuncy is 87.5 MHz,
				// then the frequency has an odd decimal digit
				if ((minBand == 87.5) && (spacing == 0.2) && (((UINT)(oldStation * 100.0) % 20) != 10))
				{
					// Otherwise tune to the lowest allowable frequency
					newStation = minBand;
				}
				// Make sure that if the spacing is 200 KHz and the min frequency is 76 MHz,
				// then the frequency has an even decimal digit
				if ((minBand == 76) && (spacing == 0.2) && (((UINT)(oldStation * 100.0) % 20) != 0))
				{
					// Otherwise tune to the lowest allowable frequency
					newStation = minBand;
				}
				// Make sure that the frequency is valid if the spacing is 100 KHz
				else if ((spacing == 0.1) && (((UINT)(oldStation * 100.0) % 10) != 0))
				{
					// Otherwise tune to the lowest allowable frequency
					newStation = minBand;
				}
				// Make sure that the frequency is valid if the spacing is 50 KHz
				else if ((spacing == 0.05) && (((UINT)(oldStation * 100.0) % 5) != 0))
				{
					// Otherwise tune to the lowest allowable frequency
					newStation = minBand;
				}
			}
			// Otherwise tune to the lowest allowable frequency
			else
			{
				newStation = minBand;
			}

			// Tune to the old station or tune to the lowest valid frequency if the
			// old station is now invalid
			m_FMRadioDevice.Tune(newStation);
		}
	}
}

void CUSBRadioDlg::UpdateSettings()
{
	CRect rect;
	GetWindowRect(&rect);

	if (m_RadioData.alwaysOnTop)
		::SetWindowPos(m_hWnd, HWND_TOPMOST, rect.left, rect.top, rect.Width(), rect.Height(), NULL);
	else
		::SetWindowPos(m_hWnd, HWND_NOTOPMOST, rect.left, rect.top, rect.Width(), rect.Height(), NULL);

	if (m_RadioData.showInTitleBar)
	{
		ShowWindow(SW_HIDE);
		ModifyStyleEx(NULL, WS_EX_APPWINDOW, SWP_FRAMECHANGED);
		ShowWindow(SW_SHOW);
	}
	else
	{
		ShowWindow(SW_HIDE);
		ModifyStyleEx(WS_EX_APPWINDOW, NULL, SWP_FRAMECHANGED);
		ShowWindow(SW_SHOW);
	}

	if (m_RadioData.showInTray)
		Shell_NotifyIcon(NIM_ADD, &m_TrayData);
	else
		Shell_NotifyIcon(NIM_DELETE, &m_TrayData);

	m_FMRadioDevice.SaveRadioSettings(&m_RadioData);

	UpdateStationToolTips(true);
}

void CUSBRadioDlg::OnTimer(UINT nIDEvent) 
{
	//Determine which event was triggered and act on it
	switch (nIDEvent)
	{
	case TIMER_FIND_DEVICE	:	//Stop the find device timer immediately
								KillTimer(TIMER_FIND_DEVICE);

								//Open the device and retrieve the radio data
								m_Status = m_FMRadioDevice.OpenFMRadio(&m_RadioData);

								//If status is OK, begin initialization
								if (m_Status == STATUS_OK)
								{
									//Determine if this is the radio's first run
									if (m_RadioData.firstRun)
									{
										//Launch first run dialogs to setup the radio
										CRadioFirstRunDlg	radioFirstRunDlg;

										radioFirstRunDlg.m_RadioData = m_RadioData;

										//If ok is pressed, then save the settings, otherwise
										//close the GUI
										if (radioFirstRunDlg.DoModal() == IDOK)
										{
											m_RadioData = radioFirstRunDlg.m_RadioData;

											UpdateSettings();
										}
										else
										{
											OnCancel();
											break;
										}
									}
											
									//Set the mono stereo button
									if (m_RadioData.monoStereo == DATA_MONOSTEREO_MONO)
									{
										GetDlgItem(IDC_BUTTON_STEREOMONO)->ShowWindow(FALSE);
										GetDlgItem(IDC_BUTTON_STEREOMONO_DOWN)->ShowWindow(TRUE);
									}
									else
									{
										GetDlgItem(IDC_BUTTON_STEREOMONO_DOWN)->ShowWindow(FALSE);
										GetDlgItem(IDC_BUTTON_STEREOMONO)->ShowWindow(TRUE);
									}

									//Determine if we mute on startup
									if (m_RadioData.muteOnStartup)
									{
										m_Muting = true;
										m_FMRadioDevice.Mute(m_Muting);
										GetDlgItem(IDC_BUTTON_MUTE)->ShowWindow(FALSE);
										GetDlgItem(IDC_BUTTON_MUTE_DOWN)->ShowWindow(TRUE);
									}
									else
									{
										m_Muting = false;
										m_FMRadioDevice.Mute(m_Muting);
										GetDlgItem(IDC_BUTTON_MUTE_DOWN)->ShowWindow(FALSE);
										GetDlgItem(IDC_BUTTON_MUTE)->ShowWindow(TRUE);
									}

									//Update the tooltips for the stations
									UpdateStationToolTips(true);

									//Reset RDS
									ResetRDSText();
									
									//Update the LED and set the poll/stream timers
									UpdateRadioLED();
									SetTimer(TIMER_POLL_DEVICE, TIMER_POLL_DEVICE_TIME, NULL);
									SetTimer(TIMER_AUDIO_STREAM, TIMER_AUDIO_STREAM_TIME, NULL);
								}
								else if (m_Status == STATUS_OUTPUTAUDIO_ERROR)
								{
									//Post a message asking if they want to try again
									if (MessageBox("Error opening audio output device, try again?", "Error", MB_YESNO | MB_ICONQUESTION) == IDYES)
									{
										m_FMRadioDevice.CloseFMRadio();
										SetTimer(TIMER_FIND_DEVICE, TIMER_FIND_DEVICE_TIME, NULL);
									}
									else
									{
										OnCancel();
										break;
									}
								}
								else if (m_Status == STATUS_FMRADIOAUDIO_ERROR)
								{
									//Post a message asking if they want to try again
									if (MessageBox("Error opening USB FM Radio audio input, try again?", "Error", MB_YESNO | MB_ICONQUESTION) == IDYES)
									{
										m_FMRadioDevice.CloseFMRadio();
										SetTimer(TIMER_FIND_DEVICE, TIMER_FIND_DEVICE_TIME, NULL);
									}
									else
									{
										OnCancel();
										break;
									}
								}
								else if (m_Status == STATUS_BOOTLOAD_ERROR)
								{
									//Bootload error, terminate program
									OnCancel();
								}
								else
								{			
									//Otherwise, no device was found, so close, and start the find
									//device polling again
									m_FMRadioDevice.CloseFMRadio();
									SetTimer(TIMER_FIND_DEVICE, TIMER_FIND_DEVICE_TIME, NULL);
								}
								break;

	case TIMER_POLL_DEVICE	:	//Get the RDBS data from the devicem, if it fails kill the poll/audio timers update
								//the LED and start looking for a valid device again
								KillTimer(TIMER_POLL_DEVICE);
								
								//Store the temp values so we can determine if a change occurs
								m_tmpRSSI = m_RDSData.recievedSignalStrength;
								m_tmpMonoStereo = m_RDSData.monoStereo;
								m_tmpRDSText = m_RDSData.rdsText;

								//Get the latest RDS data
								if (!m_FMRadioDevice.GetRDSData(&m_RDSData))
								{
									//If it fails update the missed RDS calls
									m_MissedRDSCalls++;

									//If we are at 10 missed calls, the device is not functioning properly
									//so reset everything, and start looking for a device again
									if (m_MissedRDSCalls == 10)
									{
										m_MissedRDSCalls = 0;						
										KillTimer(TIMER_AUDIO_STREAM);
										KillTimer(TIMER_POLL_DEVICE);
										KillTimer(TIMER_SCROLL_RDS);
										if (m_Scanning)
											EndScan();
										m_FMRadioDevice.CloseFMRadio();
										UpdateStationToolTips(false);
										UpdateRadioLED();
										SetTimer(TIMER_FIND_DEVICE, 0, NULL);
									}
									else
									{
										//If less than 10 have been missed, reset the timer and keep trying
										SetTimer(TIMER_POLL_DEVICE, TIMER_POLL_DEVICE_TIME, NULL);
									}
								}
								else
								{
									//Since a RDS call was successful, then reset the missed calls variable
									m_MissedRDSCalls = 0;

									//If the RDBS read passed, then make sure LED gets updated for channel/signal/stereo changes					
									if (m_tmpRSSI != m_RDSData.recievedSignalStrength)
									{
										UpdateRSSILED();
									}

									//If stereo mono changed, update that LED
									if (m_tmpMonoStereo != m_RDSData.monoStereo)
									{
										UpdateMonoStereoLED();
									}

									//If the RDS changed, update the RDS
									if (m_tmpRDSText != m_RDSData.rdsText)
									{
										//Stop any current scrolling
										KillTimer(TIMER_SCROLL_RDS);

										int textScreenLength = 0;

										//Loop through and determine the size of the new string
										for (int i = 0; (i < m_RDSData.rdsText.GetLength()) ; i++)
										{
											textScreenLength += GetAlphanumericSmallBitmap(m_RDSData.rdsText[i])->GetBitmapDimension().cx;
										}

										//If it is larger than the space in the GUI, then start scrolling, otherwise
										//store the offset to center the RDS string, and update the RDS text
										if (textScreenLength > RDS_WIDTH)
										{
											m_CurrentRDSDisplayIndex = 0;
											SetTimer(TIMER_SCROLL_RDS, TIMER_SCROLL_RDS_0_TIME, NULL);
										}
										else
										{
											m_CurrentRDSDisplayIndex = -(int)((double)(RDS_WIDTH - textScreenLength) / (double)2);
										}

										UpdateRDSDisplay();
									}
									
									//If the current station change, update the current station LED
									if (m_RDSData.currentStation != m_RadioData.currentStation)
									{
										m_RadioData.currentStation = m_RDSData.currentStation;
										UpdateStationLED();
									}

									//Set the timer to poll again
									SetTimer(TIMER_POLL_DEVICE, TIMER_POLL_DEVICE_TIME, NULL);
								}
								break;

	case TIMER_AUDIO_STREAM	:	//KillTimer(TIMER_AUDIO_STREAM);
								m_FMRadioDevice.StreamAudio();
								//SetTimer(TIMER_AUDIO_STREAM, TIMER_AUDIO_STREAM_TIME, NULL);
								break;

	case TIMER_BUTTON_DOWN	:	KillTimer(TIMER_BUTTON_DOWN);
								
								//If the down button timer goes off, either a preset is being set, or a scan
								//is being performed - set the preset, or start the scan
								if (m_FMRadioDevice.IsStreaming())
								{
									SetPreset(1, IDC_BUTTON_PRESET1);
									SetPreset(2, IDC_BUTTON_PRESET2);
									SetPreset(3, IDC_BUTTON_PRESET3);
									SetPreset(4, IDC_BUTTON_PRESET4);
									SetPreset(5, IDC_BUTTON_PRESET5);
									SetPreset(6, IDC_BUTTON_PRESET6);
									SetPreset(7, IDC_BUTTON_PRESET7);
									SetPreset(8, IDC_BUTTON_PRESET8);
									SetPreset(9, IDC_BUTTON_PRESET9);
									SetPreset(10, IDC_BUTTON_PRESET10);
									SetPreset(11, IDC_BUTTON_PRESET11);
									SetPreset(12, IDC_BUTTON_PRESET12);

									if (!m_Scanning)
									{
										StartScan(IDC_BUTTON_SCANUP, TIMER_SCAN_UP);
										StartScan(IDC_BUTTON_SCANDOWN, TIMER_SCAN_DOWN);
									}

									//Reset the down variables
									m_DownPoint = CPoint (-1, -1);
									m_KeyDown = 0x00;
								}
								break;

								//On the scan timers, perform the seek up or down for device, or presets
	case TIMER_SCAN_UP		:	SeekDevice(SEEK_UP);
								break;

	case TIMER_SCAN_DOWN	:	SeekDevice(SEEK_DOWN);
								break;

	case TIMER_SCANPRESET_UP	:	m_CurrentPreset.presetNum++;
									if (m_CurrentPreset.presetNum >= PRESET_NUM)
										m_CurrentPreset.presetNum = 0;
									m_CurrentPreset.onPreset = true;
									TuneDevice(m_RadioData.preset[m_CurrentPreset.presetNum]);
									UpdateStationLED();
									break;

	case TIMER_SCANPRESET_DOWN	:	m_CurrentPreset.presetNum--;
									if (m_CurrentPreset.presetNum < 0)
										m_CurrentPreset.presetNum = PRESET_NUM - 1;
									m_CurrentPreset.onPreset = true;
									TuneDevice(m_RadioData.preset[m_CurrentPreset.presetNum]);
									UpdateStationLED();
									break;

	case TIMER_VOLUME_MOVING	:	//If we are moving the volume, draw the cursor in a new position
									GetCursorPos(&m_Point);
									SetWindowPos(&wndTop, m_Point.x - m_MovePoint.x, m_Point.y - m_MovePoint.y, DLGWIDTH, DLGHEIGHT, SWP_SHOWWINDOW);
									break;

	case TIMER_TUNE_DELAY		:	//If the tune delay timer goes off, then perform the actual tune
									KillTimer(TIMER_TUNE_DELAY);
									TuneDevice(m_RadioData.currentStation);
									m_FMRadioDevice.StopStream(false);
									while(m_FMRadioDevice.GetRDSData(&m_RDSData));
									SetTimer(TIMER_POLL_DEVICE, 1, NULL);
									break;

	case TIMER_SCROLL_RDS		:	//As the timer goes off for scrolling rds, update the display index and
									//show the new string
									KillTimer(TIMER_SCROLL_RDS);
									m_CurrentRDSDisplayIndex ++;
									if (!(m_CurrentRDSDisplayIndex < m_RDSData.rdsText.GetLength()))
										m_CurrentRDSDisplayIndex = 0;
									UpdateRDSDisplay();
									if (m_CurrentRDSDisplayIndex != 0)
										SetTimer(TIMER_SCROLL_RDS, TIMER_SCROLL_RDS_TIME, NULL);
									else
										SetTimer(TIMER_SCROLL_RDS, TIMER_SCROLL_RDS_0_TIME, NULL);
																

	default					:	break;
	}

	CDialog::OnTimer(nIDEvent);
}

void CUSBRadioDlg::SetPreset(int preset, UINT id)
{
	CRect rect;

	((CBitmapButton*)GetDlgItem(id))->GetWindowRect(&rect);
	if ((rect.PtInRect(m_DownPoint)) || (((m_KeyDown >= KEY_F1) && (m_KeyDown <= KEY_F12)) && (preset == (m_KeyDown && 0x0F))))
	{
		m_RadioData.preset[preset - 1] = m_RadioData.currentStation;
		m_CurrentPreset.presetNum = preset - 1;
		m_CurrentPreset.onPreset = true;
		sndPlaySound("SystemAsterisk", SND_ASYNC);
		TuneDevice(m_RadioData.preset[m_CurrentPreset.presetNum]);
		UpdateStationToolTips(true);
	}
}

void CUSBRadioDlg::StartScan(UINT id, int timerID)
{
	CRect rect;

	//Determine if we came up in the same rectangle
	((CBitmapButton*)GetDlgItem(id))->GetWindowRect(&rect);

	//If so, then start the scan
	if (rect.PtInRect(m_DownPoint))
	{
		//Play the confirmation sound, set scanning and scan pressed to true
		sndPlaySound("SystemAsterisk", SND_ASYNC);
		m_Scanning = true;
		m_ScanJustPressed = true;

		//Seek down or up depending on the scan
		if (timerID == TIMER_SCAN_DOWN)
		{
			SeekDevice(SEEK_DOWN);
		}
		else
		{
			SeekDevice(SEEK_UP);
		}

		//Start the timer for the scan
		SetTimer(timerID, m_RadioData.scanTime * 1000, NULL);
	}
}

void CUSBRadioDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
	//Check to see if we are in the volume location of the dialog
	if ((point.x >= VOLUME_MIN_X) && (point.x <= VOLUME_MAX_X) &&
		(point.y >= VOLUME_MIN_Y) && (point.y <= VOLUME_MAX_Y))
	{
		m_Muting = false;
		if (GetDlgItem(IDC_BUTTON_MUTE_DOWN)->IsWindowVisible())
		{
			GetDlgItem(IDC_BUTTON_MUTE)->ShowWindow(TRUE);
			GetDlgItem(IDC_BUTTON_MUTE_DOWN)->ShowWindow(FALSE);
		}

		//Set the new volume
		m_FMRadioDevice.SetWaveOutVolume((BYTE)(((double)(point.x - VOLUME_MIN_X) / (double)(VOLUME_MAX_X - VOLUME_MIN_X)) * 100.0));
		m_Volume = m_FMRadioDevice.GetWaveOutVolume();

		InvalidateRect(CRect(CPoint(VOLUME_MIN_X, VOLUME_MIN_Y), CPoint(VOLUME_MAX_X, VOLUME_MAX_Y)), FALSE);
		UpdateWindow();

		//Set volume toggle to true to slide the volume up and down
		m_VolumeToggle = true;
	}
	else
	{
		//Store the move reference point and set moving to true
		m_MovePoint = point;
		SetTimer(TIMER_VOLUME_MOVING, 10, NULL);
	}

	CDialog::OnLButtonDown(nFlags, point);
}

void CUSBRadioDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
	//Set the new volume if it is being toggled
	if ((nFlags & MK_LBUTTON) && m_VolumeToggle)
	{
		int x = point.x;

		if (x < VOLUME_MIN_X)
			x = VOLUME_MIN_X;
		else if (x > VOLUME_MAX_X)
			x = VOLUME_MAX_X;

		//Set the new volume
		m_FMRadioDevice.SetWaveOutVolume((BYTE)(((double)(x - VOLUME_MIN_X) / (double)(VOLUME_MAX_X - VOLUME_MIN_X)) * 100.0));
		m_Volume = m_FMRadioDevice.GetWaveOutVolume();

		//Update the window with the new volume settings
		InvalidateRect(CRect(CPoint(VOLUME_MIN_X, VOLUME_MIN_Y), CPoint(VOLUME_MAX_X, VOLUME_MAX_Y)), FALSE);
		UpdateWindow();
	}

	//If anything else comes up, then kill the volume timer/toggle
	if (!(nFlags & MK_LBUTTON))
	{
		KillTimer(TIMER_VOLUME_MOVING);
		m_VolumeToggle = false;
	}
		
	CDialog::OnMouseMove(nFlags, point);
}

void CUSBRadioDlg::OnLButtonUp(UINT nFlags, CPoint point) 
{
	//Kill the volume move timer
	KillTimer(TIMER_VOLUME_MOVING);
	m_VolumeToggle = false;

	CDialog::OnLButtonUp(nFlags, point);
}

void CUSBRadioDlg::OnFMTunerLink() 
{	
	ShellExecute(GetDesktopWindow()->m_hWnd, "open", "http://www.silabs.com/FMTuners", NULL, NULL, SW_SHOW);
}

void CUSBRadioDlg::OnUSBMCULink() 
{
	ShellExecute(GetDesktopWindow()->m_hWnd, "open", "http://www.silabs.com/tgwWebApp/public/web_content/products/Microcontrollers/USB/en/USBMCU.htm", NULL, NULL, SW_SHOW);
}

void CUSBRadioDlg::OnSilabsLink()
{
	ShellExecute(GetDesktopWindow()->m_hWnd, "open", "http://www.silabs.com/", NULL, NULL, SW_SHOW);
}

void CUSBRadioDlg::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
//	CToolbarDlg toolbarDlg;

//	AfxGetApp()->m_pMainWnd = toolbarDlg;
//	toolbarDlg.DoModal();
	
	CDialog::OnLButtonDblClk(nFlags, point);
}

BOOL CUSBRadioDlg::PreTranslateMessage(MSG* pMsg) 
{
	if (NULL != m_pToolTip)
		m_pToolTip->RelayEvent(pMsg);
	
	return CDialog::PreTranslateMessage(pMsg);
}
