127 lines
3.7 KiB
C
127 lines
3.7 KiB
C
// SPDX-License-Identifier: GPL-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;
|
|
}
|