Reading a USB stream from a DYMO M10 scales
Posted
#1
(In Topic #102)
Administrator

Anyone have any experience reading usb hid streams? This is new territory for me and I might not be doing this correctly, so any help is greatly appreciated.
I have a Dymo M10 scale that I would like to read the output stream, along trying to decode it. My first issues is an "access forbidden" error…
Code
hFile = Open "/dev/hidraw3" For Read Watch
I'm not 100% sure what type of data type to use. When changing access permission on hidraw3, and running, this…
Code
Public Sub File_Read()
Dim iByte As Byte
Read #hFile, iByte
Print "Got one byte: "; iByte
End
From what I can find on the 'net, there should be a data packet of 6 elements. If I'm able to get this worked out, I'd like to tie the scale into the inventory system I wrote this past week.
If this output from dmesg is of any help…
Code
[1221565.175330] usb 2-8: USB disconnect, device number 34
[1221626.550068] usb 2-8: new low-speed USB device number 35 using ohci-pci
[1221626.744476] usb 2-8: New USB device found, idVendor=0922, idProduct=8003
[1221626.744489] usb 2-8: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[1221626.744496] usb 2-8: Product: M10 10 lb Digital Postal Scale
[1221626.744501] usb 2-8: Manufacturer: DYMO
[1221626.744506] usb 2-8: SerialNumber: 0071431044934
[1221626.772802] hid-generic 0003:0922:8003.0026: hiddev0,hidraw3: USB HID v1.01 Device [DYMO M10 10 lb Digital Postal Scale] on usb-0000:00:02.0-8/input0
Thanks!
Posted
Regular

Have a great day!
Posted
Guru

Posted
Guru

I have used 'gksu' to get root access. The output is full of all-sorts but I was able to get what I wanted. The bar-code I used is correctly displayed above the 'Convert' button.
Hopefully you can pick something out of this: -
Posted
Administrator

I've tried your project, cogier, but without any success. I do know the stream coming from the scale is binary. I've found a couple python scripts for the scale that I'll try to get working (and/or try to convert over to Gambas). I know nothing about python so it's going to take awhile once I pick up my project again.
Thanks everyone for your help. I'll post again once I'm working on this again.
Posted
Administrator

I made 2 changes to cogier's code (marked as comment in the code):
Code
Public Sub Form_Open()
hProc = Exec ["sudo", "cat", "/dev/hidraw3"] For Read As "plugin"
' used 'sudo'. changed to '/dev/hidraw3'
End
Code
Public Sub plugin_read()
Dim sTemp As String
sTemp = Read #Last As Byte ' changed '#Last, -255' to '#Last As Byte'
TextArea1.text &= sTemp
End
This change allowed the binary stream to display correctly without any extra code:
341125536034112553603411255360341125536034112553603411255360341125536034112553603411255360341125536034112553603411255360341125536034112553603411255360341125536034112553603411255360341125536034112553603411255360341125536034112553603
The above is a 6-element array repeated constantly, but with different values depending the state of the scales (ie: weight, unit of weight [ounces/kilograms], if weight has stabilized, etc). So now that brings me to the actual bits needed…
3411255360
This can be broken down into the individual elements of the array…
3 4 11 255 36 0
My current goal is to get this stream into an array so I can easily read each element. Any advice/suggestions?
Posted
Administrator

Since the scale has an auto-off after 3 minutes idle time, I need to test for a lack of stream so I can display a message. Is there a way to test for a stream?
Posted
Regular

Posted
Regular

Posted
Administrator

I have to put this project to the side for awhile again. Next go around I should have enough to work this into my inventory project.
Posted
Administrator

I was able to read (and decode) the USB stream from the DYMO M10 scale using Gambas and a couple shell commands. During this exercise I've learned the dymo scales uses a raw stream to output an array of 6 elements. After finding a Perl script that allowed me to see what the actual output was, it was just a matter of replicating it in Gambas. This turned out much easier than I had originally thought it would be. Below is the final code showing exactly how easy it was. Thanks to cogier for posting his example that I was able to build off of.
Starting with cogier's code, I move the hProc from the Form_Open() sub to a buttonStart_Click() sub so I could restart the process whenever the scales went into auto-off.
Next I needed to make sure I was using the correct HID device so I grep'd a single line in dmesg for "DYMO M10" and took it's output and pulled the correct HID device from it, plugging that into the hProc command.
Reading the stream output as Byte correctly displayed the stream which allowed each element to be added to an array (iData[0-5]).
The 6 elements are:
<LIST>
- <LI>The 1st element is unknown. It could be an error state with '3' being normal operation.
The 2nd element indicates the state the scale is in. (values: 2, 4, 5, 6) '2' = zero weight, '4' = positive weight, '5' = negative weight, '6' = over max weight
The 3rd element (either 2 or 11) is what the unit of weight mode the scale is in (ounces/kilograms).
The 4th element is for calculating the scaling factor while the scale is in ounce mode. (values: 0, 254, 255)
The 5th and 6th elements are used for calculating the weight.</LI>
And finally, when the scales go off-line, the _Kill() sub clears the TextBoxes and displays a message.
A Timer can be used to continuously check for when the scales come on-line.
Hopefully someone can use this as a starting point to read other scales (or usb/hidraw devices).
Code
' Gambas class file
Public hProc As Process
Public Sub Form_Open()
Label1.Text = "Make sure power is on, then press the start button."
End
Public Sub buttonStart_Click()
Dim sOutput As String
Shell "dmesg | grep \"DYMO M10\" | head -n 1" To sOutput
sOutput = Mid$(sOutput, InStr(sOutput, "hidraw"), 7)
hProc = Exec ["sudo", "cat", "/dev/" & sOutput] For Read As "plugin"
Label1.Text = "Ready to weigh."
End
Public Sub plugin_Kill()
TextBox1.Text = Null
TextBox2.Text = Null
TextBox3.Text = Null
TextBox4.Text = Null
TextBox5.Text = Null
TextBox6.Text = Null
Label1.Text = "Scales is off-line."
End
Public Sub plugin_Read()
Dim iTemp As Integer
Dim iData As New Integer[]
Dim i As Integer
For i = 0 To 5
iTemp = Read #Last As Byte
iData.Add(iTemp, i)
Next
TextBox1.Text = iData[0]
TextBox2.Text = iData[1]
TextBox3.Text = iData[2]
TextBox4.Text = iData[3]
TextBox5.Text = iData[4]
TextBox6.Text = iData[5]
End
Public Sub Form_Close()
Try hProc.Kill
End
Public Sub ButtonExit_Click()
Try hProc.Kill
Me.Close
End
The form is simply 2 buttons, 1 Label, and 6 TextBoxes.
[edit: corrected/updated element list.]
.
Posted
Regular

What if you got more than 9 hidraw files? (Hint: gb.pcre -> regex)
Posted
Administrator

Not sure what you are referring to with the second question, so I'll answer it this way… If you grep the device's name (eg: "dymo" in my case) and extract the hid device name (eg: "hidraw3" in my case) and feed that to the 'cat' command, it shouldn't matter how many hid files, or even if the device changes each time they are plugged in. At least I don't think it would matter. I haven't had a chance to test this by moving the scales to a different computer.
Posted
Regular

Code
sOutput = Mid$(sOutput, InStr(sOutput, "hidraw"), 7)If you've got a file named "hidraw10" it will not work, it needs to be 8, not 7 in that case.
Posted
Administrator

There's probably a better way also than grep'ing the dmesg file to find the device name/file pair since that would mean that the device would have had to been plugged in at some point after the dmesg file was cleaned.
Posted
Administrator

Since I couldn't understand gb.pcre, I decided to go back to the basics and just add an additional grep to the shell command. It worked on a test file, but since I only have 4 hidraw devices connected, I couldn't test for greater than a single digit in real use.
This change should find any hidraw file with 1 or more digits (ie: hidraw10) associated with the search string "dymo m10".
Code
Shell "dmesg | grep \"DYMO M10\" | head -n1 | grep -o 'hidraw[0-9]*'" To sOutput
' old : Shell "dmesg | grep \"DYMO M10\" | head -n1" To sOutput
hProc = Exec ["sudo", "cat", "/dev/" & Trim$(sOutput)] For Read As "Data"
' old: hProc = Exec ["sudo", "cat", "/dev/" & sOutput] For Read As "Data"
I had to Trim$ the output of the shell command since the additional grep added a newline that's only present using the shell command and not while using a terminal.
.
Posted
Regular

Posted
Administrator

\d doesn't work with grep, you have to use [0-9].
1 guest and 0 members have just viewed this.


