mirror of https://github.com/LIJI32/SameBoy.git
Emulate GB printer timer, letting one emulate the mini game in Hello Kitty Pocket Camera. Closes #290
This commit is contained in:
parent
c06e320b95
commit
d5ff93af3b
|
@ -35,6 +35,7 @@
|
||||||
@property (nonatomic, strong) IBOutlet GBPaletteView *paletteView;
|
@property (nonatomic, strong) IBOutlet GBPaletteView *paletteView;
|
||||||
@property (nonatomic, strong) IBOutlet GBObjectView *objectView;
|
@property (nonatomic, strong) IBOutlet GBObjectView *objectView;
|
||||||
@property (nonatomic, strong) IBOutlet NSPanel *printerFeedWindow;
|
@property (nonatomic, strong) IBOutlet NSPanel *printerFeedWindow;
|
||||||
|
@property (nonatomic, strong) IBOutlet NSProgressIndicator *printerSpinner;
|
||||||
@property (nonatomic, strong) IBOutlet NSImageView *feedImageView;
|
@property (nonatomic, strong) IBOutlet NSImageView *feedImageView;
|
||||||
@property (nonatomic, strong) IBOutlet NSTextView *debuggerSideViewInput;
|
@property (nonatomic, strong) IBOutlet NSTextView *debuggerSideViewInput;
|
||||||
@property (nonatomic, strong) IBOutlet NSTextView *debuggerSideView;
|
@property (nonatomic, strong) IBOutlet NSTextView *debuggerSideView;
|
||||||
|
|
|
@ -180,6 +180,12 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
||||||
[self printImage:image height:height topMargin:top_margin bottomMargin:bottom_margin exposure:exposure];
|
[self printImage:image height:height topMargin:top_margin bottomMargin:bottom_margin exposure:exposure];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void printDone(GB_gameboy_t *gb)
|
||||||
|
{
|
||||||
|
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||||
|
[self printDone];
|
||||||
|
}
|
||||||
|
|
||||||
static void setWorkboyTime(GB_gameboy_t *gb, time_t t)
|
static void setWorkboyTime(GB_gameboy_t *gb, time_t t)
|
||||||
{
|
{
|
||||||
[[NSUserDefaults standardUserDefaults] setInteger:time(NULL) - t forKey:@"GBWorkboyTimeOffset"];
|
[[NSUserDefaults standardUserDefaults] setInteger:time(NULL) - t forKey:@"GBWorkboyTimeOffset"];
|
||||||
|
@ -2060,7 +2066,7 @@ static bool is_path_writeable(const char *path)
|
||||||
[self reloadVRAMData: nil];
|
[self reloadVRAMData: nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) printImage:(uint32_t *)imageBytes height:(unsigned) height
|
- (void)printImage:(uint32_t *)imageBytes height:(unsigned) height
|
||||||
topMargin:(unsigned) topMargin bottomMargin: (unsigned) bottomMargin
|
topMargin:(unsigned) topMargin bottomMargin: (unsigned) bottomMargin
|
||||||
exposure:(unsigned) exposure
|
exposure:(unsigned) exposure
|
||||||
{
|
{
|
||||||
|
@ -2073,6 +2079,7 @@ static bool is_path_writeable(const char *path)
|
||||||
[currentPrinterImageData appendBytes:paddedImage length:sizeof(paddedImage)];
|
[currentPrinterImageData appendBytes:paddedImage length:sizeof(paddedImage)];
|
||||||
/* UI related code must run on main thread. */
|
/* UI related code must run on main thread. */
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[_printerSpinner startAnimation:nil];
|
||||||
self.feedImageView.image = [Document imageFromData:currentPrinterImageData
|
self.feedImageView.image = [Document imageFromData:currentPrinterImageData
|
||||||
width:160
|
width:160
|
||||||
height:currentPrinterImageData.length / 160 / sizeof(imageBytes[0])
|
height:currentPrinterImageData.length / 160 / sizeof(imageBytes[0])
|
||||||
|
@ -2087,6 +2094,13 @@ static bool is_path_writeable(const char *path)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)printDone
|
||||||
|
{
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[_printerSpinner stopAnimation:nil];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
- (void)printDocument:(id)sender
|
- (void)printDocument:(id)sender
|
||||||
{
|
{
|
||||||
if (self.feedImageView.image.size.height == 0) {
|
if (self.feedImageView.image.size.height == 0) {
|
||||||
|
@ -2135,7 +2149,7 @@ static bool is_path_writeable(const char *path)
|
||||||
[self disconnectLinkCable];
|
[self disconnectLinkCable];
|
||||||
[self performAtomicBlock:^{
|
[self performAtomicBlock:^{
|
||||||
accessory = GBAccessoryPrinter;
|
accessory = GBAccessoryPrinter;
|
||||||
GB_connect_printer(&gb, printImage);
|
GB_connect_printer(&gb, printImage, printDone);
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
<outlet property="osdView" destination="MX4-l2-7NE" id="Am7-fq-uvu"/>
|
<outlet property="osdView" destination="MX4-l2-7NE" id="Am7-fq-uvu"/>
|
||||||
<outlet property="paletteView" destination="ZuP-AU-0pA" id="ef6-27-Bci"/>
|
<outlet property="paletteView" destination="ZuP-AU-0pA" id="ef6-27-Bci"/>
|
||||||
<outlet property="printerFeedWindow" destination="NdE-0B-WCf" id="yVK-cS-NOJ"/>
|
<outlet property="printerFeedWindow" destination="NdE-0B-WCf" id="yVK-cS-NOJ"/>
|
||||||
|
<outlet property="printerSpinner" destination="rrz-Uh-Nae" id="CI8-Y2-s3l"/>
|
||||||
<outlet property="tilemapImageView" destination="LlK-tV-bjv" id="nSY-Xd-BjZ"/>
|
<outlet property="tilemapImageView" destination="LlK-tV-bjv" id="nSY-Xd-BjZ"/>
|
||||||
<outlet property="tilemapMapButton" destination="YIJ-Qc-SIZ" id="BB7-Gg-7XP"/>
|
<outlet property="tilemapMapButton" destination="YIJ-Qc-SIZ" id="BB7-Gg-7XP"/>
|
||||||
<outlet property="tilemapPaletteButton" destination="loB-0k-Qff" id="2Or-7l-6vn"/>
|
<outlet property="tilemapPaletteButton" destination="loB-0k-Qff" id="2Or-7l-6vn"/>
|
||||||
|
@ -680,11 +681,19 @@
|
||||||
<toolbarItem implicitItemIdentifier="NSToolbarPrintItem" explicitItemIdentifier="Print" id="mtd-zS-DXa"/>
|
<toolbarItem implicitItemIdentifier="NSToolbarPrintItem" explicitItemIdentifier="Print" id="mtd-zS-DXa"/>
|
||||||
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="AoG-LH-J4b"/>
|
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="AoG-LH-J4b"/>
|
||||||
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="Q0x-n5-Q2Y"/>
|
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="Q0x-n5-Q2Y"/>
|
||||||
|
<toolbarItem implicitItemIdentifier="E8F74F8F-6DE2-4774-A690-F71D92CD932E" label="" paletteLabel="" tag="-1" sizingBehavior="auto" id="CJX-Ff-7iQ">
|
||||||
|
<nil key="toolTip"/>
|
||||||
|
<progressIndicator key="view" wantsLayer="YES" maxValue="100" displayedWhenStopped="NO" indeterminate="YES" style="spinning" id="rrz-Uh-Nae">
|
||||||
|
<rect key="frame" x="0.0" y="14" width="32" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
</progressIndicator>
|
||||||
|
</toolbarItem>
|
||||||
</allowedToolbarItems>
|
</allowedToolbarItems>
|
||||||
<defaultToolbarItems>
|
<defaultToolbarItems>
|
||||||
<toolbarItem reference="CBz-1N-o0Q"/>
|
<toolbarItem reference="CBz-1N-o0Q"/>
|
||||||
<toolbarItem reference="Q0x-n5-Q2Y"/>
|
|
||||||
<toolbarItem reference="mtd-zS-DXa"/>
|
<toolbarItem reference="mtd-zS-DXa"/>
|
||||||
|
<toolbarItem reference="Q0x-n5-Q2Y"/>
|
||||||
|
<toolbarItem reference="CJX-Ff-7iQ"/>
|
||||||
</defaultToolbarItems>
|
</defaultToolbarItems>
|
||||||
</toolbar>
|
</toolbar>
|
||||||
<point key="canvasLocation" x="-159" y="356"/>
|
<point key="canvasLocation" x="-159" y="356"/>
|
||||||
|
|
|
@ -710,6 +710,7 @@ struct GB_gameboy_internal_s {
|
||||||
GB_write_memory_callback_t write_memory_callback;
|
GB_write_memory_callback_t write_memory_callback;
|
||||||
GB_boot_rom_load_callback_t boot_rom_load_callback;
|
GB_boot_rom_load_callback_t boot_rom_load_callback;
|
||||||
GB_print_image_callback_t printer_callback;
|
GB_print_image_callback_t printer_callback;
|
||||||
|
GB_printer_done_callback_t printer_done_callback;
|
||||||
GB_workboy_set_time_callback workboy_set_time_callback;
|
GB_workboy_set_time_callback workboy_set_time_callback;
|
||||||
GB_workboy_get_time_callback workboy_get_time_callback;
|
GB_workboy_get_time_callback workboy_get_time_callback;
|
||||||
GB_execution_callback_t execution_callback;
|
GB_execution_callback_t execution_callback;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
have my own GB Printer to figure it out myself.
|
have my own GB Printer to figure it out myself.
|
||||||
|
|
||||||
It also does not currently emulate communication timeout, which means that a bug
|
It also does not currently emulate communication timeout, which means that a bug
|
||||||
might prevent the printer operation until the GameBoy is restarted.
|
might prevent the printer operation until the Game Boy is restarted.
|
||||||
|
|
||||||
Also, field mask values are assumed. */
|
Also, field mask values are assumed. */
|
||||||
|
|
||||||
|
@ -30,6 +30,9 @@ static void handle_command(GB_gameboy_t *gb)
|
||||||
image[i] = colors[(palette >> (gb->printer.image[i] * 2)) & 3];
|
image[i] = colors[(palette >> (gb->printer.image[i] * 2)) & 3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// One second per 8-pixel row
|
||||||
|
gb->printer.time_remaining = gb->printer.image_offset / 160 * GB_get_unmultiplied_clock_rate(gb) / 256 / 8;
|
||||||
|
|
||||||
if (gb->printer_callback) {
|
if (gb->printer_callback) {
|
||||||
gb->printer_callback(gb, image, gb->printer.image_offset / 160,
|
gb->printer_callback(gb, image, gb->printer.image_offset / 160,
|
||||||
gb->printer.command_data[1] >> 4, gb->printer.command_data[1] & 7,
|
gb->printer.command_data[1] >> 4, gb->printer.command_data[1] & 7,
|
||||||
|
@ -70,7 +73,7 @@ static void handle_command(GB_gameboy_t *gb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void byte_recieve_completed(GB_gameboy_t *gb, uint8_t byte_received)
|
static void byte_receive_completed(GB_gameboy_t *gb, uint8_t byte_received)
|
||||||
{
|
{
|
||||||
gb->printer.byte_to_send = 0;
|
gb->printer.byte_to_send = 0;
|
||||||
switch (gb->printer.command_state) {
|
switch (gb->printer.command_state) {
|
||||||
|
@ -156,16 +159,13 @@ static void byte_recieve_completed(GB_gameboy_t *gb, uint8_t byte_received)
|
||||||
gb->printer.byte_to_send = 0;
|
gb->printer.byte_to_send = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (gb->printer.status == 6 && gb->printer.time_remaining == 0) {
|
||||||
|
gb->printer.status = 4; /* Done */
|
||||||
|
}
|
||||||
gb->printer.byte_to_send = gb->printer.status;
|
gb->printer.byte_to_send = gb->printer.status;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GB_PRINTER_COMMAND_STATUS:
|
case GB_PRINTER_COMMAND_STATUS:
|
||||||
|
|
||||||
/* Printing is done instantly, but let the game recieve a 6 (Printing) status at least once, for compatibility */
|
|
||||||
if (gb->printer.status == 6) {
|
|
||||||
gb->printer.status = 4; /* Done */
|
|
||||||
}
|
|
||||||
|
|
||||||
gb->printer.command_state = GB_PRINTER_COMMAND_MAGIC1;
|
gb->printer.command_state = GB_PRINTER_COMMAND_MAGIC1;
|
||||||
handle_command(gb);
|
handle_command(gb);
|
||||||
return;
|
return;
|
||||||
|
@ -197,7 +197,7 @@ static void serial_start(GB_gameboy_t *gb, bool bit_received)
|
||||||
gb->printer.byte_being_received |= bit_received;
|
gb->printer.byte_being_received |= bit_received;
|
||||||
gb->printer.bits_received++;
|
gb->printer.bits_received++;
|
||||||
if (gb->printer.bits_received == 8) {
|
if (gb->printer.bits_received == 8) {
|
||||||
byte_recieve_completed(gb, gb->printer.byte_being_received);
|
byte_receive_completed(gb, gb->printer.byte_being_received);
|
||||||
gb->printer.bits_received = 0;
|
gb->printer.bits_received = 0;
|
||||||
gb->printer.byte_being_received = 0;
|
gb->printer.byte_being_received = 0;
|
||||||
}
|
}
|
||||||
|
@ -211,10 +211,11 @@ static bool serial_end(GB_gameboy_t *gb)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GB_connect_printer(GB_gameboy_t *gb, GB_print_image_callback_t callback)
|
void GB_connect_printer(GB_gameboy_t *gb, GB_print_image_callback_t callback, GB_printer_done_callback_t done_callback)
|
||||||
{
|
{
|
||||||
memset(&gb->printer, 0, sizeof(gb->printer));
|
memset(&gb->printer, 0, sizeof(gb->printer));
|
||||||
GB_set_serial_transfer_bit_start_callback(gb, serial_start);
|
GB_set_serial_transfer_bit_start_callback(gb, serial_start);
|
||||||
GB_set_serial_transfer_bit_end_callback(gb, serial_end);
|
GB_set_serial_transfer_bit_end_callback(gb, serial_end);
|
||||||
gb->printer_callback = callback;
|
gb->printer_callback = callback;
|
||||||
|
gb->printer_done_callback = done_callback;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ typedef void (*GB_print_image_callback_t)(GB_gameboy_t *gb,
|
||||||
uint8_t bottom_margin,
|
uint8_t bottom_margin,
|
||||||
uint8_t exposure);
|
uint8_t exposure);
|
||||||
|
|
||||||
|
typedef void (*GB_printer_done_callback_t)(GB_gameboy_t *gb);
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -56,8 +58,9 @@ typedef struct
|
||||||
uint8_t bits_received;
|
uint8_t bits_received;
|
||||||
uint8_t byte_being_received;
|
uint8_t byte_being_received;
|
||||||
bool bit_to_send;
|
bool bit_to_send;
|
||||||
|
uint64_t time_remaining;
|
||||||
} GB_printer_t;
|
} GB_printer_t;
|
||||||
|
|
||||||
|
|
||||||
void GB_connect_printer(GB_gameboy_t *gb, GB_print_image_callback_t callback);
|
void GB_connect_printer(GB_gameboy_t *gb, GB_print_image_callback_t callback, GB_printer_done_callback_t done_callback);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -165,8 +165,22 @@ static void increase_tima(GB_gameboy_t *gb)
|
||||||
|
|
||||||
void GB_serial_master_edge(GB_gameboy_t *gb)
|
void GB_serial_master_edge(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
if (unlikely(gb->printer_callback && (gb->printer.command_state || gb->printer.bits_received))) {
|
if (gb->printer_callback) {
|
||||||
gb->printer.idle_time += 1 << gb->serial_mask;
|
unsigned ticks = 1 << gb->serial_mask;
|
||||||
|
if (unlikely((gb->printer.command_state || gb->printer.bits_received))) {
|
||||||
|
gb->printer.idle_time +=ticks;
|
||||||
|
}
|
||||||
|
if (unlikely(gb->printer.time_remaining)) {
|
||||||
|
if (gb->printer.time_remaining <= ticks) {
|
||||||
|
gb->printer.time_remaining = 0;
|
||||||
|
if (gb->printer_done_callback) {
|
||||||
|
gb->printer_done_callback(gb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gb->printer.time_remaining -= ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gb->serial_master_clock ^= true;
|
gb->serial_master_clock ^= true;
|
||||||
|
|
Loading…
Reference in New Issue