summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornorly <ny-git@enpas.org>2017-03-19 00:23:49 +0100
committernorly <ny-git@enpas.org>2017-03-19 00:24:05 +0100
commit6357000d97517389e2b15f8a7b01c4e83ef0d96f (patch)
treea79b465b41831d8ca808ddf1c49233199f7634f1
parentbba3a6280c23758e288d23a51a66a5b6475a4464 (diff)
Implement NMReset in case a node goes missing
-rw-r--r--vw-nm-tools.h81
-rw-r--r--vw-nm.c146
-rw-r--r--vw-nm.h13
3 files changed, 144 insertions, 96 deletions
diff --git a/vw-nm-tools.h b/vw-nm-tools.h
index 426e778..f4126a6 100644
--- a/vw-nm-tools.h
+++ b/vw-nm-tools.h
@@ -76,6 +76,81 @@ static void can_tx(int socket, struct can_frame *frame)
+static int nm_is_rx_frame_valid(struct NM_Main *nm, struct can_frame *frame)
+{
+ if (frame->can_dlc < 2) {
+ printf("Skipping short frame from CAN ID %03x\n", frame->can_id);
+ return 0;
+ }
+
+ if ((frame->can_id & ~(nm->max_nodes - 1)) != nm->can_base) {
+ printf("Skipping non-NM from CAN ID %03x\n", frame->can_id);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+
+
+
+
+
+
+
+
+static void nm_set_timer_now(struct NM_Main *nm)
+{
+ nm->tv.tv_sec = 0;
+ nm->tv.tv_usec = 0;
+ nm->timer_reason = NM_TIMER_NOW;
+}
+
+static void nm_set_timer_normal(struct NM_Main *nm)
+{
+ nm->tv.tv_sec = 0;
+ nm->tv.tv_usec = NM_USECS_NORMAL_TURN;
+ nm->timer_reason = NM_TIMER_NORMAL;
+}
+
+static void nm_set_timer_awol(struct NM_Main *nm)
+{
+ nm->tv.tv_sec = 0;
+ nm->tv.tv_usec = NM_USECS_NODE_AWOL;
+ nm->timer_reason = NM_TIMER_AWOL;
+}
+
+/*
+static void nm_set_timer_limphome(struct NM_Main *nm)
+{
+ nm->tv.tv_sec = 0;
+ nm->tv.tv_usec = NM_USECS_LIMPHOME;
+ nm->timer_reason = NM_TIMER_LIMPHOME;
+}
+*/
+
+
+
+
+
+
+static void nm_reset(struct NM_Main *nm)
+{
+ unsigned id;
+
+ for (id = 0; id < nm->max_nodes; id++) {
+ nm->nodes[id].next = 0xff;
+ nm->nodes[id].state = NM_MAIN_OFF;
+ }
+
+ nm->nodes[nm->my_id].next = nm->my_id;
+ nm->nodes[nm->my_id].state = NM_MAIN_LOGIN;
+
+ nm_set_timer_normal(nm);
+}
+
+
static struct NM_Main* nm_alloc(unsigned node_bits, NM_ID my_id, canid_t can_base)
{
@@ -100,11 +175,7 @@ static struct NM_Main* nm_alloc(unsigned node_bits, NM_ID my_id, canid_t can_bas
nm->my_id = my_id;
nm->can_base = can_base;
- nm->nodes[nm->my_id].next = nm->my_id;
- nm->nodes[nm->my_id].state = NM_MAIN_LOGIN;
-
- nm->tv.tv_sec = 0;
- nm->tv.tv_usec = NM_USECS_NODE_AWOL;
+ nm_reset(nm);
return nm;
}
diff --git a/vw-nm.c b/vw-nm.c
index 6a3ca05..c843902 100644
--- a/vw-nm.c
+++ b/vw-nm.c
@@ -28,48 +28,6 @@
-static int nm_is_rx_frame_valid(struct NM_Main *nm, struct can_frame *frame)
-{
- if (frame->can_dlc < 2) {
- printf("Skipping short frame from CAN ID %03x\n", frame->can_id);
- return 0;
- }
-
- if ((frame->can_id & ~(nm->max_nodes - 1)) != nm->can_base) {
- printf("Skipping non-NM from CAN ID %03x\n", frame->can_id);
- return 0;
- }
-
- return 1;
-}
-
-
-
-static void nm_set_timer_now(struct NM_Main *nm) {
- nm->tv.tv_sec = 0;
- nm->tv.tv_usec = 0;
- nm->timer_reason = NM_TIMER_NOW;
-}
-
-static void nm_set_timer_normal(struct NM_Main *nm) {
- nm->tv.tv_sec = 0;
- nm->tv.tv_usec = NM_USECS_NORMAL_TURN;
- nm->timer_reason = NM_TIMER_NORMAL;
-}
-
-static void nm_set_timer_awol(struct NM_Main *nm) {
- nm->tv.tv_sec = 0;
- nm->tv.tv_usec = NM_USECS_NODE_AWOL;
- nm->timer_reason = NM_TIMER_AWOL;
-}
-
-/*
-static void nm_set_timer_limphome(struct NM_Main *nm) {
- nm->tv.tv_sec = 0;
- nm->tv.tv_usec = NM_USECS_LIMPHOME;
- nm->timer_reason = NM_TIMER_LIMPHOME;
-}
-*/
static void nm_update_my_next_id(struct NM_Main *nm) {
@@ -132,11 +90,23 @@ static void nm_handle_can_frame(struct NM_Main *nm, struct can_frame *frame)
nm->nodes[sender].next = next;
nm->nodes[sender].state = state;
+ /* Update our view of the world */
+ nm_update_my_next_id(nm);
+
switch (state & NM_MAIN_MASK) {
case NM_MAIN_ON:
+ /* We're not alone, so let's transition to ON for now.
+ */
+ nm->nodes[nm->my_id].state = NM_MAIN_ON;
+
+ /* The AWOL timeout is ONLY reset on
+ * NM_MAIN_ON messages.
+ */
+ nm_set_timer_awol(nm);
+
if (next == nm->nodes[nm->my_id].next
&& nm->nodes[nm->my_id].next != nm->my_id) {
- /* sender doesn't know we exist */
+ /* Sender doesn't know we exist */
nm->nodes[nm->my_id].state = NM_MAIN_LOGIN;
@@ -157,49 +127,35 @@ static void nm_handle_can_frame(struct NM_Main *nm, struct can_frame *frame)
* NM frame.
*/
- /* Let's handle this just like a LOGIN, since
- * we're learning about a new device.
- * See case NM_MAIN_LOGIN below for details.
- */
-
- nm_update_my_next_id(nm);
- nm->nodes[nm->my_id].state = NM_MAIN_ON;
+ /* Nothing to do. */
} else if (next == nm->my_id) {
- /* It's our turn.
- * Reset the timeout so anyone we missed
- * can send its login frame to correct us.
+ /* It's our turn, do a normal timeout.
+ * This is a period in which anyone we missed
+ * can send its re-login frame to correct us.
*/
+
nm_set_timer_normal(nm);
} else {
- /* We just got some random ON message.
- * Reset the timer looking out for broken
- * connectivity.
- */
- nm_set_timer_awol(nm);
+ /* We just received a random ON message. */
+
+ /* Nothing to do. */
}
break;
case NM_MAIN_LOGIN:
/* Note: sender != nm->my_id */
- nm_update_my_next_id(nm);
-
/* We're not alone anymore, so let's change state. */
nm->nodes[nm->my_id].state = NM_MAIN_ON;
- /* We don't reset the timeout when somebody logs in,
- * i.e. (next == sender).
+ /* We don't reset the timeout when somebody logs in.
* Instead, we'll simply include them in the next
- * round. */
-
- /* Actually, when a login is done as a correction,
- * we do reset the timeout.
+ * round.
*/
- if (next != sender) {
- nm_set_timer_awol(nm);
- }
+
+ /* Nothing else to do. */
break;
case NM_MAIN_LIMPHOME:
- nm_update_my_next_id(nm);
+ break;
}
nm_dump_all(nm);
@@ -223,23 +179,37 @@ static void nm_buildframe(struct NM_Main *nm, struct can_frame *frame)
static void nm_timeout_callback(struct NM_Main *nm, struct can_frame *frame)
{
- nm_set_timer_awol(nm);
-
- nm_buildframe(nm, frame);
-}
-
-
-
-
-static void nm_start(struct NM_Main *nm, struct can_frame *frame)
-{
- nm->tv.tv_sec = 0;
- nm->tv.tv_usec = NM_USECS_NODE_AWOL;
-
-
-
- nm->nodes[nm->my_id].next = nm->my_id;
- nm->nodes[nm->my_id].state = NM_MAIN_LOGIN;
+ switch(nm->timer_reason) {
+ case NM_TIMER_NOW:
+ case NM_TIMER_NORMAL:
+ /* We're due to send our own ring message */
+ switch(nm->nodes[nm->my_id].state & NM_MAIN_MASK) {
+ case NM_MAIN_ON:
+ break;
+ case NM_MAIN_LOGIN:
+ /* We're going to be ready, let's
+ * change state (RCD 310 behavior)
+ */
+ nm->nodes[nm->my_id].state = NM_MAIN_ON;
+ break;
+ default:
+ printf("BUG: TIMER_NORMAL expired in unknown NM_MAIN state\n");
+ break;
+ }
+ nm_set_timer_awol(nm);
+ nm_buildframe(nm, frame);
+ break;
+ case NM_TIMER_AWOL:
+ /* The network is silent because a node disappeared
+ * or something bad happened.
+ * Reset everything and start over.
+ */
+ nm_reset(nm);
+ break;
+ case NM_TIMER_LIMPHOME:
+ /* TODO */
+ break;
+ }
nm_buildframe(nm, frame);
}
@@ -318,7 +288,7 @@ int main(int argc, char **argv)
if (1) {
struct can_frame frame;
- nm_start(nm, &frame);
+ nm_buildframe(nm, &frame);
can_tx(s, &frame);
}
diff --git a/vw-nm.h b/vw-nm.h
index 2c38e72..fcb6b4b 100644
--- a/vw-nm.h
+++ b/vw-nm.h
@@ -38,6 +38,7 @@ enum timer_reason {
struct NM_Main {
unsigned max_nodes;
struct NM_Node *nodes;
+
NM_ID my_id;
canid_t can_base;
@@ -48,7 +49,9 @@ struct NM_Main {
-/* This timeout is ~49 ms in:
+/* OSEK/VDX NM: T_Typ
+ *
+ * This timeout is ~49 ms in:
* - 0x19 (RCD 310, Bosch)
* (sometimes it takes a little longer)
*
@@ -62,13 +65,17 @@ struct NM_Main {
#define NM_USECS_NORMAL_TURN 45000
-/* This timeout is 140 ms in:
+/* OSEK/VDX NM: T_Max
+ *
+ * This timeout is 140 ms in:
* - 0x19 (RCD 310, Bosch)
*/
#define NM_USECS_NODE_AWOL 140000
-/* This timeout is 500 ms in:
+/* OSEK/VDX NM: T_Error
+ *
+ * This timeout is 500 ms in:
* - 0x19 (RCD 310, Bosch)
*/
#define NM_USECS_LIMPHOME 500000