I Have a full tests program written in Delphi 5 for the TMT88's but the source is abit big for here so here is the barcode bits
Please note that as its snippets from the full object some vars/functions may be missing
To get the barcode chars
{**
* @param a ean13 barcode numeric value
* @return the escpos code for the barcode print
* Description uses escpos code, return code needed to print a ean13 barcode
*}
function TPrintEscPosToPort.getBarcodeEscPosCode(l_ean13:String):String;
var
l_return:String;
begin
l_return := CHR(29) + 'k' + CHR(67) + CHR(12);
l_return := l_return + l_ean13; // Print bar code
l_return := l_return + l_ean13; // Print bar code number under thge barcode
Result := l_return
end;
to print to a printer
{**
* @param Printer Name, Item be printed, Cut the papers after the cut, #no of copies to print
* @return boolen, true if it printed
* Description prints a test page to the tysso printer
*}
function TPrintEscPosToPort.escPosPrint(const l_printer, l_textToPrint :String;l_cutPaper:Boolean=true;l_copies:integer=1): Boolean;
var
l_pPort,l_pName,l_tmp:String;
i,x:integer;
PrinterFile: TextFile;
begin
// set result to false so any thing other then a good print will be false
Result:= FALSE;
try
//Find if the printer exists, else set to defult -1
i := Printer.Printers.IndexOf(l_printer);
if (i > -1) then
begin
Printer.PrinterIndex := i;
l_pName := Printer.Printers[i]; //Get the printer name (incase its the defult and not the one passed)
l_pPort := Self.getPrinterPort(l_pName) ; // get the port name from the reg
end;
// If true add headers and footers to the passed text
if (Self.aPrintHeadersFooters) then
begin
l_tmp := Self.getHeader()
+ l_textToPrint + Self.GetFooter();
end
else
begin
l_tmp := l_textToPrint;
end;
//Send the Document To the printer
try
for x:= 1 to l_copies do //Print multi-copies
Begin
//Assign the file to a tmp file in the printer port
if (length(trim(l_pPort)) > 0) then AssignFile(PrinterFile,l_pPort)
else
begin
//only use if we cant get the port
//(may look bad as ctrl codes are still in place)
AssignPrn(PrinterFile);
l_tmp := Self.stripEscPos(l_tmp);
end;
Rewrite(PrinterFile);
try
//Send the passed Text to the printer
WriteLn(PrinterFile,l_tmp);
if (Self.aPrinterReset) then
WriteLn(PrinterFile,escReset); // Reset the printer alignment
if (l_cutPaper) then
WriteLn(PrinterFile,escFeedAndCut); //Cut the paper if needed
finally
CloseFile(PrinterFile);
Result:= true;
end;
end;
except
end;
except
end;
end;
Update
Here is a lost of control code constants from the code above, hopefully the names are descriptive enough.
const
escNewLine = chr(10); // New line (LF line feed)
escUnerlineOn = chr(27) + chr(45) + chr(1); // Unerline On
escUnerlineOnx2 = chr(27) + chr(45) + chr(2); // Unerline On x 2
escUnerlineOff = chr(27) + chr(45) + chr(0); // Unerline Off
escBoldOn = chr(27) + chr(69) + chr(1); // Bold On
escBoldOff = chr(27) + chr(69) + chr(0); // Bold Off
escNegativeOn = chr(29) + chr(66) + chr(1); // White On Black On'
escNegativeOff = chr(29) + chr(66) + chr(0); // White On Black Off
esc8CpiOn = chr(29) + chr(33) + chr(16); // Font Size x2 On
esc8CpiOff = chr(29) + chr(33) + chr(0); // Font Size x2 Off
esc16Cpi = chr(27) + chr(77) + chr(48); // Font A - Normal Font
esc20Cpi = chr(27) + chr(77) + chr(49); // Font B - Small Font
escReset = chr(27) + chr(64); //chr(27) + chr(77) + chr(48); // Reset Printer
escFeedAndCut = chr(29) + chr(86) + chr(65); // Partial Cut and feed
escAlignLeft = chr(27) + chr(97) + chr(48); // Align Text to the Left
escAlignCenter = chr(27) + chr(97) + chr(49); // Align Text to the Center
escAlignRight = chr(27) + chr(97) + chr(50); // Align Text to the Right
This is hard since it is not easy to find good articles. If you look for information you will notice how epson is not really happy sharing their knowleage. bot here are some articles that helped me with this:
- this article is really good if you want to print images Images
- This one is from epson Epson
** Update **
this is what makes the magic:
Public Class EscPOS
Private Shared PrintNam As String = "POS"
Public Shared Property PrinterName
Set(value)
PrintNam = value
End Set
Get
Return PrintNam
End Get
End Property
' Structure and API declarions:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Structure DOCINFOW
<MarshalAs(UnmanagedType.LPWStr)> Public pDocName As String
<MarshalAs(UnmanagedType.LPWStr)> Public pOutputFile As String
<MarshalAs(UnmanagedType.LPWStr)> Public pDataType As String
End Structure
<DllImport("winspool.Drv", EntryPoint:="OpenPrinterW", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function OpenPrinter(ByVal src As String, ByRef hPrinter As IntPtr, ByVal pd As Long) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="ClosePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="StartDocPrinterW", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function StartDocPrinter(ByVal hPrinter As IntPtr, ByVal level As Int32, ByRef pDI As DOCINFOW) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="EndDocPrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function EndDocPrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="StartPagePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function StartPagePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="EndPagePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function EndPagePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="WritePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function WritePrinter(ByVal hPrinter As IntPtr, ByVal pBytes As IntPtr, ByVal dwCount As Int32, ByRef dwWritten As Int32) As Boolean
End Function
Public Shared Function PrintImage(BM As Bitmap) As Boolean
Dim b As Byte() = ConvertImagetoBytes(BM)
Dim bSuccess As Boolean
Dim pUnmanagedBytes As IntPtr
' Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(b.Count)
' Copy the managed byte array into the unmanaged array.
Marshal.Copy(b, 0, pUnmanagedBytes, b.Count)
' Send the unmanaged bytes to the printer.
bSuccess = EscPOS.PrintBytes(b)
Return bSuccess
End Function
Public Shared Function PrintBytes(Document As Byte()) As Boolean
Dim hPrinter As IntPtr ' The printer handle.
Dim dwError As Int32 ' Last error - in case there was trouble.
Dim di As DOCINFOW ' Describes your document (name, port, data type).
Dim dwWritten As Int32 ' The number of bytes written by WritePrinter().
Dim bSuccess As Boolean ' Your success code.
' Set up the DOCINFO structure.
di = New DOCINFOW
di.pDocName = "RAW LOGO"
di.pDataType = "RAW"
hPrinter = New IntPtr(0)
bSuccess = False
If OpenPrinter(PrinterName.Normalize(), hPrinter, 0) Then
If StartDocPrinter(hPrinter, 1, di) Then
Dim managedData As Byte()
Dim unmanagedData As IntPtr
managedData = Document
unmanagedData = Marshal.AllocCoTaskMem(managedData.Length)
Marshal.Copy(managedData, 0, unmanagedData, managedData.Length)
If StartPagePrinter(hPrinter) Then
bSuccess = WritePrinter(hPrinter, unmanagedData, managedData.Length, dwWritten)
EndPagePrinter(hPrinter)
End If
Marshal.FreeCoTaskMem(unmanagedData)
EndDocPrinter(hPrinter)
End If
ClosePrinter(hPrinter)
End If
If bSuccess = False Then
dwError = Marshal.GetLastWin32Error()
End If
Return bSuccess
End Function
Public Shared Function ConvertImagetoBytes(BM As Bitmap) As Byte()
Dim Data As BitMapData = GetBitmapData(BM)
Dim Op As New MemoryStream
Dim bw As New BinaryWriter(Op)
bw.Write(Chr(Keys.Escape))
bw.Write("@"c)
' So we have our bitmap data sitting in a bit array called "dots."
' This is one long array of 1s (black) and 0s (white) pixels arranged
' as if we had scanned the bitmap from top to bottom, left to right.
' The printer wants to see these arranged in bytes stacked three high.
' So, essentially, we need to read 24 bits for x = 0, generate those
' bytes, and send them to the printer, then keep increasing x. If our
' image is more than 24 dots high, we have to send a second bit image
' command to draw the next slice of 24 dots in the image.
' Set the line spacing to 24 dots, the height of each "stripe" of the
' image that we're drawing. If we don't do this, and we need to
' draw the bitmap in multiple passes, then we'll end up with some
' whitespace between slices of the image since the default line
' height--how much the printer moves on a newline--is 30 dots.
bw.Write(Chr(Keys.Escape))
bw.Write("3"c)
' '3' just means 'change line height command'
bw.Write(CByte(24))
' OK. So, starting from x = 0, read 24 bits down and send that data
' to the printer. The offset variable keeps track of our global 'y'
' position in the image. For example, if we were drawing a bitmap
' that is 48 pixels high, then this while loop will execute twice,
' once for each pass of 24 dots. On the first pass, the offset is
' 0, and on the second pass, the offset is 24. We keep making
' these 24-dot stripes until we've run past the height of the
' bitmap.
Dim offset As Integer = 0
Dim width As Byte()
While offset < Data.Height
' The third and fourth parameters to the bit image command are
' 'nL' and 'nH'. The 'L' and the 'H' refer to 'low' and 'high', respectively.
' All 'n' really is is the width of the image that we're about to draw.
' Since the width can be greater than 255 dots, the parameter has to
' be split across two bytes, which is why the documentation says the
' width is 'nL' + ('nH' * 256).
bw.Write(Chr(Keys.Escape))
bw.Write("*"c)
' bit-image mode
bw.Write(CByte(33))
' 24-dot double-density
width = BitConverter.GetBytes(Data.Width)
bw.Write(width(0))
' width low byte
bw.Write(width(1))
' width high byte
For x As Integer = 0 To Data.Width - 1
' Remember, 24 dots = 24 bits = 3 bytes.
' The 'k' variable keeps track of which of those
' three bytes that we're currently scribbling into.
For k As Integer = 0 To 2
Dim slice As Byte = 0
' A byte is 8 bits. The 'b' variable keeps track
' of which bit in the byte we're recording.
For b As Integer = 0 To 7
' Calculate the y position that we're currently
' trying to draw. We take our offset, divide it
' by 8 so we're talking about the y offset in
' terms of bytes, add our current 'k' byte
' offset to that, multiple by 8 to get it in terms
' of bits again, and add our bit offset to it.
Dim y As Integer = (((offset \ 8) + k) * 8) + b
' Calculate the location of the pixel we want in the bit array.
' It'll be at (y * width) + x.
Dim i As Integer = (y * Data.Width) + x
' If the image (or this stripe of the image)
' is shorter than 24 dots, pad with zero.
Dim v As Boolean = False
If i < Data.Dots.Length Then
v = Data.Dots(i)
End If
' Finally, store our bit in the byte that we're currently
' scribbling to. Our current 'b' is actually the exact
' opposite of where we want it to be in the byte, so
' subtract it from 7, shift our bit into place in a temp
' byte, and OR it with the target byte to get it into there.
slice = slice Or CByte((If(v, 1, 0)) << (7 - b))
Next
' Phew! Write the damn byte to the buffer
bw.Write(slice)
Next
Next
' We're done with this 24-dot high pass. Render a newline
' to bump the print head down to the next line
' and keep on trucking.
offset = offset + 24
bw.Write(vbCrLf.ToCharArray)
End While
' Restore the line spacing to the default of 30 dots.
bw.Write(Chr(Keys.Escape))
bw.Write("3"c)
bw.Write(CByte(30))
bw.Flush()
Return Op.ToArray
End Function
Private Shared Function GetBitmapData(BM As Bitmap) As BitMapData
Dim threshold = 127
Dim index As Integer = 0
Dim dimensions As Integer = BM.Width * BM.Height
Dim dots As BitArray = New BitArray(dimensions)
Dim res As New BitMapData
Dim a As Integer
For y = 0 To BM.Height - 1
For x = 0 To BM.Width - 1
Dim col As Color = BM.GetPixel(x, y)
Dim luminance = CInt(col.R * 0.3 + col.G * 0.59 + col.B * 0.11)
If (luminance < threshold) = True Then
a = 1
End If
dots(index) = (luminance < threshold)
index = index + 1
Next
Next
res.Dots = dots : res.Height = BM.Height : res.Width = BM.Width
Return res
End Function
Private Class BitMapData
Public Dots As BitArray
Public Height As Int16
Public Width As Int16
End Class
' When the function is given a printer name and an unmanaged array of
' bytes, the function sends those bytes to the print queue.
' Returns True on success or False on failure.
Private Shared Function PrintEsto(ByVal pBytes As IntPtr, ByVal dwCount As Int32) As Boolean
Dim hPrinter As IntPtr ' The printer handle.
Dim dwError As Int32 ' Last error - in case there was trouble.
Dim di As DOCINFOW = Nothing ' Describes your document (name, port, data type).
Dim dwWritten As Int32 ' The number of bytes written by WritePrinter().
Dim bSuccess As Boolean ' Your success code.
' Set up the DOCINFO structure.
With di
.pDocName = "RAW Document"
.pDataType = "RAW"
End With
' Assume failure unless you specifically succeed.
bSuccess = False
If OpenPrinter(PrinterName, hPrinter, 0) Then
If StartDocPrinter(hPrinter, 1, di) Then
If StartPagePrinter(hPrinter) Then
' Write your printer-specific bytes to the printer.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, dwWritten)
EndPagePrinter(hPrinter)
End If
EndDocPrinter(hPrinter)
End If
ClosePrinter(hPrinter)
End If
' If you did not succeed, GetLastError may give more information
' about why not.
If bSuccess = False Then
dwError = Marshal.GetLastWin32Error()
End If
Return bSuccess
End Function
' SendFileToPrinter()
' When the function is given a file name and a printer name,
' the function reads the contents of the file and sends the
' contents to the printer.
' Presumes that the file contains printer-ready data.
' Shows how to use the SendBytesToPrinter function.
' Returns True on success or False on failure.
Public Shared Function PrintFile(ByVal szFileName As String) As Boolean
' Open the file.
Try
Dim fs As New FileStream(szFileName, FileMode.Open)
' Create a BinaryReader on the file.
Dim br As New BinaryReader(fs)
' Dim an array of bytes large enough to hold the file's contents.
Dim bytes(fs.Length) As Byte
Dim bSuccess As Boolean
' Your unmanaged pointer.
Dim pUnmanagedBytes As IntPtr
' Read the contents of the file into the array.
bytes = br.ReadBytes(fs.Length)
' Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(fs.Length)
' Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, fs.Length)
' Send the unmanaged bytes to the printer.
bSuccess = PrintEsto(pUnmanagedBytes, fs.Length)
' Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes)
fs.Close()
Return bSuccess
Catch ex As Exception
MsgBox(ex.Message)
Return False
End Try
End Function
' When the function is given a string and a printer name,
' the function sends the string to the printer as raw bytes.
Public Shared Function PrintString(ByVal szString As String)
Dim pBytes As IntPtr
Dim dwCount As Int32
Dim Res As Boolean
' How many characters are in the string?
dwCount = szString.Length()
' Assume that the printer is expecting ANSI text, and then convert
' the string to ANSI text.
pBytes = Marshal.StringToCoTaskMemAnsi(szString)
' Send the converted ANSI string to the printer.
Res = PrintEsto(pBytes, dwCount)
Marshal.FreeCoTaskMem(pBytes)
Return Res
End Function
End Class
And this is how I call whit class:
If EsImpresionTermica Then
If File.Exists(My.Application.Info.DirectoryPath & "\Settings.{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}\Logo.conf") Then _
RawPrinting.EscPOS.PrintBytes(File.ReadAllBytes(My.Application.Info.DirectoryPath & "\Settings.{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}\Logo.conf"))
Else
Dim MSe As New MemoryStream
Dim BWe As New BinaryWriter(MSe)
BWe.Write(Chr(&H1B))
BWe.Write("@"c) 'Inicia Imresora
BWe.Write(Chr(&H1B))
BWe.Write(CByte(3))
BWe.Write(Chr(18)) 'Establece interlineado
BWe.Write(Chr(&H1B))
BWe.Write("U"c)
BWe.Write(Chr(1)) 'Impresión unidireccional
BWe.Write(Chr(&H1B))
BWe.Write("a"c)
BWe.Write(Chr(1)) 'Centra Impresión
BWe.Write(Chr(&H1B))
BWe.Write(vbCrLf.ToCharArray)
BWe.Write(Encoding.ASCII.GetBytes(Encabezado))
BWe.Write(Chr(10))
BWe.Write(Chr(10))
BWe.Flush()
BWe.Close()
RawPrinting.EscPOS.PrintBytes(MSe.ToArray)
End If
End Sub
Best Answer
Are you using an RS-232 transceiver? The Arduino outputs 0 and 5 V for serial, while the printer uses -12 and 12 V for serial. You should use a MAX232 or similar device to get the correct physical interface. (You might be able to cheat if you invert the serial port on the Arduino, but that might not work, and it's more trouble when just getting started.)
Once that's taken care of, the RTS and DTR may be your problem. You should be able to change the DIP-switch settings on the printer and turn off flow control altogether, or switch it to software flow control.
Also, you may need to send both line feed and carriage return.
However, once all that's done it should print just fine, even without any reset commands. Send a bunch of ASCII characters and line feed/carriage returns, and it'll spit it all out.
You can ignore the RX line (on the Arduino side, TX on the printer side) for now - just send it data until you figure out the wiring, level conversion, flow control, etc.