ESC/POS Long String Barcode Not Scanable - android

I'm working on Chinese Bluetooth thermal printer Model:SCAN-X, Problem is barcodes for long strings are not scannable:
0123456789 -- printed & scannable
abcdefghijklmno -- printed & not scannable
INV-1-48 -- printed & scannable
INW-0001-0000000047 --- printed & not scannable
INW-001-0123456789 --- printed & scannable
INW-0001-123456789 --- printed & not scannable
Here is specified guide in ESC/POS doc of printer
I am bit confused is there something wrong with my code?
private void printBarcodeTest() {
OutputStream out = null;
try {
if ((socket == null) || (!socket.isConnected())) {
socket = BluetoothUtil.getSocket(mBluetoothPrinterDevice);
}
out = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
// String barcodeContent1 = "INW-1-47"; // this is printing fine
String barcodeContent1 = "INW-0001-0000000047"; // this is printing, but not readable by barcode scanner
byte[] format = new byte[]{
0x1D, // GS
0x6B, // k
(byte) 73, // m (2) this is CODE_128
(byte) barcodeContent1.length() // n (number of barcode data bytes)
};
byte[] data = ESCUtil.byteMerger(new byte[][]{
format,
barcodeContent1.getBytes(StandardCharsets.UTF_8) //d1...dn
});
if (out != null) {
// init printer
// ESC , #
writeOutStream(out, new byte[]{0x1B, 0x40});
// // left margin
// // GS , L , nL , nH
// writeOutStream(out,new byte[]{ 0x1D , 0x4C ,(byte) (0 % 256),(byte) (0 / 256)});
// set alignment to center
// ESC ,a , n
writeOutStream(out, new byte[]{0x1B, 0x61, (byte) 1});
// set HRI position
// GS , ! , n
writeOutStream(out, new byte[]{0x1D, 0x48, (byte) 2});
// set height
// GS , h , n
writeOutStream(out, new byte[]{0x1D, 0x68, (byte) 2});
// set width
// GS , w , n
writeOutStream(out, new byte[]{0x1D, 0x77, (byte) 16);
// set data to print
writeOutStream(out, data);
// set next line feed
// LF
writeOutStream(out, new byte[]{0x0A});
// print n dots in feed
// ESC , J , n
writeOutStream(out, new byte[]{0x1B, 0x4A, (byte) 160});
}
try {
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Output:
Can anyone please take a look and guide me?

Okay, it isn't the quiet zones or bounding box or the software. The problem is with the print head. There is too much bleed between the bars. If you printed out 100 of the '...0047' codes, maybe a fraction of them would scan.
Your print head (thermal, I think?) isn't cooling down enough between the bars to leave white spaces. This may be because the paper is too sensitive to heat, it may be because the print head is not designed for such tight spacing, or it may be a bad print head.
Here are some things you might want to try:
Another printer, if one is available, this might help you isolate a bad printer.
Scaling up the barcode width about 50%, increasing the space between bars. Try "writeOutStream(out, new byte[]{0x1D, 0x77, (byte) 24);"
Use Code 128C for the large numeric portion on the right. I'm not sure how to switch to Code 128C from Code 128B using that setup, but it could shorten the entire barcode symbol by 4 characters.

Related

Generate QRCode and Print in Printer Thermal using ESC POS - ZIJIANG 58mm - Delphi 10.2

I'm trying to print qr code, on a thermal pos bluetooth printer in delphi, android platform (firemonkey).
the printer is connected, I can print the text, but I can't generate and print the qr code, I would be grateful if someone can help.
The mark of the pos printer is P08-580LD (ZIJIANG).
this is the code i use in delphi-android 10.2 .
sock.connect;
// Reset Printer
ostream.write(StringToJA(escResetPrinter,'iso8859-2'));
ostream.write(StringToJA(pO8escBoldOn,'iso8859-2'));
ostream.write(StringToJA('Naziv 1'+escNewLine , 'iso8859-2'));
ostream.write(StringToJA(pO8escBoldOff,'iso8859-2'));
ostream.write(StringToJA(pO8escFontA,'iso8859-2'));
ostream.write(StringToJA('Adresa'+escNewLine , 'iso8859-2'));
ostream.write(StringToJA(escResetPrinter,'iso8859-2'));
ostream.write(StringToJA(pO8escFontB,'iso8859-2'));
ostream.write(StringToJA('MB xxxxx, ID HR-AB-99-0125--54'+escNewLine , 'iso8859-2'));
ostream.write(StringToJA(escResetPrinter,'iso8859-2'));
ostream.write(StringToJA(pO8escUnerlineOn,'iso8859-2'));
ostream.write(StringToJA('IBAN: xxxxxxxxx'+escNewLine , 'iso8859-2'));
ostream.write(StringToJA(pO8escUnerlineOff,'iso8859-2'));
ostream.write(StringToJA('OIB 99999999'+escNewLine , 'iso8859-2'));
// start - qr-code //
ostream.write(StringToJA(chr(27)+chr(90)+chr(0)+chr(7)+chr(15)+chr(25)+chr(30)+'dada' ,'iso8859-2'));
ostream.write(StringToJA(escResetPrinter,'iso8859-2'));
Sleep(250);
ostream.flush();
ostream.close;
This is documentation from the printer, and it says how to build the code, (decimal).
https://mega.nz/file/fu4zTCSR#UZ53LSty7dUpRyqzvz8li27amG1KvVlLk0slQFhd5Os
I managed to generate the qr code as below in the picture but it is not ok.
This is how the qr code should be generated according to the printer documentation
I found a function in android studio, how to build qr code, I would be grateful if someone knows how to turn a function into delphi.
.....
byte[] qrcode = PrinterCommand.getBarCommand("Zijiang Electronic Thermal Receipt Printer!", 0, 3, 6);//
Command.ESC_Align[2] = 0x01;
SendDataByte(Command.ESC_Align);
SendDataByte(qrcode);
public static byte[] getBarCommand(String str, int nVersion, int nErrorCorrectionLevel, int nMagnification)
{
if(nVersion<0 | nVersion >19 | nErrorCorrectionLevel<0 | nErrorCorrectionLevel > 3
| nMagnification < 1 | nMagnification > 8){
return null;
}
byte[] bCodeData = null;
try
{
bCodeData = str.getBytes("GBK");
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
return null;
}
byte[] command = new byte[bCodeData.length + 7];
command[0] = 27;
command[1] = 90;
command[2] = ((byte)nVersion);
command[3] = ((byte)nErrorCorrectionLevel);
command[4] = ((byte)nMagnification);
command[5] = (byte)(bCodeData.length & 0xff);
command[6] = (byte)((bCodeData.length & 0xff00) >> 8);
System.arraycopy(bCodeData, 0, command, 7, bCodeData.length);
return command;
}
Having quite similar issues on that kind of mini POS printers. When directly printing from Kotlin (Android Studio, native), I managed, somehow, to interpret partially their official manual and concluded that ESC Z works little different (actually it coresponds to the Java code you found)...
ESC Z (27 90)
first byte relates to table row ("version"), if 0 then it will "autoselect"
at first, I thougth second byte must be 'M' (77) - 'L', 'Q', 'H' - didn't manage it to work?! (actually it has to be 0,1,2,3 based on error correction - as suggested in Java code you found and posted here)
this byte relates to QR code size, 1-8
lower byte of string size (for example, for your "dada" it would be 4)
higher byte of string size (for your "dada" it would be 0... if longer than 256 characters, this shall be length div 256)
string characters
In your Delphi code, I would change (step-by-step, you can binary mask the length...):
// start - qr-code //
ps := 'dada'; // your content string... detalji o računu ili štogod...
l1 := length(ps);
y := l1 div 256;
x := l1 - y * 256;
ostream.write(StringToJA(chr(27)+chr(90)+chr(7)+chr(1)+chr(6)+chr(x)+chr(y)+ps ,'iso8859-2'));
// please not that 7-1-6 is fixed combination - 7 relates to the table from documentation, 1 relates to error correction (use 0 for "smaller" QR with less redundany, or 2 and 3 for larger more complex QR), 6 relates to size of printed code (can be set lower)

Print barcode using thermal printer Android

I was able to print text but when it comes to barcode it not showing or just showing irregular text.
Here is my source code
//barcode 128
byte[] formats = {(byte) 0x1d, (byte) 0x6b, (byte) 0x73,(byte) 0x0d};
byte[] contents = content.getBytes();
byte[] bytes = new byte[formats.length + contents.length];
System.arraycopy(formats, 0, bytes, 0, formats.length );
System.arraycopy(contents, 0, bytes, formats.length, contents.length);
usbCtrl.sendByte(bytes, dev);
usbCtrl.sendByte(LineFeed(), dev);
but the result barcode is not showing, am i missing something
Please help me
EDIT
I found the ESC/POS code :
GS k m d1...dk NUL or GS k m n d1...d k
But when I try this, still got same result
The GS k POS code has two versions (as you already discovered):
GS k - print one dimensional barcode
m - barcode mode selector
[d]k - data bytes
NUL - terminator
This version works only for pure ASCII data since it uses a 0x00 (NUL) as terminator.
GS k - print one dimensional barcode
m - barcode mode selector
n - content length in bytes
[d]k - data bytes
This version uses an additional length byte n to indicate the data part (it's also only suitable for certain codings including CODE128).
Your code has a stray 0x0d in the command bytes and may also be using the wrong format.
If you plan to print pure ASCII data format the command like this:
byte[] formats = {(byte) 0x1d, (byte) 0x6b, (byte) 0x49};
byte[] contents = content.getBytes();
byte[] bytes = new byte[formats.length + contents.length + 1];
System.arraycopy(formats, 0, bytes, 0, formats.length );
System.arraycopy(contents, 0, bytes, formats.length, contents.length);
// add a terminating NULL
bytes[formats.length + contents.length] = (byte) 0x00;
Or the more secure version since it also has the expected data length:
byte[] contents = content.getBytes();
// include the content length after the mode selector (0x49)
byte[] formats = {(byte) 0x1d, (byte) 0x6b, (byte) 0x49, (byte)content.length};
byte[] bytes = new byte[formats.length + contents.length];
System.arraycopy(formats, 0, bytes, 0, formats.length );
System.arraycopy(contents, 0, bytes, formats.length, contents.length);
If neither of the two work then your printer may simply not support CODE128.
The 5890 is a common enough specification and there are lots of cheap "drop-in" replacements on the market which leave out the more complex barcode implementations and only include simple codings like EAN8, EAN13 etc.

Android NFC read from tag type: IsoDep and NfcB

I am very new to Android development and NFC in general.
I am trying to build an application to read the content of an NFC card where I don't know anything about this card (bus card), I want to see for example how many tickets I have left.
I have scanned the card with variety of NFC applications and know that this card is of type: IsoDep AND NfcB.
Right now I am trying to read its content using IsoDep with no success (errors 6A82, 91AE, 6E00 and so on).
I have an app that waiting for new intent of type ACTION_NDEF_DISCOVERED || ACTION_TECH_DISCOVERED || ACTION_TAG_DISCOVERED opens a new thread (since it is not possible to read and connect on UI's thread) and I am trying to read the content of the card.
I guess my problem is with the bytes I am passing to isoDep.transceive(NATIVE_SELECT_APP_COMMAND).
Should I keep trying on the IsoDep or should I move to try on the NfcB?
Do you guys have any tips?
here is my code sample:
final byte[] SELECT = {
(byte) 0x00, // CLA Class
(byte) 0xA4, // INS Instruction
(byte) 0x04, // P1 Parameter 1
(byte) 0x00, // P2 Parameter 2
(byte) 0x08, // Length
(byte) 0x31, (byte)0x54, (byte)0x49, (byte)0x43, (byte)0x2e,
(byte) 0x49, (byte)0x43, (byte)0x41, // AID 315449432e494341
};
Tag tagFromIntent = m_intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
IsoDep isoDep = IsoDep.get(tagFromIntent);
try {
isoDep.connect();
byte[] result = isoDep.transceive(SELECT);
String str = bytesToHex(result);
Log.i("test", "SELECT: " + str);
isoDep.close();
} catch (Exception e) {
String error = e.getMessage();
}
my bytes to hex function:
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
=============================================================
Edit:
I have just learned that this card is using Calypso authentication scheme.
In this question's answer helped me a little: Read data from NFC tag (IsoDep)
I found a good SELECT function, i have edited my question to hold the new "SELECT" command which is working- In return i get this string: "6F228408315449432E494341A516BF0C13C70800000000029780A55307060A07062004019000" which i have no idea what it means.
Then I use this command to try and read a string:
byte[] GET_STRING = {
(byte) 0x80, // CLA Class
0x04, // INS Instruction
0x00, // P1 Parameter 1
0x00, // P2 Parameter 2
0x10 // LE maximal number of bytes expected in result
};
But i get error: 6E00, any ideas on how to proceed?
You could communicate with card with IsoDep.
You want to access data on card without specifications of this card, so there's 2 ways:
Get specification of card (how to communicate with it)
Do reverse engineering, it will take lot of time and not sure about the result, and you could "lock" access to the card
UPDATE 1
To read Rav Kav card, threre's an open-source project : http://pannetrat.com/Cardpeek/ code for Rav Kav is here https://code.google.com/p/cardpeek/source/browse/trunk/dot_cardpeek_dir/scripts/calypso/c376n3.lua
You are sending the wrong command to read the application's records. 6E00 means incorrect INS byte.
You can have a look at this github which reads some counters out of a MOBIB card, which is based on the Calypso spec.
https://github.com/flamingokweker/Android-NFC-Mobib-Reader

IsoDep APDU SELECT returns 6FXX

I am trying to implement IsoDep reading capabilities to chariotsolutions phongap-nfc plugin, so far (even though i am a complete newbie to Java/android and cordova/phonegap) I have managed to make it work with cordova, connect to the card, issue an APDU command and return it back to the web view. (hooray for me right?)
Well the simple problem is that I did not manage to get a 9000 response so far by selecting the application.
I am using LG L Fino#4.4.2.
Additions to NFCplugin.java + import nfc.tech.IsoDep, NFCa, NFCb
.... else if (action.equalsIgnoreCase(ISODEP)) {
registerIsoDep(callbackContext);
} else if (action.equalsIgnoreCase(READISODEP)){
readIsoDep(callbackContext);
} else .....
This should be the tag listener - i think so :-)
private void registerIsoDep(CallbackContext callbackContext) throws JSONException {
addTechList(new String[]{IsoDep.class.getName()});
callbackContext.success();
}
This reads the IsoDep tag, found out that it has to be called within the callback of the previous function (will get back in to that in the Js part)
private void readIsoDep(final CallbackContext callbackContext) throws JSONException {
final Tag tag = savedIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
IsoDep isoDep = IsoDep.get(tag);
try {
isoDep.connect();
isoDep.setTimeout(5000);
byte[] SELECT = {
(byte) 0x00, // CLA Class
(byte) 0xA4, // INS Instruction
(byte) 0x04, // P1 Parameter 1
(byte) 0x00, // P2 Parameter 2
(byte) 0x07, // Length
(byte) 0xA0, (byte) 0x00,
(byte) 0x00, (byte) 0x00,
(byte) 0x04, (byte) 0x10,
(byte) 0x10, // AID
(byte) 0x00 // Lenght
};
try {
byte[] result = isoDep.transceive(SELECT);
isoDep.close();
callbackContext.success(result[0] + "|" + result[1]);
}catch (IOException e) {
callbackContext.error("error" + e);
}
} catch (IOException e) {
callbackContext.error("error" + e);
}
}
});
}
Cordova implementation
,addIDDiscoverListener: function(callback, win, fail) {
document.addEventListener("tag", callback, false);
cordova.exec(win, fail, "NfcPlugin", "registerIsoDep", []);
}
};
var isoDep = {
readIsoDep: function(win, fail) {
cordova.exec(win, fail, "NfcPlugin", "readIsoDep", []);
}
}
And lastly "app.js"
nfc.addIDDiscoverListener(function(nfcEvent) {
//listenes for the isodep tag
isoDep.readIsoDep(function(tag) {
console.log(tag); //returns ADPU response codes
}, function(reason) {
console.log('error! ' + reason);
});
},
function() {
console.log('registered reader');
},
function(reason) {
console.log('error! ' + reason);
});
My problem is that no matter what app id I select whether it is MasterCard (A0000000041010) with the above one or PPES (proximity payment system environment), I get this error. Since this is my first attempt to do Java I do not know if it is an implementation issue or command issue (which should be fine) most of this code was written by looking at the chariot solutions code and literally thinking yea this should work, this is here so it should be probably be also here ("cordova execute runnable" - i know sh*t what it does, just assumed it should probably be in my code also).
Also there is probably another small bug - it reads the card only ONCE until I quit the app and start it again.
PS.: I have read a ton of SO post, googled like hell for couple of days and tried a lot of things (learned a couple also) but none of them were able to help me.
PSS.: And yes when it is done I want to merge it the the original project.
Thank for any help and sorry for the long post.
The 6F XX that you are seeing is not the status word. In fact 6F ... is exactly what you should receive when your SELECT (by DF name) command succeeds. 6F is the tag of an FCI template.
When you try to retrieve the status word, you are actually reading the first two bytes of the array that you get from the transceive() method. However, a response APDU looks like
+---------+--------+--------+
| DATA | SW1 | SW2 |
| n bytes | 1 byte | 1 byte |
+---------+--------+--------+
So you would need to check the last two bytes of result for the status word:
result[result.length - 2] + "|" + result[result.length - 1]

Transceive Failed on ISO15693 / Tag-it HF-I

I have some ISO15693 / Tag-it HF-I Plus chips and need to write something on them. These chips are completly fresh, and i read now a ton of pdf's telling me all the same. But nothing work, and i get all the time the Transceive Failed error.
I send these Data in the transceive command:
Byte: <data>
0: 0x00 // pdf says the tag understands only flag = 0x00
1: 0x21 // write single block
2-10: ID // needs to be send for this tag, only supports addressed mode
11: 0x00 // Block ID, try to write to block 0
12-16: DATA // LSB First
17-18: CRC16 // do i need to send this? and if yes, LSB first?
I tried very different flags and write modes but none of them work:
Flags: 0x01, 0x02, 0x20,0x22,0x42,0x40,0x80,0x82
Modes: 0x21,0xA2 (+ Vendor Mode 0x07)
this is my write function:
private void write(Tag tag) throws IOException, FormatException {
if (tag == null) {
return;
}
NfcV nfc = NfcV.get(tag);
byte[] ID = tag.getId();
nfc.connect();
Log.d(TAG, "Data: " + new String(((EmergencyApplication) getApplication()).getData()));
byte[] data = ((EmergencyApplication) getApplication()).getData();
// NfcV Tag has 64 Blocks with 4 Byte
if ((data.length / 4) > 64) {
// ERROR HERE!
Log.d(TAG, "too much data...");
}
for (int i = 0; i < data.length; i++) {
byte[] arrByte = new byte[17];
// Flags
arrByte[0] = 0x00; // Tag only supports flags = 0
// Command
arrByte[1] = 0x21;
// ID
Log.d(TAG, "Found ID length: " + ID.length + "... ID: " + Arrays.toString(ID));
System.arraycopy(ID, 0, arrByte, 2, 8);
// block number
arrByte[10] = (byte) (i);
// data
// TODO send LSB first...
System.arraycopy(data, i * 4, arrByte, 11, 4);
// CRC 16 of all command
byte[] check = new byte[15];
System.arraycopy(arrByte, 0, check, 0, 15);
int crc = CRC.crc16(check);
arrByte[15] = (byte) (crc >> 8);
arrByte[16] = (byte) (crc & 0xFF);
Log.d(TAG, "Writing Data: " + Arrays.toString(arrByte));
byte[] result = nfc.transceive(arrByte);
Log.d(TAG, "got result: " + Arrays.toString(result));
}
nfc.close();
Toast.makeText(this, "wrote to tag", Toast.LENGTH_LONG).show();
}
Is it another bug with the Nexus S? I use Cyanogenmod 10.1.2, so i think the Tag Lost Bug is fixed here... I can obviously read the tag and if i use the NFC Tag Info App, it shows me all block clear and writeable.
I have these PDFs read:
http://rfidshop.com.hk/datasheet%20tag/philip%20icode%20SLI.pdf - Datasheet of my Tag
http://www.waazaa.org/download/fcd-15693-3.pdf - ISO15693-3 datasheet
http://www.ti.com/lit/ug/scbu003a/scbu003a.pdf - Tag-it HF-I Plus datasheet
I tested Reading with the code from here: Reading a NXP ICODE SLI-L tag with Android - it works on all 64 blocks but writing still doesnt work... even with flag = 0x20...
Edit: I saw now that the DSFID on the Card is 0x00, which means for ISO15693-3 that the card is not writeable at all:
If its programming is not supported by the VICC, the VICC shall
respond with the value zero ('00')
This is the byte[] when sending 0x2B:
DSFID \ / AFI
| |
v v
infoRmation: [0, 15, 120, 40, -51, -51, 119, -128, 7, -32, 0, 0, 63, 3, -117]
Found some things out, i want to share:
Don't Send the Data with LSB first, it seems that the transceive command does this automatically on sending
Don't use addressed mode, it seems that the android implementation has some problems with that
Set the Option bit (0x40) in the Flags.
Fast Mode (0x02) seems to be supported by my tags, so you can set it or not
Don't set the CRC16, because it's added by android
But the worst thing at all is, that the Tags does not respond in the time that is compiled into the tag writer. You will get a Tag is lost. Exception but the Data will be written to the Tag! So the solution is to just ignore this exception and maybe validate the data after writing and try again if it doesnt work.
My current write code looks like this:
public static void write(Tag tag, byte[] data) throws IOException, FormatException,
InterruptedException {
if (tag == null) {
return;
}
NfcV nfc = NfcV.get(tag);
nfc.connect();
Log.d(TAG, "Max Transceive Bytes: " + nfc.getMaxTransceiveLength());
// NfcV Tag has 64 Blocks with 4 Byte
if ((data.length / 4) > 64) {
// ERROR HERE!
Log.d(TAG, "too much data...");
}
if ((data.length % 4) != 0) {
byte[] ndata = new byte[(data.length) + (4 - (data.length % 4))];
Arrays.fill(ndata, (byte) 0x00);
System.arraycopy(data, 0, ndata, 0, data.length);
data = ndata;
}
byte[] arrByte = new byte[7];
// Flags
arrByte[0] = 0x42;
// Command
arrByte[1] = 0x21;
for (int i = 0; i < (data.length / 4); i++) {
// block number
arrByte[2] = (byte) (i);
// data, DONT SEND LSB FIRST!
arrByte[3] = data[(i * 4)];
arrByte[4] = data[(i * 4) + 1];
arrByte[5] = data[(i * 4) + 2];
arrByte[6] = data[(i * 4) + 3];
Log.d(TAG, "Writing Data to block " + i + " [" + printHexString(arrByte) + "]");
try {
nfc.transceive(arrByte);
} catch (IOException e) {
if (e.getMessage().equals("Tag was lost.")) {
// continue, because of Tag bug
} else {
throw e;
}
}
}
nfc.close();
}
and it works pretty well.
If there is a real error, like the message is not understood, you will get the Transceive Failed message.

Categories

Resources