#include "StdAfx.h"
#include "buttonInterface.h"
// 1-wire iButton Interface Example
// Identifying iButtons in a worker thread without colliding with application thread nvram read/write operations
/*
file:///C:/Program%20Files/Dallas%20Semiconductor/1-Wire%20SDK%20V4.00%20Beta/Docs/TMEX/tmwi5ur7.html
Windows 95 98 and Me
Type# Port Driver Name Description
1 COM IB97E32.DLL uses the DS9097E adapter on COM ports
2 LPT IB10E32.DLL uses the DS1410E adapter on LPT ports
5 COM IB97U32.DLL uses the DS9097U adapter on COM ports
6 USB IB90USB.DLL uses the DS1490 adapter on USB ports (compatible with Windows 98 and Me only)
Windows NT 2000 XP
Type# Port Driver Name Description
1 COM IB97E32.DLL uses the DS9097E adapter on COM ports
2 LPT IB10E32.DLL uses the DS1410E adapter on LPT ports
5 COM IB97U32.DLL uses the DS9097U adapter on COM ports
6 USB IB90USB.DLL uses the DS1490 adapter on USB ports (compatible with 2000 and XP only)
*/
ButtonInterface::ButtonInterface(void) : hSess(0), endMonitor(false), pauseMonitor(false), monitorActive(false)
{
InitializeCriticalSection(&cs);
notificationAdded=RegisterWindowMessage("iButtonNotification_ButtonAdded");
notificationRemoved=RegisterWindowMessage("iButtonNotification_ButtonRemoved");
QueryPerformanceFrequency(&freq);
hInst = LoadLibrary("IBFS32.DLL");
if (hInst != NULL)
{
TMExtendedStartSession=(long (far pascal *)(short,short,void far *))GetProcAddress(hInst, "TMExtendedStartSession");
TMReadDefaultPort=(short (far pascal *)(short far*, short far*))GetProcAddress(hInst, "TMReadDefaultPort");
TMSetup=(short (far pascal *)(long))GetProcAddress(hInst, "TMSetup");
TMEndSession=(short (far pascal *)(long))GetProcAddress(hInst, "TMEndSession");
TMFirst=(short (far pascal *)(long, void far*))GetProcAddress(hInst, "TMFirst");
TMNext=(short (far pascal *)(long, void far*))GetProcAddress(hInst, "TMNext");
TMRom=(short (far pascal *)(long, void far*, short far*))GetProcAddress(hInst, "TMRom");
TMAccess=(short (far pascal *)(long, void far*))GetProcAddress(hInst, "TMAccess");
TMStrongAccess=(short (far pascal *)(long, void far*))GetProcAddress(hInst, "TMStrongAccess");
TMTouchByte=(short (far pascal *)(long, short))GetProcAddress(hInst, "TMTouchByte");
TMBlockStream=(short (far pascal *)(long, unsigned char far*, short))GetProcAddress(hInst, "TMBlockStream");
// nvram devices only
TMWritePacket=(short (far pascal *)(long, void far*, short, unsigned char far*, short))GetProcAddress(hInst, "TMWritePacket");
TMReadPacket=(short (far pascal *)(long, void far*, short, unsigned char far*, short))GetProcAddress(hInst, "TMReadPacket");
}
}
ButtonInterface::~ButtonInterface(void)
{
endMonitor=true;
while (monitorActive) {};
FreeLibrary(hInst);
DeleteCriticalSection(&cs);
}
bool ButtonInterface::StartSession(void)
{
if (hInst != NULL)
{
short portNum;
short portType;
TMReadDefaultPort(&portNum, &portType);
hSess=TMExtendedStartSession(portNum, portType, NULL);
if (hSess != 0)
{
// must be called before any non-session functions can be called
TMSetup(hSess);
}
}
return hSess != 0;
}
void ButtonInterface::EndSession(void)
{
if (hSess > 0)
{
endMonitor=true;
while (monitorActive) {};
TMEndSession(hSess);
hSess=NULL;
}
}
void ButtonInterface::StartMonitor(int msSleep, int debounce)
{
if (hSess > 0)
{
sleepTime=msSleep;
debounceTime=debounce;
AfxBeginThread(MonitorThreadStartup, this);
}
}
UINT ButtonInterface::MonitorThreadStartup(void* v)
{
ButtonInterface* btn=(ButtonInterface*)v;
btn->Monitor();
return 0;
}
void ButtonInterface::BeginIO(void)
{
EnterCriticalSection(&cs);
}
void ButtonInterface::EndIO(void)
{
LeaveCriticalSection(&cs);
}
bool ButtonInterface::SelectDevice(CString romCode)
{
short ROM[9]; // leave room for 32 bit value
for (int i=7; i>=0; i--)
{
CString hex=romCode.Mid(i*2, 2);
sscanf(hex, "%02X", &ROM[7-i]);
}
TMRom(hSess, stateBuffer, ROM);
int n=TMAccess(hSess, stateBuffer);
return n==1;
}
bool ButtonInterface::SelectDeviceStrong(CString romCode)
{
short ROM[9]; // leave room for 32 bit value
for (int i=7; i>=0; i--)
{
CString hex=romCode.Mid(i*2, 2);
sscanf(hex, "%02X", &ROM[7-i]);
}
TMRom(hSess, stateBuffer, ROM);
int n=TMStrongAccess(hSess, stateBuffer);
return n==1;
}
bool ButtonInterface::ReadPage(int page, unsigned char* data, int len)
{
if (len > 32) return false;
TMAccess(hSess, stateBuffer);
TMTouchByte(hSess, 0xF0);
TMTouchByte(hSess, (short)((page*32)&0xFF));
TMTouchByte(hSess, (short)((page*32)>>8));
for (int i=0; i<len; i++)
{
data[i]=(unsigned char)TMTouchByte(hSess, 0xFF);
}
return true;
}
bool ButtonInterface::WritePage(int page, unsigned char* data, int len)
{
if (len > 32) return false;
// write to scratchpad
TMAccess(hSess, stateBuffer);
TMTouchByte(hSess, 0x0F);
TMTouchByte(hSess, (short)((page*32)&0xFF));
TMTouchByte(hSess, (short)((page*32)>>8));
TMBlockStream(hSess, data, (short)len);
// get target address and ending offset/data status byte
TMAccess(hSess, stateBuffer);
TMTouchByte(hSess, 0xAA);
unsigned char auth[3];
for (int i=0; i<3; i++)
{
auth[i]=(unsigned char)TMTouchByte(hSess, 0xFF);
}
// copy scratchpad to memory
TMAccess(hSess, stateBuffer);
TMTouchByte(hSess, 0x55);
for (int i=0; i<3; i++)
{
TMTouchByte(hSess, auth[i]);
}
return true;
}
int ButtonInterface::GetButtonList(CString* codes)
{
short ret=TMFirst(hSess, stateBuffer);
int n=0;
while ( (ret==1) && (n<32) )
{
// if MSB of ROM[0] != 0, then write, else read
short ROM[8]={0, 0, 0, 0, 0, 0, 0, 0};
TMRom(hSess, stateBuffer, ROM);
// convert the ROM code into a string
char s[3]="\0\0";
CString romCode="";
for (int i=7; i>=0; i--)
{
sprintf(s, "%02X", ROM[i]);
romCode+=s;
}
codes[n]=romCode;
++n;
ret=TMNext(hSess, stateBuffer);
}
return n;
}
void ButtonInterface::Monitor(void)
{
CString* codes=new CString[32];
monitorActive=true;
while (!endMonitor)
{
Sleep(sleepTime);
if (pauseMonitor)
{
continue;
}
EnterCriticalSection(&cs);
// untouch all buttons in list
std::map<CString, ButtonInfo>::iterator iter=buttonInfo.begin();
while (iter != buttonInfo.end())
{
(*iter).second.touched=false;
++iter;
}
int numButtons=GetButtonList(codes);
// touch all found devices
for (int i=0; i<numButtons; i++)
{
CString romCode=codes[i];
iter=buttonInfo.find(romCode);
if (iter != buttonInfo.end())
{
(*iter).second.touched=true;
QueryPerformanceCounter(&(*iter).second.currentSampleTime);
}
else
{
buttonInfo[romCode]=ButtonInfo();
}
}
// Debounce all activity
// 1. If a button is new, then issue an add notification immediately
// 2. If a button hasn't been "touched" for the debounce time, then issue a remove notification
LARGE_INTEGER sampleTime;
QueryPerformanceCounter(&sampleTime);
iter=buttonInfo.begin();
while (iter != buttonInfo.end())
{
CString code=(*iter).first;
ButtonInfo& bi=(*iter).second;
if (bi.newButton)
{
PostNotification(notificationAdded, (*iter).first);
bi.newButton=false;
}
else
if (bi.touched==false)
{
if (sampleTime.QuadPart-bi.currentSampleTime.QuadPart > freq.QuadPart*debounceTime/1000)
{
PostNotification(notificationRemoved, (*iter).first);
buttonInfo.erase(iter);
break;
}
}
++iter;
}
LeaveCriticalSection(&cs);
}
endMonitor=false;
delete[] codes;
monitorActive=false;
}
void ButtonInterface::PostNotification(UINT msg, CString code)
{
CString* data=new CString(code);
AfxGetApp()->PostThreadMessage(msg, 0, (LPARAM)data);
}