Commit 9afb2f11 authored by Franksen, Benjamin's avatar Franksen, Benjamin
Browse files

scan/ellsi: use an epics timer to periodically send heartbeat


The ELLSI server expects us to send either a CAN message or a heartbeat
every 2.5 seconds. We previously sent the heartbeat only as a response when
we received one. However, the server sends a heartbeat only if there is no
CAN message to be sent, so it is not enough to just respond to the heartbeat.
parent bf2329de
......@@ -3,11 +3,12 @@
#include <string.h>
#include <assert.h>
#include "errlog.h"
#include "osiSock.h"
#include "epicsAssert.h"
#include "epicsThread.h"
#include "epicsTimer.h"
#include "osiSock.h"
#include "osiStdInt.h"
#include "can_frame.h"
#include "scan_driver.h"
#include "new.h"
......@@ -103,6 +104,9 @@ STATIC_ASSERT(sizeof(ellsiCanTelegram)==6*4);
#define CAN_TELEGRAM_LEN_RTR 0x10
#define CAN_TELEGRAM_LEN_TXDONE 0x20
/* 2.6.7 default heartbeat period in seconds */
#define ELLSI_HEARTBEAT_PERIOD 2.5
/* 2.6.8.5 ELLSI_IOCTL_GET_LAST_STATE */
typedef struct {
uint32_t lastCommand;
......@@ -187,6 +191,7 @@ struct ellsi_state {
int sock; /* socket to communicate over */
struct sockaddr_in addr; /* socket address info */
int baudrate;
epicsTimerId heartbeat_timer;
};
static ssize_t ellsi_write(void *pvt, const struct can_frame *frame) {
......@@ -427,6 +432,24 @@ static int ellsi_add_can_ids(ellsi_state_t *state) {
return ellsi_check(state->sock);
}
static void ellsi_send_heartbeat(void *pvt) {
errbuf_t buf;
ellsi_state_t *state = (ellsi_state_t *)pvt;
struct msg {
ellsiHeader header;
} __attribute__((packed)) msg;
memset(&msg, 0, sizeof(msg));
msg.header.magic = htonl(ELLSI_MAGIC);
msg.header.command = htonl(ELLSI_CMD_HEARTBEAT);
if (write(state->sock, &msg, sizeof(msg)) < 0) {
debug("ellsi_send_heartbeat(%d): send failed (%s)\n", state->sock, ERRNO_STR(buf));
} else {
debug("ellsi_send_heartbeat(%d): success\n", state->sock);
}
epicsTimerStartDelay(state->heartbeat_timer, ELLSI_HEARTBEAT_PERIOD);
}
static int ellsi_connect(void *pvt) {
errbuf_t buf;
ellsi_state_t *state = (ellsi_state_t *)pvt;
......@@ -456,6 +479,7 @@ static int ellsi_connect(void *pvt) {
if (ellsi_add_can_ids(state)) {
return -1;
}
epicsTimerStartDelay(state->heartbeat_timer, ELLSI_HEARTBEAT_PERIOD);
return 0;
}
......@@ -469,7 +493,16 @@ static scan_methods_t methods = {
int ellsiConfigPort(int can_port, const char *ip_addr, int ip_port, int baudrate) {
errbuf_t buf;
ellsi_state_t *state = new(ellsi_state_t);
static epicsTimerQueueId timer_queue;
if (!timer_queue) {
timer_queue = epicsTimerQueueAllocate(1, epicsThreadPriorityMin + 10);
if (!timer_queue) {
fprintf(stderr, "ellsiConfigPort(%d): epicsTimerQueueAllocate failed (out of memory?)\n",
state->sock);
return -1;
}
}
if (!state) {
fprintf(stderr, "ellsiConfigPort(%d): out of memory\n", state->sock);
return -1;
......@@ -492,6 +525,14 @@ int ellsiConfigPort(int can_port, const char *ip_addr, int ip_port, int baudrate
}
/* success, store driver specific configuration */
state->baudrate = baudrate;
/* create heartbeat timer */
state->heartbeat_timer = epicsTimerQueueCreateTimer (timer_queue, ellsi_send_heartbeat, state);
if (!state->heartbeat_timer) {
fprintf(stderr, "ellsiConfigPort(%d): epicsTimerQueueCreateTimer failed (out of memory?)\n",
state->sock);
free(state);
return -1;
}
/* install driver and initialize sci port */
return scan_config_port(can_port, state, &methods);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment