I am following the Zebra Android Link_OS SDK sample code for printing a test label on a ZQ510 over Bluetooth, but it won't print in ZPL format.
Here is the code I'm running to print the label:
private void sendZplOverBluetooth(final String theBtMacAddress) {
new Thread(new Runnable() {
public void run() {
try {
// Instantiate connection for given Bluetooth® MAC Address.
Connection thePrinterConn = new BluetoothConnection(theBtMacAddress);
// Initialize
Looper.prepare();
// Open the connection - physical connection is established here.
thePrinterConn.open();
// This example prints "This is a ZPL test." near the top of the label.
String zplData = "^XA^FO20,20^A0N,25,25^FDThis is a ZPL test.^FS^XZ";
// Send the data to printer as a byte array.
thePrinterConn.write(zplData.getBytes());
// Make sure the data got to the printer before closing the connection
Thread.sleep(500);
// Close the connection to release resources.
thePrinterConn.close();
Looper.myLooper().quit();
} catch (Exception e) {
// Handle communications error here.
e.printStackTrace();
}
}
}).start();
}
And here is the result of the print. (I ran it twice, that's why there are two test prints).
Then I read about how it might be in a different mode because for some reason Zebra can't detect their own proprietary language. So I tried to get the settings and see through the Android app. Again using the given Link-OS SDK example code:
private static void displaySettings(Connection c) throws ConnectionException, ZebraPrinterLanguageUnknownException, SettingsException, ZebraIllegalArgumentException {
ZebraPrinter genericPrinter = ZebraPrinterFactory.getInstance(c);
ZebraPrinterLinkOs linkOsPrinter = ZebraPrinterFactory.createLinkOsPrinter(genericPrinter);
if (linkOsPrinter != null) {
System.out.println("Available Settings for myDevice");
Set<String> availableSettings = linkOsPrinter.getAvailableSettings();
for (String setting : availableSettings) {
System.out.println(setting + ": Range = (" + linkOsPrinter.getSettingRange(setting) + ")");
}
System.out.println("\nCurrent Setting Values for myDevice");
Map<String, String> allSettingValues = linkOsPrinter.getAllSettingValues();
for (String settingName : allSettingValues.keySet()) {
System.out.println(settingName + ":" + allSettingValues.get(settingName));
}
String darknessSettingId = "print.tone";
String newDarknessValue = "10.0";
if (availableSettings.contains(darknessSettingId) &&
linkOsPrinter.isSettingValid(darknessSettingId, newDarknessValue) &&
linkOsPrinter.isSettingReadOnly(darknessSettingId) == false) {
linkOsPrinter.setSetting(darknessSettingId, newDarknessValue);
}
System.out.println("\nNew " + darknessSettingId + " Value = " + linkOsPrinter.getSettingValue(darknessSettingId));
}
}
This time, I get a SettingsException with the description of Operation cannot be performed on raw channel with a printer set to line print mode
How am I able to print ZPL text using a Mac and developing Android correctly? I read about using some Zebra Utility app for changing the mode, but it's only available for Windows, and their Android app doesn't work.
Regardless, if someone was to use the app with a printer in the incorrect mode, they would have to go through all this unnecessary setup that wouldn't be intuitive for just anybody.
Thanks for the help and appreciate any feedback.
You can programmatically set the print mode to ZPL, it's currently in line-mode.
To do so:
BluetoothConnection printerIns= new BluetoothConnection(theBtMacAddress);
ZebraPrinter zPrinterIns = ZebraPrinterFactory.getInstance(printerIns);
//Set printer to ZPL mode
zPrinterIns.sendCommand("! U1 setvar \"device.languages\" \"zpl\"\r\n");
//Feed and calibrate to the media
zPrinterIns.sendCommand("~jc^xa^jus^xz");
In your example code, You are establishing a Bluetooth connection and attempting to send raw data, make use of the ZebraPrinterand BluetoothConnection classes provided by Zebra instead from the com.zebra.sdk.printer namespace.
I corrected your code, it should work now.
new Thread(new Runnable() {
public void run() {
try {
// Instantiate connection for given Bluetooth® MAC Address.
BluetoothConnection thePrinterConn = new BluetoothConnection(theBtMacAddress);
// Initialize
Looper.prepare();
// Open the connection - physical connection is established here.
ZebraPrinter zPrinterIns = ZebraPrinterFactory.getInstance(thePrinterConn);
zPrinterIns.sendCommand("! U1 setvar \"device.languages\" \"zpl\"\r\n");
zPrinterIns.sendCommand("~jc^xa^jus^xz");
Thread.sleep(500);
// Send the data to printer as a byte array.
zPrinterIns.sendCommand("^XA^FO20,20^A0N,25,25^FDThis is a ZPL test.^FS^XZ");
// Make sure the data got to the printer before closing the connection
Thread.sleep(500);
// Close the connection to release resources.
thePrinterConn.close();
Looper.myLooper().quit();
} catch (Exception e) {
// Handle communications error here.
e.printStackTrace();
}
}
}).start();
If you don't want to perform this step programmatically like in the Dayan answer and you have acces to a Windows machine (or emulating one), install the Zebra Setup Utilities. Then following the instructions here https://km.zebra.com/kb/index?page=content&id=SO7296 to switch the print mode to ZPL with the command
! U1 setvar "device.languages" "zpl"
Related
I would like to create an application which can connect to a Bluetooth Headset via the Hands Free Protocol (HFP). I followed the Android example and have now a BluetoothSocket with its Input and OutputStream. Below you see my read and write methods (read method is executed by another Thread)
public void read() {
while (true) {
Log.d("ME", "Waiting for data");
try { // read until Exception is thrown
numBytes = inStream.read(dataBuffer);
String str = new String(dataBuffer,0,numBytes);
msgHandler.obtainMessage(numBytes, str).sendToTarget();
} catch (Exception e) {
Log.d("ME", "Input stream was disconnected", e);
break; // BluetoothDevice was disconnected => Exit
}
}
}
public void write(byte[] bytes) {
try {
outStream.write(bytes);
outStream.flush();
Log.e("ME", "Wrote: " + new String(bytes));
} catch (IOException e) {
Log.e("ME", "Error occurred when sending data", e);
}
}
When the connection is opened the Bluetooth headset sends AT+BRSF=191 over the InputStream. I tried to response with +BRSF:20\r but here is my problem. After that the device does not send any other data over the InputStream. It does not come to an Exception - it's more like the device does not know how to responde to my message. Do I send the wrong data? I have all the information from here: (HF = Hands-Free Unit AG = Audio Gateway)
Do you have any ideas what I did wrong? Have I missed something?
EDIT: These are my write calls:
write("+BRSF: 191\r");
write("OK\r");
You were missing the OK response. According to this document, the OK-code consists of a windows-style newline (CR LF), the literal OK and then another newline.
Do note that other commands are terminated by a carriage return only. For more information on the hands-free protocol, you can refer to that very document you linked in your post.
Example code:
public static final String OK = statusCode("OK")
public static final String ERROR = statusCode("ERROR")
public static String statusCode(String code) {
return "\r\n" + code + "\r\n";
}
public static String command(String cmd) {
return cmd + "\r";
}
Now you can use OK and ERROR in your code as constants, and you can use the statusCode method for other status codes.
I am trying to make an andorid app that commuicates with my server via Unity 5.4. The Devices need to be in the same network to do so.
For that i am using System.Net.Sockets and a TcpClient to connect to my server. Everything works well when i run it out of the Editor, or build it as a Windows standalone.The communication between a pc hosting the service and a diffrent pc running the standalone is possible and working as intended. As soon as i build it as an .apk and install it on my smartphone i will get a SocketException. Also my phone is stuck loading for quite some time
Is using a TcpClient, is that possible on android with unity3d ?
The Exception i get is:
System.Net.Sockets.SocketException: Connection timed out
I made sure that both devices are in the same network, e.g. the Ip for my Pc hosting the server is 192.168.178.24 and the ip for my smartphone is 192.168.178.113.
The ports required are open and the firewall lets data through.
I am runnig this code in Unity:
private TcpClient client;
private StreamWriter writer;
void Start()
{
try
{
client = new TcpClient(AddressFamily.InterNetwork);
IPAddress ipAddress = IPAddress.Parse(PlayerPrefs.GetString(MenuManager.IpPlayerPrefKey));
Debug.Log(ipAddress.ToString());
client.Connect(ipAddress, 11000);
writer = new StreamWriter(client.GetStream());
Debug.Log("connected");
}
catch (ArgumentNullException ane)
{
Debug.Log(string.Format("ArgumentNullException : {0}", ane.ToString()));
}
catch (SocketException se)
{
Debug.Log(string.Format("SocketException : {0}", se.ToString()));
}
catch (Exception e)
{
Debug.Log(string.Format("Unexpected exception : {0}", e.ToString()));
}
}
i double checked if the Ip adress recieved from the player prefs is correct, it is.
Has someone an idea what causes it to not even establish a connection ? I tried Wireshark on my pc, it didn't show any incoming packages, so my guess is the mistake is sometimes during establishing the connection.
Here is an image for my Log output from the smartphone:
LogCat Output
Edit: Server Code
public class ServiceListener
{
public TcpListener Listener;
public void StartListening()
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = Array.Find<IPAddress>(ipHostInfo.AddressList, ipMatch => ipMatch.AddressFamily == AddressFamily.InterNetwork);
Listener = new TcpListener(ipAddress, 11000);
Listener.Start();
}
public void StopListening()
{
Listener.Stop();
}
}
static void Main()
{
ServiceListener currentListener = new ServiceListener();
currentListener.StartListening();
TcpClient currentClient = currentListener.Listener.AcceptTcpClient();
StreamReader reader = new StreamReader(currentClient.GetStream());
Console.WriteLine("Connected");
while (true)
{
byte[] messageBytes = new byte[1024];
if (!reader.EndOfStream)
{
string message = reader.ReadLine();
string[] messageParts = message.Split('|');
int xOffset = int.Parse(messageParts[0]);
int yOffset = int.Parse(messageParts[1]);
bool leftClick = bool.Parse(messageParts[2]);
bool rightClick = bool.Parse(messageParts[3]);
Console.WriteLine(string.Format("x:{0},y:{1},left:{2},right:{3}", xOffset, yOffset, leftClick, rightClick));
}
else
{
currentClient = currentListener.Listener.AcceptTcpClient();
reader = new StreamReader(currentClient.GetStream());
}
}
}
Is using a TcpClient, is that possible on android with unity3d ?
Yes, it is. It is very possible and should work.
Your problem is very likely to come from this line of code:
IPAddress ipAddress = IPAddress.Parse(PlayerPrefs.GetString(MenuManager.IpPlayerPrefKey));
Since your hosting server IP is 192.168.178.24. Hardcode the value for testing purposes to see if PlayerPrefs.GetString(MenuManager.IpPlayerPrefKey) is returning an invalid IP Address.
Maybe something like:
IPAddress ipAddress = IPAddress.Parse("192.168.178.24");
Another thing to do in your server code is to put Application.runInBackground = true; in your Start() function. This will make sure that your server is running even when the Applciation is not on focus.
Finally, you are currently using synchronous server socket. When connecting, receiving data from the server, Unity will block/freeze until that operation completes. You should use asynchronous socket or run your server and client code in another Thread. This does not look like the current problem but you will run into it later on.
I am developing a restaurant app which print receipts after customer purchases foods. I have added a config screen in app which the manager uses to configure printers. A manager can print a test page to test whether he has entered right ip and port. Here is my code which prints test page:
private class PrintTask extends AsyncTask<Printer, Boolean, String> {
#Override
protected String doInBackground(Printer... params) {
try {
publishProgress(true);
Socket sock = new Socket(params[0].getIp(), Integer.parseInt(params[0].getPort()));
PrintWriter oStream = new PrintWriter(sock.getOutputStream());
oStream.printf("--------------------------------\r\n");
oStream.printf("*** TEST PRINT ***\r\n");
oStream.printf("You have configured your \n\r");
oStream.printf(params[0].getName());
oStream.printf("\r\nprinter successfully\n\r");
oStream.printf("| Thanks |\r\n");
oStream.printf("--------------------------------\r\n");
oStream.close();
sock.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
publishProgress(false);
return "";
}
#Override
protected void onProgressUpdate(Boolean... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
if(!values[0]) {
waitView.setVisibility(View.GONE);
}
else {
waitView.setVisibility(View.VISIBLE);
}
}
}
The problem is if I print on a network printer (a stand alone printer without attaching to any PC) it prints text properly. Here I am using the ip and default port 9100. But when I print to a shared printer attached to a PC, it fails to print. Any idea, where I am doing wrong...???
From what your describe it looks like that standalone printer is running some kind of "text printing service" on your given port. So looks like everything you send to this port will be printed as text.
Whereas when you have "Shared" printer on your Windows machine, it's implemented using Windows Printer service or smth like that. It's not just simple socket/port anymore where you can write ASCII text.
I'm developing an Android real-time-data app that sends data (floats and ints) to a server on the local subnet via a TCP socket. The problem I'm facing is that after sending some data simultaneously the socket doesn't send anymore data at all. I debugged the app and it shows that data is being sent but doesn't show up on the server. After this happens if I close the connection the server doesn't even get the notification that the connection has been terminated which it should according to my design model. Meanwhile I get an exception on the app saying it can not write to a broken pipe. This tells me that the problem is with the app because I also did test using a desktop app and I can send huge amounts of data to the server and it gets delivered.
And please keep in mind that the data size I'm talking about here is 252 bytes per packet.
Here's my class I'm using. (This runs in an AsyncTask object )
public class Network
{
private Socket handle;
public static enum TASK
{
TASK_CONNECT, TASK_SEND, TASK_CLOSE
}
public Network()
{
}
public String lastError = "";
public boolean Connect(String host, int port)
{
try
{
lastError = "Connecting to server.";
handle = new Socket(host, port);
handle.setTcpNoDelay(true); //
handle.setSendBufferSize(SIZE_OF_PACKET); ///==> These don't seem to help at all
handle.setKeepAlive(true); ///
return true;
}catch(IOException e)
{
lastError += e.getMessage() != null ? " "+ e.getMessage() : "";
return false;
}
}
private void err(String e){
System.err.println(e);
}
private boolean SendPacket(byte buffer[])
{
OutputStream oStream = null;
err("sending: " + buffer.length + " bytes");
try
{
lastError = "Obtaining output stream.";
oStream = handle.getOutputStream();
lastError = "Error sending data.";
oStream.write(buffer);
oStream.flush();
return true;
}catch(Exception e)
{
lastError += e.getMessage() != null ? " "+ e.getMessage() : "";
}
return false;
}
public void Close()
{
try{ handle.close(); handle = null; }catch(Exception e){} // swallow exception
}
}
I send my data in a loop depending on how many numbers I have. I tried a Google search but didn't find anything relevant. Has anyone experienced this before? It's making me mad now.
EDIT: Wireshark shows incoming "red" packets that don't reach the desktop app (server)
Look at this picture.
You can see the first few have Len > 0 the red ones have 0.
I think it's time Google interfaced the USB so we can use it. At least that'd would have been my first option.
Should you not be calling oStream.close() after you flush the stream, given that you never use it again?
Also, you say that this is being run in an AsyncTask object. Is it possible that multiple threads could be attempting to send packets at the same time? If so, you might need some form of synchronisation around the SendPacket method.
Ok. I solved the issue by using UDP instead. Thank you all.
But I still didn't find the source of the problem.
I have written this code for pinging class C IP addresses on port 6789, the thread starts when I click on a button called PING. It will retrieve all IP addresses that has the port 6789 open. But what I need is to refresh (re-ping) every, let's say 5 seconds, and add IPs recently joined if exist and omit ones that leave the port. Unfortunately another issue appears. When I started the application the first iteration of the while (true) works perfectly, and it adds any IP that had the port 6789 open to the ArrayList ips_List and then display it on the ListView, and when another device joins the port, my phone will add it to the ips_List also. BUT in the second iteration after the Thread sleeps 5 seconds and then begins to re-ping the IPs from (x.x.x.1 - x.x.x.254) to see if another IP had joined the port when pinging to an IP previously pinged, the Socket will throw IOException (as written in the code).
Why is that happening?
Thread pingo = new Thread(new Runnable() {
public void run() {
while (true) {
if (readableNetmask.equals("255.255.255.0")) {
for (int i = 2; i <= 25; i++) {
String ip_address = readableIPAddress;
String oct1 = "", oct2 = "", oct3 = "", oct4 = "";
StringTokenizer stok = new StringTokenizer(
ip_address, ".");
while (stok.hasMoreTokens()) {
oct1 = stok.nextToken();
oct2 = stok.nextToken();
oct3 = stok.nextToken();
oct4 = stok.nextToken();
}
to_ping_ip = oct1 + "." + oct2 + "." + oct3
+ "." + String.valueOf(i);
if (pingAddress(to_ping_ip, 6789)) {
ips_List.add(to_ping_ip);
}
}
}
// delay 10 seconds, then re-ping
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
break;
}
handler.post(new UpdateIPListViewRunnable());
}
}
});
pingo.start();
PingAddress() function:
public boolean pingAddress(String ip, int port) {
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(ip, port), 200);
socket.close();
} catch (IOException e) {
return false;
}
return true;
}
List where addresses appear:
static public class UpdateIPListViewRunnable implements Runnable {
public void run() {
arrayAdapter.clear();
for (int i = 0; i < ips_List.size(); i++) {
arrayAdapter.add(ips_List.get(i));
arrayAdapter.notifyDataSetChanged();
}
ips_List.clear();
}
}
Your problem is likely in your atypical usage of the word "ping". Traditionally, this refers to sending an ICMP echo request, which does not involve connection state, but is also often not allowed to ordinary user IDs such as your application will run under.
You appear to be using a stateful TCP connection instead, and may be running into difficulty in if your server is not tuned to be able to accept rapid reconnects. So you may want to try testing your server using some other client. You could also have a problem in that TCP will keep trying to get the traffic through, so it won't quickly report network troubles. You may even be ending up with multiple attempts overlapping in time.
Your best solution though would probably be to switch from TCP, which is ill suited to this task, to UDP, which is probably a better match. UDP does not have connection state, and it's also unreliable in that no automatic retries are attempted. You should be able to find a UDB echo server and client type example with a web search.
Thank you #Chris Stratton ... and there is noway that I am changing to protocol to UDP since my project's structure is build over the TCP architecture ... now for my problem I finally FOUND the solution; in my app i have a ServerSocket that is used for pinging ... now considering there are two mobiles with the same app, if PING button clicked then it will ping the other device and and the other device will accept() the connection then close() it. Now on the first mobile it will iterates another time (while(true)) and ping the same device, but that device has the ServerSocket closed so it will returns false. For this is used a recursive thread that when a mobile 1 pings mobile 2, mobile 2 will close the ServerSocket and immediately calls the same thread so the ServerSocket is opened to other pings. I tried it and it worked very well :DDD
[#Experts: any enhancements for this solution!]
Recursive Thread:
static public class ReceivePingThread extends Thread {
public void run() {
try {
ServerSocket joinPort = new ServerSocket(6789, 100);
joinPort.accept();
joinPort.close();
ReceivePingThread ReceivePingThread = new ReceivePingThread();
ReceivePingThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}