Library¶
JLIP-specific functionality.
- class vcrtool.jlip.BandInfo(*values)¶
Band information codes.
-
BROADCAST_SATELLITE =
64¶ Broadcast satellite.
-
TERRESTRIAL_BROADCAST =
48¶ Terrestrial broadcast.
-
BROADCAST_SATELLITE =
- class vcrtool.jlip.CommandResponse(checksum: int, raw: bytes, return_data: bytes, status: CommandStatus, tuple: CommandResponseTuple)¶
Command response information.
- static from_bytes(resp: bytes) CommandResponse¶
Initialise from bytes.
- status : CommandStatus¶
Command status.
- tuple : CommandResponseTuple¶
Lower-level command response information.
- class vcrtool.jlip.CommandResponseTuple(jlip_id: int, command_status: CommandStatus, return_data: bytes)¶
Lower-level command response information.
- command_status : CommandStatus¶
Command status.
- class vcrtool.jlip.CommandStatus(*values)¶
JLIP command status codes.
-
COMMAND_ACCEPTED =
3¶ Command accepted.
-
COMMAND_ACCEPTED_NOT_COMPLETE =
4¶ Command accepted but not complete.
-
COMMAND_NOT_IMPLEMENTED =
1¶ Command not implemented.
-
COMMAND_NOT_POSSIBLE =
5¶ Command not possible.
-
COMMAND_ACCEPTED =
- class vcrtool.jlip.DeviceNameResponse(checksum: int, raw: bytes, return_data: bytes, status: CommandStatus, tuple: CommandResponseTuple, name: str)¶
Device name response.
- static from_bytes(resp: bytes) DeviceNameResponse¶
Initialise from bytes.
-
class vcrtool.jlip.JLIPTransport(serial_path: str, *, jlip_id: int =
1, raise_on_error_response: bool =True)¶ Send commands to HR-S9600U VCRs and similar devices over JLIP.
The serial port is the only I/O this class performs; the request framing and response validation live in
JLIPCodec.References
http://www.johnwillis.com/2018/09/jvc-jlip-joint-level-interface-protocol.html
https://dragonminded.com/bemani/dvdemu/JLIPProtocolDocumentation.pdf
https://www.remotecentral.com/cgi-bin/forums/viewpost.cgi?1040370
- codec¶
The sans-I/O codec used to build and validate frames.
- comm¶
Serial port object.
- eject() CommandResponse¶
Eject the tape.
- eject_wait() CommandResponse¶
Eject the tape and wait until it is done.
- fast_forward() CommandResponse¶
Fast forward the tape.
- fast_play_backward() CommandResponse¶
Fast play backward.
- fast_play_forward() CommandResponse¶
Fast play forward.
- frame_step() CommandResponse¶
Move forward one frame.
- frame_step_back() CommandResponse¶
Move back one frame.
- get_baud_rate_supported() CommandResponse¶
Get the baud rate supported by the device.
0x21is returned, meaning 19200 baud, but this cannot be trusted.
- get_device_code() CommandResponse¶
Get the device code.
- get_device_name() CommandResponse¶
Get the device name.
- get_input() CommandResponse¶
Get the input of the device.
- get_machine_code() CommandResponse¶
Get the machine code.
- get_play_speed() CommandResponse¶
Get playback speed.
Known responses in the first data field:
0x67means playing backward quickly.0x6Dmeans paused or frame advancing.0x75means normal.0x77means playing forward quickly.0x7Fis returned when inapplicable.
- get_power_state() PowerStateResponse¶
Get the power state of the device.
- get_tuner_mode() VTUModeResponse¶
Get the tuner mode.
-
get_vtr_mode(*, fast: bool =
False) VTRModeResponse¶ Get the VTR mode.
- jlip_id¶
JLIP ID.
- nop() CommandResponse¶
No operation command.
- pause() CommandResponse¶
Pause playback.
- pause_recording() CommandResponse¶
Pause recording.
- play() CommandResponse¶
Start playback.
- presence_check() CommandResponse¶
Check if the device is present and responding.
- preset_channel_down() CommandResponse¶
Change to the previous preset channel.
- preset_channel_up() CommandResponse¶
Change to the next preset channel.
- raise_on_error_response¶
Raise on error response.
- real_channel_down() CommandResponse¶
Change to the previous channel.
- real_channel_up() CommandResponse¶
Change to the next channel.
- record() CommandResponse¶
Start recording.
- reset_counter() CommandResponse¶
Reset the timecode counter.
- rewind() CommandResponse¶
Rewind the tape.
- rewind_wait() CommandResponse¶
Rewind the tape and wait until it is done.
- select_band(n: int) CommandResponse¶
Select a band.
- send_command(*args: int) bytes¶
Send a command at a slower rate limit.
This will raise pyrate_limiter’s
pyrate_limiter.BucketFullExceptionif the rate limit is exceeded.
- send_command_fast(*args: int) bytes¶
Send a command with a faster rate limit.
This will raise pyrate_limiter’s
pyrate_limiter.BucketFullExceptionif the rate limit is exceeded.
- set_channel(channel: int) CommandResponse¶
Set the channel to a specific value.
- set_jlip_id(n: int) CommandResponse¶
Set the JLIP ID of the device.
- Parameters:¶
- Returns:¶
Command response.
- Return type:¶
- Raises:¶
ValueError – If the ID is not between 1 and 99.
- set_record_mode(n: int) CommandResponse¶
Set the recording mode.
- set_record_speed(n: int) CommandResponse¶
Set the recording speed.
- slow_play_backward() CommandResponse¶
Slow play backward.
- slow_play_forward() CommandResponse¶
Slow play forward.
- stop() CommandResponse¶
Stop playback or recording.
- turn_off() CommandResponse¶
Turn the device off.
- turn_on() CommandResponse¶
Turn the device on.
- class vcrtool.jlip.PowerStateResponse(checksum: int, raw: bytes, return_data: bytes, status: CommandStatus, tuple: CommandResponseTuple, is_on: bool)¶
Power state response.
- static from_bytes(resp: bytes) PowerStateResponse¶
Initialise from bytes.
- class vcrtool.jlip.VTRMode(*values)¶
VTR mode codes.
-
EJECT =
0¶ Eject.
-
FF =
2¶ Fast forward.
-
NO_MODE =
15¶ No mode.
-
PAUSE =
7¶ Pause.
-
PLAY_BWD =
5¶ Play backward.
-
PLAY_FWD =
6¶ Play forward.
-
REC =
14¶ Record.
-
REC_PAUSE =
13¶ Record pause.
-
REW =
3¶ Rewind.
-
STOP =
1¶ Stop.
-
EJECT =
- class vcrtool.jlip.VTRModeResponse(checksum: int, raw: bytes, return_data: bytes, status: CommandStatus, tuple: CommandResponseTuple, drop_frame_mode_enabled: bool, framerate: int, hour: int, minute: int, second: int, frame: int, is_ntsc: bool, is_pal: bool, recordable: bool, tape_inserted: bool, vtr_mode: VTRMode)¶
VTR mode response information.
- static from_bytes(resp: bytes) VTRModeResponse¶
Initialise from bytes.
Sans-I/O protocol layer for the devices this package controls.
The classes here contain pure framing logic and perform no input or output. SIRCSCodec
turns a SIRCSCommand into a tuple of Pulse intervals (the modulated carrier
“marks” and silent “spaces” of an infrared frame) and reverses the process, while
JLIPCodec builds JLIP request frames and validates response frames. The transport
classes in vcrtool.sircs and vcrtool.jlip drive the actual hardware using the
bytes and pulses produced here, which keeps the protocol logic trivially testable without devices
or real-time sleeping.
The SIRCS timing values follow the canonical Sony specification where every interval is a multiple
of a single unit T of 600 microseconds, and each frame is padded to a fixed 45 millisecond
period.
- vcrtool.sansio.CARRIER_FREQUENCY_HZ¶
Nominal infrared carrier frequency in hertz.
- class vcrtool.sansio.CommandStatus(*values)¶
JLIP command status codes.
-
COMMAND_ACCEPTED =
3¶ Command accepted.
-
COMMAND_ACCEPTED_NOT_COMPLETE =
4¶ Command accepted but not complete.
-
COMMAND_NOT_IMPLEMENTED =
1¶ Command not implemented.
-
COMMAND_NOT_POSSIBLE =
5¶ Command not possible.
-
COMMAND_ACCEPTED =
- vcrtool.sansio.FRAME_DURATION_US¶
Total period of a single SIRCS frame in microseconds. The trailing space is stretched to it.
- class vcrtool.sansio.JLIPCodec¶
Sans-I/O builder and validator for JLIP command frames.
- vcrtool.sansio.ONE_MARK_US¶
Duration of the mark that encodes a logical one, in microseconds.
- class vcrtool.sansio.Pulse(carrier_on: bool, duration_us: int)¶
A single carrier interval that makes up part of a SIRCS frame.
- class vcrtool.sansio.SIRCSCodec¶
Sans-I/O encoder and decoder for SIRCS infrared frames.
- static decode(pulses: Iterable[Pulse]) SIRCSCommand¶
Decode the first frame of a pulse train back into a command.
Only the marks are inspected; spaces are ignored because their durations carry no information beyond separating marks. The variant is inferred from the number of data bits found. Trailing pulses beyond the first complete frame are ignored, which lets a captured repeated signal be decoded directly.
- Parameters:¶
- Returns:¶
The recovered payload.
- Return type:¶
- Raises:¶
ValueError – If no start mark is present, a mark does not match a known duration, or the number of data bits does not correspond to a known variant.
-
static encode(command: SIRCSCommand, *, repeat: int =
1) tuple[Pulse, ...]¶ Encode a command into the pulse train of one or more frames.
Bits are transmitted least-significant first, ordered command, then address, then extended field. Every frame begins with a start mark and is padded with a final space so that its total duration equals
FRAME_DURATION_US.- Parameters:¶
- command : SIRCSCommand¶
The payload to encode.
- repeat : int¶
Number of identical frames to emit back to back. Real receivers expect at least three.
- Returns:¶
The marks and spaces for
repeatconsecutive frames.- Return type:¶
- Raises:¶
ValueError – If
repeatis less than one or any field does not fit in its variant’s bit width.
-
class vcrtool.sansio.SIRCSCommand(command: int, address: int, extended: int =
0, variant: SIRCSVariant =SIRCSVariant.TWELVE_BIT)¶ A SIRCS payload independent of its wire representation.
- extended : int¶
The extended field. Only meaningful for
SIRCSVariant.TWENTY_BIT.
- variant : SIRCSVariant¶
The frame width that determines how the fields are packed.
- class vcrtool.sansio.SIRCSVariant(*values)¶
A SIRCS frame width.
Each member’s value is a
(command_bits, address_bits, extended_bits)tuple describing how the payload is partitioned.
- vcrtool.sansio.SPACE_US¶
Duration of the silent space that separates every mark, in microseconds.
- vcrtool.sansio.START_MARK_US¶
Duration of the leading start (header) mark in microseconds.
- vcrtool.sansio.UNIT_US¶
Base SIRCS timing unit
Tin microseconds. Every other interval is a multiple of this value.
- vcrtool.sansio.ZERO_MARK_US¶
Duration of the mark that encodes a logical zero, in microseconds.
- vcrtool.sansio.checksum(vals: collections.abc.Sequence[int]) int¶
Compute the checksum for a JLIP frame.
SIRCS (Sony Infrared Remote Control System) transport over a Raspberry Pi Pico.
-
class vcrtool.sircs.PicoSIRCSTransport(serial_path: str, *, baud_rate: int =
115200, invert: bool =False)¶ Transport that delegates SIRCS timing to a Raspberry Pi Pico over USB serial.
The protocol framing lives in
SIRCSCodec. This class serialises the pulse train it produces into a compact message and writes it to the Pico, whose firmware clocks the pin edges out with a PIO state machine for jitter-free timing. The PC therefore keeps all protocol knowledge and the Pico stays a dumb, precisely-timed output peripheral.The message is a sync byte, a 16-bit big-endian pulse count, and then one three-byte record per pulse: a level byte followed by a 16-bit big-endian duration in microseconds. The level is the final pin state, so
invert(used for an active-lowCONTROL Sjack) is resolved here and the firmware simply holds the pin at the given level.- codec¶
The sans-I/O codec used to build pulse trains.
- comm¶
Serial connection to the Pico.
-
send_command(command: SIRCSCommand, *, repeat: int =
3) None¶ Encode a command and send it to the Pico.
- Parameters:¶
- command : SIRCSCommand¶
The payload to send.
- repeat : int¶
Number of identical frames to play. Sony receivers expect at least three.
Utilities.
- async vcrtool.utils.adebug_create_subprocess_exec(*args: Any, **kwargs: Any) Process¶
Run a subprocess and log the command at the
logging.DEBUGlevel.- Return type:¶
asp.CompletedProcess[Any]
- async vcrtool.utils.adebug_sleep(interval: float) None¶
Sleep for a given interval and log the sleep time at the
logging.DEBUGlevel.
- vcrtool.utils.audio_device_is_available(audio_device: str) bool¶
Check if an ALSA device can be used by attempting to open it with ffmpeg.
- vcrtool.utils.debug_sleep(interval: float) None¶
Sleep for a given interval and log the sleep time at the
logging.DEBUGlevel.
- vcrtool.utils.debug_sp_run(*args: Any, **kwargs: Any) CompletedProcess[Any]¶
Run a subprocess and log the command at the
logging.DEBUGlevel.- Return type:¶
sp.CompletedProcess[Any]
- vcrtool.utils.get_pipewire_audio_device_node_id(name: str) tuple[str, str] | tuple[None, None]¶
Get the Pipewire node ID of an ALSA device.
- vcrtool.utils.pad_right(value: T, list_: collections.abc.Sequence[T], max_length: int) list[T]¶
Pad a sequence to the right with a value.