i need to tell a printer driver to issue a form feed.
i'm printing directly to a printer using the:
OpenPrinter
StartDocPrinter
StartPagePrinter
WritePrinter
EndPagePrinter
EndDocPrinter
ClosePrinter
set of API calls.
A lot of the inspiration came from KB138594 - HOWTO: Send Raw Data to a Printer by Using the Win32 API. An important point to note in that KB article is that they (and my copied code) start the document in RAW mode:
// Fill in the structure with info about this "document."
docInfo.pDocName = "My Document";
docInfo.pOutputFile = NULL;
docInfo.pDatatype = "RAW";
StartDocPrinter(hPrinter, 1, docInfo);
Note: RAW mode (as opposed to TEXT mode) means we are issuing raw bytes to the printer driver. We promise to talk in the language it understands.
We can then use WritePrinter to write everything we want:
WritePrinter(hPrinter, "Hello, world!"); //note, extra parameters removed for clarity
WritePrinter(hPrinter, 0x0c); //form-feed
The problem here is the 0x0c form-feed character. Because we've opened the printer in RAW mode, we are promising we will send the printer driver bytes it can process. The drivers of most printers take 0x0C to mean you want to issue a form-feed.
The problem is that other printers (PDF printer, Microsoft XPS Printers) expect RAW print jobs to be in their own printer language. If you use the above to print to an XPS or PDF printer: nothing happens (i.e. no save dialog, nothing printed).
i asked for a solution to this question a while ago, and a response was that you have to change the document mode from RAW:
docInfo.pDatatype = "RAW";
to TEXT:
docInfo.pDataType = "TEXT";
Well this probably is because you send
"RAW" data directly to the printer,
and RAW can be any PDL. But the XPS
driver will probably only understands
XPS, and it will probably just ignore
your "unknown: Hello, world!0xFF" PDL. The
XPS driver will probably, if any, only
accept XPS data when you write
directly to it.
If you want to render text on the XPS
driver, you should use GDI. You might
be able to send plain text to the
driver if you specify "TEXT" as the
datatype. The print processor attached
to the driver will then "convert" the
plaintext for you by rendering the job
via GDI to the driver.
So that worked, i changed my code to declare the print document as TEXT:
// Fill in the structure with info about this "document."
docInfo.pDocName = "My Document";
docInfo.pOutputFile = NULL;
docInfo.pDatatype = "TEXT";
StartDocPrinter(hPrinter, 1, docInfo);
WritePrinter(hPrinter, "Hello, world!");
WritePrinter(hPrinter, 0x0c); //form-feed
And then the Save As dialog for XPS and PDF printers appear, and it saves correctly. And i thought all was fixed.
Except months later, when i tried to print to a <quote>real</quote> printer: the form-feed doesn't happen - presumably because i am no longer printing in "raw printer commands" mode.
So what i need is the Windows-ish way of issuing a form feed. i need the API call that will tell printer driver that i want the printer to perform a form-feed.
My question: How to tell a printer to issue a Form-Feed during printing?
Background on Data Types
The print processor tells the spooler to alter a job according to the document data type. It works in conjunction with the printer driver to send the spooled print jobs from the hard drive to the printer.
Software vendors occasionally develop their own print processors to support custom data types. Normally, the print processor does not require any settings or intervention from administrators.
Data types
The Windows printing process normally supports five data types. The two most commonly used data types, enhanced metafile (EMF) and ready to print (RAW), affect performance in different ways on both the client computer and the print server computer.
RAW is the default data type for clients other than Windows-based programs. The RAW data type tells the spooler not to alter the print job at all prior to printing. With this data type, the entire process of preparing the print job is done on the client computer.
EMF, or enhanced metafile, is the default datatype with most Windows-based programs. With EMF, the printed document is altered into a metafile format that is more portable than RAW files and usually can be printed on any printer. EMF files tend to be smaller than RAW files that contain the same print job. Regarding performance, only the first portion of a print job is altered, or rendered on the client computer, but most of the impact is on the print server computer, which also helps the application on the client computer to return control to the user faster.
The following table (taken from MSDN) shows the five different data types supported by the default Windows print processor:
Data type: RAW
Directions to spooler: Print the document with no changes.
Use: This is the data type for all clients not based on Windows.
Data type: RAW [FF appended]
Directions to spooler: Append a form-feed character (0x0C), but make no other changes. (A PCL printer omits the document's last page if there is no trailing form-feed.)
Use: Required for some applications. Windows does not assign it, but it can be set as the default in the Print Processor dialog box.
Data type: RAW [FF auto]
Directions to spooler: Check for a trailing form-feed and add one if it is not already there, but make no other changes.
Use: Required for some applications. Windows does not assign it, but it can be set as the default in the Print Processor dialog box.
Data type: NT EMF 1.00x
Directions to spooler: Treat the document as an enhanced metafile (EMF) rather than the RAW data that the printer driver puts out.
Use: EMF documents are created by Windows.
Data type: TEXT
Directions to spooler: Treat the entire job as ANSI text and add print specifications using the print device's factory defaults.
Use: This is useful when the print job is simple text and the target print device cannot interpret simple text.
You can see the print processors available for a printer, and the data types that each processor supports, through the properties of a printer in the control panel:
See also
Send ESC commands to a printer in C#
Feed paper on POS Printer C#
Print raw data to a thermal-printer using .NET
Yeah, that doesn't work. You are intentionally bypassing the printer driver, the chunk of code that presents a universal interface to any printer. Which leaves you to deal with the peculiarities of each specific printer model.
There are some common interfaces, the one you used in your code is the one that dot matrix printers of old used. PCL is common on Hewlett Packard laser printers. Postscript is common on high-end printers. The latter two have their own incantations to get a form feed.
Then there's the ocean of cheap laser and ink jet printers. They often don't have a well defined interface at all. Instead of having a processor inside the printer that translates printer commands to dots on paper, they let the printer driver do all the hard work. You'll never get one of those going, the interface is proprietary and undocumented.
The printer driver is your friend here. PrintDocument the class to use it. Getting a form feed is easy, just set e.HasMorePages = true and exit the PrintPage event handler. You already saw the StreamPrinter class I linked.
I'm unfamiliar with the TEXT document type, but I presume it's just a lowest common denominator "dumb printer" representation. If so, it might recognize a form-feed character, except you've been using the wrong character - it's not 0x12 or 0xFF, it's 0x0c. See http://en.wikipedia.org/wiki/Ascii
Since my last answer was no help, lets try the obvious. Have you tried doing EndPagePrinter followed by StartPagePrinter whenever you need a page break?
If that still doesn't work you may need to do it the hard way, using GDI. The stack looks just slightly different from the one you're using:
CreateDC
CreateFont
SelectObject
StartDoc
StartPage
TextOut
EndPage
EndDoc
DeleteDC
You'll be required to manage a font and place the text on the page yourself at each line position.
Related
I am building a embedded device that will communicate to the outside world by virtual COM. I have the descriptor and all the callbacks for the USB set up correctly and COM is working - well kind of. The problem is that when I issue the GetCommState command for the COM I get a semi valid struct back and when one fixes only couple of parameters (like setting the speed and 8N1) and try to reconfigure the port by calling SetCommState the actions fails with: 'A device attached to the system is not functioning.'
If one continues to use the port it just work - all writes and reads - without a problem. But the issue is that most libraries try to reconfigure the port by first issuing the GetCommState and then SetCommState - pyserial and C# both do it in this way.
My question is where do the "default" configuration for COM comes form?
In the USB ACM CDC standard there are (optional) class requests for SET and GET COMM feature but I can see (from USB sniffer) that they are never called (I tried with capabilities for USB ACM CDC set to 0x06 (that is without SET/GET COMM) and 0x07 (with SET/GET COMM) but in no case I get a class request from the driver). So the driver must take the config from somewhere else, does anybody knows from where or how?
I am using an NXP LPC and Windows 10 with usbser.sys driver on other end.
What I already checked is:
compared the USB descriptor to the working one - they are the same
checked the USB traffic - the enumeration and communication looks the same
without doing GetCommState and SetCommState the COM is working without problem
I attached the content of the DCB struct for working sample (left) and my (right). I do not understand where do the marked values come from? Who sets them?
The settings should come from the port driver - you can view and set default values in the Windows Device Manager. In your case, it would seem that flow control with RTS/CTS is enabled (left picture), which might be something that your USB adapter uses internally. If it works, then leave those settings as they were.
I'd advise to do like this:
Always check the result of each API function you call!
Call CreateFile to get the port handle.
Optionally call GetCommTimeouts and store the result in a zero-initialized struct like COMMTIMEOUTS com_timeouts = {0};. Change members of the struct as needed, then call SetCommTimeouts.
Create an (almost) zero-initialized struct DCB dcb = { .DCBlength = sizeof(DCB) }.
Call GetCommState on this struct.
Set baudrate, parity, stop bits etc as required. Leave other members as they were.
Call SetCommState.
my SD card cannot work after erase, what's the matter?
My SD card is working properly, then after erase 4 blocks of memory, send CMD18 it does not spit data,And the host does not get "cmd_end" MIE_EVENT。(Command transmission normal)
What I'm more suspicious of is the erasure process,because of data can trans normal without erase. my erase process is:
a. send "cmd32,args:start_address"
b. send "cmd33,args:end_address"
c. send "cmd38,args:1" start erase。
The erasure process looks fine, But the evidence suggests something is wrong with it. I have looked for relevant information about SD erasure, but nothing came of it.
See the simplified SD standard, available here: https://www.sdcard.org/downloads/pls/
Section 4.3.5 give an overview of the erase procedure.
Section 4.7 details the structures of the erase commands
The SD Erase must be a aligned to and a multiple of the ERASE_SIZE. This is available from the SD_STATUS field (section 4.10.2.5). I suspect your 4 blocks are below this threshold. You should instead consider writing out the erase pattern.
I can encoded an NFC Sticker with a website that will open when I tap it with a mobile phone. For the application I want to use it for I need to be able to expire that link so the user can't just save the URL and use it again. Basically I need to be able to put a random string in the URL that changes each time it gets scanned, such as www.mywebsite.com/TCHQ23, www.mywebsite.com/LQ8FT, ect.
Is this possible with a regular NFC sticker? If not, what kind of device would I use to make this happen? I know there are Arduino modules that can do this, but is there a simpler method or a ready made product that can act as an NFC but have the URL changed by a computer via a USB cable?
Thanks
NFC tags (some) have a feature called "Mirroring". You can mirror the read counter value to the URL, which gets incremented every time you tap it to reader i.e. Every time read command is called, the counter increases by 1. Tags like NTAG 213, NTAG 215 etc have that feature.
Update:
If your requirement is to get a portion of URL to to return random data and on a cheaper tag or sticker then I would suggest considering NTAG 213 tag, which is cost friendly and also have Mirroring feature supported.
If your URL data is http://www.abc#xyz.com then once the counter Mirroring is enabled (read counter must be enabled first) it will look something like
http://www.abc#xyz.com?000001
The last 6 digit value gets increased by value 1,every time a read command is invoked. (000002, 000003, 000004 and so on)
you can refer this link for more info
So your card/device has to present when read a NDEF record with a link in it (A "Well Known Type 1 with a record type definition of type U, etc), this will cause most phones to open a browser automatically
Some details on the Record type needed at https://www.oreilly.com/library/view/beginning-nfc/9781449324094/ch04.html
Most cards have the ability to store some static data, some have as #Adarsh Rotte says have counters, random number generators, crypto, password protection, mirroring (backup) of data, other functions but non of these will help as these custom functions and are card specific and don't / cannot present the data to match the NFC NDEF specification.
There is one type of card that can do this called JavaCard as these can run fully programmable Java Apps. These can be programmed to respond to NFC read request with the right NDEF measure where the URL can be generated on the fly.
There is a github repo with an example Java App to run on these cards that shows how to respond with and NDEF message at https://github.com/OpenJavaCard/openjavacard-ndef.
Watch out for https://github.com/OpenJavaCard/openjavacard-ndef/issues/10 if trying to use this, the default magic AID number is not the right one for NDEF and should be configured at the time you install the App on the Card.
This app emulates the behaviour of an NFC Type 4 spec card.
You would also need to customise it to have the right NDEF payload data with the right generated URL ending.
There are examples of the Card make/model supported by this App listed on the the github pages some are dual interface cards but there are some without the chip contacts and only NFC interface.
Generating the URL ending could be challenging or easy depending on level of security/validation you need.
Starting from a Random String which would be easy to fake because it has no level of validation, to a obfuscated counter, to a public key type encrypted counter.
There are also other solutions to generating the NDEF data with the right URL that don't use a Card and usually require there own power to run.
Some options:-
An Android phone can do what is call Host Card Emulation (HCE) which is very like what the JavaCard is doing, it is pretending to be a NFC Type 4 Card and the response it sends if fully programmable and could be the right type of NDEF message as per the JavaCard.
There are some "Card Reader" Devices that can be attach to a PC/Raspberry Pie via USB can also do HCE like the Android phone. e.g. https://www.acs.com.hk/en/products/342/acr1252u-usb-nfc-reader-iii-nfc-forum-certified-reader/ - this is well documented in the datasheets on how to do.
There are some other "Card Reader" modules that can connect via I2C to Arduino that can do HCE as well. (Technically most Arduino PN532 Chip's which are used in a lot of USB readers as well can do HCE but it is a bit undocumented on how to do it - see section 4 of https://www.nxp.com/docs/en/user-guide/141520.pdf)
There are some other chips that can act as static data NFC devices the also have an I2C interface to write the static data but allow a "pass through" mode to the I2C interface, again these tend to be NFC Type 4 but do some of the HCE type work for you.
e.g. the M24SR04-Y https://www.st.com/resource/en/datasheet/m24sr04-g.pdf can do it
So technically possible with a variety of methods but all not that simple to implement BUT not "Sticker" type format of NFC devices tend to be very simple NFC device as the format restricts the complexity of the hardware contained in them.
I'm capturing the output of an external program as described here. Now I am wondering about the text encoding to expect when reading the pipe's data into a memory buffer using ReadFile().
External programs can write to stdout in various ways, for example:
using printf()
using wprintf()
using WriteConsoleA()
using WriteConsoleW()
...
So will I get UTF-16 text if a program uses wprintf() or WriteConsoleW() to write to stdout and 8-bit text (depending on the default console encoding) if a program uses printf() or WriteConsoleA()? Or what encoding will text captured from an external program be in?
TD;DR: It depends on the program.
WriteConsoleA/W cannot write to pipes, only to the console so they are not a factor here.
A program that uses WriteFile directly will write in whatever format the data given to the function is. Most likely the active ANSI codepage, the OEM codepage, or UTF16-LE.
A program that uses the wchar_t print functions and the Microsoft C run-time can choose the output format (_O_WTEXT (UTF-16? with BOM), _O_U8TEXT, or _O_U16TEXT) by calling _setmode or _wsopen.
Most programs are not going to output UTF16-LE unless you give them a switch to enable this feature (cmd.exe /U etc.). The best approach if you know nothing about the programs but you prefer Unicode would be to look for a BOM and if it is not present, try to parse as UTF-8 and if/when that fails, fall back to the ANSI or OEM codepage. If you have a fair amount of buffering you could also try to detect UTF-16 without a BOM with IsTextUnicode.
If you are attached to a console you can try to influence the other process by calling SetConsoleOutputCP but I doubt anyone will listen.
See also:
Myth busting in the console
Conventional wisdom is retarded, aka What the ##%&* is _O_U16TEXT?
I'm in a senior design class for my college's computer engineering program. I'm not very good with Embedded Systems. I need to create a program that can send instruction to a microcontroller and it should have a GUI. Someone else is programming the microcontroller so I'm mostly just responding to what they will output to me. I really have no idea where to start with this, I'm a little swamped/overwhelmed on my final semester. Would someone mind pointing me in the right direction?
Additional info: We are using a TI-msp430f2274 for the device and it's really just outputting the readings of 3 gyroscopes. I'm thinking about using GTK to create the GUI but I am looking to see if there's something better.
Edit: My project is a roller alignment tool that uses gyroscopes to compare two rollers. The program would send an instruction to "zero" the tool to one roller and receive a stream of data that says the offset difference of the next roller.
We are using a TTL-232R cable with a UART interface and the program should work on Windows. I have no idea how you talk to it. College has crushed me.
If you're using a windows machine then Visual Studio and a Windows Forms Application could do the trick. I've used it previously to interface with temperature sensors and other control equipment via USB and other projects involving reading from USB Human Interface Devices. So without understanding the specifics of your project, as an IDE Visual Studio, I think, is the best and most intuitive and using the Windows API you can achieve a lot with your code.
Visual Studio 2012
HTH.
p.s. I write most of my code in VB using VS but it will support other languages too...
Edit: some example code of reading from a com port:
Sub ReceiveSerialData()
' Receive strings from a com port
Dim comport as string = "COM 6" 'or whatever com you want...
Dim baud as integer = 9600 'or whatever baud you want...
Try
com = My.Computer.Ports.OpenSerialPort(comport)
com.ReadTimeout = 10000
com.BaudRate = baud
While (com.IsOpen)
Dim Incoming As String = com.ReadLine()
If Incoming Is Nothing Then
Exit While
Else
'do something here with your com data
'i.e. display it in a rich text box, or whatever...
End If
End While
Catch ex As Exception
' display your errors here if you wish....
End Try
End Sub
I think the other answers though, esp about using tcl probably make more sense from an embedded systems point of view. I simply have no experience with them whatsoever hence my VB'ness. :-)
Since you mentioned that you've used tcl before, I'm giving my answer in tcl since IMHO it's the easiest way to do this and therefor the right tool for the right job.
The core advantage of tcl (and indeed one of the reasons it's loved by its fans) is that it's very, very cross-platform. While in other languages cross platform simply means "can run on multiple platforms" but still requires you to use different API depending on the platform, tcl smooths out platform differences providing a unified API across platforms.
Tcl treats serial ports like files so you just open it to talk to it. Granted, different platforms provides different ways of naming the ports. So on Windows, to talk to the serial port you simply do:
set rs232 [open COM1 w+]
On unixen (Linux, MacOSX etc.) you'd do:
set rs232 [open /dev/ttyS0 w+]
To set the baud rate and parity bits you can now do
fconfigure $rs232 -mode "9600,n,8,1"
Be sure to also configure the serial port to binary mode otherwise tcl will re-interpret "\n" for you depending on your OS:
fconfigure $rs232 -mode "9600,n,8,1" -translation binary -blocking 0
The "blocking" bit is to set it to non-blocking mode so that we can write event oriented code which is critical for UI apps since we don't want the IO to block our UI.
So now for a simple program that reads data from the serial port:
package require Tk ;# in case we're running in tclsh
if {[catch {set rs232 [open COM1 w+] err}]} {
tk_dialog .error Error "Could not open COM1: $err" error 0 OK
}
fconfigure $rs232 -mode "9600,n,8,1" -translation binary -blocking 0
# Draw a simple UI do dump data to:
pack [label .l -text "Gyroscope outputs:"]
pack [label .g1 -textvariable gyro1]
pack [label .g2 -textvariable gyro2]
pack [label .g3 -textvariable gyro3]
# Now the fun part, read from the serial continuously with fileevent:
set buffer ""
fileevent $rs232 readable {
append buffer [read $rs232]
# Here, you need to parse the data returned.
# Due to the byte-wise nature of serial ports the data read may not be
# complete so we need to check if it's complete. "Completeness" depends
# on you. For example the data packet may end with a newline. Or it may
# simply be a timeout between data packets.
if {[message_is_complete $buffer]} {
set gyros [parse_message $buffer]
set buffer ""
# Update the UI:
foreach x $gyros y {gyro1 gyro2 gyro2} {
set $y $x
}
}
}
Minus the comments and empty lines that's just 16 lines of code. You can of course go further and implement a more fancy UI rather than just text labels.
If you need to send data to the microcontroller simply puts to it. Just remember to override tcl's automatic newline termination:
puts -nonewline $rs232 $somedata
Use tcl's binary command if you need to format to and from binary.
I personally still prefer tcl for this because you can get a prototype up and running to read the output from your hardware in under 5 minutes. But you also mentioned interest in a node.js solution. So here's an alternative starting point for node.js
First you need to install node.js. This may or may not be trivial depending on your OS. You will need Python 2.x (not 3.0) installed on your system in order to compile node.js modules writen in C (and even node.js itself). Even if you're installing a binary distribution of node you will still have to compile the serial port library since it's not included in the core.
Next you will need to install the serialport module. The instructions vary depending on your OS. See the npm page for the module: https://npmjs.org/package/serialport
Once you've got things up and running you can simply communicate with your serial port using the serialport module:
var SerialPort = require("serialport").SerialPort
var rs232 = new SerialPort("COM1", {
baudrate: 57600
}, false);
Again, like the tcl case, the name of the serial port depends on your OS. The above is an example for Windows. For unixen you'd do:
var rs232 = new SerialPort("/dev/ttyS0", {
baudrate: 57600
}, false);
For UI, node doesn't have a core toolkit like tcl. There are many libraries on npm available allowing you to use QT or GTK or some other widget set. But the most common way of doing UI on node is to simply run it as a web server and connect to it with your web browser. The downside of this is a little additional complexity and the need to mess with HTML. The upside is HTML & CSS! Which means you can leverage tools like CSS3 effects and jQuery to create a really slick UI with very little effort.
Unfortunately, writing an interactive webapp (even a simple one) is fairly involved so I won't be providing a "simple" example implementation. I'd only suggest you read up on the more popular frameworks like express.js and templating libraries like dust or handlebars. You may also want to take a look at socket.io to simplify the implementation of real-time communications between your server and the web browser.