Detect limp home state
authornorly <ny-git@enpas.org>
Sun, 19 Mar 2017 00:44:33 +0000 (01:44 +0100)
committernorly <ny-git@enpas.org>
Sun, 19 Mar 2017 00:46:11 +0000 (01:46 +0100)
vw-nm-tools.h
vw-nm.c
vw-nm.h

index 44d5a1b39c1c7cd39878e0695d69fd7d0a9889f7..7d3c32681e0d1435270f1911cb40ce46ba997e7e 100644 (file)
@@ -137,19 +137,38 @@ static void nm_reset(struct NM_Main *nm)
 {
        unsigned id;
 
+       if (nm->nodes[nm->my_id].next == nm->my_id) {
+               nm->lonely_resets++;
+       }
+
        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;
+       if (nm->lonely_resets >= 5) {
+               printf("Limp home detected :(\n");
+
+               nm->nodes[nm->my_id].state = NM_MAIN_LIMPHOME;
+               nm_set_timer_limphome(nm);
+       } else {
+               nm->nodes[nm->my_id].state = NM_MAIN_LOGIN;
+               nm_set_timer_now(nm);
+       }
+}
+
 
-       nm_set_timer_now(nm);
+static void nm_initreset(struct NM_Main *nm)
+{
+       nm_reset(nm);
+
+       nm->lonely_resets = 0;
 }
 
 
 
+
 static struct NM_Main* nm_alloc(unsigned node_bits, NM_ID my_id, canid_t can_base)
 {
        struct NM_Main *nm;
@@ -173,7 +192,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_reset(nm);
+       nm_initreset(nm);
 
        return nm;
 }
diff --git a/vw-nm.c b/vw-nm.c
index a181fce00866871671c1bd9f3dca7cdac0c15b08..16631ad247fcb598157c5695d76a467777f03db0 100644 (file)
--- a/vw-nm.c
+++ b/vw-nm.c
@@ -79,10 +79,10 @@ static void nm_handle_can_frame(struct NM_Main *nm, struct can_frame *frame)
        }
 
        /* If we're currently stuck in Limp Home mode, and we can see
-        * someone else's messages, reset and re-login.
+        * someone else's messages: reset counters, reset NM, re-login.
         */
        if (nm->nodes[nm->my_id].state == NM_MAIN_LIMPHOME) {
-               nm_reset(nm);
+               nm_initreset(nm);
                return;
        }
 
@@ -179,27 +179,36 @@ 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_buildframe(nm, frame);
-
        switch(nm->timer_reason) {
                case NM_TIMER_NOW:
                        /* We're due to log in */
+                       nm_buildframe(nm, frame);
+
+                       if ((nm->nodes[nm->my_id].state & NM_MAIN_MASK)
+                               != NM_MAIN_LOGIN) {
+
+                               printf("BUG: TIMER_NOW expired in non-ON state %u\n",
+                                       nm->nodes[nm->my_id].state & NM_MAIN_MASK);
+                       }
 
                        /* We're going to be ready, let's
                         * change state (RCD 310 behavior)
                         */
                        nm->nodes[nm->my_id].state = NM_MAIN_ON;
+
                        nm_set_timer_normal(nm);
                        break;
                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;
-                               default:
-                                       printf("BUG: TIMER_NORMAL expired in non-ON state\n");
-                                       break;
+                       nm_buildframe(nm, frame);
+
+                       if ((nm->nodes[nm->my_id].state & NM_MAIN_MASK)
+                               != NM_MAIN_ON) {
+
+                               printf("BUG: TIMER_NORMAL expired in non-ON state %u\n",
+                                       nm->nodes[nm->my_id].state & NM_MAIN_MASK);
                        }
+
                        nm_set_timer_awol(nm);
                        break;
                case NM_TIMER_AWOL:
@@ -208,8 +217,12 @@ static void nm_timeout_callback(struct NM_Main *nm, struct can_frame *frame)
                         * Reset everything and start over.
                         */
                        nm_reset(nm);
+                       nm_buildframe(nm, frame);
                        break;
                case NM_TIMER_LIMPHOME:
+                       printf("Limp home timer expired again :(\n");
+
+                       nm_buildframe(nm, frame);
                        nm_set_timer_limphome(nm);
                        break;
        }
diff --git a/vw-nm.h b/vw-nm.h
index 23d0def4595cf482d9363020245c09543c50f02d..b9fd981bfdd0bc7c6336195cb42347ec3fa41597 100644 (file)
--- a/vw-nm.h
+++ b/vw-nm.h
@@ -44,6 +44,9 @@ struct NM_Main {
 
        struct timeval tv;
        enum timer_reason timer_reason;
+
+       /* How many times have we been alone when we reset? */
+       int lonely_resets;
 };