I have some issues printing labels on a Zebra ZQ620 bluetooth, with ZPL commands. Some of them don't work as expected. I use Android and Zebra's SDK with the next code:
new Thread(new Runnable() {
public void run() {
try {
// Instantiate insecure connection for given Bluetooth MAC Address.
Connection thePrinterConn = new BluetoothConnectionInsecure(getcBTMAC());
// Initialize
Looper.prepare();
// Open the connection - physical connection is established here.
thePrinterConn.open();
// This example prints a label.
String zplData = "^XA" +
"^FO530,10^ATR,36,20^FD Sheet: 9999/LA Lbl.: 1 S/R: 3333^FS" +
"^FO470,10^ADR,72,30^FD" + " 123456. THIS IS A BIG TEXT" + "^FS"+
"^FO420,10^ATR,36,20^FD" + " BarCode: 2139EJC 28/09/2021 Total: 6 u.^FS\n"+
"^FO300,300^B3R,N,100,N,N^FD2139EJC^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 insecure connection to release resources.
thePrinterConn.close();
Looper.myLooper().quit();
} catch (Exception e) {
// Handle communications error here.
Log.e("PRINT", e.getMessage());
e.printStackTrace();
}
}
}).start();
The label is printed partly good (rotate as required and text displayed), but the next commands don't work as expected:
^FOx,y: I can move origin in "x" axis (width) but "y" axis value is ignored and all text is printed from bottom to top. It doesn't matter what value I put in "y" value. It always is ignored. Then, I can move origin of text y this axis.
^B3R,N,100,N,N: It ignores all parameters I put. I changed height to 100, 200, 300, include or not line text. It is always ignored. I have added a ^BY3 command previously, and It changes width but not height. Barcode is printed with only 2mm of heigth and I can't set it bigger.
^ADR,72,30: All fonts command ignore scales.
Printer configuration is:
Commands: ZPL (I have tried ZPL II, hibryd_xml_zpl, epl_zpl).
Labels: 76mm (width) x 101 mm (height) . Label separator: black mark line and space between labels.
Related
I have a goal to control some arduino device via BT with help of my android phone.
When I touch a screen and move my finger around, android app generate some data, depending on my finger position, forming a string message, and then trying to send it over BT.
The problem is, when the app attempts to send many many iterations of this command.
For example, the command is: String command = "[code]command(data)/";
When I just tap a time on a screen, the app write the command once and send it over BT, and it looks good on the other side (arduino).
But when I hold and move the finger, app trying to rewrite the command every "frame", and also trying to send this command every "frame" (I mean, every moment, many many times). And then I see something like: "[code]co[cod[co[c[mma(da]coode[c[co".
The feeling is... it gets one characters array and mixed it with another, when sending... or begin sending another message before stops sending previous.
Here is the code that gets some values on touch event:
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
initPosX = x;
break;
case MotionEvent.ACTION_MOVE:
// some code that make counts and convert values...
// prepare string as a command.
String command = "[code]command(" + value + ")/";
Log.d("command", command);
// send data via BT
sendData(command);
break;
case MotionEvent.ACTION_UP:
//code
break;
default:
break;
}
Also I have BT settings up code, it all works good.
And this is the main part. Code that sending the string:
protected void sendData(String message) {
byte[] msgBuffer = message.getBytes();
try {
outStream.write(msgBuffer);
} catch (IOException e) {
//some exception code
}
}
outStream = btSocket.getOutputStream();
So... I really don't know why this happens. I wasted entire day trying to search something about.
Will be very appreciated if someone can give me a glue, where to dig next.
Thanks.
UPDATE:
Arduino side code:
if (Serial.available() > 0) {
char c = Serial.read(); // read char from BT
serialMessage.concat(c); // add this char to string.
delay(5);
if (c == '/') {
lcd.setCursor(0,0);
lcd.print(serialMessage); // print message on a display.
command = serialMessage;
serialMessage = "";
}
}
else {
if (serialMessage != "") {
lcd.setCursor(0,0);
lcd.print(serialMessage); // print message on a display.
serialMessage = "";
}
//command = serialMessage;
}
UPDATE 2:
This is a real Serial input, when I tap once
[code]command(0.0)/
and when I move finger left and right
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.23)/
[code]cm()dm()[c]a.[em1[(/
em1[em1[]a.cca.[e)[dm(/
dm(/
em1[em1[co0ood)dmd4ood8oon2ccn0cca0/
ccn.[]a-)dm(6oon.[]a1[]od0o0[c]a1[]a1[em-/
em-)dm()dm(0odcn.cca0a.[]a.[em0/
em0)dm()dm()dm(/
em1/
em1[]a1[]a.ccn0oon7ccn4c]a.ccn.[em-)dm()oodod0ccn.ccn.[]m-/
d0ooood0ccn.ccn.[]a1[]a-/
em-/
em(5ood7c]a0/
em-)ood0[em0)dm()dm(3od)dm(/
dm(/
em1[em1[]a.c]a)dodm()ood2ccn./
ed9[]a1[]a-/
em-/
em()dm()dmd0od0ooood0oon.codecn1[]a0/
[dm(5ccn.cd0ccn1ccn.[]d4ooood7ocn3
UPDATE 3:
Taps without delay:
[
code]c
ommand(0.0)/
[code]command(0.0)/
[
code]c
ommand(0.0)/
[code]command(0.0)/
[
code]c
ommand(0.0)/
[code]command(0.0)/
UPDATE 4:
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.01)/
[code]command(0.07)/
[code]command(0.15)/
[code]command(0.23)/
[code]command(0.29)/
[code]command(0.33)/
[code]command(0.37)/
[code]command(0.41)/
[co(0.44)/
[code]commandmmand(0.51)/
[code]code]command(0.6)/
[cod0.63)/
[cod0.65)/
[code]command(0.66)67)/
[code]command(0.68)/
2)/
Yes. It was overflowed serial.
I solve this issue in two steps.
First, I decrease delay for char reading on the arduino side from 5 to 1.
Second, I send a message/command only 10 times per second.
There is a code that makes this:
public void send(String string) {
if ((System.currentTimeMillis() - lastTimeSend) > 100) {
byte[] bytes = string.getBytes();
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
lastTimeSend = System.currentTimeMillis();
}
}
I am attempting to using an IOIO-RTG board to control a MCP-4131 digital potentiometer via SPI. I'm new to SPI but I believe that I've followed the SPI example. I'm able to set a resistance apparently but IOIO remains stuck afterwards. The only way to continue is to disconnect and reconnect to the board. I note that the SPI example expects a MISO and MOSI pin whereas the pot has a combined SDI/SDO pin. Is this difference the source of my issue?
IOIO RTG
IOIOLIb 0326
Application Firmware 0506
Bootloader Firmware 0402
Hardware Sprk 0020
I've tried to implement asynchronous transactions to not wait for a response but the end result is the same. I've called the highgear function from within the Looper class and outside with no change.
class Looper extends BaseIOIOLooper
{
SpiMaster spi;
protected void setup() throws ConnectionLostException
{
int clkPin = 39;//left side = 36
int misoPin = 38;//left side = 33, not expecting output
int mosiPin = 38;//left side = 35
spi = ioio_.openSpiMaster(new DigitalInput.Spec(misoPin,
Mode.PULL_UP), new DigitalOutput.Spec(mosiPin),
new DigitalOutput.Spec(clkPin),
new DigitalOutput.Spec[] { new DigitalOutput.Spec(40), new DigitalOutput.Spec(37), },
new SpiMaster.Config(Rate.RATE_125k, true, true));
}
public void highgear()
{
byte[] request = new byte[] {0,0,0,0,0,5,5,5};
byte[] response = new byte[4];
try {
SpiMaster.Result result = spi.writeReadAsync(0, request, request.length, 7, response, 0);
} catch (ConnectionLostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The expected outcome is that the MCP with give the desired resistance and the IOIO will be available for further commanding. There are no errors as the board just freezes in it's set configuration.
The shared SDO/SDI pin of the MCP-4131 should not be the problem.
From the datasheet on page 31: "The 8-lead Single Potentiometer devices are pin limited so the SDO pin is multiplexed with the SDI pin (SDI/SDO pin). After the Address/Command (first 6-bits) are received, If a valid Read command has been requested, the SDO pin starts driving the requested read data onto the SDI/SDO pin."
As long as you only write to the digital potentiometer everything should be the same as with other SPI devices.
Have you tried your code with other SPI devices or even without connecting one?
First of all, I saw an existing question (JCIFS: file retrieval is too slow to be usable), but it was for Java, not Android, and none of the suggested answers worked.
I created a default project for Android SDK 25 (7.1.1) in Android Studio 2.3, linked the library with compile 'jcifs:jcifs:1.3.17', and typed the following simple test code. The result is below the code.
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jcifs.Config.setProperty("jcifs.util.loglevel", "3");
//jcifs.Config.setProperty("jcifs.smb.client.dfs.disabled", "false");
//jcifs.Config.setProperty("jcifs.resolveOrder", "DNS");
try
{
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", ID, PASSWORD);
final SmbFile smb = new SmbFile("smb://192.168.XX.XX/Share/FileName", auth);
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
Log.d(TAG, "Test Start");
for(int i = 1000; i<10000; i+=1000)
measure(i);
Log.d(TAG, "Test End");
}
private void measure(int bufferSize)
{
Log.d(TAG, "=====Buffer: " + bufferSize + "============");
try
{
byte[] buffer = new byte[bufferSize];
int read = 0;
InputStream str = smb.getInputStream();
long start = System.nanoTime();
while(read < 1000000)
read += str.read(buffer);
long end = System.nanoTime();
str.close();
float time = (float) ((end - start) / 1000000000d);
float speed = (float) read / 1048576 / time;
Log.d(TAG, "Time:" + time + ", size =" + read);
Log.d(TAG, "Speed = " + speed + "MB/s");
}
catch(IOException exc)
{
exc.printStackTrace();
}
}
});
t.start();
}
catch(Exception exc)
{
Log.d(TAG, exc.toString());
}
}
Result
Test Start
=====Buffer: 1000============
Time:2.210785, size =1000000
Speed = 0.43137363MB/s
=====Buffer: 2000============
Time:1.4158936, size =1000000
Speed = 0.6735495MB/s
=====Buffer: 3000============
Time:1.0556641, size =1002000
Speed = 0.9051948MB/s
=====Buffer: 4000============
Time:0.7543335, size =1000000
Speed = 1.2642609MB/s
=====Buffer: 5000============
Time:3.6557617, size =1000000
Speed = 0.26086885MB/s
=====Buffer: 6000============
Time:3.292389, size =1002000
Speed = 0.2902396MB/s
=====Buffer: 7000============
Time:2.9179688, size =1001000
Speed = 0.32715496MB/s
=====Buffer: 8000============
Time:2.462616, size =1000000
Speed = 0.38726068MB/s
=====Buffer: 9000============
Time:3.9379272, size =1008000
Speed = 0.24411413MB/s
Test End
Read speed is about 0.2MB/s ~ 1.2MB/s. The device is connected to a 150Mbps Wi-Fi, so, theoretically it can achieve above 10MB/s. The SMB server is not slow either. When I copied the file to a laptop, the read speed was about 30MB/s.
Why is this so slow? What should I check? Why is the read speed about 5 times higher (1.2MB/s) if the buffer size is 4000?
By the way, I have tested copying the same file with other commercial apps. File Commander, Asus File Manager showed similary low speed, ES File Explorer showed about 2MB/s, and Solid Explorer showed about 5MB/s. Since I am pretty sure that all of them use JCIFS (albeit perhaps slightly different versions of it), there must be a way to achieve at least 5MB/s as Solid Explorer does.
After using WireShark (network analysis tool) on the Windows computer, I have found that no matter which buffer size I set, the read SMB command always gives 4286 bytes to the Windows computer. It seems that SmbFileInputStream.java is using the max buffer size from the server.
But when I saw the packets from Soild Explorer, it was 32768 bytes. So, I decompiled Solid Explorer's APK (it was of course obfuscated), and saw the SmbFileInputStream.java file inside of it (that file belongs to JCIFS). It seems that the developers of Solid Explorer has modified that file, and set a bigger readSize. So, I tried a similar thing. And then I achieved 5MB/s for the same code above.
Since JCIFS comes with LGPL, the fact that Solid Explorer is using a modified JCIFS without disclosing the source code is a violation of JCIFS' licence. But, oh well, it seems a lot of Android app developers ignores licence of the libraries they use anyway. They do not even properly credit the open-source libraries they used.
Did you try with: jcifs.Config.setProperty("jcifs.smb.client.dfs.disabled", "true");
In my case (though Java) it was helpful for slow connection. By default it is false
Only problem for me is that I'm not sure will that property "break" something else which is working fine..
There is a patch for large buffer size reading:
https://github.com/kohsuke/jcifs/issues/11
https://github.com/kohsuke/jcifs/tree/master/patches
https://jcifs.samba.org/src/patches/LargeReadWrite.patch:
From inside the README:
This patch adds two SMBs that supposedly improves read and write
performance considerably. Unfortunately it's not crystal clear that
all implementation properly support the commands. Note that in
addition to this patch an '& 0xFFFF' needs to be added in
SmbTransport.java:doRecv:~437 to appear as:
int size = Encdec.dec_uint16be( BUF, 2 ) & 0xFFFF;
although this change has been made in 1.2.7.
Not sure if this works with Android, but the solution could be similar.
Background
I've noticed a weird column for MediaStore.Images.ImageColumns called "MINI_THUMB_MAGIC" .
the documentation says just that :
The mini thumb id.
Type: INTEGER
Constant Value: "mini_thumb_magic"
The question
my guess is that this field is related to MediaStore.Images.Thumbnails .
Is it correct ? if not, what is this and how do you use it?
if it is correct , i have other questions related to it:
Is it a mini sized image of the original one? does it use the same aspect ratio or does it do center-cropping on it?
how come the size of "MICRO" is square (96 x 96) and the size of "MINI" is a non-square rectangle ( 512 x 384 ) ?
How do you use it? My guess is that it's done by using "THUMB_DATA", which is a blob, so you use it like this, but then what is the purpose of using "getThumbnail" if you already have this field?
does it get a rotated thumbnail in case the orientation value is not 0 ? meaning that if I wish to show it, I won't need to rotate the image?
Is it possible to do a query of the images together with their thumbnails? maybe using inner join?
Is it available for all Android devices and versions?
Why is it even called "magic" ? Is it because it's also available for videos (and for some reason doesn't exist for music, as it could be the album's cover photo, for example) ?
Check this file: https://github.com/android/platform_packages_providers_mediaprovider/blob/master/src/com/android/providers/media/MediaThumbRequest.java in the Android source code. This value is some magic number which allows to determine if the thumbnail is still valid. I didn't investigate that file further, but it should be no bit issue to dive deeper.
To your questions:
No, no mini-sized image
Well, I guess it's a definition by Google who want to have a square thumbnail for some lists, where only very small previews should be visible and where many items should fit on the screen and there's another thumbnail format where the images are bigger...
I don't know that, but according to Google's doc, one (THUMB_DATA) is only some raw byte array of the thumbnail (dunno in which format) and the other one (getThumbnail) retrieves a full-fledged bitmap object...
don't know
don't know
I guess so, as it's part of AOSP source code.
The word "magic" is often used for some kind of identifier. There are "magic packets" who can wake up a computer from sleep or shutdown over the network, there are magic numbers on hard disks, where some sectors (e.g. the MBR) has the hexadecimal values AA 55 on its last two byte positions, there are also magic numbers in image files which help software packages determine the image type (e.g. GIF files begin with GIF89a or GIF87a (ASCII), JPEG files begin with FF D8 hexadecimal) and there are many, many more examples. So, magic numbers are a very common term here :-)
According to the source code at the following URL, the Magic Number is the Id of the original image * a constant. That value is then used to check for a long int. If the int isn't as expected, it's considered out of sync with the image media.
http://grepcode.com/file/repo1.maven.org/maven2/org.robolectric/android-all/4.4_r1-robolectric-0/android/media/MiniThumbFile.java#MiniThumbFile.getMagic%28long%29
// Get the magic number for the specified id in the mini-thumb file.
// Returns 0 if the magic is not available.
public synchronized long getMagic(long id) {
// check the mini thumb file for the right data. Right is
// defined as having the right magic number at the offset
// reserved for this "id".
RandomAccessFile r = miniThumbDataFile();
if (r != null) {
long pos = id * BYTES_PER_MINTHUMB;
FileLock lock = null;
try {
mBuffer.clear();
mBuffer.limit(1 + 8);
lock = mChannel.lock(pos, 1 + 8, true);
// check that we can read the following 9 bytes
// (1 for the "status" and 8 for the long)
if (mChannel.read(mBuffer, pos) == 9) {
mBuffer.position(0);
if (mBuffer.get() == 1) {
return mBuffer.getLong();
}
}
} catch (IOException ex) {
Log.v(TAG, "Got exception checking file magic: ", ex);
} catch (RuntimeException ex) {
// Other NIO related exception like disk full, read only channel..etc
Log.e(TAG, "Got exception when reading magic, id = " + id +
", disk full or mount read-only? " + ex.getClass());
} finally {
try {
if (lock != null) lock.release();
}
catch (IOException ex) {
// ignore it.
}
}
}
return 0;
}
I got the runtime exception when trying to get the original Id of a thumbnail by looking up the thumbnail's path. (BTW, the disk isn't full and it's not read-only.)
It's a bit strange parameter...
While exploring the Gallery source code,
noticed that the value is being read from the cursor, but then is Never used:
#Override
protected BaseImage loadImageFromCursor(Cursor cursor) {
long id = cursor.getLong(INDEX_ID);
String dataPath = cursor.getString(INDEX_DATA_PATH);
long dateTaken = cursor.getLong(INDEX_DATE_TAKEN);
if (dateTaken == 0) {
dateTaken = cursor.getLong(INDEX_DATE_MODIFIED) * 1000;
}
// here they read it ====>>
long miniThumbMagic = cursor.getLong(INDEX_MINI_THUMB_MAGIC);
int orientation = cursor.getInt(INDEX_ORIENTATION);
String title = cursor.getString(INDEX_TITLE);
String mimeType = cursor.getString(INDEX_MIME_TYPE);
if (title == null || title.length() == 0) {
title = dataPath;
}
// and not use at all ==>>>
return new Image(this, mContentResolver, id, cursor.getPosition(),
contentUri(id), dataPath, mimeType, dateTaken, title,
orientation);
}
Maybe it was used on the previous APIs.
ref: https://android.googlesource.com/platform/packages/apps/Gallery/+/android-8.0.0_r12/src/com/android/camera/gallery/ImageList.java?autodive=0%2F%2F.
and videos list:
https://android.googlesource.com/platform/packages/apps/Gallery/+/android-8.0.0_r12/src/com/android/camera/gallery/VideoList.java?autodive=0%2F%2F
What i´m trying to do is to print a label with zebra mz220 using the information I have in my SQLite database, but I don´t know how to fill in the label using strings. Here is my code so far
case R.id.bprint:
new Thread(new Runnable() {
public void run() {
try {
// Instantiate connection for given Bluetooth® MAC Address.
ZebraPrinterConnection thePrinterConn = new BluetoothPrinterConnection("00:22:58:3C:9F:0B");
// Initialize
Looper.prepare();
// Open the connection - physical connection is established here.
thePrinterConn.open();
// here it should fill in the label but it doesn't =(
thePrinterConn.write("Input (ENCODING.LBL):! 0 200 200 200 1 ENCODING UTF-8 TEXT 0 20 30 r/n/ PRINTr/n/".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();
break;
case R.id.spb:
startActivity(new Intent(this, Barcode.class));
break;
please help, thanks
The code looks appropriate, but unfortunately your comment "I don't know how to fill in the label using strings" isn't very clear. What is the outcome when you run your code? What are you trying to achieve? As an example, you can send the following data to the printer in your 'write' call. Assuming your printer is in CPCL mode:
thePrinterConn.write("! 0 200 200 210 1\r\nTEXT 4 0 30 30 Hello world\r\nFORM\r\nPRINT\r\n" .getBytes());
CPCL manual section 2 page 3: support.zebra.com/cpws/docs/comtec/PROMAN-CPCL_RevY.pdf