B4J Question How to get data from HID device?

bjfhs

Active Member
Licensed User
Longtime User
B4X:
#AdditionalJar: purejavahidapi
#AdditionalJar: jna-4.0.0

   Dim hdi As JavaObject
    hdi.InitializeStatic("purejavahidapi.HidDeviceInfo")
    'initial PureJavaHidApi
    Dim jo As JavaObject
    jo.InitializeStatic("purejavahidapi.PureJavaHidApi")
    'list all usb hid
    Dim lst As List
    lst = jo.RunMethodJO("enumerateDevices", Null)
    'open usb hid
    Dim obj As JavaObject
    obj.InitializeStatic("purejavahidapi.HidDeviceInfo")
    Dim tmp As Boolean
    Dim PD As Long ,VD As Long
    tmp=False
    For i=0 To lst.Size-1
        Log("lst:" & lst.Get(i))
        'ListView1.Items.Add("lst:"  & lst.Get(i))
        obj = lst.Get(i)
        PD=obj.RunMethod("getProductId",Null)
        VD=obj.RunMethod("getVendorId",Null)
        If  PD=0x1001 And VD=0x6816 Then
           tmp=True
           Exit
        End If
      
    Next
    If tmp=False Then
        fx.Msgbox(MainForm, "没有发现设备!", "警告")
        Return
    End If
  
    Dim getPath As String
    getPath = obj.RunMethod("getPath",Null)
    getPath=getPath.Trim
    Log(getPath)
    Dim hd As JavaObject
    hd.InitializeStatic("purejavahidapi.HidDevice")
    hd = jo.RunMethod("openDevice",  Array As String(getPath))
log:
B4X:
Waiting for debugger to connect...
Program started.
lst:purejavahidapi.windows.HidDeviceInfo@10c98a4
lst:purejavahidapi.windows.HidDeviceInfo@1f3046d
lst:purejavahidapi.windows.HidDeviceInfo@936f4f
\\?\hid#vid_6816&pid_1001#7&5dc41fe&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
Error occurred on line: 59 (Main)
java.lang.RuntimeException: Method: openDevice not matched.
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:129)
    at b4j.example.main._appstart(main.java:200)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:625)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:168)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:90)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:94)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:77)
    at b4j.example.main.start(main.java:38)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)

some about purejavahidapi
https://github.com/nyholku/purejavahidapi/commit/4388fde3328ef5e8eb7d13ef82c91a79741f0b0a
 
Last edited:

Daestrum

Expert
Licensed User
Longtime User
Looking at the source code openDevice wants a HidDeviceInfo passed to it, have you tried just passing your obj variable to it, as that is a HidDeviceInfo variable?
 
Upvote 0

bjfhs

Active Member
Licensed User
Longtime User
Yes, I have tried it, but I got a error.
hd = jo.RunMethod("openDevice", obj)
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Think it would be
Array(obj) in the RunMethod
 
Upvote 0

bjfhs

Active Member
Licensed User
Longtime User
Think it would be
Array(obj) in the RunMethod
Thank you very much,you are right.
But the next
B4X:
Dim data(132) As Byte    '65 and 132 are test
Dim ival As Int
ival = hd.RunMethod("getFeatureReport", Array As Object( data, data.Length ))
I can't get any data,ival always is -1
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
*** just realized the buffer is 132 bytes and the first byte must be 1
B4X:
Dim data(132) As Byte     '65 and 132 are test
data(0) = 1
Dim ival As Int
ival = hd.RunMethod("getFeatureReport", Array As Object( data, data.Length ))
 
Last edited:
Upvote 0

bjfhs

Active Member
Licensed User
Longtime User
*** just realized the buffer is 132 bytes and the first byte must be 1
B4X:
Dim data(132) As Byte     '65 and 132 are test
data(0) = 1
Dim ival As Int
ival = hd.RunMethod("getFeatureReport", Array As Object( data, data.Length ))
Dim data() As Byte = 132 ,can't use in B4J, Array expected.
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
** see my edited post #6

If the value of ival >= 0 then the call worked and the data buffer will contain int's that contain the information.
 
Upvote 0

bjfhs

Active Member
Licensed User
Longtime User
Thank Daestrum, you are great.
All My code,ival always is -1.
B4X:
#AdditionalJar: purejavahidapi
#AdditionalJar: jna-4.0.0
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private Button1 As Button
    Private Button2 As Button
    Private Button3 As Button
    Dim hd As JavaObject
    Dim zx As Boolean    '设备是否在线
    Private Timer1 As Timer
    Private Label1 As Label
End Sub
Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("main") 'Load the layout file.
    MainForm.Show
    setAlwaysOnTop(MainForm, True)
    '''''''''''''''''''''''''''''''''''''''''''''''
    Dim hdi As JavaObject
    hdi.InitializeStatic("purejavahidapi.HidDeviceInfo")
    'initial PureJavaHidApi
    Dim jo As JavaObject
    jo.InitializeStatic("purejavahidapi.PureJavaHidApi")
    'list all usb hid
    Dim lst As List
    lst = jo.RunMethodJO("enumerateDevices", Null)
    'open usb hid
    Dim obj As JavaObject
    obj.InitializeStatic("purejavahidapi.HidDeviceInfo")
 
    Dim PD As Long ,VD As Long
    zx=False
    For i=0 To lst.Size-1
        Log("lst:" & lst.Get(i))
        'ListView1.Items.Add("lst:"  & lst.Get(i))
        obj = lst.Get(i)
        PD=obj.RunMethod("getProductId",Null)
        VD=obj.RunMethod("getVendorId",Null)
        If  PD=0x1001 And VD=0x6816 Then
           zx=True
           Exit
        End If
    
    Next
    If zx=False Then
        fx.Msgbox(MainForm, "No device!", "Error")
        Return
    End If
 
    Dim getPath As String
    getPath = obj.RunMethod("getPath",Null)
    getPath=getPath.Trim
    Log(getPath)
 
    hd.InitializeStatic("purejavahidapi.HidDevice")
    hd = jo.RunMethod("openDevice",  Array(obj))
    Timer1.Initialize("Timer1", 200)
    If zx Then Timer1.Enabled=True
End Sub
'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub
Sub MainForm_CloseRequest (EventData As Event)
    Timer1.Enabled=False
    If zx Then
    Dim hdCl As JavaObject
    hdCl.InitializeStatic("purejavahidapi.HidDevice")
    hdCl = hd.RunMethod("close",Null)
    End If
End Sub
Sub Timer1_Tick
    Dim data(132) As Byte
    For i=0 To 63
        data(i)=0xFF
    Next
    data(0)=1
        If zx Then
        Dim ival As Int
        ival = hd.RunMethod("getFeatureReport", Array As Object( data, data.Length ))
        Label1.Text=ival
        If ival>0 Then
            Dim tmpp As String
            For i=0 To 63'ival-1
                tmpp=tmpp & data(i)
            Next
            Label1.Text=tmpp
'            fx.Msgbox(MainForm,tmpp,"fg")
        End If
    End If
End Sub
Sub setAlwaysOnTop(frm As Object, Value As Boolean)
    Dim frmJO As JavaObject = frm
    Dim stage As JavaObject = frmJO.GetField("stage")
    stage.RunMethod("setAlwaysOnTop", Array(Value))
End Sub
 
Last edited:
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Does it return the information now?
 
Upvote 0

bjfhs

Active Member
Licensed User
Longtime User
Yes,I can do it with Daestrum's help.
B4X:
#Region Project Attributes 
 #MainFormWidth: 600
 #MainFormHeight: 600 
 #AdditionalJar: purejavahidapi
 #AdditionalJar: jna-4.2.1
#End Region

Sub Process_Globals
 Private fx As JFX
 Private MainForm As Form
 Private Button1 As Button
 Private Button2 As Button
 Private Button3 As Button
 Dim lst As List
 Dim tb1 As TableView
 Dim currentDeviceInfo As JavaObject
 Dim currentDevice As JavaObject
End Sub
Sub AppStart (Form1 As Form, Args() As String)
 MainForm = Form1
 'MainForm.RootPane.LoadLayout("main") 'Load the layout file.
 MainForm.Show
 tb1.Initialize("devices")
 tb1.SetColumns(Array("VendorID","ProductID"))
 tb1.SetColumnWidth(0,200)
 tb1.SetColumnWidth(1,190)
 lst.Initialize
 Button1.Initialize("openDevice")
 Button1.Text="open selected device"
 Button2.Initialize("readDeviceFeatures")
 Button2.Text = "read selected device features"
 Button3.Initialize("closeDevice")
 Button3.Text = "close selected device"
 MainForm.RootPane.AddNode(tb1,10,10,400,400)
 MainForm.RootPane.AddNode(Button1,10,500,400,20)
 MainForm.RootPane.AddNode(Button2,10,530,400,20)
 MainForm.RootPane.AddNode(Button3,10,560,400,20)
 setAlwaysOnTop(MainForm, True)
 asJO(Me).RunMethod("getDeviceList",Array(lst))
 For Each item As Object In lst
  Dim vendor As Short = asJO(Me).RunMethod("getVendorId",Array(item))
  Dim product As Short = asJO(Me).RunMethod("getProductId",Array(item))
  tb1.Items.Add(Array(vendor,product))
 Next
End Sub
Sub asJO(o As JavaObject) As JavaObject
 Return o
End Sub
Sub devices_SelectedRowChanged(Index As Int, Row() As Object)
 Log("item selected : "&lst.Get(Index))
 currentDeviceInfo = lst.Get(Index)' lst contains real item tableview just to show vendor etc
 'Log(GetType(currentDeviceInfo))
End Sub
Sub openDevice_Click
 currentDevice = asJO(Me).RunMethod("openDevice",Array(currentDeviceInfo))
 'Log(currentDevice)
End Sub
Sub readDeviceFeatures_Click
 Dim data() As Byte = asJO(Me).RunMethod("getFeatureReport",Array(currentDevice))
 Dim sb As StringBuilder
 sb.Initialize
 For Each b As Byte In data
  sb.Append(b&" ")
 Next
 Log(sb.ToString.Trim)
End Sub
Sub closeDevice_Click
 asJO(Me).RunMethod("closeDevice",Array(currentDevice))
End Sub
'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
 Return True
End Sub
Sub setAlwaysOnTop(frm As Object, Value As Boolean)
 Dim frmJO As JavaObject = frm
 Dim stage As JavaObject = frmJO.GetField("stage")
 stage.RunMethod("setAlwaysOnTop", Array(Value))
End Sub
#if java
import java.util.List;
import purejavahidapi.*;
import java.io.*;
volatile static boolean deviceOpen = false;
public static List getDeviceList(List lst) {
 lst.clear();
 try {
  HidDeviceInfo devInfo = null;
  if (!deviceOpen) {
   System.out.println("scanning");
   List<HidDeviceInfo> devList = PureJavaHidApi.enumerateDevices();
   for (HidDeviceInfo info : devList) {
    System.out.println(info.getVendorId());
    System.out.println(info.getProductId());
    lst.add(info);
   }
  } 
 } catch (Throwable e) {
  e.printStackTrace();
 }
 return lst;
}
public static Short getVendorId(HidDeviceInfo hid){
 return hid.getVendorId();
}
public static Short getProductId(HidDeviceInfo hid){
 return hid.getProductId();
}
public static HidDevice openDevice(HidDeviceInfo devInfo) throws IOException{
 final HidDevice dev;
 if (devInfo == null) {
  System.out.println("device not found");
  dev = null;
 } else {
  System.out.println("device found");
  if (true) {
   deviceOpen = true;
   dev = PureJavaHidApi.openDevice(devInfo);
   dev.setDeviceRemovalListener(new DeviceRemovalListener() {
    @Override
    public void onDeviceRemoval(HidDevice source) {
        System.out.println("device removed");
     deviceOpen = false;
    }
   });
   dev.setInputReportListener(new InputReportListener() {
    @Override
    public void onInputReport(HidDevice source, byte Id, byte[] data, int len) {
     System.out.printf("onInputReport: id %d len %d data ", Id, len);
      for (int i = 0; i < len; i++)
       System.out.printf("%02X ", data[i]);
       System.out.println();
    }
   });
  } 
 }
 return dev; 
}
public static void closeDevice(HidDevice hid){
 if (!deviceOpen) return;
 hid.close();
 deviceOpen = false;
}
public static byte[] getFeatureReport(HidDevice dev){
 byte[] data = new byte[132];
 data[0] = (byte)1;
 int len = 0;
 if (((len = dev.getFeatureReport(data, data.length)) >= 0) && true) {
  int Id = data[0];
  System.out.printf("getFeatureReport: id %d len %d data ", Id, len);
  for (int i = 0; i < data.length; i++)
   System.out.printf("%02X ", data[i]);
  System.out.println();
 }
 return data;
}
#End If
 
Upvote 0

Christian García S.

Active Member
Licensed User
Thanks @bjfhs,

But when I run the B4J program the device is not listed, do you think I need a special driver ??

The device is:

USB\VID_03EB&PID_5500&REV_1000

in USB Input Device
 

Attachments

  • HIDKeyboard.jpeg
    HIDKeyboard.jpeg
    83.6 KB · Views: 453
Upvote 0

Christian García S.

Active Member
Licensed User
I had to execute a program that looks for the missing drivers, after executing that program and installing the missing drivers it is now recognized.

Thanks for your help
 
Upvote 0

bjfhs

Active Member
Licensed User
Longtime User
My code is used for human interface device(HID),if your device is not a HID,you can not use it, you need special driver.
 
Upvote 0

Christian García S.

Active Member
Licensed User
Thanks @bjfhs, now I can get data from device, the issue was that missing a driver.

I can see the data when I click in buttons, but I don't know how put the values in to a B4J variable , can you help me with this?

B4X:
dev.setInputReportListener(new InputReportListener() {
    @Override
    public void onInputReport(HidDevice source, byte Id, byte[] data, int len) {
     System.out.printf("onInputReport: id %d len %d data ", Id, len);
      for (int i = 0; i < len; i++)
       System.out.printf("%02X ", data[i]);
       System.out.println();
    }

Thanks
 
Upvote 0

bjfhs

Active Member
Licensed User
Longtime User
You can raise a event from it. and then get data from B4J.(ba.raiseEventFromUI)
 
Last edited:
Upvote 0

GabrielM

Member
Licensed User
Longtime User
I second MichaStaff,
Would be great to see how could use the (ba.raiseEventFromUI) in above inline java - InputReportlistener .
Btw, is there a link to raise events documentation, please?
 
Upvote 0
Top