Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
| ||||||
| ||||||
| ||||||
| ||||||
Hand tools and fabrication machines | ||||||
|
My wife drives a Toyota Auris Hybrid and sometime ago (winter I think) the TPMS (Tyre Pressure Monitoring System) dashboard warning light came on. Unfortunately that is all the information the car gives - no indication of which tyre is the problem or why. Checking the tyres and resetting the TPMS made it go away for a while before the problem quickly returned. At the next car service, it was mentioned to them and whatever they did, it seemed to go away. They stated that one of the tyres was slightly low on pressure which I disputed because I had checked them on several occasions. Anyway the problem seemed to be 'solved' but the frustration of not knowing why remained.
How It Came About (Part 2)I was recently using an RTL2832U dongle, SDR (Software Defined Radio) and the excellent RTL_433 software to sniff some 433MHz signals when, to my surprise, up popped some messages about Toyota Tyre pressures. I realised these were coming from my wife's car outside on the driveway. Given the history (see Part 1!), I thought I should be able to come up with a way to display these tyre pressures in the car using a standalone Arduino and without having to resort to the car's ODB2 interface and CAN message decoding.
About TPMSThere are various methods which car manufacturers use for TPMS and I would point out that this solution is targeted specifically at a Toyota Auris Hybrid. It may work on other Toyota hybrids/car types but I can't say for sure. Should you decide to do a similar project, you should ensure you know what type of monitoring system and sensor is used on your car before starting otherwise you will be disappointed.
The TPMS sensors on the Auris Hybrid tyres transmit at 433MHz approximately every 90 seconds although this varies (presumably to avoid repeated collisions). The data transmitted consists primarily of a sensor ID, the tyre pressure, the tyre temperature and a checksum (other status bits are also transmitted).
There is no indication of which sensor ID maps to which wheel so this is trial and error. I have worked out which is which for our car and encoded this in the software to ensure the information is displayed consistently.
The sensor signals do not appear to be very strong so I found I needed to be within 2-3 meters to get a reliable signal.
Note: Some TPMS sensors do not transmit when the vehicle is stationary - only when the vehicle is in motion or there is a sudden change in pressure. Please remember this if trying on different car/sensor types!
AcknowledgementsI'd like to acknowledge the work done by the RTL_433 team (in particular Christian W. Zuckschwerdt) and by 'shcm' on the RAV4 Drivers Club website. Both of these were very helpful to me in understanding the 433MHz transmission protocol from the tyres and therefore speeding up the development.
Very many thanks too to Steven Andrews for his most generous support and help on this project. He has been especially helpful in helping to progress the adding of sensors for other TPMS sensors.
Two libraries were included for the I2C display:
AdaFruit_GFX/Adafruit_SSD1306 (not used in the end due to memory limitations) SSD1306Ascii/SSD1306AsciiWire (Text only library) - thanks to Bill Greiman for this.
Library for the ST7735 TFT 128 x 160 display:
Adafruit_ST7735
Adafruit_GFX.h
Adafruit_ST7735.h
Library for the ST7735 TFT 240 x 240 (round) display:
Adafruit_GFX.h
Adafruit_GC9A01A.h
EasyEDA used for schematic capture
Technical DetailsUsing the GNU SDR software I was able to work out that the tyres transmit using FSK (Frequency Shift Keying). The centre frequency is about 433.88 MHz with a deviation of around +/- 24-30kHz. The data is Biphase Mark Coded and is 72 bits in length. The data rate is 10kHz and the total message length is about 8ms.
To receive the signal I chose a CC1101 module. This module is based around the CC1101 IC from Texas Instruments and has an SPI interface along with a couple of pins which can be configured in the device to output various signals. I configured it to output the raw receive signal and the carrier sense (CS) signal. The CS hardware signal was not used in the final solution as the same signal is available by polling a register over the SPI however the hardware signal was useful when hooking up the logic analyser to 'frame' the raw receive signal and aid debugging.
Configuration of the CC1101 registers can be a little daunting but there is a software package from TI called SMART RF Studio which can help with this. The CC1101 can be used with the internal FIFO etc. to capture the data bytes directly and read them over the SPI but I could see no way to configure it for the data I was expecting so this project uses it as a basic RF receiver with the RX data being output onto one of the configurable pins and the Arduino then tries to make sense of the data stream.
The CC1101 runs off 3.3volts. Most of the Arduino boards are 5v which means a level translator is required for the interface signals. I did in fact do this with a Mega initially but I wanted the final solution to be as compact as possible so I chose the Arduino Pro Micro 3v3 (note: there is also a 5v version of this so be careful which one is ordered!). This 3v3 board only runs at 8MHz and has limited RAM but I decided I could probably get away with this.
The display used was a 0.96" 128 x 96 yellow and blue I2C module based on the SSD1306 which can be found from various suppliers. My choice of Arduino came back to bite me a bit here as the normal library for these displays uses a 1k buffer to hold a mirror of the display data. This exceeded the RAM limit and meant I had to switch to a text only, low RAM library but it seemed to work well.
Once the basic register settings for the CC1101 were established, a logic analyser assisted in showing that the CC1101 was receiving a reliable signal and was used to decode the biphase mark coding to show the individual bytes (see image below). The logic analyser was triggered from the CS signal when the pulse width was around 8ms. This generally filtered out the analyser being triggered by other unwanted RF signals.
The picture below shows an example of the logic analyser capture from one of the tyres.
The shorter pulses are around 50us and the longer pulses around 100us. Data is transmitted MS bit first. There should be a sync pattern prior to the valid data but I didn't find this a very reliable method for detecting the start of the message (possibly due to my amateurish configuration of the CC1101 AGC etc.?)
Although the data rate is 10kHz, the bi-phase encoding meant the CC1101 needed to be configured at twice this data rate (20kHz) to ensure capturing of all the transitions
As reported in the RTL_433 code, the message structure is 1st 4 bytes = sensor ID, 1 bit status, 8 bits for the pressure (P), 8 bits for the temperature (T), 7 bit status, 8 bit pressure repeated (but inverted) and an 8 bit CRC (0x07 truncated polynomial with 0x80 initial value).
The actual temperature = (T - 40) degrees C
The actual pressure = ((P/4) - 7) PSI
So I could see the message on the analyser, all I had to do now was to implement a method of decoding this using the Arduino.
I tried a few methods but the one which proved the most efficient and reliable was:
- Wait for CS to go high (by reading the CC1101 status) and mark the start time
- Use the Arduino pin interrupt to detect and store the time between edges Timings less than 12us were classified as 'glitches' and ignored. If more than 255 transitions were seen, the interrupt routine stops storing the times (buffer full).
- When the CS goes low again, calculate the width of the CS being high. If it was high for the expected ~8ms, process the timing buffer and look for a valid message. If not ~8ms or no valid message detected, wait for the next CS high again.
- The validation routine checks the timings and converts them to 0s and 1s and stores these in a 'bit buffer'. The number of bits found is returned.
- If the number of bits is the expected 72, the bit buffer is decoded into bytes
- The byte buffer is checked for a valid TPMS message - 9 bytes in all anda includes a checksum check.
- The TPMS data is displayed on the I2C display module (screen position is TPMS sensor ID specific).
The 3 components (Arduino, CC1101, OLED display) were built into a 3D printed case. The design was created using Fusion 360. It isn't the best (although OK for a first prototype) and could do with refining in the following areas:
- A little bigger to allow more room for the cabling (currently a bit tight)
- Close down the USB cable entry aperture slightly
- Close down the OLED display area (an area at the bottom of the display does not form part of the display and could be hidden
Power is supplied through the 5v USB input and can be sourced from the USB socket in the car.
How to Build OneThe design and wiring is very simple (see schematic). Make sure the OLED is wired from the correct side to avoid wires getting in the way of any enclosure which might be used.
If you haven't used this particular Arduno board before, you may need to configure the Arduino IDE for the Pro Micro board.
An excellent guide for this can be found on the Sparkfun website here.
Make sure "Sparkfun Pro Micro" is selected from the Tools-> Board list menu.
Also ensure "ATmega32U4 (3.3V 8MHz)" is then selected from the Tools-> Processor menu.
Plug in the Arduino to the computer USB port and select the allocated port from the Tools-> Port menu option.
Load the code (consisting of 5 files) into the IDE and compile and upload it to the Arduino.
To see the decoded information on the Serial port, you should uncomment the SHOWDEGUGINFO line at the top of the globals.h
Line 64/65 in the globals.h file has 4 IDs listed. These are specific to our own car and are in the order of Front Left, Front Right, Rear Left, Rear Right. This ensures that no matter what order the IDS are received in they will always appear in the correct location on the display.
Once you know the IDs for your car (shown on the Serial port with debug enabled. - note: the IDs are not shown on the OLED display) and which wheel they relate to, possibly by altering the tyre pressures one at a time, you can update the code with your IDs. This ensures they are always shown in the correct order on the display.
If the codes received don't match with lines 64/65, the 1st 4 tyre pressures received will still be displayed but the order will be based on 1st come 1st served basis and therefore there will be no relationship with the physical tyre.
The Seeeduino Xiao can be used in place of the Pro Micro. This is a faster device with more memory and is smaller in size.
Also, if using the Seeeduino Xiao, a bigger display can be used - a 1.8" ST7735. This provides space for more information such as the ID and provides a colour display.
Note: Given the larger graphics libraries, this display is unlikely to work with the limited memory on the Pro Micro.
A suitable 3D printed case for the Seeeduino Xiao and the ST7735 display will hopefully follow when all the new code additions have been completed.
V8.0 adds an optional audible alarm using a 3v3 buzzer. The flashing code is also improved and requires the installation of the ticker.h library.
How to UsePlug into a 5v USB supply.
If functioning, the title (in yellow) should be displayed on the top two lines.
If within range of any Toyota TPMS tyres, the display should show each one in turn. The larger digits show the tyre pressures, the line under the pressure shows that tyre's temperature and a digit from 1-5 giving a rough indication of how long since the last transmission. 5 = very recent, 1 = least recent. If a transmission is not received within 30 minutes, any previous data for that tyre will be erased from the display.
The tyres only transmit every ~90 seconds, so be patient when waiting for the unit to receive and update the information on the display. The closer to the tyres, the better the reception should be but it should also be possible to gather some information from nearby (e.g. in the house) if the car is sufficiently close.
This unit does not remove the need to check tyre pressures regularly with the correct equipment. It is intended only to provide some insight as to why a TPMS alarm might have been raised by the vehicle.
Versions and ConfigurationVersions:
V1.0 Originally published version using asynchronous data output from CC1101
V2.0 Updated 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 Significant changes to use synchronous data output from CC1101. Allows option of getting the CD signal state either via SPI or by monitoring hardware pin.
V5.0 Bug fix - improvements to better detect start of valid data. 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 processor
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 use of the Seeeduino Xiao for extra memory - Nano may work but not tested!), The previous 0.96" display is still supported in this version! Tested OK on Nissan Leaf (2016).
V8.0 - Added (optional) audible alarm for pressure alarms (see schematics). Improved display flashing. Tested with Toyota Auris (2016) and Nissan Leaf (2016) 433MHz OK
V9.0 - Added Pontiac (US) decoder option, moved all CC1101 configs to sensor-specific 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 - thank you!)
V9.1 - Added provisional support for Arduino Nano 33 IOT board
V9.2 - Fixed bugs in audible alarm for temperatures. Fixed missing degrees F/C for round display.
V9.3 - Corrected some title positioning for display.h, Added support for Renault Zoe (pre 07/2019 sensors). Zoe sensors on or after 07/2019 should work as standard but comment out 'Zoe' in configs.h for these.
V9.4 - Corrected compile error when not using a 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 240×320. Requires Adafruit ILI9341 library.
V9.8 - Added support for Truck Solar TPMS and Mega256 builds
V9.9 - Added variation for Ford for different temperature structure (trial only) to support Ford E-Series (Schrader 29020 - Tom Logan)
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 (thanks to TomasoNL for his help on this one).
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 TRW-C070 (Toyota Sienna) support. Requires real-world validation.
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. Late change in CC1101.h to correct bug where FIFORead function did not have a correct return statement (not apparent when compiling for Xiao processor!)
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 sensor used on Smart Fortwo 01/2007-02/2014 (433MHz) - OOK
V10.8 - Changes to get code working for Xiao RP2040 (same schematic as existing 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 (although not recommended due to memory size). Put in conditionals for the TFT display include files to handle different GPIO formats (e.g. D1 vs just 1) depending on processor selected (fix for SPI displays not working with RP2040 Xiao)
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
V12.X - Trial version only. Written for ESP32 (also tested with Seeeduino Xiao). Only tested with Toyota PMV_C210. Eliminates use of CD signal from CC1101 by continuously monitoring RX pin. Seems to improve detection rate. Tested with Wifi and MQTT. Packaged as zip file only.
Configurations:
The software specifically supports the following processors:
ProMicro (3.3v)
Arduino Nano - no longer recommended due to insufficient RAM (only 2k). (Try switching to Seeeduino Xiao (or possibly Arduino Nano 33 IOT - not yet verified but it won't require level shifters as it's 3v3!)
Seeeduino Xiao
Seeeduino RP2040 Xiao
The code automatically detects the processor type from the IDE setting (other processors are likely to work e.g. Mega but will require minor code changes and testing)
The appropriate wiring must be used for the processor being used (including level shifters for 5v processors where applicable e.g. Arduino Nano).
See pin configurations in globals.h and the schematics section for more details.
Possible combinations and status:
Sensor Type 433MHz 315MHz Comment
Toyota PMV-C210 OK N/A Working in UK
Toyota PMV-107J N/A OK Range can be an issue
Toyota TRW-C070 OK TBC Used on Toyota Sienna
Nissan Leaf (2016) OK ? Working in UK
Renault TBC ? Not confirmed
Citroen TBC ? Not confirmed
Ford TBC ? Not confirmed, different types
Jansite ? ? Not confirmed
JansiteSolar ? ? Not confirmed
Pontiac G800 N/A OK Believed working in US
Truck Solar OK N/A Awaiting confirmation
Schrader C1100 TBC ? Used on Hyundai Tuscon
Schr(A0009054100) OK N/A Used on Smart Fortwo
? = code may require changes to support these if they exist with these frequencies
TBC = code should work but needs to be confirmed with real sensors (code based on previous individual releases)
Display settings:
Please be aware there are typos in the code for the display settings - defines shown as 'ST7753' but should really be 'ST7735'. It works OK as is but may be confusing! Will try to correct on later version.
For no display at all (i.e. relies on the data put out on the usb serial port), comment out all display options:
//#define USE_1_INCH_YB_I2C_DISPLAY 1
//#define USE_2_INCH_ST7753_DISPLAY 1
//#define USE_2_INCH_ST7789_DISPLAY 1
//#define USE_24_INCH_ILI9341_DISPLAY 1
For the 0.96" OLED I2C 128x64 display uncomment the USE_1_INCH_YB_I2C_DISPLAY only
#define USE_1_INCH_YB_I2C_DISPLAY 1
//#define USE_2_INCH_ST7753_DISPLAY 1
//#define USE_2_INCH_ST7789_DISPLAY 1
//#define USE_24_INCH_ILI9341_DISPLAY 1
For the 1.8" TFT 128x160 SPI display, uncomment the USE_2_INCH_ST7753_DISPLAY only:
//#define USE_1_INCH_YB_I2C_DISPLAY 1
#define USE_2_INCH_ST7753_DISPLAY 1
//#define USE_2_INCH_ST7789_DISPLAY 1
//#define USE_24_INCH_ILI9341_DISPLAY 1
For the TFT 240x240 SPI round display, uncomment the USE_2_INCH_ST7789_DISPLAY only:
//#define USE_1_INCH_YB_I2C_DISPLAY 1
//#define USE_2_INCH_ST7753_DISPLAY 1
#define USE_2_INCH_ST7789_DISPLAY 1
//#define USE_24_INCH_ILI9341_DISPLAY 1
For the TFT 240x320 2.4" display, uncomment the USE_24_INCH_ILI9341_DISPLAY only:
//#define USE_1_INCH_YB_I2C_DISPLAY 1
//#define USE_2_INCH_ST7753_DISPLAY 1
//#define USE_2_INCH_ST7789_DISPLAY 1
#define USE_24_INCH_ILI9341_DISPLAY 1
Readout options:
To display the tyre pressures in BAR rather than PSI on the LCD display, uncomment the #define DISPLAY_PRESSURE_AS_BAR 1 in configs.h. Similarly, to display in kPA, uncomment the #define DISPLAY_PRESSURE_AS_KPA 1 line in configs.h. WIth both options commented out, the default will be PSI.
To display tyre temperatures in Fahrenheit, uncomment #define DISPLAY_TEMP_AS_FAHRENHEIT 1 in configs.h - with this line commented out, the default will be degrees C.
Alarm options:
To enable warnings of low/high tyre pressures visually on the display by flashing the value, uncomment the line:
#define ENABLE_PRESSURE_ALARMS
in configs.h and set the high/low pressures for each tyre in these arrays:
const float PressureLowLimits[]
const float PressureHighLimits[]
These values should be the same units as selected in the readout options above for the pressures (PSI, kPA or Bar).
The flash rate can be altered by changing the DISPLAYREFRESHTIMING value in globals.h (this is in milliseconds and defaults to once per second).
To enable audible alarms as well (requires buzzer connected to the appropriate Arduino pin), uncomment the line:
#define ENABLE_AUDIBLE_ALARM in config.h
Similar alarm settings can be set for temperature warnings if required:
#define ENABLE_TEMPERATURE_ALARMS 1
Buzzer settings can be altered if required in globals.h. By default, the buzzer will give 5 bleeps if an incoming tyre pressure is outside the set limits. If the alarm has already been triggered once by a particular tyre, the alarm will not sound again for repeated out-of-spec transmissions for that tyre, however a 'reminder' buzzer will go off after every 30 minutes (alterable in globals.h). Setting the reminder value in globals.h to 0 will disable this option.
Note: the alarm will give 2 short beeps on start up to indicate the buzzer is working OK.
Vehicle/Sensor settings (config.h):
- Uncomment the required frequency (433MHz or 315MHz). The other frequency option should remain commented out
- Uncomment the vehicle manufacturer/car+sensor type (only one should be selected)
- If necessary set any optional settings for that vehicle manufacturer (e.g. Ford)
Examples:
For UK frequencies (433MHz) and (Toyota) PMV-C210 TPMS sensors:
#define UK_433MHz 1
//#define US_315MHz 1
#define Toyota_PMV_C210 1 //should also work for PMV-C010??
//#define Toyota_PMV_107J 1
//#define Toyota_TRW_C070 1
//#define Renault 1
//#define NissanLeaf 1
//#define Citroen 1
//#define PontiacG82009 1
//#define TruckSolar 1
//#define JansiteSolar 1
//#define Subaru 1
For UK frequencies (433MHz) and Renault TPMS sensors:
#define UK_433MHz 1
//#define US_315MHz 1
//#define Toyota_PMV_C210 1 //should also work for PMV-C010??
//#define Toyota_PMV_107J 1
//#define Toyota_TRW_C070 1
#define Renault 1
//#define NissanLeaf 1
//#define Citroen 1
//#define PontiacG82009 1
//#define TruckSolar 1
//#define JansiteSolar 1
//#define Subaru 1
For UK frequencies (433MHz) and Nissan Leaf Sensors:
#define UK_433MHz 1
//#define US_315MHz 1
//#define Toyota_PMV_C210 1 //should also work for PMV-C010??
//#define Toyota_PMV_107J 1
//#define Toyota_TRW_C070 1
//#define Renault 1
#define NissanLeaf 1
//#define Citroen 1
//#define TruckSolar 1
//#define JansiteSolar 1
//#define Subaru 1
For UK frequencies (433MHz) and Citroen TPMS sensors:
#define UK_433MHz 1
//#define US_315MHz 1
//#define Toyota_PMV_C210 1 //should also work for PMV-C010??
//#define Toyota_PMV_107J 1
//#define Toyota_TRW_C070 1
//#define Renault 1
//#define NissanLeaf 1
#define Citroen 1
//#define PontiacG82009 1
//#define TruckSolar 1
//#define JansiteSolar 1
//#define Subaru 1
For UK frequencies (433MHz) and Truck Solar TPMS sensors:
#define UK_433MHz 1
//#define US_315MHz 1
//#define Toyota_PMV_C210 1 //should also work for PMV-C010??
//#define Toyota_PMV_107J 1
//#define Renault 1
//#define NissanLeaf 1
//#define Citroen 1
//#define PontiacG82009 1
#define TruckSolar 1
//#define JansiteSolar 1
//#define Subaru 1
For US frequencies (315MHz) and (Toyota) PMV-107J TPMS sensors:
//#define UK_433MHz 1
#define US_315MHz 1
//#define Toyota_PMV_C210 1 //should also work for PMV-C010??
#define Toyota_PMV_107J 1
//#define Toyota_TRW_C070 1
//#define Renault 1
//#define NissanLeaf 1
//#define Citroen 1
//#define PontiacG82009 1
//#define TruckSolar 1
//#define JansiteSolar 1
//#define Subaru 1
For US frequencies (315MHz) and Pontiac G800 TPMS sensors:
//#define UK_433MHz 1
#define US_315MHz 1
//#define Toyota_PMV_C210 1 //should also work for PMV-C010??
//#define Toyota_PMV_107J 1
//#define Toyota_TRW_C070 1
//#define Renault 1
//#define Dacia 1
//#define NissanLeaf 1
//#define Citroen 1
#define PontiacG82009 1
//#define TruckSolar 1
//#define JansiteSolar 1
//#define Subaru 1
For US frequencies (315MHz) and Toyota Sienna TRW-C070 TPMS sensors:
//#define UK_433MHz 1
#define US_315MHz 1
//#define Toyota_PMV_C210 1 //should also work for PMV-C010??
//#define Toyota_PMV_107J 1
#define Toyota_TRW_C070 1
//#define Renault 1
//#define Dacia 1
//#define NissanLeaf 1
//#define Citroen 1
//#define PontiacG82009 1
//#define TruckSolar 1
//#define JansiteSolar 1
//#define Subaru 1
For hardware monitoring of the CD signal (recommended), uncomment USE_HW_CD in globals.h, To obtain the CD state over the SPI bus from the CC1101, comment out USE_HW_CD (use this method if GO0 is not hardwired to an Arduino pin)
To display valid TPMS readings in the serial monitor, uncomment the #define SHOWVALIDTPMS in globals.h
To display more detailed timings etc. uncomment the #define SHOWDEBUGINFO in globals.h
Note: displaying information on the serial monitor should only be done for debug purposes as the TPMS timing is critical and readings may be missed if excessive serial port activity is employed.
Additional Information- Common
- display
- globals
- Toyota_PMV_107J
- Toyota_PMV_C210
- Renault
- Citroen
- configs
- Ford
- Jansite
- JansiteSolar
- bitmap
- display_128x160
- AudibleAlarm
- CommonFunctionDeclarations
- display_240x240round
- PontiacG82009
- UKUS_Toyota_TPMS_Monitor_V11_8
- display_240x320
- TruckSolar
- cc1101
- Toyota_TRW_C070
- Schrader_C1100
- Schrader_A9054100
- Subaru
- AllFilesV11_8
- UKUS_Toyota_TPMS_Monitor_V12_X
- V11.9.zip
- UKUS_Toyota_TPMS_Monitor_V13_2
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.
//#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
#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
#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 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);
}
}
#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);
}
}
#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);
}
}
//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
};
#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);
}
}
#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);
}
}
#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);
}
}
// '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
};
#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();
}
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
}
}
}
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();
#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();
}
#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);
}
}
//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
}
#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();
}
#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);
}
}
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));
}
#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);
}
}
#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);
}
}
#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);
}
}
#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 textNo preview (download only).
No preview (download only).
UKUS_Toyota_TPMS_Monitor_V13_2
Plain textNo preview (download only).
Comments