Files
Microtransactions64-server/devices/N64.go
2025-11-27 22:14:23 -07:00

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}
}