Click here to Skip to main content
15,896,118 members
Articles / Desktop Programming / MFC

A Basic iButton Interface

Rate me:
Please Sign up or sign in to vote.
4.48/5 (27 votes)
7 Mar 2003CPOL13 min read 196.9K   2.7K   49  
An Example Of How To Interface To Dallas Semiconductor's iButton And 1-Wire Network
#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);
}


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions