altos: Extend GPS altitudes to at least 24 bits everywhere
authorKeith Packard <keithp@keithp.com>
Fri, 11 Jul 2014 00:07:48 +0000 (17:07 -0700)
committerKeith Packard <keithp@keithp.com>
Fri, 11 Jul 2014 00:35:44 +0000 (17:35 -0700)
Telemetry gets a special 'mode' flag indicating that 24-bit data is
present; log files get new data and log readers are expected to detect
that via the firmware version number.

Signed-off-by: Keith Packard <keithp@keithp.com>
19 files changed:
src/cc1111/ao_pins.h
src/drivers/ao_aprs.c
src/drivers/ao_gps_skytraq.c
src/drivers/ao_gps_ublox.c
src/kernel/ao_gps_report.c
src/kernel/ao_gps_report_mega.c
src/kernel/ao_gps_report_metrum.c
src/kernel/ao_gps_show.c
src/kernel/ao_log.h
src/kernel/ao_log_gps.c
src/kernel/ao_log_gps.h
src/kernel/ao_telemetry.c
src/kernel/ao_telemetry.h
src/kernel/ao_tracker.c
src/test/ao_aprs_test.c
src/test/ao_flight_test.c
src/test/ao_gps_test.c
src/test/ao_gps_test_skytraq.c
src/test/ao_gps_test_ublox.c

index 1bc3d716004503bc4d0e2ad4f463cb53824c1b6c..4db49215946ebb872f7b392b2f57273ad43c65a4 100644 (file)
@@ -20,6 +20,7 @@
 
 #define HAS_RADIO              1
 #define DISABLE_LOG_SPACE      1
+#define HAS_WIDE_GPS           0
 
 #if defined(TELEMETRUM_V_1_0)
        /* Discontinued and was never built with CC1111 chips needing this */
index a9047149d981c3c0af7343bbaeab018fe14f80c7..19beb78f2b51dbf89f1f0f44563d50b203357bc2 100644 (file)
@@ -713,7 +713,7 @@ static int tncPositionPacket(void)
     if (ao_gps_data.flags & AO_GPS_VALID) {
        latitude = ao_gps_data.latitude;
        longitude = ao_gps_data.longitude;
-       altitude = ao_gps_data.altitude;
+       altitude = AO_TELEMETRY_LOCATION_ALTITUDE(&ao_gps_data);
        if (altitude < 0)
            altitude = 0;
     }
index 944a37f9b38400a05ccc3d2a437f332141af8a79..81178051b0e0416a5a758973fe9ab691ee7753fa 100644 (file)
@@ -287,7 +287,8 @@ ao_nmea_gga(void)
        ao_gps_next.hdop = i;
        ao_gps_skip_field();
 
-       ao_gps_next.altitude = ao_gps_decimal(0xff);
+       AO_TELEMETRY_LOCATION_SET_ALTITUDE(&ao_gps_next, ao_gps_decimal(0xff));
+
        ao_gps_skip_field();    /* skip any fractional portion */
 
        ao_nmea_finish();
index 077698a90d514a24672b3d990d867118a1c67a9c..487659984bb2a7ca0d57a4044c9661892a88d039 100644 (file)
@@ -728,7 +728,7 @@ ao_gps(void) __reentrant
                                if (nav_timeutc.valid & (1 << NAV_TIMEUTC_VALID_UTC))
                                        ao_gps_data.flags |= AO_GPS_DATE_VALID;
 
-                               ao_gps_data.altitude = nav_posllh.alt_msl / 1000;
+                               AO_TELEMETRY_LOCATION_SET_ALTITUDE(&ao_gps_data, nav_posllh.alt_msl / 1000);
                                ao_gps_data.latitude = nav_posllh.lat;
                                ao_gps_data.longitude = nav_posllh.lon;
 
index 07201ac235b69cd1656979fae18aaa94327c2d73..7ef98a972aefc7661166084aba65ebd05030ba02 100644 (file)
@@ -52,8 +52,12 @@ ao_gps_report(void)
                        gps_log.u.gps_longitude = gps_data.longitude;
                        ao_log_data(&gps_log);
                        gps_log.type = AO_LOG_GPS_ALT;
-                       gps_log.u.gps_altitude.altitude = gps_data.altitude;
-                       gps_log.u.gps_altitude.unused = 0xffff;
+                       gps_log.u.gps_altitude.altitude_low = gps_data.altitude_low;
+#if HAS_WIDE_GPS
+                       gps_log.u.gps_altitude.altitude_high = gps_data.altitude_high;
+#else
+                       gps_log.u.gps_altitude.altitude_high = 0xffff;
+#endif
                        ao_log_data(&gps_log);
                        if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) {
                                gps_log.type = AO_LOG_GPS_DATE;
index cb0c0fd99722eb38efc3d949f79306970e501d42..f3711fb19a9603390b8a9cc52b82a2c195c78897 100644 (file)
@@ -78,7 +78,8 @@ ao_gps_report_mega(void)
 #if GPS_SPARSE_LOG
                /* Don't log data if GPS has a fix and hasn't moved for a while */
                if ((gps_data.flags & AO_GPS_VALID) &&
-                   !ao_gps_sparse_should_log(gps_data.latitude, gps_data.longitude, gps_data.altitude))
+                   !ao_gps_sparse_should_log(gps_data.latitude, gps_data.longitude,
+                                             AO_TELEMETRY_LOCATION_ALTITUDE(&gps_data))
                        continue;
 #endif
                if ((new & AO_GPS_NEW_DATA) && (gps_data.flags & AO_GPS_VALID)) {
@@ -87,8 +88,8 @@ ao_gps_report_mega(void)
                        gps_log.type = AO_LOG_GPS_TIME;
                        gps_log.u.gps.latitude = gps_data.latitude;
                        gps_log.u.gps.longitude = gps_data.longitude;
-                       gps_log.u.gps.altitude = gps_data.altitude;
-
+                       gps_log.u.gps.altitude_low = gps_data.altitude_low;
+                       gps_log.u.gps.altitude_high = gps_data.altitude_high;
                        gps_log.u.gps.hour = gps_data.hour;
                        gps_log.u.gps.minute = gps_data.minute;
                        gps_log.u.gps.second = gps_data.second;
index 696a833b8147afd45d23dbbba2e9a9b0cdefed2e..31939385673be015f3bcf34e92c89797f7fd295d 100644 (file)
@@ -44,7 +44,8 @@ ao_gps_report_metrum(void)
                        gps_log.type = AO_LOG_GPS_POS;
                        gps_log.u.gps.latitude = gps_data.latitude;
                        gps_log.u.gps.longitude = gps_data.longitude;
-                       gps_log.u.gps.altitude = gps_data.altitude;
+                       gps_log.u.gps.altitude_low = gps_data.altitude_low;
+                       gps_log.u.gps.altitude_high = gps_data.altitude_high;
                        ao_log_metrum(&gps_log);
 
                        gps_log.type = AO_LOG_GPS_TIME;
index 3a05e35acd66260d5826513663d1653a04714bd7..e45cd795bbbd14aaf0ec967a85d5a1856f5786e8 100644 (file)
@@ -19,6 +19,8 @@
 #include <ao.h>
 #endif
 
+#include <ao_data.h>
+
 void
 ao_gps_show(void) __reentrant
 {
@@ -27,7 +29,11 @@ ao_gps_show(void) __reentrant
        printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day);
        printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second);
        printf ("Lat/Lon: %ld %ld\n", (long) ao_gps_data.latitude, (long) ao_gps_data.longitude);
-       printf ("Alt: %d\n", ao_gps_data.altitude);
+#if HAS_WIDE_GPS
+       printf ("Alt: %ld\n", (long) AO_TELEMETRY_LOCATION_ALTITUDE(&ao_gps_data));
+#else
+       printf ("Alt: %d\n", AO_TELEMETRY_LOCATION_ALTITUDE(&ao_gps_data));
+#endif
        printf ("Flags: 0x%x\n", ao_gps_data.flags);
        printf ("Sats: %d", ao_gps_tracking_data.channels);
        for (i = 0; i < ao_gps_tracking_data.channels; i++)
index 33cda3eb3560303f2a3d9030ebc0f76ed7fc89b9..080cfb02177af09053382e7074d14d7035673b92 100644 (file)
@@ -176,8 +176,8 @@ struct ao_log_record {
                int32_t         gps_latitude;
                int32_t         gps_longitude;
                struct {
-                       int16_t         altitude;
-                       uint16_t        unused;
+                       uint16_t        altitude_low;
+                       int16_t         altitude_high;
                } gps_altitude;
                struct {
                        uint16_t        svid;
@@ -246,7 +246,7 @@ struct ao_log_mega {
                struct {
                        int32_t         latitude;       /* 4 */
                        int32_t         longitude;      /* 8 */
-                       int16_t         altitude;       /* 12 */
+                       uint16_t        altitude_low;   /* 12 */
                        uint8_t         hour;           /* 14 */
                        uint8_t         minute;         /* 15 */
                        uint8_t         second;         /* 16 */
@@ -261,7 +261,8 @@ struct ao_log_mega {
                        uint8_t         hdop;           /* 27 */
                        uint8_t         vdop;           /* 28 */
                        uint8_t         mode;           /* 29 */
-               } gps;  /* 30 */
+                       int16_t         altitude_high;  /* 30 */
+               } gps;  /* 32 */
                /* AO_LOG_GPS_SAT */
                struct {
                        uint16_t        channels;       /* 4 */
@@ -273,6 +274,11 @@ struct ao_log_mega {
        } u;
 };
 
+#define AO_LOG_MEGA_GPS_ALTITUDE(l)    ((int32_t) ((l)->u.gps.altitude_high << 16) | ((l)->u.gps.altitude_low))
+#define AO_LOG_MEGA_SET_GPS_ALTITUDE(l,a)      (((l)->u.gps.mode |= AO_GPS_MODE_ALTITUDE_24), \
+                                                ((l)->u.gps.altitude_high = (a) >> 16), \
+                                                (l)->u.gps.altitude_low = (a))
+
 struct ao_log_metrum {
        char                    type;                   /* 0 */
        uint8_t                 csum;                   /* 1 */
@@ -306,8 +312,9 @@ struct ao_log_metrum {
                struct {
                        int32_t         latitude;       /* 4 */
                        int32_t         longitude;      /* 8 */
-                       int16_t         altitude;       /* 12 */
-               } gps;          /* 14 */
+                       uint16_t        altitude_low;   /* 12 */
+                       int16_t         altitude_high;  /* 14 */
+               } gps;          /* 16 */
                /* AO_LOG_GPS_TIME */
                struct {
                        uint8_t         hour;           /* 4 */
@@ -381,7 +388,7 @@ struct ao_log_gps {
                struct {
                        int32_t         latitude;       /* 4 */
                        int32_t         longitude;      /* 8 */
-                       int16_t         altitude;       /* 12 */
+                       uint16_t        altitude_low;   /* 12 */
                        uint8_t         hour;           /* 14 */
                        uint8_t         minute;         /* 15 */
                        uint8_t         second;         /* 16 */
@@ -396,7 +403,7 @@ struct ao_log_gps {
                        uint8_t         hdop;           /* 27 */
                        uint8_t         vdop;           /* 28 */
                        uint8_t         mode;           /* 29 */
-                       uint8_t         state;          /* 30 */
+                       int16_t         altitude_high;  /* 30 */
                } gps;  /* 31 */
                /* AO_LOG_GPS_SAT */
                struct {
index 3b728c25f1f7887f8d5db5d9403218e0550bbe5f..a5a6358bf7fd9267ddb414357a0f5fbd220eab8d 100644 (file)
@@ -75,7 +75,8 @@ ao_log_gps_data(uint16_t tick, struct ao_telemetry_location *gps_data)
        log.type = AO_LOG_GPS_TIME;
        log.u.gps.latitude = gps_data->latitude;
        log.u.gps.longitude = gps_data->longitude;
-       log.u.gps.altitude = gps_data->altitude;
+       log.u.gps.altitude_low = gps_data->altitude_low;
+       log.u.gps.altitude_high = gps_data->altitude_high;
 
        log.u.gps.hour = gps_data->hour;
        log.u.gps.minute = gps_data->minute;
index 5851f4d1fadbeedbe83d57a9fa797cab85cbf3a3..a9e8c83168be867353df51be4b8ece3a4cef40bd 100644 (file)
@@ -21,9 +21,6 @@
 #ifndef _AO_LOG_GPS_H_
 #define _AO_LOG_GPS_H_
 
-uint8_t
-ao_log_gps_should_log(int32_t lat, int32_t lon, int16_t alt);
-
 void
 ao_log_gps_flight(void);
 
index d321c8ffd5f6800e61db30fbadbd05e1f5e157ba..56bd715e7b690d15a800f677db7b87b37897e5af 100644 (file)
@@ -344,7 +344,7 @@ ao_send_location(void)
                ao_mutex_get(&ao_gps_mutex);
                ao_xmemcpy(&telemetry.location.flags,
                       &ao_gps_data.flags,
-                      26);
+                      27);
                telemetry.location.tick = ao_gps_tick;
                ao_mutex_put(&ao_gps_mutex);
                ao_radio_send(&telemetry, sizeof (telemetry));
index be7d0340745352d20505dc265a00e1f8390cf8da..83d432cf95f39db62dc9f602d8011c58a46f49ae 100644 (file)
@@ -86,12 +86,9 @@ struct ao_telemetry_configuration {
 
 #define AO_TELEMETRY_LOCATION          0x05
 
-#define AO_GPS_MODE_NOT_VALID          'N'
-#define AO_GPS_MODE_AUTONOMOUS         'A'
-#define AO_GPS_MODE_DIFFERENTIAL       'D'
-#define AO_GPS_MODE_ESTIMATED          'E'
-#define AO_GPS_MODE_MANUAL             'M'
-#define AO_GPS_MODE_SIMULATED          'S'
+/* Mode bits */
+
+#define AO_GPS_MODE_ALTITUDE_24                (1 << 0)        /* reports 24-bits of altitude */
 
 struct ao_telemetry_location {
        uint16_t        serial;         /*  0 */
@@ -99,7 +96,7 @@ struct ao_telemetry_location {
        uint8_t         type;           /*  4 */
 
        uint8_t         flags;          /*  5 Number of sats and other flags */
-       int16_t         altitude;       /*  6 GPS reported altitude (m) */
+       uint16_t        altitude_low;   /*  6 GPS reported altitude (m) */
        int32_t         latitude;       /*  8 latitude (degrees * 10⁷) */
        int32_t         longitude;      /* 12 longitude (degrees * 10⁷) */
        uint8_t         year;           /* 16 (- 2000) */
@@ -115,10 +112,31 @@ struct ao_telemetry_location {
        uint16_t        ground_speed;   /* 26 cm/s */
        int16_t         climb_rate;     /* 28 cm/s */
        uint8_t         course;         /* 30 degrees / 2 */
-       uint8_t         unused;         /* 31 unused */
+       int8_t          altitude_high;  /* 31 high byte of altitude */
        /* 32 */
 };
 
+#if HAS_GPS
+
+#ifndef HAS_WIDE_GPS
+#define HAS_WIDE_GPS   1
+#endif
+
+#if HAS_WIDE_GPS
+typedef int32_t                gps_alt_t;
+#define AO_TELEMETRY_LOCATION_ALTITUDE(l)      (((gps_alt_t) (l)->altitude_high << 16) | ((l)->altitude_low))
+#define AO_TELEMETRY_LOCATION_SET_ALTITUDE(l,a) (((l)->mode |= AO_GPS_MODE_ALTITUDE_24), \
+                                                ((l)->altitude_high = (a) >> 16), \
+                                                ((l)->altitude_low = (a)))
+#else
+typedef int16_t                gps_alt_t;
+#define AO_TELEMETRY_LOCATION_ALTITUDE(l)      ((gps_alt_t) (l)->altitude_low)
+#define AO_TELEMETRY_LOCATION_SET_ALTITUDE(l,a)        (((l)->mode = 0, \
+                                                 (l)->altitude_low = (a)))
+#endif /* HAS_WIDE_GPS */
+
+#endif /* HAS_GPS */
+
 #define AO_TELEMETRY_SATELLITE         0x06
 
 struct ao_telemetry_satellite_info {
index 9febc7f090cb6ac33197b40cc054b9ee216e8a39..d94340484a8221248d89068bad9320c141e3fbf0 100644 (file)
@@ -36,9 +36,9 @@ ao_usb_connected(void)
 #endif
 
 struct gps_position {
-       int32_t latitude;
-       int32_t longitude;
-       int16_t altitude;
+       int32_t         latitude;
+       int32_t         longitude;
+       gps_alt_t       altitude;
 };
 
 #define GPS_RING       16
@@ -122,12 +122,13 @@ ao_tracker(void)
                        {
                                uint8_t ring;
                                uint8_t moving = 0;
+                               gps_alt_t altitude = AO_TELEMETRY_LOCATION_ALTITUDE(&gps_data);
 
                                for (ring = ao_gps_ring_next(gps_head); ring != gps_head; ring = ao_gps_ring_next(ring)) {
                                        ground_distance = ao_distance(gps_data.latitude, gps_data.longitude,
                                                                      gps_position[ring].latitude,
                                                                      gps_position[ring].longitude);
-                                       height = gps_position[ring].altitude - gps_data.altitude;
+                                       height = gps_position[ring].altitude - altitude;
                                        if (height < 0)
                                                height = -height;
 
@@ -153,7 +154,7 @@ ao_tracker(void)
                                        ao_log_gps_data(gps_tick, &gps_data);
                                        gps_position[gps_head].latitude = gps_data.latitude;
                                        gps_position[gps_head].longitude = gps_data.longitude;
-                                       gps_position[gps_head].altitude = gps_data.altitude;
+                                       gps_position[gps_head].altitude = altitude;
                                        gps_head = ao_gps_ring_next(gps_head);
                                        ao_mutex_put(&tracker_mutex);
                                }
@@ -203,7 +204,7 @@ ao_tracker_set_telem(void)
        printf ("log_started: %d\n", log_started);
        printf ("latitude: %ld\n", (long) gps_data.latitude);
        printf ("longitude: %ld\n", (long) gps_data.longitude);
-       printf ("altitude: %d\n", gps_data.altitude);
+       printf ("altitude: %ld\n", AO_TELEMETRY_LOCATION_ALTITUDE(&gps_data));
        printf ("log_running: %d\n", ao_log_running);
        printf ("log_start_pos: %ld\n", (long) ao_log_start_pos);
        printf ("log_cur_pos: %ld\n", (long) ao_log_current_pos);
index 573b5cb22a1ed6e3386867b9f10c0f11bb019a84..ae505dea77e7e732a81bcc995624ff8adef4b959 100644 (file)
@@ -21,6 +21,8 @@
 #include <stdint.h>
 #include <stdarg.h>
 
+#define HAS_GPS        1
+
 #include <ao_telemetry.h>
 
 #define AO_GPS_NUM_SAT_MASK    (0xf << 0)
@@ -100,14 +102,11 @@ audio_gap(int secs)
 // This is where we go after reset.
 int main(int argc, char **argv)
 {
-       int     e, x;
-       int     a;
-
     audio_gap(1);
 
     ao_gps_data.latitude = (45.0 + 28.25 / 60.0) * 10000000;
     ao_gps_data.longitude = (-(122 + 44.2649 / 60.0)) * 10000000;
-    ao_gps_data.altitude = 84;
+    AO_TELEMETRY_LOCATION_SET_ALTITUDE(&ao_gps_data, 84);
     ao_gps_data.flags = (AO_GPS_VALID|AO_GPS_RUNNING);
 
     /* Transmit one packet */
index 1ab22e5b6acf4cd5af37d4e98b513b61b68fbb0f..314998c1bc750667bfe4a50abba06cb2f689b75b 100644 (file)
@@ -175,7 +175,7 @@ ao_gps_angle(void)
                        ao_gps_static.latitude / 1e7,
                        ao_gps_static.longitude / 1e7,
                        &dist, &bearing);
-       height = ao_gps_static.altitude - ao_gps_prev.altitude;
+       height = AO_TELEMETRY_LOCATION_ALTITUDE(&ao_gps_static) - AO_TELEMETRY_LOCATION_ALTITUDE(&ao_gps_prev);
 
        angle = atan2(dist, height);
        return angle * 180/M_PI;
@@ -756,7 +756,10 @@ ao_sleep(void *wchan)
                                        ao_gps_static.tick = tick;
                                        ao_gps_static.latitude = int32(bytes, 0);
                                        ao_gps_static.longitude = int32(bytes, 4);
-                                       ao_gps_static.altitude = int32(bytes, 8);
+                                       {
+                                               int32_t altitude = int32(bytes, 8);
+                                               AO_TELEMETRY_LOCATION_SET_ALTITUDE(&ao_gps_static, altitude);
+                                       }
                                        ao_gps_static.flags = bytes[13];
                                        if (!ao_gps_count)
                                                ao_gps_first = ao_gps_static;
index e799ab0fc8f0a70e612c72bcbbe6c8c724842a31..543bbcc304b032ab69c6442dbf380ca62d596473 100644 (file)
@@ -53,6 +53,9 @@ struct ao_gps_orig {
        uint16_t                v_error;        /* m */
 };
 
+#define AO_TELEMETRY_LOCATION_ALTITUDE(l)      ((l)->altitude)
+#define AO_TELEMETRY_LOCATION_SET_ALTITUDE(l,a) ((l)->altitude = (a))
+
 #define SIRF_SAT_STATE_ACQUIRED                        (1 << 0)
 #define SIRF_SAT_STATE_CARRIER_PHASE_VALID     (1 << 1)
 #define SIRF_SAT_BIT_SYNC_COMPLETE             (1 << 2)
@@ -433,7 +436,7 @@ ao_dump_state(void *wchan)
 
        if (wchan != &ao_gps_new)
                return;
-       
+
        if (ao_gps_new & AO_GPS_NEW_DATA) {
                ao_gps_print(&ao_gps_data);
                putchar('\n');
index 1b590d5e972a5fff6bce45cf37f069c7f9a492ad..5eb7118d260bdf44e51488f55f23569c5f0d10d6 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #define AO_GPS_TEST
+#define HAS_GPS 1
 #include "ao_host.h"
 #include <termios.h>
 #include <errno.h>
@@ -53,6 +54,9 @@ struct ao_gps_orig {
        uint16_t                v_error;        /* m */
 };
 
+#define AO_TELEMETRY_LOCATION_ALTITUDE(l)      ((l)->altitude)
+#define AO_TELEMETRY_LOCATION_SET_ALTITUDE(l,a) ((l)->altitude = (a))
+
 #define SIRF_SAT_STATE_ACQUIRED                        (1 << 0)
 #define SIRF_SAT_STATE_CARRIER_PHASE_VALID     (1 << 1)
 #define SIRF_SAT_BIT_SYNC_COMPLETE             (1 << 2)
index 4eb4b837d6db7951b947041720f2cba742c62a7f..5ea205d66792fd1e6ce4391cb516a24e6d764859 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #define AO_GPS_TEST
+#define HAS_GPS        1
 #include "ao_host.h"
 #include <termios.h>
 #include <errno.h>
@@ -44,7 +45,7 @@ struct ao_telemetry_location {
        uint8_t                 flags;
        int32_t                 latitude;       /* degrees * 10⁷ */
        int32_t                 longitude;      /* degrees * 10⁷ */
-       int16_t                 altitude;       /* m */
+       int16_t                 altitude_low;   /* m */
        uint16_t                ground_speed;   /* cm/s */
        uint8_t                 course;         /* degrees / 2 */
        uint8_t                 pdop;           /* * 5 */
@@ -53,8 +54,14 @@ struct ao_telemetry_location {
        int16_t                 climb_rate;     /* cm/s */
        uint16_t                h_error;        /* m */
        uint16_t                v_error;        /* m */
+       int16_t                 altitude_high;  /* m */
 };
 
+typedef int32_t                gps_alt_t;
+#define AO_TELEMETRY_LOCATION_ALTITUDE(l)      (((gps_alt_t) (l)->altitude_high << 16) | ((l)->altitude_low))
+#define AO_TELEMETRY_LOCATION_SET_ALTITUDE(l,a) (((l)->altitude_high = (a) >> 16), \
+                                                ((l)->altitude_low = (a)))
+
 #define UBLOX_SAT_STATE_ACQUIRED               (1 << 0)
 #define UBLOX_SAT_STATE_CARRIER_PHASE_VALID    (1 << 1)
 #define UBLOX_SAT_BIT_SYNC_COMPLETE            (1 << 2)