Rework timers
[revag-nm.git] / vw-nm.c
diff --git a/vw-nm.c b/vw-nm.c
index 689cf694db56450e12bd639c60d77b4636bb1d0c..6a3ca05bb311b1aeaff6f02159f055cced754a8b 100644 (file)
--- a/vw-nm.c
+++ b/vw-nm.c
@@ -45,6 +45,32 @@ static int nm_is_rx_frame_valid(struct NM_Main *nm, struct can_frame *frame)
 
 
 
+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) {
        unsigned id = nm->my_id;
@@ -60,11 +86,20 @@ static void nm_update_my_next_id(struct NM_Main *nm) {
                state = nm->nodes[id].state & NM_MAIN_MASK;
 
                if (state == NM_MAIN_ON || state == NM_MAIN_LOGIN) {
-                       /* TODO: Check for limp home nodes? */
+                       /* We skip limp home nodes */
                        nm->nodes[nm->my_id].next = id;
                        break;
                }
        } while (id != nm->my_id);
+
+       if (nm->nodes[nm->my_id].next == nm->my_id) {
+               /* Uh oh, we're the only one left. */
+
+               /* TODO */
+               nm->nodes[nm->my_id].state = NM_MAIN_LOGIN;
+
+               /* TODO: Timeout 140ms (RCD 310) */
+       }
 }
 
 
@@ -105,60 +140,66 @@ static void nm_handle_can_frame(struct NM_Main *nm, struct can_frame *frame)
 
                                nm->nodes[nm->my_id].state = NM_MAIN_LOGIN;
 
-                               nm->tv.tv_sec = 0;
-                               nm->tv.tv_usec = 0;
+                               nm_set_timer_now(nm);
+
                                /* IMPORTANT: The caller needs to check for
-                                * timeouts first, so no other NM frames are
-                                * received until our correcting login has
-                                * been sent.
+                                * timeouts first, i.e. no other NM frames
+                                * are received until our correcting login
+                                * has been sent.
                                 */
                        } else if (next == nm->nodes[nm->my_id].next) {
-                               /* where nm->nodes[nm->my_id].next == nm->my_id */
-
-                               /* TODO: Is this a case we need to handle? */
+                               /* where (nm->nodes[nm->my_id].next == nm->my_id) */
 
                                /* It can happen when:
                                 *  - our sent frames don't go anywhere
                                 *  - we just logged in and immediately
                                 *    afterwards another ECU sent a regular
-                                *    NM frame without knowing that we exist.
+                                *    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;
                        } 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.
                                 */
-                               nm->tv.tv_sec = 0;
-                               nm->tv.tv_usec = NM_USECS_MY_TURN;
+                               nm_set_timer_normal(nm);
                        } else {
                                /* We just got some random ON message.
                                 * Reset the timer looking out for broken
                                 * connectivity.
                                 */
-                               nm->tv.tv_sec = 0;
-                               nm->tv.tv_usec = NM_USECS_OTHER_TURN;
+                               nm_set_timer_awol(nm);
                        }
                        break;
                case NM_MAIN_LOGIN:
                        /* Note: sender != nm->my_id */
 
-                       printf("Handling LOGIN\n");
-
                        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.
+                       /* We don't reset the timeout when somebody logs in,
+                        * i.e. (next == sender).
                         * Instead, we'll simply include them in the next
                         * round. */
 
                        /* Actually, when a login is done as a correction,
                         * we do reset the timeout.
-                        *
-                        * TODO.
                         */
+                       if (next != sender) {
+                               nm_set_timer_awol(nm);
+                       }
                        break;
+               case NM_MAIN_LIMPHOME:
+                       nm_update_my_next_id(nm);
        }
 
        nm_dump_all(nm);
@@ -182,8 +223,7 @@ 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->tv.tv_sec = 0;
-       nm->tv.tv_usec = NM_USECS_OTHER_TURN;
+       nm_set_timer_awol(nm);
 
        nm_buildframe(nm, frame);
 }
@@ -194,7 +234,7 @@ static void nm_timeout_callback(struct NM_Main *nm, struct can_frame *frame)
 static void nm_start(struct NM_Main *nm, struct can_frame *frame)
 {
        nm->tv.tv_sec = 0;
-       nm->tv.tv_usec = 50000;
+       nm->tv.tv_usec = NM_USECS_NODE_AWOL;
 
 
 
@@ -257,13 +297,16 @@ int main(int argc, char **argv)
        struct NM_Main *nm;
        fd_set rdfs;
        int s;
+       NM_ID my_id;
 
-       if (argc != 2) {
-               printf("syntax: %s IFNAME\n", argv[0]);
+       if (argc != 3) {
+               printf("syntax: %s IFNAME MY_ID\n", argv[0]);
                return 1;
        }
 
-       nm = nm_alloc(5, 0x0b, 0x420);
+       my_id = strtoul(argv[2], NULL, 0);
+
+       nm = nm_alloc(5, my_id, 0x420);
        if (!nm) {
                printf("Out of memory allocating NM struct.\n");
                return 1;
@@ -313,6 +356,7 @@ int main(int argc, char **argv)
        }
 
        nm_free(nm);
+       close(s);
 
        return 0;
 }