<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.autosportlabs.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ddimensia</id>
	<title>Autosport Labs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.autosportlabs.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ddimensia"/>
	<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/Special:Contributions/Ddimensia"/>
	<updated>2026-09-20T12:22:34Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.44.0</generator>
	<entry>
		<id>https://wiki.autosportlabs.com/index.php?title=ESP32-CAN-X2&amp;diff=10260</id>
		<title>ESP32-CAN-X2</title>
		<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/index.php?title=ESP32-CAN-X2&amp;diff=10260"/>
		<updated>2024-11-05T19:51:11Z</updated>

		<summary type="html">&lt;p&gt;Ddimensia: /* Board Pinout */ Fixed SV2 12-13 pin descriptions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Introduction=&lt;br /&gt;
&lt;br /&gt;
ESP32-CAN-X2 is an ESP32-based development board specifically designed for CAN communication. This board has all the features of a modern ESP32 development board, integrated Wi-Fi and Bluetooth, along with the extended CAN controller. Autosport Labs has specifically designed it for CAN communication along with fast processing and computation options.  &lt;br /&gt;
&lt;br /&gt;
This is a complete how-to-use guide and this user guide will describe each and every step to use the board and harness the maximum potential of the board.&lt;br /&gt;
&lt;br /&gt;
=Features=&lt;br /&gt;
&lt;br /&gt;
Features of ESP32-CAN-X2 development board:&lt;br /&gt;
&lt;br /&gt;
* Based on ESP32-S3-WROOM-1-N8R8 microcontroller powerful dual-core Xtensa LX6 CPU running at up to 240 MHz.&lt;br /&gt;
* 384 KB ROM,  512 KB SRAM,  16 KB SRAM in RTC, 8 MB PSRAM&lt;br /&gt;
* Two LED’s : Power LED and user defined LED1&lt;br /&gt;
* Integrated Wi-Fi (802.11b/g/n) and Bluetooth capabilities&lt;br /&gt;
* Reset and Boot push button&lt;br /&gt;
* USB-C type socket for flashing, and power supply&lt;br /&gt;
* Integrated antenna for long range communication&lt;br /&gt;
* Additional CAN communication controller CAN using MCP2515&lt;br /&gt;
* 6-pin header is strategically positioned at the top for CAN communication&lt;br /&gt;
* Easy-to-interface programming. Required no external debugger for flashing&lt;br /&gt;
* Integrated CAN transceivers&lt;br /&gt;
* Configurable CAN termination resistors, which can be disabled via breakable jumpers&lt;br /&gt;
* Flexible power supply options&lt;br /&gt;
* Support of a wide choice of commonly used Integrated Development Environments (IDEs)&lt;br /&gt;
* Comprehensive free software libraries and examples for CAN communication&lt;br /&gt;
&lt;br /&gt;
=Getting started=&lt;br /&gt;
&lt;br /&gt;
This section will provide you with comprehensive information about the ESP32-CAN-X2 development board&#039;s key components, mechanical layout, power rating, &amp;amp; requirements. This detailed information helps you to use the board effectively and efficiently in your projects.&lt;br /&gt;
&lt;br /&gt;
== Key Components of ESP32-CAN-X2 Development Board ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Figure 1 given below indicates the important key components of the ESP32-CAN-X2 Development Board and their location on the board.&lt;br /&gt;
&lt;br /&gt;
[[File:Development Board Key Components.png|Figure 1]]&lt;br /&gt;
&lt;br /&gt;
=== Microcontroller ===&lt;br /&gt;
&lt;br /&gt;
The ESP32-CAN-X2 Development Board is designed around the ESP32-S3-WROOM-1-N8R8 microcontroller in a 40-pin package. The connections between the development board and the microcontroller is straightforward, where the majority of GPIO pins are directly connected with the external headers, SV1 &amp;amp; SV2, and some pins are reserved internal connections between the board and CAN controllers. The internal connections between the microcontroller and CAN controllers are shown in the CAN controller heading given below. The microcontroller pin layout is shown in Figure 2 given below.&lt;br /&gt;
&lt;br /&gt;
[[File:Microcontroller pin layout.png|Figure 2]]&lt;br /&gt;
&lt;br /&gt;
=== External Connection Header ===&lt;br /&gt;
&lt;br /&gt;
External headers, SV1 &amp;amp; SV2, are the two other important components of this development board.  SV1 is the left side dual row header and the SV2 is the right side dual row header. Both of these headers have 20 pins available for connection.  These headers provide connections for GPIOs, power output, ground (GND), power input, and CAN communication pins. Both of these header pinouts have standard size, allowing users to connect them using jumper wires, a breadboard, or even solder wires permanently onto the development board. However, while doing the wire connection the customer must make sure that none of them get short circuit. The details regarding the pin&#039;s names, numbers, outputs, and functions are given in the Board Pinout section below.&lt;br /&gt;
&lt;br /&gt;
=== CAN Controllers ===&lt;br /&gt;
&lt;br /&gt;
The MCP2515 external connected CAN communication controller, and ESP-32 built-in CAN communication controller are two other main components of this development board.&lt;br /&gt;
&lt;br /&gt;
The MCP2515, operating as the second external CAN controller in this development board, is a specialized component designed for Controller Area Network (CAN) applications. Its features include:&lt;br /&gt;
&lt;br /&gt;
* Implements CAN V2.0B at up to 1 Mb/s.&lt;br /&gt;
* High-Speed SPI Interface (10 MHz)&lt;br /&gt;
* Interrupt Output Pin with selectable enables&lt;br /&gt;
* Multiple receive and transmit buffers &lt;br /&gt;
* Low-Power CMOS Technology: - 5 mA active current (typical), 1 μA standby current&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The internal CAN controller also works at CAN V2.0. The internal CAN supports two message formats:&lt;br /&gt;
&lt;br /&gt;
* Base frame format (11-bit ID)&lt;br /&gt;
* Extended frame format (29-bit ID)&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Internal pinout connection between the CAN controllers and ESP32&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* CAN 1: This is a built-in CAN controller and its RX is connected to IO6 of the microcontroller and TX is connected to IO7 of the microcontroller. The  connections are shown in Figure 3 given below&lt;br /&gt;
* CAN 2: This is the externally connected controller and its CS, MOSI, CLK, and MISO are connected at pin numbers 1O10, 1011, 1012, and 1O13 respectively. The  connections are shown in Figure 3 given below&lt;br /&gt;
&lt;br /&gt;
[[File:Internal connection.png|Figure 3]]&lt;br /&gt;
&lt;br /&gt;
=== 6 pin JST-PH Connector ===&lt;br /&gt;
&lt;br /&gt;
The ESP32-CAN-X2 development board provides an additional 6-pin connector header at the top of the board to supports CAN communication. This header makes wiring the device more convenient and robust. The CAN communication connection pinout details are given in the pinout section below.&lt;br /&gt;
&lt;br /&gt;
=== USB-C Socket ===&lt;br /&gt;
&lt;br /&gt;
The ESP32-CAN-X2 development board has one USB-C port. This port is used for multiple functions: it powers the board, allows programming, and facilitates serial communication both ways.&lt;br /&gt;
However, it is important to note that when powering the board through the USB-C port, please ensure the nominal voltage range is 6-20V and Vmax is 40V.&lt;br /&gt;
&lt;br /&gt;
== Board Layout ==&lt;br /&gt;
&lt;br /&gt;
Mechanical board outline physical dimensions:&lt;br /&gt;
&lt;br /&gt;
* Width  : 42.10 mm&lt;br /&gt;
* Length : 72 mm&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The board top view is shown in the Figure 4 given below.&lt;br /&gt;
&lt;br /&gt;
[[File:Board top view.png|Figure 4]]&lt;br /&gt;
&lt;br /&gt;
== Power Ratings &amp;amp; Environmental Requirements ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Power Options&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The ESP32-CAN-X2 development board is flexible in its power input, and it provides multiple power input options. Power can either be supplied via the VIN pin, or via USB-C connector. Any voltage input either via USB or VIN is stepped down to 3.3 V via a voltage regulator. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pin Voltage&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
All digital &amp;amp; analog pins on the ESP32-CAN-X2 development board are 3.3 V. Do not connect any higher voltage devices to any of the pins as it will risk damaging the board.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;VIN Rating&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The nominal input voltage rating for the development board is 6-20v, with a 40v max input. Please do not attempt to power the board with a voltage outside the recommended range.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Operating Current&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The typical operating current of ESP32-CAN-X2 development board is 105mA and maximum operating current is 500mA ( peak, during transmission )&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Power Consumption&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The normal power consumption of the board is 330mW and peak power consumption is 1.65W &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Operating Temperature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Temperate rating is -40°C to +85°C&lt;br /&gt;
&lt;br /&gt;
=CAN bus information=&lt;br /&gt;
&lt;br /&gt;
CAN, also known as Control area networking, is a serial communication protocol that is widely used in Automotive applications. CAN bus communication protocol utilizes differential signaling methods in which data is transferred as a voltage difference between High and low voltage. Can Bus communication provides various advantages over other communication methods which makes it the most important communication protocol in automotive. A few features are follows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Multimaster system&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In CAN Bus communication, multiple controllers can act as a master, and multiple devices can act as a node. Each node can share  data with other nodes via the CAN bus. In modern cars, there are more than 70 ECUs, and using CAN communication each ECU acts as a node and can transfer the data to the CAN bus, this data is then available to all the ECUs, and ECU can then check the data and decide whether to receive or ignore it.&lt;br /&gt;
&lt;br /&gt;
For details, visit: https://www.csselectronics.com/pages/can-bus-simple-intro-tutorial&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lossless communication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
CAN communication uses a bitwise arbitration method that avoids the contentions of data on the bus. When two nodes simultaneously try to send the data, then the node with the high priority ( lower identifier ) gets priority and continues transmitting. The identifier message can be 11-bit ( standard CAN ) or 29-bit ( extended CAN) in length.&lt;br /&gt;
&lt;br /&gt;
For details, visit: https://dewesoft.com/blog/what-is-can-bus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Simple and cheap&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The CAN communication between the ECUs is done through a single CAN system instead of direct complex analog signal lines which makes it extremely simple and reduces errors.&lt;br /&gt;
&lt;br /&gt;
For details, visit: https://www.autopi.io/blog/can-bus-explained/&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Errorless communication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
CAN incorporates different built-in error detection mechanisms including cyclic redundancy checks (CRC), and frame check sequences (FCS) to detect errors during data transmission.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CAN network types&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Prominent CAN network types are as follows.&lt;br /&gt;
&lt;br /&gt;
* High-speed CAN bus ( Supports bit rates between 40 kbit/s and 1 Mbit/s )&lt;br /&gt;
* Low-Speed CAN bus  ( Supports bit rates between 40 kbit/s and 125 kbit/s )&lt;br /&gt;
* CAN FD  ( Supports bit rates between 1 Mbps to 8 Mbps )&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
For details, visit:https://dewesoft.com/blog/what-is-can-bus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Data transmission&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In CAN, data is transferred between two nodes in messages known as CAN frames. There are four types of CAN frames.&lt;br /&gt;
* Data frame ( Used to transfer data between two node )&lt;br /&gt;
* Remote frame ( request data from other node )&lt;br /&gt;
* Error frame ( report errors )&lt;br /&gt;
* Overload frame ( report overload )&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
For details, visit:https://www.autopi.io/blog/can-bus-explained/&lt;br /&gt;
&lt;br /&gt;
== CAN Termination ==&lt;br /&gt;
&lt;br /&gt;
CAN termination is a process of terminating the CAN bus to prevent the signal reflection at the end of the bus and to ensure the correct DC level of the bus. The CAN BUS is bidirectional, and both ends of the bus must be properly terminated to prevent errors in communication. CAN termination is achieved by placing the termination resistance, which is normally 120 ohm, that matches the nominal resistance of the cable. ISO 11898 requires normally required CAN BUS cable of impedance 120 ohm; therefore, the CAN 120 ohm resistance is used for CAN termination. However, while doing the CAN termination, it must be kept in mind that the nodes from the far two ends of the cable only require termination resistors. &lt;br /&gt;
&lt;br /&gt;
Figure 5 given below explain the CAN termination.&lt;br /&gt;
&lt;br /&gt;
[[File:CAN BUS TERMINATION.png]]&lt;br /&gt;
&lt;br /&gt;
Note :The low-speed CAN, single wire CAN, may not require the CAN bus termination.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;How to enable &amp;amp; disable CAN termination in ESP-32-X2 ?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The ESP-32-X2 development board has given two separate CAN termination pads at the top of the development board adjacent to the 6-PIN  CAN communication header. The CAN termination jumpers are shown in the figure 6 given below.&lt;br /&gt;
&lt;br /&gt;
[[File:CAN BUS TERMINATION DISABLE JUMPERS.png]]&lt;br /&gt;
&lt;br /&gt;
* Enable termination : In ESP-32-X2 development board, CAN termination is enabled by default.&lt;br /&gt;
* Disable termination : Scratch the copper trace between the pads, TERM1 &amp;amp; TERM2. &lt;br /&gt;
* Re-enable termination : Re-solder the traces between the pads&lt;br /&gt;
&lt;br /&gt;
Note : Proper termination is necessary for ensuring errorless communication and signal integrity. Please follow the above given instruction carefully.&lt;br /&gt;
&lt;br /&gt;
=Board Pinout=&lt;br /&gt;
&lt;br /&gt;
The ESP32-CAN-X2 board has 40 pins across its two headers, SV1 &amp;amp; SV2 headers, and a 6-pin header at the top. This guide explains the pin functionalities of the board. The pin configuration of development board shown in Figure 7 given below.&lt;br /&gt;
&lt;br /&gt;
[[File:Pin Configuration 1.png|Figure 7]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Left Header (SV1) Pinout (Top to Bottom)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The pin count start from the top of the left header, and the pin details are as following :&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|-&lt;br /&gt;
! Pin !! Function !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CAN1H/2.7D || high-level signal for the first CAN channel.&lt;br /&gt;
|-&lt;br /&gt;
| 2 || CAN1L/2.7D || low-level signal for the first CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 3 || CAN2H/2.7C || high-level signal for the second CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 4 || CAN2L/2.7C ||  low-level signal for the second CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 5 || RX Pin || USART RX&lt;br /&gt;
|-&lt;br /&gt;
| 6 || TX Pin || USART TX&lt;br /&gt;
|-&lt;br /&gt;
| 7-20|| GPIO Pins || GPIO&#039;s&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Right Header (SV2) Pinout (Bottom to Top )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The pin count start from bottom to top and details are as following :&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! Pin !! Function !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1-11 || GPIO Pins || GPIO&#039;s&lt;br /&gt;
|-&lt;br /&gt;
| 12-13 || 3.3V || 3.3 Voltage Output&lt;br /&gt;
|-&lt;br /&gt;
| 14-15 || 5V || 5 Voltage Output&lt;br /&gt;
|-&lt;br /&gt;
| 16-18 || GND || Ground&lt;br /&gt;
|-&lt;br /&gt;
| 19-20 || 12 Vin || 12 Voltage Input&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Top Header Pinout&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The header supports CAN communication. Pin count start at the left viewing the board from the top. Pinout configuration of header is shown in Figure 8 given below.&lt;br /&gt;
&lt;br /&gt;
[[File:6 PIN HEADER (1).png|Figure 8]]&lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; Color codes on the provided pigtail may not match documentation.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! Pin !! Function !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CAN1L/2.7A || low-level signal for the first CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 2 || CAN2L/2.7B || low-level signal for the second CAN channel &lt;br /&gt;
|-&lt;br /&gt;
| 3 || CAN2H/2.7B || high-level signal for the second CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 4 || GND || Ground&lt;br /&gt;
|-&lt;br /&gt;
| 5 || CAN1H/2.7A || high-level signal for the first CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 6 || +12V_ Aux || 6-12v power supply&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Flashing Firmware=&lt;br /&gt;
&lt;br /&gt;
Firmware flashing in this development board is straightforward. The following components are required for firmware flashings.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hardware Components&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* USB-C cable &lt;br /&gt;
* Computer running Windows, Linux, or macOS &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Software Components&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Updated Arduino IDE to compile code for ESP-32-X2.&lt;br /&gt;
* Update Mu Editor from codewith.mu&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Note : Link to download Arduino IDE : https://www.arduino.cc/en/software || Link to download Mu Editor : codewith.mu&lt;br /&gt;
&lt;br /&gt;
== Step by step instruction for Arduino IDE==&lt;br /&gt;
&lt;br /&gt;
===Sample Arduino Project===&lt;br /&gt;
https://github.com/autosportlabs/ESP32-CAN-X2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step-by-step instructions for flashing ESP-32-X2 are as follows.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Install ESP-32-X2 Board Support:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Adding ESP-32-X2 in Arduino Ide is a single-time process and its steps are as follows.&lt;br /&gt;
&lt;br /&gt;
* Open Arduino Ide&lt;br /&gt;
* Go to File &amp;gt; Preferences&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Flashing1.png| Figure 7|800px]]&lt;br /&gt;
&lt;br /&gt;
* Add the below given Json URL in the Additional board manager URL&lt;br /&gt;
&lt;br /&gt;
Json URL : https://espressif.github.io/arduino-esp32/package_esp32_index.json&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:ESPBSP1.png|Figure 8|800px]]&lt;br /&gt;
&lt;br /&gt;
* Go to Tools &amp;gt; Board &amp;gt; Boards Manager&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Flashing3.png|Figure 9|800px]]&lt;br /&gt;
&lt;br /&gt;
* In the Board Manager search bar, type ESP-32, search for esp32 by Espressif and click on install to install the board&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:ESPBSP2.png|Figure 10|800px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* After installing, click on Tool &amp;gt; Boards and select AutosportLabs ESP32-CAN-X2&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Flashing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Connect the ESP-32-X2 board to your computer using a USB-C cable with your Arduino IDE open&lt;br /&gt;
&lt;br /&gt;
* Select AutosportLabs ESP32-CAN-X2 in Tools &amp;gt; Board menu&lt;br /&gt;
&lt;br /&gt;
* Go to Tools &amp;gt; Port and select the COM port to which ESP-32-X2 is connected.&lt;br /&gt;
&lt;br /&gt;
[[File:ArduinoFlashing3.png|Figure 11|800px]]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Note : If you don’t see the COM Port in your Arduino IDE, you need to install the CP210x USB to UART Bridge VCP Drivers: https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Write your firmware code or add an existing sketch that you want to upload to your custom board.&lt;br /&gt;
&lt;br /&gt;
* Go to Sketch &amp;gt; Click upload to compile and upload the code&lt;br /&gt;
&lt;br /&gt;
* After successful uploading, you should see a “Done uploading.” message at the bottom console. This console will also show error messages if there is any error.&lt;br /&gt;
&lt;br /&gt;
[[File:ArduinoFlashing4...png|Figure 12|800px]]&lt;br /&gt;
&lt;br /&gt;
If any issues occur during upload, double-check the board selection, COM port, and your code for errors.&lt;br /&gt;
&amp;lt;be&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Importing Libraries in Arduino IDE===&lt;br /&gt;
&lt;br /&gt;
* To Install Libraries for ESP32-CAN-X2 like mcp_canbus or mcp2515&lt;br /&gt;
* Go to Sketch &amp;gt; Include Library &amp;gt; Manage LibrarieSs&lt;br /&gt;
&lt;br /&gt;
[[File:Arduino IDE Library 1.png]]&lt;br /&gt;
&lt;br /&gt;
* Type and find the desired library like mcp_canbus by Longan Labs&lt;br /&gt;
* Search and Install the library&lt;br /&gt;
&lt;br /&gt;
[[File:Arduino IDE Library 2...png]]&lt;br /&gt;
&lt;br /&gt;
== Step-by-step instruction for CircuitPython==&lt;br /&gt;
===Sample CircuitPython code===&lt;br /&gt;
https://github.com/autosportlabs/ESP32-CAN-X2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Downloading ESP-32-X2 Board Support:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Installing ESP-32-X2 is simple, please follow the steps given below :&lt;br /&gt;
&lt;br /&gt;
* Go to circuitpython.org/board/autosportlabs_esp32_can_x2&lt;br /&gt;
Click on the browse S3&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:CircuitpythonFlashing1.png|800px]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Select the desired language&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:CircuitpythonFlashing2.png|800px]]&lt;br /&gt;
* Download the latest .bin file &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:CircuitpythonFlashing4.png|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Prepare the ESP32 CAN X2 for Installation:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Connect the ESP-32-X2 board to your computer using a USB-C cable &lt;br /&gt;
* Press and hold the boot button on the development board.&lt;br /&gt;
* While holding the boot button, press and release the reset button once.&lt;br /&gt;
* Release the boot button to put the board into bootloader mode.&lt;br /&gt;
[[File:CircuitpythonFlashing5.png|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Connect to the Web Serial ESP Tool&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Go to : https://adafruit.github.io/Adafruit_WebSerial_ESPTool/&lt;br /&gt;
* Press the Connect button in the top right corner of the page.&lt;br /&gt;
* A pop-up will appear asking you to select the COM or Serial port. &lt;br /&gt;
* Look for an option with ESP32, JTAG Loader, SLAB, or FTDI in the name&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:CircuitpythonFlashing6.png|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Flash the Firmware&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Click on Choose the .bin file you downloaded.&lt;br /&gt;
* Ensure that the Offset box next to the file location is set to 0x0.&lt;br /&gt;
* After selecting the file, the button text will change to match your filename.&lt;br /&gt;
* Click the Program button to start flashing. A progress bar will appear, and after a minute or two, the firmware will be &lt;br /&gt;
written.&lt;br /&gt;
&lt;br /&gt;
[[File:Circuytpython7.gif|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Exit Bootloader Mode&#039;&#039;&#039;&lt;br /&gt;
* Press the reset button to exit bootloader mode. Shortly, the CIRCUITPY drive will pop up.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Downloading and Installing Mu Editor&#039;&#039;&#039;&lt;br /&gt;
* Download and install the recommended Mu Editor from codewith.mu.&lt;br /&gt;
* When you first start Mu, you will be prompted to select your mode. Select CircuitPython.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:Mudownload.png|800px]]&lt;br /&gt;
&lt;br /&gt;
* In Mu editor, click the Load button in the button bar, navigate to the CIRCUITPY drive, and choose code.py.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:MU2.png|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note :&#039;&#039;&#039; The CIRCUITPY drive is where your code and necessary libraries will reside. With a fresh CircuitPython install, the CIRCUITPY drive will contain a code.py file with print(&amp;quot;Hello World!&amp;quot;) and an empty lib folder. If your CIRCUITPY drive does not have a code.py file, create one and save it to the drive. CircuitPython automatically executes the code in code.py when the board starts up or resets. Do not press reset immediately after saving your code it will corrupt the drive and you may lose your code. &lt;br /&gt;
&lt;br /&gt;
* Enter your code into the editor and save the code.py file on the CIRCUITPY drive. &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:MU3.png|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Congratulations!&#039;&#039;&#039; You have just run your first CircuitPython program.&lt;br /&gt;
&lt;br /&gt;
=== Importing Libraries in Circuitpython ===&lt;br /&gt;
&lt;br /&gt;
Importing libraries in Circuitpython is straightforward. For installing Libraries in Circuitpython, please follow the steps given below :&lt;br /&gt;
* Go to https://circuitpython.org/libraries and download the bundle for version 9.xx.&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The version of the bundle should be the same that you are using.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Mu4.png|800px]]&lt;br /&gt;
&lt;br /&gt;
* Extract the zip file.&lt;br /&gt;
* Find the lib file where you can find your desired library.&lt;br /&gt;
* Copy that library folder or .mpy file and paste it to the lib folder in CIRCUITPY drive&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Mueditor Library.gif|800px]]&lt;br /&gt;
&lt;br /&gt;
=Bolt-ons=&lt;br /&gt;
Autosport Labs provides various add-on boards, known as &amp;quot;bolt-ons&amp;quot; for ESP32-CAN-X2. For Further details regarding bolt-on. Please click on the specific bolt-on links given below&lt;br /&gt;
* [https://wiki.autosportlabs.com/Bolt-on#GPS_Bolt-on GPS Bolt-on]&lt;/div&gt;</summary>
		<author><name>Ddimensia</name></author>
	</entry>
	<entry>
		<id>https://wiki.autosportlabs.com/index.php?title=ESP32-CAN-X2&amp;diff=10259</id>
		<title>ESP32-CAN-X2</title>
		<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/index.php?title=ESP32-CAN-X2&amp;diff=10259"/>
		<updated>2024-11-05T19:42:35Z</updated>

		<summary type="html">&lt;p&gt;Ddimensia: /* Board Pinout */ Fixed header identifiers on pinout&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Introduction=&lt;br /&gt;
&lt;br /&gt;
ESP32-CAN-X2 is an ESP32-based development board specifically designed for CAN communication. This board has all the features of a modern ESP32 development board, integrated Wi-Fi and Bluetooth, along with the extended CAN controller. Autosport Labs has specifically designed it for CAN communication along with fast processing and computation options.  &lt;br /&gt;
&lt;br /&gt;
This is a complete how-to-use guide and this user guide will describe each and every step to use the board and harness the maximum potential of the board.&lt;br /&gt;
&lt;br /&gt;
=Features=&lt;br /&gt;
&lt;br /&gt;
Features of ESP32-CAN-X2 development board:&lt;br /&gt;
&lt;br /&gt;
* Based on ESP32-S3-WROOM-1-N8R8 microcontroller powerful dual-core Xtensa LX6 CPU running at up to 240 MHz.&lt;br /&gt;
* 384 KB ROM,  512 KB SRAM,  16 KB SRAM in RTC, 8 MB PSRAM&lt;br /&gt;
* Two LED’s : Power LED and user defined LED1&lt;br /&gt;
* Integrated Wi-Fi (802.11b/g/n) and Bluetooth capabilities&lt;br /&gt;
* Reset and Boot push button&lt;br /&gt;
* USB-C type socket for flashing, and power supply&lt;br /&gt;
* Integrated antenna for long range communication&lt;br /&gt;
* Additional CAN communication controller CAN using MCP2515&lt;br /&gt;
* 6-pin header is strategically positioned at the top for CAN communication&lt;br /&gt;
* Easy-to-interface programming. Required no external debugger for flashing&lt;br /&gt;
* Integrated CAN transceivers&lt;br /&gt;
* Configurable CAN termination resistors, which can be disabled via breakable jumpers&lt;br /&gt;
* Flexible power supply options&lt;br /&gt;
* Support of a wide choice of commonly used Integrated Development Environments (IDEs)&lt;br /&gt;
* Comprehensive free software libraries and examples for CAN communication&lt;br /&gt;
&lt;br /&gt;
=Getting started=&lt;br /&gt;
&lt;br /&gt;
This section will provide you with comprehensive information about the ESP32-CAN-X2 development board&#039;s key components, mechanical layout, power rating, &amp;amp; requirements. This detailed information helps you to use the board effectively and efficiently in your projects.&lt;br /&gt;
&lt;br /&gt;
== Key Components of ESP32-CAN-X2 Development Board ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Figure 1 given below indicates the important key components of the ESP32-CAN-X2 Development Board and their location on the board.&lt;br /&gt;
&lt;br /&gt;
[[File:Development Board Key Components.png|Figure 1]]&lt;br /&gt;
&lt;br /&gt;
=== Microcontroller ===&lt;br /&gt;
&lt;br /&gt;
The ESP32-CAN-X2 Development Board is designed around the ESP32-S3-WROOM-1-N8R8 microcontroller in a 40-pin package. The connections between the development board and the microcontroller is straightforward, where the majority of GPIO pins are directly connected with the external headers, SV1 &amp;amp; SV2, and some pins are reserved internal connections between the board and CAN controllers. The internal connections between the microcontroller and CAN controllers are shown in the CAN controller heading given below. The microcontroller pin layout is shown in Figure 2 given below.&lt;br /&gt;
&lt;br /&gt;
[[File:Microcontroller pin layout.png|Figure 2]]&lt;br /&gt;
&lt;br /&gt;
=== External Connection Header ===&lt;br /&gt;
&lt;br /&gt;
External headers, SV1 &amp;amp; SV2, are the two other important components of this development board.  SV1 is the left side dual row header and the SV2 is the right side dual row header. Both of these headers have 20 pins available for connection.  These headers provide connections for GPIOs, power output, ground (GND), power input, and CAN communication pins. Both of these header pinouts have standard size, allowing users to connect them using jumper wires, a breadboard, or even solder wires permanently onto the development board. However, while doing the wire connection the customer must make sure that none of them get short circuit. The details regarding the pin&#039;s names, numbers, outputs, and functions are given in the Board Pinout section below.&lt;br /&gt;
&lt;br /&gt;
=== CAN Controllers ===&lt;br /&gt;
&lt;br /&gt;
The MCP2515 external connected CAN communication controller, and ESP-32 built-in CAN communication controller are two other main components of this development board.&lt;br /&gt;
&lt;br /&gt;
The MCP2515, operating as the second external CAN controller in this development board, is a specialized component designed for Controller Area Network (CAN) applications. Its features include:&lt;br /&gt;
&lt;br /&gt;
* Implements CAN V2.0B at up to 1 Mb/s.&lt;br /&gt;
* High-Speed SPI Interface (10 MHz)&lt;br /&gt;
* Interrupt Output Pin with selectable enables&lt;br /&gt;
* Multiple receive and transmit buffers &lt;br /&gt;
* Low-Power CMOS Technology: - 5 mA active current (typical), 1 μA standby current&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The internal CAN controller also works at CAN V2.0. The internal CAN supports two message formats:&lt;br /&gt;
&lt;br /&gt;
* Base frame format (11-bit ID)&lt;br /&gt;
* Extended frame format (29-bit ID)&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Internal pinout connection between the CAN controllers and ESP32&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* CAN 1: This is a built-in CAN controller and its RX is connected to IO6 of the microcontroller and TX is connected to IO7 of the microcontroller. The  connections are shown in Figure 3 given below&lt;br /&gt;
* CAN 2: This is the externally connected controller and its CS, MOSI, CLK, and MISO are connected at pin numbers 1O10, 1011, 1012, and 1O13 respectively. The  connections are shown in Figure 3 given below&lt;br /&gt;
&lt;br /&gt;
[[File:Internal connection.png|Figure 3]]&lt;br /&gt;
&lt;br /&gt;
=== 6 pin JST-PH Connector ===&lt;br /&gt;
&lt;br /&gt;
The ESP32-CAN-X2 development board provides an additional 6-pin connector header at the top of the board to supports CAN communication. This header makes wiring the device more convenient and robust. The CAN communication connection pinout details are given in the pinout section below.&lt;br /&gt;
&lt;br /&gt;
=== USB-C Socket ===&lt;br /&gt;
&lt;br /&gt;
The ESP32-CAN-X2 development board has one USB-C port. This port is used for multiple functions: it powers the board, allows programming, and facilitates serial communication both ways.&lt;br /&gt;
However, it is important to note that when powering the board through the USB-C port, please ensure the nominal voltage range is 6-20V and Vmax is 40V.&lt;br /&gt;
&lt;br /&gt;
== Board Layout ==&lt;br /&gt;
&lt;br /&gt;
Mechanical board outline physical dimensions:&lt;br /&gt;
&lt;br /&gt;
* Width  : 42.10 mm&lt;br /&gt;
* Length : 72 mm&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The board top view is shown in the Figure 4 given below.&lt;br /&gt;
&lt;br /&gt;
[[File:Board top view.png|Figure 4]]&lt;br /&gt;
&lt;br /&gt;
== Power Ratings &amp;amp; Environmental Requirements ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Power Options&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The ESP32-CAN-X2 development board is flexible in its power input, and it provides multiple power input options. Power can either be supplied via the VIN pin, or via USB-C connector. Any voltage input either via USB or VIN is stepped down to 3.3 V via a voltage regulator. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pin Voltage&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
All digital &amp;amp; analog pins on the ESP32-CAN-X2 development board are 3.3 V. Do not connect any higher voltage devices to any of the pins as it will risk damaging the board.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;VIN Rating&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The nominal input voltage rating for the development board is 6-20v, with a 40v max input. Please do not attempt to power the board with a voltage outside the recommended range.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Operating Current&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The typical operating current of ESP32-CAN-X2 development board is 105mA and maximum operating current is 500mA ( peak, during transmission )&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Power Consumption&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The normal power consumption of the board is 330mW and peak power consumption is 1.65W &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Operating Temperature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Temperate rating is -40°C to +85°C&lt;br /&gt;
&lt;br /&gt;
=CAN bus information=&lt;br /&gt;
&lt;br /&gt;
CAN, also known as Control area networking, is a serial communication protocol that is widely used in Automotive applications. CAN bus communication protocol utilizes differential signaling methods in which data is transferred as a voltage difference between High and low voltage. Can Bus communication provides various advantages over other communication methods which makes it the most important communication protocol in automotive. A few features are follows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Multimaster system&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In CAN Bus communication, multiple controllers can act as a master, and multiple devices can act as a node. Each node can share  data with other nodes via the CAN bus. In modern cars, there are more than 70 ECUs, and using CAN communication each ECU acts as a node and can transfer the data to the CAN bus, this data is then available to all the ECUs, and ECU can then check the data and decide whether to receive or ignore it.&lt;br /&gt;
&lt;br /&gt;
For details, visit: https://www.csselectronics.com/pages/can-bus-simple-intro-tutorial&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lossless communication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
CAN communication uses a bitwise arbitration method that avoids the contentions of data on the bus. When two nodes simultaneously try to send the data, then the node with the high priority ( lower identifier ) gets priority and continues transmitting. The identifier message can be 11-bit ( standard CAN ) or 29-bit ( extended CAN) in length.&lt;br /&gt;
&lt;br /&gt;
For details, visit: https://dewesoft.com/blog/what-is-can-bus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Simple and cheap&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The CAN communication between the ECUs is done through a single CAN system instead of direct complex analog signal lines which makes it extremely simple and reduces errors.&lt;br /&gt;
&lt;br /&gt;
For details, visit: https://www.autopi.io/blog/can-bus-explained/&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Errorless communication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
CAN incorporates different built-in error detection mechanisms including cyclic redundancy checks (CRC), and frame check sequences (FCS) to detect errors during data transmission.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CAN network types&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Prominent CAN network types are as follows.&lt;br /&gt;
&lt;br /&gt;
* High-speed CAN bus ( Supports bit rates between 40 kbit/s and 1 Mbit/s )&lt;br /&gt;
* Low-Speed CAN bus  ( Supports bit rates between 40 kbit/s and 125 kbit/s )&lt;br /&gt;
* CAN FD  ( Supports bit rates between 1 Mbps to 8 Mbps )&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
For details, visit:https://dewesoft.com/blog/what-is-can-bus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Data transmission&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In CAN, data is transferred between two nodes in messages known as CAN frames. There are four types of CAN frames.&lt;br /&gt;
* Data frame ( Used to transfer data between two node )&lt;br /&gt;
* Remote frame ( request data from other node )&lt;br /&gt;
* Error frame ( report errors )&lt;br /&gt;
* Overload frame ( report overload )&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
For details, visit:https://www.autopi.io/blog/can-bus-explained/&lt;br /&gt;
&lt;br /&gt;
== CAN Termination ==&lt;br /&gt;
&lt;br /&gt;
CAN termination is a process of terminating the CAN bus to prevent the signal reflection at the end of the bus and to ensure the correct DC level of the bus. The CAN BUS is bidirectional, and both ends of the bus must be properly terminated to prevent errors in communication. CAN termination is achieved by placing the termination resistance, which is normally 120 ohm, that matches the nominal resistance of the cable. ISO 11898 requires normally required CAN BUS cable of impedance 120 ohm; therefore, the CAN 120 ohm resistance is used for CAN termination. However, while doing the CAN termination, it must be kept in mind that the nodes from the far two ends of the cable only require termination resistors. &lt;br /&gt;
&lt;br /&gt;
Figure 5 given below explain the CAN termination.&lt;br /&gt;
&lt;br /&gt;
[[File:CAN BUS TERMINATION.png]]&lt;br /&gt;
&lt;br /&gt;
Note :The low-speed CAN, single wire CAN, may not require the CAN bus termination.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;How to enable &amp;amp; disable CAN termination in ESP-32-X2 ?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The ESP-32-X2 development board has given two separate CAN termination pads at the top of the development board adjacent to the 6-PIN  CAN communication header. The CAN termination jumpers are shown in the figure 6 given below.&lt;br /&gt;
&lt;br /&gt;
[[File:CAN BUS TERMINATION DISABLE JUMPERS.png]]&lt;br /&gt;
&lt;br /&gt;
* Enable termination : In ESP-32-X2 development board, CAN termination is enabled by default.&lt;br /&gt;
* Disable termination : Scratch the copper trace between the pads, TERM1 &amp;amp; TERM2. &lt;br /&gt;
* Re-enable termination : Re-solder the traces between the pads&lt;br /&gt;
&lt;br /&gt;
Note : Proper termination is necessary for ensuring errorless communication and signal integrity. Please follow the above given instruction carefully.&lt;br /&gt;
&lt;br /&gt;
=Board Pinout=&lt;br /&gt;
&lt;br /&gt;
The ESP32-CAN-X2 board has 40 pins across its two headers, SV1 &amp;amp; SV2 headers, and a 6-pin header at the top. This guide explains the pin functionalities of the board. The pin configuration of development board shown in Figure 7 given below.&lt;br /&gt;
&lt;br /&gt;
[[File:Pin Configuration 1.png|Figure 7]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Left Header (SV1) Pinout (Top to Bottom)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The pin count start from the top of the left header, and the pin details are as following :&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|-&lt;br /&gt;
! Pin !! Function !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CAN1H/2.7D || high-level signal for the first CAN channel.&lt;br /&gt;
|-&lt;br /&gt;
| 2 || CAN1L/2.7D || low-level signal for the first CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 3 || CAN2H/2.7C || high-level signal for the second CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 4 || CAN2L/2.7C ||  low-level signal for the second CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 5 || RX Pin || USART RX&lt;br /&gt;
|-&lt;br /&gt;
| 6 || TX Pin || USART TX&lt;br /&gt;
|-&lt;br /&gt;
| 7-20|| GPIO Pins || GPIO&#039;s&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Right Header (SV2) Pinout (Bottom to Top )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The pin count start from bottom to top and details are as following :&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! Pin !! Function !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1-11 || GPIO Pins || GPIO&#039;s&lt;br /&gt;
|-&lt;br /&gt;
| 12-13 || Vin || Voltage Input&lt;br /&gt;
|-&lt;br /&gt;
| 14-15 || 5V || 5 Voltage Output&lt;br /&gt;
|-&lt;br /&gt;
| 16-18 || GND || Ground&lt;br /&gt;
|-&lt;br /&gt;
| 19-20 || 12 Vin || 12 Voltage Input&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Top Header Pinout&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The header supports CAN communication. Pin count start at the left viewing the board from the top. Pinout configuration of header is shown in Figure 8 given below.&lt;br /&gt;
&lt;br /&gt;
[[File:6 PIN HEADER (1).png|Figure 8]]&lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; Color codes on the provided pigtail may not match documentation.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! Pin !! Function !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CAN1L/2.7A || low-level signal for the first CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 2 || CAN2L/2.7B || low-level signal for the second CAN channel &lt;br /&gt;
|-&lt;br /&gt;
| 3 || CAN2H/2.7B || high-level signal for the second CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 4 || GND || Ground&lt;br /&gt;
|-&lt;br /&gt;
| 5 || CAN1H/2.7A || high-level signal for the first CAN channel&lt;br /&gt;
|-&lt;br /&gt;
| 6 || +12V_ Aux || 6-12v power supply&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Flashing Firmware=&lt;br /&gt;
&lt;br /&gt;
Firmware flashing in this development board is straightforward. The following components are required for firmware flashings.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hardware Components&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* USB-C cable &lt;br /&gt;
* Computer running Windows, Linux, or macOS &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Software Components&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Updated Arduino IDE to compile code for ESP-32-X2.&lt;br /&gt;
* Update Mu Editor from codewith.mu&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Note : Link to download Arduino IDE : https://www.arduino.cc/en/software || Link to download Mu Editor : codewith.mu&lt;br /&gt;
&lt;br /&gt;
== Step by step instruction for Arduino IDE==&lt;br /&gt;
&lt;br /&gt;
===Sample Arduino Project===&lt;br /&gt;
https://github.com/autosportlabs/ESP32-CAN-X2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step-by-step instructions for flashing ESP-32-X2 are as follows.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Install ESP-32-X2 Board Support:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Adding ESP-32-X2 in Arduino Ide is a single-time process and its steps are as follows.&lt;br /&gt;
&lt;br /&gt;
* Open Arduino Ide&lt;br /&gt;
* Go to File &amp;gt; Preferences&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Flashing1.png| Figure 7|800px]]&lt;br /&gt;
&lt;br /&gt;
* Add the below given Json URL in the Additional board manager URL&lt;br /&gt;
&lt;br /&gt;
Json URL : https://espressif.github.io/arduino-esp32/package_esp32_index.json&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:ESPBSP1.png|Figure 8|800px]]&lt;br /&gt;
&lt;br /&gt;
* Go to Tools &amp;gt; Board &amp;gt; Boards Manager&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Flashing3.png|Figure 9|800px]]&lt;br /&gt;
&lt;br /&gt;
* In the Board Manager search bar, type ESP-32, search for esp32 by Espressif and click on install to install the board&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:ESPBSP2.png|Figure 10|800px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* After installing, click on Tool &amp;gt; Boards and select AutosportLabs ESP32-CAN-X2&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Flashing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Connect the ESP-32-X2 board to your computer using a USB-C cable with your Arduino IDE open&lt;br /&gt;
&lt;br /&gt;
* Select AutosportLabs ESP32-CAN-X2 in Tools &amp;gt; Board menu&lt;br /&gt;
&lt;br /&gt;
* Go to Tools &amp;gt; Port and select the COM port to which ESP-32-X2 is connected.&lt;br /&gt;
&lt;br /&gt;
[[File:ArduinoFlashing3.png|Figure 11|800px]]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Note : If you don’t see the COM Port in your Arduino IDE, you need to install the CP210x USB to UART Bridge VCP Drivers: https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Write your firmware code or add an existing sketch that you want to upload to your custom board.&lt;br /&gt;
&lt;br /&gt;
* Go to Sketch &amp;gt; Click upload to compile and upload the code&lt;br /&gt;
&lt;br /&gt;
* After successful uploading, you should see a “Done uploading.” message at the bottom console. This console will also show error messages if there is any error.&lt;br /&gt;
&lt;br /&gt;
[[File:ArduinoFlashing4...png|Figure 12|800px]]&lt;br /&gt;
&lt;br /&gt;
If any issues occur during upload, double-check the board selection, COM port, and your code for errors.&lt;br /&gt;
&amp;lt;be&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Importing Libraries in Arduino IDE===&lt;br /&gt;
&lt;br /&gt;
* To Install Libraries for ESP32-CAN-X2 like mcp_canbus or mcp2515&lt;br /&gt;
* Go to Sketch &amp;gt; Include Library &amp;gt; Manage LibrarieSs&lt;br /&gt;
&lt;br /&gt;
[[File:Arduino IDE Library 1.png]]&lt;br /&gt;
&lt;br /&gt;
* Type and find the desired library like mcp_canbus by Longan Labs&lt;br /&gt;
* Search and Install the library&lt;br /&gt;
&lt;br /&gt;
[[File:Arduino IDE Library 2...png]]&lt;br /&gt;
&lt;br /&gt;
== Step-by-step instruction for CircuitPython==&lt;br /&gt;
===Sample CircuitPython code===&lt;br /&gt;
https://github.com/autosportlabs/ESP32-CAN-X2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Downloading ESP-32-X2 Board Support:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Installing ESP-32-X2 is simple, please follow the steps given below :&lt;br /&gt;
&lt;br /&gt;
* Go to circuitpython.org/board/autosportlabs_esp32_can_x2&lt;br /&gt;
Click on the browse S3&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:CircuitpythonFlashing1.png|800px]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Select the desired language&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:CircuitpythonFlashing2.png|800px]]&lt;br /&gt;
* Download the latest .bin file &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:CircuitpythonFlashing4.png|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Prepare the ESP32 CAN X2 for Installation:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Connect the ESP-32-X2 board to your computer using a USB-C cable &lt;br /&gt;
* Press and hold the boot button on the development board.&lt;br /&gt;
* While holding the boot button, press and release the reset button once.&lt;br /&gt;
* Release the boot button to put the board into bootloader mode.&lt;br /&gt;
[[File:CircuitpythonFlashing5.png|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Connect to the Web Serial ESP Tool&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Go to : https://adafruit.github.io/Adafruit_WebSerial_ESPTool/&lt;br /&gt;
* Press the Connect button in the top right corner of the page.&lt;br /&gt;
* A pop-up will appear asking you to select the COM or Serial port. &lt;br /&gt;
* Look for an option with ESP32, JTAG Loader, SLAB, or FTDI in the name&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:CircuitpythonFlashing6.png|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Flash the Firmware&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Click on Choose the .bin file you downloaded.&lt;br /&gt;
* Ensure that the Offset box next to the file location is set to 0x0.&lt;br /&gt;
* After selecting the file, the button text will change to match your filename.&lt;br /&gt;
* Click the Program button to start flashing. A progress bar will appear, and after a minute or two, the firmware will be &lt;br /&gt;
written.&lt;br /&gt;
&lt;br /&gt;
[[File:Circuytpython7.gif|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Exit Bootloader Mode&#039;&#039;&#039;&lt;br /&gt;
* Press the reset button to exit bootloader mode. Shortly, the CIRCUITPY drive will pop up.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Downloading and Installing Mu Editor&#039;&#039;&#039;&lt;br /&gt;
* Download and install the recommended Mu Editor from codewith.mu.&lt;br /&gt;
* When you first start Mu, you will be prompted to select your mode. Select CircuitPython.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:Mudownload.png|800px]]&lt;br /&gt;
&lt;br /&gt;
* In Mu editor, click the Load button in the button bar, navigate to the CIRCUITPY drive, and choose code.py.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:MU2.png|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note :&#039;&#039;&#039; The CIRCUITPY drive is where your code and necessary libraries will reside. With a fresh CircuitPython install, the CIRCUITPY drive will contain a code.py file with print(&amp;quot;Hello World!&amp;quot;) and an empty lib folder. If your CIRCUITPY drive does not have a code.py file, create one and save it to the drive. CircuitPython automatically executes the code in code.py when the board starts up or resets. Do not press reset immediately after saving your code it will corrupt the drive and you may lose your code. &lt;br /&gt;
&lt;br /&gt;
* Enter your code into the editor and save the code.py file on the CIRCUITPY drive. &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:MU3.png|800px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Congratulations!&#039;&#039;&#039; You have just run your first CircuitPython program.&lt;br /&gt;
&lt;br /&gt;
=== Importing Libraries in Circuitpython ===&lt;br /&gt;
&lt;br /&gt;
Importing libraries in Circuitpython is straightforward. For installing Libraries in Circuitpython, please follow the steps given below :&lt;br /&gt;
* Go to https://circuitpython.org/libraries and download the bundle for version 9.xx.&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The version of the bundle should be the same that you are using.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Mu4.png|800px]]&lt;br /&gt;
&lt;br /&gt;
* Extract the zip file.&lt;br /&gt;
* Find the lib file where you can find your desired library.&lt;br /&gt;
* Copy that library folder or .mpy file and paste it to the lib folder in CIRCUITPY drive&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Mueditor Library.gif|800px]]&lt;br /&gt;
&lt;br /&gt;
=Bolt-ons=&lt;br /&gt;
Autosport Labs provides various add-on boards, known as &amp;quot;bolt-ons&amp;quot; for ESP32-CAN-X2. For Further details regarding bolt-on. Please click on the specific bolt-on links given below&lt;br /&gt;
* [https://wiki.autosportlabs.com/Bolt-on#GPS_Bolt-on GPS Bolt-on]&lt;/div&gt;</summary>
		<author><name>Ddimensia</name></author>
	</entry>
	<entry>
		<id>https://wiki.autosportlabs.com/index.php?title=RaceCapturePro_Lua_Scripting&amp;diff=10145</id>
		<title>RaceCapturePro Lua Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/index.php?title=RaceCapturePro_Lua_Scripting&amp;diff=10145"/>
		<updated>2024-05-30T16:15:58Z</updated>

		<summary type="html">&lt;p&gt;Ddimensia: /* sxRxButton() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=RaceCapture/Pro Scripting Guide=&lt;br /&gt;
==Example Scripts and How-Tos==&lt;br /&gt;
A large collection of example scripts can be found in our &#039;&#039;&#039;[[RaceCapturePro Lua Scripting Examples|Lua Scripting Examples]]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The [https://www.lua.org/manual/5.1/ Lua Reference Manual] can be found on [https://www.lua.org/ Lua.org]&lt;br /&gt;
&lt;br /&gt;
You can use [http://luaedit.sourceforge.net/ LuaEdit] to help you edit and debug your Lua code.&lt;br /&gt;
&lt;br /&gt;
==Lua Script Basics==&lt;br /&gt;
&lt;br /&gt;
===Conventions===&lt;br /&gt;
* All inputs and outputs are numbered starting at 0 (getGpio(0), setChannel(0), etc)&lt;br /&gt;
* All channel values must be numbers&lt;br /&gt;
* All virtual channel names must have no spaces (to be fixed in future revisions)&lt;br /&gt;
&lt;br /&gt;
====Writing your script====&lt;br /&gt;
&lt;br /&gt;
=====onTick() function=====&lt;br /&gt;
Your Lua script is centered around the onTick() function. RaceCapture/Pro will periodically call this function, and here you can define your custom tasks and logic. &lt;br /&gt;
&lt;br /&gt;
Example: this script will periodically write a message to the log:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
  println(&amp;quot;hello from RaceCapture/Pro&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039;: There can only be one onTick() handler; if multiple are defined your script will not work properly.&lt;br /&gt;
&lt;br /&gt;
=====Viewing the output log=====&lt;br /&gt;
You can observe the loading of new script and monitor and debug the behavior of your script by using the print() / println() functions. In order to see the log output, enable the &amp;quot;Poll Log&amp;quot; checkbox in the scripting window:&lt;br /&gt;
&lt;br /&gt;
[[image:Hello_RaceCapturePro_script.png|800px]]&lt;br /&gt;
&lt;br /&gt;
=====Controlling the onTick() rate=====&lt;br /&gt;
You can control how fast your script is executed using the setTickRate() function.  The tick Rate is specified in Hz, and the default rate is 1Hz, maximum of 1000Hz. &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; actual tick rates may be slower based on the amount of processing time in your onTick() handler. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
count = 0&lt;br /&gt;
setTickRate(10)&lt;br /&gt;
&lt;br /&gt;
function onTick()&lt;br /&gt;
  count = count + 1&lt;br /&gt;
  println(&amp;quot;Tick: &amp;quot; ..count)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[image:RaceCapture_tick_count.png|800px]]&lt;br /&gt;
&lt;br /&gt;
=====Reading and controlling inputs and outputs=====&lt;br /&gt;
&lt;br /&gt;
The Lua scripting enables endless combinations of custom behaviors by reading sensor values, controlling output lines, broadcasting CAN messages and writing data to the Auxiliary serial port. &lt;br /&gt;
&lt;br /&gt;
Example: Reading a sensor value and activating an output based on a threshold. &lt;br /&gt;
&lt;br /&gt;
Given:&lt;br /&gt;
* A calibrated temperature sensor is connected to the first analog input (0);&lt;br /&gt;
* The first GPIO is configured for output mode&lt;br /&gt;
&lt;br /&gt;
This script will activate the output upon crossing the temperature threshold of 212. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
  temperature = getAnalog(0)&lt;br /&gt;
  if temperature &amp;gt; 212 then&lt;br /&gt;
    setGpio(0, 1)&lt;br /&gt;
  else&lt;br /&gt;
    setGpio(0, 0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Combining multiple functions=====&lt;br /&gt;
When combining multiple functions into one script, it&#039;s recommended to break them into multiple functions and reference them from the main onTick() function.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function checkTemps()&lt;br /&gt;
&lt;br /&gt;
[ temperature checking logic goes here ]&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function checkAutoLogging()&lt;br /&gt;
&lt;br /&gt;
[ automatic logging logic goes here ]&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onTick()&lt;br /&gt;
  checkTemps()&lt;br /&gt;
  checkAutoLogging()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
===Debugging your script===&lt;br /&gt;
If you&#039;re not sure why your script is misbehaving, you can use the println() function to output messages in the log and observe how your script is behaving.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
  temperature = getAnalog(0)&lt;br /&gt;
  println(&amp;quot;current temp: &amp;quot; ..temperature)&lt;br /&gt;
  if temperature &amp;gt; 212 then&lt;br /&gt;
    println(&amp;quot;over temp!&amp;quot;)&lt;br /&gt;
    setGpio(0, 1)&lt;br /&gt;
  else&lt;br /&gt;
    println(&amp;quot;under temp&amp;quot;)&lt;br /&gt;
    setGpio(0, 0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Out of memory issues===&lt;br /&gt;
If you are seeing out of memory issues, try the following:&lt;br /&gt;
&lt;br /&gt;
====Mark variables in your script as local====&lt;br /&gt;
&lt;br /&gt;
Lua makes variables global by default, which is typically opposite of other programming languages.  Since global variables consume more memory, try making variables declared in your function local:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function addSomeNumbers()&lt;br /&gt;
  local var1 = 3&lt;br /&gt;
  local  var2 = 5&lt;br /&gt;
  return var1 + var2&lt;br /&gt;
end&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Reduce extra comments,  large string variable declaration and other bloat====&lt;br /&gt;
* Remove comments, shorten the size of any text strings you define - these all consume memory.&lt;br /&gt;
&lt;br /&gt;
====Simplify your script====&lt;br /&gt;
* Reduce the number of variables at the top, and inline their usage in the script.  This will help reduce the amount of global memory uses.&lt;br /&gt;
* Evaluate the functions you define. Sometimes it makes sense to combine your code into fewer functions, if it turns out you only call that function once.  Other times, you may need to break out a function to save space, if you need that function repeatedly.&lt;br /&gt;
&lt;br /&gt;
====Call the garbage collector periodically====&lt;br /&gt;
If your script is very close the limits of memory, regularly calling the garbage collector may help.   Calling collectgarbage() in the onTick() is recommended:&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
 collectgarbage()&lt;br /&gt;
-- other code --&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Try a Lua minimizer====&lt;br /&gt;
Minimizing/Minifying your script will compact your script, at the expense of making it harder to read.  You can try an [https://mothereff.in/lua-minifier online minifier] to see if that makes a difference. &lt;br /&gt;
&lt;br /&gt;
* Since it makes your script harder to maintain, we recommend this as a last resort.&lt;br /&gt;
&lt;br /&gt;
=Lua Reference=&lt;br /&gt;
RaceCapture/Pro uses the standard, lightweight Lua scripting language used as an extension / customization language for many software applications and especially gaming. &lt;br /&gt;
&lt;br /&gt;
* See [https://www.lua.org/ lua.org] for additional information on how to use the Lua language&lt;br /&gt;
=More examples=&lt;br /&gt;
You can see more examples in our [[RaceCapturePro Lua Scripting Examples|Lua Scripting Examples]] section.&lt;br /&gt;
&lt;br /&gt;
=API Reference=&lt;br /&gt;
&lt;br /&gt;
==General Input / Output (GPIO) Functions==&lt;br /&gt;
&lt;br /&gt;
===getGpio( channel )===&lt;br /&gt;
Retrieves the state of the specified GPIO channel&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: integer 0 - 2&lt;br /&gt;
*returns:&lt;br /&gt;
** state: 1 = channel is high, 0 = channel is low&lt;br /&gt;
&lt;br /&gt;
* When the channel is configured for input mode, a voltage high input (&amp;gt; 2 volts) will read as 1; a voltage low will read as 0. &lt;br /&gt;
* When the channel is configured as output, the channel reads 1 when the channel is activated (output transistor is connected to ground) &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039;: RaceCapture/Pro MK1 has internal pull-up resistors to 5V.&lt;br /&gt;
&lt;br /&gt;
===setGpio ( channel, state )===&lt;br /&gt;
Sets the state of the GPIO channel when the channel is configured for output mode. &lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: integer 0 - 2&lt;br /&gt;
** state: (int / &#039;&#039;(since 2.10.0)&#039;&#039; bool) 1 / true = output active; 0 / false = output inactive&lt;br /&gt;
*returns:&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
When the state specified is 1, the output is active (transistor is connected to ground). When state is 0, transistor is disconnected, and pullup resistor is active.&lt;br /&gt;
&lt;br /&gt;
When configured for input mode this function has no effect.&lt;br /&gt;
&lt;br /&gt;
===getButton()===&lt;br /&gt;
Gets the state of the front panel pushbutton.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** none&lt;br /&gt;
*returns&lt;br /&gt;
** state: true = pushbutton is depressed; false = pushbutton is not depressed&lt;br /&gt;
&lt;br /&gt;
==PWM / Analog Output functions==&lt;br /&gt;
&#039;&#039;&#039;PWM / Analog outputs only apply to RaceCapture/Pro MK1 and MK2&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===setPwmDutyCycle( channel, dutyCyclePct )===&lt;br /&gt;
Sets the duty cycle of the specified PWM / Analog output channel to the specified duty cycle percentage&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: PWM / Analog output channel 0 - 3&lt;br /&gt;
** dutyCyclePct: Percentage value of the duty cycle as a counting number 0 - 100&lt;br /&gt;
*returns&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
===setPwmClockFreq( frequency )===&lt;br /&gt;
Sets the clock frequency of the PWM outputs&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** frequency: the frequency of the PWM clock, in Hz. Supported range is 320-40000 Hz&lt;br /&gt;
* returns&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
===setAnalogOut( channel, voltage )===&lt;br /&gt;
Sets the output voltage of the specified PWM / Analog output channel to the specified period. A convenience function equivalent to setPwmDutyCycle that translates voltage to PWM percentage.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: PWM / Analog output channel 0 - 3&lt;br /&gt;
** voltage: the specified output voltage ( 0 - 5v)&lt;br /&gt;
** returns&lt;br /&gt;
* none&lt;br /&gt;
&lt;br /&gt;
==Timer / RPM Sensor Functions==&lt;br /&gt;
&lt;br /&gt;
===getTimerRpm(channel)===&lt;br /&gt;
Returns the current RPM of the specified timer input channel. Note, the timer channel configuration must be set to RPM mode.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns: RPM value&lt;br /&gt;
&lt;br /&gt;
===getTimerPeriodMs(channel)===&lt;br /&gt;
Returns the current duration of the full cycle pulse of the specified timer input channel, in milliseconds. Note the timer channel configuration must be set to Duration mode.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel 0 - 3. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns:  millisecond value&lt;br /&gt;
&lt;br /&gt;
===getTimerFreq(channel)===&lt;br /&gt;
Returns the current frequency present on the specified timer input channel, in Hz. Note the timer channel configuration must be set to Frequency Mode.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns:  Frequency in Hz&lt;br /&gt;
&lt;br /&gt;
===getTimerRaw(channel)===&lt;br /&gt;
Returns the current raw timer value as measured on the specified timer input channel.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel 0 - 3. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns: Raw timer value between 0 - 65535&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===resetTimerCount===&lt;br /&gt;
===getTimerCount===&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analog Sensor Functions==&lt;br /&gt;
    &lt;br /&gt;
===getAnalog(channel)===&lt;br /&gt;
Reads the scaled analog value for the specified analog input channel. &lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Analog input channel.  Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
*** Note: the last Analog input is connected to battery voltage:&lt;br /&gt;
**** Channel 7 on RaceCapture/Pro MK1 and MK2&lt;br /&gt;
****Channel 8 on RaceCapture/Pro MK3 and RaceCapture Apex&lt;br /&gt;
****Channel 0 on RaceCapture/Track MK1 / MK2&lt;br /&gt;
** returns: Scaled / calculated value for the specified analog channel as defined in the channel scaling configuration&lt;br /&gt;
&lt;br /&gt;
==Accelerometer / Yaw Sensor Functions==&lt;br /&gt;
&lt;br /&gt;
===getImu(channel)===&lt;br /&gt;
Reads the specified IMU channel&lt;br /&gt;
* params&lt;br /&gt;
** channel (0  = X, 1 = Y,  2=Z, 3= Yaw, 4= Pitch, 5 = Roll)&lt;br /&gt;
* returns&lt;br /&gt;
** The value scaled to G force, or degrees/sec depending on the channel selected&lt;br /&gt;
&lt;br /&gt;
===getImuRaw(channel)===&lt;br /&gt;
Reads the raw value of the specified accelerometer or yaw channel&lt;br /&gt;
* params&lt;br /&gt;
** channel (0  = X, 1 = Y,  2=Z, 3= Yaw, 4= Pitch, 5 = Roll)&lt;br /&gt;
* returns&lt;br /&gt;
** The raw accelerometer value&lt;br /&gt;
&lt;br /&gt;
==GPS Sensor Functions==&lt;br /&gt;
&lt;br /&gt;
===getGpsPos()===&lt;br /&gt;
Reads the current position as measured by the attached GPS module &#039;&#039;coming in firmware 2.0&#039;&#039;&lt;br /&gt;
* params&lt;br /&gt;
** none&lt;br /&gt;
* returns&lt;br /&gt;
** Latitude: latitude in decimal degrees&lt;br /&gt;
** Longitude: longitude in decimal degress&lt;br /&gt;
&lt;br /&gt;
===getGpsSpeed()===&lt;br /&gt;
Provides the current speed as measured by the attached GPS module&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current speed in MPH&lt;br /&gt;
&lt;br /&gt;
===getGpsQuality()===&lt;br /&gt;
Provides the current GPS quality indicator as indicated by the attached GPS module&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current GPS quality indicator&lt;br /&gt;
** 0: No fix; 1: Fixed; 2: SPS Fix; 3: Differential Fix&lt;br /&gt;
&lt;br /&gt;
===getGpsSats()===&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The number of GPS satellites currently used in the fix&lt;br /&gt;
&lt;br /&gt;
===getGpsTime()===&lt;br /&gt;
Provides the current GPS time as indicated by the attached GPS module (in NMEA format) &#039;&#039;todo: document this&#039;&#039;&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current GPS time value&lt;br /&gt;
&lt;br /&gt;
===getGpsDist()===&lt;br /&gt;
Provides the current GPS calculated distance from the beginning of the logging session, or from the start finish line, if configured.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The distance, in Miles&lt;br /&gt;
&lt;br /&gt;
===getGpsAltitude()===&lt;br /&gt;
Provides the current GPS calculated altitude from sea level in feet.  The method will return 0 if there is no GPS lock.&lt;br /&gt;
* Added: v2.9.0&lt;br /&gt;
* Parameters: &#039;&#039;None&#039;&#039;&lt;br /&gt;
* Returns: &amp;lt;altitude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===getGpsSec()===&lt;br /&gt;
Provides the number of seconds since midnight, as measured by the GPS module. &#039;&#039;todo: how does this relate to timezone? GMT or local?&#039;&#039;&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** number of seconds since midnight, as measured by the attached GPS module&lt;br /&gt;
&lt;br /&gt;
==Lap Statistics==&lt;br /&gt;
&lt;br /&gt;
===getLapCount()===&lt;br /&gt;
Provides the current Lap Count as determined by the start/finish line configuration and measured by the attached GPS module.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The number of laps detected since the logging session started&lt;br /&gt;
&lt;br /&gt;
===getLapTime()===&lt;br /&gt;
Provides the last lap time as determined by the start/finish line configuration and measured by the attached GPS module.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The last measured lap time in decimal minutes / seconds&lt;br /&gt;
&lt;br /&gt;
===getPredTime()===&lt;br /&gt;
&#039;&#039;as of 2.12.0 firmware&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Provides the current Predicted Lap time time as determined by the start/finish line configuration and measured by the attached GPS module. A training lap is required before the predicted time is valid.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current predicted time in decimal minutes / seconds&lt;br /&gt;
&lt;br /&gt;
===getAtStartFinish()===&lt;br /&gt;
Indicates if within the start finish line target as determined by the start/finish line configuration and measured by the attached GPS module.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** true if currently within the start/finish line target, false if outside&lt;br /&gt;
&lt;br /&gt;
===resetLapStats()===&lt;br /&gt;
&#039;&#039;since 2.16.0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Resets Lap Statistics, including lap count, lap time, predictive time, and session time. &lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
==Time Functions==&lt;br /&gt;
===getTickCount()===&lt;br /&gt;
Returns the number of milliseconds since power-up. &lt;br /&gt;
* params&lt;br /&gt;
None&lt;br /&gt;
* returns&lt;br /&gt;
** The number of milliseconds since power-up&lt;br /&gt;
&lt;br /&gt;
==CAN Bus functions==  &lt;br /&gt;
&lt;br /&gt;
===initCAN(channel, baud )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Initializes the CAN bus module. Normally this is done when RaceCapture/Pro powers on; use this function if you need to change the CAN baud rate on the fly.&lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** baud rate: Supported baud rates: 100000, 125000, 250000, 500000, 1000000&lt;br /&gt;
** termination: 1 to enable termination, 0 to disable. Defaults to 1 (enabled) &#039;&#039;Only available on RaceCapture/Pro MK3 and RaceCapture/Apex. On other platforms this setting has no effect&#039;&#039;. &lt;br /&gt;
* returns&lt;br /&gt;
** 1 if successful, 0 if initialization fails, nil if parameters are incorrect&lt;br /&gt;
&lt;br /&gt;
===txCAN(channel, id, isExtended, data, [timeout] )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Transmit a CAN message.&lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** identifier: The Identifier value of the message, either in standard (11 bit) or extended (29 bit) format.&lt;br /&gt;
** isExtended: 0 for Standard (11 bit) Identifier or 1 for Extended (29 bit) Identifier.&lt;br /&gt;
** data: CAN message payload; array up to 8 elements long.&lt;br /&gt;
** timeout: (optional) specify a timeout for sending this message. if the transmit queue is full, will block for the specified milliseconds. Defaults to 100ms&lt;br /&gt;
* returns&lt;br /&gt;
** 1 if successful, 0 if failed, nil if parameters are incorrect&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 channel = 0&lt;br /&gt;
 id = 1234&lt;br /&gt;
 ext = 0&lt;br /&gt;
 data = {11,22,33}&lt;br /&gt;
 res = txCAN(channel, id, ext, data)&lt;br /&gt;
&lt;br /&gt;
===rxCAN(channel, [timeout] )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Receive a CAN message, if available.&lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** timeout (optional). read timeout in milliseconds. defaults to 100ms.  For non-blocking functionality specify a timeout of 0.&lt;br /&gt;
* returns&lt;br /&gt;
** identifier: The Identifier value of the message, either in standard (11 bit) or extended (29 bit) format.&lt;br /&gt;
** isExtended: 0 for Standard (11 bit) Identifier or 1 for Extended (29 bit) Identifier.&lt;br /&gt;
** Data: CAN message payload; array up to 8 elements long.&lt;br /&gt;
&lt;br /&gt;
If no CAN message was received, the function returns nil&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 id, ext, data = rxCAN(0, 100) --100ms timeout&lt;br /&gt;
 if id ~= nil then&lt;br /&gt;
   println(&amp;quot;CAN rx: &amp;quot; ..id ..&amp;quot; &amp;quot; ..data[1]) --print ID and first element of received message&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
===setCANfilter(channel, filterId, extended, filter, mask )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Sets the specified CAN filter  and mask ID, to ignore CAN messages that match a particular ID pattern. &lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** filterId: The id of the filter. Up to 6 filters are supported on MK1, 15 per channel on MK2. Filter ids start at 0.&lt;br /&gt;
** extended: 0 for Standard (11 bit) Identifier or 1 for Extended (29 bit) Identifier.&lt;br /&gt;
** filter: Pattern value for CAN filter&lt;br /&gt;
** mask: the mask for the CAN filter&lt;br /&gt;
* returns&lt;br /&gt;
** 1 for success, 0 for fail, nil if parameters are incorrect&lt;br /&gt;
&lt;br /&gt;
==OBDII functions==&lt;br /&gt;
===readOBD2( PID )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Reads an OBD2 PID and returns the calculated value. This is a convenience method wrapped around the built-in CAN functions.&lt;br /&gt;
* params&lt;br /&gt;
** The OBD2 PID to read. Supported PIDs (TBD documented)&lt;br /&gt;
* returns&lt;br /&gt;
** The calculated PID value, or nil if the OBD2 PID was invalid or could not be read (e.g. CAN receive message timeout)&lt;br /&gt;
&lt;br /&gt;
===setOBD2Delay( delayMs )===&lt;br /&gt;
Sets an additional delay in-between OBDII PID queries. Normally the system will query PIDs as fast as possible, in a [[RC_OBDII|round robin fashion]].  &lt;br /&gt;
&lt;br /&gt;
If the vehicle&#039;s ECU exhibits problems with the rate of querying, an additional delay can be added between queries to effectively slow down the queries. &lt;br /&gt;
&lt;br /&gt;
* params&lt;br /&gt;
** The additional delay between PID queries, in ms&lt;br /&gt;
* returns&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
==Logger Control Functions==&lt;br /&gt;
&lt;br /&gt;
===onTick()===&lt;br /&gt;
* params:&lt;br /&gt;
** (none)&lt;br /&gt;
* returns:&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
The onTick() function is the main loop where scripting activity takes place. By default it is called by RaceCapture/Pro every 1 second (1Hz). The rate can be adjusted using the setTickRate() function. &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039; - you should only define one onTick() function in your code. If multiple onTick() functions are defined, only the last defined onTick() function will be used.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 function onTick()&lt;br /&gt;
   println(&amp;quot;Hello&amp;quot;) --write something to the log&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
===setTickRate(rate)===&lt;br /&gt;
Sets the rate at which the onTick() function is called&lt;br /&gt;
* params&lt;br /&gt;
** rate: The rate the onTick() function is called, in Hz. Max tick rate is 1000Hz.&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
==SD Logging control==&lt;br /&gt;
The following functions control logging operations to the internal SD card. &lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; Only SD card logging is controlled; External devices or apps connected to the telemetry stream are not affected by these commands.&lt;br /&gt;
&lt;br /&gt;
===isLogging()===&lt;br /&gt;
Indicates if an SD card logging session is in progress&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** 0 if not logging, non zero otherwise.&lt;br /&gt;
&lt;br /&gt;
===startLogging()===&lt;br /&gt;
Begins a logging session to the SD card.  If currently logging, this function has no effect. &lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; If an error occurs during writing, the error indicator on the front panel, if provided, will illuminate. &lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===stopLogging()===&lt;br /&gt;
Stops the current SD card logging session. If not logging, this function has no effect.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===setLed( led, state )===&lt;br /&gt;
Sets the state of a front panel LED&lt;br /&gt;
* params&lt;br /&gt;
** led (1-3)&lt;br /&gt;
** state: (int / &#039;&#039;[as of 2.10.0]&#039;&#039; bool) 1 / true = on, 0 / false = off&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===setBgStream( on/off )===&lt;br /&gt;
Sets the state of background streaming&lt;br /&gt;
* params&lt;br /&gt;
** Boolean: true for on, false for off.&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===getBgStream()===&lt;br /&gt;
Gets the state of background streaming&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** Boolean: True for on, false for off.&lt;br /&gt;
&lt;br /&gt;
==Serial Port Communications==&lt;br /&gt;
&lt;br /&gt;
These function calls allow reading / writing line oriented data from the built in serial ports. &lt;br /&gt;
&lt;br /&gt;
===Port mappings===&lt;br /&gt;
* 0 = USB port&amp;lt;br/&amp;gt;&lt;br /&gt;
* 1 = GPS port&amp;lt;br/&amp;gt;&lt;br /&gt;
* 2 = Internal telemetry port (MK2/3/Apex only)&amp;lt;br/&amp;gt;&lt;br /&gt;
* 3 = Bluetooth port&amp;lt;br/&amp;gt;&lt;br /&gt;
* 4 = Auxiliary / WiFi port&amp;lt;br/&amp;gt; (RaceCapture/Pro MK2)&lt;br /&gt;
* 5 = WiFi port&lt;br /&gt;
* 6 = External Auxiliary port (RaceCapture/Pro MK3 and RaceCapture/Apex only)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039;: We only recommend  using the designated auxiliary port for your hardware model  The other ports have been included for reference; using them may interfere with normal operations of the unit.&lt;br /&gt;
&lt;br /&gt;
===initSer( port, baud, bits, parity, stopBits)===&lt;br /&gt;
Initializes the specified serial port&lt;br /&gt;
&lt;br /&gt;
* params&lt;br /&gt;
** port: The port to initialize. (defaults to Auxiliary port)&lt;br /&gt;
** baud: The baud rate to set (defaults to 115200)&lt;br /&gt;
** bits: Number of bit in the message (8 or 7) (defaults to 8)&lt;br /&gt;
** parity: (1 = Even Parity, 2 = Odd Parity, 0 = No Parity) (defaults to No Parity)&lt;br /&gt;
** stopBits: number of stop bits (1 or 2) (defaults to 1)&lt;br /&gt;
&lt;br /&gt;
* returns&lt;br /&gt;
** true if initialization succeeds&lt;br /&gt;
&lt;br /&gt;
===readCSer( port, [timeout])===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Read a character from the specified serial port&lt;br /&gt;
&lt;br /&gt;
* params&lt;br /&gt;
** port: The port to read. (required)&lt;br /&gt;
** timeout - the read timeout, in ms.&lt;br /&gt;
&lt;br /&gt;
* returns&lt;br /&gt;
** the character read, or nil if the timeout was reached&lt;br /&gt;
&lt;br /&gt;
===readSer( port, [timeout])===&lt;br /&gt;
Read a line of data from the specified serial port. This command blocks until a newline (&#039;\n&#039;) character is received on the port, or a timeout occurs.&lt;br /&gt;
* params&lt;br /&gt;
** port: Serial port 0 - 4&lt;br /&gt;
** timeout - the read timeout, in ms.&lt;br /&gt;
** returns: a line of serial data, or nil if the timeout was reached&lt;br /&gt;
&lt;br /&gt;
===writeCSer( port, data )===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Writes the specified character to the serial port. The call will block until the character is written.&lt;br /&gt;
* params:&lt;br /&gt;
** port - the serial port to write&lt;br /&gt;
** char - the character to write.&lt;br /&gt;
&lt;br /&gt;
* returns:&lt;br /&gt;
(no return values)&lt;br /&gt;
&lt;br /&gt;
===writeSer( port, data )===&lt;br /&gt;
Writes a line of data to the specified serial port, appending a newline at the end. The call will block until all characters are written.&lt;br /&gt;
* params&lt;br /&gt;
** port: Serial port 0 - 4&lt;br /&gt;
** data: the data in string format&lt;br /&gt;
&lt;br /&gt;
* returns:&lt;br /&gt;
(no return values)&lt;br /&gt;
&lt;br /&gt;
==Logger Configuration Functions==&lt;br /&gt;
&lt;br /&gt;
===flashLoggerCfg()===&lt;br /&gt;
Writes the current configuration in RAM to flash memory.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
    &lt;br /&gt;
===setPwmClockFreq( freq )===&lt;br /&gt;
Sets the clock frequency for all PWM channels&lt;br /&gt;
* params&lt;br /&gt;
** freq: The clock frequency &#039;&#039;todo: what units?&#039;&#039;&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===getPwmClockFreq()=== &lt;br /&gt;
Gets the PWM clock frequency controlling all PWM channels&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** the PWM clock frequency &#039;&#039;todo: what units?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===calibrateImuZero()===&lt;br /&gt;
Automatically Calibrates the accelerometer zero position.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
==Virtual Channels==&lt;br /&gt;
&lt;br /&gt;
===addChannel( name, sampleRate, [precision], [min], [max], [units] )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Adds a virtual channel. This virtual channel remains in memory during runtime; it is not persisted in the configuration. Up to 100 virtual channels can be created.&lt;br /&gt;
* params&lt;br /&gt;
** name: The name of the channel, up to 10 characters long. We recommend using an existing System channel name as defined by the app when possible.&lt;br /&gt;
** sampleRate: A supported sample rate (1,10,25,50,100,200Hz)&lt;br /&gt;
** precision: (optional) the numerical precision (number of decimal places) used when logging to SD and telemetry. Defaults to 2&lt;br /&gt;
** min: (optional) The min expected value for this channel. Defaults to 0&lt;br /&gt;
** max: (optional) The max expected value for this channel. Defaults to 1000&lt;br /&gt;
** units: (optional) The units label for this channel. Defaults to empty string / none&lt;br /&gt;
&lt;br /&gt;
* returns&lt;br /&gt;
** the id of the new virtual channel, or NIL if the virtual channel could not be created. Use this id for setting the channel value (see setChannel() )&lt;br /&gt;
&lt;br /&gt;
===getChannel( Channel ID or name )===&lt;br /&gt;
* First available  in v2.9.0 ; retrieving by channel name available in v2.13.0&lt;br /&gt;
* Parameters &lt;br /&gt;
** Channel ID or name : if a number, matches on the channel ID  as provided by the &#039;&#039;&#039;addChannel&#039;&#039;&#039; function. If string, matches on any current channel in the system. &lt;br /&gt;
* Returns&lt;br /&gt;
** (number) The current value of the channel if available, or &#039;&#039;&#039;nil&#039;&#039;&#039; if the value is not available. You should always check if the value is present before using it for other purposes, especially if the script&#039;s tick rate is high relative to the channel&#039;s sample rate.&lt;br /&gt;
&lt;br /&gt;
* Examples: &lt;br /&gt;
&lt;br /&gt;
 --returns the virtual channel assigned to ID 1. Current value of channel is stored in val &lt;br /&gt;
 val = getChannel(1)&lt;br /&gt;
&lt;br /&gt;
 --get the channel by name&lt;br /&gt;
 rpm = getChannel(&amp;quot;RPM&amp;quot;) &lt;br /&gt;
 if rpm ~= nil then&lt;br /&gt;
  println(&amp;quot;rpm channel: &amp;quot; ..rpm)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
===setChannel( channelId, value )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Updates the value of a previously created virtual channel.&lt;br /&gt;
* params&lt;br /&gt;
** channelId: the ID of the channel provided by addChannel()&lt;br /&gt;
** value: the new value to set for the virtual channel&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 id = addChannel(&amp;quot;EGT&amp;quot;, 1)&lt;br /&gt;
 &lt;br /&gt;
 function onTick()&lt;br /&gt;
    temp = getAnalog(0) --read analog channel 0&lt;br /&gt;
    temp = temp * 1000&lt;br /&gt;
    setChannel(id, temp) --sets the virtual channel value&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
==Time Info==&lt;br /&gt;
These methods get you information about dates and time.  This is useful in controlling script behavior or just knowing what time it is.&lt;br /&gt;
&lt;br /&gt;
===getUptime()===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Returns the number of miliseconds since the device last started.  This is always available and is the most consistent way to time things in LUA script on RaceCapture.&lt;br /&gt;
&lt;br /&gt;
* Returns&lt;br /&gt;
** Number of milliseconds since CPU boot.&lt;br /&gt;
&lt;br /&gt;
===getDateTime()===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Returns date and time info to the best of the systems ability, in UTC.  Only available after GPS lock has been established.  Will return epoch time (Jan 1, 1970 00:00:000) if time is not available.&lt;br /&gt;
&lt;br /&gt;
* Returns: A list of date and time information in the following order:&lt;br /&gt;
** Year&lt;br /&gt;
** Month&lt;br /&gt;
** Day&lt;br /&gt;
** Hour&lt;br /&gt;
** Minute&lt;br /&gt;
** Second&lt;br /&gt;
** Millisecond&lt;br /&gt;
&lt;br /&gt;
==Dashboard Control==&lt;br /&gt;
===txButton()===&lt;br /&gt;
Simulates button press events for dashboard navigation and control.  RaceCapture dashboard must be connected for function to have effect. &lt;br /&gt;
* params&lt;br /&gt;
**  button_id:  ID of button to transmit.  0 = left button;1 = right button;2 = ack/yes;3 = no&lt;br /&gt;
** state: State of button: 1 = pressed; 0 = not pressed&lt;br /&gt;
* returns&lt;br /&gt;
** (nothing)&lt;br /&gt;
&lt;br /&gt;
==ShiftX2/3 control==&lt;br /&gt;
The following functions provide access to the [[ShiftX2]] or [[ShiftX3]] RGB sequential shift light.  &#039;&#039;Available in firmware 2.15.0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===sxSetConfig()===&lt;br /&gt;
Configures the connected ShiftX device. This must be called prior to any other configuration function calls.  All parameters are optional; call with no parameters to use the default settings:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sxSetConfig()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* params&lt;br /&gt;
** orientation: 0 (normal, 7-segment display below bar graph); 1 (inverted, 7-segment display above bar graph). Defaut value: 0&lt;br /&gt;
** brightness: 0 (automatic brightness control with ambient light sensor; 1-100: brightness percentage. Default value: 0&lt;br /&gt;
** CAN bus: 0 (connected to CAN1); 1 (connected to CAN2). Default value: 1&lt;br /&gt;
** CAN base address: base CAN address to use.  Default value: 931328)&lt;br /&gt;
** Auto brightness scaling: Amplification value to tune ambient light sensor. 0-255 value; Default value: 51&lt;br /&gt;
** Enable / Disable button events: true (Enable button event broadcast to app); false (Disable button event broadcast to app)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxCfgLinearGraph()===&lt;br /&gt;
Configures the the style and overall range for the linear graph. &lt;br /&gt;
* params&lt;br /&gt;
** Rendering Style: 0 (left-&amp;gt;right); 1 (center); 2 (right-&amp;gt;left)&lt;br /&gt;
** Linear Style: 0 (Smooth / interpolated); 1 (stepped)&lt;br /&gt;
** Low Range Threshold: The overall low range for the linear graph&lt;br /&gt;
** High Range Threshold: The overall high range for the linear graph (ignored if linear style = stepped)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetLinearThresh()===&lt;br /&gt;
Configure a threshold for the linear graph. Each threshold is identified by an ID, and thresholds are processed from low to high IDs. 5 thresholds can be defined. &lt;br /&gt;
* params&lt;br /&gt;
** Threshold Id: Id for threshold to set. (0-4). Lower IDs are evaluated first. &lt;br /&gt;
** Segment Length: 0 -&amp;gt; number of LEDs on linear graph. (Ignored if linear style = smooth)&lt;br /&gt;
** Threshold Value: Value where this threshold is activated&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxUpdateLinearGraph()===&lt;br /&gt;
Update the linear graph with the current sensor value. ShiftX will apply the previously configured thresholds to set bar graph length, color and flash. &lt;br /&gt;
* params&lt;br /&gt;
** Value: current value representing the linear graph&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
===sxSetAlert()=== &lt;br /&gt;
Direct set an alert indicator.   For ShiftX3, ID0=Alert LED on right side; ID1=Alert LED on left side.&lt;br /&gt;
* params&lt;br /&gt;
** Alert ID: ID of alert (0 -&amp;gt; # of alert indicators)&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetAlertThresh()===&lt;br /&gt;
Configures an alert threshold. Up to 5 thresholds can be configured per alert indicator. Thresholds are evaluated by ID, from low to high.&lt;br /&gt;
* params&lt;br /&gt;
** Alert ID: Id of Alert (0 -&amp;gt; # of alert indicators)&lt;br /&gt;
** Threshold ID: Id for threshold to set. (0-4). Lower IDs are evaluated first.&lt;br /&gt;
** Threshold Value: Value where this threshold is activated&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxUpdateAlert()===&lt;br /&gt;
Updates the current value for the specified Alert. ShiftX will apply the previously configured thresholds to set color and flash. &lt;br /&gt;
* params&lt;br /&gt;
** Alert ID: Id of Alert (0 -&amp;gt; # of alert indicators)&lt;br /&gt;
** Value: current value representing the alert&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetDisplay()===&lt;br /&gt;
Directly sets the value of the 7 segment display. &lt;br /&gt;
* params&lt;br /&gt;
** Digit index (must be 0)&lt;br /&gt;
** Charater: 0-9. Can set ASCII value by offsetting the value by 48 (e.g. ASCII - 48)&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetLed()===&lt;br /&gt;
Directly set any available LED on ShiftX&lt;br /&gt;
* params&lt;br /&gt;
** LED Index: 0 -&amp;gt; # of LEDs on device&lt;br /&gt;
** Number of LEDs to set: 0 -&amp;gt; # of LEDs on device (0  = set all remaining)&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxRxButton()===&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** nil if no button presses are available; otherwise:&lt;br /&gt;
** button_id (ID of button. left button = 0, right button = 1, yes = 2, ok/no = 3)&lt;br /&gt;
** state: (0 = not pressed; 1 = pressed)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
local id, state = sxRxButton()&lt;br /&gt;
if id ~= nil then println(&#039;button &#039; ..id ..&#039; state &#039; ..state) end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Helper Functions==&lt;br /&gt;
===calcGear()===&lt;br /&gt;
A convenience function to calculate the current gear of the vehicle.  &#039;&#039;Available in firmware 2.15.0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Variation 1: Use built in GPS speed channel and RPM channel named &amp;quot;RPM&amp;quot;&lt;br /&gt;
* params&lt;br /&gt;
** Tire Diameter: Tire diameter, in cm. &lt;br /&gt;
** Final Drive Ratio: The ratio of the final drive&lt;br /&gt;
** Gear 1 Ratio: Ratio of 1st gear&lt;br /&gt;
** Gear 2 Ratio: Ratio of 2nd gear (optional)&lt;br /&gt;
** Gear 3 Ratio: Ratio of 3rd gear (optional)&lt;br /&gt;
** Gear 4 Ratio: Ratio of 4th gear (optional)&lt;br /&gt;
** Gear 5 Ratio: Ratio of 5th gear (optional)&lt;br /&gt;
** Gear 6 Ratio: Ratio of 6th gear (optional)&lt;br /&gt;
* returns&lt;br /&gt;
** detected gear (1-6) or nil if no gear was detected&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
local gear = calcGear(62.7, 3.45, 4.23, 2.52, 1.66, 1.22, 1.0, 0.8)&lt;br /&gt;
if gear ~= nil then println(&#039;gear: &#039; ..gear) end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Variation 2: Specify Speed and RPM channel&lt;br /&gt;
* params&lt;br /&gt;
** Speed Channel name&lt;br /&gt;
** RPM Channel name&lt;br /&gt;
** Tire Diameter: Tire diameter, in cm. &lt;br /&gt;
** Final Drive Ratio: The ratio of the final drive&lt;br /&gt;
** Gear 1 Ratio: Ratio of 1st gear&lt;br /&gt;
** Gear 2 Ratio: Ratio of 2nd gear (optional)&lt;br /&gt;
** Gear 3 Ratio: Ratio of 3rd gear (optional)&lt;br /&gt;
** Gear 4 Ratio: Ratio of 4th gear (optional)&lt;br /&gt;
** Gear 5 Ratio: Ratio of 5th gear (optional)&lt;br /&gt;
** Gear 6 Ratio: Ratio of 6th gear (optional)&lt;br /&gt;
* returns&lt;br /&gt;
** detected gear (1-6) or nil if no gear was detected&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
local gear = calcGear(&#039;Speed&#039;, &#039;RPM&#039;, 62.7, 3.45, 4.23, 2.52, 1.66, 1.22, 1.0, 0.8)&lt;br /&gt;
if gear ~= nil then println(&#039;gear: &#039; ..gear) end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ddimensia</name></author>
	</entry>
	<entry>
		<id>https://wiki.autosportlabs.com/index.php?title=RaceCapturePro_Lua_Scripting&amp;diff=9932</id>
		<title>RaceCapturePro Lua Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/index.php?title=RaceCapturePro_Lua_Scripting&amp;diff=9932"/>
		<updated>2024-01-01T21:22:46Z</updated>

		<summary type="html">&lt;p&gt;Ddimensia: /* txButton() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=RaceCapture/Pro Scripting Guide=&lt;br /&gt;
==Example Scripts and How-Tos==&lt;br /&gt;
A large collection of example scripts can be found in our &#039;&#039;&#039;[[RaceCapturePro Lua Scripting Examples|Lua Scripting Examples]]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The [https://www.lua.org/manual/5.1/ Lua Reference Manual] can be found on [https://www.lua.org/ Lua.org]&lt;br /&gt;
&lt;br /&gt;
You can use [http://luaedit.sourceforge.net/ LuaEdit] to help you edit and debug your Lua code.&lt;br /&gt;
&lt;br /&gt;
==Lua Script Basics==&lt;br /&gt;
&lt;br /&gt;
===Conventions===&lt;br /&gt;
* All inputs and outputs are numbered starting at 0 (getGpio(0), setChannel(0), etc)&lt;br /&gt;
* All channel values must be numbers&lt;br /&gt;
* All virtual channel names must have no spaces (to be fixed in future revisions)&lt;br /&gt;
&lt;br /&gt;
====Writing your script====&lt;br /&gt;
&lt;br /&gt;
=====onTick() function=====&lt;br /&gt;
Your Lua script is centered around the onTick() function. RaceCapture/Pro will periodically call this function, and here you can define your custom tasks and logic. &lt;br /&gt;
&lt;br /&gt;
Example: this script will periodically write a message to the log:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
  println(&amp;quot;hello from RaceCapture/Pro&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039;: There can only be one onTick() handler; if multiple are defined your script will not work properly.&lt;br /&gt;
&lt;br /&gt;
=====Viewing the output log=====&lt;br /&gt;
You can observe the loading of new script and monitor and debug the behavior of your script by using the print() / println() functions. In order to see the log output, enable the &amp;quot;Poll Log&amp;quot; checkbox in the scripting window:&lt;br /&gt;
&lt;br /&gt;
[[image:Hello_RaceCapturePro_script.png|800px]]&lt;br /&gt;
&lt;br /&gt;
=====Controlling the onTick() rate=====&lt;br /&gt;
You can control how fast your script is executed using the setTickRate() function.  The tick Rate is specified in Hz, and the default rate is 1Hz, maximum of 1000Hz. &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; actual tick rates may be slower based on the amount of processing time in your onTick() handler. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
count = 0&lt;br /&gt;
setTickRate(10)&lt;br /&gt;
&lt;br /&gt;
function onTick()&lt;br /&gt;
  count = count + 1&lt;br /&gt;
  println(&amp;quot;Tick: &amp;quot; ..count)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[image:RaceCapture_tick_count.png|800px]]&lt;br /&gt;
&lt;br /&gt;
=====Reading and controlling inputs and outputs=====&lt;br /&gt;
&lt;br /&gt;
The Lua scripting enables endless combinations of custom behaviors by reading sensor values, controlling output lines, broadcasting CAN messages and writing data to the Auxiliary serial port. &lt;br /&gt;
&lt;br /&gt;
Example: Reading a sensor value and activating an output based on a threshold. &lt;br /&gt;
&lt;br /&gt;
Given:&lt;br /&gt;
* A calibrated temperature sensor is connected to the first analog input (0);&lt;br /&gt;
* The first GPIO is configured for output mode&lt;br /&gt;
&lt;br /&gt;
This script will activate the output upon crossing the temperature threshold of 212. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
  temperature = getAnalog(0)&lt;br /&gt;
  if temperature &amp;gt; 212 then&lt;br /&gt;
    setGpio(0, 1)&lt;br /&gt;
  else&lt;br /&gt;
    setGpio(0, 0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Combining multiple functions=====&lt;br /&gt;
When combining multiple functions into one script, it&#039;s recommended to break them into multiple functions and reference them from the main onTick() function.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function checkTemps()&lt;br /&gt;
&lt;br /&gt;
[ temperature checking logic goes here ]&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function checkAutoLogging()&lt;br /&gt;
&lt;br /&gt;
[ automatic logging logic goes here ]&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onTick()&lt;br /&gt;
  checkTemps()&lt;br /&gt;
  checkAutoLogging()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
===Debugging your script===&lt;br /&gt;
If you&#039;re not sure why your script is misbehaving, you can use the println() function to output messages in the log and observe how your script is behaving.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
  temperature = getAnalog(0)&lt;br /&gt;
  println(&amp;quot;current temp: &amp;quot; ..temperature)&lt;br /&gt;
  if temperature &amp;gt; 212 then&lt;br /&gt;
    println(&amp;quot;over temp!&amp;quot;)&lt;br /&gt;
    setGpio(0, 1)&lt;br /&gt;
  else&lt;br /&gt;
    println(&amp;quot;under temp&amp;quot;)&lt;br /&gt;
    setGpio(0, 0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Out of memory issues===&lt;br /&gt;
If you are seeing out of memory issues, try the following:&lt;br /&gt;
&lt;br /&gt;
====Mark variables in your script as local====&lt;br /&gt;
&lt;br /&gt;
Lua makes variables global by default, which is typically opposite of other programming languages.  Since global variables consume more memory, try making variables declared in your function local:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function addSomeNumbers()&lt;br /&gt;
  local var1 = 3&lt;br /&gt;
  local  var2 = 5&lt;br /&gt;
  return var1 + var2&lt;br /&gt;
end&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Reduce extra comments,  large string variable declaration and other bloat====&lt;br /&gt;
* Remove comments, shorten the size of any text strings you define - these all consume memory.&lt;br /&gt;
&lt;br /&gt;
====Simplify your script====&lt;br /&gt;
* Reduce the number of variables at the top, and inline their usage in the script.  This will help reduce the amount of global memory uses.&lt;br /&gt;
* Evaluate the functions you define. Sometimes it makes sense to combine your code into fewer functions, if it turns out you only call that function once.  Other times, you may need to break out a function to save space, if you need that function repeatedly.&lt;br /&gt;
&lt;br /&gt;
====Call the garbage collector periodically====&lt;br /&gt;
If your script is very close the limits of memory, regularly calling the garbage collector may help.   Calling collectgarbage() in the onTick() is recommended:&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
 collectgarbage()&lt;br /&gt;
-- other code --&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Try a Lua minimizer====&lt;br /&gt;
Minimizing/Minifying your script will compact your script, at the expense of making it harder to read.  You can try an [https://mothereff.in/lua-minifier online minifier] to see if that makes a difference. &lt;br /&gt;
&lt;br /&gt;
* Since it makes your script harder to maintain, we recommend this as a last resort.&lt;br /&gt;
&lt;br /&gt;
=Lua Reference=&lt;br /&gt;
RaceCapture/Pro uses the standard, lightweight Lua scripting language used as an extension / customization language for many software applications and especially gaming. &lt;br /&gt;
&lt;br /&gt;
* See [https://www.lua.org/ lua.org] for additional information on how to use the Lua language&lt;br /&gt;
=More examples=&lt;br /&gt;
You can see more examples in our [[RaceCapturePro Lua Scripting Examples|Lua Scripting Examples]] section.&lt;br /&gt;
&lt;br /&gt;
=API Reference=&lt;br /&gt;
&lt;br /&gt;
==General Input / Output (GPIO) Functions==&lt;br /&gt;
&lt;br /&gt;
===getGpio( channel )===&lt;br /&gt;
Retrieves the state of the specified GPIO channel&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: integer 0 - 2&lt;br /&gt;
*returns:&lt;br /&gt;
** state: 1 = channel is high, 0 = channel is low&lt;br /&gt;
&lt;br /&gt;
* When the channel is configured for input mode, a voltage high input (&amp;gt; 2 volts) will read as 1; a voltage low will read as 0. &lt;br /&gt;
* When the channel is configured as output, the channel reads 1 when the channel is activated (output transistor is connected to ground) &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039;: RaceCapture/Pro MK1 has internal pull-up resistors to 5V.&lt;br /&gt;
&lt;br /&gt;
===setGpio ( channel, state )===&lt;br /&gt;
Sets the state of the GPIO channel when the channel is configured for output mode. &lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: integer 0 - 2&lt;br /&gt;
** state: (int / &#039;&#039;(since 2.10.0)&#039;&#039; bool) 1 / true = output active; 0 / false = output inactive&lt;br /&gt;
*returns:&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
When the state specified is 1, the output is active (transistor is connected to ground). When state is 0, transistor is disconnected, and pullup resistor is active.&lt;br /&gt;
&lt;br /&gt;
When configured for input mode this function has no effect.&lt;br /&gt;
&lt;br /&gt;
===getButton()===&lt;br /&gt;
Gets the state of the front panel pushbutton.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** none&lt;br /&gt;
*returns&lt;br /&gt;
** state: true = pushbutton is depressed; false = pushbutton is not depressed&lt;br /&gt;
&lt;br /&gt;
==PWM / Analog Output functions==&lt;br /&gt;
&#039;&#039;&#039;PWM / Analog outputs only apply to RaceCapture/Pro MK1 and MK2&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===setPwmDutyCycle( channel, dutyCyclePct )===&lt;br /&gt;
Sets the duty cycle of the specified PWM / Analog output channel to the specified duty cycle percentage&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: PWM / Analog output channel 0 - 3&lt;br /&gt;
** dutyCyclePct: Percentage value of the duty cycle as a counting number 0 - 100&lt;br /&gt;
*returns&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
===setPwmClockFreq( frequency )===&lt;br /&gt;
Sets the clock frequency of the PWM outputs&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** frequency: the frequency of the PWM clock, in Hz. Supported range is 320-40000 Hz&lt;br /&gt;
* returns&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
===setAnalogOut( channel, voltage )===&lt;br /&gt;
Sets the output voltage of the specified PWM / Analog output channel to the specified period. A convenience function equivalent to setPwmDutyCycle that translates voltage to PWM percentage.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: PWM / Analog output channel 0 - 3&lt;br /&gt;
** voltage: the specified output voltage ( 0 - 5v)&lt;br /&gt;
** returns&lt;br /&gt;
* none&lt;br /&gt;
&lt;br /&gt;
==Timer / RPM Sensor Functions==&lt;br /&gt;
&lt;br /&gt;
===getTimerRpm(channel)===&lt;br /&gt;
Returns the current RPM of the specified timer input channel. Note, the timer channel configuration must be set to RPM mode.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns: RPM value&lt;br /&gt;
&lt;br /&gt;
===getTimerPeriodMs(channel)===&lt;br /&gt;
Returns the current duration of the full cycle pulse of the specified timer input channel, in milliseconds. Note the timer channel configuration must be set to Duration mode.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel 0 - 3. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns:  millisecond value&lt;br /&gt;
&lt;br /&gt;
===getTimerFreq(channel)===&lt;br /&gt;
Returns the current frequency present on the specified timer input channel, in Hz. Note the timer channel configuration must be set to Frequency Mode.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns:  Frequency in Hz&lt;br /&gt;
&lt;br /&gt;
===getTimerRaw(channel)===&lt;br /&gt;
Returns the current raw timer value as measured on the specified timer input channel.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel 0 - 3. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns: Raw timer value between 0 - 65535&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===resetTimerCount===&lt;br /&gt;
===getTimerCount===&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analog Sensor Functions==&lt;br /&gt;
    &lt;br /&gt;
===getAnalog(channel)===&lt;br /&gt;
Reads the scaled analog value for the specified analog input channel. &lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Analog input channel.  Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
*** Note: the last Analog input is connected to battery voltage:&lt;br /&gt;
**** Channel 7 on RaceCapture/Pro MK1 and MK2&lt;br /&gt;
****Channel 8 on RaceCapture/Pro MK3 and RaceCapture Apex&lt;br /&gt;
****Channel 0 on RaceCapture/Track MK1 / MK2&lt;br /&gt;
** returns: Scaled / calculated value for the specified analog channel as defined in the channel scaling configuration&lt;br /&gt;
&lt;br /&gt;
==Accelerometer / Yaw Sensor Functions==&lt;br /&gt;
&lt;br /&gt;
===getImu(channel)===&lt;br /&gt;
Reads the specified IMU channel&lt;br /&gt;
* params&lt;br /&gt;
** channel (0  = X, 1 = Y,  2=Z, 3= Yaw, 4= Pitch, 5 = Roll)&lt;br /&gt;
* returns&lt;br /&gt;
** The value scaled to G force, or degrees/sec depending on the channel selected&lt;br /&gt;
&lt;br /&gt;
===getImuRaw(channel)===&lt;br /&gt;
Reads the raw value of the specified accelerometer or yaw channel&lt;br /&gt;
* params&lt;br /&gt;
** channel (0  = X, 1 = Y,  2=Z, 3= Yaw, 4= Pitch, 5 = Roll)&lt;br /&gt;
* returns&lt;br /&gt;
** The raw accelerometer value&lt;br /&gt;
&lt;br /&gt;
==GPS Sensor Functions==&lt;br /&gt;
&lt;br /&gt;
===getGpsPos()===&lt;br /&gt;
Reads the current position as measured by the attached GPS module &#039;&#039;coming in firmware 2.0&#039;&#039;&lt;br /&gt;
* params&lt;br /&gt;
** none&lt;br /&gt;
* returns&lt;br /&gt;
** Latitude: latitude in decimal degrees&lt;br /&gt;
** Longitude: longitude in decimal degress&lt;br /&gt;
&lt;br /&gt;
===getGpsSpeed()===&lt;br /&gt;
Provides the current speed as measured by the attached GPS module&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current speed in MPH&lt;br /&gt;
&lt;br /&gt;
===getGpsQuality()===&lt;br /&gt;
Provides the current GPS quality indicator as indicated by the attached GPS module&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current GPS quality indicator&lt;br /&gt;
** 0: No fix; 1: Fixed; 2: SPS Fix; 3: Differential Fix&lt;br /&gt;
&lt;br /&gt;
===getGpsSats()===&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The number of GPS satellites currently used in the fix&lt;br /&gt;
&lt;br /&gt;
===getGpsTime()===&lt;br /&gt;
Provides the current GPS time as indicated by the attached GPS module (in NMEA format) &#039;&#039;todo: document this&#039;&#039;&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current GPS time value&lt;br /&gt;
&lt;br /&gt;
===getGpsDist()===&lt;br /&gt;
Provides the current GPS calculated distance from the beginning of the logging session, or from the start finish line, if configured.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The distance, in Miles&lt;br /&gt;
&lt;br /&gt;
===getGpsAltitude()===&lt;br /&gt;
Provides the current GPS calculated altitude from sea level in feet.  The method will return 0 if there is no GPS lock.&lt;br /&gt;
* Added: v2.9.0&lt;br /&gt;
* Parameters: &#039;&#039;None&#039;&#039;&lt;br /&gt;
* Returns: &amp;lt;altitude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===getGpsSec()===&lt;br /&gt;
Provides the number of seconds since midnight, as measured by the GPS module. &#039;&#039;todo: how does this relate to timezone? GMT or local?&#039;&#039;&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** number of seconds since midnight, as measured by the attached GPS module&lt;br /&gt;
&lt;br /&gt;
==Lap Statistics==&lt;br /&gt;
&lt;br /&gt;
===getLapCount()===&lt;br /&gt;
Provides the current Lap Count as determined by the start/finish line configuration and measured by the attached GPS module.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The number of laps detected since the logging session started&lt;br /&gt;
&lt;br /&gt;
===getLapTime()===&lt;br /&gt;
Provides the last lap time as determined by the start/finish line configuration and measured by the attached GPS module.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The last measured lap time in decimal minutes / seconds&lt;br /&gt;
&lt;br /&gt;
===getPredTime()===&lt;br /&gt;
&#039;&#039;as of 2.12.0 firmware&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Provides the current Predicted Lap time time as determined by the start/finish line configuration and measured by the attached GPS module. A training lap is required before the predicted time is valid.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current predicted time in decimal minutes / seconds&lt;br /&gt;
&lt;br /&gt;
===getAtStartFinish()===&lt;br /&gt;
Indicates if within the start finish line target as determined by the start/finish line configuration and measured by the attached GPS module.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** true if currently within the start/finish line target, false if outside&lt;br /&gt;
&lt;br /&gt;
===resetLapStats()===&lt;br /&gt;
&#039;&#039;since 2.16.0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Resets Lap Statistics, including lap count, lap time, predictive time, and session time. &lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
==Time Functions==&lt;br /&gt;
===getTickCount()===&lt;br /&gt;
Returns the number of milliseconds since power-up. &lt;br /&gt;
* params&lt;br /&gt;
None&lt;br /&gt;
* returns&lt;br /&gt;
** The number of milliseconds since power-up&lt;br /&gt;
&lt;br /&gt;
==CAN Bus functions==  &lt;br /&gt;
&lt;br /&gt;
===initCAN(channel, baud )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Initializes the CAN bus module. Normally this is done when RaceCapture/Pro powers on; use this function if you need to change the CAN baud rate on the fly.&lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** baud rate: Supported baud rates: 100000, 125000, 250000, 500000, 1000000&lt;br /&gt;
** termination: 1 to enable termination, 0 to disable. Defaults to 1 (enabled) &#039;&#039;Only available on RaceCapture/Pro MK3 and RaceCapture/Apex. On other platforms this setting has no effect&#039;&#039;. &lt;br /&gt;
* returns&lt;br /&gt;
** 1 if successful, 0 if initialization fails, nil if parameters are incorrect&lt;br /&gt;
&lt;br /&gt;
===txCAN(channel, id, isExtended, data, [timeout] )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Transmit a CAN message.&lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** identifier: The Identifier value of the message, either in standard (11 bit) or extended (29 bit) format.&lt;br /&gt;
** isExtended: 0 for Standard (11 bit) Identifier or 1 for Extended (29 bit) Identifier.&lt;br /&gt;
** data: CAN message payload; array up to 8 elements long.&lt;br /&gt;
** timeout: (optional) specify a timeout for sending this message. if the transmit queue is full, will block for the specified milliseconds. Defaults to 100ms&lt;br /&gt;
* returns&lt;br /&gt;
** 1 if successful, 0 if failed, nil if parameters are incorrect&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 channel = 0&lt;br /&gt;
 id = 1234&lt;br /&gt;
 ext = 0&lt;br /&gt;
 data = {11,22,33}&lt;br /&gt;
 res = txCAN(channel, id, ext, data)&lt;br /&gt;
&lt;br /&gt;
===rxCAN(channel, [timeout] )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Receive a CAN message, if available.&lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** timeout (optional). read timeout in milliseconds. defaults to 100ms.  For non-blocking functionality specify a timeout of 0.&lt;br /&gt;
* returns&lt;br /&gt;
** identifier: The Identifier value of the message, either in standard (11 bit) or extended (29 bit) format.&lt;br /&gt;
** isExtended: 0 for Standard (11 bit) Identifier or 1 for Extended (29 bit) Identifier.&lt;br /&gt;
** Data: CAN message payload; array up to 8 elements long.&lt;br /&gt;
&lt;br /&gt;
If no CAN message was received, the function returns nil&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 id, ext, data = rxCAN(0, 100) --100ms timeout&lt;br /&gt;
 if id ~= nil then&lt;br /&gt;
   println(&amp;quot;CAN rx: &amp;quot; ..id ..&amp;quot; &amp;quot; ..data[1]) --print ID and first element of received message&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
===setCANfilter(channel, filterId, extended, filter, mask )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Sets the specified CAN filter  and mask ID, to ignore CAN messages that match a particular ID pattern. &lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** filterId: The id of the filter. Up to 6 filters are supported on MK1, 15 per channel on MK2. Filter ids start at 0.&lt;br /&gt;
** extended: 0 for Standard (11 bit) Identifier or 1 for Extended (29 bit) Identifier.&lt;br /&gt;
** filter: Pattern value for CAN filter&lt;br /&gt;
** mask: the mask for the CAN filter&lt;br /&gt;
* returns&lt;br /&gt;
** 1 for success, 0 for fail, nil if parameters are incorrect&lt;br /&gt;
&lt;br /&gt;
==OBDII functions==&lt;br /&gt;
===readOBD2( PID )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Reads an OBD2 PID and returns the calculated value. This is a convenience method wrapped around the built-in CAN functions.&lt;br /&gt;
* params&lt;br /&gt;
** The OBD2 PID to read. Supported PIDs (TBD documented)&lt;br /&gt;
* returns&lt;br /&gt;
** The calculated PID value, or nil if the OBD2 PID was invalid or could not be read (e.g. CAN receive message timeout)&lt;br /&gt;
&lt;br /&gt;
===setOBD2Delay( delayMs )===&lt;br /&gt;
Sets an additional delay in-between OBDII PID queries. Normally the system will query PIDs as fast as possible, in a [[RC_OBDII|round robin fashion]].  &lt;br /&gt;
&lt;br /&gt;
If the vehicle&#039;s ECU exhibits problems with the rate of querying, an additional delay can be added between queries to effectively slow down the queries. &lt;br /&gt;
&lt;br /&gt;
* params&lt;br /&gt;
** The additional delay between PID queries, in ms&lt;br /&gt;
* returns&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
==Logger Control Functions==&lt;br /&gt;
&lt;br /&gt;
===onTick()===&lt;br /&gt;
* params:&lt;br /&gt;
** (none)&lt;br /&gt;
* returns:&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
The onTick() function is the main loop where scripting activity takes place. By default it is called by RaceCapture/Pro every 1 second (1Hz). The rate can be adjusted using the setTickRate() function. &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039; - you should only define one onTick() function in your code. If multiple onTick() functions are defined, only the last defined onTick() function will be used.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 function onTick()&lt;br /&gt;
   println(&amp;quot;Hello&amp;quot;) --write something to the log&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
===setTickRate(rate)===&lt;br /&gt;
Sets the rate at which the onTick() function is called&lt;br /&gt;
* params&lt;br /&gt;
** rate: The rate the onTick() function is called, in Hz. Max tick rate is 1000Hz.&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
==SD Logging control==&lt;br /&gt;
The following functions control logging operations to the internal SD card. &lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; Only SD card logging is controlled; External devices or apps connected to the telemetry stream are not affected by these commands.&lt;br /&gt;
&lt;br /&gt;
===isLogging()===&lt;br /&gt;
Indicates if an SD card logging session is in progress&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** 0 if not logging, non zero otherwise.&lt;br /&gt;
&lt;br /&gt;
===startLogging()===&lt;br /&gt;
Begins a logging session to the SD card.  If currently logging, this function has no effect. &lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; If an error occurs during writing, the error indicator on the front panel, if provided, will illuminate. &lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===stopLogging()===&lt;br /&gt;
Stops the current SD card logging session. If not logging, this function has no effect.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===setLed( led, state )===&lt;br /&gt;
Sets the state of a front panel LED&lt;br /&gt;
* params&lt;br /&gt;
** led (1-3)&lt;br /&gt;
** state: (int / &#039;&#039;[as of 2.10.0]&#039;&#039; bool) 1 / true = on, 0 / false = off&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===setBgStream( on/off )===&lt;br /&gt;
Sets the state of background streaming&lt;br /&gt;
* params&lt;br /&gt;
** Boolean: true for on, false for off.&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===getBgStream()===&lt;br /&gt;
Gets the state of background streaming&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** Boolean: True for on, false for off.&lt;br /&gt;
&lt;br /&gt;
==Serial Port Communications==&lt;br /&gt;
&lt;br /&gt;
These function calls allow reading / writing line oriented data from the built in serial ports. &lt;br /&gt;
&lt;br /&gt;
===Port mappings===&lt;br /&gt;
* 0 = USB port&amp;lt;br/&amp;gt;&lt;br /&gt;
* 1 = GPS port&amp;lt;br/&amp;gt;&lt;br /&gt;
* 2 = Internal telemetry port (MK2/3/Apex only)&amp;lt;br/&amp;gt;&lt;br /&gt;
* 3 = Bluetooth port&amp;lt;br/&amp;gt;&lt;br /&gt;
* 4 = Auxiliary / WiFi port&amp;lt;br/&amp;gt; (RaceCapture/Pro MK2)&lt;br /&gt;
* 5 = WiFi port&lt;br /&gt;
* 6 = External Auxiliary port (RaceCapture/Pro MK3 and RaceCapture/Apex only)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039;: We only recommend  using the designated auxiliary port for your hardware model  The other ports have been included for reference; using them may interfere with normal operations of the unit.&lt;br /&gt;
&lt;br /&gt;
===initSer( port, baud, bits, parity, stopBits)===&lt;br /&gt;
Initializes the specified serial port&lt;br /&gt;
&lt;br /&gt;
* params&lt;br /&gt;
** port: The port to initialize. (defaults to Auxiliary port)&lt;br /&gt;
** baud: The baud rate to set (defaults to 115200)&lt;br /&gt;
** bits: Number of bit in the message (8 or 7) (defaults to 8)&lt;br /&gt;
** parity: (1 = Even Parity, 2 = Odd Parity, 0 = No Parity) (defaults to No Parity)&lt;br /&gt;
** stopBits: number of stop bits (1 or 2) (defaults to 1)&lt;br /&gt;
&lt;br /&gt;
* returns&lt;br /&gt;
** true if initialization succeeds&lt;br /&gt;
&lt;br /&gt;
===readCSer( port, [timeout])===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Read a character from the specified serial port&lt;br /&gt;
&lt;br /&gt;
* params&lt;br /&gt;
** port: The port to read. (required)&lt;br /&gt;
** timeout - the read timeout, in ms.&lt;br /&gt;
&lt;br /&gt;
* returns&lt;br /&gt;
** the character read, or nil if the timeout was reached&lt;br /&gt;
&lt;br /&gt;
===readSer( port, [timeout])===&lt;br /&gt;
Read a line of data from the specified serial port. This command blocks until a newline (&#039;\n&#039;) character is received on the port, or a timeout occurs.&lt;br /&gt;
* params&lt;br /&gt;
** port: Serial port 0 - 4&lt;br /&gt;
** timeout - the read timeout, in ms.&lt;br /&gt;
** returns: a line of serial data, or nil if the timeout was reached&lt;br /&gt;
&lt;br /&gt;
===writeCSer( port, data )===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Writes the specified character to the serial port. The call will block until the character is written.&lt;br /&gt;
* params:&lt;br /&gt;
** port - the serial port to write&lt;br /&gt;
** char - the character to write.&lt;br /&gt;
&lt;br /&gt;
* returns:&lt;br /&gt;
(no return values)&lt;br /&gt;
&lt;br /&gt;
===writeSer( port, data )===&lt;br /&gt;
Writes a line of data to the specified serial port, appending a newline at the end. The call will block until all characters are written.&lt;br /&gt;
* params&lt;br /&gt;
** port: Serial port 0 - 4&lt;br /&gt;
** data: the data in string format&lt;br /&gt;
&lt;br /&gt;
* returns:&lt;br /&gt;
(no return values)&lt;br /&gt;
&lt;br /&gt;
==Logger Configuration Functions==&lt;br /&gt;
&lt;br /&gt;
===flashLoggerCfg()===&lt;br /&gt;
Writes the current configuration in RAM to flash memory.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
    &lt;br /&gt;
===setPwmClockFreq( freq )===&lt;br /&gt;
Sets the clock frequency for all PWM channels&lt;br /&gt;
* params&lt;br /&gt;
** freq: The clock frequency &#039;&#039;todo: what units?&#039;&#039;&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===getPwmClockFreq()=== &lt;br /&gt;
Gets the PWM clock frequency controlling all PWM channels&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** the PWM clock frequency &#039;&#039;todo: what units?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===calibrateImuZero()===&lt;br /&gt;
Automatically Calibrates the accelerometer zero position.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
==Virtual Channels==&lt;br /&gt;
&lt;br /&gt;
===addChannel( name, sampleRate, [precision], [min], [max], [units] )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Adds a virtual channel. This virtual channel remains in memory during runtime; it is not persisted in the configuration. Up to 100 virtual channels can be created.&lt;br /&gt;
* params&lt;br /&gt;
** name: The name of the channel, up to 10 characters long. We recommend using an existing System channel name as defined by the app when possible.&lt;br /&gt;
** sampleRate: A supported sample rate (1,10,25,50,100,200Hz)&lt;br /&gt;
** precision: (optional) the numerical precision (number of decimal places) used when logging to SD and telemetry. Defaults to 2&lt;br /&gt;
** min: (optional) The min expected value for this channel. Defaults to 0&lt;br /&gt;
** max: (optional) The max expected value for this channel. Defaults to 1000&lt;br /&gt;
** units: (optional) The units label for this channel. Defaults to empty string / none&lt;br /&gt;
&lt;br /&gt;
* returns&lt;br /&gt;
** the id of the new virtual channel, or NIL if the virtual channel could not be created. Use this id for setting the channel value (see setChannel() )&lt;br /&gt;
&lt;br /&gt;
===getChannel( Channel ID or name )===&lt;br /&gt;
* First available  in v2.9.0 ; retrieving by channel name available in v2.13.0&lt;br /&gt;
* Parameters &lt;br /&gt;
** Channel ID or name : if a number, matches on the channel ID  as provided by the &#039;&#039;&#039;addChannel&#039;&#039;&#039; function. If string, matches on any current channel in the system. &lt;br /&gt;
* Returns&lt;br /&gt;
** (number) The current value of the channel if available, or &#039;&#039;&#039;nil&#039;&#039;&#039; if the value is not available. You should always check if the value is present before using it for other purposes, especially if the script&#039;s tick rate is high relative to the channel&#039;s sample rate.&lt;br /&gt;
&lt;br /&gt;
* Examples: &lt;br /&gt;
&lt;br /&gt;
 --returns the virtual channel assigned to ID 1. Current value of channel is stored in val &lt;br /&gt;
 val = getChannel(1)&lt;br /&gt;
&lt;br /&gt;
 --get the channel by name&lt;br /&gt;
 rpm = getChannel(&amp;quot;RPM&amp;quot;) &lt;br /&gt;
 if rpm ~= nil then&lt;br /&gt;
  println(&amp;quot;rpm channel: &amp;quot; ..rpm)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
===setChannel( channelId, value )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Updates the value of a previously created virtual channel.&lt;br /&gt;
* params&lt;br /&gt;
** channelId: the ID of the channel provided by addChannel()&lt;br /&gt;
** value: the new value to set for the virtual channel&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 id = addChannel(&amp;quot;EGT&amp;quot;, 1)&lt;br /&gt;
 &lt;br /&gt;
 function onTick()&lt;br /&gt;
    temp = getAnalog(0) --read analog channel 0&lt;br /&gt;
    temp = temp * 1000&lt;br /&gt;
    setChannel(id, temp) --sets the virtual channel value&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
==Time Info==&lt;br /&gt;
These methods get you information about dates and time.  This is useful in controlling script behavior or just knowing what time it is.&lt;br /&gt;
&lt;br /&gt;
===getUptime()===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Returns the number of miliseconds since the device last started.  This is always available and is the most consistent way to time things in LUA script on RaceCapture.&lt;br /&gt;
&lt;br /&gt;
* Returns&lt;br /&gt;
** Number of milliseconds since CPU boot.&lt;br /&gt;
&lt;br /&gt;
===getDateTime()===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Returns date and time info to the best of the systems ability, in UTC.  Only available after GPS lock has been established.  Will return epoch time (Jan 1, 1970 00:00:000) if time is not available.&lt;br /&gt;
&lt;br /&gt;
* Returns: A list of date and time information in the following order:&lt;br /&gt;
** Year&lt;br /&gt;
** Month&lt;br /&gt;
** Day&lt;br /&gt;
** Hour&lt;br /&gt;
** Minute&lt;br /&gt;
** Second&lt;br /&gt;
** Millisecond&lt;br /&gt;
&lt;br /&gt;
==Dashboard Control==&lt;br /&gt;
===txButton()===&lt;br /&gt;
Simulates button press events for dashboard navigation and control.  RaceCapture dashboard must be connected for function to have effect. &lt;br /&gt;
* params&lt;br /&gt;
**  button_id:  ID of button to transmit.  0 = left button;1 = right button;2 = ack/yes;3 = no&lt;br /&gt;
** state: State of button: 1 = pressed; 0 = not pressed&lt;br /&gt;
* returns&lt;br /&gt;
** (nothing)&lt;br /&gt;
&lt;br /&gt;
==ShiftX2/3 control==&lt;br /&gt;
The following functions provide access to the [[ShiftX2]] or [[ShiftX3]] RGB sequential shift light.  &#039;&#039;Available in firmware 2.15.0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===sxSetConfig()===&lt;br /&gt;
Configures the connected ShiftX device. This must be called prior to any other configuration function calls.  All parameters are optional; call with no parameters to use the default settings:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sxSetConfig()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* params&lt;br /&gt;
** orientation: 0 (normal, 7-segment display below bar graph); 1 (inverted, 7-segment display above bar graph). Defaut value: 0&lt;br /&gt;
** brightness: 0 (automatic brightness control with ambient light sensor; 1-100: brightness percentage. Default value: 0&lt;br /&gt;
** CAN bus: 0 (connected to CAN1); 1 (connected to CAN2). Default value: 1&lt;br /&gt;
** CAN base address: base CAN address to use.  Default value: 931328)&lt;br /&gt;
** Auto brightness scaling: Amplification value to tune ambient light sensor. 0-255 value; Default value: 51&lt;br /&gt;
** Enable / Disable button events: true (Enable button event broadcast to app); false (Disable button event broadcast to app)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxCfgLinearGraph()===&lt;br /&gt;
Configures the the style and overall range for the linear graph. &lt;br /&gt;
* params&lt;br /&gt;
** Rendering Style: 0 (left-&amp;gt;right); 1 (center); 2 (right-&amp;gt;left)&lt;br /&gt;
** Linear Style: 0 (Smooth / interpolated); 1 (stepped)&lt;br /&gt;
** Low Range Threshold: The overall low range for the linear graph&lt;br /&gt;
** High Range Threshold: The overall high range for the linear graph (ignored if linear style = stepped)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetLinearThresh()===&lt;br /&gt;
Configure a threshold for the linear graph. Each threshold is identified by an ID, and thresholds are processed from low to high IDs. 5 thresholds can be defined. &lt;br /&gt;
* params&lt;br /&gt;
** Threshold Id: Id for threshold to set. (0-4). Lower IDs are evaluated first. &lt;br /&gt;
** Segment Length: 0 -&amp;gt; number of LEDs on linear graph. (Ignored if linear style = smooth)&lt;br /&gt;
** Threshold Value: Value where this threshold is activated&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxUpdateLinearGraph()===&lt;br /&gt;
Update the linear graph with the current sensor value. ShiftX will apply the previously configured thresholds to set bar graph length, color and flash. &lt;br /&gt;
* params&lt;br /&gt;
** Value: current value representing the linear graph&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
===sxSetAlert()=== &lt;br /&gt;
Direct set an alert indicator.   For ShiftX3, ID0=Alert LED on right side; ID1=Alert LED on left side.&lt;br /&gt;
* params&lt;br /&gt;
** Alert ID: ID of alert (0 -&amp;gt; # of alert indicators)&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetAlertThresh()===&lt;br /&gt;
Configures an alert threshold. Up to 5 thresholds can be configured per alert indicator. Thresholds are evaluated by ID, from low to high.&lt;br /&gt;
* params&lt;br /&gt;
** Alert ID: Id of Alert (0 -&amp;gt; # of alert indicators)&lt;br /&gt;
** Threshold ID: Id for threshold to set. (0-4). Lower IDs are evaluated first.&lt;br /&gt;
** Threshold Value: Value where this threshold is activated&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxUpdateAlert()===&lt;br /&gt;
Updates the current value for the specified Alert. ShiftX will apply the previously configured thresholds to set color and flash. &lt;br /&gt;
* params&lt;br /&gt;
** Alert ID: Id of Alert (0 -&amp;gt; # of alert indicators)&lt;br /&gt;
** Value: current value representing the alert&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetDisplay()===&lt;br /&gt;
Directly sets the value of the 7 segment display. &lt;br /&gt;
* params&lt;br /&gt;
** Digit index (must be 0)&lt;br /&gt;
** Charater: 0-9. Can set ASCII value by offsetting the value by 48 (e.g. ASCII - 48)&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetLed()===&lt;br /&gt;
Directly set any available LED on ShiftX&lt;br /&gt;
* params&lt;br /&gt;
** LED Index: 0 -&amp;gt; # of LEDs on device&lt;br /&gt;
** Number of LEDs to set: 0 -&amp;gt; # of LEDs on device (0  = set all remaining)&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxRxButton()===&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** nil if no button presses are available; otherwise:&lt;br /&gt;
** button_id (ID of button. left button = 0, right button = 1)&lt;br /&gt;
** state: (0 = not pressed; 1 = pressed)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
local id, state = sxRxButton()&lt;br /&gt;
if id ~= nil then println(&#039;button &#039; ..id ..&#039; state &#039; ..state) end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Helper Functions==&lt;br /&gt;
===calcGear()===&lt;br /&gt;
A convenience function to calculate the current gear of the vehicle.  &#039;&#039;Available in firmware 2.15.0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Variation 1: Use built in GPS speed channel and RPM channel named &amp;quot;RPM&amp;quot;&lt;br /&gt;
* params&lt;br /&gt;
** Tire Diameter: Tire diameter, in cm. &lt;br /&gt;
** Final Drive Ratio: The ratio of the final drive&lt;br /&gt;
** Gear 1 Ratio: Ratio of 1st gear&lt;br /&gt;
** Gear 2 Ratio: Ratio of 2nd gear (optional)&lt;br /&gt;
** Gear 3 Ratio: Ratio of 3rd gear (optional)&lt;br /&gt;
** Gear 4 Ratio: Ratio of 4th gear (optional)&lt;br /&gt;
** Gear 5 Ratio: Ratio of 5th gear (optional)&lt;br /&gt;
** Gear 6 Ratio: Ratio of 6th gear (optional)&lt;br /&gt;
* returns&lt;br /&gt;
** detected gear (1-6) or nil if no gear was detected&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
local gear = calcGear(62.7, 3.45, 4.23, 2.52, 1.66, 1.22, 1.0, 0.8)&lt;br /&gt;
if gear ~= nil then println(&#039;gear: &#039; ..gear) end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Variation 2: Specify Speed and RPM channel&lt;br /&gt;
* params&lt;br /&gt;
** Speed Channel name&lt;br /&gt;
** RPM Channel name&lt;br /&gt;
** Tire Diameter: Tire diameter, in cm. &lt;br /&gt;
** Final Drive Ratio: The ratio of the final drive&lt;br /&gt;
** Gear 1 Ratio: Ratio of 1st gear&lt;br /&gt;
** Gear 2 Ratio: Ratio of 2nd gear (optional)&lt;br /&gt;
** Gear 3 Ratio: Ratio of 3rd gear (optional)&lt;br /&gt;
** Gear 4 Ratio: Ratio of 4th gear (optional)&lt;br /&gt;
** Gear 5 Ratio: Ratio of 5th gear (optional)&lt;br /&gt;
** Gear 6 Ratio: Ratio of 6th gear (optional)&lt;br /&gt;
* returns&lt;br /&gt;
** detected gear (1-6) or nil if no gear was detected&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
local gear = calcGear(&#039;Speed&#039;, &#039;RPM&#039;, 62.7, 3.45, 4.23, 2.52, 1.66, 1.22, 1.0, 0.8)&lt;br /&gt;
if gear ~= nil then println(&#039;gear: &#039; ..gear) end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ddimensia</name></author>
	</entry>
	<entry>
		<id>https://wiki.autosportlabs.com/index.php?title=RaceCapturePro_Lua_Scripting&amp;diff=9931</id>
		<title>RaceCapturePro Lua Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/index.php?title=RaceCapturePro_Lua_Scripting&amp;diff=9931"/>
		<updated>2024-01-01T21:22:26Z</updated>

		<summary type="html">&lt;p&gt;Ddimensia: Updated button_id values to include yes/no.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=RaceCapture/Pro Scripting Guide=&lt;br /&gt;
==Example Scripts and How-Tos==&lt;br /&gt;
A large collection of example scripts can be found in our &#039;&#039;&#039;[[RaceCapturePro Lua Scripting Examples|Lua Scripting Examples]]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The [https://www.lua.org/manual/5.1/ Lua Reference Manual] can be found on [https://www.lua.org/ Lua.org]&lt;br /&gt;
&lt;br /&gt;
You can use [http://luaedit.sourceforge.net/ LuaEdit] to help you edit and debug your Lua code.&lt;br /&gt;
&lt;br /&gt;
==Lua Script Basics==&lt;br /&gt;
&lt;br /&gt;
===Conventions===&lt;br /&gt;
* All inputs and outputs are numbered starting at 0 (getGpio(0), setChannel(0), etc)&lt;br /&gt;
* All channel values must be numbers&lt;br /&gt;
* All virtual channel names must have no spaces (to be fixed in future revisions)&lt;br /&gt;
&lt;br /&gt;
====Writing your script====&lt;br /&gt;
&lt;br /&gt;
=====onTick() function=====&lt;br /&gt;
Your Lua script is centered around the onTick() function. RaceCapture/Pro will periodically call this function, and here you can define your custom tasks and logic. &lt;br /&gt;
&lt;br /&gt;
Example: this script will periodically write a message to the log:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
  println(&amp;quot;hello from RaceCapture/Pro&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039;: There can only be one onTick() handler; if multiple are defined your script will not work properly.&lt;br /&gt;
&lt;br /&gt;
=====Viewing the output log=====&lt;br /&gt;
You can observe the loading of new script and monitor and debug the behavior of your script by using the print() / println() functions. In order to see the log output, enable the &amp;quot;Poll Log&amp;quot; checkbox in the scripting window:&lt;br /&gt;
&lt;br /&gt;
[[image:Hello_RaceCapturePro_script.png|800px]]&lt;br /&gt;
&lt;br /&gt;
=====Controlling the onTick() rate=====&lt;br /&gt;
You can control how fast your script is executed using the setTickRate() function.  The tick Rate is specified in Hz, and the default rate is 1Hz, maximum of 1000Hz. &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; actual tick rates may be slower based on the amount of processing time in your onTick() handler. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
count = 0&lt;br /&gt;
setTickRate(10)&lt;br /&gt;
&lt;br /&gt;
function onTick()&lt;br /&gt;
  count = count + 1&lt;br /&gt;
  println(&amp;quot;Tick: &amp;quot; ..count)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[image:RaceCapture_tick_count.png|800px]]&lt;br /&gt;
&lt;br /&gt;
=====Reading and controlling inputs and outputs=====&lt;br /&gt;
&lt;br /&gt;
The Lua scripting enables endless combinations of custom behaviors by reading sensor values, controlling output lines, broadcasting CAN messages and writing data to the Auxiliary serial port. &lt;br /&gt;
&lt;br /&gt;
Example: Reading a sensor value and activating an output based on a threshold. &lt;br /&gt;
&lt;br /&gt;
Given:&lt;br /&gt;
* A calibrated temperature sensor is connected to the first analog input (0);&lt;br /&gt;
* The first GPIO is configured for output mode&lt;br /&gt;
&lt;br /&gt;
This script will activate the output upon crossing the temperature threshold of 212. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
  temperature = getAnalog(0)&lt;br /&gt;
  if temperature &amp;gt; 212 then&lt;br /&gt;
    setGpio(0, 1)&lt;br /&gt;
  else&lt;br /&gt;
    setGpio(0, 0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====Combining multiple functions=====&lt;br /&gt;
When combining multiple functions into one script, it&#039;s recommended to break them into multiple functions and reference them from the main onTick() function.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function checkTemps()&lt;br /&gt;
&lt;br /&gt;
[ temperature checking logic goes here ]&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function checkAutoLogging()&lt;br /&gt;
&lt;br /&gt;
[ automatic logging logic goes here ]&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onTick()&lt;br /&gt;
  checkTemps()&lt;br /&gt;
  checkAutoLogging()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
===Debugging your script===&lt;br /&gt;
If you&#039;re not sure why your script is misbehaving, you can use the println() function to output messages in the log and observe how your script is behaving.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
  temperature = getAnalog(0)&lt;br /&gt;
  println(&amp;quot;current temp: &amp;quot; ..temperature)&lt;br /&gt;
  if temperature &amp;gt; 212 then&lt;br /&gt;
    println(&amp;quot;over temp!&amp;quot;)&lt;br /&gt;
    setGpio(0, 1)&lt;br /&gt;
  else&lt;br /&gt;
    println(&amp;quot;under temp&amp;quot;)&lt;br /&gt;
    setGpio(0, 0)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Out of memory issues===&lt;br /&gt;
If you are seeing out of memory issues, try the following:&lt;br /&gt;
&lt;br /&gt;
====Mark variables in your script as local====&lt;br /&gt;
&lt;br /&gt;
Lua makes variables global by default, which is typically opposite of other programming languages.  Since global variables consume more memory, try making variables declared in your function local:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function addSomeNumbers()&lt;br /&gt;
  local var1 = 3&lt;br /&gt;
  local  var2 = 5&lt;br /&gt;
  return var1 + var2&lt;br /&gt;
end&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Reduce extra comments,  large string variable declaration and other bloat====&lt;br /&gt;
* Remove comments, shorten the size of any text strings you define - these all consume memory.&lt;br /&gt;
&lt;br /&gt;
====Simplify your script====&lt;br /&gt;
* Reduce the number of variables at the top, and inline their usage in the script.  This will help reduce the amount of global memory uses.&lt;br /&gt;
* Evaluate the functions you define. Sometimes it makes sense to combine your code into fewer functions, if it turns out you only call that function once.  Other times, you may need to break out a function to save space, if you need that function repeatedly.&lt;br /&gt;
&lt;br /&gt;
====Call the garbage collector periodically====&lt;br /&gt;
If your script is very close the limits of memory, regularly calling the garbage collector may help.   Calling collectgarbage() in the onTick() is recommended:&amp;lt;pre&amp;gt;&lt;br /&gt;
function onTick()&lt;br /&gt;
 collectgarbage()&lt;br /&gt;
-- other code --&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Try a Lua minimizer====&lt;br /&gt;
Minimizing/Minifying your script will compact your script, at the expense of making it harder to read.  You can try an [https://mothereff.in/lua-minifier online minifier] to see if that makes a difference. &lt;br /&gt;
&lt;br /&gt;
* Since it makes your script harder to maintain, we recommend this as a last resort.&lt;br /&gt;
&lt;br /&gt;
=Lua Reference=&lt;br /&gt;
RaceCapture/Pro uses the standard, lightweight Lua scripting language used as an extension / customization language for many software applications and especially gaming. &lt;br /&gt;
&lt;br /&gt;
* See [https://www.lua.org/ lua.org] for additional information on how to use the Lua language&lt;br /&gt;
=More examples=&lt;br /&gt;
You can see more examples in our [[RaceCapturePro Lua Scripting Examples|Lua Scripting Examples]] section.&lt;br /&gt;
&lt;br /&gt;
=API Reference=&lt;br /&gt;
&lt;br /&gt;
==General Input / Output (GPIO) Functions==&lt;br /&gt;
&lt;br /&gt;
===getGpio( channel )===&lt;br /&gt;
Retrieves the state of the specified GPIO channel&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: integer 0 - 2&lt;br /&gt;
*returns:&lt;br /&gt;
** state: 1 = channel is high, 0 = channel is low&lt;br /&gt;
&lt;br /&gt;
* When the channel is configured for input mode, a voltage high input (&amp;gt; 2 volts) will read as 1; a voltage low will read as 0. &lt;br /&gt;
* When the channel is configured as output, the channel reads 1 when the channel is activated (output transistor is connected to ground) &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039;: RaceCapture/Pro MK1 has internal pull-up resistors to 5V.&lt;br /&gt;
&lt;br /&gt;
===setGpio ( channel, state )===&lt;br /&gt;
Sets the state of the GPIO channel when the channel is configured for output mode. &lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: integer 0 - 2&lt;br /&gt;
** state: (int / &#039;&#039;(since 2.10.0)&#039;&#039; bool) 1 / true = output active; 0 / false = output inactive&lt;br /&gt;
*returns:&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
When the state specified is 1, the output is active (transistor is connected to ground). When state is 0, transistor is disconnected, and pullup resistor is active.&lt;br /&gt;
&lt;br /&gt;
When configured for input mode this function has no effect.&lt;br /&gt;
&lt;br /&gt;
===getButton()===&lt;br /&gt;
Gets the state of the front panel pushbutton.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** none&lt;br /&gt;
*returns&lt;br /&gt;
** state: true = pushbutton is depressed; false = pushbutton is not depressed&lt;br /&gt;
&lt;br /&gt;
==PWM / Analog Output functions==&lt;br /&gt;
&#039;&#039;&#039;PWM / Analog outputs only apply to RaceCapture/Pro MK1 and MK2&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===setPwmDutyCycle( channel, dutyCyclePct )===&lt;br /&gt;
Sets the duty cycle of the specified PWM / Analog output channel to the specified duty cycle percentage&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: PWM / Analog output channel 0 - 3&lt;br /&gt;
** dutyCyclePct: Percentage value of the duty cycle as a counting number 0 - 100&lt;br /&gt;
*returns&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
===setPwmClockFreq( frequency )===&lt;br /&gt;
Sets the clock frequency of the PWM outputs&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** frequency: the frequency of the PWM clock, in Hz. Supported range is 320-40000 Hz&lt;br /&gt;
* returns&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
===setAnalogOut( channel, voltage )===&lt;br /&gt;
Sets the output voltage of the specified PWM / Analog output channel to the specified period. A convenience function equivalent to setPwmDutyCycle that translates voltage to PWM percentage.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: PWM / Analog output channel 0 - 3&lt;br /&gt;
** voltage: the specified output voltage ( 0 - 5v)&lt;br /&gt;
** returns&lt;br /&gt;
* none&lt;br /&gt;
&lt;br /&gt;
==Timer / RPM Sensor Functions==&lt;br /&gt;
&lt;br /&gt;
===getTimerRpm(channel)===&lt;br /&gt;
Returns the current RPM of the specified timer input channel. Note, the timer channel configuration must be set to RPM mode.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns: RPM value&lt;br /&gt;
&lt;br /&gt;
===getTimerPeriodMs(channel)===&lt;br /&gt;
Returns the current duration of the full cycle pulse of the specified timer input channel, in milliseconds. Note the timer channel configuration must be set to Duration mode.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel 0 - 3. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns:  millisecond value&lt;br /&gt;
&lt;br /&gt;
===getTimerFreq(channel)===&lt;br /&gt;
Returns the current frequency present on the specified timer input channel, in Hz. Note the timer channel configuration must be set to Frequency Mode.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns:  Frequency in Hz&lt;br /&gt;
&lt;br /&gt;
===getTimerRaw(channel)===&lt;br /&gt;
Returns the current raw timer value as measured on the specified timer input channel.&lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Timer channel 0 - 3. Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
** returns: Raw timer value between 0 - 65535&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===resetTimerCount===&lt;br /&gt;
===getTimerCount===&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Analog Sensor Functions==&lt;br /&gt;
    &lt;br /&gt;
===getAnalog(channel)===&lt;br /&gt;
Reads the scaled analog value for the specified analog input channel. &lt;br /&gt;
&lt;br /&gt;
*params&lt;br /&gt;
** channel: Analog input channel.  Zero based, so first channel is 0, 2nd channel is 1, and so on. &lt;br /&gt;
*** Note: the last Analog input is connected to battery voltage:&lt;br /&gt;
**** Channel 7 on RaceCapture/Pro MK1 and MK2&lt;br /&gt;
****Channel 8 on RaceCapture/Pro MK3 and RaceCapture Apex&lt;br /&gt;
****Channel 0 on RaceCapture/Track MK1 / MK2&lt;br /&gt;
** returns: Scaled / calculated value for the specified analog channel as defined in the channel scaling configuration&lt;br /&gt;
&lt;br /&gt;
==Accelerometer / Yaw Sensor Functions==&lt;br /&gt;
&lt;br /&gt;
===getImu(channel)===&lt;br /&gt;
Reads the specified IMU channel&lt;br /&gt;
* params&lt;br /&gt;
** channel (0  = X, 1 = Y,  2=Z, 3= Yaw, 4= Pitch, 5 = Roll)&lt;br /&gt;
* returns&lt;br /&gt;
** The value scaled to G force, or degrees/sec depending on the channel selected&lt;br /&gt;
&lt;br /&gt;
===getImuRaw(channel)===&lt;br /&gt;
Reads the raw value of the specified accelerometer or yaw channel&lt;br /&gt;
* params&lt;br /&gt;
** channel (0  = X, 1 = Y,  2=Z, 3= Yaw, 4= Pitch, 5 = Roll)&lt;br /&gt;
* returns&lt;br /&gt;
** The raw accelerometer value&lt;br /&gt;
&lt;br /&gt;
==GPS Sensor Functions==&lt;br /&gt;
&lt;br /&gt;
===getGpsPos()===&lt;br /&gt;
Reads the current position as measured by the attached GPS module &#039;&#039;coming in firmware 2.0&#039;&#039;&lt;br /&gt;
* params&lt;br /&gt;
** none&lt;br /&gt;
* returns&lt;br /&gt;
** Latitude: latitude in decimal degrees&lt;br /&gt;
** Longitude: longitude in decimal degress&lt;br /&gt;
&lt;br /&gt;
===getGpsSpeed()===&lt;br /&gt;
Provides the current speed as measured by the attached GPS module&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current speed in MPH&lt;br /&gt;
&lt;br /&gt;
===getGpsQuality()===&lt;br /&gt;
Provides the current GPS quality indicator as indicated by the attached GPS module&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current GPS quality indicator&lt;br /&gt;
** 0: No fix; 1: Fixed; 2: SPS Fix; 3: Differential Fix&lt;br /&gt;
&lt;br /&gt;
===getGpsSats()===&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The number of GPS satellites currently used in the fix&lt;br /&gt;
&lt;br /&gt;
===getGpsTime()===&lt;br /&gt;
Provides the current GPS time as indicated by the attached GPS module (in NMEA format) &#039;&#039;todo: document this&#039;&#039;&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current GPS time value&lt;br /&gt;
&lt;br /&gt;
===getGpsDist()===&lt;br /&gt;
Provides the current GPS calculated distance from the beginning of the logging session, or from the start finish line, if configured.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The distance, in Miles&lt;br /&gt;
&lt;br /&gt;
===getGpsAltitude()===&lt;br /&gt;
Provides the current GPS calculated altitude from sea level in feet.  The method will return 0 if there is no GPS lock.&lt;br /&gt;
* Added: v2.9.0&lt;br /&gt;
* Parameters: &#039;&#039;None&#039;&#039;&lt;br /&gt;
* Returns: &amp;lt;altitude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===getGpsSec()===&lt;br /&gt;
Provides the number of seconds since midnight, as measured by the GPS module. &#039;&#039;todo: how does this relate to timezone? GMT or local?&#039;&#039;&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** number of seconds since midnight, as measured by the attached GPS module&lt;br /&gt;
&lt;br /&gt;
==Lap Statistics==&lt;br /&gt;
&lt;br /&gt;
===getLapCount()===&lt;br /&gt;
Provides the current Lap Count as determined by the start/finish line configuration and measured by the attached GPS module.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The number of laps detected since the logging session started&lt;br /&gt;
&lt;br /&gt;
===getLapTime()===&lt;br /&gt;
Provides the last lap time as determined by the start/finish line configuration and measured by the attached GPS module.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The last measured lap time in decimal minutes / seconds&lt;br /&gt;
&lt;br /&gt;
===getPredTime()===&lt;br /&gt;
&#039;&#039;as of 2.12.0 firmware&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Provides the current Predicted Lap time time as determined by the start/finish line configuration and measured by the attached GPS module. A training lap is required before the predicted time is valid.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** The current predicted time in decimal minutes / seconds&lt;br /&gt;
&lt;br /&gt;
===getAtStartFinish()===&lt;br /&gt;
Indicates if within the start finish line target as determined by the start/finish line configuration and measured by the attached GPS module.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** true if currently within the start/finish line target, false if outside&lt;br /&gt;
&lt;br /&gt;
===resetLapStats()===&lt;br /&gt;
&#039;&#039;since 2.16.0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Resets Lap Statistics, including lap count, lap time, predictive time, and session time. &lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
==Time Functions==&lt;br /&gt;
===getTickCount()===&lt;br /&gt;
Returns the number of milliseconds since power-up. &lt;br /&gt;
* params&lt;br /&gt;
None&lt;br /&gt;
* returns&lt;br /&gt;
** The number of milliseconds since power-up&lt;br /&gt;
&lt;br /&gt;
==CAN Bus functions==  &lt;br /&gt;
&lt;br /&gt;
===initCAN(channel, baud )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Initializes the CAN bus module. Normally this is done when RaceCapture/Pro powers on; use this function if you need to change the CAN baud rate on the fly.&lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** baud rate: Supported baud rates: 100000, 125000, 250000, 500000, 1000000&lt;br /&gt;
** termination: 1 to enable termination, 0 to disable. Defaults to 1 (enabled) &#039;&#039;Only available on RaceCapture/Pro MK3 and RaceCapture/Apex. On other platforms this setting has no effect&#039;&#039;. &lt;br /&gt;
* returns&lt;br /&gt;
** 1 if successful, 0 if initialization fails, nil if parameters are incorrect&lt;br /&gt;
&lt;br /&gt;
===txCAN(channel, id, isExtended, data, [timeout] )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Transmit a CAN message.&lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** identifier: The Identifier value of the message, either in standard (11 bit) or extended (29 bit) format.&lt;br /&gt;
** isExtended: 0 for Standard (11 bit) Identifier or 1 for Extended (29 bit) Identifier.&lt;br /&gt;
** data: CAN message payload; array up to 8 elements long.&lt;br /&gt;
** timeout: (optional) specify a timeout for sending this message. if the transmit queue is full, will block for the specified milliseconds. Defaults to 100ms&lt;br /&gt;
* returns&lt;br /&gt;
** 1 if successful, 0 if failed, nil if parameters are incorrect&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 channel = 0&lt;br /&gt;
 id = 1234&lt;br /&gt;
 ext = 0&lt;br /&gt;
 data = {11,22,33}&lt;br /&gt;
 res = txCAN(channel, id, ext, data)&lt;br /&gt;
&lt;br /&gt;
===rxCAN(channel, [timeout] )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Receive a CAN message, if available.&lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** timeout (optional). read timeout in milliseconds. defaults to 100ms.  For non-blocking functionality specify a timeout of 0.&lt;br /&gt;
* returns&lt;br /&gt;
** identifier: The Identifier value of the message, either in standard (11 bit) or extended (29 bit) format.&lt;br /&gt;
** isExtended: 0 for Standard (11 bit) Identifier or 1 for Extended (29 bit) Identifier.&lt;br /&gt;
** Data: CAN message payload; array up to 8 elements long.&lt;br /&gt;
&lt;br /&gt;
If no CAN message was received, the function returns nil&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 id, ext, data = rxCAN(0, 100) --100ms timeout&lt;br /&gt;
 if id ~= nil then&lt;br /&gt;
   println(&amp;quot;CAN rx: &amp;quot; ..id ..&amp;quot; &amp;quot; ..data[1]) --print ID and first element of received message&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
===setCANfilter(channel, filterId, extended, filter, mask )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Sets the specified CAN filter  and mask ID, to ignore CAN messages that match a particular ID pattern. &lt;br /&gt;
* params&lt;br /&gt;
** channel: The CAN channel. 0 for the first channel, 1 for the 2nd, if supported on the hardware&lt;br /&gt;
** filterId: The id of the filter. Up to 6 filters are supported on MK1, 15 per channel on MK2. Filter ids start at 0.&lt;br /&gt;
** extended: 0 for Standard (11 bit) Identifier or 1 for Extended (29 bit) Identifier.&lt;br /&gt;
** filter: Pattern value for CAN filter&lt;br /&gt;
** mask: the mask for the CAN filter&lt;br /&gt;
* returns&lt;br /&gt;
** 1 for success, 0 for fail, nil if parameters are incorrect&lt;br /&gt;
&lt;br /&gt;
==OBDII functions==&lt;br /&gt;
===readOBD2( PID )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Reads an OBD2 PID and returns the calculated value. This is a convenience method wrapped around the built-in CAN functions.&lt;br /&gt;
* params&lt;br /&gt;
** The OBD2 PID to read. Supported PIDs (TBD documented)&lt;br /&gt;
* returns&lt;br /&gt;
** The calculated PID value, or nil if the OBD2 PID was invalid or could not be read (e.g. CAN receive message timeout)&lt;br /&gt;
&lt;br /&gt;
===setOBD2Delay( delayMs )===&lt;br /&gt;
Sets an additional delay in-between OBDII PID queries. Normally the system will query PIDs as fast as possible, in a [[RC_OBDII|round robin fashion]].  &lt;br /&gt;
&lt;br /&gt;
If the vehicle&#039;s ECU exhibits problems with the rate of querying, an additional delay can be added between queries to effectively slow down the queries. &lt;br /&gt;
&lt;br /&gt;
* params&lt;br /&gt;
** The additional delay between PID queries, in ms&lt;br /&gt;
* returns&lt;br /&gt;
** none&lt;br /&gt;
&lt;br /&gt;
==Logger Control Functions==&lt;br /&gt;
&lt;br /&gt;
===onTick()===&lt;br /&gt;
* params:&lt;br /&gt;
** (none)&lt;br /&gt;
* returns:&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
The onTick() function is the main loop where scripting activity takes place. By default it is called by RaceCapture/Pro every 1 second (1Hz). The rate can be adjusted using the setTickRate() function. &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039; - you should only define one onTick() function in your code. If multiple onTick() functions are defined, only the last defined onTick() function will be used.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 function onTick()&lt;br /&gt;
   println(&amp;quot;Hello&amp;quot;) --write something to the log&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
===setTickRate(rate)===&lt;br /&gt;
Sets the rate at which the onTick() function is called&lt;br /&gt;
* params&lt;br /&gt;
** rate: The rate the onTick() function is called, in Hz. Max tick rate is 1000Hz.&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
==SD Logging control==&lt;br /&gt;
The following functions control logging operations to the internal SD card. &lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; Only SD card logging is controlled; External devices or apps connected to the telemetry stream are not affected by these commands.&lt;br /&gt;
&lt;br /&gt;
===isLogging()===&lt;br /&gt;
Indicates if an SD card logging session is in progress&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** 0 if not logging, non zero otherwise.&lt;br /&gt;
&lt;br /&gt;
===startLogging()===&lt;br /&gt;
Begins a logging session to the SD card.  If currently logging, this function has no effect. &lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; If an error occurs during writing, the error indicator on the front panel, if provided, will illuminate. &lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===stopLogging()===&lt;br /&gt;
Stops the current SD card logging session. If not logging, this function has no effect.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===setLed( led, state )===&lt;br /&gt;
Sets the state of a front panel LED&lt;br /&gt;
* params&lt;br /&gt;
** led (1-3)&lt;br /&gt;
** state: (int / &#039;&#039;[as of 2.10.0]&#039;&#039; bool) 1 / true = on, 0 / false = off&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===setBgStream( on/off )===&lt;br /&gt;
Sets the state of background streaming&lt;br /&gt;
* params&lt;br /&gt;
** Boolean: true for on, false for off.&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===getBgStream()===&lt;br /&gt;
Gets the state of background streaming&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** Boolean: True for on, false for off.&lt;br /&gt;
&lt;br /&gt;
==Serial Port Communications==&lt;br /&gt;
&lt;br /&gt;
These function calls allow reading / writing line oriented data from the built in serial ports. &lt;br /&gt;
&lt;br /&gt;
===Port mappings===&lt;br /&gt;
* 0 = USB port&amp;lt;br/&amp;gt;&lt;br /&gt;
* 1 = GPS port&amp;lt;br/&amp;gt;&lt;br /&gt;
* 2 = Internal telemetry port (MK2/3/Apex only)&amp;lt;br/&amp;gt;&lt;br /&gt;
* 3 = Bluetooth port&amp;lt;br/&amp;gt;&lt;br /&gt;
* 4 = Auxiliary / WiFi port&amp;lt;br/&amp;gt; (RaceCapture/Pro MK2)&lt;br /&gt;
* 5 = WiFi port&lt;br /&gt;
* 6 = External Auxiliary port (RaceCapture/Pro MK3 and RaceCapture/Apex only)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note&#039;&#039;&#039;: We only recommend  using the designated auxiliary port for your hardware model  The other ports have been included for reference; using them may interfere with normal operations of the unit.&lt;br /&gt;
&lt;br /&gt;
===initSer( port, baud, bits, parity, stopBits)===&lt;br /&gt;
Initializes the specified serial port&lt;br /&gt;
&lt;br /&gt;
* params&lt;br /&gt;
** port: The port to initialize. (defaults to Auxiliary port)&lt;br /&gt;
** baud: The baud rate to set (defaults to 115200)&lt;br /&gt;
** bits: Number of bit in the message (8 or 7) (defaults to 8)&lt;br /&gt;
** parity: (1 = Even Parity, 2 = Odd Parity, 0 = No Parity) (defaults to No Parity)&lt;br /&gt;
** stopBits: number of stop bits (1 or 2) (defaults to 1)&lt;br /&gt;
&lt;br /&gt;
* returns&lt;br /&gt;
** true if initialization succeeds&lt;br /&gt;
&lt;br /&gt;
===readCSer( port, [timeout])===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Read a character from the specified serial port&lt;br /&gt;
&lt;br /&gt;
* params&lt;br /&gt;
** port: The port to read. (required)&lt;br /&gt;
** timeout - the read timeout, in ms.&lt;br /&gt;
&lt;br /&gt;
* returns&lt;br /&gt;
** the character read, or nil if the timeout was reached&lt;br /&gt;
&lt;br /&gt;
===readSer( port, [timeout])===&lt;br /&gt;
Read a line of data from the specified serial port. This command blocks until a newline (&#039;\n&#039;) character is received on the port, or a timeout occurs.&lt;br /&gt;
* params&lt;br /&gt;
** port: Serial port 0 - 4&lt;br /&gt;
** timeout - the read timeout, in ms.&lt;br /&gt;
** returns: a line of serial data, or nil if the timeout was reached&lt;br /&gt;
&lt;br /&gt;
===writeCSer( port, data )===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Writes the specified character to the serial port. The call will block until the character is written.&lt;br /&gt;
* params:&lt;br /&gt;
** port - the serial port to write&lt;br /&gt;
** char - the character to write.&lt;br /&gt;
&lt;br /&gt;
* returns:&lt;br /&gt;
(no return values)&lt;br /&gt;
&lt;br /&gt;
===writeSer( port, data )===&lt;br /&gt;
Writes a line of data to the specified serial port, appending a newline at the end. The call will block until all characters are written.&lt;br /&gt;
* params&lt;br /&gt;
** port: Serial port 0 - 4&lt;br /&gt;
** data: the data in string format&lt;br /&gt;
&lt;br /&gt;
* returns:&lt;br /&gt;
(no return values)&lt;br /&gt;
&lt;br /&gt;
==Logger Configuration Functions==&lt;br /&gt;
&lt;br /&gt;
===flashLoggerCfg()===&lt;br /&gt;
Writes the current configuration in RAM to flash memory.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
    &lt;br /&gt;
===setPwmClockFreq( freq )===&lt;br /&gt;
Sets the clock frequency for all PWM channels&lt;br /&gt;
* params&lt;br /&gt;
** freq: The clock frequency &#039;&#039;todo: what units?&#039;&#039;&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
===getPwmClockFreq()=== &lt;br /&gt;
Gets the PWM clock frequency controlling all PWM channels&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** the PWM clock frequency &#039;&#039;todo: what units?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===calibrateImuZero()===&lt;br /&gt;
Automatically Calibrates the accelerometer zero position.&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
&lt;br /&gt;
==Virtual Channels==&lt;br /&gt;
&lt;br /&gt;
===addChannel( name, sampleRate, [precision], [min], [max], [units] )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Adds a virtual channel. This virtual channel remains in memory during runtime; it is not persisted in the configuration. Up to 100 virtual channels can be created.&lt;br /&gt;
* params&lt;br /&gt;
** name: The name of the channel, up to 10 characters long. We recommend using an existing System channel name as defined by the app when possible.&lt;br /&gt;
** sampleRate: A supported sample rate (1,10,25,50,100,200Hz)&lt;br /&gt;
** precision: (optional) the numerical precision (number of decimal places) used when logging to SD and telemetry. Defaults to 2&lt;br /&gt;
** min: (optional) The min expected value for this channel. Defaults to 0&lt;br /&gt;
** max: (optional) The max expected value for this channel. Defaults to 1000&lt;br /&gt;
** units: (optional) The units label for this channel. Defaults to empty string / none&lt;br /&gt;
&lt;br /&gt;
* returns&lt;br /&gt;
** the id of the new virtual channel, or NIL if the virtual channel could not be created. Use this id for setting the channel value (see setChannel() )&lt;br /&gt;
&lt;br /&gt;
===getChannel( Channel ID or name )===&lt;br /&gt;
* First available  in v2.9.0 ; retrieving by channel name available in v2.13.0&lt;br /&gt;
* Parameters &lt;br /&gt;
** Channel ID or name : if a number, matches on the channel ID  as provided by the &#039;&#039;&#039;addChannel&#039;&#039;&#039; function. If string, matches on any current channel in the system. &lt;br /&gt;
* Returns&lt;br /&gt;
** (number) The current value of the channel if available, or &#039;&#039;&#039;nil&#039;&#039;&#039; if the value is not available. You should always check if the value is present before using it for other purposes, especially if the script&#039;s tick rate is high relative to the channel&#039;s sample rate.&lt;br /&gt;
&lt;br /&gt;
* Examples: &lt;br /&gt;
&lt;br /&gt;
 --returns the virtual channel assigned to ID 1. Current value of channel is stored in val &lt;br /&gt;
 val = getChannel(1)&lt;br /&gt;
&lt;br /&gt;
 --get the channel by name&lt;br /&gt;
 rpm = getChannel(&amp;quot;RPM&amp;quot;) &lt;br /&gt;
 if rpm ~= nil then&lt;br /&gt;
  println(&amp;quot;rpm channel: &amp;quot; ..rpm)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
===setChannel( channelId, value )===&lt;br /&gt;
&#039;&#039;available in firmware 2.0&#039;&#039;&lt;br /&gt;
Updates the value of a previously created virtual channel.&lt;br /&gt;
* params&lt;br /&gt;
** channelId: the ID of the channel provided by addChannel()&lt;br /&gt;
** value: the new value to set for the virtual channel&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 id = addChannel(&amp;quot;EGT&amp;quot;, 1)&lt;br /&gt;
 &lt;br /&gt;
 function onTick()&lt;br /&gt;
    temp = getAnalog(0) --read analog channel 0&lt;br /&gt;
    temp = temp * 1000&lt;br /&gt;
    setChannel(id, temp) --sets the virtual channel value&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
==Time Info==&lt;br /&gt;
These methods get you information about dates and time.  This is useful in controlling script behavior or just knowing what time it is.&lt;br /&gt;
&lt;br /&gt;
===getUptime()===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Returns the number of miliseconds since the device last started.  This is always available and is the most consistent way to time things in LUA script on RaceCapture.&lt;br /&gt;
&lt;br /&gt;
* Returns&lt;br /&gt;
** Number of milliseconds since CPU boot.&lt;br /&gt;
&lt;br /&gt;
===getDateTime()===&lt;br /&gt;
&#039;&#039;Available since firmware 2.8.4&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Returns date and time info to the best of the systems ability, in UTC.  Only available after GPS lock has been established.  Will return epoch time (Jan 1, 1970 00:00:000) if time is not available.&lt;br /&gt;
&lt;br /&gt;
* Returns: A list of date and time information in the following order:&lt;br /&gt;
** Year&lt;br /&gt;
** Month&lt;br /&gt;
** Day&lt;br /&gt;
** Hour&lt;br /&gt;
** Minute&lt;br /&gt;
** Second&lt;br /&gt;
** Millisecond&lt;br /&gt;
&lt;br /&gt;
==Dashboard Control==&lt;br /&gt;
===txButton()===&lt;br /&gt;
Simulates button press events for dashboard navigation and control.  RaceCapture dashboard must be connected for function to have effect. &lt;br /&gt;
* params&lt;br /&gt;
**  button_id:  ID of button to transmit.  0 = left button;1 = right button;2 = Ack/Yes;3 = No&lt;br /&gt;
** state: State of button: 1 = pressed; 0 = not pressed&lt;br /&gt;
* returns&lt;br /&gt;
** (nothing)&lt;br /&gt;
&lt;br /&gt;
==ShiftX2/3 control==&lt;br /&gt;
The following functions provide access to the [[ShiftX2]] or [[ShiftX3]] RGB sequential shift light.  &#039;&#039;Available in firmware 2.15.0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===sxSetConfig()===&lt;br /&gt;
Configures the connected ShiftX device. This must be called prior to any other configuration function calls.  All parameters are optional; call with no parameters to use the default settings:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sxSetConfig()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* params&lt;br /&gt;
** orientation: 0 (normal, 7-segment display below bar graph); 1 (inverted, 7-segment display above bar graph). Defaut value: 0&lt;br /&gt;
** brightness: 0 (automatic brightness control with ambient light sensor; 1-100: brightness percentage. Default value: 0&lt;br /&gt;
** CAN bus: 0 (connected to CAN1); 1 (connected to CAN2). Default value: 1&lt;br /&gt;
** CAN base address: base CAN address to use.  Default value: 931328)&lt;br /&gt;
** Auto brightness scaling: Amplification value to tune ambient light sensor. 0-255 value; Default value: 51&lt;br /&gt;
** Enable / Disable button events: true (Enable button event broadcast to app); false (Disable button event broadcast to app)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxCfgLinearGraph()===&lt;br /&gt;
Configures the the style and overall range for the linear graph. &lt;br /&gt;
* params&lt;br /&gt;
** Rendering Style: 0 (left-&amp;gt;right); 1 (center); 2 (right-&amp;gt;left)&lt;br /&gt;
** Linear Style: 0 (Smooth / interpolated); 1 (stepped)&lt;br /&gt;
** Low Range Threshold: The overall low range for the linear graph&lt;br /&gt;
** High Range Threshold: The overall high range for the linear graph (ignored if linear style = stepped)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetLinearThresh()===&lt;br /&gt;
Configure a threshold for the linear graph. Each threshold is identified by an ID, and thresholds are processed from low to high IDs. 5 thresholds can be defined. &lt;br /&gt;
* params&lt;br /&gt;
** Threshold Id: Id for threshold to set. (0-4). Lower IDs are evaluated first. &lt;br /&gt;
** Segment Length: 0 -&amp;gt; number of LEDs on linear graph. (Ignored if linear style = smooth)&lt;br /&gt;
** Threshold Value: Value where this threshold is activated&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxUpdateLinearGraph()===&lt;br /&gt;
Update the linear graph with the current sensor value. ShiftX will apply the previously configured thresholds to set bar graph length, color and flash. &lt;br /&gt;
* params&lt;br /&gt;
** Value: current value representing the linear graph&lt;br /&gt;
* returns&lt;br /&gt;
** (none)&lt;br /&gt;
===sxSetAlert()=== &lt;br /&gt;
Direct set an alert indicator.   For ShiftX3, ID0=Alert LED on right side; ID1=Alert LED on left side.&lt;br /&gt;
* params&lt;br /&gt;
** Alert ID: ID of alert (0 -&amp;gt; # of alert indicators)&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetAlertThresh()===&lt;br /&gt;
Configures an alert threshold. Up to 5 thresholds can be configured per alert indicator. Thresholds are evaluated by ID, from low to high.&lt;br /&gt;
* params&lt;br /&gt;
** Alert ID: Id of Alert (0 -&amp;gt; # of alert indicators)&lt;br /&gt;
** Threshold ID: Id for threshold to set. (0-4). Lower IDs are evaluated first.&lt;br /&gt;
** Threshold Value: Value where this threshold is activated&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if configuration message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxUpdateAlert()===&lt;br /&gt;
Updates the current value for the specified Alert. ShiftX will apply the previously configured thresholds to set color and flash. &lt;br /&gt;
* params&lt;br /&gt;
** Alert ID: Id of Alert (0 -&amp;gt; # of alert indicators)&lt;br /&gt;
** Value: current value representing the alert&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetDisplay()===&lt;br /&gt;
Directly sets the value of the 7 segment display. &lt;br /&gt;
* params&lt;br /&gt;
** Digit index (must be 0)&lt;br /&gt;
** Charater: 0-9. Can set ASCII value by offsetting the value by 48 (e.g. ASCII - 48)&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxSetLed()===&lt;br /&gt;
Directly set any available LED on ShiftX&lt;br /&gt;
* params&lt;br /&gt;
** LED Index: 0 -&amp;gt; # of LEDs on device&lt;br /&gt;
** Number of LEDs to set: 0 -&amp;gt; # of LEDs on device (0  = set all remaining)&lt;br /&gt;
** Red: Red LED value (0-255)&lt;br /&gt;
** Green: Green LED value (0-255)&lt;br /&gt;
** Blue: Blue LED value (0-255)&lt;br /&gt;
** Flash: 0-10Hz (0 = sold on)&lt;br /&gt;
* returns&lt;br /&gt;
** true if update message was successfully broadcast to ShiftX (does not indicate if ShiftX has received it)&lt;br /&gt;
&lt;br /&gt;
===sxRxButton()===&lt;br /&gt;
* params&lt;br /&gt;
** (none)&lt;br /&gt;
* returns&lt;br /&gt;
** nil if no button presses are available; otherwise:&lt;br /&gt;
** button_id (ID of button. left button = 0, right button = 1)&lt;br /&gt;
** state: (0 = not pressed; 1 = pressed)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
local id, state = sxRxButton()&lt;br /&gt;
if id ~= nil then println(&#039;button &#039; ..id ..&#039; state &#039; ..state) end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Helper Functions==&lt;br /&gt;
===calcGear()===&lt;br /&gt;
A convenience function to calculate the current gear of the vehicle.  &#039;&#039;Available in firmware 2.15.0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Variation 1: Use built in GPS speed channel and RPM channel named &amp;quot;RPM&amp;quot;&lt;br /&gt;
* params&lt;br /&gt;
** Tire Diameter: Tire diameter, in cm. &lt;br /&gt;
** Final Drive Ratio: The ratio of the final drive&lt;br /&gt;
** Gear 1 Ratio: Ratio of 1st gear&lt;br /&gt;
** Gear 2 Ratio: Ratio of 2nd gear (optional)&lt;br /&gt;
** Gear 3 Ratio: Ratio of 3rd gear (optional)&lt;br /&gt;
** Gear 4 Ratio: Ratio of 4th gear (optional)&lt;br /&gt;
** Gear 5 Ratio: Ratio of 5th gear (optional)&lt;br /&gt;
** Gear 6 Ratio: Ratio of 6th gear (optional)&lt;br /&gt;
* returns&lt;br /&gt;
** detected gear (1-6) or nil if no gear was detected&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
local gear = calcGear(62.7, 3.45, 4.23, 2.52, 1.66, 1.22, 1.0, 0.8)&lt;br /&gt;
if gear ~= nil then println(&#039;gear: &#039; ..gear) end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Variation 2: Specify Speed and RPM channel&lt;br /&gt;
* params&lt;br /&gt;
** Speed Channel name&lt;br /&gt;
** RPM Channel name&lt;br /&gt;
** Tire Diameter: Tire diameter, in cm. &lt;br /&gt;
** Final Drive Ratio: The ratio of the final drive&lt;br /&gt;
** Gear 1 Ratio: Ratio of 1st gear&lt;br /&gt;
** Gear 2 Ratio: Ratio of 2nd gear (optional)&lt;br /&gt;
** Gear 3 Ratio: Ratio of 3rd gear (optional)&lt;br /&gt;
** Gear 4 Ratio: Ratio of 4th gear (optional)&lt;br /&gt;
** Gear 5 Ratio: Ratio of 5th gear (optional)&lt;br /&gt;
** Gear 6 Ratio: Ratio of 6th gear (optional)&lt;br /&gt;
* returns&lt;br /&gt;
** detected gear (1-6) or nil if no gear was detected&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
local gear = calcGear(&#039;Speed&#039;, &#039;RPM&#039;, 62.7, 3.45, 4.23, 2.52, 1.66, 1.22, 1.0, 0.8)&lt;br /&gt;
if gear ~= nil then println(&#039;gear: &#039; ..gear) end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ddimensia</name></author>
	</entry>
	<entry>
		<id>https://wiki.autosportlabs.com/index.php?title=RaceCapture_on_Raspberry_Pi&amp;diff=9919</id>
		<title>RaceCapture on Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/index.php?title=RaceCapture_on_Raspberry_Pi&amp;diff=9919"/>
		<updated>2023-12-22T18:40:04Z</updated>

		<summary type="html">&lt;p&gt;Ddimensia: Changed to reference bookworm as the prefered OS at this point.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Introduction=&lt;br /&gt;
&lt;br /&gt;
We designed the RaceCapture app to run nearly anywhere - even a Raspberry Pi. And now, for about $100 you can create a hardwired, dedicated dash for your RaceCapture system. &lt;br /&gt;
&lt;br /&gt;
[[image:racecapture_raspberry_pi.jpg|1024px]]&lt;br /&gt;
&lt;br /&gt;
==Benefits==&lt;br /&gt;
You get all of the benefits of a dedicated dash:&lt;br /&gt;
* &#039;&#039;&#039;Automatically runs upon power up&#039;&#039;&#039; - you can configure the dash to automatically launch the RaceCapture App - just as you&#039;d expect it to work.&lt;br /&gt;
* &#039;&#039;&#039;Hard-wired data connection to RaceCapture&#039;&#039;&#039; - no wireless connections to configure, with the reliability of a direct wire.&lt;br /&gt;
* &#039;&#039;&#039;Runs on the bare metal&#039;&#039;&#039; - The RaceCapture app runs without Android or iOS; there&#039;s no other apps competing for resources, or compromising system stability. &lt;br /&gt;
* &#039;&#039;&#039;Overheating resistance&#039;&#039;&#039; -  Your typical mobile device requires extra care in very hot weather to prevent damage to it&#039;s internal battery, and will shut down if overheated. With proper heat-sinking, the Raspberry Pi should handle the heat.&lt;br /&gt;
&lt;br /&gt;
==Compatibility==&lt;br /&gt;
The RaceCapture app running on the Raspberry Pi is compatible with any hardware version of RaceCapture or PodiumConnect. &lt;br /&gt;
&lt;br /&gt;
[[image:racecapture_raspberry_pi_backside.jpg|1024px]]&lt;br /&gt;
&lt;br /&gt;
==Experimental!==&lt;br /&gt;
While the results are pretty great, these instructions are &#039;&#039;currently&#039;&#039; for those adventurous race car hackers who know their away around a command line, comfortable working with hardware and want to dig in.  &#039;&#039;&#039;Think it&#039;s cool, but too much to tackle?&#039;&#039;&#039; Rope in your nearest computer/electronics geek - you need one on your race team, anyway. :)  &#039;&#039;&#039;Or, just use the plug and play option&#039;&#039;&#039; and use an Android or iOS device via Bluetooth or WiFi.&lt;br /&gt;
&lt;br /&gt;
==Current status and future plans==&lt;br /&gt;
Even though this is brand new and officially experimental in nature, we still made it as easy as reasonably possible: we wrapped up the RaceCapture App into as close to a self-running installer, that can run on a bone stock Raspberry Pi image - only a few changes are required to the default image, detailed below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;However&#039;&#039;&#039;, in the near future we will create a dedicated Raspberry Pi image that you can burn to an SD card and simply boot up, and move towards more official support as we iron out the issues. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reporting issues and getting support===&lt;br /&gt;
Chances are you&#039;ll encounter an issue you&#039;ll want to report. Before you do that, [https://github.com/autosportlabs/RaceCapture_App/issues?q=is%3Aopen+is%3Aissue+label%3A%22raspberry+pi%22 check the issue log] to see if it&#039;s already known.&lt;br /&gt;
&lt;br /&gt;
Otherwise - the best place for support, feedback and sharing success stories is [http://forum.autosportlabs.com on the  forums] .  Drop us a note there so we can see the progress of your project!&lt;br /&gt;
&lt;br /&gt;
=Hardware Selection=&lt;br /&gt;
===Raspberry Pi===&lt;br /&gt;
The RaceCapture app is compatible with Raspberry Pi 5, 4 and 3.&lt;br /&gt;
We recommend the Raspberry Pi 4 2GB and higher for best performance and support.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
The RaceCapture app package is designed to recognize the following screens:&lt;br /&gt;
&lt;br /&gt;
* [https://www.raspberrypi.org/products/raspberry-pi-touch-display/ Official Raspberry Pi display] with capacitive touch screen;&lt;br /&gt;
* Displays supporting the AR1100 resistive touch screen controller.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Other displays can work as well, and additional work may be needed to support the screen&#039;s touch controller. If unsure, just pick the [https://www.raspberrypi.org/products/raspberry-pi-touch-display/ Official Raspberry Pi display]&lt;br /&gt;
===Enclosure===&lt;br /&gt;
A recommended enclosure is the [http://https://www.amazon.com/dp/B01HV97F64 Smart Pi Touch Case]&lt;br /&gt;
&lt;br /&gt;
You can 3D print a sun shade for this enclosure  [[file:P001 Raspberry Pi Display Sun Shade.stl.zip|download the .stl file]] (&#039;&#039;Courtesy of Michael Lee&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
[[image:SmartPi_touch_case.jpg|400px]] [[image:RaceCapture_Sun_shade_3dprinted_preview.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
[[image:RaceCapture_RaspberryPi_sun_shade_dashboard.jpg|800px]]&lt;br /&gt;
&lt;br /&gt;
Installed on Dashboard&lt;br /&gt;
&lt;br /&gt;
===Power Supply===&lt;br /&gt;
The Raspberry Pi dashboard requires its own power supply.  You&#039;ll need a high quality 5v power supply with 2 amps minimum capacity; 3 amps is highly recommended, and ideally one with a low drop out voltage, so power is not cut to the Raspberry Pi when you&#039;re loading the main battery, such as when cranking the engine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Suggested Power Supplies&#039;&#039;&#039;&lt;br /&gt;
* [https://www.amazon.com/Jabinco-LM2596-Converter-3-0-40V-1-5-35V/dp/B0817P8BGB/ Buck Converter based on the LM2596]&lt;br /&gt;
&lt;br /&gt;
====Powering RaceCapture====&lt;br /&gt;
After you have power to the Raspberry Pi dashboard, you may notice your RaceCapture device will be powered by the USB cable connected to the Pi, just as if you&#039;re powering RaceCapture from your laptop.  &#039;&#039;&#039;You will still want to power your RaceCapture via 12v&#039;&#039;&#039;; see the respective installation guides for information on how to power your device.&lt;br /&gt;
&lt;br /&gt;
===Heat sinking===&lt;br /&gt;
If you&#039;re running in hot weather, we recommend the standard Raspberry Pi heatsink kit to keep your system cool.&lt;br /&gt;
&lt;br /&gt;
For Pi4 users, we recommend active fan cooling in addition to the heat sink.&lt;br /&gt;
&lt;br /&gt;
=Installation=&lt;br /&gt;
==Installing Raspberry Pi OS==&lt;br /&gt;
We currently recommend Raspberry Pi OS Lite, Debian Version 12 (bookworm) and require a 64bit version for app versions 2.9.0 and newer. &lt;br /&gt;
&lt;br /&gt;
Download from [https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-64-bit the official site] or use the [https://www.raspberrypi.com/software/ Raspberry Pi imager] and choose &amp;quot;Raspberry Pi OS (other)-&amp;gt;Raspberry Pi OS Lite (64-bit)&amp;quot; for the operating system, following the instructions for burning to an SD card. &lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve created your image, boot up your Raspberry Pi and follow the prompts to set your keyboard language and create a username and password.&lt;br /&gt;
&lt;br /&gt;
You should now be able to login as that user and will be greeted with a command prompt like `user@raspberrypi:~ $`&lt;br /&gt;
&lt;br /&gt;
===Wifi Setup===&lt;br /&gt;
Unless you are using a network cable you will need to setup Wifi before proceeding.  To do this you need to run the command `sudo raspi-config`,&lt;br /&gt;
this will bring up a window with several options.  To configure Wifi you will want to select `1 System Options` followed by `S1 Wireless LAN`.  It will ask you to select your Wifi country and set your network SSID and network password.&lt;br /&gt;
&lt;br /&gt;
===Timezone===&lt;br /&gt;
It is advisable to set the system&#039;s timezone before proceeding.  This is also accomplished by using raspi-config which is run with the command `sudo raspi-config`.  If you are also setting up Wifi you can configure your timezone at the same time you are configuring Wifi.  &lt;br /&gt;
&lt;br /&gt;
The timezone setting is configured in `5 Localization Options`-&amp;gt;`L2 Timezone`.  This will allow you to set the timezone by first selecting your region and a major city in your timezone.  When done setting the timezone you can back out of raspi-config by hitting escape until you are back at the command prompt.&lt;br /&gt;
&lt;br /&gt;
===Checking your network===&lt;br /&gt;
At this point it is good to make sure your Raspberry Pi is connected to your network.  Without this none of the remaining steps will be successful. &lt;br /&gt;
&lt;br /&gt;
An easy way to check that you are connected to the network is to use the command `hostname -I`, this will print out the IP address of your&lt;br /&gt;
Raspberry Pi, or a blank line if you are not connected.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
user@raspberrypi:~ $ hostname -I&lt;br /&gt;
192.168.1.183 2601:601:d07f:c107:dfb6:823:b21d:6dff&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating to latest packages===&lt;br /&gt;
It is always good form to update the latest packages after a fresh install. Enter this at the command line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt dist-upgrade&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RaceCapture App Installation==&lt;br /&gt;
For those wanting an installation that automatically launches the dashboard upon login, we have developed&lt;br /&gt;
an installation script.  The installation script allows for the selection of either running against the &lt;br /&gt;
framebuffer or X11, and helps in setting up standard Raspberry Pi configuration settings. As a bonus the installation&lt;br /&gt;
script also includes optional features such as Wifi auto reconnect, USB drive automounting and GPIO based shutdown&lt;br /&gt;
reboot support.&lt;br /&gt;
&lt;br /&gt;
If you want a more custom installation, such as running in a full Desktop environment, manual instructions are also provided. &lt;br /&gt;
===Via Installation Script===&lt;br /&gt;
From a command prompt simply run&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo sh -c &amp;quot;curl -sL bit.ly/3yTbPyZ | bash&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The installation script will setup the system configuration files so that screen blanking is disabled and GPU memory is set to 256MB.&lt;br /&gt;
It will then prompt with a series of questions and configuration options, allowing you to customize the installation.&lt;br /&gt;
====Configuration Options====&lt;br /&gt;
The installation script prompts for the following:&lt;br /&gt;
=====Auto Login=====&lt;br /&gt;
* Whether to enable auto login upon startup, if not already enabled (Recommendation: Yes)&lt;br /&gt;
** This allows the RPi to login as the current user and launch the RaceCapture App upon startup of your Raspberry Pi. Without this you will need to login every time your Raspberry Pi is powered up.&lt;br /&gt;
=====RPi3 Official Display Support=====&lt;br /&gt;
* If running an RPi3, whether you are running an Official RPi display.&lt;br /&gt;
** Only select yes if you are using a RPi3 with an Official RPi display plugged into the LCD/MIPI connector on the board. Enabling this will disable HDMI support as the RPi3 doesn&#039;t appear to automatically detect LCD screens properly.&lt;br /&gt;
=====Installation Type=====&lt;br /&gt;
* Which type of installation you want, Framebuffer (traditional installation), or X11 which enables the option of VNC support&lt;br /&gt;
* If X11 was chosen:&lt;br /&gt;
** Whether to enable VNC and if so prompts for entering a VNC password&lt;br /&gt;
=====App Features=====&lt;br /&gt;
* Watchdog: Enables automatically restarting the RaceCapture App should it crash/exit unexpectedly&lt;br /&gt;
* Cursor: Enables a visual mouse pointer (Not recommended for touchscreens)&lt;br /&gt;
* Keyboard: Enables an onscreen virtual keyboard for touch screens&lt;br /&gt;
=====Extra Features=====&lt;br /&gt;
* Wifi Auto Reconnect: Enables a script that detects if your wifi connection is down and attempts to reconnect&lt;br /&gt;
* USB Automounting: Enables automatic mounting of USB thumbdrives under /media/usb#, useful for exporting session data or saving configs off the device&lt;br /&gt;
* GPIO Reboot/Shutdown: Enables the ability to add a button or switch between GPIO21 and a ground pin, with a short press causing a reboot and a long press causing a graceful shutdown&lt;br /&gt;
&lt;br /&gt;
====Post Configuration Steps====&lt;br /&gt;
After you have selected your configuration options the installation script will proceed to download the latest RaceCapture App bundle from&lt;br /&gt;
[http://podium.live/software the Podium website], placing it in /opt.  If the latest version is already present in /opt it will skip this step.&lt;br /&gt;
&lt;br /&gt;
Next it will unpack the App into /opt/racecapture, prompting you to overwrite and existing installation if one exists.&lt;br /&gt;
&lt;br /&gt;
Finally, the script will modify some files, .bashrc and .xinitrc for X11 installations, so that the Race Capture app launches upon login.&lt;br /&gt;
&lt;br /&gt;
===Manual Installation===&lt;br /&gt;
If you choose to install the RaceCapture App manually it&#039;s assumed that you have an understanding of the different configuration and installation&lt;br /&gt;
options available for the Raspberry Pi.  Below is the minimal requirements to run the RaceCapture App via the Framebuffer. &lt;br /&gt;
If running in an X11/desktop environment the same instructions should be adequate for running the app in that environment also.&lt;br /&gt;
&lt;br /&gt;
====Install package dependencies====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt install mesa-utils libgles2 libegl1-mesa libegl-mesa0 mtdev-tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====User Permissions====&lt;br /&gt;
Ensure that the user is in the dialout, render, video and input groups.  It appears these are added by default but to be sure you should run:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo adduser $USER render&lt;br /&gt;
sudo adduser $USER video&lt;br /&gt;
sudo adduser $USER input&lt;br /&gt;
sudo adduser $USER dialout&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Installing the RaceCapture app package====&lt;br /&gt;
&lt;br /&gt;
Download the latest [http://podium.live/software RaceCapture app package for Raspberry Pi] and place it in the /opt/ directory of the Raspberry Pi.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Directly downloading to the Raspberry Pi&#039;&#039;&#039;&lt;br /&gt;
You can download it directly by getting the URL of the package by right-clicking the download link and copying the URL to your clipboard. Then, use it in the command below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /opt&lt;br /&gt;
sudo wget &amp;lt;package URL&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Extract the package=====&lt;br /&gt;
Now extract the downloaded package :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo tar -xjvf &amp;lt;downloaded file&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Launch the app====&lt;br /&gt;
Launch the RaceCapture app by running the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Launching with Watchdog====&lt;br /&gt;
You can enable an automatic watchdog that re-launches the app in case a crash occurs. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh -w 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; You can break out of the application by issuing &#039;&#039;&#039;Alt + PrntScn + k&#039;&#039;&#039; to the application. &lt;br /&gt;
&lt;br /&gt;
You can further stop all racecapture processes by issuing the following command (e.g. via ssh)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
killall -9 run_racecapture&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enabling on screen keyboard====&lt;br /&gt;
If you don&#039;t have a wireless keyboard attached via usb, you can enable an on-screen keyboard.&lt;br /&gt;
&lt;br /&gt;
Edit the kivy config.ini file with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo nano ~/.kivy/config.ini&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and update the keyboard_mode line with:&lt;br /&gt;
&lt;br /&gt;
keyboard_mode = multi&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Connecting to your RaceCapture system=&lt;br /&gt;
[[image:racecapture_raspberry_pi_connections.jpg|900px]]&lt;br /&gt;
===Powering up===&lt;br /&gt;
* Connect your RaceCapture/Pro or RaceCapture/Track to the Raspberry Pi using the USB cable. &lt;br /&gt;
* Connect the power to your display and power up.  &lt;br /&gt;
&lt;br /&gt;
====Installed via Script====&lt;br /&gt;
If you installed via the setup script and enabled autologin, simply let it start upon power-up.  &lt;br /&gt;
Without autologin you will need to first login as your default user.&lt;br /&gt;
&lt;br /&gt;
====Manual Installation====&lt;br /&gt;
See [[#Launch_the_app]]&lt;br /&gt;
&lt;br /&gt;
===Connection and usage===&lt;br /&gt;
&lt;br /&gt;
Once the RaceCapture App is running, it will connect automatically over USB.  You can use the app just as you would on Android or iOS.&lt;br /&gt;
&lt;br /&gt;
=Extra Features=&lt;br /&gt;
&lt;br /&gt;
===Hardwire buttons===&lt;br /&gt;
&lt;br /&gt;
The RaceCapture app responds to keyboard commands for certain behaviors. You can use a USB keyboard - or a device that emulates keyboard commands - to control the RaceCapture App.&lt;br /&gt;
&lt;br /&gt;
Currently there are keyboard commands for the following:&lt;br /&gt;
* &#039;&#039;&#039;Navigating dashboard screens&#039;&#039;&#039;  - Use the left and right arrow keys to switch between screens&lt;br /&gt;
* &#039;&#039;&#039;Escaping from screens / menus&#039;&#039;&#039; - The Escape key can be used to exit out of screens and options, just like the &#039;back&#039; button on Android.&lt;br /&gt;
* &#039;&#039;&#039;Acknowledging alerts&#039;&#039;&#039; - Use the following keys to acknowledge alerts, including responding to pit-to-car alerts:&lt;br /&gt;
** K : to indicate &#039;Yes&#039; or &#039;OK&#039;&lt;br /&gt;
** N : to indicate &#039;No&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Additional Tips=&lt;br /&gt;
See this link for additional tips on how to setup the Pi and speed up the boot times.  This should be especially helpful for beginners.&lt;br /&gt;
&lt;br /&gt;
https://wiki.autosportlabs.com/Raspberry_Pi_Tips&lt;br /&gt;
&lt;br /&gt;
Logfiles for troubleshooting can be found at&lt;br /&gt;
&lt;br /&gt;
/home/pi&lt;/div&gt;</summary>
		<author><name>Ddimensia</name></author>
	</entry>
	<entry>
		<id>https://wiki.autosportlabs.com/index.php?title=RaceCapture_on_Raspberry_Pi&amp;diff=9807</id>
		<title>RaceCapture on Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/index.php?title=RaceCapture_on_Raspberry_Pi&amp;diff=9807"/>
		<updated>2023-11-21T18:11:47Z</updated>

		<summary type="html">&lt;p&gt;Ddimensia: /* Installing Raspberry Pi OS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Introduction=&lt;br /&gt;
&lt;br /&gt;
We designed the RaceCapture app to run nearly anywhere - even a Raspberry Pi. And now, for about $100 you can create a hardwired, dedicated dash for your RaceCapture system. &lt;br /&gt;
&lt;br /&gt;
[[image:racecapture_raspberry_pi.jpg|1024px]]&lt;br /&gt;
&lt;br /&gt;
==Benefits==&lt;br /&gt;
You get all of the benefits of a dedicated dash:&lt;br /&gt;
* &#039;&#039;&#039;Automatically runs upon power up&#039;&#039;&#039; - you can configure the dash to automatically launch the RaceCapture App - just as you&#039;d expect it to work.&lt;br /&gt;
* &#039;&#039;&#039;Hard-wired data connection to RaceCapture&#039;&#039;&#039; - no wireless connections to configure, with the reliability of a direct wire.&lt;br /&gt;
* &#039;&#039;&#039;Runs on the bare metal&#039;&#039;&#039; - The RaceCapture app runs without Android or iOS; there&#039;s no other apps competing for resources, or compromising system stability. &lt;br /&gt;
* &#039;&#039;&#039;Overheating resistance&#039;&#039;&#039; -  Your typical mobile device requires extra care in very hot weather to prevent damage to it&#039;s internal battery, and will shut down if overheated. With proper heat-sinking, the Raspberry Pi should handle the heat.&lt;br /&gt;
&lt;br /&gt;
==Compatibility==&lt;br /&gt;
The RaceCapture app running on the Raspberry Pi is compatible with any hardware version of RaceCapture or PodiumConnect. &lt;br /&gt;
&lt;br /&gt;
[[image:racecapture_raspberry_pi_backside.jpg|1024px]]&lt;br /&gt;
&lt;br /&gt;
==Experimental!==&lt;br /&gt;
While the results are pretty great, these instructions are &#039;&#039;currently&#039;&#039; for those adventurous race car hackers who know their away around a command line, comfortable working with hardware and want to dig in.  &#039;&#039;&#039;Think it&#039;s cool, but too much to tackle?&#039;&#039;&#039; Rope in your nearest computer/electronics geek - you need one on your race team, anyway. :)  &#039;&#039;&#039;Or, just use the plug and play option&#039;&#039;&#039; and use an Android or iOS device via Bluetooth or WiFi.&lt;br /&gt;
&lt;br /&gt;
==Current status and future plans==&lt;br /&gt;
Even though this is brand new and officially experimental in nature, we still made it as easy as reasonably possible: we wrapped up the RaceCapture App into as close to a self-running installer, that can run on a bone stock Raspberry Pi image - only a few changes are required to the default image, detailed below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;However&#039;&#039;&#039;, in the near future we will create a dedicated Raspberry Pi image that you can burn to an SD card and simply boot up, and move towards more official support as we iron out the issues. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reporting issues and getting support===&lt;br /&gt;
Chances are you&#039;ll encounter an issue you&#039;ll want to report. Before you do that, [https://github.com/autosportlabs/RaceCapture_App/issues?q=is%3Aopen+is%3Aissue+label%3A%22raspberry+pi%22 check the issue log] to see if it&#039;s already known.&lt;br /&gt;
&lt;br /&gt;
Otherwise - the best place for support, feedback and sharing success stories is [http://forum.autosportlabs.com on the  forums] .  Drop us a note there so we can see the progress of your project!&lt;br /&gt;
&lt;br /&gt;
=Hardware Selection=&lt;br /&gt;
===Raspberry Pi===&lt;br /&gt;
The RaceCapture app is compatible with Raspberry Pi 4 and 3.&lt;br /&gt;
We recommend the Raspberry Pi 4 2GB and higher for best performance and support.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
The RaceCapture app package is designed to recognize the following screens:&lt;br /&gt;
&lt;br /&gt;
* [https://www.raspberrypi.org/products/raspberry-pi-touch-display/ Official Raspberry Pi display] with capacitive touch screen;&lt;br /&gt;
* Displays supporting the AR1100 resistive touch screen controller.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Other displays can work as well, and additional work may be needed to support the screen&#039;s touch controller. If unsure, just pick the [https://www.raspberrypi.org/products/raspberry-pi-touch-display/ Official Raspberry Pi display]&lt;br /&gt;
===Enclosure===&lt;br /&gt;
A recommended enclosure is the [http://https://www.amazon.com/dp/B01HV97F64 Smart Pi Touch Case]&lt;br /&gt;
&lt;br /&gt;
You can 3D print a sun shade for this enclosure  [[file:P001 Raspberry Pi Display Sun Shade.stl.zip|download the .stl file]] (&#039;&#039;Courtesy of Michael Lee&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
[[image:SmartPi_touch_case.jpg|400px]] [[image:RaceCapture_Sun_shade_3dprinted_preview.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
[[image:RaceCapture_RaspberryPi_sun_shade_dashboard.jpg|800px]]&lt;br /&gt;
&lt;br /&gt;
Installed on Dashboard&lt;br /&gt;
&lt;br /&gt;
===Power Supply===&lt;br /&gt;
The Raspberry Pi dashboard requires its own power supply.  You&#039;ll need a high quality 5v power supply with 2 amps minimum capacity; 3 amps is highly recommended, and ideally one with a low drop out voltage, so power is not cut to the Raspberry Pi when you&#039;re loading the main battery, such as when cranking the engine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Suggested Power Supplies&#039;&#039;&#039;&lt;br /&gt;
* [https://www.amazon.com/Jabinco-LM2596-Converter-3-0-40V-1-5-35V/dp/B0817P8BGB/ Buck Converter based on the LM2596]&lt;br /&gt;
&lt;br /&gt;
====Powering RaceCapture====&lt;br /&gt;
After you have power to the Raspberry Pi dashboard, you may notice your RaceCapture device will be powered by the USB cable connected to the Pi, just as if you&#039;re powering RaceCapture from your laptop.  &#039;&#039;&#039;You will still want to power your RaceCapture via 12v&#039;&#039;&#039;; see the respective installation guides for information on how to power your device.&lt;br /&gt;
&lt;br /&gt;
===Heat sinking===&lt;br /&gt;
If you&#039;re running in hot weather, we recommend the standard Raspberry Pi heatsink kit to keep your system cool.&lt;br /&gt;
&lt;br /&gt;
For Pi4 users, we recommend active fan cooling in addition to the heat sink.&lt;br /&gt;
&lt;br /&gt;
=Installation=&lt;br /&gt;
==Installing Raspberry Pi OS==&lt;br /&gt;
We currently recommend Raspberry Pi OS Lite, Debian Version 11 (bullseye) and require a 64bit version for app versions 2.9.0 and newer. &lt;br /&gt;
&lt;br /&gt;
Download from [https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-legacy-64-bit the official site] or use the [https://www.raspberrypi.com/software/ Raspberry Pi imager] and choose &amp;quot;Raspberry Pi OS (other)-&amp;gt;Raspberry Pi OS (Legacy, 64-bit) Lite&amp;quot; for the operating system, following the instructions for burning to an SD card. &lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve created your image, boot up your Raspberry Pi and follow the prompts to set your keyboard language and create a username and password.&lt;br /&gt;
&lt;br /&gt;
You should now be able to login as that user and will be greeted with a command prompt like `user@raspberrypi:~ $`&lt;br /&gt;
&lt;br /&gt;
===Wifi Setup===&lt;br /&gt;
Unless you are using a network cable you will need to setup Wifi before proceeding.  To do this you need to run the command `sudo raspi-config`,&lt;br /&gt;
this will bring up a window with several options.  To configure Wifi you will want to select `1 System Options` followed by `S1 Wireless LAN`.  It will ask you to select your Wifi country and set your network SSID and network password.&lt;br /&gt;
&lt;br /&gt;
===Timezone===&lt;br /&gt;
It is advisable to set the system&#039;s timezone before proceeding.  This is also accomplished by using raspi-config which is run with the command `sudo raspi-config`.  If you are also setting up Wifi you can configure your timezone at the same time you are configuring Wifi.  &lt;br /&gt;
&lt;br /&gt;
The timezone setting is configured in `5 Localization Options`-&amp;gt;`L2 Timezone`.  This will allow you to set the timezone by first selecting your region and a major city in your timezone.  When done setting the timezone you can back out of raspi-config by hitting escape until you are back at the command prompt.&lt;br /&gt;
&lt;br /&gt;
===Checking your network===&lt;br /&gt;
At this point it is good to make sure your Raspberry Pi is connected to your network.  Without this none of the remaining steps will be successful. &lt;br /&gt;
&lt;br /&gt;
An easy way to check that you are connected to the network is to use the command `hostname -I`, this will print out the IP address of your&lt;br /&gt;
Raspberry Pi, or a blank line if you are not connected.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
user@raspberrypi:~ $ hostname -I&lt;br /&gt;
192.168.1.183 2601:601:d07f:c107:dfb6:823:b21d:6dff&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating to latest packages===&lt;br /&gt;
It is always good form to update the latest packages after a fresh install. Enter this at the command line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt dist-upgrade&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RaceCapture App Installation==&lt;br /&gt;
For those wanting an installation that automatically launches the dashboard upon login, we have developed&lt;br /&gt;
an installation script.  The installation script allows for the selection of either running against the &lt;br /&gt;
framebuffer or X11, and helps in setting up standard Raspberry Pi configuration settings. As a bonus the installation&lt;br /&gt;
script also includes optional features such as Wifi auto reconnect, USB drive automounting and GPIO based shutdown&lt;br /&gt;
reboot support.&lt;br /&gt;
&lt;br /&gt;
If you want a more custom installation, such as running in a full Desktop environment, manual instructions are also provided. &lt;br /&gt;
===Via Installation Script===&lt;br /&gt;
From a command prompt simply run&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo sh -c &amp;quot;curl -sL bit.ly/3yTbPyZ | bash&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The installation script will setup the system configuration files so that screen blanking is disabled and GPU memory is set to 256MB.&lt;br /&gt;
It will then prompt with a series of questions and configuration options, allowing you to customize the installation.&lt;br /&gt;
====Configuration Options====&lt;br /&gt;
The installation script prompts for the following:&lt;br /&gt;
=====Auto Login=====&lt;br /&gt;
* Whether to enable auto login upon startup, if not already enabled (Recommendation: Yes)&lt;br /&gt;
** This allows the RPi to login as the current user and launch the RaceCapture App upon startup of your Raspberry Pi. Without this you will need to login every time your Raspberry Pi is powered up.&lt;br /&gt;
=====RPi3 Official Display Support=====&lt;br /&gt;
* If running an RPi3, whether you are running an Official RPi display.&lt;br /&gt;
** Only select yes if you are using a RPi3 with an Official RPi display plugged into the LCD/MIPI connector on the board. Enabling this will disable HDMI support as the RPi3 doesn&#039;t appear to automatically detect LCD screens properly.&lt;br /&gt;
=====Installation Type=====&lt;br /&gt;
* Which type of installation you want, Framebuffer (traditional installation), or X11 which enables the option of VNC support&lt;br /&gt;
* If X11 was chosen:&lt;br /&gt;
** Whether to enable VNC and if so prompts for entering a VNC password&lt;br /&gt;
=====App Features=====&lt;br /&gt;
* Watchdog: Enables automatically restarting the RaceCapture App should it crash/exit unexpectedly&lt;br /&gt;
* Cursor: Enables a visual mouse pointer (Not recommended for touchscreens)&lt;br /&gt;
* Keyboard: Enables an onscreen virtual keyboard for touch screens&lt;br /&gt;
=====Extra Features=====&lt;br /&gt;
* Wifi Auto Reconnect: Enables a script that detects if your wifi connection is down and attempts to reconnect&lt;br /&gt;
* USB Automounting: Enables automatic mounting of USB thumbdrives under /media/usb#, useful for exporting session data or saving configs off the device&lt;br /&gt;
* GPIO Reboot/Shutdown: Enables the ability to add a button or switch between GPIO21 and a ground pin, with a short press causing a reboot and a long press causing a graceful shutdown&lt;br /&gt;
&lt;br /&gt;
====Post Configuration Steps====&lt;br /&gt;
After you have selected your configuration options the installation script will proceed to download the latest RaceCapture App bundle from&lt;br /&gt;
[http://podium.live/software the Podium website], placing it in /opt.  If the latest version is already present in /opt it will skip this step.&lt;br /&gt;
&lt;br /&gt;
Next it will unpack the App into /opt/racecapture, prompting you to overwrite and existing installation if one exists.&lt;br /&gt;
&lt;br /&gt;
Finally, the script will modify some files, .bashrc and .xinitrc for X11 installations, so that the Race Capture app launches upon login.&lt;br /&gt;
&lt;br /&gt;
===Manual Installation===&lt;br /&gt;
If you choose to install the RaceCapture App manually it&#039;s assumed that you have an understanding of the different configuration and installation&lt;br /&gt;
options available for the Raspberry Pi.  Below is the minimal requirements to run the RaceCapture App via the Framebuffer. &lt;br /&gt;
If running in an X11/desktop environment the same instructions should be adequate for running the app in that environment also.&lt;br /&gt;
&lt;br /&gt;
====Install package dependencies====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt install mesa-utils libgles2 libegl1-mesa libegl-mesa0 mtdev-tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====User Permissions====&lt;br /&gt;
Ensure that the user is in the dialout, render, video and input groups.  It appears these are added by default but to be sure you should run:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo adduser $USER render&lt;br /&gt;
sudo adduser $USER video&lt;br /&gt;
sudo adduser $USER input&lt;br /&gt;
sudo adduser $USER dialout&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Installing the RaceCapture app package====&lt;br /&gt;
&lt;br /&gt;
Download the latest [http://podium.live/software RaceCapture app package for Raspberry Pi] and place it in the /opt/ directory of the Raspberry Pi.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Directly downloading to the Raspberry Pi&#039;&#039;&#039;&lt;br /&gt;
You can download it directly by getting the URL of the package by right-clicking the download link and copying the URL to your clipboard. Then, use it in the command below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /opt&lt;br /&gt;
sudo wget &amp;lt;package URL&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Extract the package=====&lt;br /&gt;
Now extract the downloaded package :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo tar -xjvf &amp;lt;downloaded file&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Launch the app====&lt;br /&gt;
Launch the RaceCapture app by running the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Launching with Watchdog====&lt;br /&gt;
You can enable an automatic watchdog that re-launches the app in case a crash occurs. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh -w 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; You can break out of the application by issuing &#039;&#039;&#039;Alt + PrntScn + k&#039;&#039;&#039; to the application. &lt;br /&gt;
&lt;br /&gt;
You can further stop all racecapture processes by issuing the following command (e.g. via ssh)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
killall -9 run_racecapture&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enabling on screen keyboard====&lt;br /&gt;
If you don&#039;t have a wireless keyboard attached via usb, you can enable an on-screen keyboard.&lt;br /&gt;
&lt;br /&gt;
Edit the kivy config.ini file with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo nano ~/.kivy/config.ini&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and update the keyboard_mode line with:&lt;br /&gt;
&lt;br /&gt;
keyboard_mode = multi&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Connecting to your RaceCapture system=&lt;br /&gt;
[[image:racecapture_raspberry_pi_connections.jpg|900px]]&lt;br /&gt;
===Powering up===&lt;br /&gt;
* Connect your RaceCapture/Pro or RaceCapture/Track to the Raspberry Pi using the USB cable. &lt;br /&gt;
* Connect the power to your display and power up.  &lt;br /&gt;
&lt;br /&gt;
====Installed via Script====&lt;br /&gt;
If you installed via the setup script and enabled autologin, simply let it start upon power-up.  &lt;br /&gt;
Without autologin you will need to first login as your default user.&lt;br /&gt;
&lt;br /&gt;
====Manual Installation====&lt;br /&gt;
See [[#Launch_the_app]]&lt;br /&gt;
&lt;br /&gt;
===Connection and usage===&lt;br /&gt;
&lt;br /&gt;
Once the RaceCapture App is running, it will connect automatically over USB.  You can use the app just as you would on Android or iOS.&lt;br /&gt;
&lt;br /&gt;
=Extra Features=&lt;br /&gt;
&lt;br /&gt;
===Hardwire buttons===&lt;br /&gt;
&lt;br /&gt;
The RaceCapture app responds to keyboard commands for certain behaviors. You can use a USB keyboard - or a device that emulates keyboard commands - to control the RaceCapture App.&lt;br /&gt;
&lt;br /&gt;
Currently there are keyboard commands for the following:&lt;br /&gt;
* &#039;&#039;&#039;Navigating dashboard screens&#039;&#039;&#039;  - Use the left and right arrow keys to switch between screens&lt;br /&gt;
* &#039;&#039;&#039;Escaping from screens / menus&#039;&#039;&#039; - The Escape key can be used to exit out of screens and options, just like the &#039;back&#039; button on Android.&lt;br /&gt;
* &#039;&#039;&#039;Acknowledging alerts&#039;&#039;&#039; - Use the following keys to acknowledge alerts, including responding to pit-to-car alerts:&lt;br /&gt;
** K : to indicate &#039;Yes&#039; or &#039;OK&#039;&lt;br /&gt;
** N : to indicate &#039;No&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Additional Tips=&lt;br /&gt;
See this link for additional tips on how to setup the Pi and speed up the boot times.  This should be especially helpful for beginners.&lt;br /&gt;
&lt;br /&gt;
https://wiki.autosportlabs.com/Raspberry_Pi_Tips&lt;br /&gt;
&lt;br /&gt;
Logfiles for troubleshooting can be found at&lt;br /&gt;
&lt;br /&gt;
/home/pi&lt;/div&gt;</summary>
		<author><name>Ddimensia</name></author>
	</entry>
	<entry>
		<id>https://wiki.autosportlabs.com/index.php?title=RaceCapture_on_Raspberry_Pi&amp;diff=9724</id>
		<title>RaceCapture on Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/index.php?title=RaceCapture_on_Raspberry_Pi&amp;diff=9724"/>
		<updated>2023-10-13T17:13:56Z</updated>

		<summary type="html">&lt;p&gt;Ddimensia: Updated links to point to &amp;#039;Legacy&amp;#039; OS version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Introduction=&lt;br /&gt;
&lt;br /&gt;
We designed the RaceCapture app to run nearly anywhere - even a Raspberry Pi. And now, for about $100 you can create a hardwired, dedicated dash for your RaceCapture system. &lt;br /&gt;
&lt;br /&gt;
[[image:racecapture_raspberry_pi.jpg|1024px]]&lt;br /&gt;
&lt;br /&gt;
==Benefits==&lt;br /&gt;
You get all of the benefits of a dedicated dash:&lt;br /&gt;
* &#039;&#039;&#039;Automatically runs upon power up&#039;&#039;&#039; - you can configure the dash to automatically launch the RaceCapture App - just as you&#039;d expect it to work.&lt;br /&gt;
* &#039;&#039;&#039;Hard-wired data connection to RaceCapture&#039;&#039;&#039; - no wireless connections to configure, with the reliability of a direct wire.&lt;br /&gt;
* &#039;&#039;&#039;Runs on the bare metal&#039;&#039;&#039; - The RaceCapture app runs without Android or iOS; there&#039;s no other apps competing for resources, or compromising system stability. &lt;br /&gt;
* &#039;&#039;&#039;Overheating resistance&#039;&#039;&#039; -  Your typical mobile device requires extra care in very hot weather to prevent damage to it&#039;s internal battery, and will shut down if overheated. With proper heat-sinking, the Raspberry Pi should handle the heat.&lt;br /&gt;
&lt;br /&gt;
==Compatibility==&lt;br /&gt;
The RaceCapture app running on the Raspberry Pi is compatible with any hardware version of RaceCapture or PodiumConnect. &lt;br /&gt;
&lt;br /&gt;
[[image:racecapture_raspberry_pi_backside.jpg|1024px]]&lt;br /&gt;
&lt;br /&gt;
==Experimental!==&lt;br /&gt;
While the results are pretty great, these instructions are &#039;&#039;currently&#039;&#039; for those adventurous race car hackers who know their away around a command line, comfortable working with hardware and want to dig in.  &#039;&#039;&#039;Think it&#039;s cool, but too much to tackle?&#039;&#039;&#039; Rope in your nearest computer/electronics geek - you need one on your race team, anyway. :)  &#039;&#039;&#039;Or, just use the plug and play option&#039;&#039;&#039; and use an Android or iOS device via Bluetooth or WiFi.&lt;br /&gt;
&lt;br /&gt;
==Current status and future plans==&lt;br /&gt;
Even though this is brand new and officially experimental in nature, we still made it as easy as reasonably possible: we wrapped up the RaceCapture App into as close to a self-running installer, that can run on a bone stock Raspberry Pi image - only a few changes are required to the default image, detailed below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;However&#039;&#039;&#039;, in the near future we will create a dedicated Raspberry Pi image that you can burn to an SD card and simply boot up, and move towards more official support as we iron out the issues. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reporting issues and getting support===&lt;br /&gt;
Chances are you&#039;ll encounter an issue you&#039;ll want to report. Before you do that, [https://github.com/autosportlabs/RaceCapture_App/issues?q=is%3Aopen+is%3Aissue+label%3A%22raspberry+pi%22 check the issue log] to see if it&#039;s already known.&lt;br /&gt;
&lt;br /&gt;
Otherwise - the best place for support, feedback and sharing success stories is [http://forum.autosportlabs.com on the  forums] .  Drop us a note there so we can see the progress of your project!&lt;br /&gt;
&lt;br /&gt;
=Hardware Selection=&lt;br /&gt;
===Raspberry Pi===&lt;br /&gt;
The RaceCapture app is compatible with Raspberry Pi 4 and 3.&lt;br /&gt;
We recommend the Raspberry Pi 4 2GB and higher for best performance and support.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
The RaceCapture app package is designed to recognize the following screens:&lt;br /&gt;
&lt;br /&gt;
* [https://www.raspberrypi.org/products/raspberry-pi-touch-display/ Official Raspberry Pi display] with capacitive touch screen;&lt;br /&gt;
* Displays supporting the AR1100 resistive touch screen controller.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Other displays can work as well, and additional work may be needed to support the screen&#039;s touch controller. If unsure, just pick the [https://www.raspberrypi.org/products/raspberry-pi-touch-display/ Official Raspberry Pi display]&lt;br /&gt;
===Enclosure===&lt;br /&gt;
A recommended enclosure is the [http://https://www.amazon.com/dp/B01HV97F64 Smart Pi Touch Case]&lt;br /&gt;
&lt;br /&gt;
You can 3D print a sun shade for this enclosure  [[file:P001 Raspberry Pi Display Sun Shade.stl.zip|download the .stl file]] (&#039;&#039;Courtesy of Michael Lee&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
[[image:SmartPi_touch_case.jpg|400px]] [[image:RaceCapture_Sun_shade_3dprinted_preview.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
[[image:RaceCapture_RaspberryPi_sun_shade_dashboard.jpg|800px]]&lt;br /&gt;
&lt;br /&gt;
Installed on Dashboard&lt;br /&gt;
&lt;br /&gt;
===Power Supply===&lt;br /&gt;
The Raspberry Pi dashboard requires its own power supply.  You&#039;ll need a high quality 5v power supply with 2 amps minimum capacity; 3 amps is highly recommended, and ideally one with a low drop out voltage, so power is not cut to the Raspberry Pi when you&#039;re loading the main battery, such as when cranking the engine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Suggested Power Supplies&#039;&#039;&#039;&lt;br /&gt;
* [https://www.amazon.com/Jabinco-LM2596-Converter-3-0-40V-1-5-35V/dp/B0817P8BGB/ Buck Converter based on the LM2596]&lt;br /&gt;
&lt;br /&gt;
====Powering RaceCapture====&lt;br /&gt;
After you have power to the Raspberry Pi dashboard, you may notice your RaceCapture device will be powered by the USB cable connected to the Pi, just as if you&#039;re powering RaceCapture from your laptop.  &#039;&#039;&#039;You will still want to power your RaceCapture via 12v&#039;&#039;&#039;; see the respective installation guides for information on how to power your device.&lt;br /&gt;
&lt;br /&gt;
===Heat sinking===&lt;br /&gt;
If you&#039;re running in hot weather, we recommend the standard Raspberry Pi heatsink kit to keep your system cool.&lt;br /&gt;
&lt;br /&gt;
For Pi4 users, we recommend active fan cooling in addition to the heat sink.&lt;br /&gt;
&lt;br /&gt;
=Installation=&lt;br /&gt;
==Installing Raspberry Pi OS==&lt;br /&gt;
We currently recommend Raspberry Pi OS Lite, Debian Version 11 (bullseye) and require a 64bit version for app versions 2.9.0 and newer. &lt;br /&gt;
&lt;br /&gt;
Download from [https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-legacy-64-bit the official site] or use the [https://www.raspberrypi.com/software/ Raspberry Pi imager] and choose &amp;quot;Raspberry Pi OS (LEGACY, 64-BIT) LITE&amp;quot; for the operating system, following the instructions for burning to an SD card. &lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve created your image, boot up your Raspberry Pi and follow the prompts to set your keyboard language and create a username and password.&lt;br /&gt;
&lt;br /&gt;
You should now be able to login as that user and will be greeted with a command prompt like `user@raspberrypi:~ $`&lt;br /&gt;
&lt;br /&gt;
===Wifi Setup===&lt;br /&gt;
Unless you are using a network cable you will need to setup Wifi before proceeding.  To do this you need to run the command `sudo raspi-config`,&lt;br /&gt;
this will bring up a window with several options.  To configure Wifi you will want to select `1 System Options` followed by `S1 Wireless LAN`.  It will ask you to select your Wifi country and set your network SSID and network password.&lt;br /&gt;
&lt;br /&gt;
===Timezone===&lt;br /&gt;
It is advisable to set the system&#039;s timezone before proceeding.  This is also accomplished by using raspi-config which is run with the command `sudo raspi-config`.  If you are also setting up Wifi you can configure your timezone at the same time you are configuring Wifi.  &lt;br /&gt;
&lt;br /&gt;
The timezone setting is configured in `5 Localization Options`-&amp;gt;`L2 Timezone`.  This will allow you to set the timezone by first selecting your region and a major city in your timezone.  When done setting the timezone you can back out of raspi-config by hitting escape until you are back at the command prompt.&lt;br /&gt;
&lt;br /&gt;
===Checking your network===&lt;br /&gt;
At this point it is good to make sure your Raspberry Pi is connected to your network.  Without this none of the remaining steps will be successful. &lt;br /&gt;
&lt;br /&gt;
An easy way to check that you are connected to the network is to use the command `hostname -I`, this will print out the IP address of your&lt;br /&gt;
Raspberry Pi, or a blank line if you are not connected.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
user@raspberrypi:~ $ hostname -I&lt;br /&gt;
192.168.1.183 2601:601:d07f:c107:dfb6:823:b21d:6dff&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating to latest packages===&lt;br /&gt;
It is always good form to update the latest packages after a fresh install. Enter this at the command line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt dist-upgrade&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RaceCapture App Installation==&lt;br /&gt;
For those wanting an installation that automatically launches the dashboard upon login, we have developed&lt;br /&gt;
an installation script.  The installation script allows for the selection of either running against the &lt;br /&gt;
framebuffer or X11, and helps in setting up standard Raspberry Pi configuration settings. As a bonus the installation&lt;br /&gt;
script also includes optional features such as Wifi auto reconnect, USB drive automounting and GPIO based shutdown&lt;br /&gt;
reboot support.&lt;br /&gt;
&lt;br /&gt;
If you want a more custom installation, such as running in a full Desktop environment, manual instructions are also provided. &lt;br /&gt;
===Via Installation Script===&lt;br /&gt;
From a command prompt simply run&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo sh -c &amp;quot;curl -sL bit.ly/3yTbPyZ | bash&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The installation script will setup the system configuration files so that screen blanking is disabled and GPU memory is set to 256MB.&lt;br /&gt;
It will then prompt with a series of questions and configuration options, allowing you to customize the installation.&lt;br /&gt;
====Configuration Options====&lt;br /&gt;
The installation script prompts for the following:&lt;br /&gt;
=====Auto Login=====&lt;br /&gt;
* Whether to enable auto login upon startup, if not already enabled (Recommendation: Yes)&lt;br /&gt;
** This allows the RPi to login as the current user and launch the RaceCapture App upon startup of your Raspberry Pi. Without this you will need to login every time your Raspberry Pi is powered up.&lt;br /&gt;
=====RPi3 Official Display Support=====&lt;br /&gt;
* If running an RPi3, whether you are running an Official RPi display.&lt;br /&gt;
** Only select yes if you are using a RPi3 with an Official RPi display plugged into the LCD/MIPI connector on the board. Enabling this will disable HDMI support as the RPi3 doesn&#039;t appear to automatically detect LCD screens properly.&lt;br /&gt;
=====Installation Type=====&lt;br /&gt;
* Which type of installation you want, Framebuffer (traditional installation), or X11 which enables the option of VNC support&lt;br /&gt;
* If X11 was chosen:&lt;br /&gt;
** Whether to enable VNC and if so prompts for entering a VNC password&lt;br /&gt;
=====App Features=====&lt;br /&gt;
* Watchdog: Enables automatically restarting the RaceCapture App should it crash/exit unexpectedly&lt;br /&gt;
* Cursor: Enables a visual mouse pointer (Not recommended for touchscreens)&lt;br /&gt;
* Keyboard: Enables an onscreen virtual keyboard for touch screens&lt;br /&gt;
=====Extra Features=====&lt;br /&gt;
* Wifi Auto Reconnect: Enables a script that detects if your wifi connection is down and attempts to reconnect&lt;br /&gt;
* USB Automounting: Enables automatic mounting of USB thumbdrives under /media/usb#, useful for exporting session data or saving configs off the device&lt;br /&gt;
* GPIO Reboot/Shutdown: Enables the ability to add a button or switch between GPIO21 and a ground pin, with a short press causing a reboot and a long press causing a graceful shutdown&lt;br /&gt;
&lt;br /&gt;
====Post Configuration Steps====&lt;br /&gt;
After you have selected your configuration options the installation script will proceed to download the latest RaceCapture App bundle from&lt;br /&gt;
[http://podium.live/software the Podium website], placing it in /opt.  If the latest version is already present in /opt it will skip this step.&lt;br /&gt;
&lt;br /&gt;
Next it will unpack the App into /opt/racecapture, prompting you to overwrite and existing installation if one exists.&lt;br /&gt;
&lt;br /&gt;
Finally, the script will modify some files, .bashrc and .xinitrc for X11 installations, so that the Race Capture app launches upon login.&lt;br /&gt;
&lt;br /&gt;
===Manual Installation===&lt;br /&gt;
If you choose to install the RaceCapture App manually it&#039;s assumed that you have an understanding of the different configuration and installation&lt;br /&gt;
options available for the Raspberry Pi.  Below is the minimal requirements to run the RaceCapture App via the Framebuffer. &lt;br /&gt;
If running in an X11/desktop environment the same instructions should be adequate for running the app in that environment also.&lt;br /&gt;
&lt;br /&gt;
====Install package dependencies====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt install mesa-utils libgles2 libegl1-mesa libegl-mesa0 mtdev-tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====User Permissions====&lt;br /&gt;
Ensure that the user is in the dialout, render, video and input groups.  It appears these are added by default but to be sure you should run:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo adduser $USER render&lt;br /&gt;
sudo adduser $USER video&lt;br /&gt;
sudo adduser $USER input&lt;br /&gt;
sudo adduser $USER dialout&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Installing the RaceCapture app package====&lt;br /&gt;
&lt;br /&gt;
Download the latest [http://podium.live/software RaceCapture app package for Raspberry Pi] and place it in the /opt/ directory of the Raspberry Pi.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Directly downloading to the Raspberry Pi&#039;&#039;&#039;&lt;br /&gt;
You can download it directly by getting the URL of the package by right-clicking the download link and copying the URL to your clipboard. Then, use it in the command below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /opt&lt;br /&gt;
sudo wget &amp;lt;package URL&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Extract the package=====&lt;br /&gt;
Now extract the downloaded package :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo tar -xjvf &amp;lt;downloaded file&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Launch the app====&lt;br /&gt;
Launch the RaceCapture app by running the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Launching with Watchdog====&lt;br /&gt;
You can enable an automatic watchdog that re-launches the app in case a crash occurs. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh -w 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; You can break out of the application by issuing &#039;&#039;&#039;Alt + PrntScn + k&#039;&#039;&#039; to the application. &lt;br /&gt;
&lt;br /&gt;
You can further stop all racecapture processes by issuing the following command (e.g. via ssh)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
killall -9 run_racecapture&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enabling on screen keyboard====&lt;br /&gt;
If you don&#039;t have a wireless keyboard attached via usb, you can enable an on-screen keyboard.&lt;br /&gt;
&lt;br /&gt;
Edit the kivy config.ini file with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo nano ~/.kivy/config.ini&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and update the keyboard_mode line with:&lt;br /&gt;
&lt;br /&gt;
keyboard_mode = multi&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Connecting to your RaceCapture system=&lt;br /&gt;
[[image:racecapture_raspberry_pi_connections.jpg|900px]]&lt;br /&gt;
===Powering up===&lt;br /&gt;
* Connect your RaceCapture/Pro or RaceCapture/Track to the Raspberry Pi using the USB cable. &lt;br /&gt;
* Connect the power to your display and power up.  &lt;br /&gt;
&lt;br /&gt;
====Installed via Script====&lt;br /&gt;
If you installed via the setup script and enabled autologin, simply let it start upon power-up.  &lt;br /&gt;
Without autologin you will need to first login as your default user.&lt;br /&gt;
&lt;br /&gt;
====Manual Installation====&lt;br /&gt;
See [[#Launch_the_app]]&lt;br /&gt;
&lt;br /&gt;
===Connection and usage===&lt;br /&gt;
&lt;br /&gt;
Once the RaceCapture App is running, it will connect automatically over USB.  You can use the app just as you would on Android or iOS.&lt;br /&gt;
&lt;br /&gt;
=Extra Features=&lt;br /&gt;
&lt;br /&gt;
===Hardwire buttons===&lt;br /&gt;
&lt;br /&gt;
The RaceCapture app responds to keyboard commands for certain behaviors. You can use a USB keyboard - or a device that emulates keyboard commands - to control the RaceCapture App.&lt;br /&gt;
&lt;br /&gt;
Currently there are keyboard commands for the following:&lt;br /&gt;
* &#039;&#039;&#039;Navigating dashboard screens&#039;&#039;&#039;  - Use the left and right arrow keys to switch between screens&lt;br /&gt;
* &#039;&#039;&#039;Escaping from screens / menus&#039;&#039;&#039; - The Escape key can be used to exit out of screens and options, just like the &#039;back&#039; button on Android.&lt;br /&gt;
* &#039;&#039;&#039;Acknowledging alerts&#039;&#039;&#039; - Use the following keys to acknowledge alerts, including responding to pit-to-car alerts:&lt;br /&gt;
** K : to indicate &#039;Yes&#039; or &#039;OK&#039;&lt;br /&gt;
** N : to indicate &#039;No&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Additional Tips=&lt;br /&gt;
See this link for additional tips on how to setup the Pi and speed up the boot times.  This should be especially helpful for beginners.&lt;br /&gt;
&lt;br /&gt;
https://wiki.autosportlabs.com/Raspberry_Pi_Tips&lt;br /&gt;
&lt;br /&gt;
Logfiles for troubleshooting can be found at&lt;br /&gt;
&lt;br /&gt;
/home/pi&lt;/div&gt;</summary>
		<author><name>Ddimensia</name></author>
	</entry>
	<entry>
		<id>https://wiki.autosportlabs.com/index.php?title=RaceCapture_on_Raspberry_Pi&amp;diff=9557</id>
		<title>RaceCapture on Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/index.php?title=RaceCapture_on_Raspberry_Pi&amp;diff=9557"/>
		<updated>2023-03-23T04:18:25Z</updated>

		<summary type="html">&lt;p&gt;Ddimensia: Updated instructions for using the rcdash_setup.sh script from https://github.com/autosportlabs/RC-App-RPi-install-script&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Introduction=&lt;br /&gt;
&lt;br /&gt;
We designed the RaceCapture app to run nearly anywhere - even a Raspberry Pi. And now, for about $100 you can create a hardwired, dedicated dash for your RaceCapture system. &lt;br /&gt;
&lt;br /&gt;
[[image:racecapture_raspberry_pi.jpg|1024px]]&lt;br /&gt;
&lt;br /&gt;
==Benefits==&lt;br /&gt;
You get all of the benefits of a dedicated dash:&lt;br /&gt;
* &#039;&#039;&#039;Automatically runs upon power up&#039;&#039;&#039; - you can configure the dash to automatically launch the RaceCapture App - just as you&#039;d expect it to work.&lt;br /&gt;
* &#039;&#039;&#039;Hard-wired data connection to RaceCapture&#039;&#039;&#039; - no wireless connections to configure, with the reliability of a direct wire.&lt;br /&gt;
* &#039;&#039;&#039;Runs on the bare metal&#039;&#039;&#039; - The RaceCapture app runs without Android or iOS; there&#039;s no other apps competing for resources, or compromising system stability. &lt;br /&gt;
* &#039;&#039;&#039;Overheating resistance&#039;&#039;&#039; -  Your typical mobile device requires extra care in very hot weather to prevent damage to it&#039;s internal battery, and will shut down if overheated. With proper heat-sinking, the Raspberry Pi should handle the heat.&lt;br /&gt;
&lt;br /&gt;
==Compatibility==&lt;br /&gt;
The RaceCapture app running on the Raspberry Pi is compatible with any hardware version of RaceCapture or PodiumConnect. &lt;br /&gt;
&lt;br /&gt;
[[image:racecapture_raspberry_pi_backside.jpg|1024px]]&lt;br /&gt;
&lt;br /&gt;
==Experimental!==&lt;br /&gt;
While the results are pretty great, these instructions are &#039;&#039;currently&#039;&#039; for those adventurous race car hackers who know their away around a command line, comfortable working with hardware and want to dig in.  &#039;&#039;&#039;Think it&#039;s cool, but too much to tackle?&#039;&#039;&#039; Rope in your nearest computer/electronics geek - you need one on your race team, anyway. :)  &#039;&#039;&#039;Or, just use the plug and play option&#039;&#039;&#039; and use an Android or iOS device via Bluetooth or WiFi.&lt;br /&gt;
&lt;br /&gt;
==Current status and future plans==&lt;br /&gt;
Even though this is brand new and officially experimental in nature, we still made it as easy as reasonably possible: we wrapped up the RaceCapture App into as close to a self-running installer, that can run on a bone stock Raspberry Pi image - only a few changes are required to the default image, detailed below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;However&#039;&#039;&#039;, in the near future we will create a dedicated Raspberry Pi image that you can burn to an SD card and simply boot up, and move towards more official support as we iron out the issues. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reporting issues and getting support===&lt;br /&gt;
Chances are you&#039;ll encounter an issue you&#039;ll want to report. Before you do that, [https://github.com/autosportlabs/RaceCapture_App/issues?q=is%3Aopen+is%3Aissue+label%3A%22raspberry+pi%22 check the issue log] to see if it&#039;s already known.&lt;br /&gt;
&lt;br /&gt;
Otherwise - the best place for support, feedback and sharing success stories is [http://forum.autosportlabs.com on the  forums] .  Drop us a note there so we can see the progress of your project!&lt;br /&gt;
&lt;br /&gt;
=Hardware Selection=&lt;br /&gt;
===Raspberry Pi===&lt;br /&gt;
The RaceCapture app is compatible with Raspberry Pi 4 and 3.&lt;br /&gt;
We recommend the Raspberry Pi 4 2GB and higher for best performance and support.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
The RaceCapture app package is designed to recognize the following screens:&lt;br /&gt;
&lt;br /&gt;
* [https://www.raspberrypi.org/products/raspberry-pi-touch-display/ Official Raspberry Pi display] with capacitive touch screen;&lt;br /&gt;
* Displays supporting the AR1100 resistive touch screen controller.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Other displays can work as well, and additional work may be needed to support the screen&#039;s touch controller. If unsure, just pick the [https://www.raspberrypi.org/products/raspberry-pi-touch-display/ Official Raspberry Pi display]&lt;br /&gt;
===Enclosure===&lt;br /&gt;
A recommended enclosure is the [http://https://www.amazon.com/dp/B01HV97F64 Smart Pi Touch Case]&lt;br /&gt;
&lt;br /&gt;
You can 3D print a sun shade for this enclosure  [[file:P001 Raspberry Pi Display Sun Shade.stl.zip|download the .stl file]] (&#039;&#039;Courtesy of Michael Lee&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
[[image:SmartPi_touch_case.jpg|400px]] [[image:RaceCapture_Sun_shade_3dprinted_preview.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
[[image:RaceCapture_RaspberryPi_sun_shade_dashboard.jpg|800px]]&lt;br /&gt;
&lt;br /&gt;
Installed on Dashboard&lt;br /&gt;
&lt;br /&gt;
===Power Supply===&lt;br /&gt;
The Raspberry Pi dashboard requires its own power supply.  You&#039;ll need a high quality 5v power supply with 2 amps minimum capacity; 3 amps is highly recommended, and ideally one with a low drop out voltage, so power is not cut to the Raspberry Pi when you&#039;re loading the main battery, such as when cranking the engine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Suggested Power Supplies&#039;&#039;&#039;&lt;br /&gt;
* [https://www.amazon.com/Jabinco-LM2596-Converter-3-0-40V-1-5-35V/dp/B0817P8BGB/ Buck Converter based on the LM2596]&lt;br /&gt;
&lt;br /&gt;
====Powering RaceCapture====&lt;br /&gt;
After you have power to the Raspberry Pi dashboard, you may notice your RaceCapture device will be powered by the USB cable connected to the Pi, just as if you&#039;re powering RaceCapture from your laptop.  &#039;&#039;&#039;You will still want to power your RaceCapture via 12v&#039;&#039;&#039;; see the respective installation guides for information on how to power your device.&lt;br /&gt;
&lt;br /&gt;
===Heat sinking===&lt;br /&gt;
If you&#039;re running in hot weather, we recommend the standard Raspberry Pi heatsink kit to keep your system cool.&lt;br /&gt;
&lt;br /&gt;
For Pi4 users, we recommend active fan cooling in addition to the heat sink.&lt;br /&gt;
&lt;br /&gt;
=Installation=&lt;br /&gt;
==Installing Raspberry Pi OS==&lt;br /&gt;
We currently recommend Raspberry Pi OS Lite, Debian Version 11 (bullseye) and require a 64bit version for app versions 2.9.0 and newer. &lt;br /&gt;
&lt;br /&gt;
Download from [https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-64-bit the official site] or use the [https://www.raspberrypi.com/software/ Raspberry Pi imager], following the instructions for burning to an SD card. &lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve created your image, boot up your Raspberry Pi and follow the prompts to set your keyboard language and create a username and password.&lt;br /&gt;
&lt;br /&gt;
You should now be able to login as that user and will be greeted with a command prompt like `user@raspberrypi:~ $`&lt;br /&gt;
&lt;br /&gt;
===Wifi Setup===&lt;br /&gt;
Unless you are using a network cable you will need to setup Wifi before proceeding.  To do this you need to run the command `sudo raspi-config`,&lt;br /&gt;
this will bring up a window with several options.  To configure Wifi you will want to select `1 System Options` followed by `S1 Wireless LAN`.  It will ask you to select your Wifi country and set your network SSID and network password.&lt;br /&gt;
&lt;br /&gt;
===Timezone===&lt;br /&gt;
It is advisable to set the system&#039;s timezone before proceeding.  This is also accomplished by using raspi-config which is run with the command `sudo raspi-config`.  If you are also setting up Wifi you can configure your timezone at the same time you are configuring Wifi.  &lt;br /&gt;
&lt;br /&gt;
The timezone setting is configured in `5 Localization Options`-&amp;gt;`L2 Timezone`.  This will allow you to set the timezone by first selecting your region and a major city in your timezone.  When done setting the timezone you can back out of raspi-config by hitting escape until you are back at the command prompt.&lt;br /&gt;
&lt;br /&gt;
===Checking your network===&lt;br /&gt;
At this point it is good to make sure your Raspberry Pi is connected to your network.  Without this none of the remaining steps will be successful. &lt;br /&gt;
&lt;br /&gt;
An easy way to check that you are connected to the network is to use the command `hostname -I`, this will print out the IP address of your&lt;br /&gt;
Raspberry Pi, or a blank line if you are not connected.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
user@raspberrypi:~ $ hostname -I&lt;br /&gt;
192.168.1.183 2601:601:d07f:c107:dfb6:823:b21d:6dff&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating to latest packages===&lt;br /&gt;
It is always good form to update the latest packages after a fresh install. Enter this at the command line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt dist-upgrade&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==RaceCapture App Installation==&lt;br /&gt;
For those wanting an installation that automatically launches the dashboard upon login, we have developed&lt;br /&gt;
an installation script.  The installation script allows for the selection of either running against the &lt;br /&gt;
framebuffer or X11, and helps in setting up standard Raspberry Pi configuration settings. As a bonus the installation&lt;br /&gt;
script also includes optional features such as Wifi auto reconnect, USB drive automounting and GPIO based shutdown&lt;br /&gt;
reboot support.&lt;br /&gt;
&lt;br /&gt;
If you want a more custom installation, such as running in a full Desktop environment, manual instructions are also provided. &lt;br /&gt;
===Via Installation Script===&lt;br /&gt;
From a command prompt simply run&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo sh -c &amp;quot;curl -sL bit.ly/3yTbPyZ | bash&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The installation script will setup the system configuration files so that screen blanking is disabled and GPU memory is set to 256MB.&lt;br /&gt;
It will then prompt with a series of questions and configuration options, allowing you to customize the installation.&lt;br /&gt;
====Configuration Options====&lt;br /&gt;
The installation script prompts for the following:&lt;br /&gt;
=====Auto Login=====&lt;br /&gt;
* Whether to enable auto login upon startup, if not already enabled (Recommendation: Yes)&lt;br /&gt;
** This allows the RPi to login as the current user and launch the RaceCapture App upon startup of your Raspberry Pi. Without this you will need to login every time your Raspberry Pi is powered up.&lt;br /&gt;
=====RPi3 Official Display Support=====&lt;br /&gt;
* If running an RPi3, whether you are running an Official RPi display.&lt;br /&gt;
** Only select yes if you are using a RPi3 with an Official RPi display plugged into the LCD/MIPI connector on the board. Enabling this will disable HDMI support as the RPi3 doesn&#039;t appear to automatically detect LCD screens properly.&lt;br /&gt;
=====Installation Type=====&lt;br /&gt;
* Which type of installation you want, Framebuffer (traditional installation), or X11 which enables the option of VNC support&lt;br /&gt;
* If X11 was chosen:&lt;br /&gt;
** Whether to enable VNC and if so prompts for entering a VNC password&lt;br /&gt;
=====App Features=====&lt;br /&gt;
* Watchdog: Enables automatically restarting the RaceCapture App should it crash/exit unexpectedly&lt;br /&gt;
* Cursor: Enables a visual mouse pointer (Not recommended for touchscreens)&lt;br /&gt;
* Keyboard: Enables an onscreen virtual keyboard for touch screens&lt;br /&gt;
=====Extra Features=====&lt;br /&gt;
* Wifi Auto Reconnect: Enables a script that detects if your wifi connection is down and attempts to reconnect&lt;br /&gt;
* USB Automounting: Enables automatic mounting of USB thumbdrives under /media/usb#, useful for exporting session data or saving configs off the device&lt;br /&gt;
* GPIO Reboot/Shutdown: Enables the ability to add a button or switch between GPIO21 and a ground pin, with a short press causing a reboot and a long press causing a graceful shutdown&lt;br /&gt;
&lt;br /&gt;
====Post Configuration Steps====&lt;br /&gt;
After you have selected your configuration options the installation script will proceed to download the latest RaceCapture App bundle from&lt;br /&gt;
[http://podium.live/software the Podium website], placing it in /opt.  If the latest version is already present in /opt it will skip this step.&lt;br /&gt;
&lt;br /&gt;
Next it will unpack the App into /opt/racecapture, prompting you to overwrite and existing installation if one exists.&lt;br /&gt;
&lt;br /&gt;
Finally, the script will modify some files, .bashrc and .xinitrc for X11 installations, so that the Race Capture app launches upon login.&lt;br /&gt;
&lt;br /&gt;
===Manual Installation===&lt;br /&gt;
If you choose to install the RaceCapture App manually it&#039;s assumed that you have an understanding of the different configuration and installation&lt;br /&gt;
options available for the Raspberry Pi.  Below is the minimal requirements to run the RaceCapture App via the Framebuffer. &lt;br /&gt;
If running in an X11/desktop environment the same instructions should be adequate for running the app in that environment also.&lt;br /&gt;
&lt;br /&gt;
====Install package dependencies====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt install mesa-utils libgles2 libegl1-mesa libegl-mesa0 mtdev-tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====User Permissions====&lt;br /&gt;
Ensure that the user is in the dialout, render, video and input groups.  It appears these are added by default but to be sure you should run:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo adduser $USER render&lt;br /&gt;
sudo adduser $USER video&lt;br /&gt;
sudo adduser $USER input&lt;br /&gt;
sudo adduser $USER dialout&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Installing the RaceCapture app package====&lt;br /&gt;
&lt;br /&gt;
Download the latest [http://podium.live/software RaceCapture app package for Raspberry Pi] and place it in the /opt/ directory of the Raspberry Pi.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Directly downloading to the Raspberry Pi&#039;&#039;&#039;&lt;br /&gt;
You can download it directly by getting the URL of the package by right-clicking the download link and copying the URL to your clipboard. Then, use it in the command below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /opt&lt;br /&gt;
sudo wget &amp;lt;package URL&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Extract the package=====&lt;br /&gt;
Now extract the downloaded package :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo tar -xjvf &amp;lt;downloaded file&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Launch the app====&lt;br /&gt;
Launch the RaceCapture app by running the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Launching with Watchdog====&lt;br /&gt;
You can enable an automatic watchdog that re-launches the app in case a crash occurs. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh -w 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; You can break out of the application by issuing &#039;&#039;&#039;Alt + PrntScn + k&#039;&#039;&#039; to the application. &lt;br /&gt;
&lt;br /&gt;
You can further stop all racecapture processes by issuing the following command (e.g. via ssh)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
killall -9 run_racecapture&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enabling on screen keyboard====&lt;br /&gt;
If you don&#039;t have a wireless keyboard attached via usb, you can enable an on-screen keyboard.&lt;br /&gt;
&lt;br /&gt;
Edit the kivy config.ini file with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo nano ~/.kivy/config.ini&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and update the keyboard_mode line with:&lt;br /&gt;
&lt;br /&gt;
keyboard_mode = multi&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Connecting to your RaceCapture system=&lt;br /&gt;
[[image:racecapture_raspberry_pi_connections.jpg|900px]]&lt;br /&gt;
===Powering up===&lt;br /&gt;
* Connect your RaceCapture/Pro or RaceCapture/Track to the Raspberry Pi using the USB cable. &lt;br /&gt;
* Connect the power to your display and power up.  &lt;br /&gt;
&lt;br /&gt;
====Installed via Script====&lt;br /&gt;
If you installed via the setup script and enabled autologin, simply let it start upon power-up.  &lt;br /&gt;
Without autologin you will need to first login as your default user.&lt;br /&gt;
&lt;br /&gt;
====Manual Installation====&lt;br /&gt;
See [[#Launch_the_app]]&lt;br /&gt;
&lt;br /&gt;
===Connection and usage===&lt;br /&gt;
&lt;br /&gt;
Once the RaceCapture App is running, it will connect automatically over USB.  You can use the app just as you would on Android or iOS.&lt;br /&gt;
&lt;br /&gt;
=Extra Features=&lt;br /&gt;
&lt;br /&gt;
===Hardwire buttons===&lt;br /&gt;
&lt;br /&gt;
The RaceCapture app responds to keyboard commands for certain behaviors. You can use a USB keyboard - or a device that emulates keyboard commands - to control the RaceCapture App.&lt;br /&gt;
&lt;br /&gt;
Currently there are keyboard commands for the following:&lt;br /&gt;
* &#039;&#039;&#039;Navigating dashboard screens&#039;&#039;&#039;  - Use the left and right arrow keys to switch between screens&lt;br /&gt;
* &#039;&#039;&#039;Escaping from screens / menus&#039;&#039;&#039; - The Escape key can be used to exit out of screens and options, just like the &#039;back&#039; button on Android.&lt;br /&gt;
* &#039;&#039;&#039;Acknowledging alerts&#039;&#039;&#039; - Use the following keys to acknowledge alerts, including responding to pit-to-car alerts:&lt;br /&gt;
** K : to indicate &#039;Yes&#039; or &#039;OK&#039;&lt;br /&gt;
** N : to indicate &#039;No&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Additional Tips=&lt;br /&gt;
See this link for additional tips on how to setup the Pi and speed up the boot times.  This should be especially helpful for beginners.&lt;br /&gt;
&lt;br /&gt;
https://wiki.autosportlabs.com/Raspberry_Pi_Tips&lt;br /&gt;
&lt;br /&gt;
Logfiles for troubleshooting can be found at&lt;br /&gt;
&lt;br /&gt;
/home/pi&lt;/div&gt;</summary>
		<author><name>Ddimensia</name></author>
	</entry>
	<entry>
		<id>https://wiki.autosportlabs.com/index.php?title=RaceCapture_on_Raspberry_Pi&amp;diff=9556</id>
		<title>RaceCapture on Raspberry Pi</title>
		<link rel="alternate" type="text/html" href="https://wiki.autosportlabs.com/index.php?title=RaceCapture_on_Raspberry_Pi&amp;diff=9556"/>
		<updated>2023-03-21T05:06:02Z</updated>

		<summary type="html">&lt;p&gt;Ddimensia: /* Installing Rasbian OS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Introduction=&lt;br /&gt;
&lt;br /&gt;
We designed the RaceCapture app to run nearly anywhere - even a Raspberry Pi. And now, for about $100 you can create a hardwired, dedicated dash for your RaceCapture system. &lt;br /&gt;
&lt;br /&gt;
[[image:racecapture_raspberry_pi.jpg|1024px]]&lt;br /&gt;
&lt;br /&gt;
==Benefits==&lt;br /&gt;
You get all of the benefits of a dedicated dash:&lt;br /&gt;
* &#039;&#039;&#039;Automatically runs upon power up&#039;&#039;&#039; - you can configure the dash to automatically launch the RaceCapture App - just as you&#039;d expect it to work.&lt;br /&gt;
* &#039;&#039;&#039;Hard-wired data connection to RaceCapture&#039;&#039;&#039; - no wireless connections to configure, with the reliability of a direct wire.&lt;br /&gt;
* &#039;&#039;&#039;Runs on the bare metal&#039;&#039;&#039; - The RaceCapture app runs without Android or iOS; there&#039;s no other apps competing for resources, or compromising system stability. &lt;br /&gt;
* &#039;&#039;&#039;Overheating resistance&#039;&#039;&#039; -  Your typical mobile device requires extra care in very hot weather to prevent damage to it&#039;s internal battery, and will shut down if overheated. With proper heat-sinking, the Raspberry Pi should handle the heat.&lt;br /&gt;
&lt;br /&gt;
==Compatibility==&lt;br /&gt;
The RaceCapture app running on the Raspberry Pi is compatible with any hardware version of RaceCapture or PodiumConnect. &lt;br /&gt;
&lt;br /&gt;
[[image:racecapture_raspberry_pi_backside.jpg|1024px]]&lt;br /&gt;
&lt;br /&gt;
==Experimental!==&lt;br /&gt;
While the results are pretty great, these instructions are &#039;&#039;currently&#039;&#039; for those adventurous race car hackers who know their away around a command line, comfortable working with hardware and want to dig in.  &#039;&#039;&#039;Think it&#039;s cool, but too much to tackle?&#039;&#039;&#039; Rope in your nearest computer/electronics geek - you need one on your race team, anyway. :)  &#039;&#039;&#039;Or, just use the plug and play option&#039;&#039;&#039; and use an Android or iOS device via Bluetooth or WiFi.&lt;br /&gt;
&lt;br /&gt;
==Current status and future plans==&lt;br /&gt;
Even though this is brand new and officially experimental in nature, we still made it as easy as reasonably possible: we wrapped up the RaceCapture App into as close to a self-running installer, that can run on a bone stock Raspberry Pi image - only a few changes are required to the default image, detailed below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;However&#039;&#039;&#039;, in the near future we will create a dedicated Raspberry Pi image that you can burn to an SD card and simply boot up, and move towards more official support as we iron out the issues. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reporting issues and getting support===&lt;br /&gt;
Chances are you&#039;ll encounter an issue you&#039;ll want to report. Before you do that, [https://github.com/autosportlabs/RaceCapture_App/issues?q=is%3Aopen+is%3Aissue+label%3A%22raspberry+pi%22 check the issue log] to see if it&#039;s already known.&lt;br /&gt;
&lt;br /&gt;
Otherwise - the best place for support, feedback and sharing success stories is [http://forum.autosportlabs.com on the  forums] .  Drop us a note there so we can see the progress of your project!&lt;br /&gt;
&lt;br /&gt;
=Hardware Selection=&lt;br /&gt;
===Raspberry Pi===&lt;br /&gt;
We recommend the Raspberry Pi 4 2GB and higher for best performance and support.&lt;br /&gt;
&lt;br /&gt;
===Display===&lt;br /&gt;
The RaceCapture app package is designed to recognize the following screens:&lt;br /&gt;
&lt;br /&gt;
* [https://www.raspberrypi.org/products/raspberry-pi-touch-display/ Official Raspberry Pi display] with capacitive touch screen;&lt;br /&gt;
* Displays supporting the AR1100 resistive touch screen controller.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Other displays can work as well, and additional work may be needed to support the screen&#039;s touch controller. If unsure, just pick the [https://www.raspberrypi.org/products/raspberry-pi-touch-display/ Official Raspberry Pi display]&lt;br /&gt;
===Enclosure===&lt;br /&gt;
A recommended enclosure is the [http://https://www.amazon.com/dp/B01HV97F64 Smart Pi Touch Case]&lt;br /&gt;
&lt;br /&gt;
You can 3D print a sun shade for this enclosure  [[file:P001 Raspberry Pi Display Sun Shade.stl.zip|download the .stl file]] (&#039;&#039;Courtesy of Michael Lee&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
[[image:SmartPi_touch_case.jpg|400px]] [[image:RaceCapture_Sun_shade_3dprinted_preview.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
[[image:RaceCapture_RaspberryPi_sun_shade_dashboard.jpg|800px]]&lt;br /&gt;
&lt;br /&gt;
Installed on Dashboard&lt;br /&gt;
&lt;br /&gt;
===Power Supply===&lt;br /&gt;
The Raspberry Pi dashboard requires its own power supply.  You&#039;ll need a high quality 5v power supply with 2 amps minimum capacity; 3 amps is highly recommended, and ideally one with a low drop out voltage, so power is not cut to the Raspberry Pi when you&#039;re loading the main battery, such as when cranking the engine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Suggested Power Supplies&#039;&#039;&#039;&lt;br /&gt;
* [https://www.amazon.com/Jabinco-LM2596-Converter-3-0-40V-1-5-35V/dp/B0817P8BGB/ Buck Converter based on the LM2596]&lt;br /&gt;
&lt;br /&gt;
====Powering RaceCapture====&lt;br /&gt;
After you have power to the Raspberry Pi dashboard, you may notice your RaceCapture device will be powered by the USB cable connected to the Pi, just as if you&#039;re powering RaceCapture from your laptop.  &#039;&#039;&#039;You will still want to power your RaceCapture via 12v&#039;&#039;&#039;; see the respective installation guides for information on how to power your device.&lt;br /&gt;
&lt;br /&gt;
===Heat sinking===&lt;br /&gt;
If you&#039;re running in hot weather, we recommend the standard Raspberry Pi heatsink kit to keep your system cool.&lt;br /&gt;
&lt;br /&gt;
For Pi4 users, we recommend active fan cooling in addition to the heat sink.&lt;br /&gt;
&lt;br /&gt;
=Installation=&lt;br /&gt;
==Installing Rasbian OS==&lt;br /&gt;
We currently recommend Raspberry Pi OS Lite, Debian Version 11 (bullseye) and require a 64bit version for app versions 2.9.0 and newer. &lt;br /&gt;
&lt;br /&gt;
Download from [https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-64-bit the official site] or use the [https://www.raspberrypi.com/software/ Raspberry Pi imager], following the instructions for burning to an SD card. &lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve created your image, boot up your Raspberry Pi and follow the prompts to set your keyboard language and create a username and password.&lt;br /&gt;
&lt;br /&gt;
You should now be able to login as that user and will be greeted with a command prompt like `user@raspberrypi:~ $`&lt;br /&gt;
&lt;br /&gt;
===Wifi Setup===&lt;br /&gt;
Unless you are using a network cable you will need to setup Wifi before proceeding.  To do this you need to run the command `sudo raspi-config`,&lt;br /&gt;
this will bring up a window with several options.  To configure Wifi you will want to select `1 System Options` followed by `S1 Wireless LAN`.  It will ask you to select your Wifi country and set your network SSID and network password.&lt;br /&gt;
&lt;br /&gt;
===Timezone===&lt;br /&gt;
It is advisable to set the system&#039;s timezone before proceeding.  This is also accomplished by using raspi-config which is run with the command `sudo raspi-config`.  If you are also setting up Wifi you can configure your timezone at the same time you are configuring Wifi.  &lt;br /&gt;
&lt;br /&gt;
The timezone setting is configured in `5 Localization Options`-&amp;gt;`L2 Timezone`.  This will allow you to set the timezone by first selecting your region and a major city in your timezone.  When done setting the timezone you can back out of raspi-config by hitting escape until you are back at the command prompt.&lt;br /&gt;
&lt;br /&gt;
===Checking your network===&lt;br /&gt;
At this point it is good to make sure your Raspberry Pi is connected to your network.  Without this none of the remaining steps will be successful. &lt;br /&gt;
&lt;br /&gt;
An easy way to check that you are connected to the network is to use the command `hostname -I`, this will print out the IP address of your&lt;br /&gt;
Raspberry Pi, or a blank line if you are not connected.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
user@raspberrypi:~ $ hostname -I&lt;br /&gt;
192.168.1.183 2601:601:d07f:c107:dfb6:823:b21d:6dff&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating to latest packages===&lt;br /&gt;
It is always good form to update the latest packages after a fresh install. Enter this at the command line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt dist-upgrade&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Raspberry Pi support==&lt;br /&gt;
The RaceCapture app is compatible with Raspberry Pi 4 and 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Enable GPU driver===&lt;br /&gt;
Enable Fake KMS under advanced boot options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo raspi-config&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Go to Advanced Options -&amp;gt; GL Driver -&amp;gt; Select OpenGL desktop driver with fake KMS&lt;br /&gt;
&lt;br /&gt;
* Be sure to reboot after exiting raspi-config&lt;br /&gt;
&lt;br /&gt;
==Installing dependencies==&lt;br /&gt;
===Activate ssh===&lt;br /&gt;
Ssh is used to store passwords used by the app. Steps to ensure it is running:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo raspi-config&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Go under Interfacing Options or Advanced Options and start the ssh service. &lt;br /&gt;
&lt;br /&gt;
Next, at the command prompt enter&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-add&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
to create at least one key.&lt;br /&gt;
&lt;br /&gt;
===Install package dependencies===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get install mesa-utils libgles2 libegl1-mesa libegl-mesa0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Change the default password===&lt;br /&gt;
For maximum security, change the password for the default user &#039;pi&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt; passwd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and specify a new, secure password.&lt;br /&gt;
&lt;br /&gt;
===Configure Raspberry Pi base settings===&lt;br /&gt;
====Enable Hardware rendering====&lt;br /&gt;
Enter the following line to enable hardware accelerated rendering.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt; sudo adduser pi render&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Notes&#039;&#039;&#039;:&lt;br /&gt;
** Without this setting, UI rendering will be extremely slow.&lt;br /&gt;
** Assumes RaceCapture is launched as pi. If not, replace pi with the user you are logging in as.&lt;br /&gt;
** If you&#039;re coming in to fix this after the fact, you&#039;ll need to reboot/re-login to take effect.&lt;br /&gt;
&lt;br /&gt;
====Enable WiFi====&lt;br /&gt;
If you want network capability in addition to the ethernet connection, [https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md enable and configure WiFi per the official documentation]&lt;br /&gt;
&lt;br /&gt;
====(Optional) Enable SSH====&lt;br /&gt;
You can optionally enable SSH for remote management from the comfort of your main computer&#039;s keyboard and screen. &lt;br /&gt;
&lt;br /&gt;
[https://www.raspberrypi.org/documentation/remote-access/ssh/ Enable and configure ssh per the official documentation]&lt;br /&gt;
&lt;br /&gt;
====Install multi-touch tools====&lt;br /&gt;
Install the packages that enable multi-touch interfaces.  Enter the following at the command line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt; sudo apt-get install mtdev-tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Configure memory split====&lt;br /&gt;
You&#039;ll need to bump up the memory made available to the GPU. Increase the default value of 64 to &#039;&#039;&#039;256&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Via raspi-config tool&#039;&#039;&#039;&lt;br /&gt;
You can adjust the memory split by running the raspi-config tool. See the [https://www.raspberrypi.org/documentation/configuration/raspi-config.md official documentation]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Editing /boot/config.txt&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can adjust the value directly by editing the /boot/config.txt file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt; sudo nano /boot/config.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Find the line containing gpu_mem=64 and change the number to 256&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
gpu_mem=256&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Save the file by pressing &#039;&#039;&#039;ctrl-x&#039;&#039;&#039; then  press &#039;&#039;&#039;Y&#039;&#039;&#039;  to confirm.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Installing the RaceCapture app package==&lt;br /&gt;
&lt;br /&gt;
Download the latest [http://podium.live/software RaceCapture app package for Raspberry Pi] and place it in the /opt/ directory of the Raspberry Pi.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Directly downloading to the Raspberry Pi&#039;&#039;&#039;&lt;br /&gt;
You can download it directly by getting the URL of the package by right-clicking the download link and copying the URL to your clipboard. Then, use it in the command below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /opt&lt;br /&gt;
sudo wget &amp;lt;package URL&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Extract the package===&lt;br /&gt;
Now extract the downloaded package :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo tar -xjvf &amp;lt;downloaded file&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Launch the app===&lt;br /&gt;
Launch the RaceCapture app by running the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Launching with Watchdog===&lt;br /&gt;
You can enable an automatic watchdog that re-launches the app in case a crash occurs. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh -w 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; You can break out of the application by issuing &#039;&#039;&#039;Alt + PrntScn + k&#039;&#039;&#039; to the application. &lt;br /&gt;
&lt;br /&gt;
You can further stop all racecapture processes by issuing the following command (e.g. via ssh)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
killall -9 run_racecapture&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Enabling on screen keyboard===&lt;br /&gt;
If you don&#039;t have a wireless keyboard attached via usb, you can enable an on-screen keyboard.&lt;br /&gt;
&lt;br /&gt;
Edit the kivy config.ini file with:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo nano ~/.kivy/config.ini&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and update the keyboard_mode line with:&lt;br /&gt;
&lt;br /&gt;
keyboard_mode = multi&lt;br /&gt;
&lt;br /&gt;
==Automatic start upon power up==&lt;br /&gt;
To get the full dedicated dashboard experience, you can enable automatic launch of the RaceCapture app upon power up. &lt;br /&gt;
&lt;br /&gt;
To do this, edit the system&#039;s startup file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo nano /etc/rc.local&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and add the following line &#039;&#039;&#039;before the exit 0&#039;&#039;&#039; line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/boot_racecapture.sh pi&lt;br /&gt;
&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Save the file by pressing &#039;&#039;&#039;ctrl-x&#039;&#039;&#039; then  press &#039;&#039;&#039;Y&#039;&#039;&#039;  to confirm.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Connecting to your RaceCapture system=&lt;br /&gt;
[[image:racecapture_raspberry_pi_connections.jpg|900px]]&lt;br /&gt;
===Powering up===&lt;br /&gt;
* Connect the power to your display and power up. &lt;br /&gt;
* Connect your RaceCapture/Pro or RaceCapture/Track to the Raspberry Pi using the USB cable.  &lt;br /&gt;
&lt;br /&gt;
* Launch the RaceCapture app by running:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/racecapture/run_racecapture.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you have it set to launch automatically, simply let it start upon power-up.&lt;br /&gt;
&lt;br /&gt;
===Connection and usage===&lt;br /&gt;
&lt;br /&gt;
Once the RaceCapture App is running, it will connect automatically over USB.  You can use the app just as you would on Android or iOS.&lt;br /&gt;
&lt;br /&gt;
=Extra Features=&lt;br /&gt;
&lt;br /&gt;
===Hardwire buttons===&lt;br /&gt;
&lt;br /&gt;
The RaceCapture app responds to keyboard commands for certain behaviors. You can use a USB keyboard - or a device that emulates keyboard commands - to control the RaceCapture App.&lt;br /&gt;
&lt;br /&gt;
Currently there are keyboard commands for the following:&lt;br /&gt;
* &#039;&#039;&#039;Navigating dashboard screens&#039;&#039;&#039;  - Use the left and right arrow keys to switch between screens&lt;br /&gt;
* &#039;&#039;&#039;Escaping from screens / menus&#039;&#039;&#039; - The Escape key can be used to exit out of screens and options, just like the &#039;back&#039; button on Android.&lt;br /&gt;
* &#039;&#039;&#039;Acknowledging alerts&#039;&#039;&#039; - Use the following keys to acknowledge alerts, including responding to pit-to-car alerts:&lt;br /&gt;
** K : to indicate &#039;Yes&#039; or &#039;OK&#039;&lt;br /&gt;
** N : to indicate &#039;No&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Additional Tips=&lt;br /&gt;
See this link for additional tips on how to setup the Pi and speed up the boot times.  This should be especially helpful for beginners.&lt;br /&gt;
&lt;br /&gt;
https://wiki.autosportlabs.com/Raspberry_Pi_Tips&lt;br /&gt;
&lt;br /&gt;
Logfiles for troubleshooting can be found at&lt;br /&gt;
&lt;br /&gt;
/home/pi&lt;/div&gt;</summary>
		<author><name>Ddimensia</name></author>
	</entry>
</feed>