{"id":38,"date":"2014-11-25T03:09:10","date_gmt":"2014-11-25T03:09:10","guid":{"rendered":"http:\/\/blog.arrozcru.org\/?p=38"},"modified":"2014-11-27T23:40:52","modified_gmt":"2014-11-27T23:40:52","slug":"using-mess-as-the-systems-printer","status":"publish","type":"post","link":"http:\/\/blog.arrozcru.org\/?p=38","title":{"rendered":"Using MESS as the system&#8217;s printer"},"content":{"rendered":"<p>What was the main reason I started <a title=\"MESSing with the ActionPrinter 2000\" href=\"http:\/\/blog.arrozcru.org\/?p=11\">MESSing with the ActionPrinter 2000<\/a>? To extract the characters&#8217; bitmaps so that I could optimize image-&gt;ASCII conversion to the printer&#8217;s specific font.<\/p>\n<p>As a fun side-project I decided to configure MESS with CUPS as a normal printer on my system to see how well it would work.<\/p>\n<p>I started off by implementing the Centronics communication used by the printer in MESS. This way, it was possible to boot any device with a Centronics interface connected to the printer, as if I was actually running a device and the printer itself. For this, I booted a simple 486 with an MS-DOS 6.22 floppy disk inside MESS.<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/0001.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-39\" src=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/0001.png\" alt=\"486\" width=\"720\" height=\"400\" srcset=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/0001.png 720w, http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/0001-300x166.png 300w\" sizes=\"auto, (max-width: 720px) 100vw, 720px\" \/><\/a><\/p>\n<p>The parallel port communication with the printer was a little bit tricky.<\/p>\n<p style=\"text-align: center; border: 1px solid black;\"><a href=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/centronics.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-40\" src=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/centronics.png\" alt=\"ActionPrinter 2000 Centronics Interface Overview\" width=\"684\" height=\"423\" srcset=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/centronics.png 684w, http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/centronics-300x185.png 300w\" sizes=\"auto, (max-width: 684px) 100vw, 684px\" \/><\/a><\/p>\n<p>When a strobe pulse is detected, the E05A30 gate array sets the BUSY signal. When the CPU is done reading the data and it&#8217;s time to unset the BUSY signal, the firmware does the following:<\/p>\n<ol>\n<li>Read the control register (which contains the ACK and BUSY signal) to a CPU register;<\/li>\n<li>Unsets the ACK signal in the CPU register and outputs everything\u00a0to the control register;<\/li>\n<li>Unsets the BUSY signal in the CPU register and outputs everything\u00a0to the control register;<\/li>\n<li>Sets the ACK signal in the CPU register and outputs everything to the control register.<\/li>\n<\/ol>\n<p>The printer&#8217;s manual had conflicting information about which component was supposed to take care of setting\/resetting the BUSY signal. Another printer&#8217;s manual (the LX-1050+, which uses the exact same gate array), had even more conflicting information about the Interface overview.<\/p>\n<p>Besides that, the 486 I was using with the printer would ignore\u00a0the ACK signal from the printer. The result was that between steps 3 and 4, the BUSY signal was unset, so the PC would ignore the ACK signal and send a new character. But step 4 would reset the BUSY signal again, since it had read the control register to a CPU register, and did not detect that the BUSY signal had changed! The PC would then send another character, so the printer had just &#8220;lost&#8221; a character somewhere in the middle of all that.<\/p>\n<p>After quite some time trying to find the problem and discussing this issue with <a href=\"http:\/\/smf.mameworld.info\/\">smf<\/a>\u00a0on IRC, he told me some very wise\u00a0words:<\/p>\n<blockquote><p>&lt;@smf&gt;\u00a0never assume that the programmer knew what he was doing<\/p><\/blockquote>\n<p>Indeed, the firmware would make much more sense if we assumed that the programmer who wrote it made a few mistakes. I had already seen a couple of nasty bugs in the firmware, such as these ones:<\/p>\n<pre class=\"lang:c decode:true \">\/* 7851 *\/\r\nint cr_not_full_step(void)\r\n{\r\n    \/* there is a bug in this function, it searches 5 items\r\n     * into an array which only contains 4 items. The last\r\n     * item (0x34) is part of the first instruction in the\r\n     * next function:\r\n     * 7864: 34 4A 10           LXI     HL,$104A\r\n     *\/\r\n    uint8_t full_steps[5] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x34 };\r\n    uint8_t cur_step = [0xC008];\r\n    for (int i = 0; i &lt; 5; i++)\r\n        if (cur_step == full_steps[i])\r\n            return 0;\r\n    return 1;\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<pre class=\"lang:c decode:true \">\/* 00CA *\/\r\nuint16_t mul16(uint16_t EA, uint8_t A)\r\n{\r\n    \/* uses EA, BC, and A *\/\r\n    uint8_t h = in16 &gt;&gt; 8;\r\n    uint8_t l = in16 &amp; 0xff;\r\n    uint16_t mh = (uint16_t) in8 * h;\r\n    uint16_t ml = (uint16_t) in8 * l;\r\n    uint16_t r = 0;\r\n    if (mh &amp; 0xff00) {\r\n        \/* check is wrong, we don't care *\/\r\n        carry = 1;\r\n    } else {\r\n        r =   mh;\r\n        r &lt;&lt;= 8;\r\n        r +=  ml;\r\n    }\r\n    return r; \/* EA *\/\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>And so\u00a0I added a little check to the gate array that made it impossible to reset the BUSY signal before the character had been read. The PC inside MESS was now capable of talking to the printer. I got this as a result of &#8220;<strong>dir &gt; LPT1<\/strong>&#8220;:<\/p>\n<p><a href=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/dir_bw.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-57 size-full\" style=\"border: 1px solid black;\" src=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/dir_bw.png\" alt=\"\" width=\"527\" height=\"588\" srcset=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/dir_bw.png 527w, http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/dir_bw-268x300.png 268w\" sizes=\"auto, (max-width: 527px) 100vw, 527px\" \/><\/a><\/p>\n<p>Did you notice that the lines are not very well aligned vertically? This happens because, up until that point, I would assume that the stepper motor positions would be exactly what the last step was set to by the firmware. This is not really the case, since the motor is not being used one step at a time. It does two steps at a time, and the printhead fires twice at different moments while the motor is still moving. The firmware is very well designed, in such a way that all this movement is taken into consideration when the printhead is moving either from left to right or from right to left. It even considers the 300 microseconds it takes for the printhead to hit the paper! I implemented all this dynamics into MESS and got perfect vertical alignment (funnily enough, even better than the actual printer, which is 20+ years old by now).<\/p>\n<p>Anyways, now I knew how to make the printer receive data inside MESS. But what about receiving data from outside of MESS?<\/p>\n<p>I created a Dummy Centronics driver in MESS that would just read from a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Named_pipe\">named pipe<\/a>\u00a0and feed that to the printer. At the other end of the named pipe I could print whatever I wanted from my host system with &#8220;<strong>cat file &gt; \/dev\/lp0<\/strong>&#8220;, such as this Lorem Ipsum:<\/p>\n<p><a href=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/lorem_ipsum_3_bw.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-56 size-full\" style=\"border: 1px solid black;\" src=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/lorem_ipsum_3_bw.png\" alt=\"\" width=\"1048\" height=\"576\" srcset=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/lorem_ipsum_3_bw.png 1048w, http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/lorem_ipsum_3_bw-300x164.png 300w, http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/lorem_ipsum_3_bw-1024x562.png 1024w, http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/lorem_ipsum_3_bw-800x439.png 800w\" sizes=\"auto, (max-width: 1048px) 100vw, 1048px\" \/><\/a><\/p>\n<p>Would it be possible to add this printer to CUPS and use it with any other program? Of course. It&#8217;s quite easy too:<\/p>\n<pre class=\"lang:sh decode:true\">$ sudo mkfifo \/dev\/lp0\r\n$ sudo chmod 666 \/dev\/lp0 # bad idea but simple solution\r\n$ sudo chown root.lp \/dev\/lp0\r\n$ sudo lpadmin -p ap2000 -E -v parallel:\/dev\/lp0 -P Generic-ESC_P_Dot_Matrix_Printer-epson.ppd\r\n<\/pre>\n<p>The printer needs <a href=\"http:\/\/www.openprinting.org\/printer\/Generic\/Generic-ESC_P_Dot_Matrix_Printer\">this\u00a0PPD file<\/a>\u00a0so that CUPS knows how to convert anything to the only language the ActionPrinter 2000\u00a0understands\u00a0(ESC\/P). At first I had configured the device as a raw printer, so CUPS would happily send PostScript commands to the printer, which would just print them as plain text.<\/p>\n<p>Now I was able to go to LibreOffice and print using the <strong>ap2000<\/strong> printer:<\/p>\n<p><a href=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/lorem_ipsum_2_scaled_bw.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-61 size-full\" style=\"border: 1px solid black;\" src=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/lorem_ipsum_2_scaled_bw.png\" alt=\"\" width=\"614\" height=\"730\" srcset=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/lorem_ipsum_2_scaled_bw.png 614w, http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/lorem_ipsum_2_scaled_bw-252x300.png 252w\" sizes=\"auto, (max-width: 614px) 100vw, 614px\" \/><\/a><\/p>\n<p>And even GIMP!:<\/p>\n<p><a href=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/antonio_bw.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-59 size-full\" style=\"border: 1px solid black;\" src=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/antonio_bw.png\" alt=\"\" width=\"630\" height=\"724\" srcset=\"http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/antonio_bw.png 630w, http:\/\/blog.arrozcru.org\/wp-content\/uploads\/2014\/11\/antonio_bw-261x300.png 261w\" sizes=\"auto, (max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p>The printer&#8217;s resolution is 120&#215;72 dpi. The pixels are not square: every 10 pixels horizontally are the same size as 6 pixels vertically.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What was the main reason I started MESSing with the ActionPrinter 2000? To extract the characters&#8217; bitmaps so that I could optimize image-&gt;ASCII conversion to the printer&#8217;s specific font. As a fun side-project I decided to configure MESS with CUPS as a normal printer on my system to see how well it would work. I &hellip; <a href=\"http:\/\/blog.arrozcru.org\/?p=38\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Using MESS as the system&#8217;s printer<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,3],"tags":[],"class_list":["post-38","post","type-post","status-publish","format-standard","hentry","category-mess","category-reverse-engineering"],"_links":{"self":[{"href":"http:\/\/blog.arrozcru.org\/index.php?rest_route=\/wp\/v2\/posts\/38","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.arrozcru.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.arrozcru.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.arrozcru.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.arrozcru.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=38"}],"version-history":[{"count":9,"href":"http:\/\/blog.arrozcru.org\/index.php?rest_route=\/wp\/v2\/posts\/38\/revisions"}],"predecessor-version":[{"id":63,"href":"http:\/\/blog.arrozcru.org\/index.php?rest_route=\/wp\/v2\/posts\/38\/revisions\/63"}],"wp:attachment":[{"href":"http:\/\/blog.arrozcru.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=38"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.arrozcru.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=38"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.arrozcru.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=38"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}