Home Page
Posted By: Golden Child Ap2000 signs of life - 07/17/20 08:14 AM
Hi guys,

I thought I'd start a separate thread for this.

There's something strange about how the upd7810 does the analog/digital conversion.

08 is written to the ANM register, which is supposed to do scan mode on inputs AN4 - AN7 and write them to CR0-CR3, but instead of getting the proper value for AN5, 0xFF gets written to CR1.

Code
 
               if (m_adcnt > m_adtot)
                {
                        m_adcnt -= m_adtot;
                        switch (m_adout)
                        {
//                              case 0: CR0 = m_tmpcr ? 0xff:0x00; break;
//                              case 1: CR1 = m_tmpcr ? 0xff:0x00; break;
//                              case 2: CR2 = m_tmpcr ? 0xff:0x00; break;
//                              case 3: CR3 = m_tmpcr ? 0xff:0x00; break;
                                case 0: CR0 = m_tmpcr; break;
                                case 1: CR1 = m_tmpcr; break;
                                case 2: CR2 = m_tmpcr; break;
                                case 3: CR3 = m_tmpcr; break;
                        }
                        m_adin  = (m_adin  + 1) & 0x07;
                        m_adout = (m_adout + 1) & 0x03;
                        if (m_adout == 0)
                                {IRR |= INTFAD;
                                printf(".IRR=%x ",IRR);}

                        m_shdone = 0;


With that mangling above, CR1 gets the expected value, 0xCB.


Code
focus 1
bp 1dee
g

Stopped at breakpoint 1
[MAME]> 

>history 1,10
1DF0: LXI     EA,$0000
1DEE: MOV     A,CR1
1DEB: MVI     EOM,$07
1DE7: SHLD    $C005
1DE3: LHLD    $9925
981A: JMP     $1DE3
001A: JMP     $981A
0019: EXA     
0018: EXX     
2091: RET     
208E: OFFIW   VV:11,$02
208D: RET     
208B: BIT     6,VV:14
2089: BIT     7,VV:11
3162: CALT    ($009A)
3168: JR      $3162
[MAME]> 

>print anm
8
>print a
CB


Before this, I would get 5 beeps which according to the service manual is a voltage error. Now it shows a little bit more life, not working properly yet.

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 07/17/20 01:04 PM
[Linked Image from i.imgur.com]

I got it to print some data, but it seems to drop characters while it's printing, probably some handshaking problem.

It should print PRINT "DATA TO PRINTER" and have DATA TO PRINTER underneath each line.

But it's a little closer 8-)

The Apple parallel interface sends 8 bit data, and the high bit is set, I just cleared the high bit and the printer liked that data a lot better.
Posted By: Golden Child Re: Ap2000 signs of life - 07/19/20 01:47 PM
More fiddling around, it seems that the timing for the AD conversion is somehow inconsistent, and setting the conversion delay to a very high value actually makes the online and lf buttons usable.

It also seems that data sent by the Apple parallel interface card doesn't bother to check the acknowledge, it just hits the strobe, so there isn't any flow control.

There's still some characters being dropped by the ap2000, haven't been able to figure that out yet.

I added some blinkenlights to show writes to the portABC and C000-C00F, and it helps to see what's going on. Man, I love blinkenlights.

[Linked Image from i.imgur.com]
Posted By: R. Belmont Re: Ap2000 signs of life - 07/19/20 08:39 PM
The source for the parallel card's ROM is available; it's possible the ACK isn't hooked up properly.
Posted By: Golden Child Re: Ap2000 signs of life - 07/20/20 10:01 AM
I looked at the PIC manual, and there's a source code listing for both the ROMs but neither one bothers to look at the ACK, they just seem to write to C0x0 and assume it gets read.

I guess the apple was slow enough that it wasn't a problem but theoretically that could cause dropped characters.

This really surprised me that there's no real flow control as it wouldn't have been hard to add.

[Linked Image from i.imgur.com]

I wrote a little crap BASIC program to write data directly to the parallel card via I/O locations, it's slow enough that it doesn't go too fast for the printer.

Code
  NEW
    1  GOTO 90
    2 POKE PO,C : ? C,PEEK(PI),PEEK(PI)  : RETURN  :   REM PRINT CHAR AND SHOW THE ACK STATUS
    90 C = PEEK(49152+256)   : REM READ FROM C100 TO ACTIVATE AUTOSTROBE
   100 PO = 49152 + 9*16 : PI =  PO+4   : REM C090 FOR OUTPUT C094 FOR ACK INPUT
   105 FOR J = 1 TO 24
   106 C=64+J : GOSUB 2 : Z$=STR$(J) :GOSUB 3000
   110 C = 27:GOSUB 2 : C = ASC("L") : GOSUB 2  : REM ESC L TO ACTIVATE GRAPHICS
   111 C = 127:GOSUB 2
   112 C = 0  : GOSUB 2
   120 FOR I=0 TO 127 : C = I : GOSUB 2 :NEXT
   150 C=13:GOSUB 2:C=10:GOSUB 2
   160 NEXT
   1999 END
   3000 FOR Z = 1 TO LEN(Z$) : C=ASC(MID$(Z$,Z,1)): GOSUB 2 : NEXT : RETURN

RUN


[Linked Image from i.imgur.com]

Another thing that was totaly puzzling me was why the LF wasn't working right, it seemed like I had to hit it twice, and then I noticed that it had PORT_TOGGLE set. Man, that was really baffling to me. I guess it pays to read the code 8-)


Code
        PORT_START("FORMFEED")
        PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Form Feed") PORT_CODE(KEYCODE_7_PAD) //PORT_TOGGLE
        PORT_START("LINEFEED")
        PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CODE(KEYCODE_9_PAD) //PORT_TOGGLE

Posted By: Golden Child Re: Ap2000 signs of life - 07/20/20 11:10 AM
I modified the basic program to wait until ACK goes low, printing a dot every time it checks and the high bit is set. It's interesting that when it's printing that the acks doesn't finish right away.

Code
NEW
   1 GOTO 90
   2 POKE PO,C : ? C" ";:X = PEEK(PI) 
   3  IF  X < 128 GOTO 5
   4 ?".";:X=PEEK(PI):GOTO 3
   5 ? : RETURN

    90 C=PEEK(49152+256)   : REM READ FROM C100 TO ACTIVATE AUTOSTROBE
   100 PO = 49152 + 9*16 : PI =  PO+4
   105 FOR J = 1 TO 24
   106 C=64+J : GOSUB 2 : Z$=STR$(J) :GOSUB 3000
   110 C = 27:GOSUB 2 : C = ASC("L") : GOSUB 2
   111 C = 127:GOSUB 2
   112 C = 0  : GOSUB 2
   120 FOR I=0 TO 127 : C = I : GOSUB 2 :NEXT
   150 C=13:GOSUB 2:C=10:GOSUB 2
   160 NEXT
   1999 END
   3000 FOR Z = 1 TO LEN(Z$) : C=ASC(MID$(Z$,Z,1)): GOSUB 2 : NEXT : RETURN

RUN


It sends the 13 and 10 (CR LF)
then ESC L
then num of chars as two bytes

and you can see the dots get very long there, probably very likely to drop chars there if you're not checking the ACK.

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 07/21/20 03:07 PM
I got really aggravated trying to get it to print graphics because it kept dropping characters. So I thought, why not cheat a little and make a little buffer to hold the data.

And so I finally got some graphics to print. It's still glitching here and there, more to solve, but it was really gratifying to finally see something that looks halfway normal.

Some zoom grafix:

[Linked Image from i.imgur.com]

Trying Triple Dump (some glitching):

[Linked Image from i.imgur.com]
Posted By: R. Belmont Re: Ap2000 signs of life - 07/21/20 04:04 PM
Interesting. I would assume Triple Dump actually does watch the handshaking, but maybe not.

The card itself apparently does some clever Woz stuff where it changes the PROM address mapping after STROBE is set until ACK comes in. Will need to investigate further.
Posted By: Golden Child Re: Ap2000 signs of life - 07/21/20 05:58 PM
Yes, it's puzzling because you'd think there would be some kind of flow control.

I saw that my "minibuffer" was getting overrun and that was causing the glitches, so let's boost the size. The buffer has gone from mini to maxi: 8 bytes to 16k and now I said what the heck, 1 meelllion bytes.


Paper Graphics
[Linked Image from i.imgur.com]
Using the 144 vertical dpi (which overprints in multiple passes looks kinda odd) but 72 dpi looks good.

Triple Dump
[Linked Image from i.imgur.com]



Posted By: Golden Child Re: Ap2000 signs of life - 07/21/20 09:14 PM
Thought I'd give it a spin with PrintMaster on the Amiga.

I tried with the cpc6128 and I was able to start Printmaster using the cpm startup disk with typing "|cpm", but it required a thousand disk swaps and it seemed to have trouble handshaking and dropping characters (even with my buffer). Oddly on the 6128, the arrow keys wouldn't work with Printmaster unless I held down the left arrow key and keeping it pressed, pressed the right arrow key.

As far as I can tell, the Amiga does watch the ack and busy lines and won't send any data while the printer isn't ready.

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 07/21/20 11:53 PM
Making calendars with Printmaster:

(I wonder how many people in the world are still using Printmaster and Dot Matrix Printers?)

[Linked Image from i.imgur.com]

While fiddling around with the cpc6128 I did encounter a strange bug. For some reason when running with the cpc6128 some of the ap2000's input ports all of a sudden went from active low to active high. This makes the printer boot up into "Data Dump Mode" because it thinks I'm holding down the Line Feed and Form Feed buttons when it starts. It's really weird that the cpc6128's doing that, because the apple2 and the amiga don't have that problem.

I'm doing a subtarget/sources build, could that be causing a problem?
Posted By: Golden Child Re: Ap2000 signs of life - 07/22/20 03:48 AM
So let's see if the ibm5150 will work with print shop.

Testing the printer gives an error.

[Linked Image from i.imgur.com]

So let's see if we can figure out where it's hanging up.

We'll set an i/o watchpoint with wpi 378,8,r and then when it hits, set al=df (ack is active low) and then printshop will continue.
After doing that we disable the watchpoint.

[Linked Image from i.imgur.com]

This diagram from art of asm shows the status register.

So going into src/devices/machine/pc_lpt.cpp and adding an xor on STATUS_ACK seems to fix the error message.
Code
int8_t pc_lpt_device::status_r()
{
        return m_cent_status_in->read() ^ STATUS_BUSY ^ STATUS_ACK;
}



[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 08/05/20 10:46 PM
Just for fun, I thought I'd play with svgedit and inkscape to see if I could make something that looks like the control panel.

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 08/11/20 02:38 AM
More silly fun:

I was thinking about having the printer make some noise while it was printing and I was able to get it to squawk a little.


[video:youtube]https://youtu.be/nXu1cxIHsZc[/video]

I think my "pin-firing" detection is missing half of the pin firings so it's pretty quiet when printing some areas.
Posted By: Golden Child Re: Ap2000 signs of life - 08/14/20 09:41 AM
So I wanted to see what kind of waveforms were being generated by mame audio. With ubuntu, I had to use pavucontrol to select the monitor of Built-in audio to get the system-generated sound for Audacity to record.

[Linked Image from i.imgur.com]



I did discover something interesting, that the 1-bit DAC was generating a signal when it wasn't actually doing anything. I suppose this is correct behavior, but it does answer why I am always hearing pops and crackles. When there's an audio dropout, the waveform drops to zero and there's a "click" sound.


The dac corresponds to this code:
Code

   /* audio hardware */
        SPEAKER(config, "speaker").front_center();
        DAC_1BIT(config, "dac", 0).add_route(ALL_OUTPUTS, "speaker", 0.25);
        voltage_regulator_device &vref(VOLTAGE_REGULATOR(config, "vref"));
        vref.add_route(0, "dac", 1.0, DAC_VREF_POS_INPUT);





Lowering the volume slider to zero for the 1 bit DAC makes the clicking disappear and the VU meters go down to no signal.

[Linked Image from i.imgur.com]

[Linked Image from i.imgur.com]


If you look at the recorded waveform, there's no actual sound being played, there's just a bunch of "dropouts" where other tasks are grabbing the cpu (probably because I'm doing a bunch of printf's)

Audacity's monitor shows -46 db on the VU meter.

[Linked Image from i.imgur.com]


It's interesting when I have the mockingboard enabled as there are multiple outputs which can contribute to the clicking.
If you change the volume on the different channel volumes, the biasing can constructively and destructively interfere and audacity's VU meters will go up and down.
Posted By: Just Desserts Re: Ap2000 signs of life - 08/14/20 09:51 AM
Why not just use -wavwrite
Posted By: R. Belmont Re: Ap2000 signs of life - 08/14/20 01:44 PM
The speaker click device the A2 uses simulates capacitive coupling because otherwise it was impossible to mix its output with a Mockingboard AY-3 or the GS's ES5503. After all, the definition of a speaker click device is that the voltage is either 0 or 5 volts, nothing in between.

Can we get back to what exactly made the AP2000 work? It was the NMI-at-startup and then something with the ADCs?
Posted By: Golden Child Re: Ap2000 signs of life - 08/14/20 02:41 PM
Ok, sorry I tend to go off on tangents. 8-)

I think that the NMI would be fixed if it didn't hit right as it starts up, maybe delayed by a little bit.


I found the ADC conversion wasn't timing correctly.

Making some crap macros to help me see how many cycles and how much time ran in between.

Code

#define LASTPASSDIFFERENCE(t, name, func, str) \
  static t staticlast##name; \
  t last##name = staticlast##name; \
  t diff##name; \
  t cur##name = func; \
  diff##name = cur##name - staticlast##name;  diff##name=diff##name;\
  printf(#name": "); \
  printf(str "\n",cur##name-last##name);\
  printf("\n");\
  staticlast##name = cur##name;

#define LASTPASSPRINT(name, str, item) \
  printf(str "\n",item##name);




so I could do

Code
LASTPASSDIFFERENCE(long int, ADCONVSCANEACH_CYCLES, total_cycles(), "T cycles = %ld   expected to see 192");
LASTPASSDIFFERENCE(double,  ADCONVSCAN_TIME,   machine().time().as_double(), "time = %e");
LASTPASSDIFFERENCE(long int, ADCONVSCAN_CYCLES, total_cycles(), "T cycles = %ld   expected to see 768");

LASTPASSDIFFERENCE(double,   ADCONVSCAN_TIME,   machine().time().as_double(), "time = %e");
LASTPASSDIFFERENCE(long int, ADCONVSCAN_CYCLES, total_cycles(), "T cycles = %ld   expected to see 768");
//printf("m_adcnt = %d\n",m_adcnt);
//LASTPASSPRINT(ADCONVSCAN_CYCLES, "T last = %ld", last);
//LASTPASSPRINT(ADCONVSCAN_CYCLES, "T cur = %ld", cur);
//LASTPASSPRINT(ADCONVSCAN_CYCLES, "T diff = %ld", diff);




so now I get something that looks pretty good and it fixes the super fast beeping when you press a control panel button.


Code
ADCONVSCANEACH_CYCLES: T cycles = 190   expected to see 192

ADCONVSCANEACH_CYCLES: T cycles = 195   expected to see 192

ADCONVSCANEACH_CYCLES: T cycles = 194   expected to see 192

ADCONVSCANEACH_CYCLES: T cycles = 190   expected to see 192

ADCONVSCANEACH_CYCLES: T cycles = 188   expected to see 192



I'll try to work up a patch, it doesn't change very much in the code.
Posted By: R. Belmont Re: Ap2000 signs of life - 08/14/20 03:38 PM
Ok, that's useful, thanks!

AJR, any thoughts on the ADC timing GC observed?
Posted By: AJR Re: Ap2000 signs of life - 08/14/20 04:31 PM
I'm not AWJ, but I'll add a few thoughts anyway.

If this really is a problem with inexact timing, then that exemplifies a common problem with MAME's MCU cores, many of which just execute each instruction all at once and then go back and run the timers and timer-based peripherals for the same number of cycles. This works fine for purely internal interrupt timers but often fails for more sensitive cases such as serial ports.

In the past, Vas Crabb has suggested "separate icount and bcount" as the one proper solution to this problem, but much like the modern floppy system (which at least does have some readable technical documentation), only Olivier Galibert seems to have fully mastered its implementation details. While I only half-understand how it works, I'm not convinced of its effectiveness as a solution, especially after finding that Olivier Galibert's MCS-96 core, despite having this thing called "bcount" (not defined in MAME's execution core), triggers high-speed outputs at the wrong times.
Posted By: Golden Child Re: Ap2000 signs of life - 08/14/20 08:02 PM
Oh, I don't think it needs to be exactly 192 T-states, (the upd7810 has 3 clock cycles to a T-state I think) it just has to be around that. The timing doesn't need to be anywhere that exact. Once it does 4 analog measurements (4 * 192) it should be around 768 T states before it will fire an INTAD interrupt.
Posted By: Golden Child Re: Ap2000 signs of life - 08/15/20 12:44 AM
Ok, I looked at it again, and the original code doesn't seem to have timing problems. I possibly (probably) screwed up the code while I was doing some experiments and trying to figure out what it actually does. (and then thought it was the original code)


I made a pull request for a few things on the upd7810 and the ap2000, if it's horrible let me know.

The NMI problem is still there, but the ap2000 controls seem to be working with just minor changes. It starts up in the "offline" mode so if you hit keypad 0 it will put it online.

Posted By: Golden Child Re: Ap2000 signs of life - 08/15/20 11:30 AM
I fiddled and fiddled and couldn't get the ap2000 to go past the initialization. It was totally baffling. I put in delays and delays and hit the NMI multiple times.

Then I read the datasheet over and over again and I got a clue:

[Linked Image from i.imgur.com]

It says that you can sample the NMI input by using SKIT and SKNIT.

So it hits the SKIT NMI at $011E and never skips past the JMP $0000.

Code
010A: 48 48       SKIT    FAD
010C: 48 48       SKIT    FAD
010E: FD          JR      $010C
010F: 53          DCR     C
0110: FB          JR      $010C
0111: 4C E1       MOV     A,CR1
0113: 74 4A 02    ONI     B,$02
0116: C5          JR      $011C
0117: 37 CA       LTI     A,$CA
0119: 6A FD       MVI     B,$FD
011B: E8          JR      $0104
011C: 37 CA       LTI     A,$CA
011E: 48 40       SKIT    NMI
0120: 54 00 00    JMP     $0000


Code
--- a/src/devices/cpu/upd7810/upd7810_opcodes.cpp
+++ b/src/devices/cpu/upd7810/upd7810_opcodes.cpp
@@ -343,7 +343,7 @@ void upd7810_device::DIV_C()
 /* 48 40: 0100 1000 0100 0000 */
 void upd7810_device::SKIT_NMI()
 {
-       if (IRR & INTNMI)
+       if (IRR & INTNMI || m_nmi)
                PSW |= SK;
        IRR &= ~INTNMI;
 }
@@ -487,7 +487,7 @@ void upd7810_device::SKIT_SB()
 /* 48 60: 0100 1000 0110 0000 */
 void upd7810_device::SKNIT_NMI()
 {
-       if (0 == (IRR & INTNMI))
+       if (0 == (IRR & INTNMI) || !m_nmi)
                PSW |= SK;
        IRR &= ~INTNMI;
 }


So I think that would be right, setting the skip flag if m_nmi is set for SKIT_NMI and if m_nmi is not set.

This gets it past this spot so it will start up.
Posted By: AJR Re: Ap2000 signs of life - 08/15/20 05:16 PM
That datasheet is a bit misleading. As a later manual explains, SKIT NMI and SKNIT NMI do not actually test INTFNMI (which makes sense since the flip-flop is cleared as soon as a NMI is taken and a NMI must always be taken), only the actual level of the NMI pin.
Posted By: Golden Child Re: Ap2000 signs of life - 08/15/20 06:56 PM

Hi AJR,

Yes, I think I understand now exactly what that means. The subtle distinctions make all the difference. Thanks for fixing this.


With my latest changes the ap2000 should start up properly and go "on-line" without having to manually hit the "on-line button".




It still drops characters though, do you guys have any objections to having a buffer to hold the incoming overflow characters until it's figured out?
Posted By: R. Belmont Re: Ap2000 signs of life - 08/15/20 08:31 PM
If it's all working now I'd like to look at the A2 parallel cards again and see if I have the handshake wrong or something.
Posted By: Golden Child Re: Ap2000 signs of life - 08/15/20 09:10 PM
Hi RB, I think it pretty much works now except for dropping chars if my latest commit is added.
Posted By: R. Belmont Re: Ap2000 signs of life - 08/15/20 10:20 PM
Yeah, I just saw that commit go in, great!
Posted By: Golden Child Re: Ap2000 signs of life - 08/16/20 11:22 AM

Throwing in a buffer in between gets us Reggie!


Code
 
 WRITE_LINE_MEMBER( e05a30_device::centronics_input_strobe )
 {

        // using a buffer to hold the incoming data when printer can't keep up.
        // This is obviously not correct, but until the answer is found,
        // allows the ap2000 to function without dropping characters.

//     if (m_centronics_strobe == true && state == false && !m_centronics_busy) {
       if (m_centronics_strobe == true && state == false) {

           if (m_centronics_data_latched) { // will lose data, so put into buffer
               minibuffer[minibufferhead] = m_centronics_data;
               minibufferhead ++;
               minibufferhead %= minibuffersize;
           }
           else {
               m_centronics_data_latch   = m_centronics_data;
 
                m_centronics_data_latched = true;
                m_centronics_busy         = true;
                m_write_centronics_busy(m_centronics_busy);
            }
        }
 
        m_centronics_strobe = state;
@@ -203,6 +219,15 @@ uint8_t e05a30_device::read(offs_t offset)
        case 0x03:
                result = m_centronics_data_latch;
                m_centronics_data_latched = false;
+
+               if (minibufferhead != minibuffertail) {
+                       m_centronics_data_latch   = minibuffer[minibuffertail++];
+                       minibuffertail %= minibuffersize;
+                       m_centronics_data_latched = true;
+                       m_centronics_busy         = true;
+                       m_write_centronics_busy(m_centronics_busy);
+                }
+
                break;
        case 0x04:
                result |= m_centronics_busy << 0;
diff --git a/src/devices/machine/e05a30.h b/src/devices/machine/e05a30.h
index 5dfb51ac81c..d7220c4bc89 100644
--- a/src/devices/machine/e05a30.h
+++ b/src/devices/machine/e05a30.h
@@ -76,6 +76,11 @@ private:
        uint8_t m_centronics_strobe;
        uint8_t m_centronics_data_latch;
        uint8_t m_centronics_data_latched;
+
+       static const int minibuffersize=1e6;  // temporary fix for dropping characters
+       int minibuffer[minibuffersize];
+       int minibufferhead;
+       int minibuffertail;
 };
 
 DECLARE_DEVICE_TYPE(E05A30, e05a30_device)




[Linked Image from i.imgur.com]

Playing with Amiga graphic dump:

[Linked Image from i.imgur.com]

Interesting that the a2 PIC Parallel firmware seems to be slightly better than the Centronics in that you don't get it sending 9E and 1D to the printer (hardcoded in the firmware for switching a Centronics Microprinter into 40 and 80 column mode).

Appleworks apple+H screen dump:

[Linked Image from i.imgur.com]
Posted By: R. Belmont Re: Ap2000 signs of life - 08/16/20 12:33 PM
What are your DIP switch settings? I have some idea how to fix it without a buffer, but I can't get any program (including Triple-Dump) to print much of anything.
Posted By: Golden Child Re: Ap2000 signs of life - 08/16/20 12:47 PM
Hi RB,

I think it's pretty much the "default" DIP settings I'm using now:

[Linked Image from i.imgur.com]

You can see what the ap2000 actually receives in its buffer by doing this in the debugger:

focus 1 (this selects the ap2000 upd7810 cpu)
ctrl+M
8000 (the internal ap2000 buffer is at $8000)


Here you can see the ap2000 getting 9E and 1D as the first characters when I've got the centronics firmware selected on the PIC.
[Linked Image from i.imgur.com]


quick and dirty: apple 2 ctrl+reset PR#1 then just type a bunch of keys and the printer will print junk:


or another idea (since the control panel keys are working now:)

when you start up mame, hold down the keypad 7 and 9 keys (LF and FF) and that will put the printer into Data Dump Mode where it displays the hex sent. It won't print anything until it gets a line of text, but you can override that by toggling keypad 0 (online/offline) and that will print the last characters sent.
Posted By: Golden Child Re: Ap2000 signs of life - 08/16/20 01:03 PM
I can't remember exactly, but I had a lot of problems getting data to the printer too:

It may even be this line in e05a30.cpp:

if (m_centronics_strobe == true && state == false && !m_centronics_busy) {

if you drop the !m_centronics_busy part, data should definitely be flowing.
Posted By: Golden Child Re: Ap2000 signs of life - 08/22/20 04:37 AM
Just for fun, I thought I'd try to hook up a rom for the Apple II Epson APL interface card using the Apple2 PIC as a model. I was able to get it working with an interesting issue. It has some really strange code that wants to read $c1c1. My workaround was to see if it had just read from that address, and if so, return 0.


so the slot number is in x so it ors with $c0, making it $c1, stores it in $01. Then stores $c1 into $00.

Then it keeps reading $c1c1 until it doesn't have the high bit set. I think this could be patched to check the busy address of the Apple2 PIC.

Code
C990: 48       pha
C991: 8A       txa
C992: 09 C0    ora #$c0
C994: 85 01    sta $01
C996: A9 C1    lda #$c1
C998: 85 00    sta $00
C99A: A0 00    ldy #$00
C99C: B1 00    lda ($00), y
C99E: 30 FC    bmi $c99c
C9A0: 8A       txa
C9A1: 0A       asl a
C9A2: 0A       asl a
C9A3: 0A       asl a
C9A4: 0A       asl a
C9A5: A8       tay
C9A6: 68       pla
C9A7: 99 80 C0 sta $c080, y
C9AA: 28       plp
C9AB: 60       rts



Otherwise, it seems to work ok, it doesn't pass 8 bits through, just 7 bits. That probably explains why Triple-Dump has such short graphical sequences, as it only sends 127 bytes of graphics data at a time so you see it doing little horizontal strips instead of a whole line at a time. It's actually super good for use with Apple II basic as it ends up stripping the high bit out.

Strangely, the CTRL+I codes don't match up with another Epson interface card manual. Anyone have an Epson APL card manual?

I can only really use CTRL+I G to do hi-res graphic dumps. So for example: CTRL+I G D I 2 space will do a graphic dump at double density, inverse and do page 2.

Also CTRL+Q by itself will dump the hi-res screen (just like the Silentype.)

Code
   100 HGR : HCOLOR = 3
   110 HPLOT 0,0 TO 279,0 : HPLOT 279,0 TO 279,191 : HPLOT 279,191 TO 0,0 : HPLOT 0,0 TO 0,191
   120 HPLOT 0,191 TO 279,191 : HPLOT 0,191 TO 279,0
   130 DATA "B","SIDE BY SIDE"
   140 DATA "A","AND PAGE 1+2"
   150 DATA "O","OR PAGE 1+2"
   160 DATA "H","XOR PAGE 1+2"
   170 DATA "I","INVERSE"
   180 DATA "E","DOUBLE SIZE"
   190 DATA "D","DOUBLE DENSITY"
   200 DATA "L","LAST LINE?"
   210 DATA "2","PAGE 2"
   220 DATA "END","END"
   300 READ A$,B$
   305 IF A$="END" THEN GOTO 400
   290 PR #1
   310 PRINT "CTRL+I G ";B$:PRINT CHR$(9)"G"A$
   320 GOTO 300

   399 REM CTRL+I G L WILL PRINT THE GFX SCREEN LINES THAT THE TEXT CURSOR IS ON
   400 ? CHR$(27)"A"CHR$(8):FOR I=0 TO 23:POKE 37,I:? CHR$(9)"GL ";:? CHR$(27)"A"CHR$(8):NEXT


[Linked Image from i.imgur.com]

Here's gfx page 1 and 2 side by side,
then gfx page 1 AND gfx page 2,
then gfx page 1 OR gfx page 2:

[Linked Image from i.imgur.com]

Seems to work ok with Triple Dump:
(discovered that the Epson FX-80 driver in Triple Dump is buggy and needed to use "Triple Dump (Beagle Bros. - 1984-10-22update).dsk" to do 80/72/90 dpi modes.)
[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 08/22/20 06:01 PM
I was able to get the Epson APL to work, why not try a Grappler Plus Parallel Interface rom that's 4K.

After not getting the bank switching right, I finally got it!

And now I can do rotated graphics with CTRL+I G R <CR>. Yay!

[Linked Image from i.imgur.com]

With the Grappler Plus, you can use an asterisk to set the Epson graphics mode from 1 to 6 so you can do 80/72/90 dpi as well as 60/120/240.

CTRL+I G * 4 <CR> will do 80 dpi.

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 09/06/20 09:23 AM

I was thinking about how it'd be interesting to write a "printer" simulator in lua so I could render various printer outputs that have different ESC codes... like Imagewriter ESC codes, 'cuz I'm dying to print dot matrix output in color.

I made a luaprinter class and I've got it so it can render to a bitmap.

Just a proof of concept.

Code
class luaprinter {

public:
        luaprinter(){};

        const static int BUFFERSIZE = 128000;  // a nice big size so we shouldn't have to worry
        int m_printerbuffer[BUFFERSIZE];
        int m_head = 0;
        int m_tail = 0;
        bitmap_rgb32 *m_bitmap;  // pointer to bitmap
        int m_xpos = 0;
        int m_ypos = 0;

        virtual void clearpage(){ m_bitmap->fill(0);};
        virtual void drawpixel(int x, int y, int pixelval){m_bitmap->pix32(y,x) = pixelval; };  // row major
        virtual int getpixel(int x, int y){return m_bitmap->pix32(y,x);};
        virtual void setheadpos(int x, int y){m_xpos=x;m_ypos=y;};
        virtual void savepage(){};
        virtual std::tuple<int*,int,int>  getbuffer() { return std::make_tuple(m_printerbuffer,m_head,m_tail);};   // returns the entire buffer as an integer a>
        virtual int getnextchar(){if (m_head==m_tail) return -1; else { int retval = m_printerbuffer[m_tail++]; m_tail %= BUFFERSIZE; return retval;}};
        virtual void putnextchar(int c){m_printerbuffer[m_head++]=c; m_head %= BUFFERSIZE;};
        void register_bitmap(bitmap_rgb32 &mybitmap){m_bitmap = &mybitmap;}  //
        void  testmodifybuffer(){ for (int i=0;i<10;i++){  m_printerbuffer[i]=i; m_head++;  };  };
        std::tuple<int,int>getheadpos() { return std::make_tuple(m_xpos,m_ypos); };

        static std::vector<luaprinter *> luaprinterlist;
};


and then hack on centronics/printer.cpp to inherit from luaprinter, and do a little bit of hookups in luaengine.

Code
        auto luaprinter_type = sol().registry().create_simple_usertype<luaprinter>("new", sol::no_constructor);
        luaprinter_type.set("clearpage", &luaprinter::clearpage);
        luaprinter_type.set("drawpixel", &luaprinter::drawpixel);
        luaprinter_type.set("getpixel", &luaprinter::getpixel);
        luaprinter_type.set("setheadpos", &luaprinter::setheadpos);
        luaprinter_type.set("savepage", &luaprinter::savepage);
        luaprinter_type.set("getbuffer", &luaprinter::getbuffer);
        luaprinter_type.set("getnextchar", &luaprinter::getnextchar);
        luaprinter_type.set("getheadpos", &luaprinter::getheadpos);
        sol().registry().set_usertype("luaprinter", luaprinter_type);

        machine_type.set("luaprinters", sol::property([this](running_machine &m) {
                        sol::table table = sol().create_table();
                        int i=0;
                        for(luaprinter* p : luaprinter::luaprinterlist)
                        {
                                table[i++] = &(*p);
                        };
                        return table;
                }));



I haven't worked it all out yet and I'm figuring out all this cpp stuff (and sometimes not figuring it out 8-) but I did get it to draw on my bitmap:
Code
for i=0,255 do for p=0,7 do 
if (2^p) & i ~= 0 then 
   manager:machine().luaprinters[0]:drawpixel(i,20+p,0) 
   manager:machine().luaprinters[0]:setheadpos(i,20) 
end end end

[Linked Image from i.imgur.com]

And it wouldn't be hard at all to do color:
[Linked Image from i.imgur.com]
Code
function iff(a,b,c) if a~=0 then return b else return c end end
for i=0,255 do 
for p=0,7 do 
if (2^p) & i ~= 0 then 
   manager:machine().luaprinters[0]:drawpixel(i,20+p,iff((2^1)&p,0xff0000,0)|iff((2^2)&p,0xff00,0)|iff((2^3)&p,0xff,0)) 
   manager:machine().luaprinters[0]:setheadpos(i,20) 
end end end
Posted By: Golden Child Re: Ap2000 signs of life - 09/07/20 04:14 AM
I was able to get my luaprinter to "print" something from Zoom Graphics pretending to be an Apple DMP:
[Linked Image from i.imgur.com]


And the lua code looks like this:

Code
function asc(c) return string.byte(c) end

function getnnnn()
  local i local retval=0 for i=3,0,-1 do ch=coroutine.yield() if ch >= asc('0') and ch <= asc('9') then retval = retval + (ch-asc('0'))*10^(i) end end return retval end

function getn(n)
  local i local retval=0 for i=n-1,0,-1 do ch=coroutine.yield() if ch >= asc('0') and ch <= asc('9') then retval = retval + (ch-asc('0'))*10^(i) end end return retval end

function renderhead(v) for i=0,7 do if (v & (2^i))~=0 then lp0:drawpixel(xpos,ypos+i,0) end end end

function dogfx() ch=coroutine.yield() renderhead(ch) xpos=xpos+1 lp0:setheadpos(xpos,ypos) end

function renderprt(ch) 
local xdpi,ydpi,feed,lfdir
xdpi = 144
ydpi = 72
feed=144/8
xpos=0
ypos=0
while 1 do 
ch = coroutine.yield() 
--print ("renderprt: "..ch.." "..string.char(ch)) 
if ch == 27 then
  ch = coroutine.yield()
  if ch == asc('n') then dpi=72
  elseif ch == asc('N') then xdpi=80
  elseif ch == asc('E') then xdpi=96
  elseif ch == asc('p') then xdpi=144
  elseif ch == asc('P') then xdpi=160
  elseif ch == asc('e') then xdpi=107
  elseif ch == asc('q') then xdpi=120
  elseif ch == asc('Q') then xdpi=136
  elseif ch == asc('f') then lfdir=1
  elseif ch == asc('r') then lfdir=-1
  elseif ch == asc('L') then lm=getn(3)
  elseif ch == asc('>') then bidir=0
  elseif ch == asc('<') then bidir=1
  elseif ch == asc('A') then feed=144/6  -- 24
  elseif ch == asc('B') then feed=144/8  -- 18
  elseif ch == asc('T') then feed=getn(2)
  elseif ch == asc('G') then nchars=getn(4)   for i=1,nchars do dogfx() end
  elseif ch == asc('S') then nchars=getn(4)   for i=1,nchars do dogfx() end
  elseif ch == asc('g') then nchars=getn(3)*8 for i=1,nchars do dogfx() end
  elseif ch == asc('V') then nchars=getn(4)   
                             ch=coroutine.yield() for i=1,nchars do renderhead(ch) end
  elseif ch == asc('F') then xpos = getn(4)
  elseif ch == asc('V') then -- set tof
  elseif ch == asc('O') then -- paper detect off
  elseif ch == asc('o') then -- paper detect on
  elseif ch == asc('!') then -- start bold
  elseif ch == asc('"') then -- end bold
  elseif ch == asc('X') then -- start underline
  elseif ch == asc('Y') then -- end underline
  else -- gobble char
  end
elseif ch == 13 then xpos = 0    -- cr
elseif ch == 10 then ypos = ypos + feed/144*ydpi xpos = 0  -- lf
elseif ch == 12 then  -- formfeed
end
end 
end

corenderprt = coroutine.create(renderprt)
coroutine.resume(corenderprt)

lp0 = manager:machine().luaprinters[0]

function feedchars(ch)
repeat
nextchar = lp0:getnextchar()
if nextchar >= 0 then coroutine.resume(corenderprt,nextchar) end
until nextchar < 0
end

function framedispatch() for i,j in pairs(dispatchlist) do j() end end
emu.register_frame(framedispatch)
dispatchlist={feedchars}



Printing from the NewsRoom demo:

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 09/08/20 01:34 AM
I thought, let's see if we can print color so I made some modifications to do color.

I looked high and low for a program that would print in color on the Apple II and I was able to get my luaprinter to print in color with Printographer. You can choose which Apple II hi-res colors match with specific color ribbons. Ribbon 1 being Yellow, 2 Magenta and 3 Cyan.


[Linked Image from i.imgur.com]

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 09/10/20 08:46 AM
I made a luaprinter for both centronics and rs232 and was having some trouble sorting out why it was dropping characters for the serial port.

Still sorting it out, gonna try a mutex, but I thought why not try to "replay" a print job to the lua printer.

It's pretty easy, just put chars into the buffer with putnextchar(). First I had to add putnextchar to luaengine which was trivial.

Code
        luaprinter_type.set("getnextchar", &luaprinter::getnextchar);
        luaprinter_type.set("putnextchar", &luaprinter::putnextchar);



I made a printout with the regular serial printer, and -printout test.txt to send it to a file.

Then did this from the console:
Code
dofile("../../luaprinter.lua")
f = io.open("test.txt")
filedata = f:read("*a")
print(#filedata)
for i=1,#filedata do lp0:putnextchar(string.byte(filedata,i)) end


and to "print" it again, this time with a different xdpi for instance:

Code

xpos=0 ypos=0 lp0:clearpage() paperxdpi=72 for i=1,#filedata do lp0:putnextchar(string.byte(filedata,i)) end



Of course this is only going to work if it fits entirely into the buffer.

[Linked Image from i.imgur.com]

Posted By: rfka01 Re: Ap2000 signs of life - 09/10/20 01:19 PM
That's really neat stuff you're coaxing the system into doing ... major thumbs up!
Robert
Posted By: Golden Child Re: Ap2000 signs of life - 09/10/20 04:39 PM
Thanks Robert!



I figured out what was wrong with my serial luaprinter, it was that I used a char variable instead of a u8 and it was converting 128-255 into a negative number. (That's what I get for growing up with Pascal CHAR types 8-) It's got to be unsigned char.

Code
void serial_luaprinter_device::rcv_complete()
{
        receive_register_extract();
        u8 recchar = get_received_char();
        m_printer->output(recchar);
        putnextchar(recchar);
}



so now the Amiga ImagewriterII driver can do this:

[Linked Image from i.imgur.com]

Oddly, printing out of the serial port seems faster than out of the parallel port.
Posted By: Golden Child Re: Ap2000 signs of life - 09/11/20 08:33 AM
Managed to get DOS Instant Artist printing, seemed to get hung up on some of the lpt status bits, specifically the paper out bit, so ^ 0x20 seemed to fix it.


[Linked Image from i.imgur.com]
Posted By: R. Belmont Re: Ap2000 signs of life - 09/11/20 12:18 PM
That's cool. The IW2 was serial only though, so I'm not quite understanding the LPT aspect smile Also, I had no idea the IW2 was supported by software on non-Apple systems.
Posted By: Vas Crabb Re: Ap2000 signs of life - 09/11/20 03:03 PM
ImageWriter II is well-supported on Windows at least until Windows XP. You can get a Bitronics-RS422 bridge to use it on an LPT port if you really want to. "Standard" Windows printer drivers assume that the same high-level byte-oriented protocol can be used to communicate with a printer whether it's on a parallel port (Bitronics or ECP), serial, or a TCP socket connection. You can thank HP for pioneering the nybble-oriented Bitronics back-channel, and their dumb print server modules that just exposed that to a TCP socket.
Posted By: Golden Child Re: Ap2000 signs of life - 09/11/20 03:39 PM
Since most printers are byte-oriented, perhaps we could have a parallel to serial converter and a serial to parallel converter.

Then you could use the ap2000 on a system that only supports serial, for example.

I made a serial luaprinter and added it to nano src/devices/bus/isa/com.cpp so you can do this:

(I did a MODE COM2:9600,N,8,1 before launching instant artist just for good measure)

[Linked Image from i.imgur.com]

[Linked Image from i.imgur.com]



I was going to see if I could get the coco3 to do the luaprinter (maybe getting a CGP-220 driver going) but it freezes up on a PRINT #-2. Also there's some strange double screen action going on.

[Linked Image from i.imgur.com]
[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 09/11/20 06:34 PM
I changed the baud rate of the serial printer to 2400 in the source code and could get bytes from the c64 but only on the user port channel 2.

Printers are supposed to be on channel 4 or 5 on the c64 iec bus, however there aren't any iec drivers that work, there's vic1515 but it's just a skeleton.

I was really keen on trying to get an okimate 20 print going, since its graphics commands are pretty simple and I had always wanted an oki.

I can get the user port to connect and send bytes.

[Linked Image from i.imgur.com]

[Linked Image from i.imgur.com]

But the c64 wants printers on 4...

[Linked Image from i.imgur.com]

I did find an okimate 20 apple2 disc on archive but it was in a2r format.
Posted By: Golden Child Re: Ap2000 signs of life - 09/13/20 03:46 AM
I found an article that mentioned printer drivers for Atari ST Degas and it has a bunch of different drivers for different dot matrix printers.

Hacking on a lua script made it output something recognizable for an Okimate 20.

Consulting the document "MCS-820_Printer_Handbook_(aka_Okimate_20).pdf" was indispensable.

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 09/13/20 02:26 PM
So let's see if we can get windows 3.1 to print something.

After some fits and starts, win 3.1 installed with "SETUP /I" which disables the hardware detection.

And the ap2000 works with the Epson FX-80 driver. Cool!

[Linked Image from i.imgur.com]

and I tried the luaprinter with the c-itoh 8510 driver as I couldn't find an imagewriter II driver anywhere for windows 3.1. Unfortunately the 8510 driver doesn't do color.

[Linked Image from i.imgur.com]

Interestingly, it complained about paper being out for the luaprinter but not the ap2000, so I did the ^0x20 to the status just to get it to work.
Posted By: Golden Child Re: Ap2000 signs of life - 09/13/20 04:06 PM
Just for fun, I added a buffer indicator to the ap2000. The buffer size is shown by the little green bars in the upper left of the printout. Each bar represents a hex digit of the size. It's kinda fun to watch the bars grow and shrink as the buffer fills and clears.

It's also a good indicator of whether the system is properly respecting the busy/ack signals as it will never use the buffer if so.

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 09/14/20 01:07 PM
Adding output_perror(0) seems to fix the paper out problems:

Code
void centronics_luaprinter_device::device_reset()
{
        printf("DEVICE RESET CALLED\n");
        m_busy = false;
        output_busy(m_busy);
        output_fault(1);
        output_ack(1);
        output_ack(0);
        output_select(1);
        output_perror(0); // added paper out
}


So let's see if Geos 2.0 will print something:

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 09/14/20 04:10 PM

And if win3.1 works, why not try win 95?

(installing from floppies and using the file manager is so tedious! but it works!)

Luaprinter:

[Linked Image from i.imgur.com]

Ap2000:

[Linked Image from i.imgur.com]
Posted By: R. Belmont Re: Ap2000 signs of life - 09/14/20 06:03 PM
Neat.
Posted By: Golden Child Re: Ap2000 signs of life - 09/15/20 11:14 PM
Thanks, RB!

I think I've got the saving the printed page nearly figured out. Here's some samples from apple II printographer printing to the Apple Scribe.

(The colors don't quite match up to the apple's color palette)

Printographer wants violet to be ribbons 2+3 but that makes it dark purple, just ribbon 2 (magenta) makes a good purple.

Apple from Zoom Graphics Disk:

[Linked Image from i.imgur.com]
[Linked Image from i.imgur.com]

Olympics from Joe Drish pictures:

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 09/16/20 03:36 PM
I was trying to clean up my code and put some things into the luaprinter constructor so they would be done automatically done, but it seems to make it not work. So strange. And printfs in the constructor don't appear until I exit mame.


The printfs that make "Scooby 8510" and "Scooby 8511" don't appear until exiting mame, yet the initvalue gets set properly to 3333.

But if I move routines into the constructor all sorts of weird things happen. So I'll leave it outside for now since I've been fiddling with this for a day...gcc problems on Ubuntu?


Code
luaprinter(device_t & thisdevice, int testvalue){ 
        m_lp_mydevice = &thisdevice; 
        time(&m_lp_session_time);  
        initvalue = testvalue;
        printf("\n\nInit Luaprinter Scooby %d\n",testvalue);
        initvalue = 33333;
        };




Code
[MAME]> lp = manager:machine().printers for i=1,#lp do print( lp[i]:getprintername(), #lp, lp[i]:getinitvalue(), lp[i]:simplename()) end
2020-09-16 08-25-19 apple2p-sl1-parallel-pic_ctx-luaprinter	3	33333	apple2p a2bus_slot a2pic centronics centronics_luaprinter centronics
2020-09-16 08-25-19 apple2p-sl2-ssc-ssc_rs232-luaprinter	3	33333	apple2p a2bus_slot a2ssc rs232 serial_luaprinter rs232
2020-09-16 08-25-19 apple2p-sl4-parallel-pic_ctx-ap2000	3	33333	apple2p a2bus_slot a2pic centronics ap2000 centronics


(exit mame here)

[MAME]> 

Init Luaprinter Scooby 8510

Init Luaprinter Scooby 8511

Init Luaprinter Scooby 810
Average speed: 100.00% (31 seconds)
sdl_kill: closing audio
Enter sdlwindow_exit
Leave sdlwindow_exit


after putting code in the constructor I get strange behavior:

Code
[MAME]> print( manager:machine().luaprinters[1]:getprintername(), #manager:machine().luaprinters)
error: 	std::bad_alloc
[MAME]> print( #manager:machine().luaprinters)
56
Posted By: Lord Nightmare Re: Ap2000 signs of life - 09/16/20 07:06 PM
Does the lua interface allow you to force fflush on stdout and stderr? I know there's some really bizarre issues in mingw/msys2 with stderr not fflush()ing itself instantly (like it does on POSIX systems) on windows.

LN
Posted By: Golden Child Re: Ap2000 signs of life - 09/16/20 08:32 PM
Hi LN,

Yes, fflush(stdout); does the trick. Thanks.

so I'm just curious now why there's so many printf's when I should only have 3 luaprinter devices
Code
luaprinter::luaprinter(device_t& thisdevice, int testvalue){ 
	m_lp_mydevice = &thisdevice; 
	time(&m_lp_session_time);  
	initvalue = testvalue;
	printf("yes you can");        // putting in a printf here
	fflush(stdout);
	
	};


Code
 ./mame64 apple2p  -sl1 parallel -sl1:parallel:pic_ctx luaprinter -flop1 ../../printographer.dsk -sl2 ssc -sl2:ssc:ssc_rs232 luaprinter -sl4 parallel -sl4:parallel:pic_ctx ap2000 -verbose

yes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canyes you canAttempting load of mame.ini
...

    _/      _/    _/_/    _/      _/  _/_/_/_/
   _/_/  _/_/  _/    _/  _/_/  _/_/  _/       
  _/  _/  _/  _/_/_/_/  _/  _/  _/  _/_/_/    
 _/      _/  _/    _/  _/      _/  _/         
_/      _/  _/    _/  _/      _/  _/_/_/_/    

mame 0.224	
Copyright (C) Nicola Salmoria and the MAME team

Lua 5.3	
Copyright (C) Lua.org, PUC-Rio

...
yes you canyes you canyes you canAttempting load of raster.ini
Attempting load of source/apple2.ini
Attempting load of apple2.ini
Attempting load of apple2p.ini
yes you canyes you canyes you canAvailable videodrivers: x11 wayland dummy 
Posted By: Golden Child Re: Ap2000 signs of life - 09/16/20 09:11 PM
So my concept is to use the luaprinter class to provide a way to save the bitmap from a driver that doesn't really need the lua parts, just the printing parts. The lua stuff is there, but the driver doesn't need to use them.


So we can inheirit from luaprinter:

Code
class epson_lx810l_device :
public device_t, 
public device_centronics_peripheral_interface, 
public luaprinter
{
...

epson_lx810l_device::epson_lx810l_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
        device_t(mconfig, type, tag, owner, clock),
        device_centronics_peripheral_interface(mconfig, *this),
        luaprinter(*this, 810),
... 


and then we can do some things in the device_start:

Code
void epson_lx810l_device::device_start()
{
	m_online_led.resolve();

	m_cr_timer = timer_alloc(TIMER_CR);

	m_screen->register_screen_bitmap(m_bitmap);
	m_bitmap.fill(0xffffff); /* Start with a clean white piece of paper */


// do the luaprinter stuff, I would like to do more in the constructor, but it seems to cause problems.

	register_bitmap(m_bitmap);  // register with luaprinter
	luaprinterlist.emplace_back(static_cast<luaprinter *>(this));
	setprintername(sessiontime()+std::string(" ")+tagname());




and then you can save the bitmap with:

MAME]> print(manager:machine().lp[3]:pageheight())
576
[MAME]> print(manager:machine().lp[3]:pagewidth())
1024
[MAME]> manager:machine().lp[3]:savepage()
[MAME]> print(manager:machine().lp[3]:getprintername())
2020-09-16 13-53-53 apple2p-sl4-parallel-pic_ctx-ap2000
[MAME]>

So here's the page saved out:
[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 09/16/20 09:30 PM
and the luaprinter code is actually pretty short:

Code

#ifndef MAME_LUAPRINTER_H
#define MAME_LUAPRINTER_H

#pragma once

#include "emu.h"
#include "png.h"
#include "emuopts.h"

class luaprinter {

public:

	int initvalue;
	device_t * m_lp_mydevice;
	luaprinter(device_t & thisdevice, int testvalue);

	static std::vector<luaprinter *> luaprinterlist;

	const static int BUFFERSIZE = 128000;
	std::array<unsigned char, BUFFERSIZE>  m_printerbuffer;
	int m_lp_head = 0;
	int m_lp_tail = 0;
	bitmap_rgb32 *m_lp_bitmap;  // pointer to bitmap
	int m_xpos = 0;
	int m_ypos = 0;
	std::string m_luaprintername;
	int m_page_count;
	static time_t m_lp_session_time;

	void addtolist(luaprinter & myprinter){ luaprinterlist.emplace_back(& myprinter);}
	void setprintername(std::string name){ m_luaprintername = name; }
	std::string getprintername(){ return m_luaprintername; }

	int getinitvalue(){ return initvalue; }

	void clearpage(){ m_lp_bitmap->fill(0xffffff);};
	void drawpixel(int x, int y, int pixelval) { m_lp_bitmap->pix32(y,x) = pixelval; };
	int getpixel(int x, int y){return m_lp_bitmap->pix32(y,x);};
	void setheadpos(int x, int y){m_xpos=x;m_ypos=y;};

	int pagewidth() { return m_lp_bitmap->width(); }
	int pageheight() { return m_lp_bitmap->height(); }

	device_t* getrootdev();
	void savepage();
	
	std::tuple<std::array<unsigned char,BUFFERSIZE>&,int,int>  getbuffer() { return std::make_tuple(std::ref(m_printerbuffer),m_lp_head,m_lp_tail);};   
	int getnextchar();
	void putnextchar(int c);
	void register_bitmap(bitmap_rgb32 &mybitmap){m_lp_bitmap = &mybitmap;}
	std::tuple<int,int>getheadpos() { return std::make_tuple(m_xpos,m_ypos); };
	int count(){ return luaprinterlist.size();}
	std::string fixcolons(std::string in);
	std::string sessiontime();
	std::string tagname();
	std::string simplename();
};


#endif  // MAME_LUAPRINTER_H


luaprinter.cpp:
Code

#include "luaprinter.h"

luaprinter::luaprinter(device_t& thisdevice, int testvalue){ 
	m_lp_mydevice = &thisdevice; 
	time(&m_lp_session_time);  
	initvalue = testvalue;
	printf("yes you can");
	fflush(stdout);
	
	};

int luaprinter::getnextchar() {
	if (m_lp_head==m_lp_tail) return -1; 
	else {
		int retval = m_printerbuffer.at(m_lp_tail++); 
		m_lp_tail %= BUFFERSIZE; 
		return retval;
	}
}

void luaprinter::putnextchar(int c) {
	m_printerbuffer.at(m_lp_head++)=c; 
	m_lp_head %= BUFFERSIZE;
}

std::string luaprinter::fixcolons(std::string in) {
    std::string final;
    for(std::string::const_iterator it = in.begin(); it != in.end(); ++it)
    {
        if((*it) != ':')
        {
            final += *it;
        }
        else final += '-';
    }
    return final;
}

std::string luaprinter::sessiontime() {
   struct tm *info;
   char buffer[120];
   info = localtime( &m_lp_session_time );
   strftime(buffer,120,"%Y-%m-%d %H-%M-%S", info);
   return std::string(buffer);
}

std::string luaprinter::tagname() {
	device_t * dev;
	device_t * lastdev;
	dev = m_lp_mydevice;
	std::string s(dev->owner()->shortname());
	while (dev) {
		lastdev = dev;
		dev=dev->owner();
	}
	lastdev=lastdev; // complains about non use
	return fixcolons(std::string(lastdev->shortname())+std::string(m_lp_mydevice->tag()));
}

std::string luaprinter::simplename() {
	device_t * dev;
	device_t * lastdev;
	dev = m_lp_mydevice;
	std::string s(dev->owner()->shortname());
	while (dev){
		s=std::string(dev->shortname())+std::string(" ")+s;
		lastdev = dev;
		dev=dev->owner();
	}
	lastdev=lastdev; // complains about non use
	return s;
}

device_t* luaprinter::getrootdev(){
	device_t* dev;
	device_t* lastdev = NULL;
	dev = m_lp_mydevice;
	while (dev){
		lastdev = dev;
		dev=dev->owner();
	}
	lastdev=lastdev; // complains about non use
	return lastdev;
}

void luaprinter::savepage(){
    emu_file file(std::string(m_lp_mydevice->machine().options().snapshot_directory()) + std::string("/") +
				std::string(getrootdev()->shortname() ) + std::string("/"), 
				OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
    auto const filerr = file.open(std::string(getprintername())+" Page "+std::to_string(m_page_count++)+".PNG");

    if (filerr == osd_file::error::NONE)
        {
            static const rgb_t png_palette[] = { rgb_t::white(), rgb_t::black() };
            // save the paper into a png
            png_write_bitmap(file, nullptr, (bitmap_t &) (* m_lp_bitmap), 2, png_palette);
        }
}




in luaengine.cpp:
Code
        auto luaprinter_type = sol().registry().create_simple_usertype<luaprinter>("new", sol::no_constructor);
        luaprinter_type.set("clearpage", &luaprinter::clearpage);
        luaprinter_type.set("drawpixel", &luaprinter::drawpixel);
        luaprinter_type.set("getpixel", &luaprinter::getpixel);
        luaprinter_type.set("setheadpos", &luaprinter::setheadpos);
        luaprinter_type.set("savepage", &luaprinter::savepage);
        luaprinter_type.set("getbuffer", &luaprinter::getbuffer);
        luaprinter_type.set("getnextchar", &luaprinter::getnextchar);
        luaprinter_type.set("putnextchar", &luaprinter::putnextchar);
        luaprinter_type.set("getheadpos", &luaprinter::getheadpos);
        luaprinter_type.set("setprintername", &luaprinter::setprintername);
        luaprinter_type.set("getprintername", &luaprinter::getprintername);
        luaprinter_type.set("fixcolons", &luaprinter::fixcolons);
        luaprinter_type.set("sessiontime", &luaprinter::sessiontime);
        luaprinter_type.set("simplename", &luaprinter::simplename);
        luaprinter_type.set("tagname", &luaprinter::tagname);
        luaprinter_type.set("count", &luaprinter::count);
        luaprinter_type.set("getinitvalue", &luaprinter::getinitvalue);
        luaprinter_type.set("pagewidth", &luaprinter::pagewidth);
        luaprinter_type.set("pageheight", &luaprinter::pageheight);

	sol().registry().set_usertype("luaprinter", luaprinter_type);




         machine_type.set("lp", sol::property([this](running_machine &m) {
                        sol::table table = sol().create_table();
                        int i=1;
                        for(auto p : luaprinter::luaprinterlist)
                        {
                        	table[i++] = p;
                        };
                        return table;
                }));
Posted By: Golden Child Re: Ap2000 signs of life - 09/18/20 04:15 PM

I thought, why not try to send the printed PNG to the printer:


dofile('../../luaprinter2.lua') -- start up my imagewriter interpreter

(print something to the page)

manager:machine().lp[1]:savepage()
print(manager:machine().lp[1]:getprintername())
os.execute('lpr ~/"Downloads/mamegit/mame/snap/ct486/2020-09-18 08-59-47 ct486-board4-lpt-lpt-centronics-luaprinter Page 0.PNG"')

and lpr sends the PNG file to the printer.

Ubuntu uses cups, I don't know how it would work on windows.
Posted By: Golden Child Re: Ap2000 signs of life - 09/18/20 06:34 PM
So if I add to my list of printers in the constructor, I get a whole bunch of devices in my list.

It seems to be initializing a bunch of devices that don't actually get used. It must be enumerating every possible device that uses the luaprinter.

Code
luaprinter::luaprinter(device_t& thisdevice, int testvalue){ 
	m_lp_mydevice = &thisdevice; 
	time(&m_lp_session_time);  
	initvalue = testvalue;

	addtoprinterlist( *this);
	printf("yes you can");
	printf(" device = %s ",thisdevice.tag());
	fflush(stdout);
	printf("count = %d\n",count());  // the size of the printerlist
	fflush(stdout);
	
	};


with one luaprinter device I get 19 items:

Code
./mame64 ct486   -hard1 hd128MB  -debug  -board4:lpt:lpt:centronics luaprinter -confirm_quit -ramsize 64M 
-board3:ide:ide:1 hdd -hard2 hd128MBpt -board3:ide:ide:1 hdd
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 1
...
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 9
    _/      _/    _/_/    _/      _/  _/_/_/_/
   _/_/  _/_/  _/    _/  _/_/  _/_/  _/       
  _/  _/  _/  _/_/_/_/  _/  _/  _/  _/_/_/    
 _/      _/  _/    _/  _/      _/  _/         
_/      _/  _/    _/  _/      _/  _/_/_/_/    

mame 0.224	
Copyright (C) Nicola Salmoria and the MAME team

Lua 5.3	
Copyright (C) Lua.org, PUC-Rio

yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 10
yes you can device = :board2:comat:serport0:luaprinter count = 11
yes you can device = :board2:comat:serport1:luaprinter count = 12
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 13
yes you can device = :board4:lpt:lpt:centronics:ap2000 count = 14
yes you can device = :board4:lpt:lpt:centronics:lx810l count = 15
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 16
Debug Build: Disabling input grab for -debug
Debug Build: Disabling input grab for -debug
Debug Build: Disabling input grab for -debug
[MAME]> 
"hd128MB" approximately matches the following
supported software items (best match first):


"hd128MBpt" approximately matches the following
supported software items (best match first):

DEVICE START CALL luaprinterlist

DEVICE START CALL luaprinterlist

DEVICE START CALL setprintername

DEVICE RESET CALLED
DEVICE RESET CALLED


MAME debugger version 0.224 (mame0224-205-g69406ddcc71-dirty)
Currently targeting ct486 (PC/AT 486 with CS4031 chipset)
[MAME]> yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 18
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 19


and if I add a second luaprinter device I get 35 total devices.


Code
/mame64 ct486  -hard1 hd128MB  -debug  -board4:lpt:lpt:centronics luaprinter -confirm_quit -ramsize 64M
 -board3:ide:ide:1 hdd -hard2 hd128MBpt -board3:ide:ide:1 hdd -board2:comat:serport1 luaprinter
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 1
...
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 8
yes you can device = :board2:comat:serport1:luaprinter count = 9
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 10
yes you can device = :board2:comat:serport1:luaprinter count = 11
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 12
yes you can device = :board2:comat:serport1:luaprinter count = 13
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 14
yes you can device = :board2:comat:serport1:luaprinter count = 15
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 16
yes you can device = :board2:comat:serport1:luaprinter count = 17
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 18
yes you can device = :board2:comat:serport1:luaprinter count = 19
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 20
    _/      _/    _/_/    _/      _/  _/_/_/_/
   _/_/  _/_/  _/    _/  _/_/  _/_/  _/       
  _/  _/  _/  _/_/_/_/  _/  _/  _/  _/_/_/    
 _/      _/  _/    _/  _/      _/  _/         
_/      _/  _/    _/  _/      _/  _/_/_/_/    

mame 0.224	
Copyright (C) Nicola Salmoria and the MAME team

Lua 5.3	
Copyright (C) Lua.org, PUC-Rio

yes you can device = :board2:comat:serport1:luaprinter count = 21
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 22
yes you can device = :board2:comat:serport0:luaprinter count = 23
yes you can device = :board2:comat:serport1:luaprinter count = 24
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 25
yes you can device = :board4:lpt:lpt:centronics:ap2000 count = 26
yes you can device = :board4:lpt:lpt:centronics:lx810l count = 27
yes you can device = :board2:comat:serport1:luaprinter count = 28
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 29
Debug Build: Disabling input grab for -debug
Debug Build: Disabling input grab for -debug
Debug Build: Disabling input grab for -debug
[MAME]> 
"hd128MB" approximately matches the following
supported software items (best match first):


"hd128MBpt" approximately matches the following
supported software items (best match first):

DEVICE START CALL luaprinterlist

DEVICE START CALL luaprinterlist

DEVICE START CALL setprintername

DEVICE RESET CALLED
DEVICE RESET CALLED
m_rs232_rxbaud read=7
rs232_rxbaud read=7


MAME debugger version 0.224 (mame0224-205-g69406ddcc71-dirty)
Currently targeting ct486 (PC/AT 486 with CS4031 chipset)
[MAME]> 

>g
[MAME]> yes you can device = :board2:comat:serport1:luaprinter count = 32
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 33
yes you can device = :board2:comat:serport1:luaprinter count = 34
yes you can device = :board4:lpt:lpt:centronics:luaprinter count = 35
Average speed: 99.93% (1 seconds)


Well, I guess as long as it works I'll keep it outside the constructor.
Posted By: Golden Child Re: Ap2000 signs of life - 09/19/20 02:55 PM

Just for fun, I wanted to see if I could get some color postscript output from the win95 printer drivers using the QMS Colorscript 230 drivers.

Setting the spool settings to Print directly to printer and disable bidirectional support because it would put 0x14 characters into the printout.

Using the "printer" centronics device and then using mame's File manager and setting the printout to a file to save out the data.


Once done, using gv (ghostview) under Ubuntu to view the output. (I had to apt install gv)

[Linked Image from i.imgur.com]
[Linked Image from i.imgur.com]
[Linked Image from i.imgur.com]
[Linked Image from i.imgur.com]

What I'd like to do is to figure out some way to have it watch the printer, when there's a long pause in the output, say 15 seconds or so, then save everything to a file, so it can run gv automatically.
Posted By: Golden Child Re: Ap2000 signs of life - 09/20/20 09:59 PM

I managed to get something working that would save the printer output bytes to separate files so you could launch a viewer on them, like gv for postscript output.

A delay of 30 seconds will separate files.


Code
lp0 = manager:machine().luaprinters[1]
filenamebase=lp0:getprintername()
filenamecount=0
idlewaitperiod=30*60
idlecount=0


function feedchars(ch)
local idleflag=0
repeat
nextchar = lp0:getnextchar()
if nextchar >= 0 then 
  idleflag=1
  if f == nil then
    filenamecount = filenamecount+1
    currentfilename = filenamebase..string.format("%04d",filenamecount)..".ps"
    f=io.open(currentfilename,"w")
    idlecount=0
  end
  f:write(string.char(nextchar))
 end 
until nextchar < 0
if idleflag==0 then
  if f~=nil then
    idlecount=idlecount+1 
    if idlecount%(60*5)==0 then print ("idle: "..idlecount/60) end
  end
else
  idlecount=0 -- reset idlecount
end
if idlecount > idlewaitperiod then
  idlecount=-1
  f:close()
  f=nil
  os.execute('gv "'..currentfilename..'" &')
  print('gv '..currentfilename)
end
end

function framedispatch() for i,j in pairs(dispatchlist) do j() end end
emu.register_frame(framedispatch)
dispatchlist={feedchars}



Code
idle: 5.0
idle: 10.0
idle: 15.0
idle: 20.0
idle: 25.0
idle: 30.0
gv 2020-09-20 14-14-25 ct486-board4-lpt-lpt-centronics-luaprinter0004.ps
Posted By: Golden Child Re: Ap2000 signs of life - 09/23/20 05:55 AM
I managed to convert the ap2000 driver into using my luaprinter routines to do the page saving:

They look a little "squashed" since the aspect ratio is off because it's 120x72. 120x144 would probably look more normal.

Some page samples:

[Linked Image from i.imgur.com]
[Linked Image from i.imgur.com]

putting the first page into gimp and stretching it to 120x144:
[Linked Image from i.imgur.com]

testing to see how many lines on a page:
[Linked Image from i.imgur.com]
Posted By: Lord Nightmare Re: Ap2000 signs of life - 09/24/20 06:05 PM
This is amazing stuff! Are you going to submit this upstream as a PR soon? I kinda want to play with it...

LN
Posted By: Golden Child Re: Ap2000 signs of life - 09/25/20 05:44 AM
Hi LN,

Thanks! Yes, I'm almost there... 8-)

I finally figured out how to blast out my screwed up github repository with "git push --force" and that completely replaced everything. Yay!

Coming soon to a theater near you 8-)
Posted By: Golden Child Re: Ap2000 signs of life - 09/26/20 09:44 PM
If you want to have a look at luaprinter, I have a branch at:

https://github.com/goldnchild/mame/tree/luaprinter

I need to clean it up and figure out the proper way of doing things using the device_interface mix-in.


[Linked Image from i.imgur.com]


One weird thing that the ap2000 is doing is that it's missing descenders when it prints in the Roman font. I thought initially that it wasn't getting the full 9 bits of the printhead, but it prints draft just fine as well as the Sans Serif.

Ramiro Polla (the uber-hacker behind the ap2000 driver) was cool enough to send me his ap2000 disassembly so maybe I can figure out why.
Posted By: Golden Child Re: Ap2000 signs of life - 10/01/20 12:25 AM
I thought I'd make a font from the pictures in the Imagewriter manual, since I always liked that font, and it doesn't look too bad.

Code
chars = {
"        "..
"        "..
"        "..
"        "..
"        "..
"        "..
"        "..
"        "..
"        ",
"   x    "..
"   x    "..
"   x    "..
"   x    "..
"        "..
"        "..
"   x    "..
"        "..
"        ",
"  x x   "..
"  x x   "..
"  x x   "..
"        "..
"        "..
"        "..
"        "..
"        "..
"        ",
"  x  x  "..
"  x  x  "..
" xxxxxx "..
"  x  x  "..
" xxxxxx "..
"  x  x  "..
"  x  x  "..
"        "..
"        ",
...
"   x    "..
"  x x   "..
" x   x  "..
"x     x "..
"xxxxxxx "..
"x     x "..
"x     x "..
"        "..
"        ",
" xxxxx  "..
" x    x "..
" x    x "..
" xxxxx  "..
" x    x "..
" x    x "..
" xxxxx  "..
"        "..
"        ",
...
}

-- just a quick test to see if it works

rmargin=125
lmargin=5
xpos=lmargin*8
tmargin=5

function printchar(c)
  c = c & 0x7f
  if c==13 or c==10 then xpos=lmargin*8 ypos=ypos+12 return end
  if xpos > rmargin*8 then xpos=lmargin*8 ypos=ypos+12 end
  if c<32 then c=32 end
  for col=0,7 do
    headdots = 0
    for row=0,8 do
      dot = chars[c-32+1]:sub(1+row*8+col,1+row*8+col)
      if dot == " " then dot=0 else dot=1 end
      headdots = headdots | (dot << row)
    end
    renderhead(headdots)      
    print(col.."  "..headdots)
    xpos = xpos+1      
  end
end

function printstring(s) for i=1,s:len() do printchar(string.byte(s,i)) end end



[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 10/02/20 04:28 AM
I was trying to find something that would print on the BBC Master and found a BeeBug dumpmaster rom.

./mame64 bbcm -printer ap2000 -romimage1 dmpmastr


It kinda works, but it seems to get its workspace corrupted when I do a *LDPIC. You're supposed to be able to hit CTRL+SHIFT+@ (mapped to backslash) to make it dump.

*BPRINT P0 V A D will setup the hotkey but it doesn't dump properly.

*BPRINT I V will do a vertical dump in inverse.
*HELP BPRINT shows you the settings.

Still, it's kinda neat to see it work.

[Linked Image from i.imgur.com]


edit: after fiddling around, I discovered that the rom scrnprnt100 has a good hotkey setup: hit CTRL+P and it prints the screen, CTRL+SHIFT+P and it prints in inverse.

./mame64 bbcm -printer ap2000 -romimage1 scrnprnt100


[Linked Image from i.imgur.com]
Posted By: Pernod Re: Ap2000 signs of life - 10/02/20 10:37 AM
Originally Posted by Golden Child
I was trying to find something that would print on the BBC Master and found a BeeBug dumpmaster rom.

./mame64 bbcm -printer ap2000 -romimage1 dmpmastr


It kinda works, but it seems to get its workspace corrupted when I do a *LDPIC. You're supposed to be able to hit CTRL+SHIFT+@ (mapped to backslash) to make it dump.

*LDPIC is a custom graphics loader on the Acorn User Gallery discs which runs in workspace at &900, so not too surprising there's a conflict.

The most popular printing ROMs at the time were Dumpout 3 (dumpout3) and Printmaster (prntmeps), but not sure if they have a hotkey dump feature.
Posted By: Golden Child Re: Ap2000 signs of life - 10/03/20 07:31 AM

I hacked up a lua script to render Epson JX-80 output from the BBC Dumpmaster rom and it looks pretty good. It supports the JX-80 on printer number 22. 22 is color with square pixels, 0 is black and white, and 5 is 72x72 dpi for square pixels.

The luaprinter wouldn't work unless I set the acknowledge to 1 in device_reset with output_ack(1).

Doubling the dots horizontally on the printout makes it look vivid.

[Linked Image from i.imgur.com]

The output is stretched 200% using gimp to make the aspect look right and rotated 90 degrees to be upright.

[Linked Image from i.imgur.com]

Posted By: Golden Child Re: Ap2000 signs of life - 10/09/20 07:05 PM
I was thinking, hmmmm can we make pdfs out of the dots. There's a catseye lua library that hacked on can make this:

[Linked Image from i.imgur.com]
[Linked Image from i.imgur.com]
[Linked Image from i.imgur.com]

It's a bit slow to be practical, gv takes a minute to render the pdf page, but still good fun.
Posted By: Golden Child Re: Ap2000 signs of life - 10/10/20 01:59 AM
More fiddling with Color Print Shop...using a rainbow background.

I was integerizing the coordinates, and that wasn't quite right.

It looks more like dot matrix output now:

[Linked Image from i.imgur.com]
[Linked Image from i.imgur.com]

but the file size is huge: 515MB

515665131 Oct 9 18:41 test94.pdf

No wonder it takes a minute to render it.
Posted By: Golden Child Re: Ap2000 signs of life - 10/10/20 11:34 PM
[Linked Image from i.imgur.com]

Reproducing this color print shop demo on youtube:

https://www.youtube.com/watch?v=z3hMOxR0n5g

It's interesting how the bitmap colors differ from the output pdf where the pdf looks more authentic.

I also got the file size a bit smaller (like 10x smaller) by not setting the color for every output dot and by using strokes instead of fills to make the dots.
Posted By: Golden Child Re: Ap2000 signs of life - 10/12/20 04:57 PM
Loading the png into gimp it's pretty easy to manually color correct by adjusting HSL:

(split view)

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 10/12/20 08:36 PM
I just figured out how to directly access members in luaengine, just specify them directly, what could be easier?

It's shocking how easy that is...

and if you want it read only just make it a property.

Code
device_luaprinter_interface_type.set("xposprop", sol::property(&device_luaprinter_interface::m_lp_xpos));
device_luaprinter_interface_type.set("name", &device_luaprinter_interface::m_lp_luaprintername);
device_luaprinter_interface_type.set("xpos", &device_luaprinter_interface::m_lp_xpos);


So then you can modify the variables directly, like manager:machine().lp[1].xpos = 200

Code
[MAME] function listlp()
[MAME]>>   print("listlp()  list of luaprinters:")
[MAME]>>   print("------------------------------")
[MAME]>>   for i,j in pairs(manager:machine().lp) do
[MAME]>>     print("lp["..i.."] = "..j:getprintername())
[MAME]>>   end
[MAME]>>   print("------------------------------")
[MAME]>> end
[MAME]> 
[MAME]> listlp()
listlp()  list of luaprinters:
------------------------------
lp[1] = 2020-10-12 10-36-18 apple2e-sl1-parallel-pic_ctx-luaprinter
lp[:sl1:parallel:pic_ctx:luaprinter] = 2020-10-12 10-36-18 apple2e-sl1-parallel-pic_ctx-luaprinter
------------------------------
[MAME]> print(manager:machine().lp[1].name)
2020-10-12 10-36-18 apple2e-sl1-parallel-pic_ctx-luaprinter
[MAME]> manager:machine().lp[1].name = "hi_there"
[MAME]> print(manager:machine().lp[1].name)
hi_there



And I was also experimenting with being able to execute lua code from inside the ap2000 driver, so I could call a lua function to say, generate dots for a pdf. So how to execute lua code? Just call load_string.


Code
device_luaprinter_interface_type.set("loadstring", [this](char const *astr)
     { printf("Trying %s\n",astr); return lua_engine::load_string(astr);  });


Code
[MAME]> manager:machine().lp[1].loadstring('print("IT WORKS")')
Trying print("IT WORKS")
IT WORKS
[MAME]> function dude(x) print ("This is a function that prints "..x) end
[MAME]> manager:machine().lp[1].loadstring('dude("IT WORKS")')
Trying dude("IT WORKS")
This is a function that prints IT WORKS


So now I need to figure out how to make it possible to call the luaengine from inside the driver.

It'd also be cool if you could load_string a string from the debugger, so you could do something complex in lua, so do something similar to a printf but make it lua code to execute.
Posted By: Golden Child Re: Ap2000 signs of life - 10/13/20 01:25 AM
Ok, so I add this to my device_luaprinter_interface:

It's a pointer to lua_engine in m_luaengine,
and also a pointer to a member function of lua_engine.

So I can call the function by

((*m_luaengine).*lualoadstring)(astr);
where astr is the string to execute.

Code

static void (lua_engine::* lualoadstring)(const char * astr);
static lua_engine *m_luaengine;

void callloadstring(const char *astr) { 
     printf("Trying callloadstring %s\n",astr); 
     ((*m_luaengine).*lualoadstring)(astr); 
}


and then in luaengine initialize them:

Code
device_luaprinter_interface::lualoadstring = &lua_engine::load_string;
device_luaprinter_interface::m_luaengine = this; 


so now I can do this:

Code
[MAME]> l = manager:machine().lp[1]
[MAME]> l:callloadstring(" l:callloadstring('print(\"whoa!\")') ")
Trying callloadstring  l:callloadstring('print("whoa!")') 
Trying callloadstring print("whoa!")
whoa!
Posted By: Golden Child Re: Ap2000 signs of life - 10/13/20 07:43 PM

Modifying the dot printing routine to call lua seems to work:

Code
char buffer[128];
snprintf(buffer,128,"if drawdot then drawdot( %f, %f ) end",
           (double) m_real_cr_pos + CR_OFFSET, yd);
callloadstring( buffer );


I use the if to check if the drawdot routine has been defined.

Code
Trying callloadstring if drawdot then drawdot( 971.000000, 170.333333 ) end
Trying callloadstring if drawdot then drawdot( 971.000000, 171.333333 ) end
Trying callloadstring if drawdot then drawdot( 971.000000, 172.333333 ) end
Trying callloadstring if drawdot then drawdot( 971.000000, 173.333333 ) end
Trying callloadstring if drawdot then drawdot( 971.000000, 174.333333 ) end



and if I define the drawdot routine from the console:

Code
function drawdot(x,y) print("DRAWDOT !!! "..x.."  "..y) end

Trying callloadstring if drawdot then drawdot( 35.000000, 60.000000 ) end
DRAWDOT !!! 35.0  60.0
Trying callloadstring if drawdot then drawdot( 35.000000, 61.000000 ) end
DRAWDOT !!! 35.0  61.0


Now I need to figure out how the ap2000 does 240 dpi because the steppers seem to step at 120 dpi, perhaps you have to watch the timing of when the printhead is fired, firing it when it's moving in-between stepper positions.
Posted By: Ramiro Polla Re: Ap2000 signs of life - 10/14/20 06:16 PM
Originally Posted by Golden Child

Now I need to figure out how the ap2000 does 240 dpi because the steppers seem to step at 120 dpi, perhaps you have to watch the timing of when the printhead is fired, firing it when it's moving in-between stepper positions.

The firmware was beautifully written and calculated down to the microseconds it takes for the printhead to hit the paper. Look for two comments which have "417 microseconds" in epson_lx810l.cpp.

In epson_lx810l_device::co0_w():
Quote
The firmware expects a 300 microseconds delay between the fire signal and the impact of the printhead on the paper. This can be verified by the timings of the steps and fire signals for the same positions with different directions (left to right or right to left). We don't simulate this delay since it is smaller than the time it takes the printhead to travel one pixel (which would be 417 microseconds), so it makes no difference to us. It is interesting to note that the vertical alignment between lines which are being printed in different directions is noticeably off in the 20+ years old printer used for testing =).


In epson_lx810l_device::device_timer()
Quote
The firmware issues two half-steps in sequence, one immediately after the other. At full speed, the motor does two half-steps at each 833 microseconds. A timer fires the printhead twice, with the same period as each half-step (417 microseconds), but with a 356 microseconds delay relative to the motor steps.
Posted By: Golden Child Re: Ap2000 signs of life - 10/15/20 03:49 AM
Hi Raimro,

Thanks for the pointers. I stuck some instrumenting in to see the delay between changes to the stepper and the timers.

yes the write to co0_w is 417 ms apart: (2525-2107 = 418)

Code
POS = 0   DATA=0
POS = 1   DATA=0
STEPPER:d
CR_STEPPER_MSECS: time = 835.9782 microsecs

CR_STEPPER current pos: -49
POS = 0   DATA=0
POS = 1   DATA=0
CR_TIMER_MSECS: time = 835.978

POS = 0   DATA=0
POS = 1   DATA=44
Fractional time co0_w: 152107.340486 
Trying callloadstring if drawdot then drawdot( 33.000000, 25.333333 ) end
Fractional time co0_w: 152107.340486 
Trying callloadstring if drawdot then drawdot( 33.000000, 29.333333 ) end
STEPPER:8
CR_STEPPER_MSECS: time = 830.0781 microsecs

CR_STEPPER current pos: -48
POS = 0   DATA=0
POS = 1   DATA=38
Fractional time co0_w: 152525.024406 
Trying callloadstring if drawdot then drawdot( 33.000000, 26.333333 ) end
Fractional time co0_w: 152525.024406 
Trying callloadstring if drawdot then drawdot( 33.000000, 27.333333 ) end
Fractional time co0_w: 152525.024406 
Trying callloadstring if drawdot then drawdot( 33.000000, 28.333333 ) end
CR_TIMER_MSECS: time = 830.078


Gonna have to study this some more 8-)
Posted By: Golden Child Re: Ap2000 signs of life - 10/15/20 01:36 PM
and checking the time since the last stepper change, it says 337 usec and 755 usec (755-337 usec = 418 usec) so yes very close to expected

Code
POS = 0   DATA=0
POS = 1   DATA=20
Fractional time co0_w: 110442.708325 
Time since last step: 757.446289 
Trying callloadstring if drawdot then drawdot( 83.000000, 26.333333 ) end
STEPPER:5
CR_STEPPER_MSECS: time = 833.9437 microsecs

CR_STEPPER current pos: -98
POS = 0   DATA=0
POS = 1   DATA=8
Fractional time co0_w: 110857.137036 
Time since last step: 337.931315 
Trying callloadstring if drawdot then drawdot( 83.000000, 28.333333 ) end
CR_TIMER_MSECS: time = 833.944

POS = 0   DATA=0
POS = 1   DATA=20
Fractional time co0_w: 111274.210604 
Time since last step: 755.004883 
Trying callloadstring if drawdot then drawdot( 82.000000, 26.333333 ) end
STEPPER:d
CR_STEPPER_MSECS: time = 831.5023 microsecs

CR_STEPPER current pos: -97
POS = 0   DATA=0
POS = 1   DATA=8
Fractional time co0_w: 111690.470369 
Time since last step: 339.762370 
Trying callloadstring if drawdot then drawdot( 82.000000, 28.333333 ) end
CR_TIMER_MSECS: time = 831.502

POS = 0   DATA=0
POS = 1   DATA=2
Fractional time co0_w: 112107.543937 
Time since last step: 756.835937 
Trying callloadstring if drawdot then drawdot( 81.000000, 30.333333 ) end
STEPPER:8
CR_STEPPER_MSECS: time = 833.3333 microsecs
Posted By: R. Belmont Re: Ap2000 signs of life - 10/15/20 02:15 PM
Reading this makes me realize how much a dot-matrix printer is like a write-only floppy drive, except it controls the exact media position instead of waiting for it to come around to the right spot.
Posted By: Ramiro Polla Re: Ap2000 signs of life - 10/16/20 11:51 AM
Originally Posted by R. Belmont
Reading this makes me realize how much a dot-matrix printer is like a write-only floppy drive, except it controls the exact media position instead of waiting for it to come around to the right spot.

Great idea for a hackerspace project: a dot-matrix printer that spins the paper and waits for the right spot to come around for each dot.
Posted By: Just Desserts Re: Ap2000 signs of life - 10/16/20 12:48 PM
True, but you would need to ensure that your paper has an index hole.
Posted By: R. Belmont Re: Ap2000 signs of life - 10/16/20 12:50 PM
Or write some kind of a sync mark and watch for it to come around.
Posted By: Golden Child Re: Ap2000 signs of life - 10/16/20 11:44 PM
I liked being able to call lua so much I made a class called luacall:

Code
/***************************************************************************
    luacall.h
    Utility class for calling lua
***************************************************************************/

#ifndef MAME_LUACALL_H
#define MAME_LUACALL_H

#pragma once

class lua_engine;

class luacall {
	public:
		static lua_engine *m_luaengine;
		static void        (lua_engine::* lualoadstringf)  (const char * astr);
		static int         (lua_engine::* luagetintvarf)   (const char * astr);
		static double      (lua_engine::* luagetdoublevarf)(const char * astr);
		static std::string (lua_engine::* luagetstringvarf)(const char * astr);

	static void lualoadstring(const char *astr) { 
			((*m_luaengine).*lualoadstringf)(astr); 
		}

	static int luagetintvar(const char *astr) {
			int retval =  ((*m_luaengine).*luagetintvarf)(astr); 
			return retval;
		}

	static double luagetdoublevar(const char *astr) {
			double retval =  ((*m_luaengine).*luagetdoublevarf)(astr); 
			return retval;
		}

	static std::string luagetstringvar(const char *astr) {
			std::string retval =  ((*m_luaengine).*luagetstringvarf)(astr); 
			return retval;
		}

}; // end class luacall  

#endif  // MAME_LUACALL_H

/***************************************************************************
    luacall.cpp
    Utility class for calling lua functions
***************************************************************************/

#include "emu.h"
#include "luacall.h"

lua_engine *luacall::m_luaengine;
void      (lua_engine::* luacall::lualoadstringf)  (const char * astr);
int         (lua_engine::* luacall::luagetintvarf)   (const char *astr);
double      (lua_engine::* luacall::luagetdoublevarf)(const char *astr);
std::string (lua_engine::* luacall::luagetstringvarf)(const char *astr);

luaengine.h:
Code
	int luagetintvar( const char *astr);
	double luagetdoublevar( const char *astr);
	std::string luagetstringvar( const char *astr);

and in luaengine.cpp:
Code
		luacall::m_luaengine = this; 
		luacall::lualoadstringf   = &lua_engine::load_string;
		luacall::luagetintvarf    = &lua_engine::luagetintvar;
		luacall::luagetdoublevarf = &lua_engine::luagetdoublevar;
		luacall::luagetstringvarf = &lua_engine::luagetstringvar;

	int         lua_engine::luagetintvar   ( const char *astr) { return sol()[astr]; };
	double      lua_engine::luagetdoublevar( const char *astr) { return sol()[astr]; };
	std::string lua_engine::luagetstringvar( const char *astr) { return sol()[astr]; };


so then I can do stuff like:

Code
// call lua with a string to execute:
	char buffer[128];
	snprintf(buffer,128,"if drawdot then drawdot( %f, %f ) end", xcoord, ycoord);
	luacall::lualoadstring(buffer);

// get the value from a double var:

printf("Get Double %f\n",luacall::luagetdoublevar("testdouble"));

//some indirection: get a double var from the name stored in the variable named by teststring2

printf("Testing luagetstring:   value for %s %f\n",
                luacall::luagetstringvar("teststring2").c_str(),
		luacall::luagetdoublevar(luacall::luagetstringvar(luacall::luagetstringvar("teststring2").c_str()).c_str()));

// get the value from a integer var:
printf("Get Int %d\n",luacall::luagetdoublevar("testint"));



If the variable isn't defined, it seems to just return 0, 0.0 or the empty string.

Code
Testing luagetstring:   value for  0.000000
Get Double 0.000000
Get Int 0
[MAME]> testdouble=5.29
[MAME]> testint=300
[MAME]> teststring2="orange"
[MAME]> orange="grape"
[MAME]> grape=777
[MAME]> 
Testing luagetstring:   value for orange 777.000000
Get Double 5.290000
Get Int 300


Posted By: Golden Child Re: Ap2000 signs of life - 10/17/20 09:36 PM
I think I may have solved the mystery of the missing bottom line. The font data is stored as 8 bits, with the bottom line saved as 3 bytes. These bytes go into a shift register when written to c001,c002 and c003 and they get shifted out at c000.

So now you can see the bottom of the character [:

[Linked Image from i.imgur.com]

so at 2708 DE gets loaded with C001 and C gets 2 so we transfer 3 bytes to c001,c002,c003 with the BLOCK instruction.

then at 2714 we read the value at C000 for our 9th pin, the other 8 bits coming from LDAX (HL+).

[Linked Image from i.imgur.com]


It seems to work for the self test, anyway.




Code

void e05a30_device::write(offs_t offset, uint8_t data)
{
	LOG("%s: e05a30_w([0xC0%02x]): %02x\n", machine().describe_context(), offset, data);

	switch (offset) {
	case 0x0:
	case 0x1:
	case 0x2:
	case 0x3:
		c000_shift_register &= ~(0xff << ((3-offset)*8));
		c000_shift_register |= (data << ((3-offset)*8));
		break;

...

uint8_t e05a30_device::read(offs_t offset)
{
	uint8_t result = 0;

	LOG("%s: e05a30_r([0xC0%02x]): ", machine().describe_context(), offset);

	switch (offset) {
	case 0x0: 
			c000_shift_register <<= 1;  // put shift before the capture
			result = (c000_shift_register & 0x1000000) ? 0x80 : 0x0; 
			break;
Posted By: Golden Child Re: Ap2000 signs of life - 10/18/20 03:07 PM
So if we can print 9 bits of the printhead, why not see if ESC ^ 9-pin graphics mode works:

[Linked Image from i.imgur.com]

According to the ESC P manual, the second byte's LSB is the 9th pin, but it's actually the MSB, just as in the printer internals.

Code

    1 GOTO 10
    5 X = PEEK( (12*16+1)*256 ) : P = 12*256*16+9*16 : FOR I=1 TO LEN(A$) : POKE P,ASC(MID$(A$,I,1)):NEXT:RETURN
   10 REM APPLE PARALLEL CARD, READ FROM C100 SETS UP STROBE, THEN POKE C090 WILL SEND CHARACTERS


     100 N = 120 * 3 : N1=((N/256)-INT(N/256))*256 :N2=INT(N/256) :? N,N1,N2:A$=CHR$(27)+"^"+CHR$(1)+CHR$(N1)+CHR$(N2) : GOSUB 5
     110 FOR J = 1 TO N/2 : A$=CHR$(1+4+(1+4)*16)+CHR$(128) : GOSUB 5 : A$=CHR$(2+8+(2+8)*16)+CHR$(128):GOSUB 5:NEXT:A$=CHR$(10):GOSUB 5




[Linked Image from i.imgur.com]

Although, come to think of it, this probably worked before the 9-pin fix since it's not going through the shift register 8-)
Posted By: R. Belmont Re: Ap2000 signs of life - 10/18/20 04:06 PM
Can you submit a pull request for the shift register fix? That would be great smile
Posted By: Golden Child Re: Ap2000 signs of life - 10/18/20 06:24 PM
Sure, RB!

(if I can get my git straightened up again 8-)

I managed to get the font looking improved, but it still isn't quite right.

The ap2000 does the NLQ fonts by printing one sequence of 9 bits, feeding the paper by 1/216" then printing the next sequence of 9 bits.

It's kinda hacky yet, but I do like the little "circles" look on the i and the r and the 2.


This is at 240x144 dots:

[Linked Image from i.imgur.com]
Posted By: R. Belmont Re: Ap2000 signs of life - 10/18/20 07:18 PM
Neat! I love those little circles too smile
Posted By: Golden Child Re: Ap2000 signs of life - 10/18/20 08:22 PM
Ok I made a PR:

ap2000 add shift register for c000 - fixes the missing 9th pin line #7366

I cloned a fresh repo so I wouldn't make a mess.

It's strange, testing it out but the keys stopped working, like holding keypad 7 (FF) when starting up to get it to go into self test mode. And holding down keypad 0 to toggle online doesn't work either.
Posted By: R. Belmont Re: Ap2000 signs of life - 10/18/20 08:36 PM
Can you check if those keys not working also happened without the shift register change?
Posted By: Golden Child Re: Ap2000 signs of life - 10/18/20 09:24 PM
Ok, I commented it out, recompiled and the keys still didn't work. So weird.

As an aside, just now when I was changing the e05a30.cpp file I accidentally opened the e05a03.h file and guess what, there's a shift register in that one also. I guess a person should go reading other similar devices for clues too 8-).
Posted By: Lord Nightmare Re: Ap2000 signs of life - 10/19/20 02:13 PM
Can you find which commit upstream broke the keys (after stashing or committing/PRing your changes?)
Posted By: Vas Crabb Re: Ap2000 signs of life - 10/19/20 02:29 PM
Is it actually broken? If the printer is using IPT_KEYBOARD then it’s intentional that it no longer responds to keys when the system keyboard is active. This is to solve the “typing on everything at once” issue you get the moment you plug a terminal into a computer with a keyboard, or plug two terminals into a computer. See https://mametesters.org/view.php?id=6320 and check the Keyboard Mode menu.
Posted By: Golden Child Re: Ap2000 signs of life - 10/19/20 03:25 PM
Ahh, I see that it is disabled by default. I did not know that menu was there 8-)

Setting it to enabled makes it active again. Cool.

Thanks, Vas.

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 10/19/20 09:34 PM
I had a mini freakout for why the keyboard wasn't working on the ct486, but it gets the rightmost screen so it comes up initially disabled. Left screen = enabled, right screen = disabled.

Simple fix, just enable it from the Keyboard menu.


[Linked Image from i.imgur.com]

Yay! So now we can see the descenders:

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 10/20/20 11:18 AM
Achievement Unlocked:

Pull request successfully merged and closed

Yay!
Posted By: Ramiro Polla Re: Ap2000 signs of life - 10/20/20 02:52 PM
Originally Posted by Golden Child
Achievement Unlocked:

Pull request successfully merged and closed

Yay!

Good job! I remember C00[0-3] bugged me for quite a while, I hadn't realized it could have been a shift register.
Posted By: Golden Child Re: Ap2000 signs of life - 10/20/20 04:13 PM
Thanks Ramiro!
Posted By: Golden Child Re: Ap2000 signs of life - 10/23/20 06:13 PM
Just for fun, fiddling with the cpc6128 and the ap2000:

You can print to the printer with PRINT #8,"HELLO"
or LIST #8

Code
     70 CLS
     80 PRINT "TESTING printerp01 PRINTER PAC II"
     81 ?
     85 PRINT "startup with printerp01"
     86 ?
     95 PRINT "type RUN "CHR$(34)"PP2 enter"
     96 ?
     99 FOR J = 1 TO 5
    100  FOR I=32 TO 127:?CHR$(I);:NEXT:PRINT
    110 NEXT
    120 |DUMP


[Linked Image from i.imgur.com]
[Linked Image from i.imgur.com]
and you can adjust the colors with

INK 0,0 makes color 0 black
INK 3,26 makes color 3 white
INK 3,27 makes color 3 grey
Posted By: Golden Child Re: Ap2000 signs of life - 11/26/20 04:23 PM
I wanted to be able to scale the bitmap so I could save a scaled version. This would be useful to double the pixels vertically so 120x72 would be 120x144 which would look more "square".

So why not expose a copyrozbitmap function to lua so I could experiment/test with it?
Code
void mycopyroz(bitmap_rgb32& dest, bitmap_rgb32& src, int srcx, int srcy, int destx, int desty, int width, int height, double scalex, double scaley) {
	copyrozbitmap(dest, rectangle(destx,destx+width*scalex-1,desty,desty+height*scaley-1), src, 
	((srcx+0.01) * 1.0 - destx * (1.0/scalex) ) * 0x10000, 
	((srcy+0.01) * 1.0 - desty * (1.0/scaley) ) * 0x10000, 
	0x10000 * (1.0/scalex), 0, 0, 
	0x10000 * (1.0/scaley), false);
	}

and then I can do stuff like:

Code
lp0 = manager:machine().lp[1] 

lp0:clearpage(0,0xffffff)
lp0:clearpage(-1,0x808080)

function drawx(x1,y1,size) 
  local y2 = y1+size-1 local x2 = x1+size-1 
  for i=0,size-1 do 
    lp0:drawpixel(x1+i,y1) lp0:drawpixel(x1+i,y2) lp0:drawpixel(x1,y1+i) lp0:drawpixel(x2,y1+i) lp0:drawpixel(x1+i,y1+i) lp0:drawpixel(x2-i,y1+i) 
  end 
end

drawx(0,0,20)  

lp0:savepagescale(0,2.0,4.0)   -- save page 0 at magnification 2.0 horiz and 4.0 vertically

for i = 0,20 do lp0:mycopyroz(lp0.m_lp_bitmap,lp0.m_lp_bitmap,0,792,70+40*i,792,20,20,2,2) end

xpos = 0 
for i = 1,10 do 
  mag = i size = 20 * mag lp0:mycopyroz(lp0.m_lp_bitmap,lp0.m_lp_bitmap,0,792+0,xpos,792-100,size/mag,size/mag,mag,mag) 
  xpos = xpos + size 
end

lp0:setheadpos(0,20)

lp0:saveall()
[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 11/28/20 02:51 AM
[Linked Image from i.imgur.com]

Experimenting with making a half-inch green bar paper background.

or a non-0xffffff background:

[Linked Image from i.imgur.com]
Posted By: Golden Child Re: Ap2000 signs of life - 11/28/20 03:10 PM
And why not add the ability to draw lines into our bitmap too:


[Linked Image from i.imgur.com]

Use a drawline routine from the hp9845 driver and make some changes:

Code
//void hp9845ct_base_state::draw_line(unsigned x0 , unsigned y0 , unsigned x1 , unsigned y1)
void drawline(int x0 , int y0 , int x1 , int y1, u32 pixelval)
{
        int dx, dy, sx, sy, x, y, err, e2;

        // draw line, vector generator uses Bresenham's algorithm
        x = x0;
        y = y0;
        dx = abs((int) (x1 - x));
        sx = x < x1 ? 1 : -1;   // actually always 1 because of normalization
        dy = abs((int) (y1 - y));
        sy = y < y1 ? 1 : -1;
        err = (dx > dy ? dx : -dy) / 2;

        for(;;){
//                plot(x, y, BIT(m_gv_line_type_mask, 15));
//               update_line_pattern();

		if (!((x<0) || (x >= m_lp_bitmap->width()) || (y<0) || (y >= m_lp_bitmap->height()))) 
					m_lp_bitmap->pix32(y,x) = pixelval;

                if (x == x1 && y == y1) break;

                e2 = err;
                if (e2 > -dx) {
                        err -= dy;
                        x += sx;
                }
                if (e2 < dy) {
                        err += dx;
                        y += sy;
                }
        }
}



and make some spokes:

Code
function drawcirclespokes(cx,cy,size,step,color) 
for i=0,360,step do 
  manager:machine().lp[1]:drawline(math.floor(cx),math.floor(cy),math.floor(cx+size*math.cos(i/360*2*math.pi)),math.floor(cy+size*math.sin(i/360*2*math.pi)),color) 
  manager:machine().lp[1]:drawline(math.floor(cx+size*math.cos(i/360*2*math.pi)),math.floor(cy+size*math.sin(i/360*2*math.pi)),
math.floor(cx+size*math.cos((i+step)/360*2*math.pi)),math.floor(cy+size*math.sin((i+step)/360*2*math.pi)),color)
 end
end

drawcirclespokes(200,792,150,360/36,0)
drawcirclespokes(0,0,360,360/36,0)
drawcirclespokes(8.5*120,0,360,360/36,0)
drawcirclespokes(9.0*120,792,360,360/36,0)

Posted By: Golden Child Re: Ap2000 signs of life - 11/29/20 12:15 PM
Some more experiments:

I made an array of bitmap_rgb32 and a readpngtobitmap routine and exposed them to lua:
Code

	bitmap_rgb32 bitmaparray[10];
	bitmap_rgb32 * getbitmaparrayitem(int item) { return &(bitmaparray[item]); }
	
	void bitmapalloc(bitmap_rgb32& bitmap, int width, int height){ bitmap.allocate(width,height); }


int readpngtobitmap(bitmap_rgb32& bitmap, std::string filename){

         emu_file file("",OPEN_FLAG_READ);;
        osd_file::error const filerr = file.open(filename);
        if (filerr != osd_file::error::NONE)
                {printf("no file!\n"); return 0;}

        // read the PNG data
        png_info png;
        png_error const result = png.read_file(file);
        file.close();
        if (result != PNGERR_NONE)
        {
                osd_printf_error("%s: Error reading PNG file\n", filename);
                return 0;
        }
   bool hasalpha=false;
   png_error result2 = png.copy_to_bitmap( *((bitmap_argb32 * ) &bitmap), hasalpha);
   
      if (PNGERR_NONE != result2)
                {
                        osd_printf_error("%s: Error copying PNG bitmap to MAME bitmap\n", filename);
                        osd_printf_error("Error result = %d\n", result);
                        return false;
                }

printf("bitmap size %d %d\n",bitmap.width(),bitmap.height());
	return 1;
}

which allows me to load various bitmap fonts as pngs so I can use those fonts:

Opening ubuntu's character map on Noto Mono 22:
[Linked Image from i.imgur.com]

Taking a screencap and figuring out the grid size in Gimp:
[Linked Image from i.imgur.com]

and a test of what the font would look like (scaling the font to 66% to make it fit 80 columns wide):
[Linked Image from i.imgur.com]

Code
manager:machine().lp[1]:readpngtobitmap(manager:machine().lp[1]:getbitmaparrayitem(4),"grid.png")

function drawstringscaleoffset(x,y,str,bitmap,xsize,ysize,rowsize,spacing,scale,offsetx,offsety,offsetsizex,offsetsizey,linegap,rtmar)
xpos = x ypos = y
  for i=1,str:len() do c = str:byte(i) if c>=32 and c<=127 then cpos = c - 32 colpos = cpos % rowsize rowpos = math.floor(cpos/rowsize) lp0:mycopyroz(lp0.m_lp_bitmap, bitmap, math.floor(colpos*xsize+offsetx),math.floor(rowpos*ysize+offsety) , xpos,ypos+792, offsetsizex, offsetsizey, scale, scale)
xpos = xpos + spacing end if xpos > rtmar or c==10 then xpos = x ypos=ypos+offsetsizey+linegap end
end
end
drawstringscaleoffset(20,-792+100,zstring,lp0:getbitmaparrayitem(4),65.75,61,16,12,0.66,25,16,20,35,-14,120*8+20)

and an experiment with a spectrum zx 8x8 font (from DamienG's ZX Origins webpage):

(I couldn't figure out why the png wouldn't load and then I realized it was an 8-bit indexed png. After converting the file to rgb with gimp and exporting it worked fine.)

[Linked Image from i.imgur.com]
© Forums