I am developing a java application (which will run on linux desktop) to print shipping labels using TSC TTP-244 Pro printer. This printer supports TSPL2 commands.
I am using USB connection and started writing some simple tests using usb4java high-level API in-order to communicate to this printer. I am able to successfully query for the printer status/state <ESC>?! or <ESC>?S (<ESC> here is ASCII 27) with out any issues but unable to issue PRINT command.
Below is my code.
#Test
public void printTest() throws UsbException
{
final UsbServices services = UsbHostManager.getUsbServices();
UsbDevice printerUsbDevice = findDevice(services.getRootUsbHub(), 0x1234, 0x1734);
UsbConfiguration configuration = device.getActiveUsbConfiguration();
UsbInterface iface = configuration.getUsbInterface((byte) 1);
iface.claim();
try
{
UsbEndpoint inEndpoint = iface.getUsbEndpoint(0x01);
UsbPipe pipe = inEndpoint.getUsbPipe();
UsbEndpoint outEndpoint = iface.getUsbEndpoint(0x82);
UsbPipe pipe2 = outEndpoint.getUsbPipe();
pipe2.open();
pipe.open();
pipe.syncSubmit(27 + "!?".getBytes("US-ASCII"));
pipe.close();
pipe2.open();
byte[] statusResponse = pipe2.syncSubmit(new byte[1]);
pipe2.close();
System.out.println(new String(statusResponse, "US-ASCII")); // Here status got is "00" if ok otherwise getting error code
pipe.open();
pipe.syncSubmit("SIZE 57 mm,37 mm");
pipe.syncSubmit("GAP 3 mm,0 mm");
pipe.syncSubmit("DIRECTION 1");
pipe.syncSubmit("CLS");
pipe.syncSubmit("TEXT 10,10 "3",0,1,1, "Test printing");
pipe.syncSubmit("PRINT 1");
pipe.close();
// at this pint of time, printer is not printing anything instead just idle
}
finally
{
iface.release();
}
}
private UsbDevice findDevice(UsbHub hub, short vendorId, short productId)
{
for (UsbDevice device : (List<UsbDevice>) hub.getAttachedUsbDevices())
{
UsbDeviceDescriptor desc = device.getUsbDeviceDescriptor();
if (desc.idVendor() == vendorId && desc.idProduct() == productId) return device;
if (device.isUsbHub())
{
device = findDevice((UsbHub) device, vendorId, productId);
if (device != null) return device;
}
}
return null;
}
Is my usb communication correct ?
Does this USB communication with the TSC printer works without installing any printer driver (on linux) ?
Yes, your communication is correct.
Yes, USB communication on linux can work directly, without drivers.
If printer is not accepting some command, double check that command, maybe there should be some control sum, or something else you have missed? Study how exactly this command should be structured.
I have done a project using serial port to communicate with printer, the details of a command are very important. The status command could have no control sum and is very simple, that's why it work out-of-the-box, but with more sophisticated command you need to read the documentation and debug.
There is also possibility, that the printer is using differnt USB endpoint for other than "status" communication.
Related
My Java program needs to get a list of the drive letters of connected USB devices, but only those that support USB 3.0 (both the device and the USB port it is plugged into, so that it works with high speed).
Currently I try to use WMI through a PowerShell command my Java programm executes.
I already found this: Powershell: Grab USB Drive letter. But it would also list USB 2.0 devices.
Regarding version detection I found this: How to check the version of the available USB ports? - The PowerShell command I tried is Get-WmiObject Win32_USBHub. This brings up several problems. First: It lists far more stuff than only USB drives (I think also all the USB hubs of my PC). Second: Even though there is a field USBVersion for all items in the list it is always empty.
Update
The essence of my research over the last days is, that there are 2 realms of information I need to connect.
Drives / Logical Drives
Drive Letter
BusType (is equal to "USB" for my matter)
USB devices
Vendor ID and Product ID (VID&PID)
bcdUSB (value within the usb device descriptor, indicating USB Version)
For a given drive letter I need to find the bcdUSB value. But I haven't found a way to get the drive corresponding to a USB device.
What I tried so far
WMI over PowerShell
Relevant commands I found are
Get-Disk // Get BusType
gwmi Win32_LogicalDisk // Get drive letter
// Those make the connection between disk and logical disk
gwmi Win32_LogicalDiskToPartition
gwmi Win32_LogicalDiskToPartition
Even though I get the BusType I couldn't make a connection to bcdUSB
usb4java (Link)
I only get information from the USB device realm here. I can load devices and see ther VID&PID and the bcdUSB value, but no way to map this to drives and drive letters.
lsusb via Cygwin
According to this post the linux command is easier to handle than WMI. So I tried to use it under Windows. But I like usb4java I only got VID&PID + bcdUSB, not the mount point (drive letter).
Searching the Windows Registry
I did a few string searchs in the Windows registry. No success.
Reading Windows Event log
I thought about ovserving Windows events to detect what Drive and what USB device connect at the same time. I didn't even find events when plugging in a USB stick.
Maybe this is what you are looking for:
Find Windows Drive Letter of a removable disk from USB VID/PID
At least someone marked the answer as working... :-)
Since the suggested Link solves this problem for C# not Java and leaves out one step, I'll post my final code here.
Summary
In Java
Use USB4Java to find all connected USB devices with bcdUSB=0x0300
Get Vendor ID and Product ID (VID&PID) for that devices
Via Powershell (with jPowerShell)
Get PnPEntity for given VID&PID
Get related USB Controller
Find associator of that USB Controller that is associated with a disk drive
Get that Disk drive
Get related disk partition
Get related logical disk -> LogicalDisk.DeviceID = Drive Letter
Code
Java class:
class UsbDetector {
private PowerShell shell;
#PostConstruct
private void init() {
shell = com.profesorfalken.jpowershell.PowerShell.openSession();
}
#OnDestroy
private void onShutdownHook() {
shell.close();
}
/**
* Get drive letters of USB 3.0 devices.
*/
public List<String> getDriveLettersForUsb3Devices() throws IOException, UsbException {
List<UsbDevice> devicesUSB3 = getAllUsb3Devices();
ImmutableList.Builder<String> driveLetterList = ImmutableList.builder();
for (UsbDevice device : devicesUSB3) {
String vidAndPid = getVidAndPid(device);
String powerShellScript = buildScript(vidAndPid);
String driveLetter = executeOnPowerShell(powerShellScript);
driveLetterList.add(driveLetter);
}
return driveLetterList.build();
}
private String executeOnPowerShell(String powerShellScript) {
InputStream psScriptStream = new ByteArrayInputStream(powerShellScript.getBytes());
BufferedReader psScriptReader = new BufferedReader(new InputStreamReader(psScriptStream));
PowerShellResponse response = shell.executeScript(psScriptReader);
return response.getCommandOutput();
}
private String buildScript(String vidAndPid) throws IOException {
InputStream psScriptStream =
getClass().getClassLoader().getResourceAsStream("GetUsbDrives.ps1");
String psScript = IOUtil.toString(psScriptStream);
psScript = String.format("$input=\"%s\"", vidAndPid) + "\n" + psScript;
return psScript;
}
/**
* The Vendor ID and Product ID are necessary to find the device via WMI.
*/
private String getVidAndPid(UsbDevice device) {
short vendorId = device.getUsbDeviceDescriptor().idVendor();
short productId = device.getUsbDeviceDescriptor().idProduct();
String vendorIdHexString = String.format("%04x", vendorId).toUpperCase();
String productIdHexString = String.format("%04x", productId).toUpperCase();
String vidAndPid = String.format("VID_%s&PID_%s", vendorIdHexString, productIdHexString);
return vidAndPid;
}
/**
* From all Usb devices find those with USB 3.0. The value bcdUsb is a hexadecimal coded number
* telling us the USB version.
*/
private List<UsbDevice> getAllUsb3Devices() throws UsbException {
List<UsbDevice> devicesUSB3 = Lists.newArrayList();
UsbServices services = new org.usb4java.javax.Services();
UsbHub hub = services.getRootUsbHub();
List<UsbDevice> devices = getAllUsbDevices(hub);
for (UsbDevice device : devices) {
UsbDeviceDescriptor descriptor = device.getUsbDeviceDescriptor();
short bcdUsb = descriptor.bcdUSB();
String bcdDecoded = DescriptorUtils.decodeBCD(bcdUsb);
if (Objects.equal(bcdDecoded, "3.00")) {
devicesUSB3.add(device);
}
}
return devicesUSB3;
}
/**
* UsbHubs can either mount UsbDevices or further UsbHubs. This method searches through the tree
* of UsbHubs for UsbDevices and returns them as list.
*/
private List<UsbDevice> getAllUsbDevices(UsbHub hub) {
List<UsbDevice> devices = Lists.newArrayList();
List<UsbDevice> attachedDevices = hub.getAttachedUsbDevices();
for (UsbDevice device : attachedDevices) {
if (device instanceof UsbHub) {
List<UsbDevice> subdevices = getAllUsbDevices((UsbHub) device);
devices.addAll(subdevices);
} else {
devices.add(device);
}
}
return devices;
}
}
PowerShell script:
# $input = "VID_XXXX&PID_XXXX (this line is added in Java Code)
# For given VID and PID of a USB device we search for
# the corresponding logical disk to get the drive letter.
# The chain of objects is:
# PnPEntity (PnP = Plug and Play)
# -> USBController
# -> Some associator of USBController that has a related disk drive
# -> diskDrive
# -> diskPartition
# -> logicalDisk
# Find PnPEntity for given VID and PID
$usbPnPEntity = (gwmi Win32_PnPEntity | where DeviceID -match $input)
# Get USB Controller related to PnP Entity
$usbController = $usbPnPEntity.getRelated("Win32_USBController")
$usbControllerID = $usbController.DeviceID
# Find objects associated with the USB Controller
$query = "ASSOCIATORS OF {Win32_USBController.DeviceID='$usbControllerID'}"
$associators = ([wmisearcher]$query).get()
# Search through associators
foreach ($associator in $associators) {
# Find associator that is related to a disk Drive
$assoDeviceID = $associator.DeviceID
$diskDrive = (gwmi win32_diskdrive | where PNPDeviceID -eq $assoDeviceID)
if($diskDrive){
# Get logical Disk related to the disk drive
$logicalDisk = $diskDrive.getRelated("Win32_DiskPartition").getRelated("Win32_LogicalDisk")
# Print device ID which is the drive letter (e.g. "C:")
$logicalDisk.DeviceID
break
}
}
Maven dependencies:
<dependency>
<groupId>org.usb4java</groupId>
<artifactId>usb4java-javax</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.profesorfalken</groupId>
<artifactId>jPowerShell</artifactId>
<version>3.1.1</version>
</dependency>
Hello this is my method to get the used mobile data for every installed application in an android phone but it only get me the data used by my app not all the apps
I need it to get the data mobile used by every app installed in the phone
void OthernetworkUsage() {
List<PackageInfo> packs = getPackageManager().getInstalledPackages(PackageManager.GET_PERMISSIONS);
for(PackageInfo p : packs){
// if(!isSystemPackage(p)){
if(usesInternet(p)) {
long received = TrafficStats.getUidRxBytes(p.applicationInfo.uid);
long sent = TrafficStats.getUidTxBytes(p.applicationInfo.uid);
String appName = p.applicationInfo.loadLabel(getPackageManager()).toString();
int uid = p.applicationInfo.uid;
Toast.makeText(this, "uid: "+uid+"/Kb - name: "+appName+": Sent = "+sent/1024+"Kb, Rcvd = "+received/1024+"Kb", Toast.LENGTH_SHORT).show();
}
//}
}
}
I really need help in that case.
getConnectionState() as connected /disconnected depending on the device .if it is sending message i should see connected and if it not sending i should get disconnected .But each time i run the below java Program i am getting status as disconnected irrespective of device is sending messages or not
RegistryManager registryManager = RegistryManager.createFromConnectionString(connectionString);
System.out.println(registryManager.getDevices(new Integer(1000)));
while(true){
ArrayList<Device> deviceslist=registryManager.getDevices(new Integer(1000));
for(Device device:deviceslist)
{
/*System.out.println(device.getDeviceId());
System.out.println(device.getPrimaryKey());
System.out.println(device.getSecondaryKey());*/
System.out.println(device.getDeviceId());
System.out.println(device.getConnectionState());
/*System.out.println(device.getConnectionStateUpdatedTime());
System.out.println(device.getLastActivityTime());
System.out.println(device.getStatusReason());
System.out.println(device.getStatusUpdatedTime());
System.out.println(device.getSymmetricKey());
System.out.println(device.geteTag());
*/ }
}
I definitely am seeing otherwise.
I'm creating an simple C# console application using the code below,
static async void QueryDevices()
{
RegistryManager manager = RegistryManager.CreateFromConnectionString(connectionString);
while (true)
{
var devices = await manager.GetDevicesAsync(100);
{
foreach (var item in devices)
{
Console.WriteLine(DateTime.Now + ": " + item.Id + ", " + item.ConnectionState);
System.Threading.Thread.Sleep(100);
}
}
}
}
The git here is to always query the whole device list, because the ConnectionState property somehow looks like "static" memebers of the single device client instance, which is not apt-to change even when the actual state changes.
And my output is like below, the "connected" state is when I'm using an java client sample to send message to the IoT Hub.
I'm experimenting with java flavored zmq to test the benefits of using PGM over TCP in my project. So I changed the weather example, from the zmq guide, to use the epgm transport.
Everything compiles and runs, but nothing is being sent or received. If I change the transport back to TCP, the server receives the messages sent from the client and I get the console output I'm expecting.
So, what are the requirements for using PGM? I changed the string, that I'm passing to the bind and connect methods, to follow the zmq api for zmq_pgm: "transport://interface;multicast address:port". That didn't work. I get and invalid argument error whenever I attempt to use this format. So, I simplified it by dropping the interface and semicolon which "works", but I'm not getting any results.
I haven't been able to find a jzmq example that uses pgm/epgm and the api documentation for the java binding does not define the appropriate string format for an endpoint passed to bind or connect. So what am I missing here? Do I have to use different hosts for the client and the server?
One thing of note is that I'm running my code on a VirtualBox VM (Ubuntu 14.04/OSX Mavericks host). I'm not sure if that has anything to do with the issue I'm currently facing.
Server:
public class wuserver {
public static void main (String[] args) throws Exception {
// Prepare our context and publisher
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket publisher = context.socket(ZMQ.PUB);
publisher.bind("epgm://xx.x.x.xx:5556");
publisher.bind("ipc://weather");
// Initialize random number generator
Random srandom = new Random(System.currentTimeMillis());
while (!Thread.currentThread ().isInterrupted ()) {
// Get values that will fool the boss
int zipcode, temperature, relhumidity;
zipcode = 10000 + srandom.nextInt(10000) ;
temperature = srandom.nextInt(215) - 80 + 1;
relhumidity = srandom.nextInt(50) + 10 + 1;
// Send message to all subscribers
String update = String.format("%05d %d %d", zipcode, temperature, relhumidity);
publisher.send(update, 0);
}
publisher.close ();
context.term ();
}
}
Client:
public class wuclient {
public static void main (String[] args) {
ZMQ.Context context = ZMQ.context(1);
// Socket to talk to server
System.out.println("Collecting updates from weather server");
ZMQ.Socket subscriber = context.socket(ZMQ.SUB);
//subscriber.connect("tcp://localhost:5556");
subscriber.connect("epgm://xx.x.x.xx:5556");
// Subscribe to zipcode, default is NYC, 10001
String filter = (args.length > 0) ? args[0] : "10001 ";
subscriber.subscribe(filter.getBytes());
// Process 100 updates
int update_nbr;
long total_temp = 0;
for (update_nbr = 0; update_nbr < 100; update_nbr++) {
// Use trim to remove the tailing '0' character
String string = subscriber.recvStr(0).trim();
StringTokenizer sscanf = new StringTokenizer(string, " ");
int zipcode = Integer.valueOf(sscanf.nextToken());
int temperature = Integer.valueOf(sscanf.nextToken());
int relhumidity = Integer.valueOf(sscanf.nextToken());
total_temp += temperature;
}
System.out.println("Average temperature for zipcode '"
+ filter + "' was " + (int) (total_temp / update_nbr));
subscriber.close();
context.term();
}
}
There are a couple possibilities:
You need to make sure ZMQ is compiled with the --with-pgm option: see here - but this doesn't appear to be your issue if you're not seeing "protocol not supported"
Using raw pgm requires root privileges because it requires the ability to create raw sockets... but epgm doesn't require that, so it shouldn't be your issue either (I only bring it up because you use the term "pgm/epgm", and you should be aware that they are not equally available in all situations)
What actually appears to be the problem in your case is that pgm/epgm requires support along the network path. In theory, it requires support out to your router, so your application can send a single message and have your router send out multiple messages to each client, but if your server is aware enough, it can probably send out multiple messages immediately and bypass this router support. The problem is, as you correctly guessed, trying to do this all on one host is not supported.
So, you need different hosts for client and server.
Another bit to be aware of is that some virtualization environments--RHEV/Ovirt and libvirt/KVM with the mac_filter option enabled come to mind-- that, by default, neuter one's abilities via (eb|ip)tables to utilize mcast between guests. With libvirt, of course, the solution is to simply set the option to '0' and restart libvirtd. RHEV/Ovirt require a custom plugin.
At any rate, I would suggest putting a sniffer on the network devices on each system you are using and watching to be sure traffic that is exiting the one host is actually visible on the other.
I have this classes for my app:
NewsApp.java
ScreenApp.java
Item.java
ui/TableList.java
The app retrieve a list of links from a webservice (.net), I use KSoap Library (as Reference project).
I use JDE 4.5 for develop, because with Eclipse I cant use the method "setRowHeight(index, int)" of ListField class, then I need use JDE 4.5
Ok, I compile the app (F7 key), and run in simulator (F5 key).
In simulator, go to the icon app, and try to open... nothing happends... the app not open... are strange... no error message (ScreenApp.java line 57)... but... if I few more minutes... I see the error message (ScreenApp.java line 57)... I think maybe is because the app try connect...
Later... I think is because not exists a internet connection in simulator (I see EDGE in the top of simulator... is strange), I stop de simulator, open MDS, and run simulator again (F5 key), and now works... the list show correctly... and I can open the links in the blackberry browser.
Now... I put all compiled files in same directory, create a ALX file:
NewsApp.alx
And install this app on device, the installation works ok, I go to the list of applications on device (8520), Open the app and I see the connection message (ScreenApp.java line 57);
I dont understand why ? in this phone (8520) I have EDGE connection with my carrier, I have the WIFI active... I can browse in any page (default browser)... but my app cant retrieve information from webservice... :(
Anybody help me please ?
You need to use Different connection parameter at the end of the url when application run on the device.
For ex. in case of wifi, you need to append ;interface=wifi" at the end of the URL.
Detail code is: you need to call getConnectionString() to get the connection sufix according to device network. I hope this will solve your problem.
/**
* #return connection string
*/
static String getConnectionString()
{
// This code is based on the connection code developed by Mike Nelson of AccelGolf.
// http://blog.accelgolf.com/2009/05/22/blackberry-cross-carrier-and-cross-network-http-connection
String connectionString = null;
// Simulator behavior is controlled by the USE_MDS_IN_SIMULATOR variable.
if(DeviceInfo.isSimulator())
{
// logMessage("Device is a simulator and USE_MDS_IN_SIMULATOR is true");
connectionString = ";deviceside=true";
}
// Wifi is the preferred transmission method
else if(WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED)
{
// logMessage("Device is connected via Wifi.");
connectionString = ";interface=wifi";
}
// Is the carrier network the only way to connect?
else if((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_DIRECT) == CoverageInfo.COVERAGE_DIRECT)
{
//logMessage("Carrier coverage.");
String carrierUid = getCarrierBIBSUid();
if(carrierUid == null)
{
// Has carrier coverage, but not BIBS. So use the carrier's TCP network
// logMessage("No Uid");
connectionString = ";deviceside=true";
}
else
{
// otherwise, use the Uid to construct a valid carrier BIBS request
// logMessage("uid is: " + carrierUid);
connectionString = ";deviceside=false;connectionUID="+carrierUid + ";ConnectionType=mds-public";
}
}
// Check for an MDS connection instead (BlackBerry Enterprise Server)
else if((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_MDS) == CoverageInfo.COVERAGE_MDS)
{
// logMessage("MDS coverage found");
connectionString = ";deviceside=false";
}
// If there is no connection available abort to avoid bugging the user unnecssarily.
else if(CoverageInfo.getCoverageStatus() == CoverageInfo.COVERAGE_NONE)
{
//logMessage("There is no available connection.");
}
// In theory, all bases are covered so this shouldn't be reachable.
else
{
//logMessage("no other options found, assuming device.");
connectionString = ";deviceside=true";
}
return connectionString;
}
/**
* Looks through the phone's service book for a carrier provided BIBS network
* #return The uid used to connect to that network.
*/
private static String getCarrierBIBSUid()
{
ServiceRecord[] records = ServiceBook.getSB().getRecords();
int currentRecord;
for(currentRecord = 0; currentRecord < records.length; currentRecord++)
{
if(records[currentRecord].getCid().toLowerCase().equals("ippp"))
{
if(records[currentRecord].getName().toLowerCase().indexOf("bibs") >= 0)
{
return records[currentRecord].getUid();
}
}
}
return null;
}