1
0
Fork 0

Compare commits

...

5 Commits

Author SHA1 Message Date
Thomas Touhey 985f970459 docs: highlight supported features and platforms 2024-05-04 17:45:21 +00:00
Thomas Touhey 52a8446ffb fix: fix bad directory detection on file sending
In case a directory is passed to cahute_send_file_to_storage(),
the file size is a very high value that does not reflect any
reality. We now detect such a case.
2024-05-04 19:15:42 +02:00
Thomas Touhey 59a6046f50 fix: fix bad directory detection for p7os
In case a directory is passed as as the '--uexe' option to
p7os, the memory allocation fails because ftell() returns a
very high value that does not reflect any reality.
We now detect such a case.
2024-05-04 19:12:17 +02:00
Thomas Touhey b28d924b74 fix: fix file name checks in p7
The 'p7 send mydir/myfile.ext' command resulted in '/myfile.ext'
being picked as the target file name instead of 'myfile.ext'.

The following commands were considered valid where they should
not have been:

* 'p7 send mydir/': could not determine the target file name
  correctly.
* 'p7 send ""': could not determine target file name correctly,
  and could not open an empty source path.
* 'p7 send hello -o ""': target file name is empty.
* 'p7 get ""': source file name is empty.
* 'p7 get hello -o ""': could not open an empty local target path.

Empty directory names are also now checked and causes the
command to fail.
2024-05-04 19:12:17 +02:00
Thomas Touhey 41366d5aef feat: add CAS100 basic support 2024-05-04 18:51:54 +02:00
17 changed files with 911 additions and 277 deletions

View File

@ -402,14 +402,15 @@ static int parse_medium_params(
char const *raw_parity =
get_casrc_setting_property(dstg, ostg, "parity");
medium->data.com.serial_speed = 9600;
medium->data.com.serial_flags = CAHUTE_SERIAL_STOP_TWO;
medium->data.com.serial_speed = 0;
medium->data.com.serial_flags = 0;
if (raw_speed) {
unsigned long speed = atol(raw_speed);
if (speed != 1200 && speed != 2400 && speed != 4800
&& speed != 9600) {
&& speed != 9600 && speed != 19200 && speed != 38400
&& speed != 57600 && speed != 115200) {
fprintf(
stderr,
"Invalid property baud=%s for %s.\n",
@ -424,9 +425,9 @@ static int parse_medium_params(
if (!raw_parity)
medium->data.com.serial_flags |= CAHUTE_SERIAL_PARITY_OFF;
else if (!strcmp(raw_parity, "e"))
else if (raw_parity[0] == 'e' || raw_parity[0] == 'E')
medium->data.com.serial_flags |= CAHUTE_SERIAL_PARITY_EVEN;
else if (!strcmp(raw_parity, "o"))
else if (raw_parity[0] == 'o' || raw_parity[0] == 'O')
medium->data.com.serial_flags |= CAHUTE_SERIAL_PARITY_ODD;
else
medium->data.com.serial_flags |= CAHUTE_SERIAL_PARITY_OFF;
@ -445,15 +446,18 @@ static int parse_medium_params(
|| get_casrc_setting_property(dstg, ostg, "9700")
|| get_casrc_setting_property(dstg, ostg, "9800"))
medium->data.com.serial_flags |=
CAHUTE_SERIAL_CASIOLINK_VARIANT_CAS40;
CAHUTE_SERIAL_PROTOCOL_CASIOLINK
| CAHUTE_SERIAL_CASIOLINK_VARIANT_CAS40;
else if (get_casrc_setting_property(dstg, ostg, "9750")
|| get_casrc_setting_property(dstg, ostg, "9850")
|| get_casrc_setting_property(dstg, ostg, "9950"))
medium->data.com.serial_flags |=
CAHUTE_SERIAL_CASIOLINK_VARIANT_CAS50;
else
CAHUTE_SERIAL_PROTOCOL_CASIOLINK
| CAHUTE_SERIAL_CASIOLINK_VARIANT_CAS50;
else if (get_casrc_setting_property(dstg, ostg, "afx")) /* Extended */
medium->data.com.serial_flags |=
CAHUTE_SERIAL_CASIOLINK_VARIANT_AUTO;
CAHUTE_SERIAL_PROTOCOL_CASIOLINK
| CAHUTE_SERIAL_CASIOLINK_VARIANT_CAS100;
medium->data.com.pause =
get_casrc_setting_property(dstg, ostg, "pause") != NULL;

View File

@ -32,6 +32,17 @@
#include <string.h>
#include <errno.h>
/* On some platforms, for directories, ftell() returns an insanely high
* number that may be platform-specific, e.g. 9223372036854775807 (2^63 - 1),
* which would correspond to the highest positive value of a long if defined
* on 64 bits. In order to detect such cases in a reasonably
* platform-independent manner, we want to cap the size of any file that
* gets stored into memory.
*
* See ``read_file_contents()`` for more details on the usage of this
* constant. */
#define REASONABLE_FILE_CONTENT_LIMIT 134217728 /* 128 MiB */
/**
* Get the current logging level as a string.
*
@ -122,6 +133,84 @@ extern void print_content(
fprintf(stdout, "<CONVERSION FAILED: 0x%04X>", err);
}
/**
* Read file contents into a buffer.
*
* @param path Path to the file to read.
* @param datap Pointer to the data to allocate and populate.
* @param sizep Pointer to the data size to populate.
* @return 0 if ok, other otherwise.
*/
extern int
read_file_contents(char const *path, cahute_u8 **datap, size_t *sizep) {
cahute_u8 *data = NULL;
size_t size;
FILE *fp;
fp = fopen(path, "rb");
if (!fp) {
fprintf(stderr, "Unable to open the file: %s\n", strerror(errno));
goto fail;
}
if (fseek(fp, 0, SEEK_END)) {
fprintf(
stderr,
"Unable to seek to the end of the file: %s\n",
strerror(errno)
);
goto fail;
}
size = ftell(fp);
if (size > REASONABLE_FILE_CONTENT_LIMIT) {
fprintf(
stderr,
"Unable to open the file: file too big (over 128MiB) or "
"unsupported file type (e.g. directory)\n"
);
goto fail;
}
if (fseek(fp, 0, SEEK_SET)) {
fprintf(
stderr,
"Unable to seek to the start of the file: %s\n",
strerror(errno)
);
goto fail;
}
if (!size) {
fprintf(stderr, "File cannot be empty!\n");
goto fail;
}
data = malloc(size);
if (!data) {
fprintf(stderr, "malloc() failed.\n");
goto fail;
}
if (!fread(data, size, 1, fp)) {
fprintf(stderr, "Could not read file data: %s\n", strerror(errno));
goto fail;
}
fclose(fp);
*datap = data;
*sizep = size;
return 0;
fail:
if (fp)
fclose(fp);
if (data)
free(data);
return 1;
}
/**
* Get a line and allocate it.
*

View File

@ -40,6 +40,9 @@ extern void print_content(
int dest_encoding
);
extern int
read_file_contents(char const *path, cahute_u8 **datap, size_t *sizep);
/* Portable getdelim() implementation. */
extern ssize_t
portable_getdelim(char **sp, size_t *np, int delim, FILE *filep);

View File

@ -338,7 +338,7 @@ static inline int check_directory_name(char const *name) {
return 1;
n = strnlen(name, 9);
if (n > 8)
if (!n || n > 8)
return 0;
for (; n--; name++)
@ -362,7 +362,7 @@ static inline int check_file_name(char const *name) {
return 1;
n = strnlen(name, 13);
if (n > 12)
if (!n || n > 12)
return 0;
for (; n--; name++)
@ -597,6 +597,8 @@ int parse_args(int argc, char **argv, struct args *args) {
o_output = strrchr(params[0], '/');
if (!o_output)
o_output = params[0];
else
o_output++;
}
args->command = COMMAND_SEND;

View File

@ -138,75 +138,6 @@ static struct long_option const long_options[] = {
LONG_OPTION_SENTINEL
};
/**
* Read file contents into a buffer.
*
* @param path Path to the file to read.
* @param datap Pointer to the data to allocate and populate.
* @param sizep Pointer to the data size to populate.
* @return 0 if ok, other otherwise.
*/
static int
read_file_contents(char const *path, cahute_u8 **datap, size_t *sizep) {
cahute_u8 *data = NULL;
size_t size;
FILE *fp;
fp = fopen(path, "rb");
if (!fp) {
fprintf(stderr, "Unable to open the file: %s\n", strerror(errno));
goto fail;
}
if (fseek(fp, 0, SEEK_END)) {
fprintf(
stderr,
"Unable to seek to the end of the file: %s\n",
strerror(errno)
);
goto fail;
}
size = ftell(fp);
if (fseek(fp, 0, SEEK_SET)) {
fprintf(
stderr,
"Unable to seek to the start of the file: %s\n",
strerror(errno)
);
goto fail;
}
if (!size) {
fprintf(stderr, "File cannot be empty!\n");
goto fail;
}
data = malloc(size);
if (!data) {
fprintf(stderr, "malloc() failed.\n");
goto fail;
}
if (!fread(data, size, 1, fp)) {
fprintf(stderr, "Could not read file data: %s\n", strerror(errno));
goto fail;
}
fclose(fp);
*datap = data;
*sizep = size;
return 0;
fail:
if (fp)
fclose(fp);
if (data)
free(data);
return 1;
}
/**
* Parse the command-line arguments.
*

View File

@ -61,12 +61,13 @@ todo_include_todos = True
mermaid_output_format = "raw"
mermaid_init_js = """
function isDarkMode() {
const theme = document.body.getAttribute("data-theme");
const color = (
getComputedStyle(document.body)
.getPropertyValue("--color-foreground-primary")
);
if (color == "#ffffffcc")
if (theme == "dark" || color == "#ffffffcc")
return true;
return false;

View File

@ -3,7 +3,29 @@ Cahute |version|
Cahute is a library and set of command-line utilities to handle serial
and USB communication protocols and file formats related to CASIO calculators,
dating from the 1990s to today.
dating from the 1990s to today. It provides the following features:
* **Transferring storage files** from and to fx-9860G compatible calculators,
over USB and serial links;
* **Receiving programs from all CASIO calculators since 1991**, over USB and
serial links;
* **Converting between character encodings**;
* **Screenstreaming** from fx-9860G, fx-CG and compatible calculators, over
USB links;
* **Flashing fx-9860G and compatible** using
:ref:`the fxRemote method <seven-fxremote-flash>`.
Officially supported OSes are Archlinux_-based and macOS_.
.. note::
For support for other platforms, see the following issues:
* `Windows XP and above
<https://gitlab.com/cahuteproject/cahute/-/issues/10>`_;
* `Debian-based distributions
<https://gitlab.com/cahuteproject/cahute/-/issues/8>`_;
* `AmigaOS <https://gitlab.com/cahuteproject/cahute/-/issues/26>`_.
The project is being worked on `on Gitlab <Cahute on Gitlab_>`_.
It is maintained by `Thomas Touhey`_.
@ -101,6 +123,9 @@ is based on.
project
.. _Archlinux: https://archlinux.org/
.. _macOS: https://www.apple.com/macos/
.. _Cahute on Gitlab: https://gitlab.com/cahuteproject/cahute
.. _Thomas Touhey: https://thomas.touhey.fr/
.. _CeCILL: http://www.cecill.info/licences.en.html

View File

@ -289,6 +289,14 @@ selected input or output format is a serial port.
``9750``, ``9850``, ``9950``
If set, use the fx-9750G header and payload format.
``afx``
If set, use the AlgebraFX / Graph 100 header and payload format.
.. warning::
This is an extended option, that does not exist in the original
CaS source.
``raw``
If set, use the raw header and payload format.
@ -302,14 +310,14 @@ selected input or output format is a serial port.
If none of the above are matched, the parity is set to even.
``baud``
Baud rate to set to the serial connection, as exact string matches:
Baud rate to set to the serial connection, from 1200 to 115200 bauds.
* ``1200``: 1200 bauds.
* ``2400``: 2400 bauds.
* ``4800``: 4800 bauds.
* ``9600``: 9600 bauds.
.. warning::
By default, the baud rate is set to 9600 bauds.
Baud rates from 19200 and above are not available in the original
CaS source.
By default, the baud rate depends on the selected model.
``dtr``
If set, enable DTR on the serial connection.

View File

@ -8,10 +8,11 @@ Both sides are defined in advance, and do not exchange roles during transfer.
In no cases can the receiver request a resource from the sender, as it
must only respond to requests and receive what the sender chooses to send.
Initiate the connection
-----------------------
Initiate the connection using the CAS40 or CAS50 variant
--------------------------------------------------------
In order to initiate the connection, the communication schema is the following:
In order to initiate the connection with the CAS40 and CAS50 variants,
the communication schema is the following:
.. mermaid::
@ -22,6 +23,44 @@ In order to initiate the connection, the communication schema is the following:
sender->>receiver: Send a 0x16 (START)
receiver->>sender: Send a 0x13 (ESTABLISHED)
See :ref:`casiolink-packet-format` for more information.
Initiate the connection using the CAS100 variant
------------------------------------------------
The CAS100 initiation flow is more complete than the CAS40 and CAS50 variants:
.. mermaid::
sequenceDiagram
Participant sender as Sender
Participant receiver as Receiver
sender->>receiver: Send a 0x16 (START)
receiver->>sender: Send a 0x13 (ESTABLISHED)
sender->>receiver: Send an MDL1 header (0x3A)
receiver->>sender: Answer with an MDL1 header (0x3A)
sender->>receiver: Acknowledge (0x06)
receiver->>sender: Acknowledge (0x06)
.. note::
On cross-variant CASIOLINK reception, since the MDL1 header is received
in the place any other data would be received in the CAS40 and CAS50
variants, the MDL1 header and acknowledgement reactions must be
managed in the data reception utilities rather than in the
communication initialization.
However, when the CAS100 variant is selected explicitely by the user,
the MDL1 header can and should be managed in the communication
initialization directly, so that device information can be exploited.
See the following for more information:
* :ref:`casiolink-packet-format`;
* :ref:`casiolink-cas100-mdl1`.
Send or receive data using the CAS40 or CAS50 variant
-----------------------------------------------------

View File

@ -119,6 +119,8 @@ The format of such headers is the following:
- Checksum for the packet.
-
.. _casiolink-cas100-adn1:
``ADN1`` headers
~~~~~~~~~~~~~~~~
@ -153,6 +155,8 @@ These packets seem to be used to send data.
-
- Integer (little endian), e.g. ``0x200`` (512).
.. _casiolink-cas100-adn2:
``ADN2`` headers
~~~~~~~~~~~~~~~~
@ -182,6 +186,34 @@ Unknown purpose.
-
- Integer (little endian), e.g. ``0x100`` (256).
.. _casiolink-cas100-bku1:
``BKU1`` headers
~~~~~~~~~~~~~~~~
Unknown purpose.
.. list-table::
:header-rows: 1
* - Offset
- Size
- Field name
- Description
- Values
* - 0 (0x00)
- 4 B
- Data Type (*DT*)
-
- ``RAMS``, ``RAMI``, ``RAM1``
* - 4 (0x04)
- 4 B
- ?
-
- Big endian 32-bit integer, e.g. ``0xE000``.
.. _casiolink-cas100-end1:
``END1`` headers
~~~~~~~~~~~~~~~~
@ -189,6 +221,8 @@ These packets are sent at the end of the communication.
They do not use additional data.
.. _casiolink-cas100-fcl1:
``FCL1`` headers
~~~~~~~~~~~~~~~~
@ -208,6 +242,8 @@ Unknown purpose.
-
- ``S000``
.. _casiolink-cas100-fmv1:
``FMV1`` headers
~~~~~~~~~~~~~~~~
@ -232,10 +268,62 @@ Unknown purpose.
-
- ``FR00`` (sic.)
.. _casiolink-cas100-mcs1:
``MCS1`` headers
~~~~~~~~~~~~~~~~
These packets contain main memory data.
.. list-table::
:header-rows: 1
* - Offset
- Size
- Field name
- Description
- Values
* - 0 (0x00)
- 3 B
- Reserved
-
- Set to ``\0``.
* - 3 (0x03)
- 2 B
- File size
-
- Big-endian 16-bit integer (?).
* - 5 (0x05)
- 1 B
- Data type
-
- 8-bit integer, among the following:
.. list-table::
:header-rows: 1
* - Data type
- Description
* - ``0x01``
- Program
* - 6 (0x06)
- 8 B
- Data name
-
- ``0xFF`` optionally terminated string.
* - 14 (0x0E)
- 8 B
- Group name
-
- ``0xFF`` optionally terminated string.
.. _casiolink-cas100-mdl1:
``MDL1`` headers
~~~~~~~~~~~~~~~~
These packets seem to contain calculator model information.
These packets contain initialization data for the CAS100 variant of the
CASIOLINK protocol, with calculator model information.
.. list-table::
:header-rows: 1
@ -287,6 +375,8 @@ These packets seem to contain calculator model information.
- 4-char string, e.g. ``"0x07"`` (``0x30``, ``0x78``, ``0x30``,
``0x37``).
.. _casiolink-cas100-req1:
``REQ1`` headers
~~~~~~~~~~~~~~~~
@ -306,6 +396,8 @@ These packets seem to be used to request information.
-
- ``INF1`` (System), ``FR00`` (Segment), ``MSG1`` (Language)
.. _casiolink-cas100-req2:
``REQ2`` headers
~~~~~~~~~~~~~~~~
@ -335,3 +427,29 @@ Unknown purpose.
- ?
-
- Integer (little endian), e.g. ``0x20000000`` (512 * 1024 * 1024)
.. _casiolink-cas100-set1:
``SET1`` headers
~~~~~~~~~~~~~~~~
Unknown purpose.
.. list-table::
:header-rows: 1
* - Offset
- Size
- Field name
- Description
- Values
* - 0 (0x00)
- 2 B
- ?
-
- ``\x30\x01``
* - 2 (0x02)
- 8 B
- ?
-
- ``0xFF`` optionally terminated string, e.g. ``Y=Data``.

View File

@ -35,6 +35,15 @@ CAHUTE_LOCAL_DATA(cahute_u8 const *)
pz_program_names =
(cahute_u8 const *)"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\xCD\xCE";
/* The MDL1 command for Graph 100 / AFX used for initialization when
* in sender / control mode. The speed and parity are inserted into the
* copy of this buffer before the checksum is recomputed and placed into
* the last byte. */
CAHUTE_LOCAL_DATA(cahute_u8 const *)
default_mdl1_payload =
(cahute_u8 const *)":MDL1GY351\xFF" "000000N1.03\0\0\x01\0\0\0\x04\0\0\0"
"\x01\0\x03\xFF\xFF\xFF\xFF\0";
/* TIMEOUT_PACKET_TYPE is the timeout before reading the packet type, i.e.
* the first byte, while TIMEOUT_PACKET_CONTENTS is the timeout before
* reading any of the following bytes. */
@ -66,30 +75,115 @@ cahute_casiolink_checksum(cahute_u8 const *data, size_t size) {
}
/**
* Check if the last received data for a link is an end packet.
* Answer a received CAS100 MDL1 header with the appropriate header,
* then apply the serial settings provided within the header, then
* handle the mutual acknowledgement.
*
* @param link Link to check.
* @return 1 if the last received data is an end data, 0 otherwise.
* This flow is described in "Initiate the connection using the CAS100
* header", assuming the link is in receive mode, and is currently in the
* state where it has received the initial MDL1 header in the link's
* data buffer.
*
* Note that we actually answer with the same MDL1 to make the calculator
* believe we are compatible with them.
*
* @param link Link for which to handle the exchange.
* @return Cahute error.
*/
CAHUTE_INLINE(int) cahute_casiolink_is_end(cahute_link *link) {
switch (link->protocol_state.casiolink.variant) {
case CAHUTE_CASIOLINK_VARIANT_CAS40:
if (!memcmp(&link->data_buffer[1], "\x17\xFF", 2))
return 1;
break;
CAHUTE_LOCAL(int) cahute_casiolink_handle_mdl1(cahute_link *link) {
unsigned long new_serial_speed = 0;
unsigned long new_serial_flags = link->serial_flags;
int mdl_correct = 1;
cahute_u8 *buf = link->data_buffer;
int err;
case CAHUTE_CASIOLINK_VARIANT_CAS50:
if (!memcmp(&link->data_buffer[1], "END", 4))
return 1;
break;
/* We want to store the provided information. */
memcpy(
link->protocol_state.casiolink.raw_device_info,
&buf[5],
CASIOLINK_RAW_DEVICE_INFO_BUFFER_SIZE
);
link->protocol_state.casiolink.flags |=
CASIOLINK_FLAG_DEVICE_INFO_OBTAINED;
case CAHUTE_CASIOLINK_VARIANT_CAS100:
if (!memcmp(&link->data_buffer[1], "END1", 4))
return 1;
break;
/* Send the MDL1 answer now. */
err = cahute_write_to_link(link, buf, 40);
if (err)
return err;
/* We should actually be receiving an acknowledgement, since we are
* sending the same packet the calculator sent. */
err = cahute_read_from_link(link, buf, 1, 0, 0);
if (err)
return err;
if (buf[0] != PACKET_TYPE_ACK) {
cahute_u8 const send_buf[] = {PACKET_TYPE_CORRUPTED};
err = cahute_write_to_link(link, send_buf, 1);
if (err)
return err;
return CAHUTE_ERROR_UNKNOWN;
}
return 0;
/* We want to decode the serial parameters, to ensure that we
* can actually decode them. */
new_serial_flags = link->serial_flags;
new_serial_flags &= ~CAHUTE_SERIAL_PARITY_MASK;
if (!memcmp(&buf[11], "038400", 6))
new_serial_speed = 38400;
else {
msg(ll_error, "Unsupported new serial speed:");
mem(ll_error, &buf[11], 6);
mdl_correct = 0;
}
if (buf[17] == 'N')
new_serial_flags |= CAHUTE_SERIAL_PARITY_OFF;
else if (buf[17] == 'E')
new_serial_flags |= CAHUTE_SERIAL_PARITY_EVEN;
else if (buf[17] == 'O')
new_serial_flags |= CAHUTE_SERIAL_PARITY_ODD;
else {
msg(ll_error, "Unsupported new serial parity:");
mem(ll_error, &buf[17], 1);
mdl_correct = 0;
}
if (!mdl_correct) {
cahute_u8 const send_buf[] = {PACKET_TYPE_CORRUPTED};
err = cahute_write_to_link(link, send_buf, 1);
if (err)
return err;
return CAHUTE_ERROR_UNKNOWN;
}
/* We are ok with the sent MDL1, we can now send an acknowledgement.
* The acknowledgement is already in our buffer, we can use that. */
err = cahute_write_to_link(link, buf, 1);
if (err)
return err;
/* Only now that the exchange has taken place, we want to set
* the serial params. */
err = cahute_set_serial_params_to_link(
link,
new_serial_flags,
new_serial_speed
);
if (err) {
msg(ll_error,
"Could not set the serial params; that makes our "
"connection irrecoverable!");
link->flags |= CAHUTE_LINK_FLAG_IRRECOVERABLE;
return err;
}
return CAHUTE_OK;
}
/**
@ -115,7 +209,9 @@ cahute_casiolink_receive_raw_data(cahute_link *link, unsigned long timeout) {
size_t part_sizes[5];
int packet_type, err, variant = 0, checksum, checksum_alt;
int log_part_data = 1, is_al_end = 0, is_end = 0, is_final = 0;
int expected_data_packet_type = PACKET_TYPE_HEADER;
restart_reception:
part_sizes[0] = 0;
do {
@ -177,13 +273,18 @@ cahute_casiolink_receive_raw_data(cahute_link *link, unsigned long timeout) {
if (link->protocol_state.casiolink.variant
!= CAHUTE_CASIOLINK_VARIANT_AUTO) {
variant = link->protocol_state.casiolink.variant;
msg(ll_info, "Received the following header:");
mem(ll_info, buf, buf_size);
} else {
/* We want to try to determine the currently selected variant based
* on the header's content. */
if (!memcmp(&buf[1], "ADN1", 4) || !memcmp(&buf[1], "ADN2", 4)
|| !memcmp(&buf[1], "END1", 4) || !memcmp(&buf[1], "FCL1", 4)
|| !memcmp(&buf[1], "FMV1", 4) || !memcmp(&buf[1], "MDL1", 4)
|| !memcmp(&buf[1], "REQ1", 4) || !memcmp(&buf[1], "REQ2", 4)) {
|| !memcmp(&buf[1], "BKU1", 4) || !memcmp(&buf[1], "END1", 4)
|| !memcmp(&buf[1], "FCL1", 4) || !memcmp(&buf[1], "FMV1", 4)
|| !memcmp(&buf[1], "MCS1", 4) || !memcmp(&buf[1], "MDL1", 4)
|| !memcmp(&buf[1], "REQ1", 4) || !memcmp(&buf[1], "REQ2", 4)
|| !memcmp(&buf[1], "SET1", 4)) {
/* The type seems to be a CAS100 header type we can use. */
variant = CAHUTE_CASIOLINK_VARIANT_CAS100;
@ -474,13 +575,32 @@ cahute_casiolink_receive_raw_data(cahute_link *link, unsigned long timeout) {
break;
case CAHUTE_CASIOLINK_VARIANT_CAS100:
if (!memcmp(&buf[1], "END1", 4)) {
if (!memcmp(&buf[1], "BKU1", 4)) {
/* Backup packet for CAS100. */
part_sizes[0] =
(buf[9] << 24) | (buf[10] << 16) | (buf[11] << 8) | buf[12];
} else if (!memcmp(&buf[1], "END1", 4)) {
/* End packet for CAS100. */
part_count = 0;
is_end = 1;
} else if (!memcmp(&buf[1], "MCS1", 4)) {
/* Main memory packet for CAS100. */
part_sizes[0] = (buf[8] << 8) | buf[9];
if (!part_sizes[0])
part_count = 0;
} else if (!memcmp(&buf[1], "MDL1", 4)) {
/* Initialization packet for CAS100. */
err = cahute_casiolink_handle_mdl1(link);
if (err)
return err;
/* From here, we go back to the beginning. */
goto restart_reception;
} else if (!memcmp(&buf[1], "SET1", 4)) {
/* TODO */
part_count = 0;
}
/* TODO */
break;
}
@ -549,143 +669,133 @@ cahute_casiolink_receive_raw_data(cahute_link *link, unsigned long timeout) {
* depending on the part count & size using PACKET_TYPE_HEADER.
* - For CAS100, the data is provided in multiple packets containing
* 1024 bytes of data each, using PACKET_TYPE_DATA. */
switch (variant) {
case CAHUTE_CASIOLINK_VARIANT_CAS40:
case CAHUTE_CASIOLINK_VARIANT_CAS50:
buf = &buf[buf_size];
buf = &buf[buf_size];
index = 1;
total = part_count - 1 + part_repeat;
for (part_i = 0; part_i < total; part_i++, index++) {
size_t part_size =
part_sizes[part_i >= part_count ? part_count - 1 : part_i];
index = 1;
total = part_count - 1 + part_repeat;
for (part_i = 0; part_i < total; part_i++, index++) {
size_t part_size =
part_sizes[part_i >= part_count ? part_count - 1 : part_i];
msg(ll_info,
"Reading data part %d/%d (%" CAHUTE_PRIuSIZE "o).",
index,
total,
part_size);
msg(ll_info,
"Reading data part %d/%d (%" CAHUTE_PRIuSIZE "o).",
index,
total,
part_size);
err = cahute_read_from_link(
link,
tmp_buf,
1,
TIMEOUT_PACKET_CONTENTS,
TIMEOUT_PACKET_CONTENTS
);
if (err == CAHUTE_ERROR_TIMEOUT_START)
return CAHUTE_ERROR_TIMEOUT;
if (err)
return err;
if (tmp_buf[0] != PACKET_TYPE_HEADER) {
msg(ll_error,
"Expected 0x3A (':') packet type, got 0x%02X.",
buf[0]);
return CAHUTE_ERROR_UNKNOWN;
}
if (part_size) {
size_t part_size_left = part_size;
cahute_u8 *p = buf;
/* Use a loop to be able to follow the transfer progress
* using logs. */
while (part_size_left) {
size_t to_read =
part_size_left > 512 ? 512 : part_size_left;
err = cahute_read_from_link(
link,
p,
to_read,
TIMEOUT_PACKET_CONTENTS,
TIMEOUT_PACKET_CONTENTS
);
if (err == CAHUTE_ERROR_TIMEOUT_START)
return CAHUTE_ERROR_TIMEOUT;
if (err)
return err;
part_size_left -= to_read;
p += to_read;
}
}
if (part_size) {
/* For color screenshots, sometimes the first byte is not
* taken into account in the checksum calculation, as it's
* metadata for the sheet and not the "actual data" of the
* sheet. But sometimes it also gets the checksum right!
* In any case, we want to compute and check both checksums
* to see if at least one matches. */
checksum = cahute_casiolink_checksum(buf, part_size);
checksum_alt =
cahute_casiolink_checksum(buf + 1, part_size - 1);
} else {
checksum = 0;
checksum_alt = 0;
}
/* Read and check the checksum. */
err = cahute_read_from_link(
link,
tmp_buf + 1,
1,
TIMEOUT_PACKET_CONTENTS,
TIMEOUT_PACKET_CONTENTS
);
if (err == CAHUTE_ERROR_TIMEOUT_START)
return CAHUTE_ERROR_TIMEOUT;
if (err)
return err;
if (checksum != tmp_buf[1] && checksum_alt != tmp_buf[1]) {
cahute_u8 const send_buf[] = {PACKET_TYPE_INVALID_DATA};
msg(ll_warn,
"Invalid checksum (expected: 0x%02X, computed: "
"0x%02X).",
tmp_buf[1],
checksum);
mem(ll_info, buf, part_size);
msg(ll_error, "Transfer will abort.");
link->flags |= CAHUTE_LINK_FLAG_IRRECOVERABLE;
err = cahute_write_to_link(link, send_buf, 1);
if (err)
return err;
return CAHUTE_ERROR_CORRUPT;
}
/* Acknowledge the data. */
{
cahute_u8 const send_buf[] = {PACKET_TYPE_ACK};
err = cahute_write_to_link(link, send_buf, 1);
if (err)
return err;
}
msg(ll_info,
"Data part %d/%d received and acknowledged.",
index,
total);
if (log_part_data)
mem(ll_info, buf, part_size);
buf += part_size;
buf_size += part_size;
}
break;
default:
/* TODO */
CAHUTE_RETURN_IMPL(
"CASIOLINK data exchange was not implemented for CAS50."
err = cahute_read_from_link(
link,
tmp_buf,
1,
TIMEOUT_PACKET_CONTENTS,
TIMEOUT_PACKET_CONTENTS
);
if (err == CAHUTE_ERROR_TIMEOUT_START)
return CAHUTE_ERROR_TIMEOUT;
if (err)
return err;
if (tmp_buf[0] != expected_data_packet_type) {
msg(ll_error,
"Expected 0x3A (':') packet type, got 0x%02X.",
buf[0]);
return CAHUTE_ERROR_UNKNOWN;
}
if (part_size) {
size_t part_size_left = part_size;
cahute_u8 *p = buf;
/* Use a loop to be able to follow the transfer progress
* using logs. */
while (part_size_left) {
size_t to_read =
part_size_left > 512 ? 512 : part_size_left;
err = cahute_read_from_link(
link,
p,
to_read,
TIMEOUT_PACKET_CONTENTS,
TIMEOUT_PACKET_CONTENTS
);
if (err == CAHUTE_ERROR_TIMEOUT_START)
return CAHUTE_ERROR_TIMEOUT;
if (err)
return err;
part_size_left -= to_read;
p += to_read;
}
}
if (part_size) {
/* For color screenshots, sometimes the first byte is not
* taken into account in the checksum calculation, as it's
* metadata for the sheet and not the "actual data" of the
* sheet. But sometimes it also gets the checksum right!
* In any case, we want to compute and check both checksums
* to see if at least one matches. */
checksum = cahute_casiolink_checksum(buf, part_size);
checksum_alt =
cahute_casiolink_checksum(buf + 1, part_size - 1);
} else {
checksum = 0;
checksum_alt = 0;
}
/* Read and check the checksum. */
err = cahute_read_from_link(
link,
tmp_buf + 1,
1,
TIMEOUT_PACKET_CONTENTS,
TIMEOUT_PACKET_CONTENTS
);
if (err == CAHUTE_ERROR_TIMEOUT_START)
return CAHUTE_ERROR_TIMEOUT;
if (err)
return err;
if (checksum != tmp_buf[1] && checksum_alt != tmp_buf[1]) {
cahute_u8 const send_buf[] = {PACKET_TYPE_INVALID_DATA};
msg(ll_warn,
"Invalid checksum (expected: 0x%02X, computed: "
"0x%02X).",
tmp_buf[1],
checksum);
mem(ll_info, buf, part_size);
msg(ll_error, "Transfer will abort.");
link->flags |= CAHUTE_LINK_FLAG_IRRECOVERABLE;
err = cahute_write_to_link(link, send_buf, 1);
if (err)
return err;
return CAHUTE_ERROR_CORRUPT;
}
/* Acknowledge the data. */
{
cahute_u8 const send_buf[] = {PACKET_TYPE_ACK};
err = cahute_write_to_link(link, send_buf, 1);
if (err)
return err;
}
msg(ll_info,
"Data part %d/%d received and acknowledged.",
index,
total);
if (log_part_data
&& part_size <= 4096) /* Let's not flood the terminal. */
mem(ll_info, buf, part_size);
buf += part_size;
buf_size += part_size;
}
}
@ -718,8 +828,8 @@ cahute_casiolink_receive_raw_data(cahute_link *link, unsigned long timeout) {
* @return Cahute error.
*/
CAHUTE_EXTERN(int) cahute_casiolink_initiate(cahute_link *link) {
cahute_u8 buf[1];
int err;
cahute_u8 *buf = link->data_buffer;
int checksum, err;
if (link->flags & CAHUTE_LINK_FLAG_RECEIVER) {
/* Expect an initiation flow. */
@ -740,6 +850,51 @@ CAHUTE_EXTERN(int) cahute_casiolink_initiate(cahute_link *link) {
err = cahute_write_to_link(link, buf, 1);
if (err)
return err;
/* In the CAS100 variant, we actually expect an additional flow here,
* being the MDL1 flow. */
if (link->protocol_state.casiolink.variant
== CAHUTE_CASIOLINK_VARIANT_CAS100) {
err = cahute_read_from_link(
link,
buf,
40,
0,
TIMEOUT_PACKET_CONTENTS
);
if (err)
return err;
msg(ll_info, "Received data for MDL1 is the following:");
mem(ll_info, buf, 40);
if (memcmp(buf, "\x3AMDL1", 5))
err = CAHUTE_ERROR_UNKNOWN;
if (!err) {
checksum = cahute_casiolink_checksum(buf + 1, 38);
if (buf[39] != checksum)
err = CAHUTE_ERROR_CORRUPT;
}
if (err) {
cahute_u8 send_buf[1] = {PACKET_TYPE_CORRUPTED};
msg(ll_error,
"Unknown or invalid packet when MDL1 was expected:");
mem(ll_error, buf, 40);
err = cahute_write_to_link(link, send_buf, 1);
if (err)
return err;
return err;
}
err = cahute_casiolink_handle_mdl1(link);
if (err)
return err;
}
} else {
/* Make the initiation flow. */
buf[0] = PACKET_TYPE_START;
@ -759,6 +914,102 @@ CAHUTE_EXTERN(int) cahute_casiolink_initiate(cahute_link *link) {
return CAHUTE_ERROR_UNKNOWN;
}
/* In the CAS100 variant, we actually need to initiate an additional
* flow here, being the MDL1 flow. */
if (link->protocol_state.casiolink.variant
== CAHUTE_CASIOLINK_VARIANT_CAS100) {
char serial_params[7];
memcpy(buf, default_mdl1_payload, 40);
/* NOTE: sprintf() adds a terminating zero, but we don't care,
* since we override buf[17] right after. */
sprintf(serial_params, "%06lu", link->serial_speed);
switch (link->serial_flags & CAHUTE_SERIAL_PARITY_MASK) {
case CAHUTE_SERIAL_PARITY_EVEN:
serial_params[6] = 'E';
break;
case CAHUTE_SERIAL_PARITY_ODD:
serial_params[6] = 'O';
break;
default:
serial_params[6] = 'N';
}
memcpy(&buf[11], serial_params, 7);
buf[39] = cahute_casiolink_checksum(&buf[1], 38);
err = cahute_write_to_link(link, buf, 40);
if (err)
return err;
err = cahute_read_from_link(
link,
buf,
40,
0,
TIMEOUT_PACKET_CONTENTS
);
if (err)
return err;
msg(ll_info, "Received data for MDL1 is the following:");
mem(ll_info, buf, 40);
err = 0;
if (memcmp(buf, "\x3AMDL1", 5)
|| memcmp(&buf[11], serial_params, 7))
err = CAHUTE_ERROR_UNKNOWN;
if (!err) {
checksum = cahute_casiolink_checksum(buf + 1, 38);
if (buf[39] != checksum)
err = CAHUTE_ERROR_CORRUPT;
}
if (err) {
cahute_u8 send_buf[1] = {PACKET_TYPE_CORRUPTED};
msg(ll_error,
"Unknown or invalid packet when MDL1 was expected:");
mem(ll_error, buf, 40);
err = cahute_write_to_link(link, send_buf, 1);
if (err)
return err;
return err;
}
/* We want to store the received MDL1 packet here.
* TODO: We may want to check the speed here. */
memcpy(
link->protocol_state.casiolink.raw_device_info,
&buf[5],
CASIOLINK_RAW_DEVICE_INFO_BUFFER_SIZE
);
link->protocol_state.casiolink.flags |=
CASIOLINK_FLAG_DEVICE_INFO_OBTAINED;
/* Send the acknowledgement. */
buf[0] = PACKET_TYPE_ACK;
err = cahute_write_to_link(link, buf, 1);
if (err)
return err;
/* Receive the initial acknowledgement. */
err = cahute_read_from_link(link, buf, 1, 0, 0);
if (err)
return err;
if (buf[0] != PACKET_TYPE_ACK)
return CAHUTE_ERROR_UNKNOWN;
}
}
return CAHUTE_OK;
@ -793,7 +1044,7 @@ CAHUTE_EXTERN(int) cahute_casiolink_terminate(cahute_link *link) {
buf[1] = 'E';
buf[2] = 'N';
buf[3] = 'D';
buf[4] = '\0';
buf[4] = '\xFF';
buf_size = 50;
break;
@ -806,17 +1057,7 @@ CAHUTE_EXTERN(int) cahute_casiolink_terminate(cahute_link *link) {
break;
}
/* Compute the checksum as well! */
{
cahute_u8 const *p = buf + 1;
size_t left = buf_size - 2;
int checksum = 0;
for (p = buf + 1, left = buf_size - 2; left; p++, left--)
checksum += *p;
buf[buf_size - 1] = checksum & 255;
}
buf[buf_size - 1] = cahute_casiolink_checksum(&buf[1], buf_size - 2);
msg(ll_info, "Sending the following end packet:");
mem(ll_info, buf, buf_size);
@ -932,6 +1173,37 @@ cahute_casiolink_receive_data(
);
}
break;
case CAHUTE_CASIOLINK_VARIANT_CAS100:
if (!memcmp(&buf[1], "MCS1", 4)) {
cahute_u8 const *p;
size_t name_size, group_size;
for (p = &buf[11]; p < &buf[19] && *p != 0xFF; p++)
;
name_size = (size_t)(p - &buf[11]);
for (p = &buf[19]; p < &buf[27] && *p != 0xFF; p++)
;
group_size = (size_t)(p - &buf[19]);
err = cahute_mcs_decode_data(
datap,
&buf[19],
group_size,
NULL, /* MCS1 packet does not present a directory. */
0,
&buf[11],
name_size,
&buf[40],
link->data_buffer_size - 40,
buf[10]
);
if (err != CAHUTE_ERROR_IMPL)
return err;
}
/* TODO */
break;
}
/* If the data was final, we still need to break here. */
@ -1036,3 +1308,71 @@ cahute_casiolink_receive_screen(
return CAHUTE_OK;
}
/**
* Produce generic device information using the optionally stored
* device information.
*
* @param link Link from which to get the cached EACK response.
* @param infop Pointer to set to the allocated device information structure.
* @return Cahute error, or 0 if no error has occurred.
*/
CAHUTE_EXTERN(int)
cahute_casiolink_make_device_info(
cahute_link *link,
cahute_device_info **infop
) {
cahute_device_info *info = NULL;
char *buf;
cahute_u8 const *raw_info;
if (~link->protocol_state.casiolink.flags
& CASIOLINK_FLAG_DEVICE_INFO_OBTAINED) {
/* We don't have a 'generic device information'. */
CAHUTE_RETURN_IMPL("No generic device with CASIOLINK.");
}
info = malloc(sizeof(cahute_device_info) + 20);
if (!info)
return CAHUTE_ERROR_ALLOC;
buf = (void *)(&info[1]);
raw_info = link->protocol_state.seven.raw_device_info;
info->cahute_device_info_flags = CAHUTE_DEVICE_INFO_FLAG_OS;
info->cahute_device_info_rom_capacity = 0;
info->cahute_device_info_rom_version = "";
info->cahute_device_info_flash_rom_capacity =
(raw_info[20] << 24) | (raw_info[19] << 16) | (raw_info[18] << 8)
| raw_info[17];
info->cahute_device_info_ram_capacity =
(raw_info[24] << 24) | (raw_info[23] << 16) | (raw_info[22] << 8)
| raw_info[21];
info->cahute_device_info_bootcode_version = "";
info->cahute_device_info_bootcode_offset = 0;
info->cahute_device_info_bootcode_size = 0;
memcpy(buf, &raw_info[13], 4);
buf[4] = 0;
info->cahute_device_info_os_version = buf;
buf += 5;
info->cahute_device_info_os_offset = 0;
info->cahute_device_info_os_size = 0;
info->cahute_device_info_product_id = "";
info->cahute_device_info_username = "";
info->cahute_device_info_organisation = "";
memcpy(buf, raw_info, 6);
buf[6] = 0;
info->cahute_device_info_hwid = buf;
buf += 7;
info->cahute_device_info_cpuid = "";
*infop = info;
return CAHUTE_OK;
}

View File

@ -295,6 +295,13 @@ union cahute_link_medium_state {
/* Absolute minimum buffer size for CASIOLINK. */
#define CASIOLINK_MINIMUM_BUFFER_SIZE 50
/* Raw device information size for CASIOLINK, most specifically the
* CAS100 variant. */
#define CASIOLINK_RAW_DEVICE_INFO_BUFFER_SIZE 33
/* Flags to describe whether device information was obtained or not. */
#define CASIOLINK_FLAG_DEVICE_INFO_OBTAINED 0x00000001
/* Maximum size of raw data that can come from an extended packet.
* Calculators support data packets with up to 256 raw bytes (512 encoded
* bytes), but fxRemote uses payloads that go up to 1028 raw bytes
@ -314,12 +321,19 @@ union cahute_link_medium_state {
/**
* CASIOLINK peer state.
*
* @property flags Flags for the CASIOLINK peer state.
* @property variant Variant with which to force data frame interpretation.
* @property last_variant Variant for the last data frame.
* @property raw_device_info Raw device information buffer, so that data
* can be extracted later if actual device information is requested.
*/
struct cahute_casiolink_state {
unsigned long flags;
int variant;
int last_variant;
cahute_u8 raw_device_info[CASIOLINK_RAW_DEVICE_INFO_BUFFER_SIZE];
};
/**
@ -535,6 +549,12 @@ cahute_casiolink_receive_screen(
unsigned long timeout
);
CAHUTE_EXTERN(int)
cahute_casiolink_make_device_info(
cahute_link *link,
cahute_device_info **infop
);
/* ---
* Protocol 7.00 functions, defined in seven.c
* --- */

View File

@ -30,6 +30,17 @@
#define CHECK_SENDER 0x00000001 /* Check that a link is not a receiver. */
#define CHECK_RECEIVER 0x00000002 /* Check that a link is a receiver. */
/* On some platforms, for directories, ftell() returns an insanely high
* number that may be platform-specific, e.g. 9223372036854775807 (2^63 - 1),
* which would correspond to the highest positive value of a long if defined
* on 64 bits. In order to detect such cases in a reasonably
* platform-independent manner, we want to cap the size of any file that
* gets stored into memory.
*
* See ``read_file_contents()`` for more details on the usage of this
* constant. */
#define REASONABLE_FILE_CONTENT_LIMIT 134217728 /* 128 MiB */
/**
* Check a link's state.
*
@ -218,9 +229,6 @@ cahute_negotiate_serial_params(
CAHUTE_RETURN_IMPL("Operation not supported by the link protocol.");
}
link->serial_flags = new_serial_flags;
link->serial_speed = speed;
err = cahute_set_serial_params_to_link(link, new_serial_flags, speed);
if (err) {
/* We have successfully negociated with the device to switch
@ -267,6 +275,18 @@ cahute_get_device_info(cahute_link *link, cahute_device_info **infop) {
return err;
switch (link->protocol) {
case CAHUTE_LINK_PROTOCOL_SERIAL_CASIOLINK:
/* With CASIOLINK, we may have received device information at
* some point. */
err = cahute_casiolink_make_device_info(
link,
&link->cached_device_info
);
if (err)
return err;
break;
case CAHUTE_LINK_PROTOCOL_SERIAL_SEVEN:
case CAHUTE_LINK_PROTOCOL_USB_SEVEN:
/* With Protocol 7.00, we may already have device information
@ -276,6 +296,7 @@ cahute_get_device_info(cahute_link *link, cahute_device_info **infop) {
cahute_seven_make_device_info(link, &link->cached_device_info);
if (err)
return err;
break;
default:
@ -374,6 +395,13 @@ cahute_send_file_to_storage(
}
file_size = (size_t)ftell(filep);
if (file_size > REASONABLE_FILE_CONTENT_LIMIT) {
msg(ll_error,
"file too big (over 128MiB) or unsupported file type (e.g. "
"directory)");
return CAHUTE_ERROR_UNKNOWN;
}
rewind(filep);
/* Send the file using the protocol. */

View File

@ -342,6 +342,7 @@ init_link(cahute_link *link, unsigned long flags, int casiolink_variant) {
return CAHUTE_ERROR_UNKNOWN;
}
casiolink_state->flags = 0;
casiolink_state->variant = casiolink_variant;
if (~flags & PROTOCOL_FLAG_NOCHECK) {
@ -1267,11 +1268,8 @@ cahute_open_serial_link(
link->medium_state.windows.overlapped.hEvent = overlapped_event_handle;
#endif
link->serial_flags = flags
& (CAHUTE_SERIAL_STOP_MASK | CAHUTE_SERIAL_PARITY_MASK
| CAHUTE_SERIAL_XONXOFF_MASK
| CAHUTE_SERIAL_DTR_MASK | CAHUTE_SERIAL_RTS_MASK);
link->serial_speed = speed;
link->serial_flags = 0;
link->serial_speed = 0;
link->protocol = protocol;
link->medium_read_start = 0;
link->medium_read_size = 0;
@ -1290,7 +1288,14 @@ cahute_open_serial_link(
/* The link is now considered opened, with protocol uninitialized.
* We want to set the serial parameters to the medium now. */
err = cahute_set_serial_params_to_link(link, link->serial_flags, speed);
err = cahute_set_serial_params_to_link(
link,
flags
& (CAHUTE_SERIAL_STOP_MASK | CAHUTE_SERIAL_PARITY_MASK
| CAHUTE_SERIAL_XONXOFF_MASK | CAHUTE_SERIAL_DTR_MASK
| CAHUTE_SERIAL_RTS_MASK),
speed
);
if (err) {
cahute_close_link(link);
return err;

View File

@ -78,7 +78,7 @@ cahute_mcs_decode_data(
}
/* TODO */
msg(ll_info, "Data Type: %02X", data_type);
msg(ll_info, "Data Type: 0x%02X", data_type);
msg(ll_info, "Directory Name: %.*s", directory_size, directory);
msg(ll_info, "Data Name: %.*s", name_size, name);
msg(ll_info, "Group Name: %.*s", group_size, group);

View File

@ -778,6 +778,29 @@ cahute_set_serial_params_to_link(
unsigned long flags,
unsigned long speed
) {
if (link->serial_flags == flags && link->serial_speed == speed)
return CAHUTE_OK;
msg(ll_info, "Setting the following serial settings:");
msg(ll_info,
" baud=%lu, parity=%s, stop bits=%d,",
speed,
(flags & CAHUTE_SERIAL_PARITY_MASK) == CAHUTE_SERIAL_PARITY_ODD ? "odd"
: (flags & CAHUTE_SERIAL_PARITY_MASK) == CAHUTE_SERIAL_PARITY_EVEN
? "even"
: "none",
(flags & CAHUTE_SERIAL_STOP_MASK) == CAHUTE_SERIAL_STOP_TWO ? 2 : 1);
msg(ll_info,
" dtr=%s, rts=%s",
(flags & CAHUTE_SERIAL_DTR_MASK) == CAHUTE_SERIAL_DTR_HANDSHAKE
? "handshake"
: (flags & CAHUTE_SERIAL_DTR_ENABLE) ? "enabled"
: "disabled",
(flags & CAHUTE_SERIAL_RTS_MASK) == CAHUTE_SERIAL_RTS_HANDSHAKE
? "handshake"
: (flags & CAHUTE_SERIAL_RTS_ENABLE) ? "enabled"
: "disabled");
switch (link->medium) {
#ifdef CAHUTE_LINK_MEDIUM_POSIX_SERIAL
case CAHUTE_LINK_MEDIUM_POSIX_SERIAL: {
@ -1052,6 +1075,8 @@ cahute_set_serial_params_to_link(
CAHUTE_RETURN_IMPL("No method available for setting serial params.");
}
link->serial_flags = flags;
link->serial_speed = speed;
return CAHUTE_OK;
}

View File

@ -2147,9 +2147,6 @@ cahute_seven_receive_data(
if (err)
return err;
link->serial_flags = new_serial_flags;
link->serial_speed = new_serial_speed;
/* We introduce an artificial sleep to make the device believe
* that we may be slow. Otherwise, the transfer may crash right
* after we have changed the properties of our link. */
@ -2170,8 +2167,7 @@ cahute_seven_receive_data(
* Therefore, we consider the link to be irrecoverable. */
msg(ll_error,
"Could not set the serial params; that makes our "
"connection "
"irrecoverable!");
"connection irrecoverable!");
link->flags |= CAHUTE_LINK_FLAG_IRRECOVERABLE;
return err;
}