Links and medium internals¶
This document describes the internals behind links and mediums; see Links and mediums for more information.
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_receive_on_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.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 manner. 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 manner. 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_send_on_link_medium(cahute_link_medium *medium, cahute_u8 const *buf, size_t size)¶
Write exactly
size
bytes of data to the link.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.
Accepted flags are a subset of the flags for
cahute_open_serial_link()
: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.
- 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.
- 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 transport using the POSIX 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).
-
CAHUTE_LINK_MEDIUM_AMIGAOS_SERIAL¶
Serial transport using AmigaOS serial I/O, as described in the AmigaOS Serial Device Guide.
-
CAHUTE_LINK_MEDIUM_WIN32_SERIAL¶
Serial transport 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.
-
CAHUTE_LINK_MEDIUM_WIN32_CESG¶
Serial transport over USB bulk or stream-only operations for USB Mass Storage (UMS) transport using CASIO’s CESG502 driver through the Windows API.
As described in Windows USB drivers, 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.
-
CAHUTE_LINK_MEDIUM_WIN32_UMS¶
USB Mass Storage (UMS) transport using the Windows API.
It is used with a
HANDLE
:Closing uses
CloseHandle
;Requesting using SCSI uses
DeviceIoControl
withIOCTL_SCSI_PASS_THROUGH_DIRECT
.
-
CAHUTE_LINK_MEDIUM_LIBUSB¶
Serial transport over USB bulk using libusb.
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
.
-
CAHUTE_LINK_MEDIUM_LIBUSB_UMS¶
USB Mass Storage (UMS) transport using libusb.
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.
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_NONE¶
No protocol on a serial medium.
This can be selected by the user in order to use the medium functions more directly, through the ones referenced in Link medium access related function declarations.
-
CAHUTE_LINK_PROTOCOL_SERIAL_CASIOLINK¶
CASIOLINK protocol over a serial medium.
See CASIOLINK protocols – 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_AUTO¶
Automatic protocol detection on a USB 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_USB_NONE¶
No protocol on a USB medium.
This can be selected by the user in order to use the medium functions more directly, through the ones referenced in Link medium access related function declarations.
-
CAHUTE_LINK_PROTOCOL_USB_CASIOLINK¶
CASIOLINK over USB bulk transport.
See CASIOLINK protocols – Serial protocols used by pre fx-9860G calculators 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) 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) 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,
CAHUTE_USB_OHP
flag presence, andCAHUTE_USB_SEVEN
orCAHUTE_USB_CAS300
flag presence to protocol and medium type mapping is the following:(in) Intf. class
(in)
OHP
flag(in)
SEVEN
orCAS300
(out) Medium
(out) Protocol
8
absent
8
present
255
present
255
absent
CAS300
CAHUTE_LINK_PROTOCOL_USB_CASIOLINK
w/CAHUTE_CASIOLINK_VARIANT_CAS300
255
absent
SEVEN
255
absent
none
See USB detection for CASIO calculators for more information.
Warning
If
CAHUTE_USB_NOPROTO
flag is passed, the medium is kept, but the protocol is replaced byCAHUTE_LINK_PROTOCOL_USB_NONE
.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()
. It only picks USB devices matching the provided filter(s) which, if non-zero, act as an accepted device type mask, i.e.:If
CAHUTE_USB_FILTER_SERIAL
is set, devices identifying as a CASIOLINK, Protocol 7.00 or Protocol 7.00 Screenstreaming device are accepted;If
CAHUTE_USB_FILTER_UMS
is set, devices identifying as an USB Mass Storage speaking calculator are accepted.
If this function finds no matching devices, it sleeps and retries until it has no attempts left. If it finds multiple, it fails with error
CAHUTE_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
or CAHUTE_LINK_PROTOCOL_USB_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 withCAHUTE_SERIAL_PROTOCOL_AUTO
.The
CAHUTE_USB_NOCHECK
flag is forbidden if neitherCAHUTE_USB_SEVEN
norCAHUTE_USB_CAS300
is provided.
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).