plain n64 driver
This commit is contained in:
parent
62ce62777d
commit
a774bc4511
|
@ -0,0 +1,3 @@
|
|||
build
|
||||
gpsp.z64
|
||||
filesystem/rom.gba
|
|
@ -0,0 +1,74 @@
|
|||
TARGET := gpsp.z64
|
||||
SOURCES := n64main.c unf/usb.c unf/debug.c
|
||||
|
||||
#OPTFLAG = -O0 -ggdb
|
||||
OPTFLAG = -O3 -flto=auto
|
||||
CFLAGS := -Wall -Wno-unused-function -DFULLSCREEN
|
||||
LDFLAGS := -flto=auto
|
||||
|
||||
#CFLAGS += -DTRACE_INSTRUCTIONS
|
||||
#CFLAGS += -DTRACE_REGISTERS
|
||||
#CFLAGS += -DTRACE_EVENTS
|
||||
#CFLAGS += -DNO_PRINT_ONLY_TRACE
|
||||
|
||||
CORE_DIR := $(abspath ..)
|
||||
|
||||
HAVE_DYNAREC := 0
|
||||
|
||||
ifeq ($(HAVE_DYNAREC),1)
|
||||
CFLAGS += -DHAVE_DYNAREC
|
||||
endif
|
||||
CFLAGS += -DMIPS_ARCH -DUSE_RGBA5551_FORMAT -DROM_BUFFER_SIZE=1
|
||||
CFLAGS += -DHAVE_STRINGS_H -DHAVE_STDINT_H -DHAVE_INTTYPES_H -D__LIBRETRO__ -DINLINE=inline
|
||||
CPU_ARCH := mips
|
||||
|
||||
include $(CORE_DIR)/Makefile.common
|
||||
SOURCES_C := $(filter-out $(CORE_DIR)/libretro/libretro.c,$(SOURCES_C))
|
||||
|
||||
CFLAGS += $(INCFLAGS)
|
||||
|
||||
BUILD_DIR = build
|
||||
CXXFLAGS := $(CFLAGS)
|
||||
ASFLAGS := $(CFLAGS) -Wa,-I$(CORE_DIR) -DN64
|
||||
|
||||
include $(N64_INST)/include/n64.mk
|
||||
|
||||
N64_CFLAGS += $(OPTFLAG)
|
||||
N64_CXXFLAGS += $(OPTFLAG)
|
||||
|
||||
OBJS := $(addprefix $(BUILD_DIR)/,$(SOURCES:.c=.o))
|
||||
OBJS += $(addprefix $(BUILD_DIR)/,$(SOURCES_C:.c=.o))
|
||||
OBJS += $(addprefix $(BUILD_DIR)/,$(SOURCES_CC:.cc=.o))
|
||||
OBJS += $(addprefix $(BUILD_DIR)/,$(SOURCES_ASM:.S=.o))
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
clean:
|
||||
$(RM) -rf $(BUILD_DIR)
|
||||
|
||||
.PHONY: all clean debug everdrive
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cc
|
||||
@mkdir -p $(dir $@)
|
||||
@echo " [CXX] $<"
|
||||
$(CXX) -c $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(TARGET): N64_ROM_TITLE = "gameplaySP64"
|
||||
$(TARGET): $(BUILD_DIR)/$(TARGET:.z64=.dfs)
|
||||
|
||||
$(BUILD_DIR)/$(TARGET:.z64=.elf): $(OBJS)
|
||||
|
||||
$(BUILD_DIR)/$(TARGET:.z64=.dfs): $(wildcard filesystem/*)
|
||||
|
||||
debug: $(TARGET)
|
||||
ares --setting DebugServer/Enabled=true \
|
||||
--setting Boot/Debugger=true \
|
||||
--setting General/HomebrewMode=true \
|
||||
$(TARGET) | grep -vE '^CPU ffffffff[^a]' &
|
||||
gdb $(BUILD_DIR)/$(TARGET:.z64=.elf) -ex 'target remote tcp::9123'
|
||||
|
||||
everdrive: $(TARGET)
|
||||
usb64 -rom=$(TARGET)
|
||||
usb64 -start
|
||||
|
||||
-include $(OBJS:.o=.d)
|
|
@ -0,0 +1,25 @@
|
|||
build with libdragon unstable. https://libdragon.dev/
|
||||
|
||||
requires real hardware or ares-emu to run. https://ares-emu.net/
|
||||
|
||||
because the n64's cpu needs *ten instructions* to byte-swap a word (and eight
|
||||
to byte-swap a half-word), we just leave memory in word-wise big-endian and
|
||||
simply invert the lower bits of addresses whenever we access bytes or halfwords
|
||||
at runtime (just one XOR instruction, and no need to touch word accesses -
|
||||
the most common by a landslide - at all!)
|
||||
|
||||
for this scheme to work, the ROM must also already be in word-wise big-endian,
|
||||
which you can achieve with binutils like so:
|
||||
|
||||
```
|
||||
objcopy -I binary -O binary --reverse-bytes=4 .../game.gba .../gpsp/libdragon/filesystem/rom.gba
|
||||
```
|
||||
|
||||
dynarec doesn't quite work yet - crashes for reasons i don't yet understand!
|
||||
to attempt to use it and/or debug, change the variables in the Makefile.
|
||||
(hint: there's also a make target `debug` that works if you have ares and
|
||||
multiarch gdb, but it doesn't change the build flags - that still needs to be
|
||||
done by hand in the Makefile)
|
||||
|
||||
ppu emulation is still done in software on the main cpu - i am hoping to make
|
||||
a renderer that utilizes the RCP, but that may take some time to implement.
|
|
@ -0,0 +1,189 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libdragon.h>
|
||||
#include <display.h>
|
||||
#include <system.h>
|
||||
|
||||
#include "unf/usb.h"
|
||||
#include "unf/debug.h"
|
||||
|
||||
#include "../common.h"
|
||||
#include "../memmap.h"
|
||||
|
||||
#include "../gba_memory.h"
|
||||
#include "../gba_cc_lut.h"
|
||||
|
||||
// Usually 59.72750057 Hz, unless GBC_RATE is overclocked (for 60FPS)
|
||||
#define GBA_FPS ((float) GBC_BASE_RATE) / (308 * 228 * 4)
|
||||
|
||||
//static s16 audio_sample_buffer[(audio_samples_per_frame + 1) * 2];
|
||||
static s16 audio_sample_buffer[2194];
|
||||
static float audio_samples_per_frame = (float)(GBA_SOUND_FREQUENCY) / (float)(GBA_FPS);
|
||||
static float audio_samples_accumulator = 0.0f;
|
||||
|
||||
static int16_t g_joypads[JOYPAD_PORT_COUNT][RETRO_DEVICE_ID_JOYPAD_R+1];
|
||||
|
||||
u32 skip_next_frame = 0;
|
||||
boot_mode selected_boot_mode = boot_game;
|
||||
|
||||
int dynarec_enable;
|
||||
int sprite_limit = 1;
|
||||
|
||||
u32 idle_loop_target_pc = 0xFFFFFFFF;
|
||||
u32 translation_gate_target_pc[MAX_TRANSLATION_GATES];
|
||||
u32 translation_gate_targets = 0;
|
||||
|
||||
surface_t* display_surface = NULL;
|
||||
size_t gba_screen_pixel_offset = 0;
|
||||
|
||||
static void audio_run(void)
|
||||
{
|
||||
u32 samples_to_read;
|
||||
u32 samples_produced;
|
||||
|
||||
/* audio_samples_per_frame is decimal;
|
||||
* get integer component */
|
||||
samples_to_read = (u32)audio_samples_per_frame;
|
||||
|
||||
/* Account for fractional component */
|
||||
audio_samples_accumulator += audio_samples_per_frame -
|
||||
(float)samples_to_read;
|
||||
|
||||
if (audio_samples_accumulator >= 1.0f)
|
||||
{
|
||||
samples_to_read++;
|
||||
audio_samples_accumulator -= 1.0f;
|
||||
}
|
||||
|
||||
samples_produced = sound_read_samples(audio_sample_buffer, samples_to_read);
|
||||
audio_push(audio_sample_buffer, samples_produced, false);
|
||||
}
|
||||
|
||||
static void allocate_video_surface() {
|
||||
display_surface = display_get();
|
||||
|
||||
gba_screen_pixels = display_surface->buffer;
|
||||
gba_screen_pixels += gba_screen_pixel_offset;
|
||||
}
|
||||
|
||||
static void video_run(void)
|
||||
{
|
||||
if (display_surface != NULL) {
|
||||
display_show(display_surface);
|
||||
}
|
||||
allocate_video_surface();
|
||||
}
|
||||
|
||||
static void setup_screen_geometry() {
|
||||
resolution_t res;
|
||||
filter_options_t filt;
|
||||
|
||||
#ifdef FULLSCREEN
|
||||
res.width = GBA_SCREEN_WIDTH;
|
||||
res.height = GBA_SCREEN_WIDTH * 3 / 4;
|
||||
filt = FILTERS_RESAMPLE_ANTIALIAS;
|
||||
#else // integer scaled, centered
|
||||
res.width = 320;
|
||||
res.height = 240;
|
||||
filt = FILTERS_RESAMPLE;
|
||||
#endif
|
||||
// TODO: do any of the interlace options give us anything like interframe blending?
|
||||
res.interlaced = INTERLACE_OFF;
|
||||
|
||||
gba_screen_pitch = res.width;
|
||||
// center in screen
|
||||
gba_screen_pixel_offset = ((res.width - GBA_SCREEN_WIDTH) + (res.width * (res.height - GBA_SCREEN_HEIGHT))) / 2;
|
||||
|
||||
display_init(res, DEPTH_16_BPP, 3, GAMMA_NONE, filt);
|
||||
}
|
||||
|
||||
int16_t input_state(unsigned port, unsigned device, unsigned index, unsigned id) {
|
||||
if (port < JOYPAD_PORT_COUNT && device == RETRO_DEVICE_JOYPAD) {
|
||||
return g_joypads[port][id];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void input_poll() {
|
||||
joypad_poll();
|
||||
JOYPAD_PORT_FOREACH(i) {
|
||||
joypad_buttons_t inp = joypad_get_buttons(i);
|
||||
g_joypads[i][RETRO_DEVICE_ID_JOYPAD_A] = inp.a;
|
||||
g_joypads[i][RETRO_DEVICE_ID_JOYPAD_B] = inp.b;
|
||||
g_joypads[i][RETRO_DEVICE_ID_JOYPAD_UP] = inp.d_up;
|
||||
g_joypads[i][RETRO_DEVICE_ID_JOYPAD_DOWN] = inp.d_down;
|
||||
g_joypads[i][RETRO_DEVICE_ID_JOYPAD_LEFT] = inp.d_left;
|
||||
g_joypads[i][RETRO_DEVICE_ID_JOYPAD_RIGHT] = inp.d_right;
|
||||
g_joypads[i][RETRO_DEVICE_ID_JOYPAD_START] = inp.start;
|
||||
g_joypads[i][RETRO_DEVICE_ID_JOYPAD_SELECT] = inp.z;
|
||||
g_joypads[i][RETRO_DEVICE_ID_JOYPAD_L] = inp.l;
|
||||
g_joypads[i][RETRO_DEVICE_ID_JOYPAD_R] = inp.r;
|
||||
}
|
||||
}
|
||||
|
||||
void set_fastforward_override(bool fastforward) {}
|
||||
|
||||
int stdio_stderr_redirect(char* buf, unsigned len) {
|
||||
usb_write(DATATYPE_TEXT, buf, len);
|
||||
return write(2, buf, len);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// UNFLoader interface plumbing for flash carts
|
||||
stdio_t console_calls = { 0, stdio_stderr_redirect, 0 };
|
||||
//debug_initialize();
|
||||
usb_initialize();
|
||||
hook_stdio_calls(&console_calls);
|
||||
printf("UNFLoader debug initialized!\n");
|
||||
|
||||
// ISViewer (i.e. ares-emu)
|
||||
debug_init_isviewer();
|
||||
printf("ISViewer debug initialized!\n");
|
||||
|
||||
dfs_init(DFS_DEFAULT_LOCATION);
|
||||
|
||||
setup_screen_geometry();
|
||||
allocate_video_surface();
|
||||
|
||||
audio_init(GBA_SOUND_FREQUENCY, 4);
|
||||
joypad_init();
|
||||
|
||||
// gpsp input.c implements this directly.
|
||||
retro_set_input_state(input_state);
|
||||
|
||||
memcpy(bios_rom, open_gba_bios_rom, sizeof(bios_rom));
|
||||
|
||||
init_gamepak_buffer();
|
||||
init_sound();
|
||||
|
||||
memset(gamepak_backup, 0xff, sizeof(gamepak_backup));
|
||||
if (load_gamepak(NULL, "rom:/rom.gba", 0, 0) != 0)
|
||||
{
|
||||
printf("Could not load the game file.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
reset_gba();
|
||||
while(true) {
|
||||
input_poll();
|
||||
update_input();
|
||||
|
||||
/* This runs just a frame */
|
||||
#ifdef HAVE_DYNAREC
|
||||
if (dynarec_enable)
|
||||
execute_arm_translate(execute_cycles);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Sticky bits only used in interpreter */
|
||||
clear_gamepak_stickybits();
|
||||
execute_arm(execute_cycles);
|
||||
}
|
||||
|
||||
audio_run();
|
||||
video_run();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,182 @@
|
|||
#ifndef UNFL_DEBUG_H
|
||||
#define UNFL_DEBUG_H
|
||||
|
||||
/*********************************
|
||||
Settings macros
|
||||
*********************************/
|
||||
|
||||
#define LIBDRAGON
|
||||
|
||||
// Enable/Disable debug
|
||||
#ifndef DEBUG_MODE
|
||||
#define DEBUG_MODE 1 // Enable/Disable debug mode
|
||||
#endif
|
||||
|
||||
// Settings
|
||||
#define DEBUG_INIT_MSG 1 // Print a message when debug mode has initialized
|
||||
#define AUTOPOLL_ENABLED 1 // Automatically poll the USB on a timer
|
||||
#define AUTOPOLL_TIME 200 // Time (in milliseconds) between auto polls
|
||||
#define USE_FAULTTHREAD 1 // Create a fault detection thread (libultra only)
|
||||
#define USE_RDBTHREAD 1 // Create a remote debugger thread
|
||||
#define OVERWRITE_OSPRINT 1 // Replaces osSyncPrintf calls with debug_printf (libultra only)
|
||||
#define MAX_COMMANDS 25 // The max amount of user defined commands possible
|
||||
|
||||
// USB thread definitions (libultra only)
|
||||
#define USB_THREAD_ID 14
|
||||
#define USB_THREAD_PRI 126
|
||||
#define USB_THREAD_STACK 0x2000
|
||||
|
||||
// Fault thread definitions (libultra only)
|
||||
#define FAULT_THREAD_ID 13
|
||||
#define FAULT_THREAD_PRI 125
|
||||
#define FAULT_THREAD_STACK 0x2000
|
||||
|
||||
// Remote debugger thread definitions (libultra only)
|
||||
#define RDB_THREAD_ID 15
|
||||
#define RDB_THREAD_PRI 124
|
||||
#define RDB_THREAD_STACK 0x2000
|
||||
|
||||
|
||||
/*********************************
|
||||
Debug Functions
|
||||
*********************************/
|
||||
|
||||
#if DEBUG_MODE
|
||||
|
||||
/*==============================
|
||||
debug_initialize
|
||||
Initializes the debug and USB library.
|
||||
Should be called last during game initialization.
|
||||
==============================*/
|
||||
|
||||
extern void debug_initialize();
|
||||
|
||||
|
||||
/*==============================
|
||||
debug_printf
|
||||
Prints a formatted message to the developer's command prompt.
|
||||
Supports up to 256 characters.
|
||||
@param A string to print
|
||||
@param variadic arguments to print as well
|
||||
==============================*/
|
||||
|
||||
extern void debug_printf(const char* message, ...);
|
||||
|
||||
|
||||
/*==============================
|
||||
debug_dumpbinary
|
||||
Dumps a binary file through USB
|
||||
@param The file to dump
|
||||
@param The size of the file
|
||||
==============================*/
|
||||
|
||||
extern void debug_dumpbinary(void* file, int size);
|
||||
|
||||
|
||||
/*==============================
|
||||
debug_screenshot
|
||||
Sends the currently displayed framebuffer through USB.
|
||||
DOES NOT PAUSE DRAWING THREAD! Using outside the drawing
|
||||
thread may lead to a screenshot with visible tearing
|
||||
==============================*/
|
||||
|
||||
extern void debug_screenshot();
|
||||
|
||||
|
||||
/*==============================
|
||||
debug_assert
|
||||
Halts the program if the expression fails.
|
||||
@param The expression to test
|
||||
==============================*/
|
||||
|
||||
#define debug_assert(expr) (expr) ? ((void)0) : _debug_assert(#expr, __FILE__, __LINE__)
|
||||
|
||||
|
||||
/*==============================
|
||||
debug_64drivebutton
|
||||
Assigns a function to be executed when the 64drive button is pressed.
|
||||
@param The function pointer to execute
|
||||
@param Whether or not to execute the function only on pressing (ignore holding the button down)
|
||||
==============================*/
|
||||
|
||||
extern void debug_64drivebutton(void(*execute)(), char onpress);
|
||||
|
||||
|
||||
/*==============================
|
||||
debug_pollcommands
|
||||
Check the USB for incoming commands.
|
||||
==============================*/
|
||||
|
||||
extern void debug_pollcommands();
|
||||
|
||||
|
||||
/*==============================
|
||||
debug_addcommand
|
||||
Adds a command for the USB to read.
|
||||
@param The command name
|
||||
@param The command description
|
||||
@param The function pointer to execute
|
||||
==============================*/
|
||||
|
||||
extern void debug_addcommand(char* command, char* description, char*(*execute)());
|
||||
|
||||
|
||||
/*==============================
|
||||
debug_parsecommand
|
||||
Stores the next part of the incoming command into the provided buffer.
|
||||
Make sure the buffer can fit the amount of data from debug_sizecommand!
|
||||
If you pass NULL, it skips this command.
|
||||
@param The buffer to store the data in
|
||||
==============================*/
|
||||
|
||||
extern void debug_parsecommand(void* buffer);
|
||||
|
||||
|
||||
/*==============================
|
||||
debug_sizecommand
|
||||
Returns the size of the data from this part of the command.
|
||||
@return The size of the data in bytes, or 0
|
||||
==============================*/
|
||||
|
||||
extern int debug_sizecommand();
|
||||
|
||||
|
||||
/*==============================
|
||||
debug_printcommands
|
||||
Prints a list of commands to the developer's command prompt.
|
||||
==============================*/
|
||||
|
||||
extern void debug_printcommands();
|
||||
|
||||
|
||||
// Ignore this, use the macro instead
|
||||
extern void _debug_assert(const char* expression, const char* file, int line);
|
||||
|
||||
// Include usb.h automatically
|
||||
#include "usb.h"
|
||||
|
||||
#else
|
||||
|
||||
// Overwrite library functions with useless macros if debug mode is disabled
|
||||
#define debug_initialize()
|
||||
#define debug_printf (void)
|
||||
#define debug_screenshot(a, b, c)
|
||||
#define debug_assert(a)
|
||||
#define debug_pollcommands()
|
||||
#define debug_addcommand(a, b, c)
|
||||
#define debug_parsecommand(a) NULL
|
||||
#define debug_sizecommand() 0
|
||||
#define debug_printcommands()
|
||||
#define debug_64drivebutton(a, b)
|
||||
#define usb_initialize() 0
|
||||
#define usb_getcart() 0
|
||||
#define usb_write(a, b, c)
|
||||
#define usb_poll() 0
|
||||
#define usb_read(a, b)
|
||||
#define usb_skip(a)
|
||||
#define usb_rewind(a)
|
||||
#define usb_purge()
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,140 @@
|
|||
#ifndef UNFL_USB_H
|
||||
#define UNFL_USB_H
|
||||
|
||||
/*********************************
|
||||
DataType macros
|
||||
*********************************/
|
||||
|
||||
// UNCOMMENT THE #DEFINE IF USING LIBDRAGON
|
||||
#define LIBDRAGON
|
||||
|
||||
// Settings
|
||||
#define USE_OSRAW 0 // Use if you're doing USB operations without the PI Manager (libultra only)
|
||||
#define DEBUG_ADDRESS_SIZE 8*1024*1024 // Max size of USB I/O. The bigger this value, the more ROM you lose!
|
||||
#define CHECK_EMULATOR 0 // Stops the USB library from working if it detects an emulator to prevent problems
|
||||
|
||||
// Cart definitions
|
||||
#define CART_NONE 0
|
||||
#define CART_64DRIVE 1
|
||||
#define CART_EVERDRIVE 2
|
||||
#define CART_SC64 3
|
||||
|
||||
// Data types defintions
|
||||
#define DATATYPE_TEXT 0x01
|
||||
#define DATATYPE_RAWBINARY 0x02
|
||||
#define DATATYPE_HEADER 0x03
|
||||
#define DATATYPE_SCREENSHOT 0x04
|
||||
#define DATATYPE_HEARTBEAT 0x05
|
||||
#define DATATYPE_RDBPACKET 0x06
|
||||
|
||||
|
||||
/*********************************
|
||||
Convenience macros
|
||||
*********************************/
|
||||
|
||||
// Use these to conveniently read the header from usb_poll()
|
||||
#define USBHEADER_GETTYPE(header) (((header) & 0xFF000000) >> 24)
|
||||
#define USBHEADER_GETSIZE(header) (((header) & 0x00FFFFFF))
|
||||
|
||||
|
||||
/*********************************
|
||||
USB Functions
|
||||
*********************************/
|
||||
|
||||
/*==============================
|
||||
usb_initialize
|
||||
Initializes the USB buffers and pointers
|
||||
@return 1 if the USB initialization was successful, 0 if not
|
||||
==============================*/
|
||||
|
||||
extern char usb_initialize(void);
|
||||
|
||||
|
||||
/*==============================
|
||||
usb_getcart
|
||||
Returns which flashcart is currently connected
|
||||
@return The CART macro that corresponds to the identified flashcart
|
||||
==============================*/
|
||||
|
||||
extern char usb_getcart(void);
|
||||
|
||||
|
||||
/*==============================
|
||||
usb_write
|
||||
Writes data to the USB.
|
||||
Will not write if there is data to read from USB
|
||||
@param The DATATYPE that is being sent
|
||||
@param A buffer with the data to send
|
||||
@param The size of the data being sent
|
||||
==============================*/
|
||||
|
||||
extern void usb_write(int datatype, const void* data, int size);
|
||||
|
||||
|
||||
/*==============================
|
||||
usb_poll
|
||||
Returns the header of data being received via USB
|
||||
The first byte contains the data type, the next 3 the number of bytes left to read
|
||||
@return The data header, or 0
|
||||
==============================*/
|
||||
|
||||
extern unsigned long usb_poll(void);
|
||||
|
||||
|
||||
/*==============================
|
||||
usb_read
|
||||
Reads bytes from USB into the provided buffer
|
||||
@param The buffer to put the read data in
|
||||
@param The number of bytes to read
|
||||
==============================*/
|
||||
|
||||
extern void usb_read(void* buffer, int size);
|
||||
|
||||
|
||||
/*==============================
|
||||
usb_skip
|
||||
Skips a USB read by the specified amount of bytes
|
||||
@param The number of bytes to skip
|
||||
==============================*/
|
||||
|
||||
extern void usb_skip(int nbytes);
|
||||
|
||||
|
||||
/*==============================
|
||||
usb_rewind
|
||||
Rewinds a USB read by the specified amount of bytes
|
||||
@param The number of bytes to rewind
|
||||
==============================*/
|
||||
|
||||
extern void usb_rewind(int nbytes);
|
||||
|
||||
|
||||
/*==============================
|
||||
usb_purge
|
||||
Purges the incoming USB data
|
||||
==============================*/
|
||||
|
||||
extern void usb_purge(void);
|
||||
|
||||
|
||||
/*==============================
|
||||
usb_timedout
|
||||
Checks if the USB timed out recently
|
||||
@return 1 if the USB timed out, 0 if not
|
||||
==============================*/
|
||||
|
||||
extern char usb_timedout(void);
|
||||
|
||||
|
||||
/*==============================
|
||||
usb_sendheartbeat
|
||||
Sends a heartbeat packet to the PC
|
||||
This is done once automatically at initialization,
|
||||
but can be called manually to ensure that the
|
||||
host side tool is aware of the current USB protocol
|
||||
version.
|
||||
==============================*/
|
||||
|
||||
extern void usb_sendheartbeat(void);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue