Workboy emulation (Cocoa only)
This commit is contained in:
parent
e35c22d405
commit
7ff3556bc3
@ -47,7 +47,7 @@ enum model {
|
|||||||
bool oamUpdating;
|
bool oamUpdating;
|
||||||
|
|
||||||
NSMutableData *currentPrinterImageData;
|
NSMutableData *currentPrinterImageData;
|
||||||
enum {GBAccessoryNone, GBAccessoryPrinter} accessory;
|
enum {GBAccessoryNone, GBAccessoryPrinter, GBAccessoryWorkboy} accessory;
|
||||||
|
|
||||||
bool rom_warning_issued;
|
bool rom_warning_issued;
|
||||||
|
|
||||||
@ -138,6 +138,16 @@ 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 setWorkboyTime(GB_gameboy_t *gb, time_t t)
|
||||||
|
{
|
||||||
|
[[NSUserDefaults standardUserDefaults] setInteger:time(NULL) - t forKey:@"GBWorkboyTimeOffset"];
|
||||||
|
}
|
||||||
|
|
||||||
|
static time_t getWorkboyTime(GB_gameboy_t *gb)
|
||||||
|
{
|
||||||
|
return time(NULL) - [[NSUserDefaults standardUserDefaults] integerForKey:@"GBWorkboyTimeOffset"];
|
||||||
|
}
|
||||||
|
|
||||||
static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample)
|
static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample)
|
||||||
{
|
{
|
||||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||||
@ -791,6 +801,9 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||||||
else if ([anItem action] == @selector(connectPrinter:)) {
|
else if ([anItem action] == @selector(connectPrinter:)) {
|
||||||
[(NSMenuItem*)anItem setState:accessory == GBAccessoryPrinter];
|
[(NSMenuItem*)anItem setState:accessory == GBAccessoryPrinter];
|
||||||
}
|
}
|
||||||
|
else if ([anItem action] == @selector(connectWorkboy:)) {
|
||||||
|
[(NSMenuItem*)anItem setState:accessory == GBAccessoryWorkboy];
|
||||||
|
}
|
||||||
else if ([anItem action] == @selector(toggleCheats:)) {
|
else if ([anItem action] == @selector(toggleCheats:)) {
|
||||||
[(NSMenuItem*)anItem setState:GB_cheats_enabled(&gb)];
|
[(NSMenuItem*)anItem setState:GB_cheats_enabled(&gb)];
|
||||||
}
|
}
|
||||||
@ -1701,6 +1714,14 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (IBAction)connectWorkboy:(id)sender
|
||||||
|
{
|
||||||
|
[self performAtomicBlock:^{
|
||||||
|
accessory = GBAccessoryWorkboy;
|
||||||
|
GB_connect_workboy(&gb, setWorkboyTime, getWorkboyTime);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
- (void) updateHighpassFilter
|
- (void) updateHighpassFilter
|
||||||
{
|
{
|
||||||
if (GB_is_inited(&gb)) {
|
if (GB_is_inited(&gb)) {
|
||||||
|
115
Cocoa/GBView.m
115
Cocoa/GBView.m
@ -1,4 +1,5 @@
|
|||||||
#import <IOKit/pwr_mgt/IOPMLib.h>
|
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||||
|
#import <Carbon/Carbon.h>
|
||||||
#import "GBView.h"
|
#import "GBView.h"
|
||||||
#import "GBViewGL.h"
|
#import "GBViewGL.h"
|
||||||
#import "GBViewMetal.h"
|
#import "GBViewMetal.h"
|
||||||
@ -8,6 +9,98 @@
|
|||||||
#define JOYSTICK_HIGH 0x4000
|
#define JOYSTICK_HIGH 0x4000
|
||||||
#define JOYSTICK_LOW 0x3800
|
#define JOYSTICK_LOW 0x3800
|
||||||
|
|
||||||
|
static const uint8_t workboy_ascii_to_key[] = {
|
||||||
|
['0'] = GB_WORKBOY_0,
|
||||||
|
['`'] = GB_WORKBOY_UMLAUT,
|
||||||
|
['1'] = GB_WORKBOY_1,
|
||||||
|
['2'] = GB_WORKBOY_2,
|
||||||
|
['3'] = GB_WORKBOY_3,
|
||||||
|
['4'] = GB_WORKBOY_4,
|
||||||
|
['5'] = GB_WORKBOY_5,
|
||||||
|
['6'] = GB_WORKBOY_6,
|
||||||
|
['7'] = GB_WORKBOY_7,
|
||||||
|
['8'] = GB_WORKBOY_8,
|
||||||
|
['9'] = GB_WORKBOY_9,
|
||||||
|
|
||||||
|
['\r'] = GB_WORKBOY_ENTER,
|
||||||
|
[3] = GB_WORKBOY_ENTER,
|
||||||
|
|
||||||
|
['!'] = GB_WORKBOY_EXCLAMATION_MARK,
|
||||||
|
['$'] = GB_WORKBOY_DOLLAR,
|
||||||
|
['#'] = GB_WORKBOY_HASH,
|
||||||
|
['~'] = GB_WORKBOY_TILDE,
|
||||||
|
['*'] = GB_WORKBOY_ASTERISK,
|
||||||
|
['+'] = GB_WORKBOY_PLUS,
|
||||||
|
['-'] = GB_WORKBOY_MINUS,
|
||||||
|
['('] = GB_WORKBOY_LEFT_PARENTHESIS,
|
||||||
|
[')'] = GB_WORKBOY_RIGHT_PARENTHESIS,
|
||||||
|
[';'] = GB_WORKBOY_SEMICOLON,
|
||||||
|
[':'] = GB_WORKBOY_COLON,
|
||||||
|
['%'] = GB_WORKBOY_PERCENT,
|
||||||
|
['='] = GB_WORKBOY_EQUAL,
|
||||||
|
[','] = GB_WORKBOY_COMMA,
|
||||||
|
['<'] = GB_WORKBOY_LT,
|
||||||
|
['.'] = GB_WORKBOY_DOT,
|
||||||
|
['>'] = GB_WORKBOY_GT,
|
||||||
|
['/'] = GB_WORKBOY_SLASH,
|
||||||
|
['?'] = GB_WORKBOY_QUESTION_MARK,
|
||||||
|
[' '] = GB_WORKBOY_SPACE,
|
||||||
|
['\''] = GB_WORKBOY_QUOTE,
|
||||||
|
['@'] = GB_WORKBOY_AT,
|
||||||
|
|
||||||
|
['q'] = GB_WORKBOY_Q,
|
||||||
|
['w'] = GB_WORKBOY_W,
|
||||||
|
['e'] = GB_WORKBOY_E,
|
||||||
|
['r'] = GB_WORKBOY_R,
|
||||||
|
['t'] = GB_WORKBOY_T,
|
||||||
|
['y'] = GB_WORKBOY_Y,
|
||||||
|
['u'] = GB_WORKBOY_U,
|
||||||
|
['i'] = GB_WORKBOY_I,
|
||||||
|
['o'] = GB_WORKBOY_O,
|
||||||
|
['p'] = GB_WORKBOY_P,
|
||||||
|
['a'] = GB_WORKBOY_A,
|
||||||
|
['s'] = GB_WORKBOY_S,
|
||||||
|
['d'] = GB_WORKBOY_D,
|
||||||
|
['f'] = GB_WORKBOY_F,
|
||||||
|
['g'] = GB_WORKBOY_G,
|
||||||
|
['h'] = GB_WORKBOY_H,
|
||||||
|
['j'] = GB_WORKBOY_J,
|
||||||
|
['k'] = GB_WORKBOY_K,
|
||||||
|
['l'] = GB_WORKBOY_L,
|
||||||
|
['z'] = GB_WORKBOY_Z,
|
||||||
|
['x'] = GB_WORKBOY_X,
|
||||||
|
['c'] = GB_WORKBOY_C,
|
||||||
|
['v'] = GB_WORKBOY_V,
|
||||||
|
['b'] = GB_WORKBOY_B,
|
||||||
|
['n'] = GB_WORKBOY_N,
|
||||||
|
['m'] = GB_WORKBOY_M,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t workboy_vk_to_key[] = {
|
||||||
|
[kVK_F1] = GB_WORKBOY_CLOCK,
|
||||||
|
[kVK_F2] = GB_WORKBOY_TEMPERATURE,
|
||||||
|
[kVK_F3] = GB_WORKBOY_MONEY,
|
||||||
|
[kVK_F4] = GB_WORKBOY_CALCULATOR,
|
||||||
|
[kVK_F5] = GB_WORKBOY_DATE,
|
||||||
|
[kVK_F6] = GB_WORKBOY_CONVERSION,
|
||||||
|
[kVK_F7] = GB_WORKBOY_RECORD,
|
||||||
|
[kVK_F8] = GB_WORKBOY_WORLD,
|
||||||
|
[kVK_F9] = GB_WORKBOY_PHONE,
|
||||||
|
[kVK_F10] = GB_WORKBOY_UNKNOWN,
|
||||||
|
[kVK_Delete] = GB_WORKBOY_BACKSPACE,
|
||||||
|
[kVK_Shift] = GB_WORKBOY_SHIFT_DOWN,
|
||||||
|
[kVK_RightShift] = GB_WORKBOY_SHIFT_DOWN,
|
||||||
|
[kVK_UpArrow] = GB_WORKBOY_UP,
|
||||||
|
[kVK_DownArrow] = GB_WORKBOY_DOWN,
|
||||||
|
[kVK_LeftArrow] = GB_WORKBOY_LEFT,
|
||||||
|
[kVK_RightArrow] = GB_WORKBOY_RIGHT,
|
||||||
|
[kVK_Escape] = GB_WORKBOY_ESCAPE,
|
||||||
|
[kVK_ANSI_KeypadDecimal] = GB_WORKBOY_DECIMAL_POINT,
|
||||||
|
[kVK_ANSI_KeypadClear] = GB_WORKBOY_M,
|
||||||
|
[kVK_ANSI_KeypadMultiply] = GB_WORKBOY_H,
|
||||||
|
[kVK_ANSI_KeypadDivide] = GB_WORKBOY_J,
|
||||||
|
};
|
||||||
|
|
||||||
@implementation GBView
|
@implementation GBView
|
||||||
{
|
{
|
||||||
uint32_t *image_buffers[3];
|
uint32_t *image_buffers[3];
|
||||||
@ -188,7 +281,20 @@
|
|||||||
|
|
||||||
-(void)keyDown:(NSEvent *)theEvent
|
-(void)keyDown:(NSEvent *)theEvent
|
||||||
{
|
{
|
||||||
|
if ([theEvent type] != NSEventTypeFlagsChanged && theEvent.isARepeat) return;
|
||||||
unsigned short keyCode = theEvent.keyCode;
|
unsigned short keyCode = theEvent.keyCode;
|
||||||
|
if (GB_workboy_is_enabled(_gb)) {
|
||||||
|
if (theEvent.keyCode < sizeof(workboy_vk_to_key) && workboy_vk_to_key[theEvent.keyCode]) {
|
||||||
|
GB_workboy_set_key(_gb, workboy_vk_to_key[theEvent.keyCode]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unichar c = [theEvent type] != NSEventTypeFlagsChanged? [theEvent.charactersIgnoringModifiers.lowercaseString characterAtIndex:0] : 0;
|
||||||
|
if (c < sizeof(workboy_ascii_to_key) && workboy_ascii_to_key[c]) {
|
||||||
|
GB_workboy_set_key(_gb, workboy_ascii_to_key[c]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
|
|
||||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
@ -232,6 +338,15 @@
|
|||||||
-(void)keyUp:(NSEvent *)theEvent
|
-(void)keyUp:(NSEvent *)theEvent
|
||||||
{
|
{
|
||||||
unsigned short keyCode = theEvent.keyCode;
|
unsigned short keyCode = theEvent.keyCode;
|
||||||
|
if (GB_workboy_is_enabled(_gb)) {
|
||||||
|
if (keyCode == kVK_Shift || keyCode == kVK_RightShift) {
|
||||||
|
GB_workboy_set_key(_gb, GB_WORKBOY_SHIFT_UP);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GB_workboy_set_key(_gb, GB_WORKBOY_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
|
|
||||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
@ -379,6 +379,12 @@
|
|||||||
<action selector="connectPrinter:" target="-1" id="tl1-CL-tAw"/>
|
<action selector="connectPrinter:" target="-1" id="tl1-CL-tAw"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
|
<menuItem title="Workboy" id="lo9-CX-BJj">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="connectWorkboy:" target="-1" id="6vS-bq-wAX"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
</items>
|
</items>
|
||||||
</menu>
|
</menu>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
|
@ -1131,8 +1131,9 @@ void GB_disconnect_serial(GB_gameboy_t *gb)
|
|||||||
gb->serial_transfer_bit_start_callback = NULL;
|
gb->serial_transfer_bit_start_callback = NULL;
|
||||||
gb->serial_transfer_bit_end_callback = NULL;
|
gb->serial_transfer_bit_end_callback = NULL;
|
||||||
|
|
||||||
/* Reset any internally-emulated device. Currently, only the printer. */
|
/* Reset any internally-emulated device. */
|
||||||
memset(&gb->printer, 0, sizeof(gb->printer));
|
memset(&gb->printer, 0, sizeof(gb->printer));
|
||||||
|
memset(&gb->workboy, 0, sizeof(gb->workboy));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GB_is_inited(GB_gameboy_t *gb)
|
bool GB_is_inited(GB_gameboy_t *gb)
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "sgb.h"
|
#include "sgb.h"
|
||||||
#include "cheats.h"
|
#include "cheats.h"
|
||||||
#include "rumble.h"
|
#include "rumble.h"
|
||||||
|
#include "workboy.h"
|
||||||
|
|
||||||
#define GB_STRUCT_VERSION 13
|
#define GB_STRUCT_VERSION 13
|
||||||
|
|
||||||
@ -372,6 +373,7 @@ struct GB_gameboy_internal_s {
|
|||||||
GB_printer_t printer;
|
GB_printer_t printer;
|
||||||
uint8_t extra_oam[0xff00 - 0xfea0];
|
uint8_t extra_oam[0xff00 - 0xfea0];
|
||||||
uint32_t ram_size; // Different between CGB and DMG
|
uint32_t ram_size; // Different between CGB and DMG
|
||||||
|
GB_workboy_t workboy;
|
||||||
);
|
);
|
||||||
|
|
||||||
/* DMA and HDMA */
|
/* DMA and HDMA */
|
||||||
@ -608,6 +610,9 @@ struct GB_gameboy_internal_s {
|
|||||||
GB_read_memory_callback_t read_memory_callback;
|
GB_read_memory_callback_t read_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_workboy_set_time_callback workboy_set_time_callback;
|
||||||
|
GB_workboy_get_time_callback workboy_get_time_callback;
|
||||||
|
|
||||||
/* IR */
|
/* IR */
|
||||||
uint64_t cycles_since_ir_change; // In 8MHz units
|
uint64_t cycles_since_ir_change; // In 8MHz units
|
||||||
uint64_t cycles_since_input_ir_change; // In 8MHz units
|
uint64_t cycles_since_input_ir_change; // In 8MHz units
|
||||||
|
@ -189,13 +189,13 @@ static void byte_reieve_completed(GB_gameboy_t *gb, uint8_t byte_received)
|
|||||||
|
|
||||||
static void serial_start(GB_gameboy_t *gb, bool bit_received)
|
static void serial_start(GB_gameboy_t *gb, bool bit_received)
|
||||||
{
|
{
|
||||||
gb->printer.byte_being_recieved <<= 1;
|
gb->printer.byte_being_received <<= 1;
|
||||||
gb->printer.byte_being_recieved |= bit_received;
|
gb->printer.byte_being_received |= bit_received;
|
||||||
gb->printer.bits_recieved++;
|
gb->printer.bits_received++;
|
||||||
if (gb->printer.bits_recieved == 8) {
|
if (gb->printer.bits_received == 8) {
|
||||||
byte_reieve_completed(gb, gb->printer.byte_being_recieved);
|
byte_reieve_completed(gb, gb->printer.byte_being_received);
|
||||||
gb->printer.bits_recieved = 0;
|
gb->printer.bits_received = 0;
|
||||||
gb->printer.byte_being_recieved = 0;
|
gb->printer.byte_being_received = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ typedef struct
|
|||||||
uint8_t compression_run_lenth;
|
uint8_t compression_run_lenth;
|
||||||
bool compression_run_is_compressed;
|
bool compression_run_is_compressed;
|
||||||
|
|
||||||
uint8_t bits_recieved;
|
uint8_t bits_received;
|
||||||
uint8_t byte_being_recieved;
|
uint8_t byte_being_received;
|
||||||
bool bit_to_send;
|
bool bit_to_send;
|
||||||
} GB_printer_t;
|
} GB_printer_t;
|
||||||
|
|
||||||
|
169
Core/workboy.c
Normal file
169
Core/workboy.c
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include "gb.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
static inline uint8_t int_to_bcd(uint8_t i)
|
||||||
|
{
|
||||||
|
return (i % 10) + ((i / 10) << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t bcd_to_int(uint8_t i)
|
||||||
|
{
|
||||||
|
return (i & 0xF) + (i >> 4) * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note: This peripheral was never released. This is a hacky software reimplementation of it that allows
|
||||||
|
reaccessing all of the features present in Workboy's ROM. Some of the implementation details are
|
||||||
|
obviously wrong, but without access to the actual hardware, this is the best I can do.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void serial_start(GB_gameboy_t *gb, bool bit_received)
|
||||||
|
{
|
||||||
|
gb->workboy.byte_being_received <<= 1;
|
||||||
|
gb->workboy.byte_being_received |= bit_received;
|
||||||
|
gb->workboy.bits_received++;
|
||||||
|
if (gb->workboy.bits_received == 8) {
|
||||||
|
gb->workboy.byte_to_send = 0;
|
||||||
|
if (gb->workboy.mode != 'W' && gb->workboy.byte_being_received == 'R') {
|
||||||
|
gb->workboy.byte_to_send = 'D';
|
||||||
|
gb->workboy.key = GB_WORKBOY_NONE;
|
||||||
|
gb->workboy.mode = gb->workboy.byte_being_received;
|
||||||
|
gb->workboy.buffer_index = 1;
|
||||||
|
|
||||||
|
time_t time = gb->workboy_get_time_callback(gb);
|
||||||
|
struct tm tm;
|
||||||
|
tm = *localtime(&time);
|
||||||
|
memset(gb->workboy.buffer, 0, sizeof(gb->workboy.buffer));
|
||||||
|
|
||||||
|
gb->workboy.buffer[0] = 4; // Unknown, unused, but appears to be expected to be 4
|
||||||
|
gb->workboy.buffer[2] = int_to_bcd(tm.tm_sec); // Seconds, BCD
|
||||||
|
gb->workboy.buffer[3] = int_to_bcd(tm.tm_min); // Minutes, BCD
|
||||||
|
gb->workboy.buffer[4] = int_to_bcd(tm.tm_hour); // Hours, BCD
|
||||||
|
gb->workboy.buffer[5] = int_to_bcd(tm.tm_mday); // Days, BCD. Upper most 2 bits are added to Year for some reason
|
||||||
|
gb->workboy.buffer[6] = int_to_bcd(tm.tm_mon + 1); // Months, BCD
|
||||||
|
gb->workboy.buffer[0xF] = tm.tm_year; // Years, plain number, since 1900
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (gb->workboy.mode != 'W' && gb->workboy.byte_being_received == 'W') {
|
||||||
|
gb->workboy.byte_to_send = 'D'; // It is actually unknown what this value should be
|
||||||
|
gb->workboy.key = GB_WORKBOY_NONE;
|
||||||
|
gb->workboy.mode = gb->workboy.byte_being_received;
|
||||||
|
gb->workboy.buffer_index = 0;
|
||||||
|
}
|
||||||
|
else if (gb->workboy.mode != 'W' && (gb->workboy.byte_being_received == 'O' || gb->workboy.mode == 'O')) {
|
||||||
|
gb->workboy.mode = 'O';
|
||||||
|
gb->workboy.byte_to_send = gb->workboy.key;
|
||||||
|
if (gb->workboy.key != GB_WORKBOY_NONE) {
|
||||||
|
if (gb->workboy.key & GB_WORKBOY_REQUIRE_SHIFT) {
|
||||||
|
gb->workboy.key &= ~GB_WORKBOY_REQUIRE_SHIFT;
|
||||||
|
if (gb->workboy.shift_down) {
|
||||||
|
gb->workboy.byte_to_send = gb->workboy.key;
|
||||||
|
gb->workboy.key = GB_WORKBOY_NONE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gb->workboy.byte_to_send = GB_WORKBOY_SHIFT_DOWN;
|
||||||
|
gb->workboy.shift_down = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (gb->workboy.key & GB_WORKBOY_FORBID_SHIFT) {
|
||||||
|
gb->workboy.key &= ~GB_WORKBOY_FORBID_SHIFT;
|
||||||
|
if (!gb->workboy.shift_down) {
|
||||||
|
gb->workboy.byte_to_send = gb->workboy.key;
|
||||||
|
gb->workboy.key = GB_WORKBOY_NONE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gb->workboy.byte_to_send = GB_WORKBOY_SHIFT_UP;
|
||||||
|
gb->workboy.shift_down = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (gb->workboy.key == GB_WORKBOY_SHIFT_DOWN) {
|
||||||
|
gb->workboy.shift_down = true;
|
||||||
|
gb->workboy.user_shift_down = true;
|
||||||
|
}
|
||||||
|
else if (gb->workboy.key == GB_WORKBOY_SHIFT_UP) {
|
||||||
|
gb->workboy.shift_down = false;
|
||||||
|
gb->workboy.user_shift_down = false;
|
||||||
|
}
|
||||||
|
gb->workboy.byte_to_send = gb->workboy.key;
|
||||||
|
gb->workboy.key = GB_WORKBOY_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (gb->workboy.mode == 'R') {
|
||||||
|
if (gb->workboy.buffer_index / 2 >= sizeof(gb->workboy.buffer)) {
|
||||||
|
gb->workboy.byte_to_send = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (gb->workboy.buffer_index & 1) {
|
||||||
|
gb->workboy.byte_to_send = "0123456789ABCDEF"[gb->workboy.buffer[gb->workboy.buffer_index / 2] & 0xF];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gb->workboy.byte_to_send = "0123456789ABCDEF"[gb->workboy.buffer[gb->workboy.buffer_index / 2] >> 4];
|
||||||
|
}
|
||||||
|
gb->workboy.buffer_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (gb->workboy.mode == 'W') {
|
||||||
|
gb->workboy.byte_to_send = 'D';
|
||||||
|
if (gb->workboy.buffer_index < 2) {
|
||||||
|
gb->workboy.buffer_index++;
|
||||||
|
}
|
||||||
|
else if ((gb->workboy.buffer_index - 2) < sizeof(gb->workboy.buffer)) {
|
||||||
|
gb->workboy.buffer[gb->workboy.buffer_index - 2] = gb->workboy.byte_being_received;
|
||||||
|
gb->workboy.buffer_index++;
|
||||||
|
if (gb->workboy.buffer_index - 2 == sizeof(gb->workboy.buffer)) {
|
||||||
|
struct tm tm = {0,};
|
||||||
|
tm.tm_sec = bcd_to_int(gb->workboy.buffer[7]);
|
||||||
|
tm.tm_min = bcd_to_int(gb->workboy.buffer[8]);
|
||||||
|
tm.tm_hour = bcd_to_int(gb->workboy.buffer[9]);
|
||||||
|
tm.tm_mday = bcd_to_int(gb->workboy.buffer[0xA]);
|
||||||
|
tm.tm_mon = bcd_to_int(gb->workboy.buffer[0xB] & 0x3F) - 1;
|
||||||
|
tm.tm_year = (uint8_t)(gb->workboy.buffer[0x14] + (gb->workboy.buffer[0xA] >> 6)); // What were they thinking?
|
||||||
|
gb->workboy_set_time_callback(gb, mktime(&tm));
|
||||||
|
gb->workboy.mode = 'O';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gb->workboy.bits_received = 0;
|
||||||
|
gb->workboy.byte_being_received = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool serial_end(GB_gameboy_t *gb)
|
||||||
|
{
|
||||||
|
bool ret = gb->workboy.bit_to_send;
|
||||||
|
gb->workboy.bit_to_send = gb->workboy.byte_to_send & 0x80;
|
||||||
|
gb->workboy.byte_to_send <<= 1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GB_connect_workboy(GB_gameboy_t *gb,
|
||||||
|
GB_workboy_set_time_callback set_time_callback,
|
||||||
|
GB_workboy_get_time_callback get_time_callback)
|
||||||
|
{
|
||||||
|
memset(&gb->workboy, 0, sizeof(gb->workboy));
|
||||||
|
GB_set_serial_transfer_bit_start_callback(gb, serial_start);
|
||||||
|
GB_set_serial_transfer_bit_end_callback(gb, serial_end);
|
||||||
|
gb->workboy_set_time_callback = set_time_callback;
|
||||||
|
gb->workboy_get_time_callback = get_time_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GB_workboy_is_enabled(GB_gameboy_t *gb)
|
||||||
|
{
|
||||||
|
return gb->workboy.mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GB_workboy_set_key(GB_gameboy_t *gb, uint8_t key)
|
||||||
|
{
|
||||||
|
if (gb->workboy.user_shift_down != gb->workboy.shift_down &&
|
||||||
|
(key & (GB_WORKBOY_REQUIRE_SHIFT | GB_WORKBOY_FORBID_SHIFT)) == 0) {
|
||||||
|
if (gb->workboy.user_shift_down) {
|
||||||
|
key |= GB_WORKBOY_REQUIRE_SHIFT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
key |= GB_WORKBOY_FORBID_SHIFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gb->workboy.key = key;
|
||||||
|
}
|
118
Core/workboy.h
Normal file
118
Core/workboy.h
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#ifndef workboy_h
|
||||||
|
#define workboy_h
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "gb_struct_def.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t byte_to_send;
|
||||||
|
bool bit_to_send;
|
||||||
|
uint8_t byte_being_received;
|
||||||
|
uint8_t bits_received;
|
||||||
|
uint8_t mode;
|
||||||
|
uint8_t key;
|
||||||
|
bool shift_down;
|
||||||
|
bool user_shift_down;
|
||||||
|
uint8_t buffer[0x15];
|
||||||
|
uint8_t buffer_index; // In nibbles during read, in bytes during write
|
||||||
|
} GB_workboy_t;
|
||||||
|
|
||||||
|
typedef void (*GB_workboy_set_time_callback)(GB_gameboy_t *gb, time_t time);
|
||||||
|
typedef time_t (*GB_workboy_get_time_callback)(GB_gameboy_t *gb);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GB_WORKBOY_NONE = 0xFF,
|
||||||
|
GB_WORKBOY_REQUIRE_SHIFT = 0x40,
|
||||||
|
GB_WORKBOY_FORBID_SHIFT = 0x80,
|
||||||
|
|
||||||
|
GB_WORKBOY_CLOCK = 1,
|
||||||
|
GB_WORKBOY_TEMPERATURE = 2,
|
||||||
|
GB_WORKBOY_MONEY = 3,
|
||||||
|
GB_WORKBOY_CALCULATOR = 4,
|
||||||
|
GB_WORKBOY_DATE = 5,
|
||||||
|
GB_WORKBOY_CONVERSION = 6,
|
||||||
|
GB_WORKBOY_RECORD = 7,
|
||||||
|
GB_WORKBOY_WORLD = 8,
|
||||||
|
GB_WORKBOY_PHONE = 9,
|
||||||
|
GB_WORKBOY_ESCAPE = 10,
|
||||||
|
GB_WORKBOY_BACKSPACE = 11,
|
||||||
|
GB_WORKBOY_UNKNOWN = 12,
|
||||||
|
GB_WORKBOY_LEFT = 13,
|
||||||
|
GB_WORKBOY_Q = 17,
|
||||||
|
GB_WORKBOY_1 = 17 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_W = 18,
|
||||||
|
GB_WORKBOY_2 = 18 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_E = 19,
|
||||||
|
GB_WORKBOY_3 = 19 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_R = 20,
|
||||||
|
GB_WORKBOY_T = 21,
|
||||||
|
GB_WORKBOY_Y = 22 ,
|
||||||
|
GB_WORKBOY_U = 23 ,
|
||||||
|
GB_WORKBOY_I = 24,
|
||||||
|
GB_WORKBOY_EXCLAMATION_MARK = 24 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_O = 25,
|
||||||
|
GB_WORKBOY_TILDE = 25 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_P = 26,
|
||||||
|
GB_WORKBOY_ASTERISK = 26 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_DOLLAR = 27 | GB_WORKBOY_FORBID_SHIFT,
|
||||||
|
GB_WORKBOY_HASH = 27 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_A = 28,
|
||||||
|
GB_WORKBOY_4 = 28 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_S = 29,
|
||||||
|
GB_WORKBOY_5 = 29 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_D = 30,
|
||||||
|
GB_WORKBOY_6 = 30 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_F = 31,
|
||||||
|
GB_WORKBOY_PLUS = 31 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_G = 32,
|
||||||
|
GB_WORKBOY_MINUS = 32 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_H = 33,
|
||||||
|
GB_WORKBOY_J = 34,
|
||||||
|
GB_WORKBOY_K = 35,
|
||||||
|
GB_WORKBOY_LEFT_PARENTHESIS = 35 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_L = 36,
|
||||||
|
GB_WORKBOY_RIGHT_PARENTHESIS = 36 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_SEMICOLON = 37 | GB_WORKBOY_FORBID_SHIFT,
|
||||||
|
GB_WORKBOY_COLON = 37,
|
||||||
|
GB_WORKBOY_ENTER = 38,
|
||||||
|
GB_WORKBOY_SHIFT_DOWN = 39,
|
||||||
|
GB_WORKBOY_Z = 40,
|
||||||
|
GB_WORKBOY_7 = 40 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_X = 41,
|
||||||
|
GB_WORKBOY_8 = 41 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_C = 42,
|
||||||
|
GB_WORKBOY_9 = 42 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_V = 43,
|
||||||
|
GB_WORKBOY_DECIMAL_POINT = 43 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_B = 44,
|
||||||
|
GB_WORKBOY_PERCENT = 44 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_N = 45,
|
||||||
|
GB_WORKBOY_EQUAL = 45 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_M = 46,
|
||||||
|
GB_WORKBOY_COMMA = 47 | GB_WORKBOY_FORBID_SHIFT,
|
||||||
|
GB_WORKBOY_LT = 47 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_DOT = 48 | GB_WORKBOY_FORBID_SHIFT,
|
||||||
|
GB_WORKBOY_GT = 48 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_SLASH = 49 | GB_WORKBOY_FORBID_SHIFT,
|
||||||
|
GB_WORKBOY_QUESTION_MARK = 49 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_SHIFT_UP = 50,
|
||||||
|
GB_WORKBOY_0 = 51 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_UMLAUT = 51,
|
||||||
|
GB_WORKBOY_SPACE = 52,
|
||||||
|
GB_WORKBOY_QUOTE = 53 | GB_WORKBOY_FORBID_SHIFT,
|
||||||
|
GB_WORKBOY_AT = 53 | GB_WORKBOY_REQUIRE_SHIFT,
|
||||||
|
GB_WORKBOY_UP = 54,
|
||||||
|
GB_WORKBOY_DOWN = 55,
|
||||||
|
GB_WORKBOY_RIGHT = 56,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void GB_connect_workboy(GB_gameboy_t *gb,
|
||||||
|
GB_workboy_set_time_callback set_time_callback,
|
||||||
|
GB_workboy_get_time_callback get_time_callback);
|
||||||
|
bool GB_workboy_is_enabled(GB_gameboy_t *gb);
|
||||||
|
void GB_workboy_set_key(GB_gameboy_t *gb, uint8_t key);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user