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 hours59,512
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)
  {
    #ifdef SHOWDEBUGINFO
       Serial.println(F("Pressure check mis-match"));
    #endif
    return;
  }

  realpressure = (double)pressure1;
  realpressure = realpressure * 1.7;  //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
  
  //realtemp = (temp - 32.0) * 0.5555556;

#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.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;
  int8_t ByteCount = 0;
  int8_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,0xAA, 0xA9};
  ManchesterStartPos = FindManchesterStart(pattern, 24);
  if (ManchesterStartPos < 0) ManchesterStartPos = 0;
  StartDataIndex = ManchesterStartPos ;


  if (ManchesterStartPos == -1 )
  {
    #ifdef SHOWDEBUGINFO
       Serial.println(F("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)
  {
      
      //checksum not yet worked out
      crcResult = Compute_CRC_SUM(0, 6,  0x00);
      //if (crcResult != RXBytes[6])
      if (crcResult != crcResult)
      {
         #ifdef SHOWDEBUGINFO
          Serial.print(F("CRC calc: "));
          Serial.print(crcResult, HEX);
          Serial.print(F("  CRC rcvd: "));
          Serial.println(RXBytes[6], HEX);
          Serial.println(F("CRC Check failed"));
          PrintBytes(7);
          #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 Not Implemented!"));
         #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);
  }


}

JansiteSolar

C Header File
#ifdef UK_433MHz

    
    #define EXPECTEDBITCOUNT 88
    #define EXPECTEDBYTECOUNT 11
    
    #define SYNCBITS 24
    
    #define CDWIDTH_MIN 18500
    #define CDWIDTH_MAX 25000
    
    #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 Solar 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 = 2; i <= 4; 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[5] & 0x0F;

  pressure1 = RXBytes[7];

  temp = RXBytes[6];

  pressure2 = pressure1;



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

  realpressure = (double)pressure1;
  realpressure = realpressure * 1.6;  //kpa
  realpressure = realpressure * 0.145038;  //psi

  realtemp = (float)temp;
  realtemp = realtemp - 55.0;
//  #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
//     realtemp = ((realtemp * 9.0)/5.0) + 32.0;
//  #endif  
  //realtemp = (temp - 32.0) * 0.5555556;

#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.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;
  uint16_t crcResult16;
  uint16_t ReceivedCRC;

  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[] = {0xA6,0xA6, 0x5A};
  const uint8_t pattern[] = {0x59,0x59, 0xA5};
  ManchesterStartPos = FindManchesterStart(pattern, 24) - 24;
  if (ManchesterStartPos < 0) ManchesterStartPos = 0;
  
  StartDataIndex = ManchesterStartPos;

  if (ManchesterStartPos == -1 )
  {
    #ifdef SHOWDEBUGINFO
       Serial.println(F("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)
  {
      if ((RXBytes[0] != 0xDD) || (RXBytes[1] != 0x33))
      {
          #ifdef SHOWDEBUGINFO
            Serial.print(F("Sync Check failed: Expected 0xDD 0x33, received 0x"));
            Serial.print(RXBytes[0], HEX);
            Serial.print(F(" 0x"));
            Serial.println(RXBytes[1], HEX);
            PrintBytes(ByteCount);
          #endif
          return(false);        
      }
      
      
      //check the checksum...
      ReceivedCRC = (( uint16_t)RXBytes[9] << 8) | ( uint16_t)RXBytes[10];

      crcResult16 = Compute_CRC16(2,7,0x8005,0x0000  );
      if (ReceivedCRC != crcResult16)
      {
         #ifdef SHOWDEBUGINFO
          Serial.print(F("CRC calc: "));
          Serial.print(crcResult16, HEX);
          Serial.print(F("  CRC rcvd: "));
          Serial.println(ReceivedCRC, HEX);
          Serial.println(F("CRC Check failed"));
          PrintBytes(ByteCount);
          #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);
  }


}

bitmap

C Header File
Background car image used on ST7735 display
// '128x60 car', 160x128px
const unsigned char car_bmp_128x60_car [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xff, 0x20, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0xff, 0xc8, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x04, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x18, 0x7f, 0xff, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 
  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x5f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9f, 0xff, 0xdf, 0xd0, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0xff, 0xef, 
  0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x7e, 0xff, 0xff, 0xf7, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xf7, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0xff, 0xff, 0xff, 
  0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 
  0x7f, 0xff, 0xff, 0xff, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x1f, 0x7f, 0xff, 0xff, 0xff, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0xff, 0xff, 0xff, 0xf7, 0xc0, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0xff, 0xff, 0xff, 
  0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 
  0x7f, 0xff, 0xff, 0xff, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x1f, 0x7f, 0xff, 0xff, 0xff, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0xf0, 0x00, 0xff, 0xf7, 0xc0, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0xc0, 0x00, 0x3f, 
  0xe7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 
  0x7f, 0x00, 0x00, 0x0f, 0xe7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x03, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x01, 0xf7, 0xc0, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x78, 0x00, 0x00, 0x01, 
  0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x78, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, 
  0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x7c, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x7c, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x01, 
  0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 
  0xec, 0x00, 0x00, 0x03, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x02, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x66, 0x00, 0x00, 0x06, 0x7e, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0xff, 0xff, 0xfe, 
  0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x67, 0xff, 0xff, 0xfe, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x63, 0xff, 0xff, 0xfe, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xff, 0xff, 0xfe, 0x70, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xff, 0xff, 0xfe, 
  0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x63, 0xff, 0xff, 0xfc, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x63, 0xff, 0xff, 0xfc, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xff, 0xff, 0xfc, 0x70, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xff, 0xff, 0xfc, 
  0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x63, 0xff, 0xff, 0xfc, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x63, 0xff, 0xff, 0xfc, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xff, 0xff, 0xfc, 0x70, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xff, 0xff, 0xfc, 
  0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x63, 0xff, 0xff, 0xfc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x61, 0xff, 0xff, 0xfc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0xff, 0xff, 0xf8, 0x60, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0xff, 0xff, 0xf8, 
  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xe3, 0xff, 0xff, 0xfc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xe3, 0xff, 0xff, 0xfc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xff, 0xff, 0xfc, 0x60, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xff, 0xff, 0xfc, 
  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 
  0x63, 0xff, 0xff, 0xfc, 0x67, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x1f, 0x73, 0xff, 0xff, 0xfc, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7b, 0xff, 0xff, 0xfd, 0xf7, 0xc0, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0xff, 0xff, 0xfd, 
  0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 
  0x7f, 0xff, 0xff, 0xff, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x1f, 0x7f, 0xff, 0xff, 0xff, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0x80, 0x00, 0x1f, 0xf7, 0xc0, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0x00, 0x00, 0x0f, 
  0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 
  0x7d, 0x00, 0x00, 0x09, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x1f, 0x7f, 0x00, 0x00, 0x0f, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0x00, 0x00, 0x0f, 0xf7, 0xc0, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7f, 0x00, 0x00, 0x0f, 
  0xe7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 
  0x7f, 0x80, 0x00, 0x1f, 0xe7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x1f, 
  0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x3f, 0xc0, 0x00, 0x3f, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x3f, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xff, 0xff, 0xff, 
  0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x1f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 
  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x18, 0xff, 0xff, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 2576)
const int16_t car_bmp_allArray_LEN = 1;
const unsigned char* car_bmp_allArray[1] = {
  car_bmp_128x60_car
};

display_128x160

C Header File
#include "bitmap.h"
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735

#if USE_GPIO_Dx == 1
  #define TFT_CS D5  //or gpio 7
  #define TFT_RST D3  //or gpio 29
  #define TFT_DC D4  //or gpio 6
#else
  #define TFT_CS 5
  #define TFT_RST 3
  #define TFT_DC 4
#endif




  Adafruit_ST7735 display = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);

  uint8_t DisplayTimeoutBar(uint32_t TimeSinceLastUpdate)
  {
      int 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;
                      
      }
  }

void PrintFreq()
{
  display.setCursor(118,0);
  #ifdef US_315MHz
     display.print("315 MHz");
  #else
     display.print("433 MHz");
  #endif
}


void ShowTemperatureType()
{
    //display.setCursor(70,118);
    display.drawCircle(80, 120, 2, ST77XX_MAGENTA);
    display.setCursor(84,118);
    display.setTextColor(ST77XX_MAGENTA);
    display.setTextSize(1);
   #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
      display.print(F("F"));
   #else
      display.print(F("C"));
   #endif
}

void DrawTitle()
{
  //background header
  display.fillRect(0, 0,159,16, ST77XX_BLUE);
  
  display.setCursor(2,0);
  display.setTextColor(ST77XX_YELLOW);
  display.setTextSize(1);
    #ifdef NissanLeaf
       display.print(F("Nissan Leaf TPMS"));
    #elif Dacia
       display.print(F("Dacia TPMS"));
    #elif Renault
       #ifdef Zoe
          display.print(F("Ren Zoe(early) TPMS"));
       #else
          display.print(F("Renault TPMS"));
       #endif
    #elif Citroen
       display.print(F("Citroen TPMS"));
    #elif Jansite
       display.print(F("Jansite TPMS"));
    #elif JansiteSolar
       display.print(F("JSolar TPMS"));
    #elif Ford
       display.print(F("Ford TPMS"));
    #elif PontiacG82009
       display.print(F("Pontiac G8 TPMS"));
    #elif Hyundai_i35
       display.print(F("Hyundai i35"));
    #elif Schrader_C1100
       display.print(F("Hyundai Tucson"));
    #elif Schrader_A9054100
       display.print(F("Smart ForTwo"));
    #elif Subaru
       display.println(F("Subaru TPMS")); 
    #else
       display.print(F("Toyota TPMS"));
    #endif
  PrintFreq();  
  display.setCursor(45,8);
  display.setTextColor(ST77XX_YELLOW);
  display.setTextSize(1);
  display.print(F(" JSMSolutions V"));
  display.print(VERSION);

  ShowTemperatureType();
  
}

void DrawBackground()
{
     int LineSplitCol = 72;
     
     display.drawBitmap(0, 8, car_bmp_128x60_car, 160, 128, ST77XX_WHITE);
     display.drawLine(8,LineSplitCol,54,LineSplitCol,ST77XX_BLUE);
     display.drawLine(108,LineSplitCol,154,LineSplitCol,ST77XX_BLUE);
}

void DrawSignal(uint8_t Level, int16_t x, int16_t y)
{
 
       
  if (Level >=1)
  {
       display.fillRect(x+8, y ,4,4, ST77XX_YELLOW);
  }
  else
  {
     display.fillRect(x+8, y ,4,4, ST7735_BLACK);
     display.drawRect(x+8, y ,4,4, ST77XX_YELLOW);
  }
       
  if (Level >=2)
  {
       display.fillRect(x+11, y -2,4,6, ST77XX_YELLOW);
  }
  else
  {
      display.fillRect(x+11, y -2,4,6, ST7735_BLACK);
      display.drawRect(x+11, y -2,4,6, ST77XX_YELLOW);
  }
       
  if (Level >=3)
  {
     display.fillRect(x+14, y -4,4,8, ST77XX_YELLOW);
  }
  else
  {
     display.fillRect(x+14, y -4,4,8, ST7735_BLACK);
     display.drawRect(x+14, y -4,4,8, ST77XX_YELLOW);
  }
  
       
  if (Level >=4)
  {
      display.fillRect(x+17, y-6,4,10, ST77XX_YELLOW);
  }
  else
  {
      display.fillRect(x+17, y -6,4,10, ST7735_BLACK);
      display.drawRect(x+17, y -6,4,10, ST77XX_YELLOW);
  }
       
  if (Level >=5)
  {
      display.fillRect(x+20, y -8,4,12, ST77XX_YELLOW);
  }
  else
  {
     display.fillRect(x+20, y -8,4,12, ST7735_BLACK);
     display.drawRect(x+20, y -8,4,12, ST77XX_YELLOW);
  }  
      
}

void DisplayInit()
{
    
  display.initR(INITR_GREENTAB);   // initialize a ST7735S chip, black tab
  //display.initR(0x06);  //fix for 2 row + 1 col offset issue (shows as random pixels in those areas)
  display.setRotation(3);
  display.fillScreen(ST7735_BLACK);
  display.setTextWrap(false);
}




  int16_t GetBlockStartX(int16_t DisplayIndex)
  {
  
    
      switch (DisplayIndex)
      {
        case 0:
          return(2);
          break;
        case 1:
          return(102);
          break;
        case 2:
          return(2);
          break;
        case 3:
          return(102);
          break;
      }
      return(0);
  }

  
  int16_t GetBlockStartY(int16_t DisplayIndex)
  {

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



  void WheelShow(int16_t DisplayIndex,bool Warning)
  {
     int16_t x, y;
     uint16_t col;
     
     switch (DisplayIndex)
     {
        case 0:
                x = 59;
                y = 33 + 8;
                break;
        case 1:
                x = 101;
                y = 33 + 8;
                break;
        case 2:
                x = 59;
                y = 78 + 8;
                break;
        case 3:
                x = 101;
                y = 78 + 8;
                break;
        default:
                x = 128;
                y = 160;
                break;               
     }
     

     if (Warning == true)
     {
        col = ST77XX_RED;   
     }
     else
     {
        col = ST77XX_WHITE;   
     }

     display.fillRect(x,y,5,13,col);
     

     
     
  }

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

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

     display.fillRect(x,y,56,8,ST7735_BLACK);
     display.fillRect(x+4,y,52,51,ST7735_BLACK);
     WheelShow(DisplayIndex,false);
     
  }



  void UpdateBlock(int16_t DisplayIndex,int16_t i)
  {
        int16_t x,y;
        char s[6], sID[9];
        uint8_t sig;


        if ((TPMS[i].LowPressure == true) || (TPMS[i].HighPressure == true))
        {
          
          if (DisplayFlash)
          {
             strcpy(s,"    ");
             WheelShow(DisplayIndex,true);  //show wheel as red
          }
          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), 4, 0, s);  //rounded to integer value
             #else
                dtostrf(TPMS[i].TPMS_Pressure, 3, 1, s);
             #endif
             WheelShow(DisplayIndex,true);   //show wheel as red
          }
        }
        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), 4, 0, s);  //rounded to integer value
           #else
              dtostrf(TPMS[i].TPMS_Pressure, 3, 1, s);
           #endif
           WheelShow(DisplayIndex,false);    //show wheel as normal (white)
        }

        
        x = GetBlockStartX(DisplayIndex);
        y = GetBlockStartY(DisplayIndex);
        
        //ID first
        display.setCursor(x+6, y);
        display.setTextSize(1);
        display.setTextColor(ST77XX_RED,ST7735_BLACK );
        sprintf(sID,"%08lX",TPMS[i].TPMS_ID);
        //display.print(TPMS[i].TPMS_ID,HEX);
        display.print(sID);
        
        //tyre pressure
        display.setCursor(x + 6,y + 15);
        display.setTextSize(2);
        display.setTextColor(ST77XX_GREEN,ST7735_BLACK);
        display.print(s);

        //temperature
        display.setCursor(x + 26,y + 40);
        display.setTextSize(1);
        //display.setTextColor(ST77XX_GREEN,ST7735_BLACK);
        display.setTextColor(ST77XX_MAGENTA,ST7735_BLACK);

        
        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), 5, 1, s);
               #else
                  dtostrf(TPMS[i].TPMS_Temperature, 5, 1, s);
               #endif
               display.print(s); 
               //display.print(t);
            }
          }
          else
          {
               #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
                  dtostrf(DegC_To_DegF(TPMS[i].TPMS_Temperature), 5, 1, s);
               #else
                  dtostrf(TPMS[i].TPMS_Temperature, 5, 1, s);
               #endif
               display.print(s); 
               //display.print(t);
          }
        }
        
        //display vertical bars showing how long since last update 5 bars = recent 1 bar = nearing timeout (at timeout it will be removed from display altogether)        
        sig = DisplayTimeoutBar(millis() - TPMS[i].lastupdated);
        DrawSignal(sig, x,y+44);

  }

  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);
           }
         }

      }


    }
    


  }

  void DisplayWarning(char* msg, int16_t x, int16_t y)
  {
        display.setCursor(x ,y);
        display.setTextSize(1);
        display.print(msg);
    
  }

  void ScreenSetup()
  {
      DisplayInit();
      DrawBackground();
      DrawTitle();

  }

AudibleAlarm

C Header File
extern void AudibleAlarmOnOff();
extern void AudibleAlarmReminder();

Ticker AudibleAlarmSoundTimer(AudibleAlarmOnOff, 1000, 1, MILLIS);
Ticker AudibleAlarmReminderTimer(AudibleAlarmReminder, AUDIBLE_ALARM_REMINDER_TIME_MS, 1, MILLIS);

boolean IsAlarmActive()
{//check if alarm is active (including reminder timer running)
   status_t ReminderStatus = AudibleAlarmReminderTimer.state();
   
   if (Audible_Alarm_Running)
      return(true);
   if (ReminderStatus == RUNNING)
      return(true);

   return(false);
}

void AudibleAlarm(bool TurnOn)
{
  if (TurnOn)
  {
     digitalWrite(AUDIBLE_ALARM_PIN, Audible_AlarmPin_Active);
     Audible_Alarm_On = true;
  }
  else
  {
     digitalWrite(AUDIBLE_ALARM_PIN, !Audible_AlarmPin_Active);
     Audible_Alarm_On = false;
  }
}

void StopAlarm()
{
  AudibleAlarm(false);
  AudibleAlarmSoundTimer.stop();
  AudibleAlarmReminderTimer.stop();
  Audible_Alarm_Running = false;
  //Serial.println("###Alarm Stopped");
}

void StartAlarm()
{
   AudibleAlarmSoundTimer.stop(); //just in case!
   AudibleAlarm(true);
   AudibleAlarmSoundTimer.interval(AUDIBLE_ALARM_ON_TIME_MS);
   Audible_Alarm_Cycle_Countdown = AUDIBLE_ALARM_ONOFF_COUNT;
   AudibleAlarmSoundTimer.start();
   Audible_Alarm_Running = true;
   //Serial.println("###Alarm Started");
   
}

void AudibleAlarmReminder()
{
   //Serial.println("###Alarm reminder");
   AudibleAlarmReminderTimer.stop();
   if (Pressure_Alarm_Active || Temperature_Alarm_Active)
   {
      StartAlarm();  //start the alarm cycle again
   }
   
}

void AudibleAlarmOnOff()
{//AudibleAlarmSoundTimer callback function
  //Serial.println("###Alarm on/off tone");
  if ((Pressure_Alarm_Active == false) && ( Temperature_Alarm_Active == false)) 
  {//cancel further timers, turn off alarm
     StopAlarm();
  }
  else
  {//if alarm is on, turn it off and set the off time
     if (Audible_Alarm_On) 
     {
        AudibleAlarm(false);  //turn off alarm
        Audible_Alarm_Cycle_Countdown--;
        if (Audible_Alarm_Cycle_Countdown <= 0)
        {//alarm cycle finished - start the reminder timeout
           AudibleAlarmSoundTimer.stop();
           if (AUDIBLE_ALARM_REMINDER_TIME_MS != 0)
           {
              AudibleAlarmReminderTimer.start();    //start the remibnder timeout    
           }      
        }
        else
        {//off timings
            AudibleAlarmSoundTimer.interval(AUDIBLE_ALARM_OFF_TIME_MS);
            AudibleAlarmSoundTimer.start();   //start the off time                       
        }
     }
     else
     {
         AudibleAlarm(true);  //turn on alarm
         AudibleAlarmSoundTimer.interval(AUDIBLE_ALARM_ON_TIME_MS);
         AudibleAlarmSoundTimer.start();   //start the on time
     }
  }   
}

CommonFunctionDeclarations

C Header File
extern void GetPreferredIndexStr(uint32_t ID, char* sptr);
extern int16_t GetDisplayIndexFromID(uint32_t ID);
extern int16_t GetDisplayIndexFromTyreIndex(int16_t i);
extern void MatchIDandUpdate(uint32_t id ,uint16_t status, float realtemp,float realpressure);
extern bool IsValidSync(uint16_t Width);
extern bool IsValidShort(uint16_t Width);
extern bool IsValidLong(uint16_t Width);
extern bool IsEndMarker(uint16_t Width);
extern bool IsTooShort(uint16_t Width);
extern bool IsTooLong(uint16_t Width);
extern int16_t ValidateBit();
extern int16_t ValidateBit(int16_t Index);
extern  uint16_t Compute_CRC16( int16_t bcount, uint16_t Poly,   uint16_t crc_init );
extern  uint16_t Compute_CRC16(int16_t start, int16_t bcount,  uint16_t Poly,   uint16_t crc_init );
extern uint8_t Compute_CRC8( int16_t bcount,  uint8_t Poly, uint8_t crc_init );
extern uint8_t Compute_CRC_XOR(int16_t Start, int16_t bcount, uint8_t crc_init);
extern uint8_t Compute_CRC_SUM(int16_t Start, int16_t bcount, uint8_t crc_init);
extern int16_t GetRSSI_dbm();
extern int16_t ManchesterDecode(int16_t StartIndex);
extern int16_t ManchesterDecode_ZeroBit(int16_t StartIndex);
extern int16_t DifferentialManchesterDecode(int16_t StartIndex);
extern void InvertBitBuffer();
extern int16_t DecodeBitArray(int16_t StartIndex, uint8_t ShiftRightBitCount);
extern int16_t DecodeBitArray( uint8_t ShiftRightBitCount);
extern int16_t FindManchesterStart(const uint8_t *pattern,int16_t pattern_bits_len );
extern void PrintTimings(uint8_t StartPoint, uint16_t Count);
extern void PrintBytes(uint16_t Count);
extern void PrintData(int16_t StartPos, uint16_t Count);
extern void PrintData(int16_t StartPos, uint16_t Count, bool ShowHex);
extern void PrintManchesterData(int16_t StartPos, uint16_t Count, bool ShowHex);
extern void InvertBitBuffer();
extern float DegC_To_DegF(float DegC);
extern float DegF_To_DegC(float DegF);
extern float DegC_To_DegK(float DegC);
extern float DegF_To_DegK(float DegF);
extern float DegC_To_DegF(float DegC);
extern float DegF_To_DegC(float DegF);
extern double PSI_To_BAR(double Pressure_PSI);
extern double PSI_To_KPA(double Pressure_PSI);
extern double BAR_To_PSI(double Pressure_BAR);
extern double KPA_To_PSI(double Pressure_KPA);
extern double ConvertPressureForDisplay(double Pressure_PSI);



extern uint8_t ReadFIFO();
extern uint8_t Get_RX_FIFO_Count();
void ClearRXBuffer();

display_240x240round

C Header File
#include "bitmap.h"
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_GC9A01A.h>
//#include <Adafruit_ILI9341.h>



#if USE_GPIO_Dx == 1
  #define TFT_CS D5  //or gpio 7
  #define TFT_RST D3  //or gpio 29
  #define TFT_DC D4  //or gpio 6
#else
  #define TFT_CS 5
  #define TFT_RST 3
  #define TFT_DC 4
#endif


//Display Pixel Buffer
#define DB 3

// Hardware SPI on Feather or other boards
Adafruit_GC9A01A display = Adafruit_GC9A01A(TFT_CS, TFT_DC, TFT_RST);


  uint8_t 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;
                      
      }
  }

void PrintFreq()
{
  //display.fillRect(0,0,240,240,GC9A01A_BLACK);
  //display.setCursor(118,0);
  display.setCursor(100,218);
  #ifdef US_315MHz
     display.print(F("315 MHz"));
  #else
     display.print(F("433 MHz"));
  #endif
}


void DrawTitle()
{
  //background header
  display.fillRect(0, 0,239,25 + DB, GC9A01A_BLUE);
  display.fillRect(0, 215,215,25 + DB, GC9A01A_BLUE);
    
  //display.setCursor(2,0);
 // display.setCursor(2,0 + DB);
  display.setCursor(80,16 + DB);
  display.setTextColor(GC9A01A_YELLOW);
  display.setTextSize(1);
    #ifdef NissanLeaf
       display.print(F("Nissan Leaf TPMS"));
    #elif Dacia
       display.print(F("Dacia TPMS"));
    #elif Renault
       #ifdef Zoe
          display.println(F("Ren Zoe(early) TPMS"));
       #else
          display.println(F("Renault TPMS"));
       #endif
    #elif Citroen
       display.print(F("Citroen TPMS"));
    #elif Jansite
       display.print(F("Jansite TPMS"));
    #elif JansiteSolar
       display.print(F("JSolar TPMS"));
    #elif Ford
       display.print(F("  Ford TPMS"));
    #elif PontiacG82009
       display.print(F("Pontiac TPMS"));
    #elif Hyundai_i35
       display.print(F("Hyundai i35"));
    #elif Schrader_C1100
       display.print(F("Hyundai Tucson"));
    #elif Schrader_A9054100
       display.print(F("Smart ForTwo"));
    #elif Subaru
       display.println(F("Subaru TPMS")); 
    #else
       display.print(F("Toyota TPMS"));
    #endif
  PrintFreq();  
  display.setCursor(55,8 + DB);
  display.setTextColor(GC9A01A_YELLOW);
  display.setTextSize(1);
  display.print(F(" JSMSolutions V"));
  display.print(VERSION);
}

void DrawBackground()
{
     int16_t LineSplitCol = 126;
     
     //display.drawBitmap(0, 0, car_bmp_240x240_car, 240, 240, GC9A01A_WHITE);
     display.drawLine(8,LineSplitCol,115,LineSplitCol,GC9A01A_BLUE);
     display.drawLine(125,LineSplitCol,232,LineSplitCol,GC9A01A_BLUE);

}

void DrawSignal(uint8_t Level, int16_t x, int16_t y)
{
 
       
  if (Level >=1)
  {
     display.fillRect(x+8, y ,4,4, GC9A01A_RED);
  }
  else
  {
     display.fillRect(x+8, y ,4,4, GC9A01A_BLACK);
     display.drawRect(x+8, y ,4,4, GC9A01A_RED);
  }
       
  if (Level >=2)
  {
     display.fillRect(x+11, y -2,4,6, GC9A01A_RED);
  }
  else
  {
     display.fillRect(x+11, y -2,4,6, GC9A01A_BLACK);
     display.drawRect(x+11, y -2,4,6, GC9A01A_RED);
  }
       
  if (Level >=3)
  {
     display.fillRect(x+14, y -4,4,8, GC9A01A_RED);
  }
  else
  {
     display.fillRect(x+14, y -4,4,8, GC9A01A_BLACK);
     display.drawRect(x+14, y -4,4,8, GC9A01A_RED);
  }
  
       
  if (Level >=4)
  {
     display.fillRect(x+17, y-6,4,10, GC9A01A_RED);
  }
  else
  {
     display.fillRect(x+17, y -6,4,10, GC9A01A_BLACK);
     display.drawRect(x+17, y -6,4,10, GC9A01A_RED);
  }
       
  if (Level >=5)
  {
     display.fillRect(x+20, y -8,4,12, GC9A01A_RED);
  }
  else
  {
     display.fillRect(x+20, y -8,4,12, GC9A01A_BLACK);
     display.drawRect(x+20, y -8,4,12, GC9A01A_RED);
  }  
      
}

void DisplayInit()
{
    
  //display.initR(INITR_BLACKTAB);   // initialize a GC9A01AS chip, black tab
  //display.setRotation(3);

  //writeRegister (0x51, 0);
  display.setTextWrap(false);
  display.begin();
  display.invertDisplay(1);
  display.setRotation(2);
  display.fillScreen(GC9A01A_BLACK);

}




  int16_t GetBlockStartX(uint8_t i)
  {
  

      switch (i)
      {
        case 0:
          return(26);
          break;
        case 1:
          return(132);
          break;
        case 2:
          return(26);
          break;
        case 3:
          return(132);
          break;
      }
      return(0);
  }

  
  int16_t GetBlockStartY(uint8_t i)
  {
  

      switch (i)
      {
        case 0:
          return(48);
          break;
        case 1:
          return(48);
          break;
        case 2:
          return(134);
          break;
        case 3:
          return(134);
          break;
          
      }
      return(0);
  }



  void WheelShow(int16_t DisplayIndex,bool Warning)
  {
     int16_t x, y;
     uint16_t col;
     
     switch (DisplayIndex)
     {
        case 0:
                x = 89;
                y = 74;
                break;
        case 1:
                x = 152;
                y = 74;
                break;
        case 2:
                x = 89;
                y = 141;
                break;
        case 3:
                x = 152;
                y = 141;
                break;
        default:
                x = 240;
                y = 240;
                break;               
     }
     

     if (Warning == true)
     {
        col = GC9A01A_RED;   
     }
     else
     {
        col = GC9A01A_WHITE;   
     }

     //display.fillRect(x,y,7,19,col);
     

     
     
  }

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

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

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

     //display.fillRect(x,y,56,8,GC9A01A_BLACK);
     display.fillRect(x+0,y+8,92,68,GC9A01A_BLACK);
     WheelShow(DisplayIndex,false);
     
  }

  void UpdateBlock(int16_t DisplayIndex,int16_t i)
  {
        int16_t x,y;
        char s[6], sID[9];
        uint8_t sig;
        char t;

        if ((TPMS[i].LowPressure == true) || (TPMS[i].HighPressure == true))
        {
          if (DisplayFlash)
          {
             strcpy(s,"    ");
             WheelShow(DisplayIndex,true);
          }
          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), 4, 0, s);  //rounded to integer value
             #else
                dtostrf(TPMS[i].TPMS_Pressure, 3, 1, s);
             #endif
             WheelShow(DisplayIndex,true);  
          }
        }
        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), 4, 0, s);  //rounded to integer value
           #else
              dtostrf(TPMS[i].TPMS_Pressure, 3, 1, s);
           #endif
           WheelShow(DisplayIndex,false);
        }

        
        x = GetBlockStartX(DisplayIndex);
        y = GetBlockStartY(DisplayIndex);
        
        //ID first
        display.setCursor(x+28, y);
        display.setTextSize(1);
        display.setTextColor(GC9A01A_RED,GC9A01A_BLACK );
        sprintf(sID,"%08lX",TPMS[i].TPMS_ID);
        //display.print(TPMS[i].TPMS_ID,HEX);
        display.print(sID);
        
        //tyre pressure
        display.setCursor(x,y + 18);
        display.setTextSize(4);
        display.setTextColor(GC9A01A_GREEN,GC9A01A_BLACK);
        display.print(s);

        //temperature
        display.setCursor(x + 6, y + 55);
        display.setTextSize(2);
        display.setTextColor(GC9A01A_GREEN,GC9A01A_BLACK);

        #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, 1, s);
               #else
                  dtostrf(TPMS[i].TPMS_Temperature, 2, 1, s);
               #endif
               display.print(s); 
               display.print(t);
            }
          }
          else
          {
               #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
                  dtostrf(DegC_To_DegF(TPMS[i].TPMS_Temperature), 2, 1, s);
               #else
                  dtostrf(TPMS[i].TPMS_Temperature, 2, 1, s);
               #endif
               display.print(s); 
               display.print(t);
          }
        }
        
        //display vertical bars showing how long since last update 5 bars = recent 1 bar = nearing timeout (at timeout it will be removed from display altogether)        
        sig = DisplayTimeoutBar(millis() - TPMS[i].lastupdated);
        DrawSignal(sig, x,y+4);

  }

  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);
           }
         }

      }


    }


  }

  void DisplayWarning(char* msg, int16_t x, int16_t y)
  {
        display.setCursor(x ,y);
        display.setTextSize(1);
        display.print(msg);
    
  }

  void ScreenSetup()
  {
      DisplayInit();
      DrawBackground();
      DrawTitle();  
  }

PontiacG82009

C Header File
#ifdef UK_433MHz

 #error Pontiac timings not defined for 433MHz   
 
#elif US_315MHz


    //these 315MHz timings are guesses and not proven
    
    #define EXPECTEDBITCOUNT 72
    #define EXPECTEDBYTECOUNT 10
    #define EXPECTEDFIFOBYTECOUNT 18
    #define SYNCBITS 11

    #ifdef USE_HW_CD 
       #define CDWIDTH_MIN 15000
       #define CDWIDTH_MAX 21500
    #else
       #define CDWIDTH_MIN 26000
       #define CDWIDTH_MAX 29500
    #endif
    
    #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     0x16        // GDO2 Output Pin Configuration 
    #define CC1101_DEFVAL_IOCFG1     0x2E        // GDO1 Output Pin Configuration - not used
    #define CC1101_DEFVAL_IOCFG0     0x06        // GDO0 Output Pin Configuration - Carrier Sense output
    #define CC1101_DEFVAL_FIFOTHR    0x4F        // RX FIFO and TX FIFO Thresholds - 64 bytes in FIFO
    #define CC1101_DEFVAL_SYNC1      0x65        // Synchronization word, high byte  
    #define CC1101_DEFVAL_SYNC0      0xA5        // Synchronization word, low byte
    #define CC1101_DEFVAL_PKTLEN     0x12        // Packet Length
    #define CC1101_DEFVAL_PKTCTRL1   0xE0        // Packet Automation Control
    #define CC1101_DEFVAL_PKTCTRL0   0x00       // Packet Automation Control - FIFO data
    #define CC1101_DEFVAL_ADDR       0x00        // Device Address
    #define CC1101_DEFVAL_CHANNR     0x00        // Channel Number
    #define CC1101_DEFVAL_FSCTRL1    0x06        // Frequency Synthesizer Control (was 0x06)
    #define CC1101_DEFVAL_FSCTRL0    0x00        // Frequency Synthesizer Control
    
    // Carrier frequency = 314.98MHz
    #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) - N/A

    #define CC1101_DEFVAL_MDMCFG4    0x88        // Modem Configuration 
    #define CC1101_DEFVAL_MDMCFG3    0x51        // Modem Configuration (data rate = 8.35kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x36       // Modem Configuration (ASK, Sync 16 + no Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration 

    #define CC1101_DEFVAL_AGCCTRL2     0xC6
    #define CC1101_DEFVAL_AGCCTRL1     0x50
    #define CC1101_DEFVAL_AGCCTRL0     0x40
            
//    #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     0x11         // 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,  temp;
  double realpressure;
  float realtemp;



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

  }

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

  status = ((uint16_t)RXBytes[0] << 16) | RXBytes[1] << 8 | RXBytes[2];

  pressure1 = RXBytes[7];

  temp = RXBytes[8];  //in fahrenheit


  realpressure = (float)pressure1;
  realpressure = realpressure * 2.5;  //kpa
  realpressure = realpressure / 6.895;  //psi
  realtemp = (float)temp;
  realtemp = realtemp - 60.0;  //centigrade !!!!! Note: this conversion differs from the conversion used on RTL433 for Schrader !!!!


#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.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 j;
  int16_t ManchesterStartPos = -1;
  uint8_t ByteCount = 0;
  uint8_t crcResult;
  uint8_t RX_FIFO[EXPECTEDFIFOBYTECOUNT + 2];
  uint8_t RX_FIFO_Index;
  uint8_t i;
  uint8_t FIFO_Data;

  if (Get_RX_FIFO_Count() < EXPECTEDFIFOBYTECOUNT)
  {
     return(false);
  }

  StartDataIndex = 0;

  RX_FIFO_Index = 0;
  //read FIFO bytes and convert back to bits
  RX_FIFO[RX_FIFO_Index++] = CC1101_DEFVAL_SYNC1;
  RX_FIFO[RX_FIFO_Index++] = CC1101_DEFVAL_SYNC0;
  for (i=RX_FIFO_Index; i<EXPECTEDFIFOBYTECOUNT+2;i++)
  {
     RX_FIFO[i] = ReadFIFO();
  }
  #ifdef SHOWDEBUGINFO 
    Serial.println(F("FIFO Data:")); 
    for (i=0; i<EXPECTEDFIFOBYTECOUNT+2;i++)
    {
       Serial.print(RX_FIFO[i], HEX);
       Serial.print(F(" "));
    }
    Serial.println(F("")); 
  #endif
  
  //translate FIFO data to bits
  BitCount = 0;
  for (i=0; i<EXPECTEDFIFOBYTECOUNT+2;i++)
  {
     FIFO_Data = RX_FIFO[i];
     for (j=7;j>=0;j--)
     {
        IncomingBits[BitCount++] = bitRead(FIFO_Data,j);
     }
   }


  InvertBitBuffer();
  ManchesterStartPos = 0;
  StartDataIndex = ManchesterStartPos;


  ByteCount = ManchesterDecode(ManchesterStartPos);
  //PrintBytes(ByteCount);
  if (ByteCount >= EXPECTEDBYTECOUNT)
  {
      
      //check the checksum...
      crcResult = Compute_CRC_SUM(0,EXPECTEDBYTECOUNT-1, 0x00);
      if (crcResult != RXBytes[9])
      {
        #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);
  }


}

UKUS_Toyota_TPMS_Monitor_V11_8

Arduino
//Changes:
//V1.0 - Originally published version
//V2.0 - Altered to allow support for spare tyre reporting (although not displayed on LCD display)
//V3.0 - Added #define in globals.h to switch between BAR and PSI
//V4.0 - Now uses synchronous data from CC1101 and option of using either the SPI or the hardware pin for the CD signal (#define USE_HW_CD in globals.h). Also tideied up debug information if required (globals.h #defines)
//V5.0 - Corrected possible sync error when looking for start of data stream. Fix should improve hit rate on valid TPMS detection
//V5.1 - Added freq offset updates (SWRA159) - removed again(makes it worse!)
//V5.1.1 - Added functions for extracting RSSI as dbm
//V6.0 - Added code for options for US (315MHz) or UK (433MHz), also for different sensor types (PMV-C210, PMV-107J)
//V6.1 - Added support for Seeeduino Xiao
//V6.2 - Included support for Renault (Renault Clio, Renault Captur and maybe Dacia Sandero?) as an option (to be verified)
//V6.3 - Included support for Citroen (possibly also includes Peugeot and likely Fiat, Mitsubishi, VDO-types) as an option (to be verified)
//V6.4 - Some code rationalisation, all sensor timings now in Configs.h
//V6.5 - Tried to improve PMV-107J decode by starting at the end of the buffer and working forwards
//V6.6 - Added other car types (under development), changed PMV-107J frequency deviation, added #define as option to only detect specified IDs, stripped leading 4 bits from ID (as per 'Glopes' comment) for Toyota, moved some globals settings to Config.h, changed AGC settings 
//V6.7 - Adjusted PMV_C210 presure calculation to lower PSI by 0.3 (as suggested by Steven Andrews by comparing with Autel programmer). 
//     - Added option for displaying Fahrenheit (#ifdef DISPLAY_TEMP_AS_FAHRENHEIT in configs.h) rather than centigrade.
//     - Re-introduced flashing display if pressures outside of pre-set limits (enabled by #define ENABLE_PRESSURE_ALARMS in configs.h. PressureLowLimits and PressureHighLimits in config.h should be set as required)
//V7.0 - Included option for 1.8" TFT display (requires Seeeduino Xiao for extra memory)
//V8.0 - Added optional audible alarm for pressure alarms. Improved display flashing. Tested with Nissan Leaf 433MHz OK
//V9.0 - Added Pontiac (US) decoder option, moved all CC1101 configs to sensor-spcific include files, improved timer handling. Added temperature compensation for pressure limits (set pressure limits reference temperature in configs.h). Added kPA pressure display option.
//       Pressures always stored locally as psi and temperatures as deg C - including limits (converted if required for the display).
//       Tyre pressure and temperature limits are assumed to be in the required units e.g. bar, kpa, psi, degC, degF depending on config choice.
//       Added support for 240x240 round display (Steven Andrews' display code)
//V9.1 - Added provisional support for Arduino Nano 33 IOT board
//V9.2 - Fixed bugs in audible alarm for temperatures.. Fixed missing F/C for round display.
//V9.3 - Corrected some title positioning for display.h, Added support for Renault Zoe (pre 07/2019)
//V9.4 - Corrected compile error when not using display - thanks Zaran on Hackster.io
//V9.5 - Changes to cope with multiple tyre sets (Summer/Winter). Corrected bug in ID matching (IDs were allocated to PROGMEM but referenced as SRAM for lookups), this meant tyre position was not being reported correctly. Moved Ref[3] to globals.
//V9.6 - Fixed bug where lcd display was partially obliterated if TYRECOUNT > 4 (the default is now 5)
//V9.7 - Fixed bug in Ford.h which caused out of range temperture values to be displayed on screen when temperture below 0C. 
//       Changes to support new larger screen type (supplied by Steven Andrews' - thank you!). 2.4inch LCD Display Module 65K RGB Colors, ILI9341 2.4" TFT 240320. Requires Adafruit ILI9341 library.
//V9.8 - Added support for Truck Solar TPMS and Mega256 build
//V9.9 - Added support for Ford strange Ford E-series (Tom Logan). It appears temperature format is reported in 2 ways depending upon whether or not the sensor was manually triggered (or not)
//V10.0 - Improved Ford incoming message handling
//V10.1 - Changed Ford pressure decode in line with actual E-series Schrader sensor feedback. This sensor also seems to delay sending temperatures after sleeping and sends a counter instead.
//V10.2 - Missing conditional for 2.4" screen in setup in .ino file (line 350) preventing initialisation of display (USE_24_INCH_ILI9341_DISPLAY). Causes screen to continually display white.
//V10.3 - Changed PMV-107J & PMV-C210 to try to improve detections. Code now walks through the received bit stream until a valid checksum match is found (or runs out of data)
//        This avoids the need to look for sync bits which may not be reliable at the start of the bit stream (includes change to common.h)
//V10.4 - Added trial for Toyota Sienna (TRW C070 sensor)
//V10.5 - Improvements to Toyota Sienna TRW C070 detection/validation. Added Hyundai I35 as option for this same sensor. 
//        Fixed temperature display bug (thanks Larry on Hackster for pointing this out.) - it would overflow/underflow with certain readings
//        Feedback from Alistair Clark on Hackster indicates that the C210 decode also works for Toyota Corolla (2019-22 PMV-C215 sensor)
//V10.6 - Corrected slight bug in display.h for Hyundai (should have been newline print)/ Thanks to grigata on Hackster for pointing this out.
//        Reported by gamer765 that PMV-107J also works for PMV-C11A sensors.
//        Added support for Hyundai Tucson TL/TLE (2015) using Schrader C1100/C8000 sensor. Many thanks to RM for helping on this one.
//V10.7 - Correct bug in CC1101.h in ReadFIFO function - it was missing the return statement (but worked for Xiao without it???)! Thanks to Nomake Wan for helping out on this one.
//        Added possible support for Xiao RP2040 (TBC)
//        Added support for Schrader A0009054100 senosr used on Smart Fortwo 01/2007-02/2014 (433MHz) - OOK
//V10.8 - Debugged to get Xiao RP2040 working. Same schematic as previous Xiao
//V11.0 - Added Winter tyre pressure limits (optionally). These could be easily be missed and cause an indexing outside of the array if INCLUDE_WINTER_SET enabled.
//        Added suport for Summer/Winter tyres on the displays (previously only available on serial output). Basically, if so configured, the
//        Summer and Winter tyre IDs will be recognised and displayed in their position on the display - user should make sure the other tyre set is out of range!
//V11.1 - Abandonded (not published)
//V11.2 - Changed handling of CD in main routine. Need to configure a valid ENDTIMING_MAX for each sensor type. This is used to exit the CD loop early if a reasonable number of bits have been received and it's been > ENDTIMING_MAX since the last edge (i.e. an ivalid bit timing - probably only valid for Manchester coded data)
//V11.3 - Added processor option for Adafruit 3v itsybitsy
//      - Put in conditionals for the TFT display include files to handle different GPIO formats (e.g. D1 vs just 1) depending on processor selected
//V11.4 - Changes from 10.8 affected CDWidth timings causing some sensors not to be detected. Fixed.
//      - Added software version to serial print out at startup
//V11.5 - Added LCD type to serial print out at startup. Debugged Jansite Solar code. Corrected bug in CRC routines. Changed all general declarations to width-specific types e.g. int to int16_t
//V11.6 - Trial of Subaru Impreza sensors code, both 433MHz and 315MHz (the two frequencies have different protocols)
//V11.7 - Tidied sloppy coding as much as possible in order to remove compiler warnings 
//V11.8 - Corrected bug in Manchester decoding under cetain circumstances when the number of leading 'short' timings before a 'long' timing is an odd number.
//        My thanks to Andrey Oleynik for pointing this out. Affected Toyota PMV_C210 and PMV107J
//        Fixed bug in Toyota_PMV_C210 around line 426,, DecodeBitArray call was missing a parameter and therefore calling the wrong instance. 
//        This caused the search for possible alternative valid checksum somewhere in the sequence to have always failed
//        Adjusted Deviation, data rate, AGC settings for PMV107J (US - 315MHz) as recommended by Andrey Oleynik to improve reception


#define VERSION "11.8"


#include <SPI.h>

#include "configs.h"
#include "globals.h"
#include <Ticker.h>


#include "CommonFunctionDeclarations.h"

#ifdef USE_LCDDISPLAY
   #ifdef USE_1_INCH_YB_I2C_DISPLAY 
      #include <Wire.h>
      #include "display.h"
   #elif USE_2_INCH_ST7735_DISPLAY 
      #include "display_128x160.h"
   #elif USE_2_INCH_ST7789_DISPLAY
      #include "display_240x240round.h"
   #elif USE_24_INCH_ILI9341_DISPLAY
      #include "display_240x320.h"
   #endif
#endif

#ifdef ENABLE_AUDIBLE_ALARM
   #include "AudibleAlarm.h"
#endif

#ifdef Toyota_PMV_C210
   #include "Toyota_PMV_C210.h"
#elif Toyota_PMV_107J
   #include "Toyota_PMV_107J.h"
#elif defined(Toyota_TRW_C070) || defined(Hyundai_i35)
   #include "Toyota_TRW_C070.h"
#elif defined Schrader_C1100
   #include "Schrader_C1100.h"
#elif defined Schrader_A9054100
   #include "Schrader_A9054100.h"
#elif NissanLeaf
   #include "Renault.h"
#elif Dacia
   #include "Renault.h"
#elif  Renault
   #include "Renault.h"
#elif Citroen
   #include "Citroen.h"
#elif Ford
   #include "Ford.h"
#elif  Jansite
   #include "Jansite.h"
#elif  JansiteSolar
   #include "JansiteSolar.h"
#elif PontiacG82009
   #include "PontiacG82009.h"
#elif TruckSolar
   #include "TruckSolar.h"
#elif Subaru
   #include "Subaru.h"
#endif

#include "cc1101.h"
#include "Common.h"

Ticker displayflashtimer(DisplayTimerExpired,NOBLANK_MS, 0, MILLIS);
Ticker SignalRefreshTimer(SignalRefreshRequired, SIGNALREFRESHTIMING, 0, MILLIS);

void UpdateTimers()
{
  #ifdef USE_LCDDISPLAY
     SignalRefreshTimer.update();
  #endif
  
  #if defined(ENABLE_PRESSURE_ALARMS) || defined(ENABLE_TEMPERATURE_ALARMS)
     displayflashtimer.update();
     #ifdef ENABLE_AUDIBLE_ALARM
      if (Audible_Alarm_Running)
      {
         AudibleAlarmSoundTimer.update();  //check the timers
         AudibleAlarmReminderTimer.update();
      }

     #endif
     
  #endif

}

void CheckForScreenUpdates()
{
  UpdateTimers();
  #ifdef USE_LCDDISPLAY


    #if defined(ENABLE_PRESSURE_ALARMS) || defined(ENABLE_TEMPERATURE_ALARMS)
     if (DisplayFlashExpired || (TPMS_Changed == true) || Check_TPMS_Timeouts() || SignalRefreshNeeded )
      {//display update required

          UpdateDisplay();
          if (DisplayFlashExpired)
          {
              DisplayFlashExpired = false;
          }
          TPMS_Changed = false;
          if (SignalRefreshNeeded == true)
          {
             SignalRefreshNeeded = false;
          }
      }
    #else

        if ((TPMS_Changed == true) || Check_TPMS_Timeouts() || SignalRefreshNeeded )
        {
          UpdateDisplay();
          TPMS_Changed = false;
          if (SignalRefreshNeeded == true)
          {
             SignalRefreshNeeded = false;
          }
        } 
          

    #endif


    
  #endif
}

void SendDebug(String Mess)
{
  Serial.println(Mess);
}




void setup() {

  uint8_t resp;
  uint8_t regfail;

  //SPI CC1101 chip select set up
  pinMode(CC1101_CS, OUTPUT);
  digitalWrite(CC1101_CS, HIGH);


  Serial.begin(115200);




  pinMode(LED_RX, OUTPUT);
  pinMode(RXPin, INPUT);
  pinMode(CDPin, INPUT);

  delay(2000);

  #ifdef ENABLE_AUDIBLE_ALARM
    pinMode(AUDIBLE_ALARM_PIN, OUTPUT);
    digitalWrite(AUDIBLE_ALARM_PIN,!Audible_AlarmPin_Active);
    SPI.begin();

     AudibleAlarm(true);  //audible alarm test
     delay(200);
     AudibleAlarm(false);
     delay(300);
     AudibleAlarm(true);  //audible alarm test
     delay(200);
     AudibleAlarm(false);
     delay(500);
     AudibleAlarmReminderTimer.stop();
     delay(800);
  #else
     SPI.begin();
     delay(2000);
  #endif



  Serial.println(F(""));
  Serial.println(F(""));
  Serial.println(F("########################################################################"));
  Serial.println(F(""));
  Serial.println(F("STARTING..."));
  Serial.print(F("Software version "));
  Serial.println(VERSION);
  Serial.print(F("Configured for processor type "));
  Serial.println(PROC_TYPE);

#ifdef USE_TEST_TIMINGS
   Serial.println(F("Warning: *****   BUILD FOR RUNNING HARD CODED TEST TIMES ONLY - NOT FOR REAL-TIME USE *****"));
#endif


#ifdef USE_LCDDISPLAY
   #ifdef USE_1_INCH_YB_I2C_DISPLAY 
      Serial.println(F("Configured for 0.96in SSD1306 I2C 64x128 OLED display"));
   #elif USE_2_INCH_ST7735_DISPLAY
      Serial.println(F("Configured for 1.8in ST7735 SPI 160x128 TFT display"));
   #elif USE_2_INCH_ST7789_DISPLAY
      Serial.println(F("Configured for 1.28in ST7789 SPI 240x240 TFT round display"));
   #elif USE_24_INCH_ILI9341_DISPLAY
      Serial.println(F("Configured for 2.4in ILI9341 SPI 240x320 TFT display"));
   #else
      Serial.println(F("Warning: LCD selected but no type defined"));
   #endif
#else
   Serial.println(F("No LCD display configured - Serial output only"));
#endif


#ifdef USE_LCDDISPLAY 
  #ifdef USE_1_INCH_YB_I2C_DISPLAY 
    #if USE_ADAFRUIT
      if (!display.begin(SSD1306_EXTERNALVCC, I2C_ADDRESS)) {
        Serial.println(F("SSD1306 allocation failed"));
        while(1)
        {
          delay(10);// Don't proceed, loop forever
        }
      }
      display.clearDisplay();
      display.display();
    #else
      Wire.begin();
      Wire.setClock(400000L);
      display.begin(&Adafruit128x64, I2C_ADDRESS);
      display.setFont(Adafruit5x7);
      display.clear();
      ShowTitle();
    #endif
    Serial.println(F("SSD1306 initialised OK"));
   #else

   #endif
#endif

  //initialise the CC1101

  Serial.print(F("Resetting CC1101 "));
  uint8_t retrycount = 0;
  while (retrycount < 5)
  {
     Serial.print(F("."));
     CC1101_reset();
     if (readConfigReg(0) == 0x29)
        break;
     retrycount++;
     delay(5);
  }
  Serial.println(F(""));

  if (readConfigReg(0) == 0x29)
  {
    Serial.println(F("CC1101 reset successful"));
  }
  else
  {
    Serial.println(F("CC1101 reset failed. Try rebooting"));
    #ifdef USE_LCDDISPLAY 
       #ifdef USE_2_INCH_ST7735_DISPLAY
          DisplayInit();
          DrawTitle(); 
          DisplayWarning((char *) "CC1101 reset failed", 0, 64);
          DisplayWarning((char *) "Power off/on", 0,80); 
          while(1)
          {
            delay(10);// Don't proceed, loop forever
          }
       #endif
    #endif   
  }


  ConfigureCC1101();
  Serial.print(F("CC1101 configured for "));
  #ifdef US_315MHz
     Serial.print (F("US (315MHz)"));
  #else
     Serial.print (F("UK (433MHz)"));
  #endif

  #ifdef Toyota_PMV_C210
     Serial.println (F(" and PMV-C210 TPMS sensor"));
  #elif Toyota_PMV_107J
     Serial.println (F(" and PMV-107J TPMS sensor"));
  #elif Toyota_TRW_C070
     Serial.println (F(" and TRW-C070 TPMS sensor"));
  #elif Hyundai_i35
     Serial.println (F(" and Hyundai i35 (TRW-C070) TPMS sensor"));
  #elif NissanLeaf
     Serial.println (F(" and Nissan Leaf(Renault) TPMS sensor"));
  #elif Dacia
     Serial.println (F(" and Dacia (Renault) TPMS sensor"));    
  #elif Renault
       #ifdef Zoe
          Serial.println("and Renault Zoe(pre 07/2019 X10) TPMS sensor");
       #else
          Serial.println("and Renault TPMS sensor");
       #endif
  #elif Citroen
     Serial.println (F(" and Citroen TPMS sensor"));
  #elif Ford
     Serial.println (F(" and Ford TPMS sensor"));
  #elif Jansite
     Serial.println (F(" and Jansite TPMS sensor"));
  #elif JansiteSolar
     Serial.println (F(" and Jansite-Solar TPMS sensor"));
  #elif PontiacG82009
     Serial.println (F(" and Pontiac TPMS sensor"));
  #endif

  setIdleState();
  digitalWrite(LED_RX, LED_OFF);

  resp = readStatusReg(CC1101_PARTNUM);
  Serial.print(F("CC1101 Part no: "));
  Serial.println(resp, HEX);

  resp = readStatusReg(CC1101_VERSION);
  Serial.print(F("CC1101 Version: "));
  Serial.println(resp, HEX);

  regfail = VerifyCC1101Config();
  if (regfail > 0)
  {
     Serial.print(F("Config verification fail #"));
     Serial.println(regfail);
  }
  else
  {
     Serial.println(F("Config verification OK"));
  }

  #ifdef USE_LCDDISPLAY 
    #ifdef USE_2_INCH_ST7735_DISPLAY
      ScreenSetup();
    #elif USE_2_INCH_ST7789_DISPLAY
      ScreenSetup();
    #elif USE_24_INCH_ILI9341_DISPLAY
      ScreenSetup();
    #endif
  #endif 





  digitalWrite(LED_RX, LED_ON);

  pinMode(DEBUGPIN, OUTPUT);
  digitalWrite(DEBUGPIN, LOW);




  InitTPMS();

  PrintIDs();


  digitalWrite(LED_RX, LED_OFF);


  //Calibrate();
  LastCalTime = millis();
  DisplayTimer = millis();
  DisplayFlash  = false;
  
  setRxState();
  Flush_RX_FIFO(true);

   #if defined(ENABLE_PRESSURE_ALARMS) || defined(ENABLE_TEMPERATURE_ALARMS)
     displayflashtimer.start();
  #else
     displayflashtimer.stop();
  #endif

  #ifdef USE_LCDDISPLAY
      SignalRefreshTimer.start();
  #endif
}



void loop() {

#ifdef USE_TEST_TIMINGS
  static uint32_t lastts = millis();
#endif


  if (millis() - LastCalTime > CAL_PERIOD_MS)
  {
      setIdleState();  //configuration is set to auto-cal when goimg from Idle to RX
      Calibrate();
      LastCalTime = millis();
      setRxState();      
  }

// check timers...
  UpdateTimers(); 


  InitDataBuffer();


#ifdef USE_TEST_TIMINGS
 
    //Used for hard-coded test time testing only
    if ((millis() - lastts) >= 10000)
    {//run test every 10 seconds
       ReceiveMessage();
       lastts = millis();  //reset 10 second timer
    }
    CheckForScreenUpdates();

#else
  //normal usage

  //wait for carrier status to go low
  while (GetCarrierStatus() == true)
  {
     CheckForScreenUpdates();
  }

  //wait for carrier status to go high  looking for rising edge
  while (GetCarrierStatus() == false)
  {
       //UpdateTimers();
       if (Get_RX_FIFO_Count() > 0)
       {
          //Serial.println("Flushing FIFO");
          Flush_RX_FIFO(true);
       }
       CheckForScreenUpdates();
       delay(1);
  }

  if (GetCarrierStatus() == true)
  { //looks like some data coming in...
    
    ReceiveMessage();

    #ifdef USE_LCDDISPLAY
       CheckForScreenUpdates();
    #endif

  }


#endif



}

display_240x320

C Header File
#include "bitmap.h"
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ILI9341.h>


#if USE_GPIO_Dx == 1
  #define TFT_CS D5  //or gpio 7
  #define TFT_RST D3  //or gpio 29
  #define TFT_DC D4  //or gpio 6
#else
  #define TFT_CS 5
  #define TFT_RST 3
  #define TFT_DC 4
#endif

//Display Pixel Buffer
#define DB 3

//Tweak Colors
#define ILI9341_ORANGEM 0xF300
#define ILI9341_GREENM  0x129B
//#define ILI9341_GREENM  0x06C5

// Hardware SPI on Feather or other boards
Adafruit_ILI9341 display = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);


  uint8_t DisplayTimeoutBar(uint32_t TimeSinceLastUpdate)
  {
      int 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;
                      
      }
  }

void PrintFreq()
{
  //display.fillRect(0,0,240,320,ILI9341_BLACK);
  //display.setCursor(118,0);
  display.setCursor(275,18);
  #ifdef US_315MHz
     display.setTextSize(1);
     display.print(F("315 MHz"));
  #else
     display.print(F("433 MHz"));
  #endif
}


  void DrawTitle()
{
  //background header
  display.fillRect(0, 0,320,25 + DB, ILI9341_GREENM);
  //display.fillRect(0, 215,320,25 + DB, ILI9341_GREENM);
    
  //display.setCursor(2,0);
 // display.setCursor(2,0 + DB);
  display.setCursor(80,4 + DB);
  display.setTextColor(ILI9341_BLACK);
  display.setTextSize(2);
    #ifdef NissanLeaf
       display.print(F("Nissan Leaf TPMS"));
    #elif Dacia
       display.print(F("Dacia TPMS"));
    #elif Renault
       #ifdef Zoe
          display.println(F("Ren Zoe(early) TPMS"));
       #else
          display.println(F("Renault TPMS"));
       #endif
    #elif Citroen
       display.print(F("Citroen TPMS"));
    #elif Jansite
       display.print(F("Jansite TPMS"));
    #elif JansiteSolar
       display.print(F("JSolar TPMS"));
    #elif Ford
       display.print(F("Ford F250 TPMS"));
    #elif PontiacG82009
       display.print(F("Porsche Carerra"));
    #elif Hyundai_i35
       display.print(F("Hyundai i35"));
    #elif Schrader_C1100
       display.print(F("Hyundai Tucson"));
    #elif Schrader_A9054100
       display.print(F("Smart ForTwo"));
    #elif Subaru
       display.println(F("Subaru TPMS")); 
    #else
       display.print(F("Toyota TPMS"));
    #endif
  PrintFreq();  
  display.setCursor(56,8 + DB);
  display.setTextColor(ILI9341_BLACK);
  display.setTextSize(1);
  display.print(" ");
  //display.print(VERSION);
}

void DrawBackground()
{
     int LineSplitCol = 136;
     
     //display.drawBitmap(0, 0, car_bmp_240x240_car, 240, 240, ILI9341_WHITE);
     //display.drawLine(8,LineSplitCol,115,LineSplitCol,ILI9341_ORANGEM);
     //display.drawLine(125,LineSplitCol,232,LineSplitCol,ILI9341_ORANGEM);
     display.drawLine(5,LineSplitCol,150,LineSplitCol,ILI9341_ORANGEM);
     display.drawLine(170,LineSplitCol,315,LineSplitCol,ILI9341_ORANGEM);

}

void DrawSignal(uint8_t Level, int16_t x, int16_t y)
{
 
       
  if (Level >=1)
  {
     display.fillRect(x+8, y ,4,4, ILI9341_GREENM);
  }
  else
  {
     display.fillRect(x+8, y ,4,4, ILI9341_BLACK);
     display.drawRect(x+8, y ,4,4, ILI9341_GREENM);
  }
       
  if (Level >=2)
  {
     display.fillRect(x+11, y -2,4,6, ILI9341_GREENM);
  }
  else
  {
     display.fillRect(x+11, y -2,4,6, ILI9341_BLACK);
     display.drawRect(x+11, y -2,4,6, ILI9341_GREENM);
  }
       
  if (Level >=3)
  {
     display.fillRect(x+14, y -4,4,8, ILI9341_GREENM);
  }
  else
  {
     display.fillRect(x+14, y -4,4,8, ILI9341_BLACK);
     display.drawRect(x+14, y -4,4,8, ILI9341_GREENM);
  }
  
       
  if (Level >=4)
  {
     display.fillRect(x+17, y-6,4,10, ILI9341_GREENM);
  }
  else
  {
     display.fillRect(x+17, y -6,4,10, ILI9341_BLACK);
     display.drawRect(x+17, y -6,4,10, ILI9341_GREENM);
  }
       
  if (Level >=5)
  {
     display.fillRect(x+20, y -8,4,12, ILI9341_GREENM);
  }
  else
  {
     display.fillRect(x+20, y -8,4,12, ILI9341_BLACK);
     display.drawRect(x+20, y -8,4,12, ILI9341_GREENM);
  }  
      
}

uint32_t testText()
{
  display.fillScreen(ILI9341_BLACK);
  uint32_t start = micros();
  display.setCursor(0, 0);
  display.setTextColor(ILI9341_WHITE);
  display.setTextSize(1);
  display.println("Hello World!");
  display.setTextColor(ILI9341_YELLOW);
  display.setTextSize(2);
  display.println(1234.56);
  display.setTextColor(ILI9341_RED);
  display.setTextSize(3);
  display.println(0xDEADBEEF, HEX);
  display.println();
  display.setTextColor(ILI9341_GREEN);
  display.setTextSize(5);
  display.println("Groop");
  display.setTextSize(2);
  display.println("I implore thee,");
  display.setTextSize(1);
  display.println("my foonting turlingdromes.");
  display.println("And hooptiously drangle me");
  display.println("with crinkly bindlewurdles,");
  display.println("Or I will rend thee");
  display.println("in the gobberwarts");
  display.println("with my blurglecruncheon,");
  display.println("see if I don't!");

  delay(5000);
  return micros() - start;
}

void DisplayInit()
{
    
  //display.initR(INITR_BLACKTAB);   // initialize a ILI9341S chip, black tab
  //display.setRotation(3);

  //writeRegister (0x51, 0);
  //testText();
  display.setTextWrap(false);
  display.begin();
  display.invertDisplay(0);
  display.setRotation(3);
  display.fillScreen(ILI9341_BLACK);

}




  int GetBlockStartX(int DisplayIndex)
  {
  

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

  
  int GetBlockStartY(int DisplayIndex)
  {
  

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



  void WheelShow(int16_t DisplayIndex,bool Warning)
  {
     int16_t x, y;
     uint16_t col;
     
     switch (DisplayIndex)
     {
        case 0:
                x = 89;
                y = 74;
                break;
        case 1:
                x = 152;
                y = 74;
                break;
        case 2:
                x = 89;
                y = 141;
                break;
        case 3:
                x = 152;
                y = 141;
                break;
        default:
                x = 340;
                y = 240;
                break;               
     }
     

     if (Warning == true)
     {
        col = ILI9341_RED;   
     }
     else
     {
        col = ILI9341_WHITE;   
     }

     //display.fillRect(x,y,7,19,col);
     

     
     
  }

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

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

     //display.fillRect(x,y,56,8,ILI9341_BLACK);
     display.fillRect(x+0,y+8,144,85,ILI9341_BLACK);
     WheelShow(DisplayIndex,false);
     
  }

  void UpdateBlock(int16_t DisplayIndex,int16_t i)
  {
        int16_t x,y;
        char s[6], sID[9];
        uint8_t sig;
        char t;


        if ((TPMS[i].LowPressure == true) || (TPMS[i].HighPressure == true))
        {
          if (DisplayFlash)
          {
             strcpy(s,"    ");
             WheelShow(DisplayIndex,true);
          }
          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), 4, 0, s);  //rounded to integer value
             #else
                dtostrf(TPMS[i].TPMS_Pressure, 3, 1, s);
             #endif
             WheelShow(DisplayIndex,true);  
          }
        }
        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), 4, 0, s);  //rounded to integer value
           #else
              dtostrf(TPMS[i].TPMS_Pressure, 3, 1, s);
           #endif
           WheelShow(DisplayIndex,false);
        }

        
        x = GetBlockStartX(DisplayIndex);
        y = GetBlockStartY(DisplayIndex);
        
        //ID first
        display.setCursor(x+50, y);
        display.setTextSize(1);
        display.setTextColor(ILI9341_GREENM,ILI9341_BLACK );
        sprintf(sID,"%08lX",TPMS[i].TPMS_ID);
        //display.print(TPMS[i].TPMS_ID,HEX);
        display.print(sID);
                        
        //tyre pressure
        display.setCursor(x,y + 18);
        display.setTextSize(6);
        display.setTextColor(ILI9341_ORANGEM,ILI9341_BLACK);
        display.print(s);

        //temperature
        display.setCursor(x + 30, y + 67);
        display.setTextSize(3);
        display.setTextColor(ILI9341_ORANGEM,ILI9341_BLACK);

        #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, 1, s);
               #else
                  dtostrf(TPMS[i].TPMS_Temperature, 2, 1, s);
               #endif
               display.print(s); 
               display.print(t);
            }
          }
          else
          {
               #ifdef DISPLAY_TEMP_AS_FAHRENHEIT
                  dtostrf(DegC_To_DegF(TPMS[i].TPMS_Temperature), 2, 1, s);
               #else
                  dtostrf(TPMS[i].TPMS_Temperature, 2, 1, s);
               #endif
               display.print(s); 
               display.print(t);
          }
        }
        
        //display vertical bars showing how long since last update 5 bars = recent 1 bar = nearing timeout (at timeout it will be removed from display altogether)        
        sig = DisplayTimeoutBar(millis() - TPMS[i].lastupdated);
        DrawSignal(sig, x+15,y+4);

  }

  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);
           }
         }

      }


    }


  }

  void DisplayWarning(char* msg, int16_t x, int16_t y)
  {
        display.setCursor(x ,y);
        display.setTextSize(1);
        display.print(msg);
    
  }

  void ScreenSetup()
  {
      DisplayInit();
      DrawBackground();
      DrawTitle();  
  }

TruckSolar

C Header File
#ifdef UK_433MHz


    #define EXPECTEDBITCOUNT 80
    #define EXPECTEDBYTECOUNT 9
    #define SYNCBITS 16
  
    #define CDWIDTH_MIN 18500
    #define CDWIDTH_MAX 24000
  
    #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


   #error Truck Solar timings not defined for 315MHz


#endif

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



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

  }

  id = id & 0xFFFFFFFF;

  GetPreferredIndexStr(id, Ref);

  Wheel = RXBytes[4];

  status = RXBytes[5] >> 4;

  pressure1 =  ((uint16_t)RXBytes[5] & 0x0f) << 8 | RXBytes[6];

  temp = RXBytes[7];

  pressure2 = pressure1;



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

  realpressure = KPA_To_PSI((double)pressure1); 
  realtemp = (float)temp;



#ifdef SHOWVALIDTPMS
  Serial.print(F("Pos: "));
  Serial.print(Ref);
  Serial.print(F("   Wheel: "));
  Serial.print(Wheel);
  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();
}



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 bitcount > MAXBITS-1"));
         #endif
         return;
      }
   }
  
}


bool ValidateTimings()
{


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

  StartDataIndex = 0;

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


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

  ConvertTimingsToBits();

  InvertBitBuffer();


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


  if (ManchesterStartPos == -1 )
  {
    #ifdef SHOWDEBUGINFO
       Serial.println(F("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 + 8);
  if (ByteCount >= EXPECTEDBYTECOUNT)
  {
      
      //check the checksum...
      crcResult = Compute_CRC_XOR(0,8,  0x00);
      if (crcResult != RXBytes[8])
      {
         #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);
  }


}

cc1101

C Header File
enum RFSTATE
{
  RFSTATE_IDLE = 0,
  RFSTATE_RX,
  RFSTATE_TX
};






//SPIClass spi;

/**
 * Frequency channels
 */
#define NUMBER_OF_FCHANNELS      10

/**
 * Type of transfers
 */
#define WRITE_BURST              0x40
#define READ_SINGLE              0x80
#define READ_BURST               0xC0

/**
 * Type of register
 */
#define CC1101_CONFIG_REGISTER   READ_SINGLE
#define CC1101_STATUS_REGISTER   READ_BURST


/**
 * Buffer and data lengths
 */
#define CCPACKET_BUFFER_LEN        64
#define CCPACKET_DATA_LEN          CCPACKET_BUFFER_LEN - 3

/**
 * Class: CCPACKET
 * 
 * Description:
 * CC1101 data packet class
 */
struct CCPACKET
{
  public:
     //Data length
    uint8_t length;
     // Data buffer
    uint8_t data[CCPACKET_DATA_LEN];
     //* CRC OK flag
    bool crc_ok;
     // Received Strength Signal Indication
    uint8_t rssi;
     // Link Quality Index
    uint8_t lqi;
};



/**
 * Macros
 */

//#define wait_Miso()  delay(3)
void wait_Miso()
{
   uint32_t st = micros();
   while(digitalRead(MISO) == HIGH)
   {
      if (micros() - st > 500)
         break;
   }
}
// Get GDO0 pin state
#define getGDO0state()  digitalRead(PORT_GDO0)
// Wait until GDO0 line goes high
#define wait_GDO0_high()  while(!getGDO0state()) {delay(1);}
// Wait until GDO0 line goes low
#define wait_GDO0_low()  while(getGDO0state()) {delay(1);}



/**
 * PATABLE & FIFO's
 */
#define CC1101_PATABLE           0x3E        // PATABLE address
#define CC1101_TXFIFO            0x3F        // TX FIFO address
#define CC1101_RXFIFO            0x3F        // RX FIFO address

/**
 * Command strobes
 */
#define CC1101_SRES              0x30        // Reset CC1101 chip
#define CC1101_SFSTXON           0x31        // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). If in RX (with CCA):
                                             // Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround).
#define CC1101_SXOFF             0x32        // Turn off crystal oscillator
#define CC1101_SCAL              0x33        // Calibrate frequency synthesizer and turn it off. SCAL can be strobed from IDLE mode without
                                             // setting manual calibration mode (MCSM0.FS_AUTOCAL=0)
#define CC1101_SRX               0x34        // Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1
#define CC1101_STX               0x35        // In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1.
                                             // If in RX state and CCA is enabled: Only go to TX if channel is clear
#define CC1101_SIDLE             0x36        // Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable
#define CC1101_SWOR              0x38        // Start automatic RX polling sequence (Wake-on-Radio) as described in Section 19.5 if
                                             // WORCTRL.RC_PD=0
#define CC1101_SPWD              0x39        // Enter power down mode when CSn goes high
#define CC1101_SFRX              0x3A        // Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states
#define CC1101_SFTX              0x3B        // Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states
#define CC1101_SWORRST           0x3C        // Reset real time clock to Event1 value
#define CC1101_SNOP              0x3D        // No operation. May be used to get access to the chip status byte

/**
 * CC1101 configuration registers
 */
#define CC1101_IOCFG2            0x00        // GDO2 Output Pin Configuration
#define CC1101_IOCFG1            0x01        // GDO1 Output Pin Configuration
#define CC1101_IOCFG0            0x02        // GDO0 Output Pin Configuration
#define CC1101_FIFOTHR           0x03        // RX FIFO and TX FIFO Thresholds
#define CC1101_SYNC1             0x04        // Sync Word, High Byte
#define CC1101_SYNC0             0x05        // Sync Word, Low Byte
#define CC1101_PKTLEN            0x06        // Packet Length
#define CC1101_PKTCTRL1          0x07        // Packet Automation Control
#define CC1101_PKTCTRL0          0x08        // Packet Automation Control
#define CC1101_ADDR              0x09        // Device Address
#define CC1101_CHANNR            0x0A        // Channel Number
#define CC1101_FSCTRL1           0x0B        // Frequency Synthesizer Control
#define CC1101_FSCTRL0           0x0C        // Frequency Synthesizer Control
#define CC1101_FREQ2             0x0D        // Frequency Control Word, High Byte
#define CC1101_FREQ1             0x0E        // Frequency Control Word, Middle Byte
#define CC1101_FREQ0             0x0F        // Frequency Control Word, Low Byte
#define CC1101_MDMCFG4           0x10        // Modem Configuration
#define CC1101_MDMCFG3           0x11        // Modem Configuration
#define CC1101_MDMCFG2           0x12        // Modem Configuration
#define CC1101_MDMCFG1           0x13        // Modem Configuration
#define CC1101_MDMCFG0           0x14        // Modem Configuration
#define CC1101_DEVIATN           0x15        // Modem Deviation Setting
#define CC1101_MCSM2             0x16        // Main Radio Control State Machine Configuration
#define CC1101_MCSM1             0x17        // Main Radio Control State Machine Configuration
#define CC1101_MCSM0             0x18        // Main Radio Control State Machine Configuration
#define CC1101_FOCCFG            0x19        // Frequency Offset Compensation Configuration
#define CC1101_BSCFG             0x1A        // Bit Synchronization Configuration
#define CC1101_AGCCTRL2          0x1B        // AGC Control
#define CC1101_AGCCTRL1          0x1C        // AGC Control
#define CC1101_AGCCTRL0          0x1D        // AGC Control
#define CC1101_WOREVT1           0x1E        // High Byte Event0 Timeout
#define CC1101_WOREVT0           0x1F        // Low Byte Event0 Timeout
#define CC1101_WORCTRL           0x20        // Wake On Radio Control
#define CC1101_FREND1            0x21        // Front End RX Configuration
#define CC1101_FREND0            0x22        // Front End TX Configuration
#define CC1101_FSCAL3            0x23        // Frequency Synthesizer Calibration
#define CC1101_FSCAL2            0x24        // Frequency Synthesizer Calibration
#define CC1101_FSCAL1            0x25        // Frequency Synthesizer Calibration
#define CC1101_FSCAL0            0x26        // Frequency Synthesizer Calibration
#define CC1101_RCCTRL1           0x27        // RC Oscillator Configuration
#define CC1101_RCCTRL0           0x28        // RC Oscillator Configuration
#define CC1101_FSTEST            0x29        // Frequency Synthesizer Calibration Control
#define CC1101_PTEST             0x2A        // Production Test
#define CC1101_AGCTEST           0x2B        // AGC Test
#define CC1101_TEST2             0x2C        // Various Test Settings
#define CC1101_TEST1             0x2D        // Various Test Settings
#define CC1101_TEST0             0x2E        // Various Test Settings

/**
 * Status registers
 */
#define CC1101_PARTNUM           0x30        // Chip ID
#define CC1101_VERSION           0x31        // Chip ID
#define CC1101_FREQEST           0x32        // Frequency Offset Estimate from Demodulator
#define CC1101_LQI               0x33        // Demodulator Estimate for Link Quality
#define CC1101_RSSI              0x34        // Received Signal Strength Indication
#define CC1101_MARCSTATE         0x35        // Main Radio Control State Machine State
#define CC1101_WORTIME1          0x36        // High Byte of WOR Time
#define CC1101_WORTIME0          0x37        // Low Byte of WOR Time
#define CC1101_PKTSTATUS         0x38        // Current GDOx Status and Packet Status
#define CC1101_VCO_VC_DAC        0x39        // Current Setting from PLL Calibration Module
#define CC1101_TXBYTES           0x3A        // Underflow and Number of Bytes
#define CC1101_RXBYTES           0x3B        // Overflow and Number of Bytes
#define CC1101_RCCTRL1_STATUS    0x3C        // Last RC Oscillator Calibration Result
#define CC1101_RCCTRL0_STATUS    0x3D        // Last RC Oscillator Calibration Result 


//#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 = 868 MHz (not used)
////#define CC1101_DEFVAL_FREQ2_868  0x21        // Frequency Control Word, High Byte
////#define CC1101_DEFVAL_FREQ1_868  0x65        // Frequency Control Word, Middle Byte
////#define CC1101_DEFVAL_FREQ0_868  0xCC        // Frequency Control Word, Low Byte
//
////// Carrier frequency = 433.8798 MHz
////#define CC1101_DEFVAL_FREQ2_433  0x10        // Frequency Control Word, High Byte
////#define CC1101_DEFVAL_FREQ1_433  0xB0        // Frequency Control Word, Middle Byte
////#define CC1101_DEFVAL_FREQ0_433  0x71        // Frequency Control Word, Low Byte
////#define CC1101_DEFVAL_MDMCFG4_433    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_433    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
////#define CC1101_DEFVAL_DEVIATN_433    0x41      // Modem Deviation Setting (+/-28.56kHz)
////
////// Carrier frequency = 315MHz MHz
////#define CC1101_DEFVAL_FREQ2_315  0x0C        // Frequency Control Word, High Byte
////#define CC1101_DEFVAL_FREQ1_315  0x1D        // Frequency Control Word, Middle Byte
////#define CC1101_DEFVAL_FREQ0_315  0x57        // Frequency Control Word, Low Byte
////#define CC1101_DEFVAL_MDMCFG4_315    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_315    0x93        // Modem Configuration (now 93 = data rate = 20kHz)
////#define CC1101_DEFVAL_DEVIATN_315    0x40        // Modem Deviation Setting (+/-25.390625)
////
////
////
////#define CC1101_DEFVAL_MDMCFG2    0x10        // Modem Configuration (GFSK, No Sync or Manchester coding)
////
////#define CC1101_DEFVAL_MDMCFG1    0x22        // Modem Configuration Channel spacing 200kHz
////#define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration
//
//
//#define CC1101_DEFVAL_MCSM2      0x07        // Main Radio Control State Machine Configuration
////#define CC1101_DEFVAL_MCSM1      0x30        // 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_AGCCTRL2   0x43        // AGC Control
//////#define CC1101_DEFVAL_AGCCTRL2   0xC6        // AGC Control
////#define CC1101_DEFVAL_AGCCTRL2   0x87       // AGC Control
////////#define CC1101_DEFVAL_AGCCTRL1   0x40        // AGC Control
//////#define CC1101_DEFVAL_AGCCTRL1   0x50        // AGC Control
////#define CC1101_DEFVAL_AGCCTRL1   0x58        // AGC Control
////#define CC1101_DEFVAL_AGCCTRL0   0x80        // AGC Control
//
//#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
//

/**
 * Alias for some default values
 */
#define CCDEF_CHANNR  CC1101_DEFVAL_CHANNR
#define CCDEF_SYNC0  CC1101_DEFVAL_SYNC0
#define CCDEF_SYNC1  CC1101_DEFVAL_SYNC1
#define CCDEF_ADDR  CC1101_DEFVAL_ADDR

/**
 * Macros
 */
// Read CC1101 Config register
#define readConfigReg(regAddr)    readReg(regAddr, CC1101_CONFIG_REGISTER)
// Read CC1101 Status register
#define readStatusReg(regAddr)    readReg(regAddr, CC1101_STATUS_REGISTER)
// Enter Rx state
//#define setRxState()              cmdStrobe(CC1101_SRX)
// Enter Tx state
//#define setTxState()              cmdStrobe(CC1101_STX)
// Enter IDLE state
#define setIdleState()            cmdStrobe(CC1101_SIDLE)
#define StartCalibration()        cmdStrobe(CC1101_SCAL)
// Flush Rx FIFO
#define flushRxFifo()             cmdStrobe(CC1101_SFRX)
// Flush Tx FIFO
#define flushTxFifo()             cmdStrobe(CC1101_SFTX)
// Disable address check
#define disableAddressCheck()     writeReg(CC1101_PKTCTRL1, 0x04)
// Enable address check
#define enableAddressCheck()      writeReg(CC1101_PKTCTRL1, 0x06)
// Disable CCA
#define disableCCA()              writeReg(CC1101_MCSM1, 0)
// Enable CCA
#define enableCCA()               writeReg(CC1101_MCSM1, CC1101_DEFVAL_MCSM1)
// Set PATABLE single byte
#define setTxPowerAmp(setting)    paTableByte = setting
// PATABLE values
#define PA_LowPower               0x60
#define PA_LongDistance           0xC0




// Select (SPI) CC1101
void cc1101_Select(){

  //delayMicroseconds(150);
  //spi.begin();
  //spi.beginTransaction(SPISettings(5000000,MSBFIRST,SPI_MODE0));
  SPI.beginTransaction(SPISettings(5000000,MSBFIRST,SPI_MODE0));
  digitalWrite(CC1101_CS, LOW);
}

void cc1101_Deselect(){
  //spi.end();

  //delayMicroseconds(50);
  digitalWrite(CC1101_CS, HIGH);
  //spi.endTransaction();
  SPI.endTransaction();


}

/**
 * wakeUp
 * 
 * Wake up CC1101 from Power Down state
 */
void wakeUp(void)
{
  cc1101_Select();                      // Select CC1101
  wait_Miso();                          // Wait until MISO goes low
  cc1101_Deselect();                    // Deselect CC1101
}


/**
 * writeReg
 * 
 * Write single register into the CC1101 IC via SPI
 * 
 * 'regAddr'  Register address
 * 'value'  Value to be writen
 */
void writeReg(uint8_t regAddr, uint8_t value) 
{
  cc1101_Select();                      // Select CC1101
  //wait_Miso();                          // Wait until MISO goes low
  SPI.transfer(regAddr);                    // Send register address
  SPI.transfer(value);                      // Send value
  //spi.transfer(regAddr);                    // Send register address
  //spi.transfer(value);                      // Send value
  cc1101_Deselect();                    // Deselect CC1101
}

/**
 * readReg
 * 
 * Read CC1101 register via SPI
 * 
 * 'regAddr'  Register address
 * 'regType'  Type of register: CC1101_CONFIG_REGISTER or CC1101_STATUS_REGISTER
 * 
 * Return:
 *  Data byte returned by the CC1101 IC
 */
uint8_t readReg(uint8_t regAddr, uint8_t regType)
{
  uint8_t addr, val;

  addr = regAddr | regType;
  cc1101_Select();                      // Select CC1101
  //wait_Miso();                          // Wait until MISO goes low
  //spi.transfer(addr);                       // Send register address
  //val = spi.transfer(0x00);                 // Read result
  SPI.transfer(addr);                       // Send register address
  val = SPI.transfer(0x00);                 // Read result
  cc1101_Deselect();                    // Deselect CC1101

  return val;
}

/**
 * setCCregs
 * 
 * Configure CC1101 registers
 */
void setCCregs(void) 
{
  writeReg(CC1101_IOCFG2,  CC1101_DEFVAL_IOCFG2);
  writeReg(CC1101_IOCFG1,  CC1101_DEFVAL_IOCFG1);
  writeReg(CC1101_IOCFG0,  CC1101_DEFVAL_IOCFG0);
  writeReg(CC1101_FIFOTHR,  CC1101_DEFVAL_FIFOTHR);
  writeReg(CC1101_SYNC1,  CC1101_DEFVAL_SYNC1);
  writeReg(CC1101_SYNC0,  CC1101_DEFVAL_SYNC0);
  writeReg(CC1101_PKTLEN,  CC1101_DEFVAL_PKTLEN);
  writeReg(CC1101_PKTCTRL1,  CC1101_DEFVAL_PKTCTRL1);
  writeReg(CC1101_PKTCTRL0,  CC1101_DEFVAL_PKTCTRL0);
  writeReg(CC1101_ADDR,  CC1101_DEFVAL_ADDR);
  writeReg(CC1101_CHANNR,  CC1101_DEFVAL_CHANNR);

  
  // Set default synchronization word
  //setSyncWord(syncWord);

  // Set default device address
  //setDevAddress(devAddress);

  // Set default frequency channel
  //setChannel(channel);
  
  writeReg(CC1101_FSCTRL1,  CC1101_DEFVAL_FSCTRL1);
  writeReg(CC1101_FSCTRL0,  CC1101_DEFVAL_FSCTRL0);

//  // Set default carrier frequency = 868 MHz
//  //setCarrierFreq(carrierFreq);
//  writeReg(CC1101_FREQ2,  CC1101_DEFVAL_FREQ2_868);
//  writeReg(CC1101_FREQ1,  CC1101_DEFVAL_FREQ1_868);
//  writeReg(CC1101_FREQ0,  CC1101_DEFVAL_FREQ0_868);


  writeReg(CC1101_FREQ2,  CC1101_DEFVAL_FREQ2);
  writeReg(CC1101_FREQ1,  CC1101_DEFVAL_FREQ1);
  writeReg(CC1101_FREQ0,  CC1101_DEFVAL_FREQ0);
  writeReg(CC1101_DEVIATN,  CC1101_DEFVAL_DEVIATN);
  writeReg(CC1101_MDMCFG4,  CC1101_DEFVAL_MDMCFG4);
  writeReg(CC1101_MDMCFG3,  CC1101_DEFVAL_MDMCFG3);

  writeReg(CC1101_MDMCFG2,  CC1101_DEFVAL_MDMCFG2);
  writeReg(CC1101_MDMCFG1,  CC1101_DEFVAL_MDMCFG1);
  writeReg(CC1101_MDMCFG0,  CC1101_DEFVAL_MDMCFG0);
 
  writeReg(CC1101_MCSM2,  CC1101_DEFVAL_MCSM2);
  writeReg(CC1101_MCSM1,  CC1101_DEFVAL_MCSM1);
  writeReg(CC1101_MCSM0,  CC1101_DEFVAL_MCSM0);
  writeReg(CC1101_FOCCFG,  CC1101_DEFVAL_FOCCFG);
  writeReg(CC1101_BSCFG,  CC1101_DEFVAL_BSCFG);
  writeReg(CC1101_AGCCTRL2,  CC1101_DEFVAL_AGCCTRL2);
  writeReg(CC1101_AGCCTRL1,  CC1101_DEFVAL_AGCCTRL1);
  writeReg(CC1101_AGCCTRL0,  CC1101_DEFVAL_AGCCTRL0);
  writeReg(CC1101_WOREVT1,  CC1101_DEFVAL_WOREVT1);
  writeReg(CC1101_WOREVT0,  CC1101_DEFVAL_WOREVT0);
  writeReg(CC1101_WORCTRL,  CC1101_DEFVAL_WORCTRL);
  writeReg(CC1101_FREND1,  CC1101_DEFVAL_FREND1);
  writeReg(CC1101_FREND0,  CC1101_DEFVAL_FREND0);
  writeReg(CC1101_FSCAL3,  CC1101_DEFVAL_FSCAL3);
  writeReg(CC1101_FSCAL2,  CC1101_DEFVAL_FSCAL2);
  writeReg(CC1101_FSCAL1,  CC1101_DEFVAL_FSCAL1);
  writeReg(CC1101_FSCAL0,  CC1101_DEFVAL_FSCAL0);
  writeReg(CC1101_RCCTRL1,  CC1101_DEFVAL_RCCTRL1);
  writeReg(CC1101_RCCTRL0,  CC1101_DEFVAL_RCCTRL0);
  writeReg(CC1101_FSTEST,  CC1101_DEFVAL_FSTEST);
  writeReg(CC1101_PTEST,  CC1101_DEFVAL_PTEST);
  writeReg(CC1101_AGCTEST,  CC1101_DEFVAL_AGCTEST);
  writeReg(CC1101_TEST2,  CC1101_DEFVAL_TEST2);
  writeReg(CC1101_TEST1,  CC1101_DEFVAL_TEST1);
  writeReg(CC1101_TEST0,  CC1101_DEFVAL_TEST0);
  
  // Send empty packet
//  CCPACKET packet;
//  packet.length = 0;
//  sendData(packet);
}

/**
 * cmdStrobe
 * 
 * Send command strobe to the CC1101 IC via SPI
 * 
 * 'cmd'  Command strobe
 */     
void cmdStrobe(uint8_t cmd) 
{
  cc1101_Select();                      // Select CC1101
  //wait_Miso();                          // Wait until MISO goes low
  //spi.transfer(cmd);                        // Send strobe command
  SPI.transfer(cmd);                        // Send strobe command
  cc1101_Deselect();                    // Deselect CC1101
}


/**
 * setRxState
 * 
 * Enter Rx state
 */
void setRxState()
{
  cmdStrobe(CC1101_SRX);

}

void setTxState()
{
  cmdStrobe(CC1101_STX);

}


/**
 * reset
 * 
 * Reset CC1101
 */
void CC1101_reset(void) 
{
  cc1101_Deselect();                    // Deselect CC1101
  delay(1);
  cc1101_Select();                      // Select CC1101
  delay(1);
  cc1101_Deselect();                    // Deselect CC1101
  delay(1);
  cc1101_Select();                      // Select CC1101

  wait_Miso();                          // Wait until MISO goes low
  //spi.transfer(CC1101_SRES);                // Send reset command strobe
  SPI.transfer(CC1101_SRES);                // Send reset command strobe
  wait_Miso();                          // Wait until MISO goes low

  cc1101_Deselect();                    // Deselect CC1101


}

void ConfigureCC1101()
{
    setCCregs();                          // Reconfigure CC1101
}

uint8_t VerifyCC1101Config()
{

   if (readReg(CC1101_IOCFG2,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_IOCFG2)
   {
      Serial.println(readReg(CC1101_IOCFG2,CC1101_CONFIG_REGISTER),HEX);
      return(1);
   }
   if (readReg(CC1101_IOCFG1,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_IOCFG1)
      return(2);
   if (readReg(CC1101_IOCFG0,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_IOCFG0)
      return(3);
   if (readReg(CC1101_FIFOTHR,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_FIFOTHR)
      return(4);
   if (readReg(CC1101_PKTLEN,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_PKTLEN)
      return(5);
   if (readReg(CC1101_PKTCTRL1,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_PKTCTRL1)
      return(6);
   if (readReg(CC1101_PKTCTRL0,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_PKTCTRL0)
      return(7);
   if (readReg(CC1101_FSCTRL1,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_FSCTRL1)
      return(8);
   if (readReg(CC1101_FSCTRL0,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_FSCTRL0)
      return(9);
   if (readReg(CC1101_FREQ2,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_FREQ2)
      return(10);
   if (readReg(CC1101_FREQ1,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_FREQ1)
      return(11);
   if (readReg(CC1101_FREQ0,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_FREQ0)
      return(12);
   if (readReg(CC1101_DEVIATN,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_DEVIATN)
      return(13);
   if (readReg(CC1101_MDMCFG4,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_MDMCFG4)
      return(14);
   if (readReg(CC1101_MDMCFG3,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_MDMCFG3)
      return(15);
   if (readReg(CC1101_MDMCFG2,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_MDMCFG2)
      return(16);
   if (readReg(CC1101_MDMCFG1,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_MDMCFG1)
      return(17);
   if (readReg(CC1101_MDMCFG0,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_MDMCFG0)
      return(18);
   if (readReg(CC1101_MCSM2,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_MCSM2)
      return(19);
   if (readReg(CC1101_MCSM1,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_MCSM1)
      return(20);
   if (readReg(CC1101_MCSM0,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_MCSM0)
      return(21);
   if (readReg(CC1101_FOCCFG,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_FOCCFG)
      return(22);
   if (readReg(CC1101_BSCFG,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_BSCFG)
      return(23);
   if (readReg(CC1101_AGCCTRL2,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_AGCCTRL2)
      return(24);
   if (readReg(CC1101_AGCCTRL1,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_AGCCTRL1)
      return(25);
   if (readReg(CC1101_AGCCTRL0,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_AGCCTRL0)
      return(26);
//   if (readReg(CC1101_IOCFG2,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_IOCFG1)
//      return(27);
//   if (readReg(CC1101_IOCFG2,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_IOCFG1)
//      return(28);      
//   if (readReg(CC1101_IOCFG2,CC1101_CONFIG_REGISTER) !=  CC1101_DEFVAL_IOCFG1);
//      return(29);
      

   return(0);
//  writeReg(CC1101_WOREVT1,  CC1101_DEFVAL_WOREVT1);
//  writeReg(CC1101_WOREVT0,  CC1101_DEFVAL_WOREVT0);
//  writeReg(CC1101_WORCTRL,  CC1101_DEFVAL_WORCTRL);
//  writeReg(CC1101_FREND1,  CC1101_DEFVAL_FREND1);
//  writeReg(CC1101_FREND0,  CC1101_DEFVAL_FREND0);
//  writeReg(CC1101_FSCAL3,  CC1101_DEFVAL_FSCAL3);
//  writeReg(CC1101_FSCAL2,  CC1101_DEFVAL_FSCAL2);
//  writeReg(CC1101_FSCAL1,  CC1101_DEFVAL_FSCAL1);
//  writeReg(CC1101_FSCAL0,  CC1101_DEFVAL_FSCAL0);
//  writeReg(CC1101_RCCTRL1,  CC1101_DEFVAL_RCCTRL1);
//  writeReg(CC1101_RCCTRL0,  CC1101_DEFVAL_RCCTRL0);
//  writeReg(CC1101_FSTEST,  CC1101_DEFVAL_FSTEST);
//  writeReg(CC1101_PTEST,  CC1101_DEFVAL_PTEST);
//  writeReg(CC1101_AGCTEST,  CC1101_DEFVAL_AGCTEST);
//  writeReg(CC1101_TEST2,  CC1101_DEFVAL_TEST2);
//  writeReg(CC1101_TEST1,  CC1101_DEFVAL_TEST1);
//  writeReg(CC1101_TEST0,  CC1101_DEFVAL_TEST0);
}

boolean GetCarrierStatus()
{
#ifndef USE_HW_CD
  uint8_t ret;

  
  ret = readStatusReg(CC1101_PKTSTATUS);

  if ((ret & 0x40) == 0)
  {
    return(false);
  }
  else
  {
    return(true);
  }
#else
    if (digitalRead(CDPin) == HIGH)
    {
      return(true);
    }
    else
    {
      return(false);
    }
#endif
}

void WaitCarrierEnd()
{
   while (GetCarrierStatus() == true)
   {
       //wait for carrier detect to change to low state
       delayMicroseconds(100);
   }
}

uint8_t GetState()
{
  uint8_t ret;
  ret = readStatusReg(CC1101_MARCSTATE);
  return(ret);
}

void Calibrate()
{

    
    Serial.println(F("Calibrating..."));    
//    setIdleState();
//    StartCalibration();
//    delayMicroseconds(100);
//    while(GetState() != 0x01)
//    {};  //wait for idle state
    Serial.println(F("Calibration complete"));

}

uint8_t Get_RX_FIFO_Count()
{
  return(readStatusReg(CC1101_RXBYTES));
}

void Flush_RX_FIFO(bool ReEnableRXMode)
{
   setIdleState();
   flushRxFifo();
   if (ReEnableRXMode)
   {
      setRxState(); 
   }
   
}
bool IsRX_FIFO_Overflow()
{
  if ((Get_RX_FIFO_Count() & 0x80) == 0x80)
  {
    return(true);    
  }
  else
  {
    return(false);
  }
}

uint8_t ReadFIFO()
{
  return(readStatusReg(CC1101_RXFIFO));
}

Toyota_TRW_C070

C Header File
#ifdef UK_433MHz

   

    #define EXPECTEDBITCOUNT 64
    #define EXPECTEDBYTECOUNT 8
    
    #define SYNCBITS 16
    
    #define CDWIDTH_MIN 5500
    #define CDWIDTH_MAX 9000
    
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_NOM 50
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 140
    #define SYNCTIMING_MAX 160
    
    #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 9000
    
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_NOM 50
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 140
    #define SYNCTIMING_MAX 160
    
    #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;
  double realpressure;
  float realtemp;



  for (i = 2; i <= 5; i++)
  {
    id = id << 8;
    id = id + RXBytes[i];

  }

  GetPreferredIndexStr(id, Ref);

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

  status = RXBytes[6];


  temp = RXBytes[1] & 0x7F;
  realtemp = (float)temp;
  realtemp = realtemp - 50;
  realpressure =  ((double)RXBytes[0] / 5.0);



  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);

#endif



   MatchIDandUpdate(id,status, realtemp, realpressure);
   

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



}



void ConvertTimingsToBits()
{
   int16_t i,x;
   
   //bool CurrentState = FirstEdgeState;
   bool CurrentState = FirstEdgeIsHighToLow?true:false;
   BitCount = 0;
   ValidTimingsStart = 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 (IsTooLong(Timings[i] ) && (i< 30))
          {
             for (x = 1;x<= (int)((((float)Timings[i]/SHORTTIMING_NOM)) + 0.5);x++)
             {
                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;
                   ValidTimingsStart = i+1;
               }
               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 bitcount > MAXBITS-1"));
         #endif
         return;
      }
   }
  
}


void ConvertTimingsToBits_Old()
{
   int16_t i;
   
   //bool CurrentState = FirstEdgeState;
   bool CurrentState = FirstEdgeIsHighToLow?true:false;
   BitCount = 0;
   ValidTimingsStart = 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 (IsValidSync(Timings[i]) && (i< 20))
          {
             IncomingBits[BitCount++] = CurrentState;
             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;
                   ValidTimingsStart = i+1;
               }
               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 bitcount > MAXBITS-1"));
         #endif
         return;
      }
   }
  
}


bool ValidateBits()
{
  uint8_t crcResult;
  uint8_t ByteCount = 0;
  int16_t ManchesterStartPos = -1;
  const uint8_t pattern[] = {0x55};
  
  ManchesterStartPos = FindManchesterStart(pattern, 8);
//  Serial.print(F("Manchester start: "));
//  Serial.println(ManchesterStartPos);
  StartDataIndex = ManchesterStartPos;

  int Attempts = (BitCount - (EXPECTEDBITCOUNT*2))+1;
  if (Attempts < 0)
     Attempts = 0;
  int16_t StartPoint = 0;  //shift start point

  if (StartDataIndex == -1)
  {//couldn't find header
    Attempts = 0;
    StartPoint = 0;
    #ifdef SHOWDEBUGINFO
        Serial.println(F("Header not found"));
    #endif
  }
  else
  {
    StartPoint = StartDataIndex;
  }
  
  while (Attempts > 0)
  {
    ByteCount = ManchesterDecode(StartPoint );
    if (ByteCount >= EXPECTEDBYTECOUNT)
    {     
        //check the checksum...
        crcResult = Compute_CRC8(7,0x07,  0x00);
        if (crcResult == RXBytes[7]) 
        {
           StartDataIndex = StartPoint;
           return(true);
        }
        else
        {
           StartPoint++;
           Attempts--; 
        }
    }
    else
    {
       StartPoint++;
       Attempts--; 
    }

  
  }

  return(false);

}

bool ValidateTimings()
{


  bool GoodCSUM = false;

  StartDataIndex = 0;
  ClearRXBuffer();

  if (TimingsIndex < 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);
  }



  ConvertTimingsToBits();

  if (BitCount < (EXPECTEDBITCOUNT*2) ) //2 incoming (Manchester) bits = 1 expected bit
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
       Serial.print(F("Insufficient decoded bit count ="));
       Serial.println(BitCount);
    #endif
    return (false);
  }

  GoodCSUM = ValidateBits();
  


  if (GoodCSUM == false)
  {
     #ifdef SHOWDEBUGINFO
        Serial.println(F("Inverting.."));
     #endif
     InvertBitBuffer();
     GoodCSUM = ValidateBits();
     
  }
  

  if (GoodCSUM == false)
  {
     #ifdef SHOWDEBUGINFO
       Serial.println(F("No valid data found"));
       Serial.print(F("Bit count: "));
       Serial.print(BitCount);
       Serial.print(F("  Attempts: "));
       Serial.println((BitCount - (EXPECTEDBITCOUNT*2))+1);
     #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);
  }




}

Schrader_C1100

C Header File
#ifdef UK_433MHz

   

    #define EXPECTEDBITCOUNT 72
    #define EXPECTEDBYTECOUNT 9
    
    #define SYNCBITS 16
    
    #define CDWIDTH_MIN 7500
    #define CDWIDTH_MAX 11000
    
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_NOM 50
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 140
    #define SYNCTIMING_MAX 160
    
    #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 72
    #define EXPECTEDBYTECOUNT 9
    
    #define SYNCBITS 16
    
    #define CDWIDTH_MIN 7500
    #define CDWIDTH_MAX 11000
    
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_NOM 50
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 120
    #define SYNCTIMING_MIN 140
    #define SYNCTIMING_MAX 160
    
    #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,  temp;
  double realpressure;
  float realtemp;
  bool BatteryIsLow = false;


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

  }

  GetPreferredIndexStr(id, Ref);

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

  status = RXBytes[7];
  if (status && 0x80 == 0x80)
  {
    BatteryIsLow = true;
  }
  


  temp = RXBytes[6];
  realtemp = (float)temp;
  realtemp = realtemp - 56;
  pressure1 = RXBytes[4];
  realpressure =  ((double)(pressure1) * 0.51) - 0.9;



  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("   Sudden pressure change?: "));
//  if (status & 0x10)
//  {
//    Serial.print(F("Yes"));
//  }
//  else
//  {
//    Serial.print(F("No"));
//  }
//  Serial.print(F("   Manual trigger (LF)?: "));
//  if (status & 0x01)
//  {
//    Serial.print(F("Yes"));
//  }
//  else
//  {
//    Serial.print(F("No"));
//  }
//  Serial.println(F(""));
#endif



   MatchIDandUpdate(id,status, realtemp, realpressure);
   

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


}



void ConvertTimingsToBits()
{
   int16_t i,x;
   
   //bool CurrentState = FirstEdgeState;
   bool CurrentState = FirstEdgeIsHighToLow?true:false;
   BitCount = 0;
   ValidTimingsStart = 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 (IsTooLong(Timings[i] ) && (i< 30))
          {
             for (x = 1;x<= (int)((((float)Timings[i]/SHORTTIMING_NOM)) + 0.5);x++)
             {
                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;
                   ValidTimingsStart = i+1;
               }
               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 bitcount > MAXBITS-1"));
         #endif
         return;
      }
   }
  
}



bool ValidateBits()
{
  uint8_t crcResult;
  uint8_t ByteCount = 0;
  int16_t ManchesterStartPos = -1;
  //const uint8_t pattern[] = {0x71, 0x55};
  //const uint8_t pattern[] = {0x86};
  const uint8_t pattern[] = {0xAA, 0xA9};
  //const uint8_t pattern[] = { 0x07};
  
  ManchesterStartPos = FindManchesterStart(pattern, sizeof(pattern) * 8);
//  Serial.print(F("Manchester start: "));
//  Serial.println(ManchesterStartPos);
  StartDataIndex = ManchesterStartPos;
  ByteCount = ManchesterDecode(StartDataIndex );
//  PrintBytes(ByteCount);
  
//
//  return(true);

  int16_t Attempts = (BitCount - (EXPECTEDBITCOUNT*2))+1;
  if (Attempts < 0)
     Attempts = 0;
  int16_t StartPoint = 0;  //shift start point

  if (StartDataIndex == -1)
  {//couldn't find header
    Attempts = 0;
    StartPoint = 0;
    #ifdef SHOWDEBUGINFO
        Serial.println(F("Header not found"));
    #endif
  }
  else
  {
    StartPoint = StartDataIndex;
  }

// ManchesterDecode(StartPoint );
// PrintData(0,StartPoint);
// PrintData(StartPoint,ByteCount * 8 *2);
  
  while (Attempts > 0)
  {
    ByteCount = ManchesterDecode(StartPoint );

    if (ByteCount >= EXPECTEDBYTECOUNT)
    {     
        //PrintBytes(ByteCount);
        crcResult = Compute_CRC_SUM(0, 8, 0);
        if (crcResult == RXBytes[8]) 
        {
           StartDataIndex = StartPoint;
           return(true);
        }
        else
        {
//           StartDataIndex = StartPoint;
//           return(true);
           StartPoint++;
           Attempts--; 
        }
    }
    else
    {
       StartPoint++;
       Attempts--; 
    }

  
  }

  return(false);

}

bool ValidateTimings()
{

  bool GoodCSUM = false;

  StartDataIndex = 0;
  ClearRXBuffer();

  if (TimingsIndex < 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();

  if (BitCount < (EXPECTEDBITCOUNT*2) ) //2 incoming (Manchester) bits = 1 expected bit
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
       Serial.print(F("Insufficient decoded bit count ="));
       Serial.println(BitCount);
    #endif
    return (false);
  }

  InvertBitBuffer();
  GoodCSUM = ValidateBits();
  

  if (GoodCSUM == false)
  {
     #ifdef SHOWDEBUGINFO
       Serial.println(F("No valid data found"));
       Serial.print(F("Bit count: "));
       Serial.print(BitCount);
       Serial.print(F("  Attempts: "));
       Serial.println((BitCount - (EXPECTEDBITCOUNT*2))+1);
     #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.
//       #ifdef SHOWDEBUGINFO
//         PrintTimings(0,ValidTimingsStart);
//         PrintTimings(ValidTimingsStart,TimingsIndex-ValidTimingsStart );
//         PrintData(0,ManchesterStartPos);
//         PrintData(ManchesterStartPos,ByteCount * 8 *2);
//       #endif
        return(true);
  }




}

Schrader_A9054100

C Header File
#ifdef UK_433MHz

   

    #define EXPECTEDBITCOUNT 64
    #define EXPECTEDBYTECOUNT 8
    
    #define SYNCBITS 4
    
    #define CDWIDTH_MIN 12000
    #define CDWIDTH_MAX 30000
    
    #define SHORTTIMING_MIN 80
    #define SHORTTIMING_NOM 120
    #define SHORTTIMING_MAX 160
    #define LONGTIMING_MIN 180
    #define LONGTIMING_MAX 260
    #define SYNCTIMING_MIN 260
    #define SYNCTIMING_MAX 160
    
    #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    0x47        // 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     0x00        // 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    0x06        // 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    0xC8        // Modem Configuration (C8 = data rate 8kHz, bandwidth 116kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x43        // Modem Configuration (now 93 = data rate = 8kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x34       // Modem Configuration (ASK, no sync + no Manchester coding)
    #define CC1101_DEFVAL_MDMCFG1    0x21        // Modem Configuration Channel spacing 100kHz
    #define CC1101_DEFVAL_MDMCFG0    0xF8        // Modem Configuration      
    #define CC1101_DEFVAL_AGCCTRL2   0x64 //0x64       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x78 //0x78        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0xB3 //0xB3        // 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     0x14        // 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     0xB6        // 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 Schrader_A9054100 timings not defined for 315MHz 

#endif

void DecodeTPMS()
{
  int16_t i;
  uint32_t id = 0;
  uint16_t status, pressure1, temp;
  double realpressure;
  float realtemp;
  char ID[8];

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

  }

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

  GetPreferredIndexStr(id, Ref);

 
  status = (RXBytes[0] & 0x0F);
  status = status << 4;
  status = status + (RXBytes[1] >> 4);

  


  temp = RXBytes[6];
  realtemp = (float)temp;
  realtemp = realtemp - 50;
  //pressure1 = RXBytes[5];
  pressure1 = RXBytes[5];
  realpressure =  (((double)(pressure1) * 0.362) - 0.05);



  if (realpressure < 0)
     realpressure = 0.0;




#ifdef SHOWVALIDTPMS
  Serial.print(F("Pos: "));
  Serial.print(Ref);
  Serial.print(F("   ID: "));
  sprintf(ID,"%07lX", id);
  Serial.print(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);

#endif



   MatchIDandUpdate(id,status, realtemp, realpressure);
   

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


}



void ConvertTimingsToBits()
{
   int16_t i,x;
   
   //bool CurrentState = FirstEdgeState;
   bool CurrentState = FirstEdgeIsHighToLow?true:false;
   BitCount = 0;
   ValidTimingsStart = 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 (IsTooLong(Timings[i] ))
          {
            if (i < 30)
            {//expand any leading long pulses (may be syncs)
              for (x = 1;x<= (int)((((float)Timings[i]/SHORTTIMING_NOM)) + 0.5);x++)
              {
                  IncomingBits[BitCount++] = CurrentState;
              }
            }
            else
            {//assume an end bit, end the conversion
              IncomingBits[BitCount++] = CurrentState;
              return;
            }
           
          }
          else
          {
         
            if (IsTooShort(Timings[i] ))
            {
            
               if (i < TimingsIndex/2)  //enough bits in the buffer to continue trying?
               { //invalid bit timing, reset
                   
                   BitCount = 0;
                   ValidTimingsStart = i+1;
               }
               else
               {// end the conversion
  //                #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 bitcount > MAXBITS-1"));
         #endif
         return;
      }
   }
  
}



bool ValidateBits()
{
  uint8_t crcResult;
  uint8_t ByteCount = 0;
  int16_t ManchesterStartPos = -1;
  int16_t Attempts;
  int16_t Tries;
  int16_t StartPoint;

  //const uint8_t pattern[] = {0xAB, 0x40};
  const uint8_t pattern[] = {0xD5};


  
  ManchesterStartPos = FindManchesterStart(pattern, 8);
  if (ManchesterStartPos >= 0)
  {
    StartDataIndex = ManchesterStartPos - 0;
    StartPoint = StartDataIndex;
    ByteCount = ManchesterDecode_ZeroBit(StartPoint );
    if (ByteCount >= EXPECTEDBYTECOUNT)
    {     
        //PrintBytes(ByteCount);
        RXBytes[0] = RXBytes[0] & 0x0F;  //ignore upper nibble - thisis a sync nibble and not used in the crc

        //check the checksum...
        crcResult = Compute_CRC8(7,0x07,  0x00);  
        //crcResult = Compute_CRC_SUM(0, 8, 0);
        if (crcResult == RXBytes[7]) 
        {
          return(true);
        }
    }
    StartDataIndex = 0;
    StartPoint = 0;  //shift start point
    ClearRXBuffer();
    

    
  }
  else
  {

    #ifdef SHOWDEBUGINFO
        Serial.println(F("Header pattern not found"));
    #endif
  }

  StartPoint = 0;
  Tries = 1;

  Attempts = (BitCount - (EXPECTEDBITCOUNT*2))+1;
  if (Attempts < 0)
     Attempts = 0;


//ManchesterDecode_ZeroBit(StartPoint );
// PrintData(0,StartPoint);
// PrintData(StartPoint,ByteCount * 8 *2);
  
  while (Attempts > 0)
  {
    ByteCount = ManchesterDecode_ZeroBit(StartPoint );
    //Serial.println(ByteCount);

    if (ByteCount >= EXPECTEDBYTECOUNT)
    {     
        //PrintBytes(ByteCount);
        RXBytes[0] = RXBytes[0] & 0x0F;  //ignore upper nibble - thisis a sync nibble and not used in the crc

        //check the checksum...
        crcResult = Compute_CRC8(7,0x07,  0x00);  
        //crcResult = Compute_CRC_SUM(0, 8, 0);
        if (crcResult == RXBytes[7]) 
        {
           StartDataIndex = StartPoint;
           #ifdef SHOWDEBUGINFO
              Serial.print("Tries = ");
              Serial.println(Tries);
           #endif
           return(true);
        }
        else
        {
//           StartDataIndex = StartPoint;
//           return(true);
           StartPoint++;
           Attempts--; 
        }
    }
    else
    {
       StartPoint++;
       Attempts--; 
    }
    Tries++;
    ClearRXBuffer();
  
  }

  return(false);

}

bool ValidateTimings()
{


  bool GoodCSUM = false;

  StartDataIndex = 0;
  ClearRXBuffer();

  if (TimingsIndex < 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);
  }



  ConvertTimingsToBits();

  if (BitCount < (EXPECTEDBITCOUNT*2) ) //2 incoming (Manchester) bits = 1 expected bit
  { //not enough in the buffer to consider a valid message
    #ifdef SHOWDEBUGINFO
       Serial.print(F("Insufficient decoded bit count ="));
       Serial.println(BitCount);
    #endif
    return (false);
  }

  GoodCSUM = ValidateBits();
  

  if (GoodCSUM == false)
  {
     #ifdef SHOWDEBUGINFO
       Serial.println(F("No valid data found"));
       Serial.print(F("Bit count: "));
       Serial.print(BitCount);
       Serial.print(F("  Attempts: "));
       Serial.println((BitCount - (EXPECTEDBITCOUNT*2))+1);
     #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);
  }




}

Subaru

C Header File
#ifdef UK_433MHz
    //Subaru Impreza 09/2016-12/2022 Sensor: Schrader PN 28103FL000/28103FL00A
    //Uses FSK with 50us pulse widths (different protocol from 315MHz)
    
    #define EXPECTEDBITCOUNT 72
    #define EXPECTEDBYTECOUNT 9
    
    #define SYNCBITS 24
    
    #define CDWIDTH_MIN 8500
    #define CDWIDTH_MAX 20000
    
    #define SHORTTIMING_MIN 35
    #define SHORTTIMING_NOM 50
    #define SHORTTIMING_MAX 79
    #define LONGTIMING_MIN 80
    #define LONGTIMING_MAX 160
    #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
     //Subaru Impreza 07/2013-12/2022 Sensor: Schrader PN 28103SG000/28103AJ00A
     //Uses ASK with 100us pulse widths (different protocol from 433MHz), looks to be same as RTL433 Schrader SMD3MA4

    #define EXPECTEDBITCOUNT 42
    #define EXPECTEDBYTECOUNT 5 //4 + 2 bits)
    
    #define SYNCBITS 24
    
    #define CDWIDTH_MIN 10000
    #define CDWIDTH_MAX 23000
    
    #define SHORTTIMING_MIN 70
    #define SHORTTIMING_NOM 100
    #define SHORTTIMING_MAX 159
    #define LONGTIMING_MIN 160
    #define LONGTIMING_MAX 300
    #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    0x4F        // 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 

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

    #define CC1101_DEFVAL_MDMCFG4    0x58        // Modem Configuration (59 = data rate = 8kHz - actual data rate is 4kHz but due to bi-phase coding need to double the rate, RX bandwidth 325kHz)
    #define CC1101_DEFVAL_MDMCFG3    0x43        // Modem Configuration (now 43 = data rate = 8kHz)
    #define CC1101_DEFVAL_MDMCFG2    0x34        // Modem Configuration (ASK, no preamble, 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   0x64 //0x64       // AGC Control
    #define CC1101_DEFVAL_AGCCTRL1   0x78 //0x78        // AGC Control
    #define CC1101_DEFVAL_AGCCTRL0   0xB3 //0xB3        // 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     0x14   //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     0xB6  //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
     #error Subaru timings not defined,, choose 433MHz or 325MHz


#endif


void ConvertTimingsToBits()
{
   int16_t i,x;
   
   //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 (IsTooLong(Timings[i] ) && (i< 40))
          {
             for (x = 1;x<= (int)((((float)Timings[i]/SHORTTIMING_NOM)) + 0.5);x++)
             {
                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;
                   ValidTimingsStart = i+1;
               }
               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;
      }
   }
  
}


#ifdef UK_433MHz
  void DecodeTPMS()
  {
    int16_t i;
    uint32_t id = 0;
    uint16_t status, pressure1,  temp;
    double realpressure;
    float realtemp;
    bool BatteryIsLow = false;
  
  
    for (i = 0; i <= 3; i++)
    {
      id = id << 8;
      id = id + RXBytes[i];
  
    }
  
    GetPreferredIndexStr(id, Ref);
  
    // id = (unsigned)RXBytes[0] << 24 | RXBytes[1] << 16 | RXBytes[2] << 8 | RXBytes[3];
  
    status = RXBytes[7];
    if (status && 0x80 == 0x80)
    {
      BatteryIsLow = true;
    }
    
  
  
    temp = RXBytes[6];
    realtemp = (float)temp;
    realtemp = realtemp - 52;
    pressure1 = RXBytes[4];
    realpressure =  ((double)(pressure1) * 0.4) + 0.1 ;
  
  
  
    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("   Sudden pressure change?: "));
  //  if (status & 0x10)
  //  {
  //    Serial.print(F("Yes"));
  //  }
  //  else
  //  {
  //    Serial.print(F("No"));
  //  }
  //  Serial.print(F("   Manual trigger (LF)?: "));
  //  if (status & 0x01)
  //  {
  //    Serial.print(F("Yes"));
  //  }
  //  else
  //  {
  //    Serial.print(F("No"));
  //  }
  //  Serial.println(F(""));
  #endif
  
    //DisplayStatusInfo();
  
     MatchIDandUpdate(id,status, realtemp, realpressure);
     
  
    #ifdef SHOWVALIDTPMS
       Serial.println(F(""));
    #endif
  }
  

  bool ValidateTimings()
  {
  

    int16_t ManchesterStartPos = -1;
    uint8_t ByteCount = 0;
    uint8_t crcResult;
    uint8_t ReceivedCRC = 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();
    
  //  Serial.println("Incoming raw bit stream...");
  //  PrintData(0,BitCount, false);
  
  
    InvertBitBuffer();
    
  //  Serial.println("Inverted raw bits..");
  //  PrintData(0,BitCount, false);
  
    //const uint8_t pattern[] = {0xA6,0xA6, 0x5A};
    const uint8_t pattern[] = {0xAA,0xAA,0xA1};
    ManchesterStartPos = FindManchesterStart(pattern, 24) ;
    if (ManchesterStartPos < 0) ManchesterStartPos = 0;
    
    StartDataIndex = ManchesterStartPos;
  
  //  Serial.println("Bits for Manchester decoding..");
  //  PrintData(ManchesterStartPos,BitCount-ManchesterStartPos, false);
  
  
  
  
    if (ManchesterStartPos == -1 )
    {
      #ifdef SHOWDEBUGINFO
         Serial.println(F("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);
  
  //  Serial.println("Manchester decoded bits..");
  //  PrintManchesterData(0,  ManchesterBitCount,false);
  //
  //  Serial.print(F("Byte count = "));
  //  Serial.println(ByteCount);
  //  PrintBytes(ByteCount);
    
    if (ByteCount >= EXPECTEDBYTECOUNT)
    {
  
        
        
        //checksum unknown...
        crcResult = Compute_CRC_SUM(0, 8, 0);
        if (crcResult != RXBytes[8])
        {
           #ifdef SHOWDEBUGINFO
            Serial.print(F("CRC calc: "));
            Serial.print(crcResult, HEX);
            Serial.print(F("  CRC rcvd: "));
            Serial.println(ReceivedCRC, HEX);
            Serial.println(F("CRC Check failed"));
            PrintBytes(ByteCount);
            #endif
          #ifdef IGNORECHECKSUMERRORS
            DecodeTPMS();
            TPMS_Changed = false;  //don't update display for csum error
          #endif
          return(false);
        }
        else
        {
          //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);
    }
  
  
  }

#else

  //US 315MHz
  //  ^^^^_^_^_^_^_^_^_^_^_^_^_^_^_^ _^^^^^_FFFFFFIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIPPPPPPPPPPPPPPPPCCCC
  //inverted....
  //  ____^_^_^_^_^_^_^_^_^_^_^_^_^_ ^_____^ FFFFFFII IIIIIIII IIIIIIII IIIIIIII IIIIIIII IIIIIIII IIIIIIPP PPPPPPPP PPPPPPCC CC

  void DecodeTPMS()
  {
    int16_t i;
    uint32_t id = 0;
    uint16_t status, pressure1, pressure2, temp;
    double realpressure;
    float realtemp;
    bool IDFound = false;
    uint8_t SensorType;
    bool BatteryIsLow = false;
  
  
    for (i = 0; i <= 3; i++)
    {
      id = id << 8;
      id = id + RXBytes[i];
  
    }

    id = RXBytes[0] & 0x1F;
    id = (id << 8) + RXBytes[1];
    id = (id << 8) + RXBytes[2];
    id = id << 3;
    id = id + (RXBytes[3] >>5);
    
    
  
    GetPreferredIndexStr(id, Ref);
  
    // id = (unsigned)RXBytes[0] << 24 | RXBytes[1] << 16 | RXBytes[2] << 8 | RXBytes[3];
  
    status = RXBytes[0] >> 5;
//    if (status && 0x80 == 0x80)
//    {
//      BatteryIsLow = true;
//    }
    
  
  
    temp = 0;  //no temperature transmitted!!
    realtemp = (float)temp;
    realtemp = realtemp - 52;
    realtemp = NO_VALID_TEMPERATURE;
    //pressure1 = RXBytes[5];
    pressure1 = ((RXBytes[3] & 0x1F) << 3)  + (RXBytes[4] >> 5) ;
    Serial.print(F("Pressure byte = 0x"));
    Serial.println(pressure1,HEX);
    realpressure =  ((double)(pressure1) * 0.2) ;
  
  
  
    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("   No Temperatures Transmitted "));
    if (realtemp == NO_VALID_TEMPERATURE)
    {
       Serial.print("---");
    }
    else
    {
       Serial.print(realtemp);
    }
    Serial.print(F("   Tyre Pressure: "));
    Serial.print(realpressure);
  //  Serial.print(F("   Sudden pressure change?: "));
  //  if (status & 0x10)
  //  {
  //    Serial.print(F("Yes"));
  //  }
  //  else
  //  {
  //    Serial.print(F("No"));
  //  }
  //  Serial.print(F("   Manual trigger (LF)?: "));
  //  if (status & 0x01)
  //  {
  //    Serial.print(F("Yes"));
  //  }
  //  else
  //  {
  //    Serial.print(F("No"));
  //  }
  //  Serial.println(F(""));
  #endif
  
    //DisplayStatusInfo();
  
     MatchIDandUpdate(id,status, realtemp, realpressure);
     
  
    #ifdef SHOWVALIDTPMS
       Serial.println(F(""));
    #endif
  }
  

  bool ValidateTimings()
  {
  
  
    uint8_t BitWidth;
    uint8_t BitWidthNext;
    uint8_t BitWidthNextPlus1;
    uint8_t BitWidthPrevious;
    uint8_t diff = TimingsIndex - CheckIndex;
    //uint32_t tmp;
    bool WaitingTrailingZeroEdge = false;
    int16_t ret;
    int16_t ManchesterStartPos = -1;
    uint8_t ByteCount = 0;
    uint8_t crcResult;
    uint8_t ReceivedCRC = 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"));
         Serial.print("Timings index = ");
         Serial.println(TimingsIndex);
      #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();
    
//    Serial.println("Incoming raw bit stream...");
//    PrintData(0,BitCount, false);
  
  
    InvertBitBuffer();
    
//    Serial.println("Inverted raw bits..");
//    PrintData(0,BitCount, false);
  
    //const uint8_t pattern[] = {0xA6,0xA6, 0x5A};
    const uint8_t pattern[] = {0x55,0x55,0x41};
    ManchesterStartPos = FindManchesterStart(pattern, 24) ;
    if (ManchesterStartPos < 0) ManchesterStartPos = 0;
    
    StartDataIndex = ManchesterStartPos;
  
//    Serial.println("Bits for Manchester decoding..");
//    PrintData(ManchesterStartPos,BitCount-ManchesterStartPos, false);
  
  
  
  
    if (ManchesterStartPos == -1 )
    {
      #ifdef SHOWDEBUGINFO
         Serial.println(F("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);
  
//    Serial.println("Manchester decoded bits..");
//    PrintManchesterData(0,  ManchesterBitCount,false);
  
    Serial.print(F("Byte count = "));
    Serial.println(ByteCount);
    PrintBytes(ByteCount);
    
    if (ByteCount >= EXPECTEDBYTECOUNT)
    {
     
        //checksum unknown...
        crcResult = Compute_CRC_SUM(0, 4, 0);
            Serial.print(F("CRC calc: "));
            Serial.println(crcResult, HEX);        
        if (crcResult != crcResult )
        {
           #ifdef SHOWDEBUGINFO
            Serial.print(F("CRC calc: "));
            Serial.print(crcResult, HEX);
            Serial.print(F("  CRC rcvd: "));
            Serial.println(ReceivedCRC, HEX);
            Serial.println(F("CRC Check failed"));
            PrintBytes(ByteCount);
            #endif
          #ifdef IGNORECHECKSUMERRORS
            DecodeTPMS();
            TPMS_Changed = false;  //don't update display for csum error
          #endif
          return(false);
        }
        else
        {
          //decode the message...
          Serial.println(F("Checksum check unknown - treat data with caution!!"));
          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);
    }
  
  
  }



#endif

AllFilesV11_8

Plain text
Zip file of all software files in this project (to save downloading each one individually)
No preview (download only).

UKUS_Toyota_TPMS_Monitor_V12_X

Plain text
Trial version for EP32 which doesn't use CD signal
No preview (download only).

V11.9.zip

Plain text
Trial version for Mercedes AMG GT
No preview (download only).

UKUS_Toyota_TPMS_Monitor_V13_2

Plain text
Trial version for ESP32 Wifi and MQTT and BMW Series 5/Audi E-tron sensors. This version is in development and only a few sensors are supported at the moment. Code continually scans the received data rather than using the CD to frame the data
No preview (download only).

Credits

JSMSolns

JSMSolns

12 projects • 35 followers

Comments