changeset 244:d1e26bffa503 main

Initial check in for the odr-imu project.
author Bob Cook <bob@bobcookdev.com>
date Tue, 21 Jul 2015 19:53:49 -0700
parents b568dde5f512
children 44333100915a
files main/robots/odr-imu/canmsgs.cpp main/robots/odr-imu/func.h main/robots/odr-imu/jamfile main/robots/odr-imu/leds.cpp main/robots/odr-imu/leds.h main/robots/odr-imu/leds.inl main/robots/odr-imu/main.cpp main/robots/odr-imu/project_defs.h main/robots/odr-imu/status.cpp
diffstat 9 files changed, 1034 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-imu/canmsgs.cpp	Tue Jul 21 19:53:49 2015 -0700
@@ -0,0 +1,143 @@
+// ----------------------------------------------------------------------------------------
+//
+//  Copyright (C) 2015 Bob Cook
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+// 
+//  CAN related functions for the Outdoor Robot IMU node.
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+// 
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+// 
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+//
+// ----------------------------------------------------------------------------------------
+
+#include "project_defs.h"
+
+#include "func.h"
+
+#include "packages/avr/can/m1.h"
+
+#include "packages/common/can/can_helpers.h"
+#include "packages/common/can/can_messages.h"
+#include "packages/common/can/can_nodes.h"
+
+#include "packages/avr/device/spinwait.h"
+
+// ----------------------------------------------------------------------------------------
+
+bool canmsg_init()
+{
+    return m1can_init();
+}
+
+// ----------------------------------------------------------------------------------------
+
+bool canmsg_send_emergency()
+{
+    return m1can_send( can_build_message_id( can_node_sensor_imu,
+                                             can_node_broadcast,
+                                             can_dataid_emergency ), 0, 0 );
+}
+
+// ----------------------------------------------------------------------------------------
+
+bool canmsg_send_all_clear()
+{
+    return m1can_send( can_build_message_id( can_node_sensor_imu,
+                                             can_node_broadcast,
+                                             can_dataid_all_clear ), 0, 0 );
+}
+
+// ----------------------------------------------------------------------------------------
+
+bool canmsg_send_heartbeat()
+{
+    return m1can_send( can_build_message_id( can_node_sensor_imu,
+                                             can_node_broadcast,
+                                             can_dataid_heartbeat ), 0, 0 );
+}
+
+// ----------------------------------------------------------------------------------------
+
+bool canmsg_send_gps_latitude( int16_t degrees, uint16_t minutes, uint16_t min_fract )
+{
+    uint32_t msgid;
+    msgid = can_build_message_id( can_node_sensor_gps,
+                                  can_node_broadcast,
+                                  can_dataid_gps_latitude );
+
+    can_data_gps_data data;
+
+    data.degrees          = degrees;
+    data.min_thousandths  = minutes;
+    data.min_thousandths *= can_data_gps_min_multiplier;
+    data.min_thousandths += ( min_fract / // convert between units
+                ( nmea_fractional_minutes_multiplier / can_data_gps_min_multiplier ) );
+
+    return m1can_send( msgid, reinterpret_cast< uint8_t* >( &data ), sizeof( data ) );
+}
+
+// ----------------------------------------------------------------------------------------
+
+bool canmsg_process_pending()
+{
+    uint32_t recvid;
+    bool     recvrequest = false;
+    uint8_t  recvdata[ 8 ];
+    uint8_t  recvlen = sizeof( recvdata );
+
+    for ( ;; )
+    {
+        if ( ! m1can_read( &recvid, &recvrequest, recvdata, &recvlen ) )
+        {
+            return true; // no messages, everything ok
+        }
+
+        uint8_t  srcnode;
+        uint8_t  dstnode;
+        uint16_t dataid;
+        can_parse_message_id( recvid, &srcnode, &dstnode, &dataid );
+
+        if ( dstnode != can_node_broadcast && dstnode != can_node_sensor_imu )
+        {
+            continue; // not for us, try again
+        }
+
+        switch ( dataid )
+        {
+            case can_dataid_emergency:
+                status_got_emergency( srcnode );
+                break;
+
+            case can_dataid_all_clear:
+                status_got_all_clear( srcnode );
+                break;
+
+            case can_dataid_heartbeat:
+            case can_dataid_odrmgr_update:
+                status_got_heartbeat( srcnode );
+                break;
+        }
+    }
+
+    return true; // no errors
+}
+
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-imu/func.h	Tue Jul 21 19:53:49 2015 -0700
@@ -0,0 +1,63 @@
+// ----------------------------------------------------------------------------------------
+//
+//  Copyright (C) 2012-2013 Bob Cook
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+// 
+//  Function prototypes.
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+// 
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+// 
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+//
+// ----------------------------------------------------------------------------------------
+
+#if !defined( FUNC_H )
+#define FUNC_H
+
+#include <stdint.h>
+
+// ----------------------------------------------------------------------------------------
+
+void status_init();
+void status_update();
+
+void status_set_emergency();
+
+void status_got_emergency( uint8_t node );
+void status_got_all_clear( uint8_t node );
+void status_got_heartbeat( uint8_t node );
+void status_got_gps_sentence();
+
+bool status_is_emergency();
+bool status_is_gps_active();
+
+// ----------------------------------------------------------------------------------------
+
+bool canmsg_init();
+bool canmsg_send_emergency();
+bool canmsg_send_all_clear();
+bool canmsg_send_heartbeat();
+bool canmsg_send_gps_fix_info( uint8_t satellites );
+bool canmsg_send_gps_latitude( int16_t degrees, uint16_t minutes, uint16_t min_fract );
+bool canmsg_send_gps_longitude( int16_t degrees, uint16_t minutes, uint16_t min_fract );
+bool canmsg_process_pending();
+
+// ----------------------------------------------------------------------------------------
+#endif // #if !defined( FUNC_H )
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-imu/jamfile	Tue Jul 21 19:53:49 2015 -0700
@@ -0,0 +1,47 @@
+# -----------------------------------------------------------------------------------------
+#
+#   Copyright (C) 2015 Bob Cook
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#    
+#   Permission is hereby granted, free of charge, to any person obtaining a copy
+#   of this software and associated documentation files (the "Software"), to deal
+#   in the Software without restriction, including without limitation the rights
+#   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+#   copies of the Software, and to permit persons to whom the Software is
+#   furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included in
+#   all copies or substantial portions of the Software.
+#
+#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+#   THE SOFTWARE.
+#
+# -----------------------------------------------------------------------------------------
+
+if $(TRACE) { echo "trace /robots/odr-imu/jamfile" ; }
+
+SubDir TOP robots odr-imu ;
+
+# -----------------------------------------------------------------------------------------
+
+avr_executable
+    odr-imu atmega16m1
+    : main.cpp
+      canmsgs.cpp
+      leds.cpp
+      status.cpp
+      packages.avr.can.pkg
+      packages.avr.device.pkg
+      packages.common.can.pkg
+      packages.common.util.pkg
+    ;
+
+# -----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-imu/leds.cpp	Tue Jul 21 19:53:49 2015 -0700
@@ -0,0 +1,42 @@
+// ----------------------------------------------------------------------------------------
+//
+//  Copyright (C) 2015 Bob Cook
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+// 
+//  LED functions for the Outdoor Robot IMU board.
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+// 
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+// 
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+//
+// ----------------------------------------------------------------------------------------
+
+#include <avr/io.h>
+
+// ----------------------------------------------------------------------------------------
+
+void leds_off()
+{
+    PORTB |= ( 1 << PB2 );
+    PORTC |= ( 1 << PC4 ) | ( 1 << PC5 );
+    PORTD |= ( 1 << PD7 );
+}
+
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-imu/leds.h	Tue Jul 21 19:53:49 2015 -0700
@@ -0,0 +1,67 @@
+// ----------------------------------------------------------------------------------------
+//
+//  Copyright (C) 2015 Bob Cook
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+// 
+//  Function prototypes for the LEDs.
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+// 
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+// 
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+//
+// ----------------------------------------------------------------------------------------
+
+#if !defined( LEDS_H )
+#define LEDS_H
+
+// ----------------------------------------------------------------------------------------
+
+void leds_off();
+
+// ----------------------------------------------------------------------------------------
+
+void led_red_off() __attribute__((always_inline));
+void led_red_on() __attribute__((always_inline));
+void led_red_toggle() __attribute__((always_inline));
+
+// ----------------------------------------------------------------------------------------
+
+void led_yellow_off() __attribute__((always_inline));
+void led_yellow_on() __attribute__((always_inline));
+void led_yellow_toggle() __attribute__((always_inline));
+
+// ----------------------------------------------------------------------------------------
+
+void led_green_1_off() __attribute__((always_inline));
+void led_green_1_on() __attribute__((always_inline));
+void led_green_1_toggle() __attribute__((always_inline));
+
+// ----------------------------------------------------------------------------------------
+
+void led_green_2_off() __attribute__((always_inline));
+void led_green_2_on() __attribute__((always_inline));
+void led_green_2_toggle() __attribute__((always_inline));
+
+// ----------------------------------------------------------------------------------------
+
+#include "leds.inl"
+
+// ----------------------------------------------------------------------------------------
+#endif // #if !defined( LEDS_H )
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-imu/leds.inl	Tue Jul 21 19:53:49 2015 -0700
@@ -0,0 +1,99 @@
+// ----------------------------------------------------------------------------------------
+//
+//  Copyright (C) 2015 Bob Cook
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+// 
+//  LED functions for the Outdoor Robot IMU board.
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+// 
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+// 
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+//
+// ----------------------------------------------------------------------------------------
+
+#include <avr/io.h>
+
+inline void led_red_off()
+{
+    PORTD |= ( 1 << PD7 );
+}
+
+inline void led_red_on()
+{
+    PORTD &= ~( 1 << PD7 );
+}
+
+inline void led_red_toggle()
+{
+    PORTD ^= ( 1 << PD7 );
+}
+
+// ----------------------------------------------------------------------------------------
+
+inline void led_yellow_off()
+{
+    PORTB |= ( 1 << PB2 );
+}
+
+inline void led_yellow_on()
+{
+    PORTB &= ~( 1 << PB2 );
+}
+    
+inline void led_yellow_toggle()
+{
+    PORTB ^= ( 1 << PB2 );
+}
+    
+// ----------------------------------------------------------------------------------------
+
+inline void led_green_2_off()
+{
+    PORTC |= ( 1 << PC4 );
+}
+
+inline void led_green_2_on()
+{
+    PORTC &= ~( 1 << PC4 );
+}
+    
+inline void led_green_2_toggle()
+{
+    PORTC ^= ( 1 << PC4 );
+}
+    
+// ----------------------------------------------------------------------------------------
+
+inline void led_green_1_off()
+{
+    PORTC |= ( 1 << PC5 );
+}
+
+inline void led_green_1_on()
+{
+    PORTC &= ~( 1 << PC5 );
+}
+
+inline void led_green_1_toggle()
+{
+    PORTC ^= ( 1 << PC5 );
+}
+    
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-imu/main.cpp	Tue Jul 21 19:53:49 2015 -0700
@@ -0,0 +1,381 @@
+// ----------------------------------------------------------------------------------------
+//
+//  Copyright (C) 2015 Bob Cook
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+// 
+//  IMU node for the Outdoor Robot project, using a CAN interface.
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+// 
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+// 
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+//
+// ----------------------------------------------------------------------------------------
+
+#include <avr/interrupt.h>
+#include <avr/io.h>
+#include <avr/sleep.h>
+
+#include "project_defs.h"
+
+#include "func.h"
+#include "leds.h"
+
+#include "packages/avr/device/int_helpers.h"
+#include "packages/avr/device/spinwait.h"
+#include "packages/avr/device/uart.h"
+
+#include "packages/common/util/misc.h"
+
+// always after other includes
+#include "packages/avr/device/workaround34734.h"
+
+// ----------------------------------------------------------------------------------------
+
+static const uint8_t trigger_main_loop_ok    = ( 1 << 0 );
+static const uint8_t trigger_send_heartbeat  = ( 1 << 1 );
+static const uint8_t trigger_check_emergency = ( 1 << 2 );
+static const uint8_t trigger_update_status   = ( 1 << 3 );
+
+static volatile uint8_t g_triggers;
+
+// ----------------------------------------------------------------------------------------
+
+static const uint8_t odrgps_fatal_error_can_init = 1;
+static const uint8_t odrgps_fatal_error_can_comm = 2;
+static const uint8_t odrgps_fatal_error_exiting  = 9;
+
+void odrgps_fatal_error( uint8_t fault )
+{
+    cli(); // no more interrupts
+    DDRB = 0; DDRC = 0; DDRD = 0; // everything is an input
+    DDRB |= ( 1 << PB2 ); // except the leds
+    DDRC |= ( 1 << PC4 ) | ( 1 << PC5 );
+    DDRD |= ( 1 << PD7 );
+    leds_off();
+
+    for ( ;; )
+    {
+        for ( uint8_t i = 0; i < 5; i++ )
+        {
+            led_red_on();
+            spinwait_delay_ms( 125 );
+            led_red_off();
+            spinwait_delay_ms( 75 );
+        }
+
+        spinwait_delay_ms( 125 );
+        led_red_on();
+        led_yellow_on();
+        spinwait_delay_ms( 125 );
+
+        for ( uint8_t i = 0; i < fault; i++ )
+        {
+            led_green_1_on();
+            led_green_2_on();
+            spinwait_delay_ms( 350 );
+            
+            led_green_1_off();
+            led_green_2_off();
+            spinwait_delay_ms( 350 );
+        }
+
+        spinwait_delay_ms( 1000 );
+        
+        led_red_off();
+        led_yellow_off();
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+
+void odrgps_hw_init()
+{
+    //--    Turn off all interrupts.
+
+    cli();
+    interrupts_clear_all();
+
+    //--    Indicator LEDs on PORTB.2, PORTC.4, PORTC.5, PORTD.7
+
+    DDRB |= ( 1 << PB2 );
+    DDRC |= ( 1 << PC4 ) | ( 1 << PC5 );
+    DDRD |= ( 1 << PD7 );
+    leds_off();
+
+    //--    Blink the LEDs just to say hello.
+    
+    for ( uint8_t i = 0; i < 5; i++ )
+    {
+        led_red_on();
+        led_yellow_on();
+        led_green_1_on();
+        led_green_2_on();
+        spinwait_delay_ms( 75 );
+        leds_off();
+        spinwait_delay_ms( 75 );
+    }
+
+    //--    Timer0 gives up a periodic "heartbeat" interrupt at ~100 Hz.
+
+    TCCR0A = 0
+
+        | ( 0 << COM0A1 ) | ( 0 << COM0A0 )                 // OC0A disconnected
+        | ( 0 << COM0B1 ) | ( 0 << COM0B0 )                 // OC0B disconnected
+        | ( 1 << WGM01  ) | ( 0 << WGM00  )                 // CTC mode
+        ;
+
+    TCCR0B = 0
+
+        | ( 0 << FOC0A ) | ( 0 << FOC0B )                   // no force output compare
+        | ( 0 << WGM02 )                                    // CTC mode
+        | ( 1 << CS02  ) | ( 0 << CS01  ) | ( 1 << CS00 )   // clk/1024
+        ;
+
+    OCR0A = 156;
+
+    TIMSK0 |= ( 1 << OCIE0A );
+
+    //--    Initialize the status subsystem.
+
+    status_init();
+
+    //--    Initialize the serial port to the GPS unit, 4800 bps.
+
+    uart0_init();
+    uart0_set_baudrate( 4800 );
+
+    //--    Initialize the CAN related functions and hardware.
+
+    if ( ! canmsg_init() )
+    {
+        odrgps_fatal_error( odrgps_fatal_error_can_init );
+    }
+
+    //--    When we sleep we want the "idle" mode e.g. wake up on any interrupt.
+
+    set_sleep_mode( SLEEP_MODE_IDLE );
+
+    //--    Re-enable interrupts.
+
+    sei();
+}
+
+// ----------------------------------------------------------------------------------------
+
+ISR( TIMER0_COMPA_vect )
+{
+    static uint8_t count = 0;
+
+    //--    The trigger_main_loop_ok flag indicates the main loop is "alive" e.g. still
+    //      running. We only blink the "heartbeat" LED if it continues to toggle.
+    //
+    //      led blink pattern: 60 milliseconds on, 150 off, 60 on
+    //      check ESTOP status: every 100 milliseconds
+    //      update the system status every 500 milliseconds
+    //      heartbeat: every 2.5 seconds
+    
+    if ( count % 10 == 0 )
+    {
+        g_triggers |= trigger_check_emergency;
+    }
+
+    if ( count % 50 == 0 )
+    {
+        g_triggers |= trigger_update_status;
+    }
+
+    switch ( ++count )
+    {
+        case 10:
+            if ( g_triggers & trigger_main_loop_ok ) { led_green_1_on(); }
+            break;
+
+        case 16:
+            if ( g_triggers & trigger_main_loop_ok ) { led_green_1_off(); }
+            break;
+
+        case 31:
+            if ( g_triggers & trigger_main_loop_ok ) { led_green_1_on(); }
+            break;
+
+        case 37:
+            if ( g_triggers & trigger_main_loop_ok ) { led_green_1_off(); }
+            g_triggers &= ~trigger_main_loop_ok;
+            break;
+
+        case 125:
+            g_triggers |= trigger_send_heartbeat;
+            break;
+
+        case 250:
+            g_triggers |= trigger_send_heartbeat;
+            count = 0;
+            break;
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+
+int main()
+{
+    //--    Initialize the hardware and send a "hello we started" message.
+
+    odrgps_hw_init();
+    canmsg_send_all_clear();
+
+    //--    Loop forever responding to CAN messages and system status.
+
+    uint8_t can_comm_errors = 0;
+
+    for ( ;; )
+    {
+        //--    The main loop is still running.
+
+        g_triggers |= trigger_main_loop_ok;
+
+        //--    Sleep until there is a new interrupt (the CAN driver gets one, as does
+        //      the periodic heartbeat, so we won't sleep forever).
+
+//        sleep_mode();
+
+        //--    Character available from the GPS module?
+
+        if ( uart0_is_char_available() )
+        {
+            if ( nmea_parse( uart0_read() ) )
+            {
+                //--    NMEA sentence parsed successfully.
+
+                led_green_2_toggle();
+                status_got_gps_sentence();
+
+                uint8_t satellites;
+
+                if ( nmea_position_fix( &satellites ) )
+                {
+                    if ( ! canmsg_send_gps_fix_info( satellites ) )
+                    {
+                        ++can_comm_errors;
+                    }
+
+                    int16_t  degrees;
+                    uint16_t minutes;
+                    uint16_t min_fract;
+
+                    nmea_latitude( &degrees, &minutes, &min_fract );
+
+                    if ( ! canmsg_send_gps_latitude( degrees, minutes, min_fract ) )
+                    {
+                        ++can_comm_errors;
+                    }
+
+                    nmea_longitude( &degrees, &minutes, &min_fract );
+
+                    if ( ! canmsg_send_gps_longitude( degrees, minutes, min_fract ) )
+                    {
+                        ++can_comm_errors;
+                    }
+                }
+                else
+                {
+                    if ( ! canmsg_send_gps_fix_info( 0 ) )
+                    {
+                        ++can_comm_errors;
+                    }
+                }
+            }
+        }
+        else if ( ! status_is_gps_active() )
+        {
+            led_green_2_off();
+        }
+
+        //--    Check for an emergency situation?
+
+        if ( g_triggers & trigger_check_emergency )
+        {
+            g_triggers &= ~trigger_check_emergency;
+
+            if ( status_is_emergency() )
+            {
+                led_red_on();
+            }
+            else
+            {
+                led_red_off();
+            }
+        }
+
+        //--    Time to send the heartbeat message?
+
+        if ( g_triggers & trigger_send_heartbeat )
+        {
+            g_triggers &= ~trigger_send_heartbeat;
+
+            if ( ! canmsg_send_heartbeat() )
+            {
+                ++can_comm_errors;
+            }
+        }
+
+        //--    Time to check status?
+
+        if ( g_triggers & trigger_update_status )
+        {
+            g_triggers &= ~trigger_update_status;
+
+            status_update();
+        }
+
+        //--    Any pending CAN messages to receive/process?
+
+        if ( ! canmsg_process_pending() )
+        {
+            ++can_comm_errors;
+        }
+
+        //--    Report warning and/or error conditions.
+
+        bool warning = false;
+
+        if ( can_comm_errors > 50 )
+        {
+            odrgps_fatal_error( odrgps_fatal_error_can_comm );
+        }
+        else if ( can_comm_errors > 10 )
+        {
+            warning = true;
+        }
+
+        if ( warning )
+        {
+            led_yellow_on();
+        }
+        else
+        {
+            led_yellow_off();
+        }
+    }
+
+    odrgps_fatal_error( odrgps_fatal_error_exiting );
+    return 0;
+}
+
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-imu/project_defs.h	Tue Jul 21 19:53:49 2015 -0700
@@ -0,0 +1,48 @@
+// ----------------------------------------------------------------------------------------
+//
+//  Copyright (C) 2015 Bob Cook
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+//  
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+//  
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+//
+// ----------------------------------------------------------------------------------------
+
+#if !defined( PROJECT_DEFS_H )
+#define PROJECT_DEFS_H
+
+// ----------------------------------------------------------------------------------------
+//  packages/avr/common
+
+#define PRJ_CPU_FREQ    16000000L
+
+// ----------------------------------------------------------------------------------------
+//  packages/avr/can
+
+#define PRJ_M1CAN_ENABLE
+#define PRJ_M1CAN_CANBUS_500_KHZ
+#define PRJ_M1CAN_TX_BUFFER_SIZE  8
+
+// ----------------------------------------------------------------------------------------
+//  packages/avr/device
+
+#define PRJ_UART0_USE_POLLED_MODE
+
+
+#endif // #if !defined( PROJECT_DEFS_H )
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-imu/status.cpp	Tue Jul 21 19:53:49 2015 -0700
@@ -0,0 +1,144 @@
+// ----------------------------------------------------------------------------------------
+//
+//  Copyright (C) 2015 Bob Cook
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+// 
+//  Status functions for the Outdoor Robot IMU node.
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+// 
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+// 
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+//
+//  There is an implicit assumption our "heartbeat" is 2 Hz (twice per second).
+//
+// ----------------------------------------------------------------------------------------
+
+#include "func.h"
+#include "leds.h"
+
+#include <avr/io.h>
+
+#include "packages/common/can/can_nodes.h"
+
+// ----------------------------------------------------------------------------------------
+//  "beats" is 500ms (approximately)
+
+static volatile uint8_t g_beats_without_mgr;
+static volatile uint8_t g_beats_without_imu;
+
+static volatile uint8_t g_status_flags;
+
+static const uint8_t status_flag_emergency_active = ( 1 << 0 );
+
+// ----------------------------------------------------------------------------------------
+
+void status_init()
+{
+    // initalize the heartbeat watchdog assuming no contact yet
+    g_beats_without_mgr = 100;
+    g_beats_without_imu = 100;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void status_update()
+{
+    if ( g_beats_without_mgr < 200 ) { ++g_beats_without_mgr; }
+    if ( g_beats_without_imu < 200 ) { ++g_beats_without_imu; }
+}
+
+// ----------------------------------------------------------------------------------------
+
+void status_got_heartbeat( uint8_t source )
+{
+    switch ( source )
+    {
+        case can_node_odr_manager:
+            g_beats_without_mgr = 0;
+            break;
+
+//        case can_node_odr_sonar_front:
+//            break;
+
+//        case can_node_gps:
+//            g_beats_without_gps = 0;
+//            break;
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+
+void status_got_imu_packet()
+{
+    g_beats_without_imu = 0;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void status_set_emergency()
+{
+    g_status_flags |= status_flag_emergency_active;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void status_got_emergency( uint8_t source )
+{
+    g_status_flags |= status_flag_emergency_active;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void status_got_all_clear( uint8_t source )
+{
+    if ( source == can_node_odr_manager )
+    {
+        g_status_flags &= ~status_flag_emergency_active;
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+
+bool status_is_emergency()
+{
+    // more than two seconds == down
+    if ( g_beats_without_mgr > 5 )
+    {
+        return true;
+    }
+
+    // more than five seconds == down
+    if ( g_beats_without_imu > 11 )
+    {
+        return true;
+    }
+
+    return ( g_status_flags & status_flag_emergency_active ) > 0;
+}
+
+// ----------------------------------------------------------------------------------------
+
+bool status_is_imu_active()
+{
+    // more than five seconds == down
+    return ( g_beats_without_imu < 11 );
+}
+
+// ----------------------------------------------------------------------------------------
+