Gameboy Development Forum

Discussion about software development for the old-school Gameboys, ranging from the "Gray brick" to Gameboy Color
(Launched in 2008)

You are not logged in.

#1 2015-06-14 22:56:51

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Anyone have experience with the GB Printer?

I tried downloading the printlib from http://shen.mansell.tripod.com/games/ga … meboy.html

I loaded the prntdemo.gb rom onto my flash cart and connected it to my GB Printer, and it works as intended, printing a test image.

But when I try to run the make.bat to compile it on my own, I get errors. I did have to make a couple changes to the makefile and the source files, but they shouldn't affect whatever is going wrong here.

In the source files, I changed <gb.h> to <gb/gb.h>, and on the makefiles, I just changed the path to my own lcc compiler. This is the error I get:

https://i.imgur.com/9UwPplp.png

Any ideas?

Last edited by Scazon (2015-06-15 15:24:25)

Offline

 

#2 2015-06-15 10:27:34

Tauwasser
Member
Registered: 2010-10-23
Posts: 160

Re: Anyone have experience with the GB Printer?

Look at line 133 in prntdemo.c and try to find out why your compiler dies.

cYa,

Tauwasser

Offline

 

#3 2015-06-15 15:23:22

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Re: Anyone have experience with the GB Printer?

I ended up changing a few more things and got it to compile correctly.

First, I had to change all the large tile data unsigned char arrays to const, and that fixed the address overflow error.

Then I found that the fatal compiler error (I think) was due to two variables being declared in main() as "unsigned long". I changed it to "UWORD" and it compiled with no other errors (just the same warnings as above).

However, now when I load the GB ROM, I get a "Check Link" error that I don't know how to fix (I get the error even when connected correctly to a physical GB printer).

I can trace the error to the SendPrinterByte() function which lies in the comm.s file. Unfortunately I don't know ASM, so I'm stuck here.

Offline

 

#4 2015-06-15 17:54:00

Tauwasser
Member
Registered: 2010-10-23
Posts: 160

Re: Anyone have experience with the GB Printer?

comm.s is just the link port assembler. It assumes that your compiler put the argument (byte from SendPrinterByte(byte)) onto the stack. So that's the first thing I'd check. Look if the code that you compiled still uses the same calling convention/ABI. If it doesn't, then that's your problem.

In general you could also try to convert the assembler to c code. Should be straightforward.

Code:

_SendPrinterByte::
        di                 ;;  disable interrupts
    lda    hl,2(sp)           ;;  get to last pushed argument
    ld    a,(hl)             ;;  load to a
        ldh     (0x01),a   ;;  store argument to FF01
        ld      a,#0x81
        ldh     (0x02),a   ;;  store 0x81     to FF02 (transfer start, internal clock)
sent:   ldh     a,(0x02)   ;;  wait until transfer complete (FF02b7 reset)
    and    #0x80
    jp    NZ,sent
        ldh     a,(0x01)   ;;  load shifted-in byte
    ld    e,a
        ld      d,#0x00    ;;  store result zero-extended in de
        ei                 ;;  enable interrupts
    ret

cYa,

Tauwasser

Offline

 

#5 2015-06-16 17:41:30

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Re: Anyone have experience with the GB Printer?

Here's my attempt at converting the asm to C (there were also a couple other functions in that file, I tried converting them, too, because they seemed more straightforward (I just implemented them based on their name). It appears to be correct(?).

Code:

unsigned char GetLow(UWORD twoBytes){
  return twoBytes & (UWORD)0xFFFF;
}

unsigned char GetHigh(UWORD twoBytes){
  return twoBytes>>8;
}

unsigned char SendPrinterByte(unsigned char byte){
  unsigned char result;
  disable_interrupts();
  SB_REG = byte; //data to send
  SC_REG = 0x81; //1000 0001 - start, internal clock
  while (SC_REG & 0x80){} //wait until b1 reset
  result = SB_REG; //return response stored in SB_REG
  enable_interrupts();
  return result;
}

When I move these to the PrntCmd.c file, the game now correctly identifies the link cable and starts sending data/printing, but it only gives me this image:
https://i.imgur.com/9TkTcYZ.png
(a blank line)

So now I'm trying to figure out what's causing that.

There's also a line in the main() function that declares a UBYTE e, but e is only used in the line "x = py+e+e;" in one of the for loops (and is never initialized nor changed). It is apparently Very Important, because if I take this out, the game stops sending data at line 6 and freezes there.

Offline

 

#6 2015-06-16 19:05:49

Tauwasser
Member
Registered: 2010-10-23
Posts: 160

Re: Anyone have experience with the GB Printer?

Scazon wrote:

Code:

unsigned char GetLow(UWORD twoBytes){
  return twoBytes & (UWORD)0xFFFF;
}

unsigned char GetHigh(UWORD twoBytes){
  return twoBytes>>8;
}

No, GetHigh returns the high byte from the passed 16-bit word, GetLow returns the low byte from the passed 16-bit word. This might be related to your printing issue.

Code:

UBYTE GetHigh(UWORD w) {
    return (w & 0xFF00u) >> 8;
}

UBYTE GetLow(UWORD w) {
    return (w & 0xFFu);
}

Scazon wrote:

Code:

unsigned char SendPrinterByte(unsigned char byte){
  unsigned char result;
  disable_interrupts();
  SB_REG = byte; //data to send
  SC_REG = 0x81; //1000 0001 - start, internal clock
  while (SC_REG & 0x80){} //wait until b1 reset
  result = SB_REG; //return response stored in SB_REG
  enable_interrupts();
  return result;
}

Looking good. Should probably use UBYTE instead of "unsigned char", but that's a matter of taste. I'd do "while (SC_REG & 0x80u);", but a matter of taste again. Make sure SB_REG and SC_REG are declared volatile.


Scazon wrote:

When I move these to the PrntCmd.c file, the game now correctly identifies the link cable and starts sending data/printing

So it seems the calling convention did change if it works now. Good for you! Try to fix the GetLow function and see if that fixes your printing issue.


Scazon wrote:

There's also a line in the main() function that declares a UBYTE e, but e is only used in the line "x = py+e+e;" in one of the for loops (and is never initialized nor changed). It is apparently Very Important, because if I take this out, the game stops sending data at line 6 and freezes there.

e is apparently just to account for the difference in stride between x and y. Since that's 0 for your pic_map, I'd assume the code relies on e being implicitly zero due to the way the compiler code initializes RAM. I'd take it out.
Line 65 in main doesn't do remotely what you'd think it does, so I'd change it as well. == has higher precendence than &, so "if ((py & 2 == 2) && (py>0))" becomes "if ((py & 1) && (py > 0))"...

Code:

void main(){
  
  UBYTE result; /* error codes */
  UBYTE index;  /* index into pic_map */
  
  UWORD bgtile; /* bg tile index/offset into pic_tiles */
  UBYTE px, py; /* loop variables */
  
  set_bkg_data(128,128,&font[0]);
  set_bkg_data(0,158,&pic_tiles[0]);
  set_bkg_tiles(0,0,20,18,&pic_map[0]);

  SHOW_BKG;

  PrinterInit();

  result = CheckLinkCable();
  if(result !=0){
    p_err("check link          ",result);
  }
  result=CheckForErrors();
  if(result !=0){
    p_err("check error         ",result);
  }

  /* init index to 0 => start at beginning of pic_map */
  index = 0;

  for (py = 0; py < 18; py++) {
  
    p_tell("Sending Data line   ", py);
    for (px = 0; px < 20; px++) {
    
        /* get tile index */
        bgtile = pic_map[index++];
        /* convert to offset, i.e. bgtile *= 16, use 4 bit shifts */
        bgtile <<= 4;
        
        /* send tile data */
        memcpy(&p_data[0], &pic_tiles[bgtile], 16);
        PrintTileData(p_data);
  
    }

    /* check printer status after every second line */
    if (py & 1) {
    
        result = GetPrinterStatus();
        /* TODO: should probably do something here */
        if (result = CheckForErrors())
            p_err("check errors2       ", result);
    
    }
  }

  /* TODO: does crt catch main exiting? */

}

I did not check if this actually compiles. All typos are yours to keep. GBDK-doc.pdf says memcpy is available, so why not use it.

cYa,

Tauwasser

Offline

 

#7 2015-06-17 08:15:53

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Re: Anyone have experience with the GB Printer?

Tauwasser wrote:

No, GetHigh returns the high byte from the passed 16-bit word, GetLow returns the low byte from the passed 16-bit word. This might be related to your printing issue.

So they did do what I thought, I just implemented them wrong. My bad, haha.

Tauwasser wrote:

Make sure SB_REG and SC_REG are declared volatile.

SB_REG and SC_REG are basically macros for the addresses 0xFF01 and 0xFF02. They're defined in hardware.h as "(*(volatile UINT8 *)0xFF01)" (and FF02, respectively), so we're good there.

Tauwasser wrote:

I did not check if this actually compiles. All typos are yours to keep. GBDK-doc.pdf says memcpy is available, so why not use it.

I tried your main() code (and #included <string.h> for memcpy) and it looks like it compiles (and it's much more understandable, thanks!). The single line printing issue is still there, BUT, if you check out what it outputs now:
https://i.imgur.com/RTAbqmf.png
You'll see that it's a *slightly darker shade of gray*

I think the problem now lies somewhere in PrintTileData() in PrntCmd.c (or something with p_data). Currently trying to grok how that function works.

Thanks so much for your help, by the way. I've made a few games with gbdk but I'm still new to this kind of lower-level programming and I'm learning as I go. I'd really like my next game to use the printer and I feel like it's *almost* there.

edit: if I change &pic_tiles[bgtile] to just &pic_tiles in the memcpy call, I get a full-sized (160x144) light gray image...

edit2: I looked at the Game Boy Programming manual at how the printer receives data packets, so now the function at least makes sense, I'm trying to figure out if anything in here isn't working properly.

Last edited by Scazon (2015-06-17 15:02:03)

Offline

 

#8 2015-06-17 21:45:31

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Re: Anyone have experience with the GB Printer?

Looking at main(), I think index should be a UWORD? Because there's 360 tiles total, and the index would wrap around at 255 if it were only one byte.

I don't know if that wraparound error is causing any problems (because it seems it should still print, but that the bottom of the image would be a duplicate of the first few rows). But either way, even if I declare it as UWORD, I wrote some debugging print statements that indicate it's still wrapping around at 255.

Also, when calculating the checksum portion of the packet, it's supposed to be 2 bytes that represent the sum of the header and all contents of the data, but aren't you sending like 640 bytes of data per packet? (40 tiles * 16 bytes per tile). How can the checksum possibly contain that information with only 2 bytes? Unless I'm reading that part wrong..

Last edited by Scazon (2015-06-17 22:57:30)

Offline

 

#9 2015-06-18 05:09:14

Tauwasser
Member
Registered: 2010-10-23
Posts: 160

Re: Anyone have experience with the GB Printer?

Scazon wrote:

Looking at main(), I think index should be a UWORD? Because there's 360 tiles total, and the index would wrap around at 255 if it were only one byte.

Yep, I didn't think that 18 by 20 might be >=256 wink.

Scazon wrote:

I don't know if that wraparound error is causing any problems (because it seems it should still print, but that the bottom of the image would be a duplicate of the first few rows).

It is a problem. But your analysis is correct, it should print the top half of the image twice.

Scazon wrote:

But either way, even if I declare it as UWORD, I wrote some debugging print statements that indicate it's still wrapping around at 255.

Try not doing index++ inside the pic_map[index++] statement. Instead, do pic_map[index]; index = index + 1; Maybe GBDK is doing a byte-increment only? Check the lss file to know for sure. Or disassemble the code and post it.

Scazon wrote:

Also, when calculating the checksum portion of the packet, it's supposed to be 2 bytes that represent the sum of the header and all contents of the data, but aren't you sending like 640 bytes of data per packet? (40 tiles * 16 bytes per tile). How can the checksum possibly contain that information with only 2 bytes? Unless I'm reading that part wrong..

Haven't looked at that part yet. But we copy 0x10 bytes (1 tile) to p_data, then call PrintTileData(p_data), so it shouldn't be 0x40 tiles per packet.

cYa,

Tauwasser

Offline

 

#10 2015-06-18 10:07:50

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Re: Anyone have experience with the GB Printer?

Tauwasser wrote:

But we copy 0x10 bytes (1 tile) to p_data, then call PrintTileData(p_data), so it shouldn't be 0x40 tiles per packet.

Not 0x40, but 40 tiles (2 horizontal lines of tiles per packet)

We copy 0x10 bytes to p_data, but we loop that in main(), (the nested for loops py<18, px<20, 360 tiles total for the whole screen). PrintTileData() collects the tile data, but doesn't actually end the packet until it's received 40 tiles' worth of data, and doesn't start printing until it receives all 9 packets.

In PrntCmd.c in PrintTileData(), there's a global counter that's counting tiles sent. At tile_num==40 (two lines of data, i.e. 1 packet), we send the end packet data (checksum and dummy bytes) and then when packet == 9 (9*2 lines per packet, or 18 horizontal lines total), we send the final start printing instruction.

The 5th and 6th byte of the packet header (PRINT_TILE) represent the amount of data to be sent in the packet, which says here 0x80 and 0x02 which is 640 bytes (0x0280).

Last edited by Scazon (2015-06-18 10:09:13)

Offline

 

#11 2015-06-18 12:18:36

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Re: Anyone have experience with the GB Printer?

AHH ok I'm onto something. I did a complete rewrite of how the printer status is saved (because I don't think the original one was working as intended? And also I wanted to see if there were any errors in the status that weren't showing up). The CheckPrinterStatus and CheckForErrors functions were pretty much useless.

Anyway, I changed it so the PrinterStatus[] array is only two bytes (as it should be) and had it update only when sending one of the dummy bytes in a packet (because that's when the status is received). The first byte should always be 0x81, indicating the printer is connected, and the second byte should be 0 when everything's ok (with other bits giving different errors).

It managed to print this beautiful thing (I changed the default image data to my avatar):
https://i.imgur.com/Pl9RRLj.png

So now I'm getting somewhere.

edit: i think the tile glitches are due to both index and bgtile wrapping at 255, which I still can't correct.

Last edited by Scazon (2015-06-18 12:41:41)

Offline

 

#12 2015-06-18 14:16:20

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Re: Anyone have experience with the GB Printer?

Yeah, something is going strange with the index and bgtile variables.

Here's a bit of the code from main();
https://i.imgur.com/ziyFW7s.png

If I comment out the print statement, then I get the image above (which indicates that both bgtile and index are wrapping around).

If I leave in the print statement, the image 'corrects' itself (bgtile is now working, but index is still wrapping), which is verified by what the print statements actually print out as well.

https://i.imgur.com/Z1Bi5l0.png

Offline

 

#13 2015-06-18 16:53:35

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Re: Anyone have experience with the GB Printer?

SUCCESS!

https://i.imgur.com/7L6iMa0l.jpg

Wanna know how I fixed the overflow error?

Code:

if (index == 255){
  index = (UWORD)256;
} else {
  index = index + 1;
}

I'd like to know if there's a more reliable way to increment past 255, otherwise this is what I got.

Either way, thanks for the help! Now I can get started on my game. I'll probably also clean this up and post it as a 'newer' version of the printlib, since I had to make so many changes to it. I also want to change it to be able to easily print strings, and print one line at a time instead of waiting for a whole page.

Offline

 

#14 2015-06-19 19:04:32

Tauwasser
Member
Registered: 2010-10-23
Posts: 160

Re: Anyone have experience with the GB Printer?

Congratulations on making it work smile

That's most likely a bug in gbdk then, which is very weird, because it'S a very specific edge case to get wrong.

I suspect that something is up with timing. Your print statement takes some time in order to print the string. If you take it out, the look will call PrintTileData much more rapidly. There is probably some code missing to check if the printer is ready to accept new data.

It might be worth writing this printer information down for the next guy wink

cYa,

Tauwasser

Offline

 

#15 2015-06-20 16:32:57

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Re: Anyone have experience with the GB Printer?

My only doubt about that issue is that the code technically does wait for it to be ready to receive more data (the send byte function waits until the 7th bit of sc_reg to reset, meaning the serial transfer is complete). You do have to make sure the printer is physically ready before sending another print instruction (i.e. sending print data while it's still physically printing), but that doesn't happen in my code because it only sends 1 print instruction. There could still be a timing issue somewhere else though. I was having similar issues when trying to get it to print text (one char tile at a time)-- it would randomly replace some characters with others.. but I haven't seen a consistent pattern yet to figure out what's wrong.

I definitely want to redocument all this printer code, but I want to get a better library working before I do that. The game I want to make is gonna be a kind of interactive fiction, so I need to rework it to print text, and print single lines instead of whole images.

Doing that has been relatively easy so far, now that I got the bulk of it out of the way. Still trying to work out line feeds so that there isn't so much space between single lines of text (there's a certain way you have to send line feed data that's just a bunch of trial and error to test). I accidentally misplaced a bit and ended up with 18 printed lines of "Hello World!" when I just wanted one.

I did manage to get this, though, so it's coming along.

https://i.imgur.com/cnwbhMF.jpg

Offline

 

#16 2015-06-20 17:49:18

Tauwasser
Member
Registered: 2010-10-23
Posts: 160

Re: Anyone have experience with the GB Printer?

Scazon wrote:

My only doubt about that issue is that the code technically does wait for it to be ready to receive more data (the send byte function waits until the 7th bit of sc_reg to reset, meaning the serial transfer is complete).

But that's only the serial transfer part. The printer might need time to copy data from its serial input buffer to the printer graphics buffer. So if you keep sending data when the printer hasn't moved the old data yet, you'll overwrite part of last transfer frame's data. Call GetPrinterStatus after every SendPrinterCommand(PRINTER_EOF), put the codes into an array, then print the array. The PrinterStatus registers are never fully analyzed, so there might be a bit there that shows the printer's busy.

Scazon wrote:

I definitely want to redocument all this printer code, but I want to get a better library working before I do that. The game I want to make is gonna be a kind of interactive fiction, so I need to rework it to print text, and print single lines instead of whole images.

Good. Also nice progress you're making. I wonder how many people actually still have usable printer paper though. I know I have a printer boxed somewhere with one roll of paper -- and I'm not sure it's still good.

cYa,

Tauwasser

Offline

 

#17 2015-06-20 18:03:39

Scazon
Member
From: Boston, MA
Registered: 2015-06-14
Posts: 24
Website

Re: Anyone have experience with the GB Printer?

The printercommand(PRINTER_EOF) is only called once during a full screen print (at the end of ALL the tile data transfers). I rewrote the printerstatus function to update after every packet sent (20 tiles when printing a whole image, or 10 tiles when printing one line).

On the emulator, the status received indicates everything is alright. When I run it on the gameboy, it returns 8, which means "Unprocessed data present". So I guess that's it. Unsure how to resolve it though. Would it be just pinging the printer with status updates until it comes back clear? I'll try that. But also, the above printed alright even though it came back with that status, so I dunno.

Tauwasser wrote:

I wonder how many people actually still have usable printer paper though. I know I have a printer boxed somewhere with one roll of paper -- and I'm not sure it's still good.

All original printer paper should be expired by now. I have a few rolls, and they print spotty and faded. But because the printer is just a glorified thermal printer, you can use any old 1.5" receipt paper (or cut a longer roll to size). I got my rolls off Amazon here and it works fine.

Last edited by Scazon (2015-06-20 18:08:40)

Offline

 

#18 2016-01-24 06:21:36

Joancz
New member
Registered: 2016-01-19
Posts: 1

Re: Anyone have experience with the GB Printer?

Hello,

First sorry for my bad english, i'm french smile

I have a problem with the printlib. i can compile my sourcecode, but that's all. Visual boy launch the GBrinter output image but it's all white. My real printer react to my roms, but don't print image...

If someone can ahve a look at my source code and help me smile

http://www.partage-facile.com/ZNU7ALAJG … b.rar.html


Thank you wink

Last edited by Joancz (2016-01-24 06:27:19)

Offline

 

#19 2021-08-25 16:14:58

T0biasCZe
New member
Registered: 2021-08-15
Posts: 4

Re: Anyone have experience with the GB Printer?

Joancz wrote:

Hello,

First sorry for my bad english, i'm french smile

I have a problem with the printlib. i can compile my sourcecode, but that's all. Visual boy launch the GBrinter output image but it's all white. My real printer react to my roms, but don't print image...

If someone can ahve a look at my source code and help me smile

http://www.partage-facile.com/ZNU7ALAJG … b.rar.html


Thank you wink

i fixed the code, so it compiles in GBDK 2020
https://drive.google.com/file/d/1pEHIUL … sp=sharing

Offline

 

Board footer

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson