Links and mediums¶
All communication implementations are centered around resources called links. Internally, links are mostly constituted of:
A medium, which is an interface with a set of resources to communicate with the underlying medium opened with the system or hardware.
A protocol, which is a set of resources and functions that do not constitute an interface, since protocols may obey different logics.
A link only requires one memory allocation (except for system resources that are allocated / opened using different functions), and the medium and the protocol are initialized together using link opening functions.
Mediums¶
Mediums define a common set of interfaces that can be used by protocols to communicate with the device or host.
A medium is represented by the following type:
-
struct cahute_link_medium¶
Link medium representation.
This structure is usually directly allocated with the link, i.e.
cahute_link
instance, and is accessed throughlink->medium
.
Medium interface¶
Most mediums support a stream-like interface with the following functions:
-
int cahute_read_from_link_medium(cahute_link_medium *medium, cahute_u8 *buf, size_t size, unsigned long first_timeout, unsigned long next_timeout)¶
Read exactly
size
bytes of data into the buffer.Note
An alias for using the medium indirectly through a link is available as
cahute_read_from_link
, where the first argument is the link instead of the medium.This function uses the medium read buffer to store any incoming excess data, for it to be processed first next time before using the underlying buffer to read more data.
Warning
This function does not provide the number of bytes that have been read in case of error (with the exception of
CAHUTE_ERROR_TIMEOUT_START
, which implies that no bytes have been read).This is to simplify as much as possible protocol implementations, but it also means that the medium should be considered irrecoverable in such cases.
Errors to be expected from this function are the following:
CAHUTE_ERROR_TIMEOUT_START
The first byte was not received in a timely matter. This can only occur if
first_timeout
was not set to 0.CAHUTE_ERROR_TIMEOUT
A byte past the first one was not received in a timely matter. This can only occur if
next_timeout
was not set to 0.CAHUTE_ERROR_GONE
The device is no longer present, usually either because the USB cable has been unplugged on one end or the other, or the serial adapter has been unplugged from the host.
CAHUTE_ERROR_UNKNOWN
The medium-specific operations have yielded an error code that Cahute did not interpret. Some details can usually be found in the logs.
- Parameters:
medium – Link medium to receive data from.
buf – Buffer in which to write the received data.
size – Size of the data to write to the buffer.
first_timeout – Maximum delay to wait before the first byte of the data, in milliseconds. If this is set to 0, the first byte will be awaited indefinitely.
next_timeout – Maximum delay to wait between two bytes of the data, or before the last byte, in milliseconds. If this is set to 0, next bytes will be awaited indefinitely.
- Returns:
Error, or
CAHUTE_OK
.
-
int cahute_skip_from_link_medium(cahute_link_medium *medium, size_t size, unsigned long first_timeout, unsigned long next_timeout)¶
Skip exactly
size
bytes of data.Note
An alias for using the medium indirectly through a link is available as
cahute_skip_from_link
, where the first argument is the link instead of the medium.This function is a convenience function for protocol implementations. It uses
cahute_read_from_link()
to read into a trashable buffer, and thus, comes with the same risks and errors.- Parameters:
medium – Link medium to skip received data from.
size – Size of the data to receive and skip.
first_timeout – Maximum delay to wait before the first byte of the data, in milliseconds. If this is set to 0, the first byte will be awaited indefinitely.
next_timeout – Maximum delay to wait between two bytes of the data, or before the last byte, in milliseconds. If this is set to 0, next bytes will be awaited indefinitely.
- Returns:
Error, or
CAHUTE_OK
.
-
int cahute_write_to_link_medium(cahute_link_medium *medium, cahute_u8 const *buf, size_t size)¶
Write exactly
size
bytes of data to the link.Note
An alias for using the medium indirectly through a link is available as
cahute_write_to_link
, where the first argument is the link instead of the medium.Errors to be expected from this function are the following:
CAHUTE_ERROR_GONE
The device is no longer present, usually either because the USB cable has been unplugged on one end or the other, or the serial adapter has been unplugged from the host.
CAHUTE_ERROR_UNKNOWN
The medium-specific operations have yielded an error code that Cahute did not interpret. Some details can usually be found in the logs.
- Parameters:
medium – Link medium to send data to.
buf – Buffer from which to read the data to send.
size – Size of the data to read and send.
- Returns:
Error, or
CAHUTE_OK
.
Serial mediums such as CAHUTE_LINK_MEDIUM_POSIX_SERIAL
or
CAHUTE_LINK_MEDIUM_WIN32_SERIAL
support changing the parameters
of the serial link using the following function:
-
int cahute_set_serial_params_to_link_medium(cahute_link_medium *medium, unsigned long flags, unsigned long speed)¶
Set the serial parameters to the medium.
Note
An alias for using the medium indirectly through a link is available as
cahute_set_serial_params_to_link
, where the first argument is the link instead of the medium.Accepted flags are a subset of the flags for
cahute_open_serial()
:CAHUTE_SERIAL_STOP_*
(stop bits);CAHUTE_SERIAL_PARITY_*
(parity);CAHUTE_SERIAL_XONXOFF_*
(XON/XOFF software control);CAHUTE_SERIAL_DTR_*
(DTR hardware control);CAHUTE_SERIAL_RTS_*
(RTS hardware control).
- Parameters:
medium – Link medium to set the serial parameters to.
flags – Flags to set to the medium.
speed – Speed to set to the medium.
- Returns:
Error, or
CAHUTE_OK
.
USB Mass Storage mediums support an interface capable of making SCSI requests, with the following functions:
-
int cahute_scsi_request_to_link_medium(cahute_link_medium *medium, cahute_u8 const *command, size_t command_size, cahute_u8 const *data, size_t data_size, int *statusp)¶
Emit an SCSI request to the medium, with or without data.
Note
An alias for using the medium indirectly through a link is available as
cahute_scsi_request_to_link
, where the first argument is the link instead of the medium.- Parameters:
medium – Link medium to send the command and optional payload to, and receive the status from.
command – Command to send.
command_size – Size of the command to send.
data – Optional data to send along with the command. This can be set to
NULL
ifdata_size
is set to 0.data_size – Size of the data to send along with the command.
statusp – Pointer to the status code to set to the one returned by the device.
- Returns:
Error, or
CAHUTE_OK
.
-
int cahute_scsi_request_from_link_medium(cahute_link_medium *medium, cahute_u8 const *command, size_t command_size, cahute_u8 *buf, size_t buf_size, int *statusp)¶
Emit an SCSI request to the medium, while requesting data.
Note
An alias for using the medium indirectly through a link is available as
cahute_scsi_request_from_link
, where the first argument is the link instead of the medium.- Parameters:
medium – Link medium to send the command to, and receive the data and status from.
command – Command to send.
command_size – Size of the command to send.
buf – Buffer to fill with the requested data.
buf_size – Size of the data to request.
statusp – Pointer to the status code to set to the one returned by the device.
- Returns:
Error, or
CAHUTE_OK
.
Available medium types¶
Medium types are represented as CAHUTE_LINK_MEDIUM_*
constants internally.
Warning
The medium constants are only represented if they are available on the
current configuration. This is a simple way for medium-specific
implementations to be defined or not, with #ifdef
.
Available mediums are the following:
-
CAHUTE_LINK_MEDIUM_POSIX_SERIAL¶
Serial medium using the POSIX STREAMS API, with a file descriptor (fd):
Closing using close(2);
Sending uses write(2);
Serial params setting uses termios(3), including
tcdrain()
, and tty_ioctl(4), especiallyTIOCMGET
andTIOCMSET
.
Only available on platforms considered POSIX, including Apple’s OS X explicitely (since they do not define the
__unix__
constant like Linux does).Available protocols on this medium are the following:
-
CAHUTE_LINK_MEDIUM_AMIGAOS_SERIAL¶
Serial medium using AmigaOS serial I/O, as described in the AmigaOS Serial Device Guide.
Available protocols on this medium are the following:
-
CAHUTE_LINK_MEDIUM_WIN32_SERIAL¶
Serial medium using the Windows API, with a
HANDLE
and Overlapped I/O:Closing uses
CloseHandle
;Receiving uses
ReadFile
andWaitForSingleObject
, and depending on whether the second function succeeded or not, eitherGetOverlappedResult
orCancelIo
, to ensure we don’t have any buffer writes post-freeing the link;Sending uses
WriteFile
andWaitForSingleObject
, and depending on whether the second function succeeded or not, eitherGetOverlappedResult
orCancelIo
, to ensure we don’t have any buffer reads post-freeing the link;Serial params setting uses
SetCommState
.
For more information, see Serial Communications in Win32.
Available protocols on this medium are the following:
-
CAHUTE_LINK_MEDIUM_WIN32_CESG¶
USB device used as a host through CASIO’s CESG502 driver using the Windows API.
As described in Driver detection on Microsoft Windows, we must detect if the device driver is CESG502 or a libusb-compatible driver by using SetupAPI or CfgMgr32, and use this medium in the first case.
It is used with a
HANDLE
and Overlapped I/O:Closing uses
CloseHandle
;Receiving uses
ReadFile
andWaitForSingleObject
, and depending on whether the second function succeeded or not, eitherGetOverlappedResult
orCancelIo
, to ensure we don’t have any buffer writes post-freeing the link;Sending uses
WriteFile
andWaitForSingleObject
, and depending on whether the second function succeeded or not, eitherGetOverlappedResult
orCancelIo
, to ensure we don’t have any buffer reads post-freeing the link.
Note that CESG502 waits for calculator input by default, and always requires a buffer bigger than the actual input it receives (4 KiB is usually enough). It also abstracts away whether it using bulk transfers directly, or USB Mass Storage, into a stream interface; this however does not allow you to make SCSI requests directly.
Available protocols on this medium are the following:
-
CAHUTE_LINK_MEDIUM_WIN32_UMS¶
USB Mass Storage device used as a host using the Windows API.
It is used with a
HANDLE
:Closing uses
CloseHandle
;Requesting using SCSI uses
DeviceIoControl
withIOCTL_SCSI_PASS_THROUGH_DIRECT
.
Available protocols on this medium are the following:
-
CAHUTE_LINK_MEDIUM_LIBUSB¶
USB device used as a host through libusb, with bulk transport.
It is used with a
libusb_device_handle
, opened using alibusb_context
:Closing uses
libusb_close
on the device handle, andlibusb_exit
on the libusb context;Receiving and sending uses
libusb_bulk_transfer
.
Available protocols on this medium are the following:
-
CAHUTE_LINK_MEDIUM_LIBUSB_UMS¶
USB device used as a host through libusb, implementing USB Mass Storage (UMS) with Bulk-only transport.
As for
CAHUTE_LINK_MEDIUM_LIBUSB
, it is used with alibusb_device_handle
, opened using alibusb_context
:Closing uses
libusb_close
on the device handle, andlibusb_exit
on the libusb context;Requesting using SCSI uses
libusb_bulk_transfer
with manual reading and writing of the Command Block Wrapper (CBW) and Command Status Wrapper (CSW).
See USB Mass Storage Class, Bulk-Only Transport for more information on CBW and CSW format and protocol in general.
Available protocols on this medium are the following:
Protocols¶
Protocols define what operations and logics are available, and how to implement these operations and logics.
All protocols may use the data buffer, which is in the link directly, which serves at storing raw data or screen data received using the protocol.
Available protocols are:
-
CAHUTE_LINK_PROTOCOL_SERIAL_AUTO¶
Automatic protocol detection on a serial medium.
Note that this doesn’t outlive link protocol initialization, and gets replaced by the actual protocol afterwards; see Protocol initialization for more details.
-
CAHUTE_LINK_PROTOCOL_SERIAL_CASIOLINK¶
CASIOLINK protocol over a serial medium.
See CASIOLINK protocol – Serial protocols used by pre fx-9860G calculators for more information.
Note that in this case, the CASIOLINK variant is set in the
protocol_state.casiolink.variant
property of the link.
-
CAHUTE_LINK_PROTOCOL_SERIAL_SEVEN¶
Protocol 7.00 over a serial medium.
See Protocol 7.00 – Serial and USB protocol used by post fx-9860G calculators for more information.
This differs from
CAHUTE_LINK_PROTOCOL_USB_SEVEN
by the availability of command 02 “Set link settings”.
-
CAHUTE_LINK_PROTOCOL_SERIAL_SEVEN_OHP¶
Protocol 7.00 Screenstreaming over a serial medium.
See Protocol 7.00 Screenstreaming – fx-9860G and fx-CG screenstreaming for more information.
-
CAHUTE_LINK_PROTOCOL_USB_SEVEN¶
Protocol 7.00 over USB bulk transport or USB Mass Storage or USB Mass Storage commands.
See Protocol 7.00 – Serial and USB protocol used by post fx-9860G calculators and USB Mass Storage (UMS) and proprietary extensions for fx-CG calculators for more information.
-
CAHUTE_LINK_PROTOCOL_USB_SEVEN_OHP¶
Protocol 7.00 Screenstreaming over USB bulk transport or USB Mass Storage extended commands.
See Protocol 7.00 Screenstreaming – fx-9860G and fx-CG screenstreaming and USB Mass Storage (UMS) and proprietary extensions for fx-CG calculators for more information.
-
CAHUTE_LINK_PROTOCOL_USB_MASS_STORAGE¶
USB Mass Storage without extensions.
Opening behaviours¶
In this section, we will describe the behaviour of link opening functions.
cahute_open_serial_link()
This function first validates all params to ensure compatibility, e.g. throws an error in case of unsupported flag, speed, or combination.
Note
The protocol is selected, depending on the flags, to one of the following:
Then, depending on the platform:
On POSIX and compatible, it will attempt to open the serial device using open(2). If this succeeds, the medium of the created link will be set to
CAHUTE_LINK_MEDIUM_POSIX_SERIAL
;On Windows, it will attempt to open the serial device using
CreateFile
, then, if it succeeds, callSetCommTimeouts
withReadTimeoutInterval
set toMAXDWORD
in order to only read what is directly available, and create the event for the overlapped object usingCreateEvent
. If this succeeds, the medium of the created link will be set toCAHUTE_LINK_MEDIUM_WIN32_SERIAL
;Otherwise, it will return
CAHUTE_ERROR_IMPL
.
If the underlying medium has successfully been opened, it will allocate the link and call
cahute_set_serial_params_to_link()
to set the initial serial parameters to it.It will then initialize the protocol using the common protocol initialization procedure; see Protocol initialization.
cahute_open_usb_link()
This function first validates all params to ensure compatibility, e.g. throws an error in case of unsupported flag or combination.
If libusb support has been disabled, the function returns
CAHUTE_ERROR_IMPL
.Otherwise, on all platforms, this function creates a context using
libusb_init
, gets the device list usinglibusb_get_device_list
, and finds one matching the provided bus and address numbers usinglibusb_get_bus_number
andlibusb_get_device_address
on every entry.If a matching device is found, the configuration is obtained using
libusb_get_device_descriptor
andlibusb_get_active_config_descriptor
, in order to:Get the vendor (VID) and product (PID) identifiers, to ensure they match one of the known combinations for CASIO calculators.
Get the interface class (
bInterfaceClass
) to determine the protocol and medium type.In both cases, ensure that the bulk IN and OUT endpoints exist, and get their endpoint identifiers.
Note
While historical implementations of CASIO’s protocols using libusb hardcode 0x82 as Bulk IN and 0x01 as Bulk OUT, this has proven to change on other platforms such as OS X; see #3 (comment 1823215641) for more context.
The interface class and
CAHUTE_USB_OHP
flag presence to protocol and medium type mapping is the following:(in) Intf. class
(in)
OHP
flag(out) Medium
(out) Protocol
8
absent
8
present
255
absent
255
present
See USB detection for CASIO calculators for more information.
Once all metadata has been gathered, the function opens the device using
libusb_open
, and attempt to claim its interface usinglibusb_claim_interface
andlibusb_detach_kernel_driver
.Note
Access errors, i.e. any of these two functions returning
LIBUSB_ERROR_ACCESS
, are ignored, since libusb is still able to communicate with the device on some platforms afterwards.See #3 for more context.
If the device opening yields
LIBUSB_ERROR_NOT_SUPPORTED
, it means that the device is running a driver that is not supported by libusb.On Windows, in this case, we look for a USB device with a device address equal to the libusb port number, obtained using
libusb_get_port_number
, then:If the underlying driver to the device is identified as CESG502, we use the USB device interface as a
CAHUTE_LINK_MEDIUM_WIN32_CESG
medium;Otherwise, we look for disk drive then volume devices via bus relations, and use the volume device interface as a
CAHUTE_LINK_MEDIUM_WIN32_UMS
medium.
Once all is done, the link is created with the selected medium and protocol. The function will then initialize the protocol using the common protocol initialization procedure; see Protocol initialization.
cahute_open_simple_usb_link()
This function is a convenience function, using mostly public functions to work:
It detects available USB devices using
cahute_detect_usb()
. If it finds none, it sleeps and retries until it has no attempts left. If it finds multiple, it fails with errorCAHUTE_ERROR_TOO_MANY
.It opens the found USB device using
cahute_open_usb_link()
.
It used to be to the program or library to define by itself, and was in the guides, but this behaviour is found in most simple scripts that use the Cahute library, so it was decided to include it within the library.
Protocol initialization¶
The common protocol initialization procedure is defined by a function named
init_link
in link/open.c
.
First of all, if the selected protocol is
CAHUTE_LINK_PROTOCOL_SERIAL_AUTO
, the communication initialization
is used to determine the protocol in which both devices should communicate.
Note
Since the initialization step is necessary for automatic protocol
discovery to take place, the CAHUTE_SERIAL_NOCHECK
flag
is forbidden with CAHUTE_SERIAL_PROTOCOL_AUTO
.
This is described in cahute_open_serial_link()
’s flags description.
Then, the initialization sequence is run depending on the protocol and role
(sender or receiver, depending on the presence of the
CAHUTE_SERIAL_RECEIVER
CAHUTE_USB_RECEIVER
in the flags
of the original function).