HidDevice

Top  Previous  Next

The HidDevice object is use to interact with the opened hid device.

Methods

Return

Signature

Description

bytesWritten, error

write(data)

Writes data and returns number of bytes written

data, error

read(len, timeoutMS)

Reads data of length len and with timeout timeoutMS

boolean, error

setNonBlocking(boolean)

Sets the device to be non-blocking or not.

bytesWritten, error

setFeatureReport(data)

Writes a feature report

data, error

getFeatureReport(len, reportId)

Reads a feature report

string, error

getSerial()

Gets the serial number

string, error

getManufacturerString()

Gets the manufacturer string

string, error

getProductString()

Gets the product string


close()

Closes the device.

 

HidDevice::write

The first byte of data must contain the Report ID. For devices which only support a single report, this must be set to 0x0. The remaining bytes contain the report data. Since the Report ID is mandatory, calls to write will always contain one more byte than the report contains. For example, if a hid report is 16 bytes long, 17 bytes must be passed to write, the Report ID (or 0x0, for devices with a single report), followed by the report data (16 bytes). In this example, the length passed in would be 17.

 

hid_write() will send the data on the first OUT endpoint, if one exists. If it does not, it will send the data through the Control Endpoint (Endpoint 0).

HidDevice::read

Input reports are returned to the host through the INTERRUPT IN endpoint. The first byte will contain the Report number if the device uses numbered reports. Timeout is the number of milliseconds to wait or 0 if wait indefinitely. Len is the length of the data to receive.

HidDevice::setNonBlocking

In non-blocking mode calls to read will return immediately with a value of 0 if there is no data to be read. In blocking mode, read will wait (block) until there is data to read before returning.

HidDevice::setFeatureReport

Feature reports are sent over the Control endpoint as a Set_Report transfer. The first byte of data must contain the Report ID. For devices which only support a single report, this must be set to 0x0. The remaining bytes contain the report data. Since the Report ID is mandatory, calls to setFeatureReport will always contain one more byte than the report contains. For example, if a hid report is 16 bytes long, 17 bytes must be passed to setFeatureReport: the Report ID (or 0x0, for devices which do not use numbered reports), followed by the report data (16 bytes). In this example, the length passed in would be 17.

HidDevice::getFeatureReport

Gets the feature report for report id reportId. Note that report id is passed as a number not a binary.

HidDevice::close

Closes the resources associated with the hid device. Make very sure that you are no longer using this device, especially any blocking HidDevice::read or getFeatureReport functions. These will crash Girder if you close while they are still running.

Examples

Sending data.

The code below sends a CCF code from a PIR-1 or PIR-4. The hidDev variable came from the example code in the hid.open section. What the function below does is basically split the CCF code into 60 byte chunks. Prepends a header with report id = 0, PIR command id = 14, flags 0 (continue), 1 (first packet) or 2 (last packet) plus the length of the data in bytes followed by the CCF data. The reason for splitting the CCF code like this is that USB-HID has a maximum transfer size of 64 bytes.

 

function sendCCF( dev, bitmask, repeats, ccf )

 

    local ccfParts = string.split(ccf," ")

    table.print(ccfParts)

    local firstPacket = true

    local data = '';

    for i, v in ipairs(ccfParts) do

              

      if i == 1 then

          data = data .. string.char( repeats ) .. string.char(bitmask)

      end

      

 

      local value = math.hextodecimal(v)

 

      local vl = bit.band(value,0xff)

      local vh = bit.rshift(value,8)

 

      data = data .. string.char(vh) .. string.char(vl)

 

      local lastPacket = i == #ccfParts;

      

      if string.len(data) >= 60 or lastPacket then

      

        local flags = 0;

        if firstPacket then

            flags = bit.bor(flags,1)

        end

        firstPacket = false;

        if lastPacket then

            flags = bit.bor(flags,2)

        end

        

        local reportHeader = '\000\014' .. string.char(flags) .. string.char( string.len(data))

        local packet = reportHeader .. data

        hidDev:write(packet)        

        data = ''

 

      end

    

    end

 

end

 

sendCCF(hidDev, 3, 2, "0000 006E 0000 0022 0156 00A9 0014 0014 0014 0040 0014 0040 0014 0040 0014 0014 0014 0040 0014 0040 0014 0014 0014 0040 0014 0014 0014 0014 0014 0014 0014 0040 0014 0014 0014 0014 0014 0040 0014 0040 0014 0014 0014 0040 0014 0040 0014 0040 0014 0014 0014 0014 0014 0014 0014 0014 0014 0040 0014 0014 0014 0014 0014 0014 0014 0040 0014 0040 0014 0040 0014 05EF")

 

Receiving data.

Receiving data is as easy as calling HidDevice::read( reportSize + 1, 1000). This is great as long as your device does not generate any data unsolicited. How would you know when to call read in that case. To solve this problem you can start a new thread that reads with a timeout.

 

hidTerminated = false

 

function receiveIrCodes( dev )

 

  thread.newthread( function() 

  

    while not hidTerminated and not gir.girderClosing do

    

        local data, err = dev:read(65, 250)

        if not data then

            hidTerminated = nil

            print(err)

            return

        end

        

        if string.len(data) > 0 then        

            print(string.len(data))

            print(math.binarytohex(data))        

        end

        

        

    end

    

    hidTerminated = nil

         

  

  end,{})

 

 

end

 

receiveIrCodes(hidDev)

print("Receiving...")

 

Closing up.

Since we cannot rip the HidDevice from underneat the thread without crashing Girder we're going to do it the nice way. We check if hidTerminated has been set to false. If so we set it to true and wait for the thread to set it to false or nil.

 

if hidTerminated == false then

    hidTerminated = true

    print("Waiting...")

    while ( hidTerminated ) do

      print("Waiting...")

    end

end

 

hidDev:close()

hidDev = nil

 

The code above work just fine but it uses some global variables and is scattered across a few actions. Let's put it into a nice class.