I'm trying to print a ticket, and need to print out m³ as unit of measurement using a serial printer. And the following is what I have tried so far:
if (!printer.IsOpen)
printer.Open();
printer.WriteLine(string.Format("{0} m{1}", "2.34", Convert.ToChar(0xB3)));
printer.Close();
When I tried to debug and view the value using the text visualizer the text is correct which is "2.34 m³". But when it comes to printing, the text changed to "2.34 m?", where the expected output should be "2.34 m³".
I've been trying to figure this out for days. Please help. Thanks.
It seems as if your printer does not support the '³' character natively.
Therefore you need the printer manufacturer's technical manual. There, you must identify a control character sequence for superscript mode and put it in from of a (normal) character '3'. After it, you must switch off superscript mode again.This control codes are printer specific, and you need, therefore you must have this information from the printer manufacturer.
Assuming "Superscript on" is ESC 0x4e and "Superscript off" is ESC 0x4f, then your cde would look like this:
printer.WriteLine(string.Format("{0} m{1}3{2}", "2.34", "\x1b\x4e", "\x1b\x4f" );
What font are you using? I think the font you're using doesn't support that character, which is why it put a ?. During debug it shows the right character because visual studio is using a font that does support that character. Try choosing a different font and see if that helps.
I don't know C# well enough to comment on the code in your question, but it's absolutely possible to print the ³ character in ESC/POS by sending "\x1B\x74\x02\xFC".
Here is a picture of a receipt from an Epson TM-T20:
I printed this by using a PHP library which understands how to convert UTF-8 into the available code pages of ESC/POS printers. A similar library exists for python, and you would be well advised to use a C# equivalent if it exists!
<?php
require __DIR__ . '/vendor/autoload.php';
use Mike42\Escpos\Printer;
use Mike42\Escpos\PrintConnectors\FilePrintConnector;
use Mike42\Escpos\CapabilityProfile;
$connector = new FilePrintConnector("php://stdout");
$profile = CapabilityProfile::load("default");
$printer = new Printer($connector, $profile);
$printer -> text("2.43 m³\n");
$printer -> cut();
$printer -> close();
This corresponds to the following hexdump.
$ php superscript-demo.php | hexdump -C
00000000 1b 40 32 2e 34 33 20 6d 1b 74 02 fc 0a 1d 56 41 |.#2.43 m.t....VA|
00000010 03 |.|
00000011
All of the commands here are:
ESC # - set formatting and character encoding settings back to their defaults.
ESC t 2 - select code page 2.
LF - line break
ESC V 65 3 - a cut command
The magic here is ESC t 2. The code page numbered 2 on Epson printers is legacy code page 850 on Epson printers. Other vendors may be different, but the manual for your printer also shows CP850 at the same position.
Your default code page (CP437) does not contain the character you want, while in code page 850, ³ is represented by 0xFC. Once you change code pages, the change is active until you either reset the printer, or issue ESC #.
To save time finding special characters individually, you can select a code page which contains everything you plan to use, and then lean on your programming language standard library to encode strings with that code page.
Related
I have a program for parsing GS1 Barcodes (with Zebra scanner), which worked just fine, atleast I thought it was OK...
Until I came across one box with 2 GS1 barcodes.. one "linear" and one data matrix (UDI). For linear, it worked just fine, I successfully got out the GTIN and Serial. But datamatrix is different. For some reason, its content is a bit longer than linear code, it has some production date and something else at the end.
This is the Linear code: (01)00380652555852(17)260221(21)25146965079(30)1
This is data matrix: (01)00380652555852(17)260221(21)2514696507911210222240SA60AT225
I have problems with parsing out the Serial number - 25146965079.
Serial number in GS1 has a length of 1-20 characters. This one has 11, but How can I make it stop after the 9 characters? How can I know that the serial ends there?
I tried transforming each character to UDI, but it seems that there is no special separating character or anything.. so I honestly donjt know what to do. Does anyone have any idea?
This the code, if anyone wanna try anything https://prnt.sc/1x2sw8l
Those codes/products came right from the manufacturer, so there shouldnt be anything wrong with the code, I guess...
If you verify the barcode with a scanner that is designed to interpret a GS1 structure, you will see that the generated barcode is in fact incorrect.
You are missing a GS after the serial number, these codes MUST end a variable-length field if it's not the last one. This is specified in GS1 general specifications section 7.8.5.2
Without this separator you can't know where the serial ends - or, a machine interpreting the code can't know.
Tell the manufacturer that they need to study the GS1 specs.
Edit: the "correct" version would be:
(01)00380652555852(17)260221(21)25146965079<GS>(11)210222(240)SA60AT225
The parentheses and group separator <GS> are not included literally in the code.
Since you have two variable-length identifiers (21) and (240) you need a GS no matter what you do. Only alternative would be to have some padding for serial number, then you could do without separator.
According to the GS1 documentation (page 156 and forwards)
All the fields are correct
(01)00380652555852 --> GTIN
(17)260221 --> Expiration date
(21)25146965079 --> Serial Number
(11)210222 --> Production Date
(240)SA60AT225 --> Additional Product Identification
I tried scanning the image but the result was the same as yours.
So the problem is that the separators are not there. Which is a problem for you, and there is no way to know where the serial number ends without the separator.
I am sorry my English is not good
The reason of this problem is group separetors are unreadable character for example if you focus on text box and press capslock button or shift button nothing appear in text box the same in gs
To solve this problem
Public l as integer
And put the following code in keyup event
If textbox1.textlenght = l then
My.combuter.keybord.sendkeys({enter})
L= textbox1.textlenght
End if
This code will give space after each litter (because each litter combined with cabslock button) and five spaces in groub space
store raw input in KeyPress event and then read the character for Letter Or Digit.
if (e.KeyChar != 13)
{
int asci = Convert.ToInt32(e.KeyChar);
if (asci > 31 && asci < 128) // numeric and chars only
rawbcode += Convert.ToChar((int)(e.KeyChar & 0xffff));
else
{
if (asci == 29)
{
rawbcode += "<GS>"; // GS1 Seperator
}
}
}
I am working on a POS application that supports EMV cards. I am able to read card data from a Verifone MX card reader in TLV, but I am facing issues in decoding the TLV data to readable data.
I am able to Split the data into TLV Tags and its values. The resultant value is in Hex instead of Decoded text.
Example:
This is a sample TLV data (I got this sample TLV Data here
6F2F840E325041592E5359532E4444463031A51DBF0C1A61184F07A0000000031010500A564953412044454249548701019000
When i check this TLV in TLVUtil, I get data in certain Tags in readable format (like Tag 50 here).
The Closest I could get in my application is this:
Tag Value
50 56495341204445424954
4F A0000000031010
61 4F07A0000000031010500A56495341204445424954870101
6F 840E325041592E5359532E4444463031A51DBF0C1A61184F07A0000000031010500A56495341204445424954870101
84 325041592E5359532E4444463031
87 1
90
A5 BF0C1A61184F07A0000000031010500A56495341204445424954870101
BF0C 61184F07A0000000031010500A56495341204445424954870101
I would like to know if there is any way to identify certain tags that need to be converted from Hex to string or if there is any TLV Parser and decoder available in .Net that can replicate the TLVUtil tool.
Complete list of EMV tags and are available in EMVCo 4.3 specification book 3 -
you can download from here - https://www.emvco.com/download_agreement.aspx?id=654
How data is represented differs from field to field. Check 'Annex A - Data Elements Dictionary'
Details on encoding is mentioned in section 4.3
Read both the sections and your problem solved.
There are only a few tags that need to be converted to string. Generally tags that are put on POS screen personalized in hex equivalent of readable string.
5F20 : Cardholder Name
50 : Application Label.
5F2D : Language Preference
You must know which tags can be converted.
As it seems to me, programmatically you can identify something like,
Tag is of one byte ( 5A - Pan number ) or it contain 2 byte ( 5F20 - CARD HOLDER NAME), AND
length is of 1 byte or 2 byte AND
Tag is primitiv or constructed. More you can read Here
and if you know the list you can get something useful Here, It define the format of tag that you are looking for.
Here you can hard coded the format as it is well defined.
Hope it helps.
That data beginni g with 6F is a File Control Information (FCI) responded by an EMV card after SELECT command. There is an example in this video also decoded and explained.
https://youtu.be/iWg8EBhsfjY
Its easy check it out
I need help decoding this received response.
at
OK
+CUSD: 0,"ar#?$ #9#d? ?# ???(d??)##1pD?"?T?Hc#
?& ?#D??? ?#??5 41 IA ?R",17
OK
+CUSD: 0,"ar?hb? ?' 10?# ? ?hb#?J##?#?? #f#??#?#S#d$#",17
I tried when dcs value was 72 on another network provider.
but this one value 17 I don't understand.
how to decode it?
after results :
AT+CSCS="UCS2"
OK
at+cusd=1,"002a003100350030002a0032002a00330032003300390031002a00360039003100370037002a00310023",15
+CUSD: 0,"00610072003f00680062003f0020003f00270020002000310030003f00400020003f0020003f006800620040003f004a00400040003f0040003f003f0020004000660040003f003f0040003f004000530040006400240040",17
AT+CSMP?
+CSMP: 17,167,0,0
OK
by the way when i set my AT+CSCS="UTF-8" it report Error but
it is reported back with this command AT+CSCS=?
The format of the response is according to 27.007:
+CUSD=[<n>[,<str>[,<dcs>]]]
Thus the third parameter is <dcs>. Its format is just deferred:
<dcs>: 3GPP TS 23.038 [25] Cell Broadcast Data Coding Scheme in integer format
(default 0)
In chapter "5 CBS Data Coding Scheme" in 23.038 it states These codings may also be used for USSD.
For 17, binary 0001 0001:
bit 7..4 Coding Group Bits = 0001
bit 3..0 = 0001 --> UCS2; message preceded by language indication
And it notes that
An MS not supporting UCS2 coding will present the two character language identifier followed by improperly interpreted user data.
which is exactly the case in your output (e.g. ar meaning arabic followed by garbage).
For 72, binary 0100 1000:
bit 7..4 Coding Group Bits = 01xx
bit 5 = 0 --> uncompressed,
bit 4 = 0 --> no class meaning
bit 3 & 2 = 1 & 0 --> UCS2 (16bit)
The "not supporting" part above might just be that you are using a limited character set encoding (PCCP437). In any case, unless your modem does not support UTF-8 you really should use that and not this PCCP437. Or you might use USC2. If your modem lacks both of those characters, you can try HEX (guessing on my part from what I saw when researching this answer, maybe you need to set the <dcs> parameter in AT+CSMP for this to work?).
Notice that after selecting UCS2 every string must be encoded that way, including switching to another character set, see this answer for an example.
Use the following functions to decode "UCS2" response data:
public static String HexStr2UnicodeStr(String strHex)
{
byte[] ba = Hex2ByteArray(strHex);
return HexBytes2UnicodeStr(ba);
}
public static String HexBytes2UnicodeStr(byte[] ba)
{
var strMessage = Encoding.BigEndianUnicode.GetString(ba, 0, ba.Length);
return strMessage;
}
for example:
String str1 = SmsEngine.HexStr2UnicodeStr("002a003100350030002a0032002a00330032003300390031002a00360039003100370037002a00310023");
// str1 = "*150*2*32391*69177*1#"
Please also check UnicodeStr2HexStr()
the format could be :
namestamp count marks name percentage
ddmmyyyyhhmmss 1 75 abc 75
I would personally use a library like NPOI, however, I'm not sure on the compatibility with Windows Phone... it should work though.
A bit of background information:
Inorder to read/write to SLE4442 memory cards, my app is currently using an Omnikey Cardman 3021 USB card reader, a Sumbsembly Smartcard API (external dll) which is capable of wrapping CT-API calls (directed to omnikey's dll) so that I can read/write the memory card in my c# app.
The only problem here is that Omnikey only provides a 32-bit dll of their CT-API. I asked if they are going to produce a 64-bit version, but they couldn't be bothered.
Current situation:
Inorder to make my application 64-bit capable, I must rewrite it using Windows WinSCard API. The problem here is that there are no specific examples on the web how to do it. Also getting hold of working APDU commands is nearly impossible, but I've managed to aquire two slightly different versions that sort of work.
I have googled this a hundred times over many months and with what I have managed to gobble together I can finally read the SLE4442 memory card. But for the life of me I can't get writing to work.
The code:
I'm not going to post the entire code into this first post (if need be I can do it later or provide a link to the source code).
But I'll outline the basic steps.
1) SCardEstablishContext
2) Get the reader name via SCardListReaders
3) SCardConnect
4) Read entire memory with SCardTransmit and APDU new byte[] { 0xFF, 0xB0, 0, 0, 0 };
5) Verify pin with SCardTransmit and APDU new byte[] { 0xFF, 0x20, 0, 0, 3, 0xFF, 0xFF, 0xFF }; (Note that this does return 0x90;0x00 as a response, which means the verification should have been succesful)
6) Try to write with ScardTransmit and APDU new byte[] { 0xFF, 0xD6, 0, 0, 50, 1 }; (try to write value 1 at memory position 50) - I have also tried using an APDU with the first parameter being 0x00 and/or the second byte being 0xD0. The response has never been 0x90;0x00 so I assume there is an error during writing, but I haven't been able to find any meaning to the error codes returned.
Possible causes:
Because I can read a memory card with the WinSCard API then it must be possible to also write to one (side note - the memory card(s) that I try to write to are in in working condition, I haven't locked them down by failing to verify the PIN 3 times).
1) Maybe the write APDU command is wrong. Could be that the instruction byte (second byte) is incorrect, or the memory location uses some sort of an extended coding scheme.
2) Maybe the verify command didn't actually verify. As in the command itself is fine, which is why 0x90 was returned, but I must call or setup something first.
3) Just a hunch, but I think that this is the real culprit. While googling I did find some vague references to having to call the SCardControl method with parameter IOCTL_SMARTCARD_SET_CARD_TYPE and setting the card type to SLE4442. But again no working examples anywhere and my trial-and-error testing resulted in failures. I got "One or more of the supplied parameters could not be properly interpreted." and some other error messages as well, can't remember what they all were. Assuming the code I copy-pasted from google code has the right descriptions for the error codes.
What I need:
What I need is someone to post or direct me to a site that has full+working code in c# for read/write SLE4442 using WinSCard API and it must work in both 32-bit and 64-bit enviroments.
The code doesn't have to be foolproof - eg. handling every possible error situation nicely. I should be able to do that myself. But if it is (including the APDU command result descriptions - eg. 0x90;0x00 is success, but 0x6B;0x4D is... etc...) then all the better.
APDU for writing to card, in your example, should be:
FF D6 00 50 01 01
Our Omnikey (3121) terminal writes data on SLE4442/SLE4442 cards perfectly, try this APDU:
FF D6 00 04 10 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E AA
see also:
http://acs.com.hk/drivers/eng/API_ACR122U.pdf, chapter 5.4
FF,D2,00,01,03,01,02,03 (new pin = 1,2,3) does not work (also after verifying existing PIN:
6D,00,FF,20,00,00 03,FF,FF,FF) - It returns error code 6D00.
For us (yet) not a huge problem, as we code our cards now with the Xiring XiMax terminal (programmable terminal with it's own SDK, the terminal can store data in flash memory).
However, we need to find a solution soon. I am interested in your (future) findings.
Do you have the Omnikey SDK? We can send you working examples in C++ that can change PSC (pin) and data on SLE4442/5542 cards.
This week (so not tomorrow, as previously stated, we have many things going on and are constantly ) we will test the (so far) working code with the Omnikey 1021). Hope to help you out.
We always have 50+ Omnikey 3121 readers on stock and we can offer you these (1+) for a far batter price. Let me know if you are interested.
I am also interested what where you are located and what applications you are developing.