JSMSolns
Published © GPL3+

Arduino TPMS Tyre Pressure Display

Project using Arduino Micro and a CC1101 to receive and display the tyre pressures transmitted by a Toyota (Auris Hybrid) and some others

IntermediateFull instructions provided3 hours60,123
Arduino TPMS Tyre Pressure Display

Things used in this project

Hardware components

Pro Micro - 3.3V/8MHz
SparkFun Pro Micro - 3.3V/8MHz
Make sure this is the 3V3 version!
×1
TI CC1101 Module (387-464MHz)
×1
0.96in I2C 128x64 Yellow & Blue OLED Display Module
×1
USB-A to Micro-USB Cable
USB-A to Micro-USB Cable
×1
Seeed Studio Seeeduino Xiao Micro Controller
Alternative to using the Pro Micro (cheaper, smaller, more memory and much faster but still 3v3 I/O)
×1
3v Piezo buzzer
Optional addition if audible alarms required for low/high pressure warnings Please ensure the current drawn by the buzzer is less than the selected processor can sink (usually <7mA). If a larger current is needed, an external drive circuit will be required.
×1
1.8in TFT SPI display 128 x 160 RGB
1.8" TFT SPI display 128 x 160 RGB as alternative to I2C display
×1

Software apps and online services

Arduino IDE
Arduino IDE
Texas Instruments TI SMART RF Studio7
Fusion
Autodesk Fusion
Used for the enclosure design
Cura
Saleae Logic Analyser Softwre
Used during development

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
For 3D printing enclosure (if required)

Story

Read more

Custom parts and enclosures

3D CAD file - ProMicro

Fusion 360 file for case for ProMicro and I2C display

TPMS_Case_Bottom - Pro Micro (STL)

TPMS_Case_Top - Pro Micro (STL)

CAD view of case bottom - Pro Micro

CAD View of Case (showing lid) - Pro Micro

3D CAD File - Seeduino Xiao + 1.8" display + PCB

Fusion 360 file for case for Seeduino Xiao and 1.8" display module
Uses PCB designed for this project

3D CAD File - Seeduino Xiao + 1.8" display + PCB (STL)

TPMS case for Seeeduino Xiao with 1.8" display and custom PCB in STL format

3D CAD File - Seeduino Xiao + 1.8" display + PCB - Case Only (STL)

3D CAD File - Seeduino Xiao + 1.8" display + PCB - Lid Only (STL)

CAD View of Seeeduino Xiao + 1.8" display

Schematics

Circuit diagram for Toyota TPMS monitor_ProMicro3v3

Schematic_Toyota_TPMS_Monitor_SeeeduinoXiao

Schematic for Seeeduino Xiao processor

Schematic TPMS using Seeeduino Xiao and 1.8" ST7735 TFT and Buzzer Alarm

Code

Common

C Header File
extern Ticker SignalRefreshTimer;
extern Ticker displayflashtimer;

#define CD_END_DELAY_TIME  2500

void PrintIDs()
{
  uint8_t i;
  Serial.print(F("Preset IDs:  "));
  for(i=0;i<TYRECOUNT;i++)
  {
    Serial.print(F(" 0x"));
    Serial.print(IDLookup[i],HEX);
    if (i == 4)
    {
      Serial.println(F(""));
      Serial.print(F("             "));
    }
    else
    {
       if (i < TYRECOUNT-1)
          Serial.print(F(","));      
    }

  }
  Serial.println(F(""));
}

double PSI_To_BAR(double Pressure_PSI)
{
   return(Pressure_PSI/PSI2BAR);
}

double PSI_To_KPA(double Pressure_PSI)
{
   return(Pressure_PSI * KPA2PSI);
}

double BAR_To_PSI(double Pressure_BAR)
{
   return(Pressure_BAR * PSI2BAR);
}

double KPA_To_PSI(double Pressure_KPA)
{
   return(Pressure_KPA/KPA2PSI);
}

float DegC_To_DegK(float DegC)
{
   return(DegC + 273.15);
}

float DegF_To_DegK(float DegF)
{
   return(DegC_To_DegK(DegF_To_DegC(DegF)));
}

float DegC_To_DegF(float DegC)
{
  return((DegC * 1.8) + 32.0);
}

float DegF_To_DegC(float DegF)
{
   return((DegF-32.0)/1.8);
}


double ConvertPressureForDisplay(double Pressure_PSI)
{
   #ifdef DISPLAY_PRESSURE_AS_BAR
      return(PSI_To_BAR(Pressure_PSI));
   #elif DISPLAY_PRESSURE_AS_KPA
      return(PSI_To_KPA(Pressure_PSI));
   #else
      return(Pressure_PSI);
   #endif
}


void ResetSignalRefreshTimer()
{
   SignalRefreshTimer.start();
}

void EdgeInterrupt()
{
  uint32_t ts = micros();
  uint32_t BitWidth;

  if (TimingsIndex == MAXTIMINGS)
  {
    return;
  }


  BitWidth = ts - LastEdgeTime_us;
 
  if (WaitingFirstEdge)
  {
    if (IsTooShort(BitWidth))
    {
      LastEdgeTime_us = ts;  //ignore short pulses at the start of the transmission
      return;
    }
    
    if (digitalRead(RXPin) == LOW)
    {
      FirstEdgeIsHighToLow = true;
    }
    else
    {
      FirstEdgeIsHighToLow = false;
    }
    WaitingFirstEdge = false;
  }

    

   
//  if (BitWidth <= 12)  //ignore glitches
//  {
//    return;
//  }
  if (BitWidth > 0xFFFF)
  {
    BitWidth = 0xFFFF;
//    Serial.print(ts);
//    Serial.print(" ");
//    Serial.println(LastEdgeTime_us);
  }

  LastEdgeTime_us = ts;
  Timings[TimingsIndex++] = (uint16_t)BitWidth;

}


bool IsTooShort(uint16_t Width)
{
  if (Width < SHORTTIMING_MIN)
  {
    return (true);
  }
  else
  {
    return (false);
  }
}

bool IsTooLong(uint16_t Width)
{
  if (Width > LONGTIMING_MAX)
  {
    return (true);
  }
  else
  {
    return (false);
  }
}




bool IsValidSync(uint16_t Width)
{
  if ((Width >= SYNCTIMING_MIN) && (Width <= SYNCTIMING_MAX))
  {
    return (true);
  }
  else
  {
    return (false);
  }
}

bool IsValidShort(uint16_t Width)
{
  if ((Width >= SHORTTIMING_MIN) && (Width <= SHORTTIMING_MAX))
  {
    return (true);
  }
  else
  {
    return (false);
  }
}


bool IsValidLong(uint16_t Width)
{
  if ((Width >= LONGTIMING_MIN) && (Width <= LONGTIMING_MAX))
  {
    return (true);
  }
  else
  {
    return (false);
  }
}

bool IsEndMarker(uint16_t Width)
{
  uint16_t UpperLimit,LowerLimit;
  UpperLimit = ENDTIMING_MAX;
  LowerLimit = ENDTIMING_MIN;
  if ((Width >= LowerLimit) && (Width <= UpperLimit))
  {
     return(true);
  }
  else
  {
    return(false);
  }
}


int16_t ValidateBit()
{
  uint16_t BitWidth = Timings[CheckIndex];

  if (IsValidLong(BitWidth))
  {
    return (BITISLONG);
  }

  if (IsValidShort(BitWidth))
  {
    return (BITISSHORT);
  }

  if (IsValidSync(BitWidth))
  {
    return (BITISSYNC);
  }


  return (-1);

}

int16_t ValidateBit(int16_t Index)
{
  uint16_t BitWidth = Timings[Index];

  if (IsValidLong(BitWidth))
  {
    return (BITISLONG);
  }

  if (IsValidShort(BitWidth))
  {
    return (BITISSHORT);
  }

  if (IsValidSync(BitWidth))
  {
    return (BITISSYNC);
  }


  return (BITISUNDEFINED);

}

uint16_t Compute_CRC16( int16_t bcount,  uint16_t Poly,  uint16_t crc_init )
{
   return(Compute_CRC16(0,  bcount, Poly,   crc_init ));
}

 uint16_t Compute_CRC16(int16_t startbyte, int16_t bcount,  uint16_t Poly,   uint16_t crc_init )
{
    uint16_t remainder = crc_init;
    byte Abit;

    int16_t c;
    int16_t index = startbyte;
    for (c = 0; c < bcount; c++,index++) 
    {
        remainder ^= (( uint16_t)RXBytes[index]) << 8;
        for (Abit = 0; Abit < 8; ++Abit) 
        {
            if (remainder & 0x8000) {
                remainder = (remainder << 1) ^ Poly;
            }
            else {
                remainder = (remainder << 1);
            }
        }
    }
    return remainder;
  
}

uint8_t Compute_CRC8( int16_t bcount, uint8_t Poly, uint8_t crc_init )
{
  uint8_t crc = crc_init;
  int16_t c;
  for (c = 0; c < bcount; c++)
  {
    uint8_t b = RXBytes[c];
    /* XOR-in next input byte */
    uint8_t data = (uint8_t)(b ^ crc);
    /* get current CRC value = remainder */
    if (Poly == 0x07)
    {
      crc = (uint8_t)(pgm_read_byte(&CRC8_Poly_07_crctable2[data]));
    }
    else
    {
      if (Poly == 0x13)
      {
        crc = (uint8_t)(pgm_read_byte(&CRC8_Poly_13_crctable2[data]));
      }
    }

  }

  return crc;
}

uint8_t Compute_CRC_XOR(int16_t StartByte, int16_t bcount, uint8_t crc_init)
{
  uint8_t crc = crc_init;
  int16_t index = StartByte;
  int16_t c;

  for (c = 0; c < bcount; c++,index++)
  {
    crc = crc ^ RXBytes[index];
  }
  
  return(crc);
}

uint8_t Compute_CRC_SUM(int16_t StartByte, int16_t bcount, uint8_t crc_init)
{
  uint8_t crc = crc_init;
  int16_t c;
  int16_t index = StartByte;

  for (c = 0; c < bcount; c++,index++)
  {
    crc = crc + RXBytes[index];
  }
  
  return(crc);
}

int16_t GetRSSI_dbm()
{
  uint8_t RSSI_Read;
  uint8_t RSSI_Offset = 74;
  int16_t ret;
  
  RSSI_Read = readStatusReg(CC1101_RSSI);
  if (RSSI_Read >= 128)
  {
    ret = (int)((int)(RSSI_Read - 256) /  2) - RSSI_Offset;
  }
  else
  {
    ret = (RSSI_Read / 2) - RSSI_Offset;
  }
  return(ret);
}

void ClearRXBuffer()
{
  int16_t i;

  for (i = 0; i < (int16_t)sizeof(RXBytes); i++)
  {
    RXBytes[i] = 0;
  }
}

int16_t ManchesterDecode_ZeroBit(int16_t StartIndex)
{
   int16_t i;
   bool bit1, bit2;
   uint8_t b = 0;
   uint8_t n = 0;

   RXByteCount = 0;
   for (i = StartIndex; i< BitCount-1;i+=2)
   {
      bit1 = IncomingBits[i];
      bit2 = IncomingBits[i+1];

      if (bit1 == bit2)
      {
      //  #ifdef SHOWDEBUGINFO
      //     Serial.print(F("Manchester decode exited at index: "));
      //     Serial.println(i + StartIndex);
      //  #endif
         if (n != 0)
         {//partial bits?
            b = b << (8 - n);
            RXBytes[RXByteCount] = b;
            RXByteCount++;            
         }
      
         return RXByteCount;
      }

    b = b << 1;
    b = b + (bit2 == true? 0:1);
    n++;
    if (n == 8)
    {
      RXBytes[RXByteCount] = b;
      RXByteCount++;
      if (RXByteCount >= (int16_t) sizeof(RXBytes))
      {
        return(RXByteCount);
      }
      n = 0;
      b = 0;
    }     
    
   }

   if (n != 0)
   {//partial bits?
      b = b << (8 - n);
      RXBytes[RXByteCount] = b;
      RXByteCount++;            
   }

   return RXByteCount;

}

int16_t ManchesterDecode(int16_t StartIndex)
{
   int16_t i, index = 0;
   bool bit1, bit2;
   uint8_t b = 0;
   uint8_t n = 0;
   

   RXByteCount = 0;
   ManchesterBitCount = 0;
   for (i = StartIndex; i< BitCount-1;i+=2)
   {
      bit1 = IncomingBits[i];
      bit2 = IncomingBits[i+1];

      if (bit1 == bit2)
      {
      //  #ifdef SHOWDEBUGINFO
      //     Serial.print(F("Manchester decode exited at index: "));
      //     Serial.println(i + StartIndex);
      //  #endif
         if (n != 0)
         {//partial bits?
            b = b << (8 - n);
            RXBytes[RXByteCount] = b;
            RXByteCount++;            
         }
         
      
         return RXByteCount;
      }

    b = b << 1;
    b = b + (bit2 == true? 1:0);
    ManchesterDecodedBits[index++] = (bit2 == true? 1:0);
    n++;
    if (n == 8)
    {
      RXBytes[RXByteCount] = b;
      RXByteCount++;
      if (RXByteCount >= (int16_t)sizeof(RXBytes))
      {
        ManchesterBitCount = index;
        return(RXByteCount);
      }
      n = 0;
      b = 0;
    }     
    
   }

   ManchesterBitCount = index;

   if (n != 0)
   {//partial bits?
      b = b << (8 - n);
      RXBytes[RXByteCount] = b;
      RXByteCount++;            
   }
         
   
   return RXByteCount;

}

int16_t DifferentialManchesterDecode(int16_t StartIndex)
{
   int16_t i;
   bool bit1, bit2, bit3;
   uint8_t b = 0;
   uint8_t n = 0;

   RXByteCount = 0;
   for (i = StartIndex; i< BitCount-1;i+=2)
   {
      bit1 = IncomingBits[i];
      bit2 = IncomingBits[i+1];
      bit3 = IncomingBits[i+2];

      if (bit1 != bit2)
      {
        if (bit2 != bit3)
        {
          b = b << 1;
          b = b + 0;
          n++;
          if (n == 8)
          {
            RXBytes[RXByteCount] = b;
            RXByteCount++;
            n = 0;
            b = 0;
          }          
        }
        else
        {
          bit2 = bit1;
          i+=1;
          break;
        }
      }
      else
      {
        bit2 = 1 - bit1;
        break;
      }
   }


   for (; i< BitCount-1;i+=2)  
   {
      bit1 = IncomingBits[i];

      if (bit1 == bit2)
         return RXByteCount;
      bit2 = IncomingBits[i+1];

      b = b << 1;
      b = b + (bit1 == bit2? 1:0);
      n++;
      if (n == 8)
      {
        RXBytes[RXByteCount] = b;
        RXByteCount++;
        n = 0;
        b = 0;
      } 

     
   }
    
   return RXByteCount;

}

void InvertBitBuffer()
{
   int16_t i;

   for (i = 0;i < BitCount;i++)
   {
      IncomingBits[i] = !IncomingBits[i];
   }
  
}

static inline uint8_t bit_at(const uint8_t *bytes, uint16_t bit)

{
    return (uint8_t)(bytes[bit >> 3] >> (7 - (bit & 7)) & 1);
}

int16_t FindManchesterStart(const uint8_t *pattern,int16_t pattern_bits_len )
{


   int16_t ipos = 0;
   int16_t ppos = 0; // cursor on init pattern

   if (BitCount < pattern_bits_len) 
      return -1;

    while ((ipos < BitCount-3) && (ppos < pattern_bits_len)) 
    {
        if (IncomingBits[ipos] == bit_at(pattern, ppos)) 
        {
            ppos++;
            ipos++;
            if (ppos == pattern_bits_len)
                return ipos;
        }
        else 
        {
            ipos -= ppos;
            ipos++;
            ppos = 0;
        }
    }

    // Not found
    return -1;
 
}

void InitDataBuffer()
{
  BitIndex = 0;
  BitCount = 0;
  ValidBlock = false;
  //WaitingTrailingZeroEdge = false;
  WaitingFirstEdge  = true;
  CheckIndex = 0;
  TimingsIndex = 0;
  SyncFound = false;
  //digitalWrite(DEBUGPIN, LOW);

}


void ClearTPMSData(int16_t i)
{
  if (i > TYRECOUNT)
    return;

  TPMS[i].TPMS_ID = 0;
  TPMS[i].lastupdated = 0;
  #ifdef DISPLAY_PRESSURE_AS_BAR
     TPMS[i].TPMS_LowPressureLimit = BAR_To_PSI(PressureLowLimits[i]);
     TPMS[i].TPMS_HighPressureLimit = BAR_To_PSI(PressureHighLimits[i]);
  #elif DISPLAY_PRESSURE_AS_KPA
     TPMS[i].TPMS_LowPressureLimit = KPA_To_PSI(PressureLowLimits[i]);
     TPMS[i].TPMS_HighPressureLimit = KPA_To_PSI(PressureHighLimits[i]);
  #else
     TPMS[i].TPMS_LowPressureLimit = PressureLowLimits[i];
     TPMS[i].TPMS_HighPressureLimit = PressureHighLimits[i];
  #endif



  #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
     TPMS[i].TPMS_LowTemperatureLimit = DegF_To_DegC(TemperatureLowLimits[i]);
     TPMS[i].TPMS_HighTemperatureLimit = DegF_To_DegC(TemperatureHighLimits[i]);  
  #else
     TPMS[i].TPMS_LowTemperatureLimit = TemperatureLowLimits[i];
     TPMS[i].TPMS_HighTemperatureLimit = TemperatureHighLimits[i];
  #endif
  
  TPMS[i].LowPressure = false;
  TPMS[i].HighPressure = false;
  TPMS[i].LowTemperature = false;
  TPMS[i].HighTemperature = false;
  TPMS[i].AudibleAlarmActive = false;
  #ifdef USE_LCDDISPLAY
     if (i < 4)
        ClearDisplayBlock(i);
  #endif
}

void PulseDebugPin(int16_t width_us)
{
  digitalWrite(DEBUGPIN, HIGH);
  delayMicroseconds(width_us);
  digitalWrite(DEBUGPIN, LOW);
}

void UpdateFreqOffset()
{
    FreqOffsetAcc = FreqOffsetAcc + readStatusReg(CC1101_FREQEST);
    writeReg(CC1101_FSCTRL0, FreqOffsetAcc);
    
}



int16_t GetPreferredIndex(uint32_t ID)
{
  int16_t i;

  //for (i = 0; i  < (sizeof(IDLookup) / sizeof(IDLookup[0])); i++)
  for (i = 0; i  < TYRECOUNT; i++)
  {
    if (IDLookup[i] == ID)
    {
      return (i);
    }

  }
  return (-1);
}

int16_t GetDisplayIndexFromID(uint32_t ID)
{
  //return the location on the screen where the ID should be displayed (0-3)
  int16_t tmp;
  tmp = GetPreferredIndex(ID) % 5;

  if ((tmp < 0) || (tmp > 3))
  {
     return(-1);
  }
    
  return(tmp);
}

int16_t GetDisplayIndexFromTyreIndex(int16_t i)
{
   //convert tyre index to screen position, so 0->0,, 1->1, 2->2, 3->3, 4->-1(spare not displayed),Winter tyres: 5->0, 6->1, 7->2, 8->3, 9->-1(spare not displayed)
  int16_t tmp;
  tmp = i % 5;
  if ((tmp < 0) || (tmp > 3))
  {
     return(-1);
  }
  return(tmp);
}

void GetPreferredIndexStr(uint32_t ID, char* sptr)
{
  int16_t tmp;
  tmp = GetPreferredIndex(ID);

  switch (tmp % 5)
  {
    case 0:
       strcpy(sptr, "FL");
       break;
    case 1:
       strcpy(sptr, "FR");
       break;
    case 2:
       strcpy(sptr, "RL");
       break; 
    case 3:
       strcpy(sptr, "RR");
       break;
    case 4:
       strcpy(sptr, "SP");
       break;
    default:
       sptr[0] = '\0';
       break;
    
  }
}

void PrintTimings(uint8_t StartPoint, uint16_t Count)
{
  uint16_t i;
  char c[10];
  for (i = 0; i < Count; i++)
  {
    if ((StartPoint == 0) && (i == (uint16_t)StartDataIndex))
         Serial.println();
    sprintf(c, "%3d,",Timings[StartPoint + i]);
    Serial.print(c);
    //Serial.print(Timings[StartPoint + i]);
    //Serial.print(F(","));
  }
  Serial.println(F(""));
  //    for (i = 0;i<Count;i++)
  //    {
  //          Serial.print(BitTimings[StartPoint + i]);
  //          Serial.print(",");
  //    }
  //    Serial.println("");


}

void PrintManchesterData(int16_t StartPos, uint16_t Count, bool ShowHex)
{

  uint16_t i, c;
  uint8_t hexdata = 0;
  for (i = StartPos, c = 1; c <= Count; i++, c++)
  {
    Serial.print(ManchesterDecodedBits[i]);
    if (ShowHex)
    {
      hexdata = (hexdata << 1) + ManchesterDecodedBits[i];
      if (c % 8 == 0)
      {
        Serial.print(F(" ["));
        Serial.print(hexdata, HEX);
        Serial.print(F("] "));
        hexdata = 0;
      }
    }
  }
  Serial.println(F("")); 
}

void PrintData(int16_t StartPos, uint16_t Count, bool ShowHex)
{

  uint16_t i, c;
  uint8_t hexdata = 0;
  for (i = StartPos, c = 1; c <= Count; i++, c++)
  {
    Serial.print(IncomingBits[i]);
    if (ShowHex)
    {
      hexdata = (hexdata << 1) + IncomingBits[i];
      if (c % 8 == 0)
      {
        Serial.print(F(" ["));
        Serial.print(hexdata, HEX);
        Serial.print(F("] "));
        hexdata = 0;
      }
    }
  }
  Serial.println(F(""));
}

void PrintData(int16_t StartPos, uint16_t Count)
{

   PrintData(StartPos, Count, true);
}

void PrintData(uint16_t Count)
{
   PrintData(0,Count, true);
//  uint16_t i;
//  byte hexdata;
//  for (i = 0; i < Count; i++)
//  {
//    Serial.print(IncomingBits[i]);
//    hexdata = (hexdata << 1) + IncomingBits[i];
//    if ((i + 1) % 8 == 0)
//    {
//      Serial.print(F(" ["));
//      Serial.print(hexdata, HEX);
//      Serial.print(F("] "));
//      hexdata = 0;
//    }
//  }
//  Serial.println(F(""));
}



void PrintBytes(uint16_t Count)
{
  uint16_t i;

  for (i = 0; i < Count; i++)
  {
    Serial.print(F(" ["));
    Serial.print(RXBytes[i],HEX);
    Serial.print(F("] "));
  }
  Serial.println(F(""));

}
void InitTPMS()
{
  int16_t i;

  for (i = 0; i < TYRECOUNT; i++)
  {
    ClearTPMSData(i);
  }
  #ifdef USE_LCDDISPLAY 
     UpdateDisplay();
     SignalRefreshNeeded = false;
  #endif

}

double GetTempCompensatedPressureLimit(double LimitsPressure, float LimitsTemperature_DegC, float CurrentTemperature_DegC)
{
   return((CurrentTemperature_DegC + DEGC_TO_KELVIN) * (LimitsPressure / (LimitsTemperature_DegC + DEGC_TO_KELVIN)));  // T2 * (P1/T1)
}

bool PressureBelowLowPressureLimit(int16_t TyreIndex)
{
  bool ret = false;

  double RoundedPressure = round(TPMS[TyreIndex].TPMS_Pressure * 10)/10.0;
  float LowLimit = TPMS[TyreIndex].TPMS_LowPressureLimit;
  float Temperature = TPMS[TyreIndex].TPMS_Temperature;
  
  #ifdef ENABLE_PRESSURE_ALARM_TEMPERATURE_COMPENSATION
     if (Temperature != NO_VALID_TEMPERATURE)
     {
       LowLimit = GetTempCompensatedPressureLimit(LowLimit, PressureLimitsTemperature,Temperature);   //adjust the limit based on the current temperatue and the temperature defined for the limits setting T2 * (P1/T1)
       LowLimit = round(LowLimit * 10)/10.0;
     }
  #endif

  if (RoundedPressure < LowLimit)
  {
       ret = true;
  }

  return(ret);
  
}

bool PressureAboveHighPressureLimit(int16_t TyreIndex)
{
  bool ret = false;

  double RoundedPressure = round(TPMS[TyreIndex].TPMS_Pressure * 10)/10.0;
  float HighLimit = TPMS[TyreIndex].TPMS_HighPressureLimit;
  float Temperature = TPMS[TyreIndex].TPMS_Temperature;
  
  #ifdef ENABLE_PRESSURE_ALARM_TEMPERATURE_COMPENSATION
     if (Temperature != NO_VALID_TEMPERATURE)
     {     
       HighLimit = GetTempCompensatedPressureLimit(HighLimit, PressureLimitsTemperature,Temperature);   //adjust the limit based on the current temperatue and the temperature defined for the limits setting T2 * (P1/T1)
       HighLimit = round(HighLimit * 10)/10.0;
     }
  #endif

  if (RoundedPressure > HighLimit)
  {
       ret = true;
  }

  return(ret);
  
}

bool TemperatureBelowLowTemperatureLimit(int16_t TyreIndex)
{
  bool ret = false;

  float LowLimit = TPMS[TyreIndex].TPMS_LowTemperatureLimit;
  float Temperature = round(TPMS[TyreIndex].TPMS_Temperature * 10)/10.0;

  if (Temperature == NO_VALID_TEMPERATURE)
  {
    ret = false;
  }
  else
  {
    if (Temperature < LowLimit)
    {
         ret = true;
    }    
  }
  return(ret);
  
}

bool TemperatureAboveHighTemperatureLimit(int16_t TyreIndex)
{
  bool ret = false;

  float HighLimit = TPMS[TyreIndex].TPMS_HighTemperatureLimit;
  float Temperature = round(TPMS[TyreIndex].TPMS_Temperature * 10)/10.0;
  

  if (Temperature == NO_VALID_TEMPERATURE)
  {
    ret = false;
  }
  else
  {
    if (Temperature > HighLimit)
    {
         ret = true;
    }    
  }
  return(ret);
  
}

void UpdateTPMSData(int16_t index, uint32_t ID, uint16_t status, float Temperature, double Pressure)
{

  if (index >= TYRECOUNT)
    return;

  TPMS[index].TPMS_ID = ID;
  TPMS[index].TPMS_Status = status;
  TPMS[index].lastupdated = millis();
  TPMS[index].TPMS_Temperature = Temperature;
  TPMS[index].TPMS_Pressure = Pressure;


...

This file has been truncated, please download it to see its full contents.

display

C Header File
//#define USE_ADAFRUIT 1
#define USE_TEXTONLY 1


extern void ResetSignalRefreshTimer();

#ifndef USE_ADAFRUIT

   #include "SSD1306Ascii.h"
   #include "SSD1306AsciiWire.h"

   SSD1306AsciiWire display;



  void ShowTitle()
  {
    //display.clear();
  
    display.set1X();             // Normal 1:1 pixel scale
    //display.setTextColor(WHITE, BLACK);       // Draw white text
  
    display.setCursor(0, 0);
    #ifdef NissanLeaf
       display.println(F("Nissan Leaf TPMS"));
    #elif Dacia
       display.println(F("Dacia TPMS"));
    #elif Renault
       #ifdef Zoe
          display.println(F("Ren Zoe(early) TPMS"));
       #else
          display.println(F("Renault TPMS"));
       #endif
    #elif Citroen
       display.println(F("Citroen TPMS"));
    #elif Jansite
       display.println(F("Jansite TPMS"));
    #elif JansiteSolar
       display.println(F("JSolar TPMS"));
    #elif Ford
       display.println(F("Ford TPMS"));
    #elif PontiacG82009
       display.println("Pontiac G8 TPMS");
    #elif Hyundai_i35
       display.println(F("Hyundai i35"));
    #elif Schrader_C1100
       display.println(F("Hyundai Tucson"));
    #elif Schrader_A9054100
       display.println(F("Smart ForTwo TPMS")); 
    #elif Subaru
       display.println(F("Subaru TPMS"));  
    #else
       display.println(F("Toyota TPMS"));
    #endif
    display.print(F(" JSM Solutions "));
    display.print(VERSION);
    //display.println(")");
  
  
  }

  char DisplayTimeoutBar(uint32_t TimeSinceLastUpdate)
  {
      int16_t HowCloseToTimeout;
      HowCloseToTimeout = (int16_t)(TimeSinceLastUpdate/(TPMS_TIMEOUT/5));

      switch(HowCloseToTimeout)
      {
        case 0: 
           //return(FONTBAR_7);
           return('5');
           break;
        case 1: 
           //return(FONTBAR_5);
           return('4');
           break;
        case 2: 
           //return(FONTBAR_3);
           return('3');
           break;
        case 3: 
           //return(FONTBAR_2);
           return('2');
           break;
        case 4: 
           //return(FONTBAR_1);
           return('1');
           break;
        default: 
           //return(FONTBAR_0);
           return('0');
           break;
                      
      }
  }


  int16_t GetBlockStartX(int16_t DisplayIndex)
  {
  

      switch (DisplayIndex)
      {
        case 0:
          return(0);
          break;
        case 1:
          return(59);
          break;
        case 2:
          return(0);
          break;
        case 3:
          return(59);
          break;
      }
      return (0);
  }

  
  int16_t GetBlockStartY(int16_t DisplayIndex)
  {
  

      switch (DisplayIndex)
      {
        case 0:
          return(2);
          break;
        case 1:
          return(2);
          break;
        case 2:
          return(5);
          break;
        case 3:
          return(5);
          break;
          
      }
     return (0);
  }

  void ClearDisplayBlock(int16_t DisplayIndex)
  {
     int16_t x,y;

     x = GetBlockStartX(DisplayIndex);
     y = GetBlockStartY(DisplayIndex);

     display.setFont(Adafruit5x7);
     display.set2X();
     display.clearField(x,y,4);
     display.set1X();
     display.clearField(x,y+2,8);
     
  }




  void UpdateBlock(int16_t DisplayIndex,int16_t i)
  {
        int16_t x,y;
        char s[20];
        char t;

        if ((TPMS[i].LowPressure == true) || (TPMS[i].HighPressure == true))
        {
          if (DisplayFlash)
          {
             strcpy(s,"    ");
          }
          else
          {
             #ifdef DISPLAY_PRESSURE_AS_BAR
                dtostrf(PSI_To_BAR(TPMS[i].TPMS_Pressure), 4, 2, s);
             #elif DISPLAY_PRESSURE_AS_KPA
                dtostrf(PSI_To_KPA(TPMS[i].TPMS_Pressure), 3, 0, s);  //rounded to integer value
             #else
                dtostrf(TPMS[i].TPMS_Pressure, 3, 1, s);
             #endif
          }
        }
        else
        {
           #ifdef DISPLAY_PRESSURE_AS_BAR
              dtostrf(PSI_To_BAR(TPMS[i].TPMS_Pressure), 4, 2, s);
           #elif DISPLAY_PRESSURE_AS_KPA
              dtostrf(PSI_To_KPA(TPMS[i].TPMS_Pressure), 3, 0, s);  //rounded to integer value
           #else
              dtostrf(TPMS[i].TPMS_Pressure, 3, 1, s);
           #endif
        }

        
        x = GetBlockStartX(DisplayIndex);
        y = GetBlockStartY(DisplayIndex);
        display.setCursor(x, y);
        
        //sprintf(temperature,"%s F", str_temp);
        //sprintf(s,"%.1f",TPMS[i].TPMS_Pressure);
        //display.invertDisplay(InvertMode);
        display.setFont(Adafruit5x7);
        display.set2X();
        //display.clearField(x,y,4);
        display.print(s);


        display.setCursor(x, y+2);
        display.setFont(Adafruit5x7);
        display.set1X();
        //display.clearField(x,y+2,8);


        #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
           t = 'F';
        #else
           t = 'C';
        #endif

        if (TPMS[i].TPMS_Temperature == NO_VALID_TEMPERATURE)
        {
           display.print("  ---  ");
        }
        else
        {
  
          if ((TPMS[i].LowTemperature == true) || (TPMS[i].HighTemperature == true))
          {
            if (DisplayFlash)
            {
               strcpy(s,"       ");
               display.print(s); 
            }
            else
            {
               #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
                  dtostrf(DegC_To_DegF(TPMS[i].TPMS_Temperature), 2, 0, s);
               #else
                  dtostrf(TPMS[i].TPMS_Temperature, 2, 0, s);
               #endif
                display.print(" ");
                display.print(s);
                display.setFont(System5x7);
                display.print(char(128));  //degrees symbol
                display.setFont(Adafruit5x7);
               display.print(t);
               display.print("  ");
            }
          }
          else
          {
               #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
                  dtostrf(DegC_To_DegF(TPMS[i].TPMS_Temperature), 2, 0, s);
               #else
                  dtostrf(TPMS[i].TPMS_Temperature, 2, 0, s);
               #endif
                display.print(" ");
                display.print(s);
                display.setFont(System5x7);
                display.print(char(128));  //degrees symbol
                display.setFont(Adafruit5x7);
               display.print(t);
               display.print("  ");
          }
        }




        
        //dtostrf(TPMS[i].TPMS_Temperature, 2, 0, s);
//        display.print(" ");
//        display.print(s);
//        display.setFont(System5x7);
//        display.print(char(128));  //degrees symbol
//        display.setFont(Adafruit5x7);
//        #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
//           display.print("F");
//        #else
//           display.print("C");
//        #endif
//        display.print("  ");

        //display vertical bar showing how long since last update 7 bars = recent 1 bar = nearing timeout (at timeout it will be removed from display altogether)
        display.setFont(System5x7);          
        display.print(DisplayTimeoutBar(millis() - TPMS[i].lastupdated));
  }
 
  void UpdateDisplay()
  {
    int16_t i;

  
    int16_t DisplayIndex;
  

    //for (i = 0; i < 4; i++)
    for (i = 0; i < TYRECOUNT; i++) 
    {
      
      if (TPMS[i].TPMS_ID != 0)
      {
         //Only update the areas which need it to keep the timing overheads down
         DisplayIndex = GetDisplayIndexFromTyreIndex(i);

         if (DisplayIndex >= 0)
         {
           UpdateBlock(DisplayIndex,i);
           if ((bitRead(TPMSChangeBits,i) == 1))
           {
              bitClear(TPMSChangeBits,i);
           }
         }

      }


    }    
  
  }

#else
   #include <Adafruit_GFX.h>
   #include <Adafruit_SSD1306.h>


   #define SCREEN_WIDTH 128 // OLED display width, in pixels
   #define SCREEN_HEIGHT 64 // OLED display height, in pixels
   Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,  &Wire, -1);


  void ShowTitle()
  {
    display.clearDisplay();
    display.setFont(Adafruit5x7);
    display.setTextSize(1);             // Normal 1:1 pixel scale
    display.setTextColor(WHITE, BLACK);       // Draw white text
  
    display.setCursor(0, 0);
    #ifdef NissanLeaf
       display.println("Nissan Leaf TPMS");
    #elif Dacia
       display.println("Dacia TPMS");
    #elif Renault
       display.println("Renault TPMS");
    #elif Citroen
       display.println("Citroen TPMS");
    #elif Jansite
       display.println("Jansite TPMS");
    #elif JansiteSolar
       display.println("JSolar TPMS");
    #elif Ford
       display.println("Ford TPMS");
    #elif PontiacG82009
       display.println("Pontiac G8 TPMS");
    #elif Hyundai_i35
       display.println(F("Hyundai i35"));
    #elif Schrader_C1100
       display.println(F("Hyundai Tucson"));
    #elif Schrader_A9054100
       display.println(F("Smart ForTwo TPMS")); 
    #elif Subaru
       display.println(F("Subaru TPMS"));   
    #else
       display.println("Toyota TPMS");
    #endif
    
    display.print(" JSM Solutions ");
    display.print(VERSION);
    //display.println(")");
  
  
  }
  
  void UpdateDisplay()
  {
    int16_t i;
    int16_t x = 0;
    int16_t y = 0;
    char s[6];
 
  
  
    ShowTitle();
    
    display.setFont(Adafruit5x7);
    display.setTextSize(2);
  
    for (i = 0; i < 4; i++)
    {
     
      switch (i)
      {
        case 0:
          x = 0;
          y = 16;
          break;
        case 1:
          x = 64;
          y = 16;
          break;
        case 2:
          x = 0;
          y = 48;
          break;
        case 3:
          x = 64;
          y = 48;
          break;
      }
  
  
      display.setCursor(x, y);
  
      if (TPMS[i].TPMS_ID != 0)
      {
        dtostrf(TPMS[i].TPMS_Pressure, 3, 1, s);
        //sprintf(temperature,"%s F", str_temp);
        //sprintf(s,"%.1f",TPMS[i].TPMS_Pressure);
        display.print(s);
      }
    }
    display.display();

  
  }
   


#endif

globals

C Header File
#define USE_HW_CD 1
//#define USE_TEST_TIMINGS 1



#define SHOWVALIDTPMS 1
#define SHOWDEBUGINFO 1
//#define IGNORECHECKSUMERRORS 1
#define ALWAYSSHOWTIMINGS 1
//#define SPECIFIC_IDS_ONLY 1

#define I2C_ADDRESS 0x3C


#define LED_OFF HIGH
#define LED_ON LOW

#define TPMS_TIMEOUT 900000 //(15 * 60 * 1000)  15 minutes
#define CAL_PERIOD_MS 3600000 //60 * 60 * 1000  60 minutes

#define FONTBAR_7 123
#define FONTBAR_5 124
#define FONTBAR_3 125
#define FONTBAR_2 126
#define FONTBAR_1 127
#define FONTBAR_0 32


//#ifdef INCLUDESPARETYRE  - nolonger used. If no spare with TPMS, just set the ID to 0xFFFFFFF
//  #define TYRECOUNT 5
//#else
//  #define TYRECOUNT 4
//#endif

#ifdef INCLUDE_WINTER_SET
   #define TYRECOUNT 10
#else
   #define TYRECOUNT 5
#endif

#define PSI2BAR 14.504
#define KPA2PSI 6.895

#define DEGC_TO_KELVIN 273.15

#define NO_VALID_TEMPERATURE -99

#define BITISLONG 1
#define BITISSHORT 0
#define BITISSYNC 2
#define BITISUNDEFINED -1

// hardware pin configuration

#ifdef ARDUINO_AVR_PROMICRO
   #define PROC_TYPE "Arduino Pro Micro"
   #define USE_GPIO_Dx 0
   const int16_t RXPin = 7;   //must be an ext interrupt pin
   const int16_t CDPin = 9;  //if wired, define 'USE_HW_CD' above, otherwise CD pin status is received over SPI
   const int16_t CC1101_CS = 10;  // Define the Chip Select pin
   const int16_t AUDIBLE_ALARM_PIN = 8;
   const int16_t DEBUGPIN = 6;
   const int16_t LED_RX = LED_BUILTIN;
   const int16_t MAXBITS =200;
   const int16_t MAXTIMINGS = 255;
#elif ARDUINO_AVR_NANO
   #define PROC_TYPE "Arduino Nano"
   #define USE_GPIO_Dx 0
   #error Arduino Nano has insufficient RAM (only 2k) to run this program. Switch to another board type e.g. Arduino Nano 33 IOT. 
//   const int RXPin = 2;   //must be an ext interrupt pin
//   const int CDPin = 9;  //if wired, define 'USE_HW_CD' above, otherwise CD pin status is received over SPI
//   const int CC1101_CS = 10;  // Define the Chip Select pin
//   const int AUDIBLE_ALARM_PIN = 8;
//   const int DEBUGPIN = 6;
//   const int LED_RX = LED_BUILTIN;
//   const int MAXBITS = 200;
//   const int MAXTIMINGS = 255;
#elif ARDUINO_SEEED_XIAO_M0
   #define PROC_TYPE "Seeeduino Xiao"
   #define USE_GPIO_Dx 0
   const int16_t RXPin = 1;   //must be an ext interrupt pin
   const int16_t CDPin = 0;  //if wired, define 'USE_HW_CD' above, otherwise CD pin status is received over SPI
   const int16_t CC1101_CS = 2;  // Define the Chip Select pin
   const int16_t AUDIBLE_ALARM_PIN = 7;
   const int16_t DEBUGPIN = 12;  //use the TX LED pin
   const int16_t LED_RX = LED_BUILTIN;
   const int16_t MAXBITS = 1000;
   const int16_t MAXTIMINGS = 900;
#elif ARDUINO_SEEED_XIAO_RP2040
   #define PROC_TYPE "Seeeduino Xiao RP2040"
   #define USE_GPIO_Dx 1
   const int16_t RXPin = D1;   //must be an ext interrupt pin
   const int16_t CDPin = D0;  //if wired, define 'USE_HW_CD' above, otherwise CD pin status is received over SPI
   const int16_t CC1101_CS = D2;  // Define the Chip Select pin
   const int16_t AUDIBLE_ALARM_PIN = D7;
   const int16_t DEBUGPIN = 16;  //use the TX LED pin
   const int16_t LED_RX = 17;
   const int16_t MAXBITS = 1000;
   const int16_t MAXTIMINGS = 900;
#elif ARDUINO_SAMD_NANO_33_IOT
   #define PROC_TYPE "Arduino Nano 33 IOT"
   #define USE_GPIO_Dx 0
   const int16_t RXPin = 2;   //must be an ext interrupt pin
   const int16_t CDPin = 9;  //if wired, define 'USE_HW_CD' above, otherwise CD pin status is received over SPI
   const int16_t CC1101_CS = 10;  // Define the Chip Select pin
   const int16_t AUDIBLE_ALARM_PIN = 8;
   const int16_t DEBUGPIN = 6;
   const int16_t LED_RX = LED_BUILTIN;
   const int16_t MAXBITS = 1000;
   const int16_t MAXTIMINGS = 900;
   #include <avr/dtostrf.h>
#elif ARDUINO_AVR_MEGA2560
   #define PROC_TYPE "Mega 256"
   #define USE_GPIO_Dx 0
   const int16_t RXPin = 2;   //must be an ext interrupt pin
   const int16_t CDPin = 3;  //if wired, define 'USE_HW_CD' above, otherwise CD pin status is received over SPI
   const int16_t CC1101_CS = 4;  // Define the Chip Select pin
   const int16_t AUDIBLE_ALARM_PIN = 5;
   const int16_t DEBUGPIN = 6;  //use the TX LED pin
   const int16_t LED_RX = LED_BUILTIN;
   const int16_t MAXBITS = 1000;
   const int16_t MAXTIMINGS = 900;
#elif ARDUINO_AVR_ITSYBITSY32U4_3V
   #define PROC_TYPE "ITSYBITSY32U4_3V"
   #define USE_GPIO_Dx 0
   const int16_t RXPin = 7;   //must be an ext interrupt pin
   const int16_t CDPin = 9;  //if wired, define 'USE_HW_CD' above, otherwise CD pin status is received over SPI
   const int16_t CC1101_CS = 10;  // Define the Chip Select pin
   const int16_t AUDIBLE_ALARM_PIN = 8;
   const int16_t DEBUGPIN = 6;  //use the TX LED pin
   const int16_t LED_RX = LED_BUILTIN;
   const int16_t MAXBITS = 200;
   const int16_t MAXTIMINGS = 255;
#else
   #error No configuration set up for this processor type in globals.h
#endif

#define AUDIBLE_ALARM_ON_TIME_MS 500
#define AUDIBLE_ALARM_OFF_TIME_MS 1000
#define AUDIBLE_ALARM_ONOFF_COUNT 5
#define AUDIBLE_ALARM_REMINDER_TIME_MS 1800000L //30 x 60 x 1000 (repeat alarm after 30 minutes) - Set to zero for no reminders. Note: value must be > (AUDIBLE_ALARM_ON_TIME_MS + AUDIBLE_ALARM_OFF_TIME_MS) * AUDIBLE_ALARM_ONOFF_COUNT


volatile static uint32_t LastEdgeTime_us = 0;

volatile static bool ValidBlock = false;
volatile static bool WaitingFirstEdge = true;
volatile uint16_t Timings[MAXTIMINGS+1];
volatile bool FirstEdgeIsHighToLow;
uint16_t ValidTimingsStart;


volatile uint16_t TimingsIndex = 0;
uint16_t CheckIndex = 0;
bool SyncFound = false;
uint32_t CD_Width;
int16_t StartDataIndex = 0;
bool TPMS_Changed = false;
bool Pressure_Alarm_Active = false;
bool Temperature_Alarm_Active = false;
bool Audible_Alarm_On = false;
bool Audible_AlarmPin_Active = LOW;
int16_t Audible_Alarm_Cycle_Countdown = 0;
bool Audible_Alarm_Running = false;

uint32_t DisplayTimer =0;
boolean DisplayFlash  = false;
boolean DisplayFlashExpired = false;
boolean SignalRefreshNeeded = false;
//const uint32_t  DISPLAYFLASHREFRESHTIMING = 1000;  //pressures warning flash rate
const uint16_t NOBLANK_MS = 1500;  //pressures warning flash rate (on time)
const uint16_t BLANK_MS = 500;  //pressures warning flash rate (off time)
const uint32_t  SIGNALREFRESHTIMING = 20000;  //force screen update so that signal bar can be updated if needed
int8_t TPMSChangeBits = 0;


bool IncomingBits[MAXBITS]; 
bool ManchesterDecodedBits[MAXBITS/2 + 2];
uint16_t ManchesterBitCount = 0;
uint16_t BitIndex = 0;
int16_t BitCount = 0;

uint16_t FreqOffset;
uint16_t DemodLinkQuality;
int16_t RSSIvalue;
uint16_t FreqOffsetAcc = 0;
uint32_t LastCalTime;
char Ref[3];

int16_t RawCount = 0;
//byte ManchesterRX[64];  //holds received Manchester byte message (converted from the rawdata)
uint8_t RXBytes[20];  //holds the raw incoming databytes from the CC1101 serial port
int16_t RXByteCount;
uint32_t IncomingAddress;

//function declataions
extern bool ValidateTimings();
extern bool ReceiveMessage();
extern void DecodeTPMS();



//this table (and its order define known TPMS IDs so that they their values are always displayed in the same order
const uint32_t  IDLookup[] =
{
  FRONT_LEFT, FRONT_RIGHT, 
  REAR_LEFT, REAR_RIGHT, 
  SPARE,
  WINTER_FRONT_LEFT, WINTER_FRONT_RIGHT, 
  WINTER_REAR_LEFT, WINTER_REAR_RIGHT, 
  WINTER_SPARE,  
};





  ////CRCTable
  const unsigned char PROGMEM CRC8_Poly_07_crctable2[] =
  {
  
      0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
      0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
      0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
      0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
      0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
      0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
      0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
      0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
      0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
      0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
      0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
      0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
      0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
      0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
      0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
      0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
  };

  const unsigned char PROGMEM CRC8_Poly_13_crctable2[] =
  {
  
        0x00, 0x13, 0x26, 0x35, 0x4C, 0x5F, 0x6A, 0x79, 0x98, 0x8B, 0xBE, 0xAD, 0xD4, 0xC7, 0xF2, 0xE1,
        0x23, 0x30, 0x05, 0x16, 0x6F, 0x7C, 0x49, 0x5A, 0xBB, 0xA8, 0x9D, 0x8E, 0xF7, 0xE4, 0xD1, 0xC2,
        0x46, 0x55, 0x60, 0x73, 0x0A, 0x19, 0x2C, 0x3F, 0xDE, 0xCD, 0xF8, 0xEB, 0x92, 0x81, 0xB4, 0xA7,
        0x65, 0x76, 0x43, 0x50, 0x29, 0x3A, 0x0F, 0x1C, 0xFD, 0xEE, 0xDB, 0xC8, 0xB1, 0xA2, 0x97, 0x84,
        0x8C, 0x9F, 0xAA, 0xB9, 0xC0, 0xD3, 0xE6, 0xF5, 0x14, 0x07, 0x32, 0x21, 0x58, 0x4B, 0x7E, 0x6D,
        0xAF, 0xBC, 0x89, 0x9A, 0xE3, 0xF0, 0xC5, 0xD6, 0x37, 0x24, 0x11, 0x02, 0x7B, 0x68, 0x5D, 0x4E,
        0xCA, 0xD9, 0xEC, 0xFF, 0x86, 0x95, 0xA0, 0xB3, 0x52, 0x41, 0x74, 0x67, 0x1E, 0x0D, 0x38, 0x2B,
        0xE9, 0xFA, 0xCF, 0xDC, 0xA5, 0xB6, 0x83, 0x90, 0x71, 0x62, 0x57, 0x44, 0x3D, 0x2E, 0x1B, 0x08,
        0x0B, 0x18, 0x2D, 0x3E, 0x47, 0x54, 0x61, 0x72, 0x93, 0x80, 0xB5, 0xA6, 0xDF, 0xCC, 0xF9, 0xEA,
        0x28, 0x3B, 0x0E, 0x1D, 0x64, 0x77, 0x42, 0x51, 0xB0, 0xA3, 0x96, 0x85, 0xFC, 0xEF, 0xDA, 0xC9,
        0x4D, 0x5E, 0x6B, 0x78, 0x01, 0x12, 0x27, 0x34, 0xD5, 0xC6, 0xF3, 0xE0, 0x99, 0x8A, 0xBF, 0xAC,
        0x6E, 0x7D, 0x48, 0x5B, 0x22, 0x31, 0x04, 0x17, 0xF6, 0xE5, 0xD0, 0xC3, 0xBA, 0xA9, 0x9C, 0x8F,
        0x87, 0x94, 0xA1, 0xB2, 0xCB, 0xD8, 0xED, 0xFE, 0x1F, 0x0C, 0x39, 0x2A, 0x53, 0x40, 0x75, 0x66,
        0xA4, 0xB7, 0x82, 0x91, 0xE8, 0xFB, 0xCE, 0xDD, 0x3C, 0x2F, 0x1A, 0x09, 0x70, 0x63, 0x56, 0x45,
        0xC1, 0xD2, 0xE7, 0xF4, 0x8D, 0x9E, 0xAB, 0xB8, 0x59, 0x4A, 0x7F, 0x6C, 0x15, 0x06, 0x33, 0x20,
        0xE2, 0xF1, 0xC4, 0xD7, 0xAE, 0xBD, 0x88, 0x9B, 0x7A, 0x69, 0x5C, 0x4F, 0x36, 0x25, 0x10, 0x03
  };

struct TPMS_entry
{
  uint32_t TPMS_ID;
  uint32_t lastupdated;
  uint16_t TPMS_Status;
  double TPMS_Pressure;
  float TPMS_Temperature;
  float TPMS_LowTemperatureLimit;
  float TPMS_HighTemperatureLimit;
  double TPMS_LowPressureLimit;
  double TPMS_HighPressureLimit;
  boolean LowPressure;
  boolean HighPressure;
  boolean LowTemperature;
  boolean HighTemperature;
  int16_t RSSIdBm;
  boolean AudibleAlarmActive;
} TPMS[TYRECOUNT];


enum RXStates
{
  Waiting_Byte33 = 0,
  Got_Byte33,
  Got_Byte55,
  Got_Byte53,
  Manch1,
  Manch2
};


//following tables useful for testing/debugging the software without the need to receive actual hardware data
//can be turned on/off using the #define USE_TEST_TIMINGS at the top of this include file

#ifdef Toyota_PMV_C210 

   #ifdef UK_433MHz
//    const uint16_t TestTimings[] =
//      {
//        24,264,104,448,48,200,96,104,96,96,56,48,48,48,56,48,96,48,56,96,96,104,48,48,48,56,96,48,
//        48,56,56,40,48,56,48,96,96,104,96,48,56,96,48,48,56,48,96,104,48,48,96,56,48,96,104,48,48,
//        48,48,104,96,104,96,96,56,48,96,56,48,48,48,48,48,104,96,56,48,48,48,48,56,48,48,48,48,56,
//        48,48,56,40,56,48,48,96,104,48,48,48,56,48,48,48,56,48,48,96,104,96,48,56,96,104,56,56,104,
//        96,408
//      };

      const uint16_t TestTimings[] =
      {
      52,56,44,56,44,52,48,52,100,196,96,100,104,96,56,40,60,40,60,44,52,44,108,44,52,92,112,88,56,44,52,48,104,96,96,100,104,44,56,92,104,48,52,96,104,44,56,92,56,44,104,44,56,92,104,48,52,44,60,40,60,92,104,92,48,52,100,52,44,52,56,100,92,100,52,52,48,48,104,48,48,100,92,56,52,48,52,44,52,48,52,96,100,100,48,48,52,56,48,44,100,56,48,44,56,92,48,52,56,44,96,52,56,44,56,44,52
      };
      
       const bool FirstTimingIsLow = true;
   #endif


   
#elif Renault 

   #ifdef UK_433MHz
//    const uint16_t TestTimings[] =
//      {
//       
//        350,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,100,50,
//        50,50,50,100,100,50,50,100,50,50,100,100,
//        100,100,50,50,50,50,100,100,100,100,
//        50,50,100,50,50,100,100,100,50,50,50,50,
//        100,50,50,50,50,50,50,100,50,50,100,50,
//        50,50,50,100,100,100,100,50,50,50,50,100,
//        100,50,50,50,50,50,50,100,100,100,100,
//        50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
//        50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
//        50,100,100,50,50,50,50,50,50,50,50,50,50,50,
//        300,50,50,50,50,50
//      };
//    const bool FirstTimingIsLow = true;
//   #endif



    const uint16_t TestTimings[] =
      {
          364,60,44,56,52,52,52,52,52,52,52,52,52,52,52,56,52,
          52,52,52,52,52,52,52,52,52,52,52,52,104,52,52,52,52,
          104,108,52,52,104,52,52,104,104,104,104,104,52,52,52,
          52,108,52,52,52,52,52,52,104,52,52,104,104,52,52,104,
          52,56,104,52,52,104,52,52,104,52,52,52,52,104,52,52,
          104,108,104,52,52,52,52,52,52,104,52,52,52,52,104,108,
          100,108,52,52,104,52,52,52,52,52,52,52,52,52,52,52,
          52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
          52,52,104,52,56,104,52,52,104,52,52,52,52,104,264      
      };
       const bool FirstTimingIsLow = true;
   #endif


   
#elif Citroen 

   #ifdef UK_433MHz
    const uint16_t TestTimings[] =
      {
         350,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,100,
         100,50,50,50,50,100,50,50,50,50,100,50,50,
         100,100,50,50,50,50,100,50,50,100,50,50,50,
         50,50,50,50,50,50,50,50,50,100,100,100,100,
         50,50,50,50,50,50,50,50,100,100,50,50,50,50,
         100,100,50,50,50,50,100,100,100,50,50,100,
         100,100,50,50,50,50,50,50,50,50,50,50,50,50,
         100,100,50,50,50,50,50,50,50,50,50,50,100,
         100,50,50,50,50,100,50,50,50,50,100,50,50,
         50,50,50,50,50,50,50,50,50,50,100,100,50,
         50,50,50,50,50,100,50,50,50,50,100,50,
         300,50,50,50,50,50
      };
       const bool FirstTimingIsLow = true;
   #endif

   
      
#elif Toyota_PMV_107J

   #ifdef US_315MHz
//    const uint16_t TestTimings[] =
//      {
//        32,52,152,52,100,708,556,200,204,204,100,100,204,200,104,100,200,204,200,204,204,100,100,
//        100,100,204,204,100,100,100,100,204,100,100,204,204,100,100,200,204,100,104,200,100,104,
//        100,100,100,100,104,100,204,100,100,100,104,100,100,104,100,200,100,104,100,100,100,104,
//        200,100,104,200,204,100,100,200,204,204,100,100,204,100,100,104,100,200,104,100,100,100,
//        104,100,100,100,100,104,200,104,100,200,104,100,100,100,204,100,104,100,104,100,100,152,
//        932,52,0
//       }; 
//    const uint16_t TestTimings[] =
//      {
//          36,1452,204,200,104,100,200,204,100,100,204,200,204,204,200,100,100,104,100,204,200,100,
//          100,104,100,204,100,100,200,204,100,100,204,204,100,100,204,100,100,100,104,100,100,100,
//          100,204,204,200,100,104,100,100,100,104,200,100,104,200,100,104,200,100,104,200,204,100,
//          100,204,100,100,204,100,100,200,104,100,204,100,100,100,104,100,100,100,104,200,204,200,
//          200,204,204,200,104,100,204,200,152,100
//
//      }; 
//     const uint16_t TestTimings[] =
//      {
//
//            628,612,200,100,104,200,200,204,200,100,104,100,100,200,204,200,204,100,100,100,104,100,
//            100,100,100,204,100,100,204,100,100,204,200,100,104,200,100,100,104,100,100,100,100,104,
//            100,100,100,100,204,200,104,100,100,100,100,104,200,100,100,104,100,100,100,104,100,100,
//            100,204,100,100,100,100,204,200,204,200,204,100,100,200,104,100,200,100,104,100,100,100,
//            104,100,100,100,100,104,100,200,204,100,100,204,100,100,100,100,204,100,100,164,740
//      };

     const uint16_t TestTimings[] =
      {
            72,200,200,1172,104,104,104,104,104,200,200,200,104, 96,200,200,104, 96,208,200,200, 96,
            104, 96,104,200,208,200,200, 96,104, 96,104,104, 96,200,104, 96,104, 96,208, 96,104,200,
            200,104, 96,104,104, 96,104,200, 96,104, 96,104, 96,104, 96,104,200,200,200,208,200,200,
            104, 96,200,104, 96,104, 96,104,104, 96,104, 96,104, 96,104,200, 96,104,104, 96,200,208,
            200,200,104, 96, 96,104,104, 96,104, 96,200,104,104, 96, 96,192,104, 96,192,200,1096,896,
            112,184, 96 

      };
    const bool FirstTimingIsLow = true;
   #endif 


  
#elif Ford 

   #ifdef UK_433MHz

    const uint16_t TestTimings[] =
      {
            52,56,48,56,48,56,48,56,48,56,48,56,52,52,48,56,48,56,48,56,48,56,48,52,52,52,52,52,
            52,104,104,104,104,52,52,52,52,104,104,104,52,52,52,52,104,104,104,52,52,104,52,52,
            100,52,52,52,52,52,52,104,104,104,52,52,104,104,52,52,104,104,104,52,52,104,52,52,
            100,56,48,52,52,104,104,104,104,104,52,52,104,52,52,52,52,52,52,52,52,104,104,104,
            104,52,52,52,52,104,48,52,104,52,52,52,52,52,52,104,52,52,52,52,104,104,80
      };

    
       const bool FirstTimingIsLow = true;
   #endif

  #ifdef US_315MHz

    const uint16_t TestTimings[] =
//      {
//            53,52,51,52,53,52,53,52,53,51,52,53,52,53,52,52,52,52,53,51,51,51,53,52,52,52,108,106,102,
//            105,53,53,52,50,52,51,52,52,53,55,106,101,103,54,55,54,51,102,103,52,55,54,51,51,52,111,48,
//            51,102,53,51,52,52,104,105,105,104,104,108,106,102,106,53,52,52,51,53,53,52,52,52,51,52,53,
//            54,53,49,53,106,52,52,104,52,53,51,52,53,51,52,51,53,54,54,52,101,104,53,54,54,53,101,105,
//            54,52,52,50,103,53,54,55,52,104,107,56,50,52,55,55,619
//      };


      {
            52,53,51,52,52,52,51,53,52,52,52,53,51,51,52,53,51,51,52,52,51,53,51,106,106,
            100,105,54,52,51,52,50,51,52,52,52,53,106,101,102,52,55,53,51,102,104,51,53,53,51,
            52,51,108,51,50,100,53,52,52,53,104,104,102,104,103,109,104,104,104,51,51,52,52,53,
            52,51,53,51,52,52,53,55,52,49,49,52,51,106,106,100,107,53,52,100,106,53,52,101,107,
            50,54,53,51,103,104,51,51,53,51,52,51,54,55,52,50,99,93,47,46,97,150,597    
      };
       const bool FirstTimingIsLow = true;
   #endif
   


#elif Jansite

   #ifdef UK_433MHz

//    const uint16_t TestTimings[] =
//      {
//            52,56,48,56,48,56,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,
//            52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,
//            52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,
//            52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,
//            52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,
//            52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,
//            52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,
//            52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,
//            52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,
//            52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,
//            52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,
//            52,56,52,52,52,104,104,104,104,104,108,104,104,104,52,52,104,104,104,108,52,52,104,
//            104,52,52,52,52,52,52,104,56,52,104,52,52,52,52,104,52,52,104,52,56,104,52,52,104,
//            104,52,52,52,52,108,52,52,104,104,104,52,52,52,52,104,108,52,52,104,104,52,52,52,
//            52,52,52,104,52,56,104,52,52,104,104,52,52,52,52,104,56,52,52,52,52,52,52,52,52,
//            52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,
//            52,52,52,52,52,52,52,56,52,104,104,104,104,104,104,108,104,104,52,52,104,104,104,
//            104,56,52,104,104,52,52,52,52,52,52,104,56,52,104,52,52,52,52,104,52,52,104,56,48,
//            108,52,52,104,104,52,52,52,52,104,56,52,104,104,104,52,52,52,52,104,104,56,52,104,
//            104,52,52,52,52,52,52,104,56,52,104,52,52,104,104,52,52,52,52
//      };

    const uint16_t TestTimings[] =
      {
            52,64,40,64,44,52,52,52,52,56,48,56,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,
52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,
52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,
52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,
52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,
52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,
52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,
52,56,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,
52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,
52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,
52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,108,104,52,52,52,
52,104,104,104,108,104,52,52,104,52,52,52,52,104,52,52,108,104,104,52,52,52,52,52,52,104,108,104,
104,104,104,52,52,104,108,104,104,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,
52,104,104,56,52,52,52,104,52,52,104,104,104,108,104,104,104,104,104,52,52,104,56,52,52,52,52,52,
52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,
52,52,52,52,52,56,52,52,52,52,52,104,104,52,52,52,52,108,104,104,104,104,52,52,104,52,52,56,
52,104,52,52,104,104,104,52,52,52,56,52,52,104,104,104,104,104,104,56,52,104,104,104,104,52,52,52,
52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,104,104,52,52,52,52,104,52,52,108,104,
104,104,104,104,104,108,104,52,52,160 
       
       };     
       const bool FirstTimingIsLow = false;
   #endif


#elif JansiteSolar
    #ifdef UK_433MHz

    const uint16_t TestTimings[] =
      {
        //53,40,48,56,48,56,48,56,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,
        //52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,
        //52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
        //52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,48,56,52,52,52,52,52,52,52,52,
        //52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,
        //52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,
        //52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,
        //52,52,52,52,52,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,52,
        //52,52,52,52,52,52,52,52,52,56,48,56,52,52,52,52,52,52,52,52,52,52,52,52,52,52,56,52,
        //52,52,52,52,52,52,52,52,104,104,52,52,56,52,104,104,104,52,52,104,52,52,104,56,52,104,52,52,
        //52,52,52,52,104,104,52,56,100,108,52,52,104,52,52,52,52,104,104,104,108,104,104,52,52,52,52,52,
        //52,52,56,48,52,108,104,52,52,52,52,52,52,52,52,52,52,52,52,56,52,52,52,52,52,104,104,52,
        //52,104,52,56,104,52,52,52,52,104,104,104,104,104,108,52,52,52,52,52,52,52,52,52,52,52,52,52,
        //52,52,56,52,52,104,104,104,52,52,104,52,52,108,52,52,52,52,104,104,104,52,52,52,52,52,52,108,
        //748,32
        
        53, 52, 52, 53, 52, 52, 53, 52, 52, 52, 53, 53, 51, 53, 52, 52, 52, 53, 52, 52, 52, 54, 
        51, 52, 53, 52, 52, 52, 53, 52, 52, 53, 52, 52, 52, 53, 52, 53, 53, 51, 52, 53, 52, 52, 53, 
        52, 52, 53, 55, 49, 53, 52, 52, 52, 53, 53, 51, 53, 52, 52, 53, 52, 52, 53, 52, 53, 52, 52, 
        52, 52, 53, 52, 53, 52, 52, 52, 53, 52, 52, 53, 52, 52, 53, 52, 52, 52, 53, 52, 52, 52, 53, 
        52, 52, 53, 52, 52, 52, 53, 52, 52, 53, 52, 52, 53, 52, 52, 53, 52, 52, 53, 52, 52, 52, 52, 
        53, 52, 53, 52, 52, 52, 53, 52, 53, 52, 52, 52, 52, 53, 52, 53, 54, 50, 53, 52, 52, 53, 52, 
        52, 52, 53, 52, 53, 52, 52, 53, 53, 51, 52, 53, 52, 52, 53, 52, 52, 54, 51, 52, 52, 53, 52, 
        52, 52, 53, 52, 52, 53, 52, 52, 52, 54, 51, 52, 52, 53, 52, 52, 53, 52, 52, 53, 52, 52, 53, 
        52, 53, 51, 52, 53, 52, 53, 52, 52, 52, 52, 53, 52, 52, 53, 52, 53, 52, 53, 51, 53, 52, 52, 
        52, 53, 52, 52, 53, 52, 52, 53, 52, 52, 52, 53, 52, 52, 52, 53, 52, 52, 54, 51, 52, 52, 53, 
        52, 52, 53, 52, 52, 52, 53, 52, 52, 53, 52, 52, 52, 53, 52, 52, 53, 50, 53, 50, 52, 53, 54, 
        53,104,102, 52, 53, 51, 53,106,105,104, 52, 53,104, 52, 53,106, 53, 51,104, 53, 53, 52, 51,
        104, 51, 51, 52, 52,106,105,103,103, 52, 54,109,105,103, 53, 53, 52, 53,103, 51, 51, 52, 53, 
        54, 51,103,105, 54, 53,106,105, 52, 53, 51, 53, 52, 51, 51, 51, 52, 51, 53, 51,104,103,107,
        106,106,107, 52, 51,109, 49, 53, 52, 52,105, 52, 53, 52, 53, 52, 52, 53, 52, 52, 52, 52, 53, 
        52, 52, 53, 52, 52, 51, 53, 50, 52, 53, 53, 54,105,103, 52, 52, 53, 52, 51, 51,106, 53, 51,
        103,106, 54, 53,107,103, 52, 51, 52, 53, 53, 51, 51, 51,101, 46, 46, 93, 92, 48, 47,898


       };     
       const bool FirstTimingIsLow = false;
   #endif   

#elif Hyundai_i35
    #ifdef UK_433MHz

    const uint16_t TestTimings[] =
      {

      104, 56, 52,440,152, 48, 48, 52, 48, 52, 48, 48, 52, 48, 48,100,
      100,100, 52, 48, 48, 48,100, 48, 52, 96, 52, 48,100, 52, 48,100,
      100, 96,100,100,100, 96, 52, 48,104, 48, 48, 48, 52, 48, 48,104, 
      96, 48, 52,100, 96, 52, 48,100, 48, 52, 96, 52, 48, 52, 48, 48, 
      48,104, 48, 52, 96, 48, 52, 48, 52, 48, 52, 96,100,100,100, 96,
      100, 48, 48,100,104, 48, 52, 96,100,100, 48, 52, 48, 48, 52, 48, 
      48, 52, 52, 48,100, 48, 48, 44, 52, 48, 48, 92, 48,348, 52,216,108, 52
       
       
       };     
       const bool FirstTimingIsLow = true;
   #endif 

#elif Schrader_C1100
    #ifdef UK_433MHz

    const uint16_t TestTimings[] =
      {

      54, 51, 53, 52, 52, 52, 53, 52, 52, 52, 53, 52, 52, 53, 52, 53, 52, 51, 
      51, 54, 54, 51, 51, 53,106, 52, 51,105, 53, 52, 52, 53, 51, 51, 52, 54, 
      54, 58, 46, 50,104, 51, 52, 53, 52,104,108,105,102,104, 52, 51,108, 54, 
      52,102,103, 52, 52, 53, 51, 53, 52,107,108,100,106, 54, 52, 51, 51,103, 
      52, 55, 54, 53,103,104, 54, 51, 51, 51,103, 53, 55,107,102,105, 53, 52, 
      52, 52, 52, 53, 52, 51, 52, 51, 53, 54, 55, 52,101,106, 54, 51, 51, 52,
      107, 52, 52,103, 53, 53, 53, 51, 52, 53, 52, 51, 52, 51, 53, 51, 54, 51,
      108,106,102,104, 52, 52, 52, 55, 52, 50,103,111, 53

       
       
       };     
       const bool FirstTimingIsLow = false;
   #endif 

#elif Subaru
    #ifdef UK_433MHz

    const uint16_t TestTimings[] =
      {
         //derived from Subaru.sr RTL433 capture
         208, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 
         212,104,50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
         104,100, 50, 50,100, 50, 50, 50, 50,100, 50, 50,100, 50, 50,100, 50, 50, 50, 50,100,100, 50, 50, 50, 50, 50, 50,100,100,
         50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,100,100, 50, 50,100,100, 50, 50, 50, 50, 50, 50, 50, 50,
         100,100, 50, 50, 50, 50, 50, 50, 50, 50,100, 50, 50,100, 50, 50,100,100, 50, 50, 50, 50,100,500

       
       
       };     
       const bool FirstTimingIsLow = false;
       
   #elif US_315MHz

    const uint16_t TestTimings[] =
      {

          553,246,122,122,124,121,123,123,123,123,124,122,123,124,121,123,123,122,
          123,123,123,123,126,124,125,122,123,123,120,489,246,123,123,121,123,247,
          124,122,123,124,123,124,244,121,122,247,247,123,124,120,124,246,244,123,
          123,247,122,124,123,122,246,123,122,245,122,126,246,124,121,122,121,246,
          245,123,124,124,124,124,122,122,121,244,245,123,125,126,124,125,125,125,
          3036
      
       };     
       const bool FirstTimingIsLow = true;
       
   #endif 
#endif




#ifdef USE_TEST_TIMINGS
      const int16_t TestTimings_len = sizeof(TestTimings)/sizeof(TestTimings[0]);
#endif

Toyota_PMV_107J

C Header File
#ifdef UK_433MHz


     #define EXPECTEDBITCOUNT 66
     #define EXPECTEDBYTECOUNT 9     

    //these 433MHz timings are guesses and not proven
    
    #define CDWIDTH_MIN 6000
    #define CDWIDTH_MAX 9500
    
    #define SHORTTIMING_MIN 40
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 175
    #define SYNCTIMING_MAX 1200
    
    #define ENDTIMING_MIN  0
    #define ENDTIMING_MAX   500

      
    #define CC1101_DEFVAL_IOCFG2     0x0C        // GDO2 Output Pin Configuration - Serial out (synchronous)
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x12 //0x30        // Packet Automation Control - synchronous data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 433.919830 MHz
    #define CC1101_DEFVAL_FREQ2  0x10        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1  0xB0        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0  0x71        // Frequency Control Word, Low Byte

    #define CC1101_DEFVAL_DEVIATN    0x40      // Modem Deviation Setting (+/-25.390625kHz)

    #define CC1101_DEFVAL_MDMCFG4    0x59        // Modem Configuration (59 = data rate = 20kHz - actual data rate is 10kHz but due to bi-phase coding need to double the rate, RX bandwidth 325kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
    #define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control

        
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration

    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings



      
 
#elif US_315MHz


    //these 315MHz timings are guesses and not proven
    

      #define EXPECTEDBITCOUNT 66
      #define EXPECTEDBYTECOUNT 9
          
      #define CDWIDTH_MIN 12000
      #define CDWIDTH_MAX 17500
    
      #define SHORTTIMING_MIN 80
      #define SHORTTIMING_MAX 139
      #define LONGTIMING_MIN 166
      #define LONGTIMING_MAX 250
      #define SYNCTIMING_MIN 350
      #define SYNCTIMING_MAX 1500

      #define ENDTIMING_MIN  140
      #define ENDTIMING_MAX   500


    #define CC1101_DEFVAL_IOCFG2     0x0C        // GDO2 Output Pin Configuration - Serial out (synchronous)
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x12 //0x30        // Packet Automation Control - synchronous data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 314.979828 MHz
    #define CC1101_DEFVAL_FREQ2  0x0C        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1  0x1D        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0  0x57        // Frequency Control Word, Low Byte
      
    #define CC1101_DEFVAL_DEVIATN    0x44      // Modem Deviation Setting (+/-38kHz) //deviation widened to 38kHz as recommended by Andrey Oleynik

    #define CC1101_DEFVAL_MDMCFG4    0x78        // Modem Configuration (78 = data rate = 10kHz - actual data rate is 5kHz but due to bi-phase coding need to double the rate, RX bandwidth 232kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x94        // Modem Configuration (now 94 = data rate = 10kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
//    #define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
//    #define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
//    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL2   0x43       // AGC Control   //agc set as recommended by Andrey Oleynik
    #define CC1101_DEFVAL_AGCCTRL1   0x40        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x81        // AGC Control
    
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration

    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings


#endif



void DecodeTPMS()
{

  uint32_t id = 0;
  uint16_t status, pressure1, pressure2, temp, battery_low, counter, failed;
   double realpressure;
  float realtemp;


  


  //note: incoming bit stream has been shifted right by 6 bits in DecodeBitArray to give integral number of bytes (for checksum)

  id = (uint32_t)(RXBytes[0]) << 26| (uint32_t)(RXBytes[1]) << 18 | (uint32_t)(RXBytes[2]) << 10 | (uint32_t)(RXBytes[3]) << 2 | (uint32_t)(RXBytes[4]) >> 6; 
  id = id & 0xFFFFFFF;

  GetPreferredIndexStr(id, Ref);
 
  status = RXBytes[4] & 0x3f; // status bits and 0 filler

  battery_low = (RXBytes[4] & 0x20) >> 5;
  counter = (RXBytes[4] & 0x18) >> 3;
  failed = RXBytes[4] & 0x01;

  pressure1 = RXBytes[5];
  pressure2 = RXBytes[6] ^ 0xff;
  temp = RXBytes[7];
  




  if (pressure1 != pressure2)
  {
    Serial.println(F("Pressure check mis-match"));
    return;
  }

  realpressure = (double) pressure1;
  realpressure = ((realpressure - 40) * 0.363) - 0.735;  //default to psi, kpa would be (pressure1 - 40.0) * 2.48
  if (realpressure < 0.0)
    realpressure = 0.0;
  realtemp = (float)temp;
  realtemp = realtemp - 40.0;


#ifdef SHOWVALIDTPMS
  Serial.print(F("Pos: "));
  Serial.print(Ref);
  Serial.print(F("   ID: "));
  Serial.print(id, HEX);
  Serial.print(F("   Status: 0x"));
  Serial.print(status,HEX);
  Serial.print(F(" [Battery status: "));
  Serial.print(battery_low);
  Serial.print(F("   Counter: "));
  Serial.print(counter);
  Serial.print(F("   Failed status: "));
  Serial.print(failed);  
  Serial.print(F("]   Temperature: "));
  Serial.print(realtemp);
  Serial.print(F("   Tyre Pressure: "));
  Serial.print(realpressure);
  Serial.print(F(" (psi)  "));
  Serial.print(realpressure/PSI2BAR);
  Serial.print(F(" (bar)"));
  Serial.println(F(""));
#endif



  MatchIDandUpdate(id,status, realtemp, realpressure);



  #ifdef SHOWVALIDTPMS
     Serial.println(F(""));
  #endif


}






bool ValidateTimings()
{


  //uint16_t BitWidth;
  uint16_t diff = TimingsIndex;
  bool WaitingTrailingZeroEdge = false;
  int16_t ret;
  int16_t ByteCount = 0;
  uint8_t crcResult = 0;
  bool ConversionFinished = false;
  int16_t Offset = 0;

  StartDataIndex = 0;

  if (diff < EXPECTEDBITCOUNT)
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
      Serial.print(F("Insufficient data in buffer ("));
      Serial.print(diff);
      Serial.println(F(")"));
    #endif
    return(false);
  }


  CheckIndex = 0;

  while ((diff > 0) && (BitCount < MAXBITS) && (ConversionFinished == false))
  { //something in buffer to process...
    diff = TimingsIndex - CheckIndex;

    //BitWidth = Timings[CheckIndex];



      ret = ValidateBit();
      switch (ret)
      {
        case BITISUNDEFINED:
          //invalid bit
          if (BitCount >= EXPECTEDBITCOUNT)
          {
            ConversionFinished = true;
            break;
          }
             
          BitIndex = 0;
          BitCount = 0;
          WaitingTrailingZeroEdge = false;
          StartDataIndex = CheckIndex + 1;
          Offset = StartDataIndex;

          break;

        case BITISSHORT:
          if (WaitingTrailingZeroEdge)
          {
            //BitTimings[BitIndex] = BitWidth;
            IncomingBits[BitIndex++] = 0;
            BitCount++;
            WaitingTrailingZeroEdge = false;
          }
          else
          {
            WaitingTrailingZeroEdge = true;
          }
          break;

        case BITISLONG:
          if (WaitingTrailingZeroEdge)
          { //shouldn't get a long pulse when waiting for the second short pulse (i.e. expecting bit = 0)
            //try to resync from here?
            if (BitCount >= EXPECTEDBITCOUNT)
            {
              ConversionFinished = true;
              break;
            }
            BitIndex = 0;
            BitCount = 0;
            WaitingTrailingZeroEdge = false;
            //CheckIndex--;  //recheck this entry
            //Retry from the start with an offset to resync
            Offset++;
            CheckIndex = Offset;
            StartDataIndex = CheckIndex;
          }
          else
          {
            //BitTimings[BitIndex] = BitWidth;
            IncomingBits[BitIndex++] = 1;
            BitCount++;
          }
          break;

        case BITISSYNC:
          if (BitCount >= EXPECTEDBITCOUNT)
          {
            ConversionFinished = true;
            break;
          }
          BitIndex = 0;
          BitCount = 0;
          WaitingTrailingZeroEdge = false;
          StartDataIndex = CheckIndex + 1;
          Offset = StartDataIndex;
          break;
      }
      CheckIndex++;
    }




  if (BitCount >= EXPECTEDBITCOUNT)
  {
     int Attempts = BitCount - EXPECTEDBITCOUNT+1;
     int StartPoint = 0;  //shift start point

     //keep shifting the data until a valid checksum or run out of data...
     do
     {
        ByteCount = DecodeBitArray(StartPoint,6);  //shifted right by 6 bits in DecodeBitArray to give integral number of bytes (for checksum)
        crcResult = 0xFF;  //ensure crcResult != RXBytes[8] if ByteCount < EXPECTEDBYTECOUNT (DecodeBitArray clears the RX buffer to 0x00)
        if (ByteCount >= EXPECTEDBYTECOUNT)
        {
           crcResult = Compute_CRC8(8,0x13, 0x00);
        }
      
        Attempts--;
        StartPoint++;  

     } while((crcResult != RXBytes[8]) && (Attempts > 0));

      //ByteCount = DecodeBitArray(ShiftPlaces);

      //crcResult = Compute_CRC8(8,0x13, 0x00);

      if (crcResult != RXBytes[8])
      {
         #ifdef SHOWDEBUGINFO
          Serial.print(F("CRC calc: "));
          Serial.println(crcResult, HEX);
          Serial.print(F("  CRC rcvd: "));
          Serial.println(RXBytes[8], HEX);
          Serial.println(F("CRC Check failed"));
        #endif
        //PrintData(BitCount);
        #ifdef IGNORECHECKSUMERRORS
          DecodeTPMS();
          TPMS_Changed = false;  //don't update display for csum error
        #endif
      }
      else
      {
        //decode the message...
        Serial.println(F("CRC Check OK"));
        
        DecodeTPMS();
        TPMS_Changed = true;  //indicates the display needs to be updated.
      }

    
      return(true);
  }
  else
  {
    return(false);
  }
  
}

Toyota_PMV_C210

C Header File
//Toyota Corolla (2019-22 PMV-C215 sensor)
//Toyota CHR (2020 PMV_C215 sensor)


#ifdef UK_433MHz


    #define EXPECTEDBITCOUNT 72
    #define EXPECTEDBYTECOUNT 9
    #define SYNCBITS 11
  
    #define CDWIDTH_MIN 5500
    #define CDWIDTH_MAX 10500 //10500
  
    #define SHORTTIMING_MIN 40
    #define SHORTTIMING_NOM 50
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 175
    #define SYNCTIMING_MAX 1200
  
    #define ENDTIMING_MIN  0
    #define ENDTIMING_MAX  500


    #define CC1101_DEFVAL_IOCFG2     0x0C        // GDO2 Output Pin Configuration - Serial out (synchronous)
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x12 //0x30        // Packet Automation Control - synchronous data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 433.919830 MHz
    #define CC1101_DEFVAL_FREQ2  0x10        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1  0xB0        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0  0x71        // Frequency Control Word, Low Byte

    #define CC1101_DEFVAL_DEVIATN    0x40      // Modem Deviation Setting (+/-25.390625kHz)

    #define CC1101_DEFVAL_MDMCFG4    0x59        // Modem Configuration (59 = data rate = 20kHz - actual data rate is 10kHz but due to bi-phase coding need to double the rate, RX bandwidth 325kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
    #define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
    
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration

    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings



      
 
#elif US_315MHz


    //these 315MHz timings are guesses and not proven
    
    #define EXPECTEDBITCOUNT 72
    #define EXPECTEDBYTECOUNT 9
    #define SYNCBITS 11
    
    #define CDWIDTH_MIN 5500
    #define CDWIDTH_MAX 10500
    
    #define SHORTTIMING_MIN 40
    #define SHORTTIMING_NOM 50
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 175
    #define SYNCTIMING_MAX 1200
    
    #define ENDTIMING_MIN  0
    #define ENDTIMING_MAX   500


    #define CC1101_DEFVAL_IOCFG2     0x0C        // GDO2 Output Pin Configuration - Serial out (synchronous)
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x12 //0x30        // Packet Automation Control - synchronous data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 314.979828 MHz
    #define CC1101_DEFVAL_FREQ2  0x0C        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1  0x1D        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0  0x57        // Frequency Control Word, Low Byte
      
    #define CC1101_DEFVAL_DEVIATN    0x40      // Modem Deviation Setting (+/-25.390625kHz)

    #define CC1101_DEFVAL_MDMCFG4    0x59        // Modem Configuration (59 = data rate = 20kHz - actual data rate is 10kHz but due to bi-phase coding need to double the rate, RX bandwidth 101.562500kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
    #define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
    
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration

    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings


#endif

void DecodeTPMS()
{
  int16_t i;
  uint32_t id = 0;
  uint16_t status, pressure1, pressure2, temp;
  double realpressure;
  float realtemp;


  for (i = 0; i < 4; i++)
  {
    id = id << 8;
    id = id + RXBytes[i];

  }

  id = id & 0xFFFFFFF;

  GetPreferredIndexStr(id, Ref);

  // id = (unsigned)RXBytes[0] << 24 | RXBytes[1] << 16 | RXBytes[2] << 8 | RXBytes[3];

  status = (RXBytes[4] & 0x80) | (RXBytes[6] & 0x7f); // status bit and 0 filler

  pressure1 = (RXBytes[4] & 0x7f) << 1 | RXBytes[5] >> 7;

  temp = (RXBytes[5] & 0x7f) << 1 | RXBytes[6] >> 7;

  pressure2 = RXBytes[7] ^ 0xff;



  if (pressure1 != pressure2)
  {
    Serial.println(F("Pressure check mis-match"));
    return;
  }

  realpressure = (double)pressure1;
  realpressure = (realpressure * 0.25) - 7.35;
  if (realpressure < 0) 
     realpressure = 0.0;
  realtemp = (float)temp;
  realtemp = realtemp - 40.0;
//#ifdef DISPLAY_TEMP_AS_FAHRENHEIT
//  realtemp = ((realtemp * 9.0)/5.0) + 32.0;
//#endif


#ifdef SHOWVALIDTPMS
  Serial.print(F("Pos: "));
  Serial.print(Ref);
  Serial.print(F("   ID: "));
  Serial.print(id, HEX);
  Serial.print(F("   Status: 0x"));
  Serial.print(status,HEX);
  Serial.print(F("   Temperature: "));
  Serial.print(realtemp);
  Serial.print(F("   Tyre Pressure: "));
  Serial.print(realpressure);
  Serial.print(F(" (psi)  "));
  Serial.print(realpressure/PSI2BAR);
  Serial.print(F(" (bar)"));
  Serial.println(F(""));
#endif

  //DisplayStatusInfo();

  MatchIDandUpdate(id,status, realtemp, realpressure);

//  //update the array of tyres data
//  for (i = 0; i < TYRECOUNT; i++)
//  { //find a matching ID if it already exists
//    if (id == TPMS[i].TPMS_ID)
//    {
//      UpdateTPMSData(i, id, status, realtemp, realpressure);
//      IDFound = true;
//      break;
//    }
//
//  }
//
//  //no matching IDs in the array, so see if there is an empty slot to add it into, otherwise, ignore it.
//  if (IDFound == false)
//  {
//
//    prefindex = GetPreferredIndex(id);
//    if (prefindex == -1)
//    { //not found a specified index, so use the next available one..
//      #ifndef SPECIFIC_IDS_ONLY 
//        for (i = 0; i < TYRECOUNT; i++)
//        {
//          if (TPMS[i].TPMS_ID == 0)
//          {
//            UpdateTPMSData(i, id, status, realtemp, realpressure);
//            break;
//          }
//        }
//      #endif
//    }
//    else
//    { //found a match in the known ID list...
//      UpdateTPMSData(prefindex, id, status, realtemp, realpressure);
//    }
//
//  }


  #ifdef SHOWVALIDTPMS
     Serial.println(F(""));
  #endif


  //UpdateDisplay();
}










bool ValidateTimings()
{

  //uint16_t BitWidth;
  uint16_t diff = TimingsIndex;
  //uint32_t tmp;
  bool WaitingTrailingZeroEdge = false;
  int16_t ret;
  uint8_t crcResult = 0;
  bool ConversionFinished = false;
  int16_t ByteCount = 0;
  int16_t Offset = 0;

  StartDataIndex = 0;

  if (diff < EXPECTEDBITCOUNT)
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
      Serial.print(F("Insufficient data in buffer ("));
      Serial.print(diff);
      Serial.println(F(")"));
    #endif
    return(false);
  }


  CheckIndex = 0;

  //while ((diff > 0) && (BitCount < EXPECTEDBITCOUNT))
  while ((diff > 0) && (BitCount < MAXBITS) && (ConversionFinished == false))
  { //something in buffer to process...
    diff = TimingsIndex - CheckIndex;

    //BitWidth = Timings[CheckIndex];



      ret = ValidateBit();
      switch (ret)
      {
        case BITISUNDEFINED:
          //invalid bit
          if (BitCount >= EXPECTEDBITCOUNT)
          {
            ConversionFinished = true;
            break;
          }
             
          BitIndex = 0;
          BitCount = 0;
          WaitingTrailingZeroEdge = false;
          StartDataIndex = CheckIndex + 1;
          Offset = StartDataIndex;

          break;

        case BITISSHORT:
          if (WaitingTrailingZeroEdge)
          {
            //BitTimings[BitIndex] = BitWidth;
            IncomingBits[BitIndex++] = 0;
            BitCount++;
            WaitingTrailingZeroEdge = false;
          }
          else
          {
            WaitingTrailingZeroEdge = true;
          }
          break;

        case BITISLONG:
          if (WaitingTrailingZeroEdge)
          { //shouldn't get a long pulse when waiting for the second short pulse (i.e. expecting bit = 0)
            //try to resync from here?
            if (BitCount >= EXPECTEDBITCOUNT)
            {
              ConversionFinished = true;
              break;
            }
            BitIndex = 0;
            BitCount = 0;
            WaitingTrailingZeroEdge = false;
            //CheckIndex--;  //recheck this entry
            //Retry from the start with an offset to resync
            Offset++;
            CheckIndex = Offset;
            StartDataIndex = CheckIndex;
          }
          else
          {
            //BitTimings[BitIndex] = BitWidth;
            IncomingBits[BitIndex++] = 1;
            BitCount++;
          }
          break;

        case BITISSYNC:
          if (BitCount >= EXPECTEDBITCOUNT)
          {
            ConversionFinished = true;
            break;
          }
          BitIndex = 0;
          BitCount = 0;
          WaitingTrailingZeroEdge = false;
          StartDataIndex = CheckIndex + 1;
          Offset = StartDataIndex;
          break;
      }
      CheckIndex++;
    }




  if (BitCount >= EXPECTEDBITCOUNT)
  {
     int Attempts = BitCount - EXPECTEDBITCOUNT+1;
     int StartPoint = 0;  //shift start point

     //keep shifting the data until a valid checksum or run out of data...
     do
     {
        ByteCount = DecodeBitArray(StartPoint, 0);
        if (ByteCount >= EXPECTEDBYTECOUNT)
        {
          crcResult = Compute_CRC8(8,0x7, 0x80);
        
          Attempts--;
          StartPoint++; 
        } 

     } while((crcResult != RXBytes[8]) && (Attempts > 0) && (ByteCount >= EXPECTEDBYTECOUNT));


      if (crcResult != RXBytes[8])
      {
         #ifdef SHOWDEBUGINFO
          Serial.print(F("CRC calc: "));
          Serial.println(crcResult, HEX);
          Serial.print(F("  CRC rcvd: "));
          Serial.println(RXBytes[8], HEX);
          Serial.println(F("CRC Check failed"));
        #endif
        //PrintData(BitCount);
        #ifdef IGNORECHECKSUMERRORS
          DecodeTPMS();
          TPMS_Changed = false;  //don't update display for csum error
        #endif
      }
      else
      {
        //decode the message...
        Serial.println(F("CRC Check OK"));
        
        DecodeTPMS();
        TPMS_Changed = true;  //indicates the display needs to be updated.
      }

    
      return(true);
  }
  else
  {
    return(false);
  }
  
}

Renault

C Header File
#ifdef UK_433MHz



  #ifndef Zoe
    #define EXPECTEDBITCOUNT 72
    #define EXPECTEDBYTECOUNT 9
    
    #define SYNCBITS 16
    
    #define CDWIDTH_MIN 7000
    #define CDWIDTH_MAX 11500
    
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 175
    #define SYNCTIMING_MAX 1200
    
    #define ENDTIMING_MIN  0
    #define ENDTIMING_MAX   500


    #define CC1101_DEFVAL_IOCFG2     0x0C        // GDO2 Output Pin Configuration - Serial out (synchronous)
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    //#define CC1101_DEFVAL_IOCFG0     0x0D        // GDO0 Output Pin Configuration
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x12 //0x30        // Packet Automation Control - synchronous data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 433.919830 MHz
    #define CC1101_DEFVAL_FREQ2  0x10        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1  0xB0        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0  0x0C        // Frequency Control Word, Low Byte

    #define CC1101_DEFVAL_DEVIATN    0x41      // Modem Deviation Setting 

    #define CC1101_DEFVAL_MDMCFG4    0x59        // Modem Configuration (59 = data rate = 20kHz - actual data rate is 10kHz but due to bi-phase coding need to double the rate, RX bandwidth 325kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
    #define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
    
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration

    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings

  #else
  //Renault Zoe...
    #define EXPECTEDBITCOUNT 64
    #define EXPECTEDBYTECOUNT 8
    
    #define SYNCBITS 16
    
    #define CDWIDTH_MIN 7000
    #define CDWIDTH_MAX 11500
    
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 175
    #define SYNCTIMING_MAX 1200
    
    #define ENDTIMING_MIN  0
    #define ENDTIMING_MAX   500


    #define CC1101_DEFVAL_IOCFG2     0x0C        // GDO2 Output Pin Configuration - Serial out (synchronous)
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    //#define CC1101_DEFVAL_IOCFG0     0x0D        // GDO0 Output Pin Configuration
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x12 //0x30        // Packet Automation Control - synchronous data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 433.919830 MHz
    #define CC1101_DEFVAL_FREQ2  0x10        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1  0xB0        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0  0x0C        // Frequency Control Word, Low Byte

    #define CC1101_DEFVAL_DEVIATN    0x41      // Modem Deviation Setting 

    #define CC1101_DEFVAL_MDMCFG4    0x59        // Modem Configuration (59 = data rate = 20kHz - actual data rate is 10kHz but due to bi-phase coding need to double the rate, RX bandwidth 325kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
    #define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
    
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration

    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings



  #endif

      
 
#elif US_315MHz


   #error Renault timings not defined for 315MHz


#endif


void DecodeTPMS()
{
  int16_t i;
  uint32_t id = 0;
  uint16_t status, pressure1, pressure2, temp;
  double realpressure;
  float realtemp;




  #ifdef Zoe
    for (i = 0; i <= 2; i++)
    {
      id = id << 8;
      id = id + RXBytes[i];
  
    }
  #else
    for (i = 5; i >= 3; i--)
    {
      id = id << 8;
      id = id + RXBytes[i];
  
    }
  #endif



  // id = (unsigned)RXBytes[0] << 24 | RXBytes[1] << 16 | RXBytes[2] << 8 | RXBytes[3];
  GetPreferredIndexStr(id, Ref);

  #ifdef Zoe
     status = (((uint16_t)RXBytes[3]) << 8) | RXBytes[6];
     pressure1 = RXBytes[4] ;
     temp = RXBytes[5];
     pressure2 = pressure1;
     realpressure = (double)pressure1;
     realpressure = realpressure * 0.2;  //psi
     realtemp = (float)temp;
     realtemp = realtemp - 50.0;
  #else
     status = RXBytes[0] >> 2;
     pressure1 = (RXBytes[0] & 0x03)  << 8 | RXBytes[1];
     temp = RXBytes[2];
     pressure2 = pressure1;
     realpressure = (double)pressure1;
     realpressure = realpressure * 0.75;  //kpa
     realpressure = realpressure * 0.145038;  //psi
     realtemp = (float)temp;
     realtemp  = realtemp - 30.0;
  #endif

  if (pressure1 != pressure2)
  {
    #ifdef SHOWDEBUGINFO
       Serial.println(F("Pressure check mis-match"));
    #endif
    return;
  }

//  #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
//     realtemp = ((realtemp * 9.0)/5.0) + 32.0;
//  #endif

#ifdef SHOWVALIDTPMS
  Serial.print(F("Pos: "));
  Serial.print(Ref);
  Serial.print(F("   ID: "));
  Serial.print(id, HEX);
  #ifdef Zoe
     Serial.print(F("   Status?????: 0x"));
  #else
     Serial.print(F("   Status: 0x"));
  #endif
  Serial.print(status,HEX);
  Serial.print(F("   Temperature: "));
  Serial.print(realtemp);
  Serial.print(F("   Tyre Pressure: "));
  Serial.print(realpressure);
  Serial.println(F(""));
#endif

  //DisplayStatusInfo();


  MatchIDandUpdate(id,status, realtemp, realpressure);



  #ifdef SHOWVALIDTPMS
     Serial.println(F(""));
  #endif


  //UpdateDisplay();
}




void ConvertTimingsToBits()
{
   int16_t i;
   
   //bool CurrentState = FirstEdgeState;
   bool CurrentState = FirstEdgeIsHighToLow?true:false;
   BitCount = 0;
   

   for (i=0;i<= TimingsIndex;i++)
   {
      if (IsValidShort(Timings[i]) )
      {
         IncomingBits[BitCount++] = CurrentState;
      }
      else
      {
        if (IsValidLong(Timings[i]) )
        {
           IncomingBits[BitCount++] = CurrentState;
           IncomingBits[BitCount++] = CurrentState;
        }
        else
        {
          if (IsTooShort(Timings[i] ) || IsTooLong(Timings[i] ) )
          {
            
             if (i < TimingsIndex/2)  //enough bits in the buffer to continue trying?
             { //invalid bit timing, reset
                 
                 BitCount = 0;
             }
             else
             {// end the conversion
                //assume an end bit
                if (IsTooLong(Timings[i]) )
                {
                  IncomingBits[BitCount++] = CurrentState;
                }
//                #ifdef SHOWDEBUGINFO
//                   Serial.print(F("ConvertTimingsToBits exited at index: "));
//                   Serial.print(i);
//                   Serial.print(F(" bitcount: "));
//                   Serial.print(BitCount);
//                   Serial.print(F("  Timing value = "));
//                   Serial.println(Timings[i]);
//                #endif
                return;
             }
          }
        }
      }
      CurrentState = !CurrentState;

      if (BitCount >= MAXBITS-1) 
      {
         #ifdef SHOWDEBUGINFO
            Serial.println(F("Exited ConvertTimingsToBits with botcount > MAXBITS-1"));
         #endif
         return;
      }
   }
  
}



bool ValidateTimings()
{

  int16_t ManchesterStartPos = -1;
  uint8_t ByteCount = 0;
  uint8_t crcResult;

  StartDataIndex = 0;

  if (TimingsIndex < (SYNCBITS + EXPECTEDBITCOUNT) ) //header + valid data (minimum)
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
       Serial.println(F("Insufficient data in buffer"));
    #endif
    return (false);
  }

  if (TimingsIndex > 200)  //header + valid data (minimum)
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
       Serial.println(F("Excessive data in buffer"));
    #endif
    return (false);
  }

  //Serial.print("Timings index = ");
  //Serial.println(TimingsIndex);

  ConvertTimingsToBits();

  InvertBitBuffer();
  
  const uint8_t pattern[] = {0xAA, 0xA9}; 
  ManchesterStartPos = FindManchesterStart(pattern,16 );
  StartDataIndex = ManchesterStartPos;

  if (ManchesterStartPos == -1 )
  {
    InvertBitBuffer();
    ManchesterStartPos = FindManchesterStart(pattern,16 );
    StartDataIndex = ManchesterStartPos;
  
    if (ManchesterStartPos == -1 )
    {    
      #ifdef SHOWDEBUGINFO
         Serial.println(F("Renault header not found"));
      #endif
      return (false);   
    }
  }

  ByteCount = ManchesterDecode(ManchesterStartPos);
  if (ByteCount >= EXPECTEDBYTECOUNT)
  {
      
      //check the checksum...
      #ifdef Zoe
         crcResult = Compute_CRC_XOR(0,EXPECTEDBYTECOUNT, 0x00);
      #else
         crcResult = Compute_CRC8(EXPECTEDBYTECOUNT, 0x07, 0x00);
      #endif
      if (crcResult != 0)
      {
        #ifdef SHOWDEBUGINFO
           Serial.println(F("CRC Check failed"));
        #endif
        #ifdef IGNORECHECKSUMERRORS
          DecodeTPMS();
          TPMS_Changed = false;  //don't update display for csum error
        #endif
        return(false);
      }
      else
      {
         #ifdef SHOWDEBUGINFO
           Serial.println(F("CRC Check OK"));
         #endif
        //decode the message...
        DecodeTPMS();
        TPMS_Changed = true;  //indicates the display needs to be updated.
        return(true);
      }


  }
  else
  {
    #ifdef SHOWDEBUGINFO
       Serial.print(F("Insufficient bytes: "));
       Serial.print(ByteCount);
       Serial.print(F(" received, expected at least: "));
       Serial.println(EXPECTEDBYTECOUNT);
       PrintTimings(0,ByteCount * 8);
    #endif
    return (false);
  }


}

Citroen

C Header File
      
     
#ifdef UK_433MHz



    #define EXPECTEDBITCOUNT 80
    #define EXPECTEDBYTECOUNT 10
    
    #define SYNCBITS 16
    
    #define CDWIDTH_MIN 8000
    #define CDWIDTH_MAX 11500
    
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 175
    #define SYNCTIMING_MAX 1200
    
    #define ENDTIMING_MIN  0
    #define ENDTIMING_MAX  500


    #define CC1101_DEFVAL_IOCFG2     0x0C        // GDO2 Output Pin Configuration - Serial out (synchronous)
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x12 //0x30        // Packet Automation Control - synchronous data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 433.919830 MHz
    #define CC1101_DEFVAL_FREQ2  0x10        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1  0xB0        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0  0x71        // Frequency Control Word, Low Byte

    #define CC1101_DEFVAL_DEVIATN    0x40      // Modem Deviation Setting (+/-25.390625kHz)

    #define CC1101_DEFVAL_MDMCFG4    0x59        // Modem Configuration (59 = data rate = 20kHz - actual data rate is 10kHz but due to bi-phase coding need to double the rate, RX bandwidth 325kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
    #define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
    
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration

    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings



      
 
#elif US_315MHz


         #error Citroen timings not defined for 315MHz


#endif      



void DecodeTPMS()
{
  int16_t i;
  uint32_t id = 0;
  uint16_t status, state, pressure1, pressure2, temp, flags, repeat, battery;
  double realpressure;
  float realtemp;


  

  for (i = 1; i <= 4; i++)
  {
    id = id << 8;
    id = id + RXBytes[i];

  }

  // id = (unsigned)RXBytes[0] << 24 | RXBytes[1] << 16 | RXBytes[2] << 8 | RXBytes[3];
  GetPreferredIndexStr(id, Ref);
  
  state = RXBytes[0];

  pressure1 = RXBytes[6];

  temp = RXBytes[7];

  pressure2 = pressure1;

  battery = RXBytes[8];
  status = RXBytes[5];
  flags = RXBytes[5] >>4;
  repeat = RXBytes[5] & 0x0F;



  if (pressure1 != pressure2)
  {
    Serial.println(F("Pressure check mis-match"));
    return;
  }

  realpressure = (double)pressure1;
  realpressure = realpressure * 1.364;  //kpa
  realpressure = realpressure * 0.145038;  //psi
  realtemp = (float)temp;
  realtemp = realtemp - 50.0;
//  #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
//     realtemp = ((realtemp * 9.0)/5.0) + 32.0;
//  #endif
  
#ifdef SHOWVALIDTPMS
  Serial.print(F("Pos: "));
  Serial.print(Ref);
  Serial.print(F("   ID: "));
  Serial.print(id, HEX);
  Serial.print(F("   State: 0x"));
  Serial.print(state,HEX);
  Serial.print(F("   Status: 0x"));
  Serial.print(status,HEX);
  Serial.print(F("   ["));
  Serial.print(F("Flags: 0x"));
  Serial.print(flags,HEX);
  Serial.print(F("   Repeat: "));
  Serial.print(repeat);
  Serial.print(F("]"));
  Serial.print(F("   Battery(?): "));
  Serial.print(battery);
  Serial.print(F("   Temperature: "));
  Serial.print(realtemp);
  Serial.print(F("   Tyre Pressure: "));
  Serial.print(realpressure);
  Serial.println(F(""));
#endif

  //DisplayStatusInfo();

   MatchIDandUpdate(id,status, realtemp, realpressure);
   
  #ifdef SHOWVALIDTPMS
     Serial.println(F(""));
  #endif


  //UpdateDisplay();
}








void ConvertTimingsToBits()
{
   int16_t i;
   
   //bool CurrentState = FirstEdgeState;
   bool CurrentState = FirstEdgeIsHighToLow?true:false;
   BitCount = 0;
   

   for (i=0;i<= TimingsIndex;i++)
   {
      if (IsValidShort(Timings[i]) )
      {
         IncomingBits[BitCount++] = CurrentState;
      }
      else
      {
        if (IsValidLong(Timings[i]) )
        {
           IncomingBits[BitCount++] = CurrentState;
           IncomingBits[BitCount++] = CurrentState;
        }
        else
        {
          if (IsTooShort(Timings[i] ) || IsTooLong(Timings[i] ) )
          {
            
             if (i < TimingsIndex/2)  //enough bits in the buffer to continue trying?
             { //invalid bit timing, reset
               
                 BitCount = 0;
             }
             else
             {// end the conversion
                return;
             }
          }
        }
      }
      CurrentState = !CurrentState;

      if (BitCount >= MAXBITS-1) 
      {
         return;
      }
   }
  
}




bool ValidateTimings()
{



  int16_t ManchesterStartPos = -1;
  uint8_t ByteCount = 0;
  uint8_t crcResult = 0;

  StartDataIndex = 0;

  if (TimingsIndex < (SYNCBITS + EXPECTEDBITCOUNT) )  //header + valid data (minimum)
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
       Serial.println(F("Insufficient data in buffer"));
    #endif
    return(false);
  }

  if (TimingsIndex > 200)  //header + valid data (minimum)
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
       Serial.println(F("Excessive data in buffer"));
    #endif
    return(false);
  }

  //Serial.print("Timings index = ");
  //Serial.println(TimingsIndex);

  ConvertTimingsToBits();

  //InvertBitBuffer();

  const uint8_t pattern[] = {0xAA, 0xA9};
  ManchesterStartPos = FindManchesterStart(pattern, 16);
  StartDataIndex = ManchesterStartPos;

  if (ManchesterStartPos == -1 )
  {
    #ifdef SHOWDEBUGINFO
       Serial.println(F("Citroen header not found"));
    #endif

    return(false);   
//  }
//  else
//  {
//     #ifdef SHOWDEBUGINFO
//       Serial.print("Timings index = ");
//       Serial.println(TimingsIndex);
//       Serial.print("CD Width = ");
//       Serial.println(CD_Width);
//       Serial.print("Bit count = ");
//       Serial.println(BitCount);
//       PrintTimings(0,TimingsIndex);
//       PrintData(BitCount);
//    #endif 
  }

  ByteCount = ManchesterDecode(ManchesterStartPos);
  if (ByteCount == EXPECTEDBYTECOUNT)
  {

       crcResult = Compute_CRC_XOR(1,10, 0x00);  //Checksum, XOR bytes 1 to 9 = 0
       if (crcResult != 0)
      {
         Serial.println(F("CRC Check failed"));
        #ifdef IGNORECHECKSUMERRORS
          DecodeTPMS();
          TPMS_Changed = false;  //don't update display for csum error
        #endif
        return(false);
      }
      else
      {
        Serial.println(F("CRC Check OK"));
        //decode the message...
        DecodeTPMS();
        TPMS_Changed = true;  //indicates the display needs to be updated.
        return(true);
      }
     
  }
  else
  {
    return(false);
  }


}

configs

C Header File
//Select the display type being used:
//#define USE_1_INCH_YB_I2C_DISPLAY 1
#define USE_2_INCH_ST7735_DISPLAY 1
//#define USE_2_INCH_ST7789_DISPLAY 1  //(round display)
//#define USE_24_INCH_ILI9341_DISPLAY 1


//Receive frequency
#define UK_433MHz 1
//#define US_315MHz 1

//Vehicle/sensor type
//#define Toyota_TRW_C070 1
#define Toyota_PMV_C210 1   //Toyota Auris, should also work for PMV-C010?? and PMV-C215 (Toyota Corolla)
//#define Hyundai_i35 1  //uses PMV-C210 sensor
//#define Schrader_C1100 1  //used on Hyundai Tucson TL/TLE 01/2015-12/2015
//#define Schrader_A9054100 1
//#define Toyota_PMV_107J 1   //used on Lexus RX series 07/2013-09/2015
//#define Renault 1
//#define Zoe 1   //for Renault Zoe 09/2012 to 06/2019 only (you must select 'Renault' define as well for this!)
//#define Dacia 1
//#define NissanLeaf 1
//#define Citroen 1
//#define PontiacG82009 1
//#define TruckSolar 1
//#define JansiteSolar 1 
//#define Subaru 1


//#define Ford 1

//Possible Ford variants..
//#define Ford_FSeries_SD 1
//#define Ford_FSeries_2006_2008 1
//#define Ford_ESeries_TEST 1
//#define Ford_OtherVariants 1



//#define Jansite 1  //requires bigger buffer sizes - won't work on ProMicro or Nano?
 


#ifdef Ford_FSeries_SD
   #define FordType 2
#elif Ford_FSeries_2006_2008
   #define FordType 1
#elif Ford_ESeries_TEST
   #define FordType 3
#else
   #define FordType 0
#endif



////#define INCLUDESPARETYRE 1    - nolonger used. If no spare with TPMS, just set the ID to 0xFFFFFFF
//#define INCLUDE_WINTER_SET 1

//Pressure display and limits units (default is PSI and deg C if these not set)
//#define DISPLAY_PRESSURE_AS_BAR 1
//#define DISPLAY_PRESSURE_AS_KPA 1
//#define DISPLAY_TEMP_AS_FAHRENHEIT 1  //if uncommented,temperature is displayed as deg F, otherwise displayed as deg C

#define ENABLE_PRESSURE_ALARMS 1
#define ENABLE_TEMPERATURE_ALARMS 1

#define ENABLE_AUDIBLE_ALARM 1

#define ENABLE_PRESSURE_ALARM_TEMPERATURE_COMPENSATION 1


#if defined(USE_2_INCH_ST7735_DISPLAY) || defined(USE_2_INCH_ST7789_DISPLAY) || defined(USE_1_INCH_YB_I2C_DISPLAY)  || defined(USE_24_INCH_ILI9341_DISPLAY)
   #define USE_LCDDISPLAY 1
#endif

//config checks...

#if defined(UK_433MHz) && defined(US_315MHz)
   #error Cannot define both 433MHz and 315MHz simultaneously
#endif

#if !defined(UK_433MHz) && !defined(US_315MHz)
   #error Must define either 433MHz or 315MHz
#endif


#if defined(USE_LCDDISPLAY) && (defined(USE_2_INCH_ST7735_DISPLAY) || defined(USE_2_INCH_ST7789_DISPLAY)  || defined(USE_24_INCH_ILI9341_DISPLAY)) && defined(ARDUINO_AVR_PROMICRO)
   #error ProMicro does not have enough memory for this display!
#endif

//tyre IDs for vehicle....(may need to prefix known IDs with leading 'F' to match reception)
  #define FRONT_LEFT  0x01721EB0L
  #define FRONT_RIGHT 0x0172221FL
  #define REAR_LEFT   0x0172223EL
  #define REAR_RIGHT  0x01721E9AL
  #define SPARE       0x01FFFFFFL
  #define WINTER_FRONT_LEFT  0x02721EB0L
  #define WINTER_FRONT_RIGHT 0x0272221FL
  #define WINTER_REAR_LEFT   0x0272223EL
  #define WINTER_REAR_RIGHT  0x02721E9AL
  #define WINTER_SPARE       0x0FFFFFFFL




int Ford_SensorType = FordType;  //3 different types seen, select 0,1,2 to match the pressure readings


//Settings for pressure and temperature limits (including Winter tyres if required). Used as flashing warnings on display and audible alarm if enabled in hardware
const float PressureLimitsTemperature = 20;
const  double PressureLowLimits[]
{
  30, 30, 
  30, 30,
  30
  #ifdef INCLUDE_WINTER_SET
    , 30, 30, 
    30, 30,
    30
  #endif
};

const double  PressureHighLimits[]
{
  33, 33, 
  33, 33,
  33
  #ifdef INCLUDE_WINTER_SET
    , 33, 33, 
    33, 33,
    33
  #endif
};

//set temperature limits to Fahrenheit or Centigrade depending on DISPLAY_TEMP_AS_FAHRENHEIT setting (will be converted to centigrade when loading if required)
const float  TemperatureLowLimits[]
{
  -10, -10, 
  -10, -10,
  -10
  #ifdef INCLUDE_WINTER_SET
    , -20, -20, 
    -20, -20,
    -20
  #endif
};

const float  TemperatureHighLimits[]
{
  33, 33, 
  33, 33,
  33
  #ifdef INCLUDE_WINTER_SET
    , 33, 33, 
    33, 33,
    33
  #endif
};

Ford

C Header File
#ifdef UK_433MHz

   

    #define EXPECTEDBITCOUNT 64
    #define EXPECTEDBYTECOUNT 8
    
    #define SYNCBITS 16
    
    #define CDWIDTH_MIN 5500
    #define CDWIDTH_MAX 10000
    
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 175
    #define SYNCTIMING_MAX 1200
    
    #define ENDTIMING_MIN  0
    #define ENDTIMING_MAX   500
    

    #define CC1101_DEFVAL_IOCFG2     0x0C        // GDO2 Output Pin Configuration - Serial out (synchronous)
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x12 //0x30        // Packet Automation Control - synchronous data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 433.919830 MHz
    #define CC1101_DEFVAL_FREQ2  0x10        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1  0xB0        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0  0x71        // Frequency Control Word, Low Byte

    #define CC1101_DEFVAL_DEVIATN    0x40      // Modem Deviation Setting (+/-25.390625kHz)

    #define CC1101_DEFVAL_MDMCFG4    0x59        // Modem Configuration (59 = data rate = 20kHz - actual data rate is 10kHz but due to bi-phase coding need to double the rate, RX bandwidth 325kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
    #define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
    
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration

    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings



      
 
#elif US_315MHz

    
    #define EXPECTEDBITCOUNT 64
    #define EXPECTEDBYTECOUNT 8
    
    #define SYNCBITS 16
    
    #define CDWIDTH_MIN 5500
    #define CDWIDTH_MAX 10000
    
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 175
    #define SYNCTIMING_MAX 1200
    
    #define ENDTIMING_MIN  0
    #define ENDTIMING_MAX   500
     

    #define CC1101_DEFVAL_IOCFG2     0x0C        // GDO2 Output Pin Configuration - Serial out (synchronous)
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x12 //0x30        // Packet Automation Control - synchronous data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 314.979828 MHz
    #define CC1101_DEFVAL_FREQ2  0x0C        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1  0x1D        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0  0x57        // Frequency Control Word, Low Byte
      
    #define CC1101_DEFVAL_DEVIATN    0x40      // Modem Deviation Setting (+/-25.390625kHz)

    #define CC1101_DEFVAL_MDMCFG4    0x59        // Modem Configuration (59 = data rate = 20kHz - actual data rate is 10kHz but due to bi-phase coding need to double the rate, RX bandwidth 101.562500kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
    #define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
    
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration

    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings


#endif

void DecodeTPMS()
{
  int16_t i;
  uint32_t id = 0;
  uint16_t status,  temp;
  uint16_t pressure1 = 0;
  double realpressure;
  float realtemp;
  uint8_t SensorType;


  for (i = 0; i <= 3; i++)
  {
    id = id << 8;
    id = id + RXBytes[i];

  }

  GetPreferredIndexStr(id, Ref);

  status = ((RXBytes[5]  & 0x7F) << 1) | (RXBytes[6] & 0xDF);





  SensorType = Ford_SensorType;

  switch (SensorType)
  {
     case 0:
           temp = RXBytes[5];
           realtemp = (float)temp;
           realtemp = realtemp - 56;
           realpressure =  ((double)RXBytes[4] * 0.25);  //psi  //Ford F-Series 01/2009-12/2014 (315MHz)
                                                                //Ford F-Series 01/2017-12/2020 (315MHz)
           break;
     case 1:
           temp = RXBytes[5];
           realtemp = (float)temp;
           realtemp = realtemp - 56;
           realpressure = ((double)RXBytes[4] * 0.45);  //psi //Ford F-Series SD 01/2009-05/2010 (315MHz)
           break;
     case 2:
           temp = RXBytes[5];
           realtemp = (float)temp;
           realtemp = realtemp - 56;
           realpressure = ((double)RXBytes[4] * 0.20);  //psi //Ford F-Series 01/2006-12/2008 (315MHz)
           break;
     case 3:  //test for Tom Logan
           if ((RXBytes[5] & 0xC0) == 0xC0)
           {
             //likely to be a count rather than temperature, so set temperature to absolute zero to denote invalid temperature..
             realtemp = NO_VALID_TEMPERATURE;              
           }
           else
           {
             temp = RXBytes[5];
             realtemp = (float)temp;
             realtemp = realtemp - 56;          
           }

           //changes to match E-seies results feedback (Tom Logan)
           if (RXBytes[6] & 0x20)
           {
              realpressure = ((double)RXBytes[4] * 0.25) + 58; //psi //try to fix for Tom Logan's E-series Schrader 29020 sensors
           }
           else
           {
              realpressure = ((double)RXBytes[4] * 0.25); //psi //try to fix for Tom Logan's E-series Schrader 29020 sensors
           }

           break;

     default:
           
           if (RXBytes[6] & 0x40)           // temperature scale mode?
           {
              temp = RXBytes[5] ^ 0x80;
           }
           else
           {
              temp = RXBytes[5];
           }
           realtemp = (float)temp;
           realtemp = realtemp - 56;

           
           pressure1 = ((RXBytes[6] & 0x20)  << 3) | RXBytes[4];  //as per RTL433 code
           if (pressure1 < 90)
           {
             realpressure = 0.3 + ((double)pressure1 * 0.25); 
           }
           else
           {
             realpressure = 6.8 + ((double)pressure1 * 0.2122727273);           
           }
           

           break;
  }
  if (realpressure < 0)
     realpressure = 0.0;




#ifdef SHOWVALIDTPMS
  Serial.print(F("Pos: "));
  Serial.print(Ref);
  Serial.print(F("   ID: "));
  Serial.print(id, HEX);
  Serial.print(F("   Status????: 0x"));
  Serial.print(status,HEX);
  Serial.print(F("   Temperature: "));
  if (realtemp == NO_VALID_TEMPERATURE)
  {
     Serial.print("---");
  }
  else
  {
     Serial.print(realtemp);
  }
  Serial.print(F("   Tyre Pressure????: "));
  Serial.print(realpressure);
  Serial.print(F("   Sensor type????: "));
  Serial.print(SensorType);
  Serial.print(F("   Byte 4 dec: "));
  Serial.print(RXBytes[4]);
  Serial.print(F("   Byte 4  hex: "));
  Serial.print(RXBytes[4], HEX);
  Serial.print(F("   Byte 5 dec: "));
  Serial.print(RXBytes[5]);
  Serial.print(F("   Byte 5  hex: "));
  Serial.print(RXBytes[5], HEX);
  Serial.print(F("   Byte 6 dec: "));
  Serial.print(RXBytes[6]);
  Serial.print(F("   Byte 6  hex: "));
  Serial.print(RXBytes[6], HEX);
//  Serial.print(F("   Pressure bits dec: "));
//  Serial.print(pressure1);
//  Serial.print(F("   Pressure bits hex: "));
//  Serial.print(pressure1, HEX);  
  Serial.println(F(""));
#endif

  //DisplayStatusInfo();

   MatchIDandUpdate(id,status, realtemp, realpressure);
   

  #ifdef SHOWVALIDTPMS
     Serial.println(F(""));
  #endif


  //UpdateDisplay();
}






void ConvertTimingsToBits()
{
   int16_t i;
   
   //bool CurrentState = FirstEdgeState;
   bool CurrentState = FirstEdgeIsHighToLow?true:false;
   BitCount = 0;
   

   for (i=0;i<= TimingsIndex;i++)
   {
      if (IsValidShort(Timings[i]) )
      {
         IncomingBits[BitCount++] = CurrentState;
      }
      else
      {
        if (IsValidLong(Timings[i]) )
        {
           IncomingBits[BitCount++] = CurrentState;
           IncomingBits[BitCount++] = CurrentState;
        }
        else
        {
          if (IsTooShort(Timings[i] ) || IsTooLong(Timings[i] ) )
          {
            
             if (i < TimingsIndex/2)  //enough bits in the buffer to continue trying?
             { //invalid bit timing, reset
                 
                 BitCount = 0;
             }
             else
             {// end the conversion
                //assume an end bit
                if (IsTooLong(Timings[i]) )
                {
                  IncomingBits[BitCount++] = CurrentState;
                }
//                #ifdef SHOWDEBUGINFO
//                   Serial.print(F("ConvertTimingsToBits exited at index: "));
//                   Serial.print(i);
//                   Serial.print(F(" bitcount: "));
//                   Serial.print(BitCount);
//                   Serial.print(F("  Timing value = "));
//                   Serial.println(Timings[i]);
//                #endif
                return;
             }
          }
        }
      }
      CurrentState = !CurrentState;

      if (BitCount >= MAXBITS-1) 
      {
         #ifdef SHOWDEBUGINFO
            Serial.println(F("Exited ConvertTimingsToBits with botcount > MAXBITS-1"));
         #endif
         return;
      }
   }
  
}



bool ValidateTimings()
{


  int16_t ManchesterStartPos = -1;
  uint8_t ByteCount = 0;
  uint8_t crcResult;

  StartDataIndex = 0;

  if (TimingsIndex < (SYNCBITS + EXPECTEDBITCOUNT) ) //header + valid data (minimum)
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
       Serial.println(F("Insufficient data in buffer"));
    #endif
    return (false);
  }

  if (TimingsIndex > 200)  //header + valid data (minimum)
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
       Serial.println(F("Excessive data in buffer"));
    #endif
    return (false);
  }

  //Serial.print("Timings index = ");
  //Serial.println(TimingsIndex);

  ConvertTimingsToBits();

  InvertBitBuffer();
   
  const uint8_t pattern[] = {0xAA, 0xA9};
  ManchesterStartPos = FindManchesterStart(pattern, 16);
  StartDataIndex = ManchesterStartPos;

  if (ManchesterStartPos == -1 )
  {
    //try with inverted data in case initial bit was read incorectly...
    InvertBitBuffer();
    ManchesterStartPos = FindManchesterStart(pattern, 16);
    StartDataIndex = ManchesterStartPos;
    if (ManchesterStartPos == -1 )
    {
       #ifdef SHOWDEBUGINFO
          Serial.println(F("Header not found"));
       #endif

       return (false);   
    } 
  }

  ByteCount = ManchesterDecode(ManchesterStartPos);
  if (ByteCount >= EXPECTEDBYTECOUNT)
  {
      
      //check the checksum...
      crcResult = Compute_CRC_SUM(0,7,  0x00);
      if (crcResult != RXBytes[7])
      {
         #ifdef SHOWDEBUGINFO
          Serial.print(F("CRC calc: "));
          Serial.print(crcResult, HEX);
          Serial.print(F("  CRC rcvd: "));
          Serial.println(RXBytes[7], HEX);
          Serial.println(F("CRC Check failed"));
        #endif
        #ifdef IGNORECHECKSUMERRORS
          DecodeTPMS();
          TPMS_Changed = false;  //don't update display for csum error
        #endif
        return(false);
      }
      else
      {
         #ifdef SHOWDEBUGINFO
           Serial.println(F("CRC Check OK"));
         #endif
        //decode the message...
        DecodeTPMS();
        TPMS_Changed = true;  //indicates the display needs to be updated.
        return(true);
      }


  }
  else
  {
    #ifdef SHOWDEBUGINFO
       Serial.print(F("Insufficient bytes: "));
       Serial.print(ByteCount);
       Serial.print(F(" received, expected at least: "));
       Serial.println(EXPECTEDBYTECOUNT);
       PrintTimings(0,ByteCount * 8);
    #endif
    return (false);
  }


}

Jansite

C Header File
#ifdef UK_433MHz


    #define EXPECTEDBITCOUNT 56
    #define EXPECTEDBYTECOUNT 7
    
    #define SYNCBITS 16
    
    #define CDWIDTH_MIN 28500
    #define CDWIDTH_MAX 31000
  
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 175
    #define SYNCTIMING_MAX 1200
    
    #define ENDTIMING_MIN  0
    #define ENDTIMING_MAX   500



    #define CC1101_DEFVAL_IOCFG2     0x0C        // GDO2 Output Pin Configuration - Serial out (synchronous)
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    #define CC1101_DEFVAL_IOCFG0     0x0E        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x0F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0xD5        // Synchronization word, high byte  11010101 01001111
    #define CC1101_DEFVAL_SYNC0      0x4F        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x09        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0x00        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x12 //0x30        // Packet Automation Control - synchronous data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x0F        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 433.919830 MHz
    #define CC1101_DEFVAL_FREQ2  0x10        // Frequency Control Word, High Byte
    #define CC1101_DEFVAL_FREQ1  0xB0        // Frequency Control Word, Middle Byte
    #define CC1101_DEFVAL_FREQ0  0x71        // Frequency Control Word, Low Byte

    #define CC1101_DEFVAL_DEVIATN    0x40      // Modem Deviation Setting (+/-25.390625kHz)

    #define CC1101_DEFVAL_MDMCFG4    0x59        // Modem Configuration (59 = data rate = 20kHz - actual data rate is 10kHz but due to bi-phase coding need to double the rate, RX bandwidth 325kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
    #define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
    
    #define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM1      0x3C        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_MCSM0      0x18        // Main Radio Control State Machine Configuration
    #define CC1101_DEFVAL_FOCCFG     0x16        // Frequency Offset Compensation Configuration
    #define CC1101_DEFVAL_BSCFG      0x6C        // Bit Synchronization Configuration

    
    #define CC1101_DEFVAL_WOREVT1    0x87        // High Byte Event0 Timeout
    #define CC1101_DEFVAL_WOREVT0    0x6B        // Low Byte Event0 Timeout
    #define CC1101_DEFVAL_WORCTRL    0xFB        // Wake On Radio Control
    #define CC1101_DEFVAL_FREND1     0x56        // Front End RX Configuration
    #define CC1101_DEFVAL_FREND0     0x10        // Front End TX Configuration
    
    #define CC1101_DEFVAL_FSCAL3     0xE9        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL2     0x2A        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL1     0x00        // Frequency Synthesizer Calibration
    #define CC1101_DEFVAL_FSCAL0     0x1F        // Frequency Synthesizer Calibration
    
    #define CC1101_DEFVAL_RCCTRL1    0x41        // RC Oscillator Configuration
    #define CC1101_DEFVAL_RCCTRL0    0x00        // RC Oscillator Configuration
    
    #define CC1101_DEFVAL_FSTEST     0x59        // Frequency Synthesizer Calibration Control
    
    #define CC1101_DEFVAL_PTEST      0x7F        // Production Test
    #define CC1101_DEFVAL_AGCTEST    0x3F        // AGC Test
    
    #define CC1101_DEFVAL_TEST2      0x81        // Various Test Settings
    #define CC1101_DEFVAL_TEST1      0x35        // Various Test Settings
    #define CC1101_DEFVAL_TEST0      0x09        // Various Test Settings



      
 
#elif US_315MHz


  #error Jansite timings not defined for 315MHz

#endif


void DecodeTPMS()
{
  int16_t i;
  uint32_t id = 0;
  uint16_t status, pressure1, pressure2, temp;
   double realpressure;
  float realtemp;



  for (i = 0; i <= 3; i++)
  {
    id = id << 8;
    id = id + RXBytes[i];

  }
  id = (id >> 4) & 0xFFFFFFFL;
  GetPreferredIndexStr(id, Ref);

  // id = (unsigned)RXBytes[0] << 24 | RXBytes[1] << 16 | RXBytes[2] << 8 | RXBytes[3];

  status = RXBytes[3] & 0x0F;

  pressure1 = RXBytes[4];

  temp = RXBytes[5];

  pressure2 = pressure1;



  if (pressure1 != pressure2)
  {