|
|
#include "App.h"
#include "BaseWindow.h"
#include "ConsoleBaseWindow.h"
#include "ConsoleWindow.h"
#include "UsbThread.h"
#include "AppWindow.h"
#include "ByteBuffer.h"
class App::Private
{
public:
Private()
: usb(::GetCurrentThreadId())
{
//
}
AppWindow win;
UsbThread usb;
ByteBuffer buf;
} ;
//-------------------------
App::App()
: impl(* new App::Private)
{
impl.win.SetMessage("Press 'f' to freeze");
}
App::~App()
{
impl.usb.End();
delete &impl;
}
byte* App::Buffer()
{
return impl.buf.in;
}
void App::Show()
{
impl.win.Init(*this);
impl.usb.Start();
impl.win.Show();
}
int App::ReturnCode()
{
return impl.win.ReturnCode();
}
void App::ProcessByte(byte v)
{
impl.buf.Prepend(v);
impl.win.Redraw();
}
void App::Freeze()
{
impl.usb.Freeze();
impl.win.SetMessage("Press 'u' to unfreeze");
}
void App::Unfreeze()
{
impl.usb.Unfreeze();
impl.win.SetMessage("Press 'f' to freeze");
}
|
|
|
#pragma once
#include "common.h"
class App
{
public:
App();
~App();
void Show();
int ReturnCode();
void ProcessByte(byte v);
byte* Buffer();
void Freeze();
void Unfreeze();
private:
class Private;
Private& impl;
} ;
|
|
|
#include "AppWindow.h"
#include "App.h"
#include "UsbThread.h"
//-------------------------
void AppWindow::Init(App& a)
{
mApp = &a;
Register(UsbThread::WM_BYTE, (TranslateFunc) &AppWindow::OnByte);
}
void AppWindow::OnByte(WPARAM wparam, LPARAM lparam)
{
mApp->ProcessByte((byte) wparam);
}
//override OnChar
void AppWindow::OnChar(WPARAM wparam, LPARAM lparam)
{
switch ((char) wparam)
{
case 'f': mApp->Freeze(); break;
case 'u': mApp->Unfreeze(); break;
case 'q': PostQuitMessage(0); break;
}
}
//override OnPaint
void AppWindow::OnPaint(WPARAM wparam, LPARAM lparam)
{
Draw(mApp->Buffer());
}
|
|
|
#pragma once
#include "ConsoleWindow.h"
class App;
class AppWindow : public ConsoleWindow
{
public:
AppWindow() : mApp(0)
{
//nothing
}
void Init(App& c);
void OnByte(WPARAM wparam, LPARAM lparam);
void OnChar(WPARAM wparam, LPARAM lparam);
void OnPaint(WPARAM wparam, LPARAM lparam);
private:
App* mApp;
} ;
|
|
|
#pragma once
//-------------------------
#include <wtypes.h>
class BaseThread
{
public:
//----
BaseThread()
{
}
//----
void Start()
{
::CreateThread(0, 0, theThread, (LPVOID) this, 0, &mTid);
}
virtual long Run() = 0;
private:
//----
static DWORD WINAPI theThread(LPVOID parm)
{
return ((BaseThread*) parm)->Run();
}
private:
DWORD mTid;
} ;
|
|
|
#pragma once
#include <wtypes.h>
#include <map>
class BaseWindow
{
public:
typedef void (BaseWindow::* TranslateFunc) (WPARAM, LPARAM);
int ReturnCode()
{
return mReturnCode;
}
void Register(UINT msg, TranslateFunc f)
{
//only one handler per message id
//todo: multiple handlers
mMap[msg] = f;
}
virtual void Redraw()
{
PostMessage(0, WM_PAINT, 0, 666);
}
//overridable
//return true to skip message handling and wait for next message
virtual bool PreHandler(UINT id, WPARAM wparam, LPARAM lparam)
{
//do nothing
return false;
}
//overridable:
//handle unknown messages
virtual void UnknownHandler(UINT id, WPARAM wparam, LPARAM lparam)
{
//do nothing
}
//default handlers
virtual void OnChar(WPARAM wparam, LPARAM lparam)
{
//do nothing
}
virtual void OnQuit(WPARAM wparam, LPARAM lparam)
{
mReturnCode = 0;
}
virtual void OnPaint(WPARAM wparam, LPARAM lparam)
{
//do nothing
}
virtual void OnDestroy(WPARAM wparam, LPARAM lparam)
{
PostQuitMessage(0);
}
void Show()
{
//load remaining handlers
LoadMap();
MSG msg;
while (::GetMessage(&msg, 0, 0, 0))
{
::TranslateMessage(&msg);
this->Dispatch(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
}
LRESULT Dispatch(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (PreHandler(message, wParam, lParam))
return 0;
TranslateMap::iterator it = mMap.find(message);
if (it == mMap.end())
return ::DefWindowProc(hwnd, message, wParam, lParam);
TranslateFunc f = (*it).second;
(this->*f)(wParam, lParam);
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
private:
void LoadMap()
{
Register(WM_CHAR, &BaseWindow::OnChar);
Register(WM_QUIT, &BaseWindow::OnQuit);
Register(WM_PAINT, &BaseWindow::OnPaint);
Register(WM_DESTROY, &BaseWindow::OnDestroy);
}
private:
typedef std::map<UINT, TranslateFunc> TranslateMap;
TranslateMap mMap;
int mReturnCode;
} ;
|
|
|
#pragma once
//-------------------------
class ByteBuffer
{
public:
ByteBuffer()
{
memset(in, 0x0, sizeof(in));
}
void Prepend(byte v)
{
for (int j = 19; j > 0; --j)
{
in[j] = in[j-1];
}
in[0] = v;
}
byte in[20];
} ;
|
|
|
#pragma once
typedef unsigned char byte;
|
|
|
#include <conio.h>
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
#include "ConsoleBaseWindow.h"
ConsoleBaseWindow::ConsoleBaseWindow()
: mKB(::GetCurrentThreadId())
{
mKB.Start();
outh = ::GetStdHandle(STD_OUTPUT_HANDLE);
Clear();
}
void ConsoleBaseWindow::Clear()
{
CONSOLE_SCREEN_BUFFER_INFO info;
::GetConsoleScreenBufferInfo(outh, &info);
int cols = info.srWindow.Right;
int rows = info.srWindow.Bottom;
Home();
string blank;
blank.resize(cols, ' ');
for(int r = 0; r < rows; ++r)
cout << blank << endl;
}
void ConsoleBaseWindow::Home()
{
COORD coord;
coord.X = 0;
coord.Y = 0;
::SetConsoleCursorPosition(outh, coord);
}
void ConsoleBaseWindow::Write(int c)
{
::putch(c);
}
void ConsoleBaseWindow::Writeln()
{
cout << endl;
}
void ConsoleBaseWindow::Write(const std::string& msg)
{
cout << msg;
}
void ConsoleBaseWindow::Writeln(const std::string& msg)
{
Write(msg);
Writeln();
}
void ConsoleBaseWindow::WriteHexByte(unsigned char b)
{
//todo: save the format flags
cout << uppercase << hex << setfill('0') << setw(2) << (int) b;
//todo: reset the format flags
}
|
|
|
#pragma once
#include <string>
#include "BaseWindow.h"
#include "KeyboardThread.h"
class ConsoleBaseWindow : public BaseWindow
{
public:
ConsoleBaseWindow();
void Clear();
void Home();
void Write(int c);
void Writeln();
void Write(const std::string& msg);
void Writeln(const std::string& msg);
void WriteHexByte(unsigned char b);
private:
HANDLE outh;
KeyboardThread mKB;
} ;
|
|
|
#include <string>
using namespace std;
#include "ConsoleWindow.h"
void ConsoleWindow::SetMessage(const string& s)
{
msg = s;
msg.resize(80, ' ');
this->Redraw();
}
//redraws the screen
void ConsoleWindow::Draw(byte* buf)
{
Home();
HeaderRow(buf);
for (int r = 0; r < 8; ++r)
{
byte mask = (byte) (0x80 >> r);
RowStart();
Row(buf, mask);
NextLine();
}
MessageRow();
}
void ConsoleWindow::Row(byte* in, byte mask)
{
bool lastbit = ((in[0] & mask) == 0) ? false : true;
for (int c = 0; c < 20; ++c)
{
bool bit = ((in[c] & mask) == 0) ? false : true;
if (lastbit && bit)
putHi();
else if (!lastbit && !bit)
putLo();
else if (lastbit && !bit)
putHi2Lo();
else // !lastbit && bit
putLo2Hi();
lastbit = bit;
}
}
void ConsoleWindow::RowStart()
{
Write('[');
}
void ConsoleWindow::HeaderRow(byte* in)
{
Write(' ');
for (int c = 0; c < 20; ++c)
{
WriteHexByte(in[c]);
Write(' ');
}
Writeln();
}
void ConsoleWindow::MessageRow()
{
Writeln(msg);
}
void ConsoleWindow::NextLine()
{
Writeln();
Writeln();
}
//waveform : a segment of the wave is 3 characters wide
//show the segment was hi
void ConsoleWindow::putHi()
{
writeHi();
writeHi();
writeHi();
}
//show the segment was lo
void ConsoleWindow::putLo()
{
writeLo();
writeLo();
writeLo();
}
//show the segment transitioned from hi to lo
void ConsoleWindow::putHi2Lo()
{
writeHi();
writeLo();
writeLo();
}
//show the segment transitioned from lo to hi
void ConsoleWindow::putLo2Hi()
{
writeLo();
writeHi();
writeHi();
}
//a lo is the underbar
void ConsoleWindow::writeLo()
{
Write('_');
}
//a hi is a graphic character similar to an underbar
void ConsoleWindow::writeHi()
{
Write(0xC4);
}
|
|
|
#pragma once
#include <string>
#include "ConsoleBaseWindow.h"
class ConsoleWindow : public ConsoleBaseWindow
{
public:
void SetMessage(const std::string& s);
void Draw(byte* buf);
private:
void Row(byte* in, byte mask);
void RowStart();
void HeaderRow(byte* in);
void MessageRow();
void NextLine();
void putHi();
void putLo();
void putHi2Lo();
void putLo2Hi();
void writeLo();
void writeHi();
private:
std::string msg;
};
|
|
|
#pragma once
#include <string>
#include <wtypes.h>
class FT_Exception
{
public:
FT_Exception(const std::string& m, ULONG rc)
: Msg(m), RC(rc)
{
}
std::string Msg;
ULONG RC;
} ;
|
|
|
//uncomment to turn on tracing
//#define TRACEON
#include "Tracer.h"
#include "App.h"
//-------------------------
int main()
{
App app;
app.Show();
return app.ReturnCode();
}
|
|
|
#include <conio.h>
#include "KeyboardThread.h"
KeyboardThread::KeyboardThread(DWORD tid)
: mParentThreadId(tid)
{
}
//----
long KeyboardThread::Run()
{
for (;;)
{
Sleep(100); //check every 100 ms for a keyboard hit
if (! ::kbhit())
continue;
PostThreadMessage(mParentThreadId, WM_CHAR, getch(), 0);
}
}
|
|
|
#pragma once
//-------------------------
#include "BaseThread.h"
class KeyboardThread : public BaseThread
{
public:
KeyboardThread(DWORD tid);
long Run();
private:
DWORD mParentThreadId;
} ;
|
|
|
#pragma once
#ifdef TRACEON
#include <fstream>
#include <string>
class Tracer
{
public:
Tracer()
{
mFile.open("out.txt", ios::out);
}
void Write(const std::string& s)
{
mFile.write(s.c_str(), (std::streamsize) s.size());
mFile.write("\n", 1);
mFile.flush();
}
~Tracer()
{
mFile.close();
}
private:
std::fstream mFile;
} ;
const std::string toString(long i)
{
char buf[20];
sprintf(buf, "%ld", i);
return buf;
}
const std::string toString(HWND i)
{
char buf[20];
sprintf(buf, "0x%8.8X", (long) i);
return buf;
}
Tracer gTrace;
#define TRACE(s) gTrace.Write(s)
#else
#define TRACE(s)
#endif
|
|
|
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string>
using std::string;
#pragma comment (lib, "FTD2XX.lib")
#include "FTD2XX.H"
#include "common.h"
#include "FtException.h"
#include "UsbBoard.h"
class UsbBoard::Private
{
public:
Private() : mHandle(0)
{
}
FT_HANDLE mHandle;
} ;
//-------------------------
UsbBoard::UsbBoard()
: impl(* new UsbBoard::Private)
{
}
UsbBoard::~UsbBoard()
{
delete &impl;
}
//----
int UsbBoard::NumDevs()
{
DWORD numDevs = 0;
FT_STATUS ftStatus = FT_ListDevices(&numDevs, 0, FT_LIST_NUMBER_ONLY);
if (ftStatus != FT_OK)
throw new FT_Exception("FAILED: FT_ListDevices", ftStatus);
//cout << "NumDevs: " << numDevs << "\n";
return numDevs;
}
//----
string UsbBoard::ConvertRC(ULONG rc)
{
switch (rc)
{
case 0: return "OK";
case 1: return "Invalid Handle";
case 2: return "Device Not Found";
default:
char buf[50];
sprintf(buf, "status=", rc);
return buf;
}
}
//----
void UsbBoard::Open(int portnum)
{
if (impl.mHandle != 0)
Close();
FT_STATUS ftStatus = FT_Open(portnum, &impl.mHandle);
if (ftStatus != FT_OK)
{
impl.mHandle = 0;
throw new FT_Exception("FAILED: FT_Open", ftStatus);
}
}
//----
void UsbBoard::Close()
{
if (impl.mHandle == 0) return;
FT_STATUS ftStatus = FT_Close(impl.mHandle);
impl.mHandle = 0;
if (ftStatus != FT_OK)
throw new FT_Exception("FAILED: FT_Close", ftStatus);
}
//----
void UsbBoard::Write()
{
DWORD byteswritten;
DWORD len;
byte buf[20];
buf[0] = 0x01;
buf[1] = 0x65;
buf[2] = 0x64;
len = 3;
FT_STATUS ftStatus = FT_Write(impl.mHandle, buf, len, &byteswritten);
if (ftStatus != FT_OK)
throw new FT_Exception("FAILED: FT_Write", ftStatus);
}
//----
byte UsbBoard::Read()
{
byte buf[20];
DWORD bytestoread = 2;
DWORD bytesread;
FT_STATUS ftStatus = FT_Read(impl.mHandle, buf, bytestoread, &bytesread);
if (ftStatus != FT_OK)
throw new FT_Exception("FAILED: FT_Read", ftStatus);
if (buf[0] != 0x55)
throw new FT_Exception("FAILED: FT_Read bad LRC", buf[0]);
if (bytesread != 2)
throw new FT_Exception("FAILED: FT_Read bytesread!=2", bytesread);
return buf[1];
}
|
|
|
#pragma once
#include <wtypes.h>
#include <string>
//-------------------------
class UsbBoard
{
public:
UsbBoard();
~UsbBoard();
int NumDevs();
static std::string ConvertRC(ULONG rc);
void Open(int portnum);
void Close();
void Write();
byte Read();
private:
class Private;
Private& impl;
} ;
|
|
|
#include <iostream>
#include <iomanip>
using namespace std;
#include "FtException.h"
#include "UsbThread.h"
#include "UsbBoard.h"
//--------------------
UsbThread::UsbThread(DWORD tid)
: mDone(false), mFrozen(false), mParentTid(tid)
{
}
//--------------------
long UsbThread::Run()
{
try
{
UsbBoard usb;
int num = usb.NumDevs();
if (num < 1)
return 1;
usb.Open(0);
while (!mDone)
{
if (!mFrozen)
{
usb.Write();
Send(WM_BYTE, usb.Read());
}
Sleep(100);
}
usb.Close();
}
catch (FT_Exception* ex)
{
cout << "FAILED: (" << ex->RC << ") " << ex->Msg << endl;
}
return 0;
}
//----
void UsbThread::End()
{
mDone = true;
}
//----
void UsbThread::Freeze()
{
mFrozen = true;
}
//----
void UsbThread::Unfreeze()
{
mFrozen = false;
}
void UsbThread::Send(UINT msg, byte v)
{
::PostThreadMessage(mParentTid, msg, (WPARAM) v, 0);
}
|
|
|
#pragma once
#include <wtypes.h>
#include "BaseThread.h"
class UsbThread : public BaseThread
{
public:
enum { WM_BYTE = WM_USER+1, } ;
UsbThread(DWORD tid);
long Run();
void End();
void Freeze();
void Unfreeze();
private:
void Send(UINT msg, byte v);
private:
DWORD mParentTid;
bool mDone;
bool mFrozen;
} ;
|