NetMD.Factory (NetMD v0.1.0)

Copy Markdown View Source

The NetMD factory command set, ported from netmd-js.

Factory mode exposes the player's internal memory (RAM / EEPROM / disc cache peripheral) for reading and writing. It backs firmware patching, raw UTOC access and the display override. This is dangerous; a wrong write can brick the device. Do not use it unless you know exactly what you are doing.

Three device families need slightly different framing, modelled as a tagged struct (:netmd, :himd, :rh1). Open one with open/1, which authenticates and detects the variant, then use the memory and device functions here or the higher-level operations in NetMD.Factory.Commands.

Summary

Types

Memory region to address.

How to open a memory range.

t()

An authenticated factory interface.

Device family: base NetMD, Hi-MD, or the MZ-RH1 special case.

Functions

Authenticate the factory session.

Open, keep open, or close a memory range for access. A no-op on the MZ-RH1, which addresses memory through the peripheral instead.

Factory-transfer checksum (CRC-16/CCITT) over data.

A short device code string like "S1.600" (chip family, firmware version, subversion).

The device code: chip type, hardware id, firmware version and subversion.

The device's firmware version as a BCD-decoded number.

EEPROM checksum with the standard seeds (0xA596 for Hi-MD).

Authenticate a factory session on an open device and detect its variant.

Read length bytes of type memory at address.

Read length bytes from the disc-cache metadata peripheral.

Set the display mode (:default or :override).

Override the display with text (a string, encoded to Shift-JIS, or raw bytes with raw: true). At most 8 characters or 9 raw bytes.

Front-panel switch and button state.

Write data to type memory at address.

Write to the disc-cache metadata peripheral.

Types

error()

@type error() :: NetMD.Interface.error()

memory_type()

@type memory_type() :: :mapped | :eeprom_2 | :eeprom_3 | 0..255

Memory region to address.

open_type()

@type open_type() :: :close | :read | :write | :read_write | 0..255

How to open a memory range.

t()

@type t() :: %NetMD.Factory{device: NetMD.Device.t(), variant: variant()}

An authenticated factory interface.

variant()

@type variant() :: :netmd | :himd | :rh1

Device family: base NetMD, Hi-MD, or the MZ-RH1 special case.

Functions

auth(factory)

@spec auth(t()) :: :ok | error()

Authenticate the factory session.

change_memory_state(factory, address, length, type, state, opts \\ [])

@spec change_memory_state(
  t(),
  non_neg_integer(),
  non_neg_integer(),
  memory_type(),
  open_type(),
  keyword()
) :: :ok | error()

Open, keep open, or close a memory range for access. A no-op on the MZ-RH1, which addresses memory through the peripheral instead.

checksum(data, opts \\ [])

@spec checksum(
  binary(),
  keyword()
) :: 0..65535

Factory-transfer checksum (CRC-16/CCITT) over data.

Options: as_16bit: true treats the input as little-endian 16-bit words; seed: sets the initial value (Hi-MD memory uses 0xA596).

descriptive_device_code(factory)

@spec descriptive_device_code(t()) :: {:ok, String.t()} | error()

A short device code string like "S1.600" (chip family, firmware version, subversion).

device_code(factory)

@spec device_code(t()) ::
  {:ok,
   %{
     chip_type: byte(),
     hwid: byte(),
     version: non_neg_integer(),
     subversion: byte()
   }}
  | error()

The device code: chip type, hardware id, firmware version and subversion.

device_version(factory)

@spec device_version(t()) :: {:ok, non_neg_integer()} | error()

The device's firmware version as a BCD-decoded number.

eeprom_checksum(data, opts \\ [])

@spec eeprom_checksum(
  binary(),
  keyword()
) :: 0..65535

EEPROM checksum with the standard seeds (0xA596 for Hi-MD).

open(device)

@spec open(NetMD.Device.t()) :: {:ok, t()} | error()

Authenticate a factory session on an open device and detect its variant.

Runs the same subunit-identifier handshake as the reference for side effects, authenticates, then reads the device code to promote MZ-RH1 devices to their special interface.

read(factory, address, length, type)

@spec read(t(), non_neg_integer(), non_neg_integer(), memory_type()) ::
  {:ok, binary()} | error()

Read length bytes of type memory at address.

read_metadata_peripheral(factory, sector, offset, length)

@spec read_metadata_peripheral(
  t(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer()
) ::
  {:ok, binary()} | error()

Read length bytes from the disc-cache metadata peripheral.

set_display_mode(factory, mode)

@spec set_display_mode(t(), :default | :override) :: :ok | error()

Set the display mode (:default or :override).

set_display_override(factory, text, opts \\ [])

@spec set_display_override(t(), String.t() | binary(), keyword()) :: :ok | error()

Override the display with text (a string, encoded to Shift-JIS, or raw bytes with raw: true). At most 8 characters or 9 raw bytes.

switch_status(factory)

@spec switch_status(t()) :: {:ok, [non_neg_integer()]} | error()

Front-panel switch and button state.

write(factory, address, data, type)

@spec write(t(), non_neg_integer(), binary(), memory_type()) :: :ok | error()

Write data to type memory at address.

write_metadata_peripheral(factory, sector, offset, data)

@spec write_metadata_peripheral(t(), non_neg_integer(), non_neg_integer(), binary()) ::
  :ok | error()

Write to the disc-cache metadata peripheral.