// SPDX-License-Identifier: LGPL-2.0-only // SPDX-FileCopyrightText: 2023 Oleksij Rempel /* * This file implements Annex C.1.2 File Server Status according to * ISO 11783-13:2021. */ #include #include #include #include #include #include #include #include #include #include #include "isobusfs_srv.h" /* * isobusfs_srv_fss_init - Initialize the file server status structure * @priv: Pointer to the private data structure of the ISOBUS file server * * This function initializes the file server status structure, which * represents the status of the file server according to Annex C.1.2 * of ISO 11783-13:2021. */ void isobusfs_srv_fss_init(struct isobusfs_srv_priv *priv) { struct isobusfs_cm_fss *st = &priv->st; st->fs_function = isobusfs_cg_function_to_buf(ISOBUSFS_CG_CONNECTION_MANAGMENT, ISOBUSFS_CM_F_FS_STATUS); st->status = 0; st->num_open_files = 0; memset(st->reserved, 0xFF, sizeof(st->reserved)); } /* * isobusfs_srv_fss_get_rate - Get the rate of File Server Status transmission * @priv: Pointer to the private data structure of the ISOBUS file server * * Returns: the transmission rate of the File Server Status messages depending * on the current state of the file server. */ static unsigned int isobusfs_srv_fss_get_rate(struct isobusfs_srv_priv *priv) { switch (priv->st_state) { case ISOBUSFS_SRV_STATE_IDLE: return ISOBUSFS_CM_F_FS_STATUS_IDLE_RATE; /* * On every change of Byte 2 "File Server Status" send max 5 status * messages per second. */ case ISOBUSFS_SRV_STATE_STAT_CHANGE_1: /* fall through */ case ISOBUSFS_SRV_STATE_STAT_CHANGE_2: /* fall through */ case ISOBUSFS_SRV_STATE_STAT_CHANGE_3: /* fall through */ case ISOBUSFS_SRV_STATE_STAT_CHANGE_4: /* fall through */ case ISOBUSFS_SRV_STATE_STAT_CHANGE_5: priv->st_state--; return ISOBUSFS_CM_F_FS_STATUS_BUSY_RATE; case ISOBUSFS_SRV_STATE_BUSY: return ISOBUSFS_CM_F_FS_STATUS_BUSY_RATE; default: pr_warn("%s:%i: unknown state %d", __func__, __LINE__, priv->st_state); } /* * In case something is wrong, fall back to idle rate to not spam the * bus. */ return ISOBUSFS_CM_F_FS_STATUS_IDLE_RATE; } /** * isobusfs_srv_fss_send - Send periodic File Server Status messages * @priv: Pointer to the private data structure of the ISOBUS file server * * Returns: 0 if the message was sent successfully, a negative error code * otherwise. */ int isobusfs_srv_fss_send(struct isobusfs_srv_priv *priv) { unsigned int next_msg_rate; int64_t time_diff; int ret; /* Test if it is proper time to send next status message. */ time_diff = timespec_diff_ms(&priv->cmn.next_send_time, &priv->cmn.last_time); if (time_diff > ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) { /* too early to send next message */ return 0; } if (time_diff < -ISOBUSFS_CM_F_FS_STATUS_RATE_JITTER) { pr_warn("too late to send next fs status message: %ld ms", time_diff); } /* Make sure we send the message with the latest stats */ if (priv->st_msg_stats.tskey_sch != priv->st_msg_stats.tskey_ack) pr_warn("previous message was not acked"); /* send periodic file servers status messages. */ ret = send(priv->sock_fss, &priv->st, sizeof(priv->st), MSG_DONTWAIT); if (ret < 0) { ret = -errno; pr_warn("Failed to send FS status message, error code: %d (%s)", ret, strerror(ret)); return ret; } pr_debug("> tx FS status: 0x%02x, opened files: %d", priv->st.status, priv->st.num_open_files); /* Calculate time for the next status message */ next_msg_rate = isobusfs_srv_fss_get_rate(priv); priv->cmn.next_send_time = priv->cmn.last_time; timespec_add_ms(&priv->cmn.next_send_time, next_msg_rate); return 0; }