65.9K
CodeProject 正在变化。 阅读更多。
Home

一个基本的 iButton 接口

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.48/5 (24投票s)

2003 年 3 月 8 日

CPOL

13分钟阅读

viewsIcon

202181

downloadIcon

2754

关于如何连接 Dallas Semiconductor 的 iButton 和 1-Wire 网络的示例。

目录

引言
什么是 iButton
在这里如何使用
iButton 代码加密
NIC 地址加密
许可证时间加密

系统要求
轮询
通知
冲突

Button 接口类
驱动程序初始化
会话启动和终止
获取 1-Wire 设备列表
启动工作线程
暂停和恢复工作线程
在应用程序中处理通知消息
设备选择
NVRAM 读/写函数
设备监控期间的 NVRAM I/O
工作线程
CDialog 通知处理程序

结论

Sample Image - IButtonInterface.jpg

引言

首先,希望本文内容不会冒犯任何人!本文旨在演示一种有趣的技术在一种更]有趣(并且在大多数州都是合法)的行业中的应用。在很多方面,这个行业与其他任何商业形式(想想安然)一样腐败,也]不比其他行业更腐败。由于它受到政府和特殊利益集团的密切]监控,因此它可能比大多数行业]更]负责任。

在成人娱乐行业,跟踪现金交易是一个]可疑的过程。我的客户部分]解决了这个问题,]使用了]一家]名为“iButton”的]有趣的小]设备,由 Dallas Semiconductor 制造(另一部分涉及]分布在]整个]俱乐部]的]定制硬件,]通过]以太网]使用]专有]通信协议)。使用]这种]设备,]计算机]系统]可以]跟踪]舞蹈、]存入]账单]接受器]的]钱、]授权]门]访问]等。该]系统]安装]在]全国各地的]舞厅,]在]许多]情况下,]使]俱乐部的]收入]翻倍,]因为]现在]可以]准确]地]跟踪]舞蹈]收入]。]要]查看]您]附近]的]系统]演示……

如]上]所述,]现金]交易]监控]很]复杂。]支持]两种]现金]交易]模型——“]借记]账户”]和“]贷记]账户”。]以下]图]示]了]这]两种]模型]之间]的]区别。][根据]俱乐部]的要求,]使用]其中]一种]或]另一种]或]两种]方法。

贷记账户

借记账户

在这两种]情况下,]这种]方法]仅]在]存在]激活]包厢、]窗口]或其他]启动]了]表演者]和]客户]之间]定时]交互]的]设备]的]方法]时]才]起作用。]在]表演者]和]客户]之间]直接]接触]的]情况]下],]使用]了]带有]激活]灯]的]包厢]。]这]仍然]需要]检票员],]他们]是]在]俱乐部]里]四处]走动]的]人],]确保]没有]表演者]在]没有]激活]的]情况下]与]客户]在]包厢]里]。]大多数]俱乐部]还有]广泛]的]视频]监控],]这些]监控]被]持续]监控]和]录像]。]有趣]的是],]VHS]磁带]仍]在使用],]而不是]花哨]的]数字]录像机]。]据]解释],]原因]是],]警察]只会]拿]走]磁带]作为]证据],]而]如果]您]有]数字]录像机],]他们]会]拿]走]整个]设备]。

该]系统的]其他]功能]包括]能够]根据]表演者](]由]iButton]标识)]和]激活]点](]包厢]、]包厢]类型]、]淋浴]等)]收取]不同]的]金额]。]这]都]是]因为]表演者]iButton]的]唯一]ID]才]可能]。

什么是 iButton?

iButton]就像]雪花]。]没有]两]个]是]相同]的]。]在]制造]时],]每个]设备]的]只读]内存](]ROM])]中]都]写入]了]一个]唯一]的]8]字节](]64]位])]代码]。]除了]ROM]之外],]iButtons]还有]几种]类型],]其中]许多]包括]非易失性]随机]访问]内存](]NVRAM])、]定时]器]功能]和]实时]时钟]。]有趣]的]设备]包括]解码]环]、]Java]解释器]和]温度]传感器]。]设备]使用]“1-wire”]网络]寻址],]这是]Dallas] Semiconductor]为]支持]iButton]接口]而]设计]的]网络]协议]。

有关]iButtons]的]更多]信息]和]下载]iButton] SDK],]请]访问]此处:] www.ibutton.com

在]本文]中],]我]将]说明

  • 读取 ROM 代码
  • 读取和写入 NVRAM 页面
  • 通过工作线程进行 1-Wire 轮询
  • 自定义对话框通知
  • iButton 去抖

此代码]适用于]所有]支持]NVRAM]的]iButton],]例如]DS1994]。

在这里如何使用?

在我]客户]使用的]软件]中],]使用]带]NVRAM]的]iButton]作为]复制]保护]机制]和]许可证]续订]服务]。]使用的]加密]算法]基于]公共]域]的]“Blowfish”]算法]。]主题]的]CP]文章]在此处]。]验证]加密]的]代码]本身]就]是]加密]的],]并且]由于]它]是用]专有]脚本]语言](]哦],]有机会]推广]AAL])]编写]的],]因此]很难]确定]验证]测试]所]在]的确切]位置],]因为]这]实际上]是]用于]整个]应用程序]的]通用]代码]。(]来]吧],]Bill],]试试]看)。

iButton 代码加密

首先],]iButton]代码]的]加密]版本]本身]会]写入]NVRAM]。]这]可以]防止]能力]中等]的]人]将]授权]从]一个]iButton]复制]到]另一]个]。]由于]iButtons]是]唯一]的],]一个]按钮]的]解密]iButton]代码]将]不]等于]另一]个]按钮]的]代码]。

NIC 地址加密

其次],]计算机]的]NIC]地址](]不是]IP]地址])]被]加密]并]存储]在]iButton]中]。]这]可以]防止]软件]在]未]注册]操作]的]计算机]上]运行]。]除了]防止]非法]副本],]这]也]确保]了]对]运行]软件]的]计算机]系统]有]一些]控制]。]几乎]所有]情况]下],]都会]向]客户]销售]一个]交钥匙]系统]。

许可证时间加密

软件]通常]会]向]俱乐部]授予]一定]的]操作]时数]的]许可证]。]这]确保]了]持续]的]收入]来源],]并且]在]某些]客户]未]及时]付款]的]情况下],]它]确保]了]系统]在]一定]时间]后]会]关闭]。]是的],]在这个]行业],]人们]喜欢]保留]他们]的]现金],]并且]需要]使用]诸如]此类]方法]来]确保]人们]为]他们]的]系统]付款]。]许可]的]操作]时数]被]加密]并]存储]在]iButton]中]。]在]软件]操作]期间],]这个]值]会]频繁]地]递减]。]使用]这种]方法]代替]iButton]的]计时器]功能]是为了]确保]时间]只]在]软件]实际]运行]时]才]递减]。

系统要求

除了]识别]在]俱乐部]发生]的]交易]之外],]iButton]还]用于]在]现金]结算]和]收入]报表](]以及]其他]地方])]的]列表框]和]组合框]中]快速]选择]表演者]。]为了]支持]这种]功能],]存在]几个]挑战],]其中]一些]与]iButtons]无关]。

轮询

1-wire]网络]是]一个]轮询]网络]。]它]不会]在]设备]被]添加到]网络]或]从]网络]中]移除]时]通知]系统]。]因此],]使用]一个]线程]来]监控]网络]上]的]设备]。]存在]两个]并发症]。]一个]是],]1-wire]驱动程序]消耗]大量]CPU]资源]。]在]1.6Ghz] P4]上]以]100ms]为]间隔]轮询]一个]包含]两个]设备]的]网络]会导致]CPU]利用率]接近]50%]。]这]对于]持续]操作]是]不可接受]的],]因此]需要]一种]仅]在]需要]时]才]激活]轮询]的]机制]。

其次],]因为]人]实际]上]使用]一个]简单]的]“]读取器”](]见]图])]将]iButton]连接]到]网络],]iButton]可以在]短](]小于]500ms])]时间]内]出现]和]消失]数]次]。]其中]一个]结果]是],]网络]上]设备]的]顺序]可能]会]发生]变化]。]这]在]该]系统]的]初始]实现]中]导致]了]问题],]因为]我]期望]许可证]iButton](]它]物理]上]安装]在]连接]到]并行]端口]的]支架]中]——]顺便]说]一句],]支架]有]自己]的]唯一]地址])]总是]出现在]设备]列表]中]的]第一个]。]唉],]这]不]一定]是]这样]。]为了]补偿]这个]问题],]实现]了一个]简单]的]去抖]系统]。]这个]机制]在]iButton]添加到]网络]时]提供]即时]通知],]但]会]延迟]500ms]后]才]从]网络]中]移除]“]iButton]移除”]通知]。]这]可以]防止]向]用户]界面]发出]多个]“]新]按钮”]通知]。

通知

下一个]问题]是如何]将]事件]通知]到]包含]列表框]或]组合框]的]对话框]。]在]本文]提供的]示例]中],]使用]了]一个]自定义]消息]通知]方案],]并且]必须]重写]CDialog]的]PreTranslateMessage]方法]。]在]实际]使用]的]系统中],]消息]被]放入]内部]队列],]在]应用程序]的]OnIdle()]函数]期间]进行]处理]。]由于]当]模态]对话框]存在]时],]此]函数]不]处于]活动]状态],]对话框]实现]了一个]定时器],]该]定时器]会]发出]消息]并]激活]相同]的]OnIdle]处理]。]对于]有]兴趣]的]人]来说],]这种]实现]方式]的]原因是]它]还]服务]于]其他]目的],]例如]启用]处理]来自]俱乐部]网络]的]其他]传入]消息]。]由于]Access]用作]数据库],]所有]数据库]事务]必须]在]应用程序]线程]中]发生]。]好了]。]这就是]技术]原因]。

冲突

轮询]例程]工作]线程]与]任何]应用程序]线程] I/O]之间的]冲突]使用]信号量]解决]。

Button 接口类

这个]类]是一个]框架],]用于]添加]iButton]系列]支持]的]额外]功能]。]它]当前]读取]ROM]代码],]读取]和]写入]NVRAM]页面],]并]提供]一种]用于]通知]网络]上]设备]更改]的]轮询]机制]。]类]定义]是

class ButtonInterface
{
private:

    static UINT ButtonInterface::MonitorThreadStartup(void* v);

public:

    ButtonInterface(void);
    virtual ~ButtonInterface(void);

    bool StartSession(void);
    void EndSession(void);

    void StartMonitor(int msSleep=100, int debounceTime=500);
    void EndMonitor(void) {endMonitor=true;};

    void PauseMonitor(void) {pauseMonitor=true;};
    void ResumeMonitor(void) {pauseMonitor=false;};

    void BeginIO(void);
    void EndIO(void);

    bool SelectDevice(CString romCode);
    bool SelectDeviceStrong(CString romCode);

    bool ReadPage(int page, unsigned char* data, int len);
    bool WritePage(int page, unsigned char* data, int len);

    bool IsMonitorActive(void) {return monitorActive;};

    UINT GetNotificationAdded(void) {return notificationAdded;};
    UINT GetNotificationRemoved(void) {return notificationRemoved;};

    int GetButtonList(CString* codes);

protected:

    void Monitor(void);
    void PostNotification(UINT msg, CString code);

    struct ButtonInfo
    {
        ButtonInfo(void)
        {
            touched=false;
            newButton=true;
        }
        LARGE_INTEGER currentSampleTime;
        bool touched;
        bool newButton;
    };

protected:

    // button code to info mapping

    std::map<CString, ButtonInfo> buttonInfo;        
    // notification message data


    std::map<CString, CString*> msgData;
    HINSTANCE hInst;          // library instance

    long hSess;               // session instance

    bool endMonitor;          // end monitor thread flag

    bool pauseMonitor;        // pause monitor thread.

    bool monitorActive;       // worker thread is running

    int sleepTime;            // sample rate in ms

    int debounceTime;         // debounce time, in ms

    CRITICAL_SECTION cs;      // thread blocking

    BYTE stateBuffer[15360];  // internal for TMX interface

    UINT notificationAdded;   // button added notification message

    UINT notificationRemoved; // button removed notification message

    LARGE_INTEGER freq;       // counts per second


private:

    // function pointers to TMX DLL

    short (far pascal* TMReadDefaultPort)
          (short far* portNum, short far* portType);
    long (far pascal* TMExtendedStartSession)
         (short portNum, short portType, void far* enhSessOpt);
    short (far pascal* TMSetup)(long hSess);
    short (far pascal* TMEndSession)(long hSess);

    short (far pascal* TMFirst)(long hSess, void far* stateBuff);
    short (far pascal* TMNext)(long hSess, void far* stateBuff);
    short (far pascal* TMRom)
          (long hSess, void far* stateBuff, short far* ROM);
    short (far pascal* TMAccess)
          (long hSess, void far* stateBuff);
    short (far pascal* TMStrongAccess)
          (long hSess, void far* stateBuff);
    short (far pascal* TMWritePacket)
          (long hSess, void far* stateBuff, short page,
           unsigned char far* data, short len);
    short (far pascal* TMReadPacket)
          (long hSess, void far* stateBuff, short page,
          unsigned char far* data, short len);
    short (far pascal* TMTouchByte)(long hSess, short byte);
    short (far pascal* TMBlockStream)
          (long hSess, unsigned char far* data, short len);
};

驱动程序初始化

可以通过]包含]应用程序]中的]LIB]来]初始化]驱动程序],]或者]通过]在]运行时]加载]DLL]并]以]编程]方式]确定]接口]点]来]初始化]驱动程序]。]我]选择了]后者],]因为它]能够]在]不]重新编译](]由于]依赖]的]LIB])]的]情况下]更新]驱动程序]。]这]简化]了]俱乐部]的]新]iButton]驱动程序]软件]更新],]在]许多]情况下],]他们]可以]自己]完成]。]以下]代码]说明]了]加载]DLL]并]获取]该]ButtonInterface]对象]的]实现]所需]函数]的]入口点]。

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);
}

会话启动和终止

所有]与]1-wire]网络的]接口]都]必须]在]会话]内]执行]。]会话]机制]在]会话]处于]活动]状态]时]阻止]其他]应用程序]访问]1-wire]网络]。]Dallas] Semiconductor]建议]您]将]会话]保持]打开]时间]尽可能]短],]以免]其他]应用程序]被]阻止]访问]网络]。]由于]这是一个]专有]的]交钥匙]系统],]因此]这]不是]问题],]并且]会话]会]在]ButtonInterface]对象的]整个]生命周期]内]保持]。]以下]代码]说明]了]启动]和]终止]会话],]这]也]会自动]终止]工作]线程]。

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;
    }
}

获取 1-Wire 设备列表

随时]可以通过]调用]GetButtonList]方法]在]应用程序]线程]中]获取]所有]1-wire]设备]的]列表]。]请]注意],]此]方法]不会]影响]ButtonInterface]对象]内部]用于]确定]1-wire]设备]的]添加]和]删除]的]标志]。]以下]代码]说明]了]如何]获取]1-wire]网络]上]的]设备]。]该]对象]目前]最多]处理]32]个]设备]。]每个]设备]的]ROM]代码]都]作为]CString]数组]返回],]而不是]十六进制]值]。]请]注意],]ROM]代码]的]读取]顺序]与]iButton]上]显示]的]顺序]相反]。]这]纠正]了]驱动程序]返回]ROM]代码]时]是]反序]的事实]。

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;
}

这段]代码]通过]简单]的]“First”]和]“Next”]迭代]来]获取]网络]上的]设备]。]每个]字节]都]被]转换]为]字节]十六进制]值]的]ASCII]表示]。

启动工作线程

轮询]工作]线程]以]默认]的]100ms]轮询]间隔]和]500ms]去抖]电路]启动]。]终止]会]设置]一个]标志],]导致]线程]在]下次]启动]轮询]时]退出]。]由于]使用]了]相当]不精确]的]Sleep]函数],]这些]计时]值]仅]是]近似]的]。

...
    void StartMonitor(int msSleep=100, int debounceTime=500);
    void EndMonitor(void) {endMonitor=true;};
...    
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;
}

工作]线程]使用]与]应用程序]线程]网络]标识]相同]的方法]。]此外],]它]会]设置]和]清除]各种]标志]来]标识]新]设备]、]从]网络]中]移除]的]设备],]并]处理]设备]去抖]。


暂停和恢复工作线程

当]暂停]时],]工作]线程]会]在]轮询]间隔]时]唤醒],]并且]只]检查]线程]是否]需要]终止]。]暂停]时]不]执行]轮询]。]当]您]只想]出于]性能]或其他]原因]停止]轮询],]而不]必]经历]销毁]和]重新]创建]对象](]这将]导致]重新]加载]DLL])]时],]这]非常有用]。

...
    void PauseMonitor(void) {pauseMonitor=true;};
    void ResumeMonitor(void) {pauseMonitor=false;};
...

在应用程序中处理通知消息

ButtonInterface]对象]建立]自己]独特]的]“]按钮]添加”]和]“]按钮]移除”]通知]。]这些]可以]通过]在]类]头]文件]中]定义]的]两个]方法]来]确定

...
    UINT GetNotificationAdded(void) {return notificationAdded;};
    UINT GetNotificationRemoved(void) {return notificationRemoved;};
...

设备选择

在]读取]和]写入]NVRAM]之前],]必须]在]1-wire]上]选择]特定]的]设备]。]为了]确保]正确]选择],]必须]使用]所需]设备]的]ROM]代码]调用]TMAccessStrong]驱动程序]函数]。]如果]使用]TMAccess],]您]将]不]保证]所需]的]设备]实际]上]在]网络]上](]这]已经]通过]经验]验证])。]ButtonInterface]类]提供]了]选择]设备]的]两种]方法]。]“]较弱”]的]SelectDevice]方法]可以在]使用]SelectDeviceStrong]方法]验证]设备]已]存在]于]网络]之后]使用]。]有关]更多]信息],]请]阅读]iButton] SDK]中]的]TMAccess]和]TMAccessStrong]文档]。

bool ButtonInterface::SelectDevice(CString romCode)
{
    short ROM[9];
        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];
        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;
}

NVRAM 读/写函数

NVRAM]页面]读/写]函数]与]硬件]实现]紧密]相关],]每个]页面]最多]读取]和]写入]32]个]字节]。]此]实现]不支持]智能]的]跨]页面]边界]检测]。]虽然]驱动程序]提供]了]TMReadPacket]和]TMWritePacket]函数],]但]这些]函数]仅]支持]NVRAM]设备],]例如]DS1993]。]当然],]这些]信息]没有]在]TMReadPacket]函数]中]提到],]只有]TMWritePacket]函数]提到]了],]这]导致]我]花了]大约]4]个小时]才]弄]清楚]为什么]我]无法]读取]或]写入]DS1994]设备]。

ReadPage]方法]通过]1-wire]网络]发出]一个]命令],]请求]指定]页面],]然后]读取]所需]字节]数],]最多]为]页面]大小],]即]32]个]字节]。

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));

类似]地],]WritePage]将]最多]一个]页面]大小](]32]个]字节])]发送]到]指定]页面]

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;
}

请]注意],]当]一个]字节]被]放置]到]网络]上]时],]1-wire]网络]总是]返回]一个]字节]。]在]读取]字节]的]情况下],]将]0xFF]放置]到]网络]上]。]在]写入]字节]的]情况]下],]将]非]0xFF]的]字节]放置]到]网络]上]。]因此],]真正的]二进制]数据]无法]存储]在]NVRAM]中]。]另请]注意],]在]写入]过程]中],]目标]的]起始]和]结束]地址]在]数据]传输]后]从]网络]中]读取],]并且]必须]写]回]到]网络]才能]实际]提交]数据]到]内存]。]这]可以]用于]确保]数据]完整性]。

设备监控期间的 NVRAM I/O

为了]避免]与]设备]监控]线程]发生]冲突],]应用程序]必须]使用]以下]方法]启动]和]终止]I/O]会话

void ButtonInterface::BeginIO(void)
{
    EnterCriticalSection(&cs);
}
void ButtonInterface::EndIO(void)
{
    LeaveCriticalSection(&cs);
}

当]不]使用]监控]线程]时],]则]不需要]这样做]。

工作线程

这个]线程]相当]不]言自明]。]去抖]功能]是最]有趣]的],]它]涉及到]计时]一个]设备]在]列表中]保持]“]未]触碰”]多]久]。]一旦]设备]保持]“]未]触碰”]达到]指定]时间],]就会]将]一个]通知]消息]发布]到]应用程序]线程],]并且]设备]会]从]列表中]移除]。]这]也]会]终止]对]移除]设备]的]测试],]因此],]如果]多个]设备]同时]被]移除],]通知]将]会]被]轮询]速率]延迟]。

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;
}

CDialog 通知处理程序

以下]代码]说明]了]如何在]CDialog]派生]类]中]处理]监视器]线程]通知]。]在此]示例]中],]按钮]代码]要么]被]添加到]列表]控件]列表]中],]要么]被]移除]。]请]注意],]ROM]代码]*]CString]由]消息]处理]程序]释放]。

BOOL CButtonTestDlg::PreTranslateMessage(MSG* msg)
{
    BOOL ret;
    if (msg->message==btn->GetNotificationAdded())
    {
        CString* code=(CString*)msg->lParam;
        buttonList.ButtonPresent(code, true);
        delete code;
        ret=true;
    }
    else
    if (msg->message==btn->GetNotificationRemoved())
    {
        CString* code=(CString*)msg->lParam;
        buttonList.ButtonPresent(code, false);
        delete code;
        ret=true;
    }
    else
    {
        ret=CDialog::PreTranslateMessage(msg);
    }
    return ret;
}

结论

总而言之],]iButton]是]跟踪]货币]交易]的]绝佳]解决方案]。]在]我]客户]系统]的]特定]案例]中],]所有]资金]都]维护]在]监控]俱乐部]交易]的]服务器]中]。]在]其他]应用程序]中],]资金]可以直接]维护]在]iButton] NVRAM]中],]为]授权]请求]和]资金]贷记/借记]提供]自主]支持]。]还有]许多]其他]有趣]的]应用]!

© . All rights reserved.