You've already forked Microtransactions64-server
mirror of
https://github.com/Print-and-Panic/Microtransactions64-server.git
synced 2026-01-21 10:17:31 -08:00
126 lines
2.7 KiB
Go
126 lines
2.7 KiB
Go
package devices
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"log"
|
|
|
|
"go.bug.st/serial"
|
|
)
|
|
|
|
const (
|
|
MAX_DATA_SIZE = 512
|
|
)
|
|
|
|
type N64 interface {
|
|
Start() error
|
|
Close() error
|
|
SendData(data []byte) error
|
|
ReceiveData() ([]byte, error)
|
|
}
|
|
|
|
type EverDrive struct {
|
|
PortName string
|
|
port serial.Port
|
|
running bool
|
|
}
|
|
|
|
func (e *EverDrive) Start() error {
|
|
mode := &serial.Mode{
|
|
BaudRate: 9600,
|
|
DataBits: 8,
|
|
Parity: serial.NoParity, // Changed from EvenParity
|
|
StopBits: serial.OneStopBit, // Changed from TwoStopBits
|
|
}
|
|
port, err := serial.Open(e.PortName, mode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
e.port = port
|
|
e.running = true
|
|
return nil
|
|
}
|
|
|
|
func (e *EverDrive) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func (e *EverDrive) SendData(data []byte) error {
|
|
if !e.running {
|
|
return fmt.Errorf("N64 is not running")
|
|
}
|
|
|
|
// --- 1. CONSTRUCT THE UNFLOADER PACKET ---
|
|
|
|
// Header (4 Bytes)
|
|
packet := []byte{'D', 'M', 'A', '@'}
|
|
|
|
// Data Type (1 Byte)
|
|
// using 0x01 (DataTypeText) is fine, or define your own.
|
|
packet = append(packet, 0x01)
|
|
|
|
// Size (3 Bytes, Big Endian)
|
|
// This tells usb.c how many REAL bytes of payload to expect.
|
|
lengthBuf := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(lengthBuf, uint32(len(data)))
|
|
packet = append(packet, lengthBuf[1:]...) // Skip first byte, append last 3
|
|
|
|
// Payload (The Coin)
|
|
packet = append(packet, data...)
|
|
|
|
// PAYLOAD ALIGNMENT (Crucial per usb.c line 640)
|
|
// len = ALIGN(usb_datasize, 2);
|
|
// If we send 1 byte (odd), usb.c will read 2 bytes.
|
|
// We must provide that padding byte or it will eat the 'C' of the footer.
|
|
if len(data)%2 != 0 {
|
|
packet = append(packet, 0x00)
|
|
}
|
|
|
|
// Footer (4 Bytes)
|
|
packet = append(packet, 'C', 'M', 'P', 'H')
|
|
|
|
// --- 2. HARDWARE PADDING (The Fix) ---
|
|
// The EverDrive needs a 512-byte transfer to wake up.
|
|
// We pad the rest of the buffer with zeros.
|
|
// The N64 will read the packet above, then fail 'DMA@' checks
|
|
// on the zeros until the buffer is empty. This is expected behavior.
|
|
|
|
blockSize := 512
|
|
totalLen := len(packet)
|
|
|
|
if totalLen < blockSize {
|
|
padding := make([]byte, blockSize-totalLen)
|
|
packet = append(packet, padding...)
|
|
}
|
|
|
|
// Write exactly 512 bytes
|
|
_, err := e.port.Write(packet)
|
|
if err != nil {
|
|
log.Printf("❌ N64 Write Error: %v", err)
|
|
return err
|
|
}
|
|
|
|
log.Printf("📤 Sent Packet (Payload: %v | Total Wire: %d)", data, len(packet))
|
|
return nil
|
|
}
|
|
func (e *EverDrive) ReceiveData() ([]byte, error) {
|
|
if !e.running {
|
|
return nil, fmt.Errorf("N64 is not running")
|
|
}
|
|
|
|
data := make([]byte, MAX_DATA_SIZE)
|
|
_, err := e.port.Read(data)
|
|
if err != nil {
|
|
log.Printf("❌ N64 Read Error: %v", err)
|
|
return nil, err
|
|
}
|
|
|
|
log.Printf("📥 Received %s from N64", data)
|
|
return data, nil
|
|
}
|
|
|
|
func NewEverDrive(portName string) *EverDrive {
|
|
return &EverDrive{PortName: portName}
|
|
}
|