Import last changes from 2017-03-26, including MDI hack
[revag-nm.git] / vw-nm.c
diff --git a/vw-nm.c b/vw-nm.c
index 5c15071e3b7b47727bf988ce64d4bbed0b874d9b..329f95e4b38fa8a52db1476faf67915afbca0aca 100644 (file)
--- a/vw-nm.c
+++ b/vw-nm.c
@@ -30,7 +30,8 @@
 
 
 
-static void nm_update_my_next_id(struct NM_Main *nm) {
+static void nm_update_my_next_id(struct NM_Main *nm)
+{
        unsigned id = nm->my_id;
 
        do {
@@ -53,6 +54,28 @@ static void nm_update_my_next_id(struct NM_Main *nm) {
 
 
 
+
+static unsigned nm_num_active_nodes(struct NM_Main *nm)
+{
+       unsigned id = 0;
+       unsigned active = 0;
+
+       for (id = 0; id < nm->max_nodes; id++) {
+               NM_State state;
+
+               state = nm->nodes[id].state & NM_MAIN_MASK;
+
+               if (state == NM_MAIN_ON || state == NM_MAIN_LOGIN) {
+                       /* We skip limp home nodes */
+                       active++;
+               }
+       }
+
+       return active;
+}
+
+
+
 static void nm_handle_can_frame(struct NM_Main *nm, struct can_frame *frame)
 {
        NM_ID sender, next;
@@ -78,6 +101,15 @@ static void nm_handle_can_frame(struct NM_Main *nm, struct can_frame *frame)
                return;
        }
 
+       /* If we're currently stuck in Limp Home mode, and we can see
+        * someone else's messages: reset counters, reset NM, re-login.
+        */
+       if ((nm->nodes[nm->my_id].state & NM_MAIN_MASK)
+               == NM_MAIN_LIMPHOME) {
+               nm_initreset(nm);
+               return;
+       }
+
        nm->nodes[sender].next = next;
        nm->nodes[sender].state = state;
 
@@ -143,9 +175,19 @@ static void nm_handle_can_frame(struct NM_Main *nm, struct can_frame *frame)
                         * round.
                         */
 
+                       /* HACK:
+                        * Special case: The Media-In's NM implementation
+                        * doesn't auto-switch to NM_ON. Let's say hello,
+                        * even if it ends up being a little late.
+                        */
+                       if (nm_num_active_nodes(nm) >= 2) {
+                               nm_set_timer_normal(nm);
+                       }
+
                        /* Nothing else to do. */
                        break;
                case NM_MAIN_LIMPHOME:
+                       /* Nothing we can do. Poor guy. */
                        break;
        }
 
@@ -172,23 +214,35 @@ static void nm_timeout_callback(struct NM_Main *nm, struct can_frame *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;
-                               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_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);
-                       nm_buildframe(nm, frame);
                        break;
                case NM_TIMER_AWOL:
                        /* The network is silent because a node disappeared
@@ -196,13 +250,15 @@ 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:
-                       /* TODO */
+                       printf("Limp home timer expired again :(\n");
+
+                       nm_buildframe(nm, frame);
+                       nm_set_timer_limphome(nm);
                        break;
        }
-
-       nm_buildframe(nm, frame);
 }
 
 
@@ -275,14 +331,6 @@ int main(int argc, char **argv)
 
        s = net_init(argv[1]);
 
-       /* Stir up the hornet's nest */
-       if (1) {
-               struct can_frame frame;
-
-               nm_buildframe(nm, &frame);
-               can_tx(s, &frame);
-       }
-
        while (1) {
                int retval;