can-utils/isobusfs/isobusfs_srv_cm_fss.c

127 lines
3.7 KiB
C

// SPDX-License-Identifier: LGPL-2.0-only
// SPDX-FileCopyrightText: 2023 Oleksij Rempel <linux@rempel-privat.de>
/*
* This file implements Annex C.1.2 File Server Status according to
* ISO 11783-13:2021.
*/
#include <err.h>
#include <errno.h>
#include <inttypes.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#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;
}