// f8254Dlg.cpp : implementation file // #include "stdafx.h" #include "f8254.h" #include "f8254Dlg.h" #include "ACCES32.h" #include #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define InsCR(x) x += 0x0d; x += 0x0a; const INITIALIZE = 1; // initialize the counter const START = 2; // start counting const SINCESTART = 4; // how many since starting const SINCELAST = 8; // how many since last check const STOP = 16; // stop counting const RESET = 32; // reset counter to 65535 bool FreqInRunning, PulseWidthRunning; UINT FreqInTimer, PulseWidthTimer; ///////////////////////////////////////////////////////////////////////////// // CF8254Dlg dialog CF8254Dlg::CF8254Dlg(CWnd* pParent /*=NULL*/) : CDialog(CF8254Dlg::IDD, pParent) { //{{AFX_DATA_INIT(CF8254Dlg) m_Instructions = _T("Instructions:"); m_FeatureRadio = -1; m_BaseEdit = _T("E010"); m_EventCountEdit = _T(""); m_FreqInEdit = _T(""); m_FreqOutEdit = _T("150000"); m_PulseEdit = _T(""); //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CF8254Dlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CF8254Dlg) DDX_Control(pDX, IDC_FreqOutEdit, m_FreqOutEditCtrl); DDX_Control(pDX, IDC_EventCountEdit, m_EventCountEditCtrl); DDX_Control(pDX, IDC_SinceLastButton, m_SinceLastButtonCtrl); DDX_Control(pDX, IDC_SinceFirstButton, m_SinceFirstButtonCtrl); DDX_Control(pDX, IDC_RealLabel, m_RealLabelCtrl); DDX_Control(pDX, IDC_RealEdit, m_RealEditCtrl); DDX_Control(pDX, IDC_PulseEdit, m_PulseEditCtrl); DDX_Control(pDX, IDC_PulseLabel, m_PulseLabelCtrl); DDX_Control(pDX, IDC_FreqOutLabel, m_FreqOutLabelCtrl); DDX_Control(pDX, IDC_FreqInLabel, m_FreqInLabelCtrl); DDX_Control(pDX, IDC_EventTestButton, m_EventTestButtonCtrl); DDX_Control(pDX, IDC_EventCountLabel, m_EventCountLabelCtrl); DDX_Control(pDX, IDOK, m_StartButtonCtrl); DDX_Control(pDX, IDC_FreqInEdit, m_FreqInEditCtrl); DDX_Text(pDX, IDC_RealEdit, m_RealEdit); DDX_Text(pDX, IDC_Instructions, m_Instructions); DDX_Radio(pDX, IDC_FreqInRadio, m_FeatureRadio); DDX_Text(pDX, IDC_BaseEdit, m_BaseEdit); DDX_Text(pDX, IDC_EventCountEdit, m_EventCountEdit); DDX_Text(pDX, IDC_FreqInEdit, m_FreqInEdit); DDX_Text(pDX, IDC_FreqOutEdit, m_FreqOutEdit); DDX_Text(pDX, IDC_PulseEdit, m_PulseEdit); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CF8254Dlg, CDialog) //{{AFX_MSG_MAP(CF8254Dlg) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDCANCEL, OnExitButtonClick) ON_BN_CLICKED(IDOK, OnStartButtonClick) ON_WM_TIMER() ON_BN_CLICKED(IDC_FreqInRadio, OnFreqInRadioClick) ON_BN_CLICKED(IDC_FreqOutRadio, OnFreqOutRadio) ON_BN_CLICKED(IDC_EventCountRadio, OnEventCountRadio) ON_BN_CLICKED(IDC_PulseWidthRadio, OnPulseWidthRadio) ON_BN_CLICKED(IDC_SinceFirstButton, OnSinceFirstButtonClick) ON_BN_CLICKED(IDC_SinceLastButton, OnSinceLastButtonClick) ON_BN_CLICKED(IDC_EventTestButton, OnEventTestButtonClick) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CF8254Dlg message handlers BOOL CF8254Dlg::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_hIcon, FALSE); // Set small icon FreqInRunning = false; PulseWidthRunning = false; m_FreqInLabelCtrl.ShowWindow(SW_HIDE); m_FreqInEditCtrl.ShowWindow(SW_HIDE); m_FreqOutLabelCtrl.ShowWindow(SW_HIDE); m_FreqOutEditCtrl.ShowWindow(SW_HIDE); m_RealLabelCtrl.ShowWindow(SW_HIDE); m_RealEditCtrl.ShowWindow(SW_HIDE); m_EventCountLabelCtrl.ShowWindow(SW_HIDE); m_EventCountEditCtrl.ShowWindow(SW_HIDE); m_EventTestButtonCtrl.ShowWindow(SW_HIDE); m_SinceFirstButtonCtrl.ShowWindow(SW_HIDE); m_SinceLastButtonCtrl.ShowWindow(SW_HIDE); m_PulseLabelCtrl.ShowWindow(SW_HIDE); m_PulseEditCtrl.ShowWindow(SW_HIDE); InsCR(m_Instructions); m_Instructions += "Choose which feature of the 8254 chip to demonstrate with the radio buttons at the top of the form, and enter the chip's base address above."; if (InPortB(0x61) == 0xAA55) { MessageBox("ACCESNT.SYS not detected. Please copy ACCESNT.SYS into [NT]/system32/drivers and re-run this sample.", "Warning", MB_OK); } // TODO: Add extra initialization here UpdateData(false); 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 CF8254Dlg::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(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CF8254Dlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CF8254Dlg::OnExitButtonClick() { exit(0); } void CF8254Dlg::OnStartButtonClick() { unsigned long Frequency; double Temp; UpdateData(true); if (m_FeatureRadio > -1) { sscanf(m_BaseEdit.GetBuffer(0), "%x", &BaseAddress); if (m_FeatureRadio == 0) { if (!FreqInRunning) { m_StartButtonCtrl.SetWindowText("Stop Measure"); FreqInRunning = true; FreqInTimer = SetTimer(1, 100, NULL); } else { m_StartButtonCtrl.SetWindowText("Start Measure"); FreqInRunning = false; KillTimer(FreqInTimer); } // end if FreqInTimer / else } else if (m_FeatureRadio == 1) { UpdateData(true); sscanf(m_FreqOutEdit.GetBuffer(0), "%d", &Frequency); Temp = FreqOutTest(BaseAddress, Frequency); m_RealEdit.Format("%f", Temp); } else if (m_FeatureRadio == 2) { EventCountTest(BaseAddress, INITIALIZE + START); } else if (m_FeatureRadio == 3) { if (!PulseWidthRunning) { m_StartButtonCtrl.SetWindowText("Stop Measure"); PulseWidthRunning = true; PulseWidthTimer = SetTimer(2, 1000, NULL); } else { m_StartButtonCtrl.SetWindowText("Start Measure"); PulseWidthRunning = false; KillTimer(PulseWidthTimer); } } UpdateData(false); } } void CF8254Dlg::OnTimer(UINT nIDEvent) { if (nIDEvent == FreqInTimer) { unsigned secondcount; unsigned long timeout; long returnval; timeout = 65535; CtrMode(BaseAddress, 1, 3); // 0111 0110 ctr1 mode3, LSB/MSB CtrLoad(BaseAddress, 1, 0xFFFE); // load LSB and MSB values into // ctr1 to make slow input to gate 0 while ((ReadStatus(BaseAddress) == 1) && (timeout != 0)) timeout--; // out ctr1 = 1 timeout = 65535; CtrMode(BaseAddress, 0, 2); // 0011 0100 ctr0 mode 2 L/M CtrLoad(BaseAddress, 0, 0xFFFF); // load 65535 into ctr 0 while ((ReadStatus(BaseAddress) == 0) && (timeout != 0)) timeout--; // ctr1 still 0 timeout = 65535; while ((ReadStatus(BaseAddress) == 1) && (timeout != 0)) timeout--; // ctr1 = 1 secondcount = ReadCounter0(BaseAddress); // read value of counter returnval = long((65535 - secondcount)/0.032767); // convert from counts to f m_FreqInEdit.Format("%d", returnval); } else if (nIDEvent == PulseWidthTimer) { const TIMEOUTVAL = 150000; unsigned long temp, secondcount, previouscount; unsigned long timeout, one, two; CtrMode(BaseAddress, 2, 2); // ctr2 mode2 CtrLoad(BaseAddress, 2, 0xFFFF); // write 65535 to counter 2 CtrMode(BaseAddress, 1, 2); // ctr1 mode2 CtrLoad(BaseAddress, 1, 0xFFFF); // write 65535 to counter 1 temp = ReadCounter1(BaseAddress); // read the counter timeout = 0; //the following two repeat-until loops ensure a high transition has happened //(a high on gate input reloads the counter) do { previouscount = temp; temp = ReadCounter1(BaseAddress); timeout++; } while ((temp != previouscount) && (timeout < TIMEOUTVAL)); one = ReadCounter2(BaseAddress); if (timeout < TIMEOUTVAL) timeout = 0; do { secondcount = ReadCounter1(BaseAddress); timeout++; } while ((temp == secondcount) && (timeout < TIMEOUTVAL)); if (timeout < TIMEOUTVAL) timeout = 0; // wait until the counts stop (low on the gate again) do { previouscount = secondcount; secondcount = ReadCounter1(BaseAddress); timeout++; } while ((secondcount != previouscount) && (timeout < TIMEOUTVAL)); two = ReadCounter2(BaseAddress); if (timeout < TIMEOUTVAL) m_PulseEdit.Format("%d", ((one - two) * 65536 + (65535 - secondcount))); // return the counts for the pulse else m_PulseEdit = "0"; } UpdateData(false); CDialog::OnTimer(nIDEvent); } void CF8254Dlg::CtrMode(unsigned int Base, unsigned int cntr, unsigned int mode) { BYTE ctrl; ctrl = (cntr << 6) | 0x30 | (mode << 1); OutPortB(Base + 3, ctrl); } void CF8254Dlg::CtrLoad(unsigned int Base, unsigned int c, unsigned short val) { BYTE temp; temp = val & 0x00FF; OutPortB(Base + c, temp); temp = (val & 0xFF00) >> 8; OutPortB(Base + c, temp); } // NOTE: CtrRead isn't actually used in this sample, but it is here for reference unsigned CF8254Dlg::CtrRead(unsigned int Base, unsigned int c) { OutPortB(Base + 3, c << 6); return InPortB(Base + c) + (InPortB(Base + c) << 8); } unsigned CF8254Dlg::ReadStatus(unsigned int Base) { OutPortB(Base + 3, 0xE4); // 1110 0100 ReadBack for ctr1 return InPortB(Base + 1) >> 7; // ctr1 output } void CF8254Dlg::InitCounter(unsigned int Base) { CtrMode(Base, 0, 0); // 0011 0000 ctr0 LSB/MSB mode 0 CtrLoad(Base, 0, 0xFFFF); // load 65535 into ctr0 } unsigned CF8254Dlg::ReadCounter0(unsigned int Base) { unsigned LSB, MSB; OutPortB(Base + 3, 0xD2); // 1101 0010 RB ctr0 latch LSB = InPortB(Base); // LSB of ctr0 MSB = InPortB(Base); // MSB of ctr0 return (MSB << 8) + LSB; // values at ctr1 = 0 } unsigned long CF8254Dlg::ReadCounter1(unsigned int Base) { unsigned LSB, MSB; OutPortB(Base + 3, 0xD4); // 1101 0100 Read Back counts ctr1 LSB = InPortB(Base + 1); // ctr1 counts LSB MSB = InPortB(Base + 1); // ctr1 counts MSB return (MSB << 8) + LSB; } unsigned long CF8254Dlg::ReadCounter2(unsigned int Base) { unsigned LSB, MSB; OutPortB(Base + 3, 0xD8); // 1101 1000 Read Back counts ctr2 LSB = InPortB(Base + 2); // ctr1 counts LSB MSB = InPortB(Base + 2); // ctr1 counts MSB return (MSB << 8) + LSB; } void CF8254Dlg::OnFreqInRadioClick() { m_StartButtonCtrl.EnableWindow(true); KillTimer(FreqInTimer); KillTimer(PulseWidthTimer); m_FreqInLabelCtrl.ShowWindow(SW_SHOW); m_FreqInEditCtrl.ShowWindow(SW_SHOW); m_FreqOutLabelCtrl.ShowWindow(SW_HIDE); m_FreqOutEditCtrl.ShowWindow(SW_HIDE); m_RealLabelCtrl.ShowWindow(SW_HIDE); m_RealEditCtrl.ShowWindow(SW_HIDE); m_EventCountLabelCtrl.ShowWindow(SW_HIDE); m_EventCountEditCtrl.ShowWindow(SW_HIDE); m_EventTestButtonCtrl.ShowWindow(SW_HIDE); m_SinceFirstButtonCtrl.ShowWindow(SW_HIDE); m_SinceLastButtonCtrl.ShowWindow(SW_HIDE); m_PulseLabelCtrl.ShowWindow(SW_HIDE); m_PulseEditCtrl.ShowWindow(SW_HIDE); m_FeatureRadio = 0; m_StartButtonCtrl.SetWindowText("Start Input"); m_Instructions = "Instructions:"; InsCR(m_Instructions); m_Instructions += "Choose which feature of the 8254 chip to demonstrate with the radio buttons at the top of the form, and enter the chip's base address above."; InsCR(m_Instructions); m_Instructions += "Frequency Measurement requires CTR0 Gate controlled by CTR1 Output and a 1MHz clock input to CTR1. Bring the the frequency you want to measure into Counter 0 input."; InsCR(m_Instructions); m_Instructions += "Click the 'Start Measure' button to demonstrate the frequency measuring feature. The measured frequency will be displayed in the text box."; UpdateData(false); } void CF8254Dlg::OnFreqOutRadio() { m_StartButtonCtrl.EnableWindow(true); KillTimer(FreqInTimer); KillTimer(PulseWidthTimer); m_FreqInLabelCtrl.ShowWindow(SW_HIDE); m_FreqInEditCtrl.ShowWindow(SW_HIDE); m_FreqOutLabelCtrl.ShowWindow(SW_SHOW); m_FreqOutEditCtrl.ShowWindow(SW_SHOW); m_RealLabelCtrl.ShowWindow(SW_SHOW); m_RealEditCtrl.ShowWindow(SW_SHOW); m_EventCountLabelCtrl.ShowWindow(SW_HIDE); m_EventCountEditCtrl.ShowWindow(SW_HIDE); m_EventTestButtonCtrl.ShowWindow(SW_HIDE); m_SinceFirstButtonCtrl.ShowWindow(SW_HIDE); m_SinceLastButtonCtrl.ShowWindow(SW_HIDE); m_PulseLabelCtrl.ShowWindow(SW_HIDE); m_PulseEditCtrl.ShowWindow(SW_HIDE); m_FeatureRadio = 1; m_StartButtonCtrl.SetWindowText("Start Input"); m_Instructions = "Instructions:"; InsCR(m_Instructions); m_Instructions += "Choose which feature of the 8254 chip to demonstrate with the radio buttons at the top of the form, and enter the chip's base address above."; InsCR(m_Instructions); m_Instructions += "Frequency Generation requires a 1MHz input to CTR1, and CTR1 Output connected to CTR2 Clock, as well as both CTR1 & CTR2 Gates enabled. The frequency will be generated from Counter 2 output."; InsCR(m_Instructions); m_Instructions += "To demonstrate the frequency output feature, enter the desired output frequency in the text box (between 1Hz and 250000Hz), then click the 'Start Output' button."; InsCR(m_Instructions); m_Instructions += "The actual output frequency will be also be displayed."; UpdateData(false); } void CF8254Dlg::OnEventCountRadio() { m_StartButtonCtrl.EnableWindow(true); KillTimer(FreqInTimer); KillTimer(PulseWidthTimer); m_FreqInLabelCtrl.ShowWindow(SW_HIDE); m_FreqInEditCtrl.ShowWindow(SW_HIDE); m_FreqOutLabelCtrl.ShowWindow(SW_HIDE); m_FreqOutEditCtrl.ShowWindow(SW_HIDE); m_RealLabelCtrl.ShowWindow(SW_HIDE); m_RealEditCtrl.ShowWindow(SW_HIDE); m_EventCountLabelCtrl.ShowWindow(SW_SHOW); m_EventCountEditCtrl.ShowWindow(SW_SHOW); m_EventTestButtonCtrl.ShowWindow(SW_SHOW); m_SinceFirstButtonCtrl.ShowWindow(SW_SHOW); m_SinceLastButtonCtrl.ShowWindow(SW_SHOW); m_PulseLabelCtrl.ShowWindow(SW_HIDE); m_PulseEditCtrl.ShowWindow(SW_HIDE); m_FeatureRadio = 2; m_StartButtonCtrl.SetWindowText("Start Input"); m_Instructions = "Instructions:"; InsCR(m_Instructions); m_Instructions += "Choose which feature of the 8254 chip to demonstrate with the radio buttons at the top of the form, and enter the chip's base address above."; InsCR(m_Instructions); m_Instructions += "Event Counting requires CTR0 Gate enabled, or connected to CTR1. Bring your pulse train in on Counter 0 input."; InsCR(m_Instructions); m_Instructions += "Click the 'Start Counting' button to demonstrate the event counting feature. Use the 'Since First' and 'Since Last' buttons to display the event counts since starting the demo, and since the last reading, respectively."; InsCR(m_Instructions); m_Instructions += "Use the 'Stop & Reset' button to stop the demo, and reset the count."; UpdateData(false); } void CF8254Dlg::OnPulseWidthRadio() { m_StartButtonCtrl.EnableWindow(true); KillTimer(FreqInTimer); KillTimer(PulseWidthTimer); m_FreqInLabelCtrl.ShowWindow(SW_HIDE); m_FreqInEditCtrl.ShowWindow(SW_HIDE); m_FreqOutLabelCtrl.ShowWindow(SW_HIDE); m_FreqOutEditCtrl.ShowWindow(SW_HIDE); m_RealLabelCtrl.ShowWindow(SW_HIDE); m_RealEditCtrl.ShowWindow(SW_HIDE); m_EventCountLabelCtrl.ShowWindow(SW_HIDE); m_EventCountEditCtrl.ShowWindow(SW_HIDE); m_EventTestButtonCtrl.ShowWindow(SW_HIDE); m_SinceFirstButtonCtrl.ShowWindow(SW_HIDE); m_SinceLastButtonCtrl.ShowWindow(SW_HIDE); m_PulseLabelCtrl.ShowWindow(SW_SHOW); m_PulseEditCtrl.ShowWindow(SW_SHOW); m_FeatureRadio = 3; m_StartButtonCtrl.SetWindowText("Start Input"); m_Instructions = "Instructions:"; InsCR(m_Instructions); m_Instructions += "Choose which feature of the 8254 chip to demonstrate with the radio buttons at the top of the form, and enter the chip's base address above."; InsCR(m_Instructions); m_Instructions += "Pulse Width Measurement requires a 1MHz input to CTR1. Bring the the signal you want to measure into Gate 1."; InsCR(m_Instructions); m_Instructions += "Click the 'Start Measure' button to demonstrate the pulse width measuring feature. The measured pulse width will be displayed in the text box."; UpdateData(false); } double CF8254Dlg::FreqOutTest(unsigned int Base, unsigned long Frequency) { unsigned short countsA, countsB, x, temp; //unsigned long temp; double trash, Result; x = 2; Result = 0; if ((Frequency > 250000) || (Frequency < 1)) return 0; // return if freq is too low/high trash = Frequency; // convert to float for division trash = 1000000/trash; // calculate the number of counts temp = unsigned short(trash); // round to the nearest count do { // try to divide the counts countsA = x; // evenly between the two counters x++; } while ( ((temp % countsA) != 0) && (countsA < temp) && (countsA < 65535) ); // exit if counts too high if ((countsA >= temp) && (temp < 131070)) { // gone through all vals countsA = 2; // counter can only hold 65535 countsB = temp / 2; } else { if (temp >= 131070) { // counts too high to fit in counter countsA = 20; // divide to make fit countsB = temp / 20; } else countsB = temp / countsA; // if found divisor use it } CtrMode(Base, 2, 3); // 1011 1110 ctr2 mode3 CtrLoad(Base, 2, countsA); CtrMode(Base, 1, 2); // 0111 0100 ctr1 mode2 CtrLoad(Base, 1, countsB); Result = 1000000.0 / (countsA * countsB); return Result; } unsigned CF8254Dlg::EventCountTest(unsigned int Base, int Feature) { static unsigned previousmeasure = 0; unsigned currentmeasure, returnvalue; bool flag; flag = false; returnvalue = 0; currentmeasure = 0; if (INITIALIZE & Feature) // 1 InitCounter(Base); // init counter0 to count in mode 0 if (START & Feature) // 2 CtrMode(Base, 1, 1); // 0111 0010 ctr1 LSB/MSB mode 1 // to hold gate of ctr0 high if (SINCESTART & Feature) { // 4 if (!flag) { // counts down from 65535 currentmeasure = 65535 - ReadCounter0(Base); flag = true; // flag read counter } returnvalue = currentmeasure; // set value to return } if (SINCELAST & Feature) { // 8 if (!flag) { // calculate counts currentmeasure = 65535 - ReadCounter0(Base); flag = true; } // calculate since last returnvalue = currentmeasure - previousmeasure; } if (STOP & Feature) // 16 CtrMode(Base, 1, 0); // 0111 0000 ctr1 mode0 out=0 if (RESET & Feature) { // 32 InitCounter(Base); // init counter to 65535 previousmeasure = 0; // no previous counts } if (flag) { // set previous measure if counter read previousmeasure = currentmeasure; return returnvalue; // if counter read return value } else return 0; // return 0 if counter not read } void CF8254Dlg::OnSinceFirstButtonClick() { m_EventCountEdit.Format("%u", EventCountTest(BaseAddress, SINCESTART)); UpdateData(false); } void CF8254Dlg::OnSinceLastButtonClick() { m_EventCountEdit.Format("%u", EventCountTest(BaseAddress, SINCELAST)); UpdateData(false); } void CF8254Dlg::OnEventTestButtonClick() { EventCountTest(BaseAddress, STOP + RESET); }