X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=vw-nm.c;h=a181fce00866871671c1bd9f3dca7cdac0c15b08;hb=93a111710a794d7c602d2b31387e4f882df4a7cd;hp=689cf694db56450e12bd639c60d77b4636bb1d0c;hpb=0aa4c34efd1890654cbdc946790737312f2f630d;p=revag-nm.git diff --git a/vw-nm.c b/vw-nm.c index 689cf69..a181fce 100644 --- a/vw-nm.c +++ b/vw-nm.c @@ -28,22 +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_update_my_next_id(struct NM_Main *nm) { @@ -60,7 +44,7 @@ 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; } @@ -94,70 +78,83 @@ 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 and re-login. + */ + if (nm->nodes[nm->my_id].state == NM_MAIN_LIMPHOME) { + nm_reset(nm); + return; + } + 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; - 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. */ + + /* 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->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; + /* We just received a random ON message. */ + + /* Nothing to do. */ } 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. * 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. + * round. */ + + /* Nothing else to do. */ + break; + case NM_MAIN_LIMPHOME: + /* Nothing we can do. Poor guy. */ break; } @@ -182,26 +179,40 @@ 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_buildframe(nm, frame); -} - - + switch(nm->timer_reason) { + case NM_TIMER_NOW: + /* We're due to log in */ -static void nm_start(struct NM_Main *nm, struct can_frame *frame) -{ - nm->tv.tv_sec = 0; - nm->tv.tv_usec = 50000; - - - - nm->nodes[nm->my_id].next = nm->my_id; - nm->nodes[nm->my_id].state = NM_MAIN_LOGIN; - - nm_buildframe(nm, frame); + /* 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_set_timer_awol(nm); + 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: + nm_set_timer_limphome(nm); + break; + } } @@ -257,13 +268,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; @@ -271,14 +285,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_start(nm, &frame); - can_tx(s, &frame); - } - while (1) { int retval; @@ -313,6 +319,7 @@ int main(int argc, char **argv) } nm_free(nm); + close(s); return 0; }