diff --git a/src/rcv/novatel.c b/src/rcv/novatel.c
index 8dc2027404132c438479e82248687f278d9e38bb..1df540310fd43faf8402fab8d7bfe88665197d14 100644
--- a/src/rcv/novatel.c
+++ b/src/rcv/novatel.c
@@ -10,6 +10,7 @@
 *     [3] NovAtel, OM-20000129 Rev2 OEM6 Family Firmware Reference Manual, 2011
 *     [4] NovAtel, OM-20000127 Rev1 OEMStar Firmware Reference Manual, 2009
 *     [5] NovAtel, OM-20000129 Rev6 OEM6 Family Firmware Reference Manual, 2014
+*     [6] Novatel, OM-20000169 Rev15A OEM7 Commands and Logs Reference Manual, 2020
 *
 * version : $Revision: 1.2 $ $Date: 2008/07/14 00:05:05 $
 * history : 2007/10/08 1.0 new
@@ -55,37 +56,39 @@
 *                           output L2W instead of L2D for L2Pcodeless
 *                           test toc difference to output beidou ephemeris
 *           2019/05/10 1.17 save galileo E5b data to obs index 2
+*           2020/05/11 1.18 add OEM7 messages
 *-----------------------------------------------------------------------------*/
 #include "rtklib.h"
 
-#define OEM4SYNC1   0xAA        /* oem4 message start sync code 1 */
-#define OEM4SYNC2   0x44        /* oem4 message start sync code 2 */
-#define OEM4SYNC3   0x12        /* oem4 message start sync code 3 */
+#define OEM4SYNC1   0xAA         /* oem4 message start sync code 1 */
+#define OEM4SYNC2   0x44         /* oem4 message start sync code 2 */
+#define OEM4SYNC3   0x12         /* oem4 message start sync code 3 */
 
-#define OEM4HLEN    28          /* oem4 message header length (bytes) */
+#define OEM4HLEN    28           /* oem4 message header length (bytes) */
 
-#define ID_ALMANAC  73          /* message id: oem4 decoded almanac */
-#define ID_GLOALMANAC 718       /* message id: oem4 glonass decoded almanac */
-#define ID_GLOEPHEMERIS 723     /* message id: oem4 glonass ephemeris */
-#define ID_IONUTC   8           /* message id: oem4 iono and utc data */
-#define ID_RANGE    43          /* message id: oem4 range measurement */
-#define ID_RANGECMP 140         /* message id: oem4 range compressed */
-#define ID_RAWALM   74          /* message id: oem4 raw almanac */
-#define ID_RAWEPHEM 41          /* message id: oem4 raw ephemeris */
-#define ID_RAWWAASFRAME 287     /* message id: oem4 raw waas frame */
-
-#define ID_QZSSIONUTC 1347      /* message id: oem6 qzss ion/utc parameters */
-#define ID_QZSSRAWEPHEM 1330    /* message id: oem6 qzss raw ephemeris */
-#define ID_QZSSRAWSUBFRAME 1331 /* message id: oem6 qzss raw subframe */
-#define ID_RAWSBASFRAME 973     /* message id: oem6 raw sbas frame */
-#define ID_GALEPHEMERIS 1122    /* message id: oem6 decoded galileo ephemeris */
-#define ID_GALALMANAC 1120      /* message id: oem6 decoded galileo almanac */
-#define ID_GALCLOCK 1121        /* message id: oem6 galileo clockinformation */
-#define ID_GALIONO  1127        /* message id: oem6 decoded galileo iono corrections */
-#define ID_GALFNAVRAWPAGE 1413  /* message id: oem6 raw galileo f/nav paga data */
-#define ID_GALINAVRAWWORD 1414  /* message id: oem6 raw galileo i/nav word data */
-#define ID_RAWCNAVFRAME 1066    /* message id: oem6 raw cnav frame data */
-#define ID_BDSEPHEMERIS 1696    /* message id: oem6 decoded bds ephemeris */
+#define ID_ALMANAC  73           /* message id: oem4 decoded almanac */
+#define ID_GLOALMANAC 718        /* message id: oem4 glonass decoded almanac */
+#define ID_GLOEPHEMERIS 723      /* message id: oem4 glonass ephemeris */
+#define ID_IONUTC   8            /* message id: oem4 iono and utc data */
+#define ID_RANGE    43           /* message id: oem4 range measurement */
+#define ID_RANGECMP 140          /* message id: oem4 range compressed */
+#define ID_RAWALM   74           /* message id: oem4 raw almanac */
+#define ID_RAWEPHEM 41           /* message id: oem4 raw ephemeris */
+#define ID_RAWWAASFRAME 287      /* message id: oem4 raw waas frame */
+#define ID_QZSSIONUTC 1347       /* message id: oem6 qzss ion/utc parameters */
+#define ID_QZSSRAWEPHEM 1330     /* message id: oem6 qzss raw ephemeris */
+#define ID_QZSSRAWSUBFRAME 1331  /* message id: oem6 qzss raw subframe */
+#define ID_RAWSBASFRAME 973      /* message id: oem6 raw sbas frame */
+#define ID_GALEPHEMERIS 1122     /* message id: oem6 decoded galileo ephemeris */
+#define ID_GALINAVEPHEMERIS 1309 /* message id: oem7 decoded galileo inav ephemeris */
+#define ID_GALFNAVEPHEMERIS 1310 /* message id: oem7 decoded galileo fnav ephemeris */
+#define ID_GALALMANAC 1120       /* message id: oem6 decoded galileo almanac */
+#define ID_GALCLOCK 1121         /* message id: oem6 galileo clockinformation */
+#define ID_GALIONO  1127         /* message id: oem6 decoded galileo iono corrections */
+#define ID_GALFNAVRAWPAGE 1413   /* message id: oem6 raw galileo f/nav paga data */
+#define ID_GALINAVRAWWORD 1414   /* message id: oem6 raw galileo i/nav word data */
+#define ID_RAWCNAVFRAME 1066     /* message id: oem6 raw cnav frame data */
+#define ID_BDSEPHEMERIS 1696     /* message id: oem6 decoded bds ephemeris */
 
 #define WL1         0.1902936727984
 #define WL2         0.2442102134246
@@ -787,6 +790,168 @@ static int decode_galephemerisb(raw_t *raw)
     raw->ephsat=eph.sat;
     return 2;
 }
+/* decode INAV galephemerisb ------------------------------------------------------*/
+static int decode_galinavephemerisb(raw_t *raw)
+{
+    eph_t eph={0};
+    unsigned char *p=raw->buff+OEM4HLEN;
+    double tow,sqrtA,tt;
+    char *msg;
+    int prn,svh_e1b,svh_e5b,dvs_e1b,dvs_e5b;
+    int toc_inav,week;
+    
+    trace(3,"decode_galephemerisb: len=%d\n",raw->len);
+    
+    if (raw->len<OEM4HLEN+220) {
+        trace(2,"oem7 galinavephemrisb length error: len=%d\n",raw->len);
+        return -1;
+    }
+    prn       =U4(p);   p+=4;
+    svh_e5b   =U1(p)&3; p+=1;
+    dvs_e5b   =U1(p)&1; p+=1+1+1;
+    svh_e1b   =U1(p)&3; p+=1;
+    dvs_e1b   =U1(p)&1; p+=1+1+1;
+    eph.iode  =U2(p);   p+=2;   /* IODNav */
+    eph.sva   =U1(p);   p+=1; /* SISA index */
+    // inav source
+    p+=1;
+    //
+    eph.toes  =U4(p);   p+=4;
+    toc_inav  =U4(p);   p+=4;
+    eph.M0    =R8(p);   p+=8;
+    eph.deln  =R8(p);   p+=8;
+    eph.e     =R8(p);   p+=8;
+    sqrtA     =R8(p);   p+=8;
+    eph.i0    =R8(p);   p+=8;
+    eph.idot  =R8(p);   p+=8;
+    eph.OMG0  =R8(p);   p+=8;
+    eph.omg   =R8(p);   p+=8;
+    eph.OMGd  =R8(p);   p+=8;
+    eph.cuc   =R8(p);   p+=8;
+    eph.cus   =R8(p);   p+=8;
+    eph.crc   =R8(p);   p+=8;
+    eph.crs   =R8(p);   p+=8;
+    eph.cic   =R8(p);   p+=8;
+    eph.cis   =R8(p);   p+=8;
+    eph.f0    =R8(p);   p+=8;
+    eph.f1    =R8(p);   p+=8;
+    eph.f2    =R8(p);   p+=8;
+    eph.tgd[0]=R8(p);   p+=8; /* BGD: E5A-E1 (s) */
+    eph.tgd[1]=R8(p);         /* BGD: E5B-E1 (s) */
+
+    eph.iodc  =eph.iode;
+    eph.svh   =(svh_e5b<<7)|(dvs_e5b<<6)|(svh_e1b<<1)|dvs_e1b;    
+    eph.A     =sqrtA*sqrtA;
+    
+    /* set data source defined in rinex 3.03 */
+    eph.code=((1<<0)|(1<<9));
+    
+    if (raw->outtype) {
+        msg=raw->msgtype+strlen(raw->msgtype);
+        sprintf(msg," prn=%3d iod=%3d toes=%6.0f",prn,eph.iode,eph.toes);
+    }
+    if (!(eph.sat=satno(SYS_GAL,prn))) {
+        trace(2,"oem7 galinavephemeris satellite error: prn=%d\n",prn);
+        return -1;
+    }
+    tow=time2gpst(raw->time,&week);
+    eph.week=week; /* gps-week = gal-week */
+    eph.toe=gpst2time(eph.week,eph.toes);
+    
+    /* for week-handover problem */
+    tt=timediff(eph.toe,raw->time);
+    if      (tt<-302400.0) eph.week++;
+    else if (tt> 302400.0) eph.week--;
+    eph.toe=gpst2time(eph.week,eph.toes);
+    eph.toc=adjweek(eph.toe,toc_inav);
+    eph.ttr=adjweek(eph.toe,tow);
+    
+    if (!strstr(raw->opt,"-EPHALL")) {
+        if (raw->nav.eph[eph.sat-1].iode==eph.iode&&
+            raw->nav.eph[eph.sat-1].code==eph.code) return 0; /* unchanged */
+    }
+    raw->nav.eph[eph.sat-1]=eph;
+    raw->ephsat=eph.sat;
+    return 2;
+}
+/* decode FNAV galephemerisb ------------------------------------------------------*/
+static int decode_galfnavephemerisb(raw_t *raw)
+{
+    eph_t eph={0};
+    unsigned char *p=raw->buff+OEM4HLEN;
+    double tow,sqrtA,tt;
+    char *msg;
+    int prn,svh_e5a,dvs_e5a;
+    int toc_fnav,week;
+    
+    trace(3,"decode_galfnavephemerisb: len=%d\n",raw->len);
+    
+    if (raw->len<OEM4HLEN+220) {
+        trace(2,"oem7 galephemrisb length error: len=%d\n",raw->len);
+        return -1;
+    }
+    prn       =U4(p);   p+=4;
+    svh_e5a   =U1(p)&3; p+=1;
+    dvs_e5a   =U1(p)&1; p+=1+1+1;
+    eph.iode  =U2(p);   p+=2;   /* IODNav */
+    eph.sva   =U1(p);   p+=1+1; /* SISA index */
+    eph.toes  =U4(p);   p+=4;
+    toc_fnav  =U4(p);   p+=4;
+    eph.M0    =R8(p);   p+=8;
+    eph.deln  =R8(p);   p+=8;
+    eph.e     =R8(p);   p+=8;
+    sqrtA     =R8(p);   p+=8;
+    eph.i0    =R8(p);   p+=8;
+    eph.idot  =R8(p);   p+=8;
+    eph.OMG0  =R8(p);   p+=8;
+    eph.omg   =R8(p);   p+=8;
+    eph.OMGd  =R8(p);   p+=8;
+    eph.cuc   =R8(p);   p+=8;
+    eph.cus   =R8(p);   p+=8;
+    eph.crc   =R8(p);   p+=8;
+    eph.crs   =R8(p);   p+=8;
+    eph.cic   =R8(p);   p+=8;
+    eph.cis   =R8(p);   p+=8;
+    eph.f0    =R8(p);   p+=8;
+    eph.f1    =R8(p);   p+=8;
+    eph.f2    =R8(p);   p+=8;
+    eph.tgd[0]=R8(p);   
+
+    eph.iodc  =eph.iode;
+    eph.svh   =(svh_e5a<<4)|(dvs_e5a<<3);    
+    eph.A     =sqrtA*sqrtA;
+    
+    /* set data source defined in rinex 3.03 */
+    eph.code=((1<<1)|(1<<8));
+    
+    if (raw->outtype) {
+        msg=raw->msgtype+strlen(raw->msgtype);
+        sprintf(msg," prn=%3d iod=%3d toes=%6.0f",prn,eph.iode,eph.toes);
+    }
+    if (!(eph.sat=satno(SYS_GAL,prn))) {
+        trace(2,"oemv galephemeris satellite error: prn=%d\n",prn);
+        return -1;
+    }
+    tow=time2gpst(raw->time,&week);
+    eph.week=week; /* gps-week = gal-week */
+    eph.toe=gpst2time(eph.week,eph.toes);
+    
+    /* for week-handover problem */
+    tt=timediff(eph.toe,raw->time);
+    if      (tt<-302400.0) eph.week++;
+    else if (tt> 302400.0) eph.week--;
+    eph.toe=gpst2time(eph.week,eph.toes);
+    eph.toc=adjweek(eph.toe,toc_fnav);
+    eph.ttr=adjweek(eph.toe,tow);
+    
+    if (!strstr(raw->opt,"-EPHALL")) {
+        if (raw->nav.eph[eph.sat-1].iode==eph.iode&&
+            raw->nav.eph[eph.sat-1].code==eph.code) return 0; /* unchanged */
+    }
+    raw->nav.eph[eph.sat-1]=eph;
+    raw->ephsat=eph.sat;
+    return 2;
+}
 /* decode galalmanacb --------------------------------------------------------*/
 static int decode_galalmanacb(raw_t *raw)
 {
@@ -1084,6 +1249,8 @@ static int decode_oem4(raw_t *raw)
         case ID_QZSSRAWSUBFRAME: return decode_qzssrawsubframeb(raw);
         case ID_QZSSIONUTC    : return decode_qzssionutcb    (raw);
         case ID_GALEPHEMERIS  : return decode_galephemerisb  (raw);
+        case ID_GALINAVEPHEMERIS  : return decode_galinavephemerisb  (raw);
+        case ID_GALFNAVEPHEMERIS  : return decode_galfnavephemerisb  (raw);
         case ID_GALALMANAC    : return decode_galalmanacb    (raw);
         case ID_GALCLOCK      : return decode_galclockb      (raw);
         case ID_GALIONO       : return decode_galionob       (raw);