Add car-off shutdown detection to LIN_to_IR firmware
This commit is contained in:
@@ -85,6 +85,7 @@ uint32_t get_mce_code(uint8_t button) {
|
||||
case 4: return 0x800f0421; // RIGHT
|
||||
case 5: return 0x800f0422; // ENTER / OK
|
||||
case 6: return 0x800f0423; // BACK
|
||||
case 7: return 0x800f046f; // F12 (Shutdown)
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
@@ -105,6 +106,8 @@ unsigned long last_frame_time = 0;
|
||||
uint8_t current_button = 0;
|
||||
uint8_t toggle_bit = 0;
|
||||
unsigned long last_ir_send_time = 0;
|
||||
unsigned long last_lin_activity_time = 0;
|
||||
bool is_car_on = false;
|
||||
|
||||
void process_button_state(uint8_t active_button) {
|
||||
unsigned long now = millis();
|
||||
@@ -179,10 +182,15 @@ void setup() {
|
||||
LINBusSerial.begin(9600);
|
||||
frame = LinFrame();
|
||||
last_frame_time = millis();
|
||||
last_lin_activity_time = millis();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (LINBusSerial.available()) {
|
||||
last_lin_activity_time = millis();
|
||||
if (!is_car_on) {
|
||||
is_car_on = true;
|
||||
}
|
||||
b = LINBusSerial.read();
|
||||
n = frame.num_bytes();
|
||||
|
||||
@@ -201,4 +209,13 @@ void loop() {
|
||||
if (millis() - last_frame_time > 200) {
|
||||
current_button = 0;
|
||||
}
|
||||
|
||||
// Car off detection: if no LIN activity for 5 seconds, send F12 to trigger shutdown
|
||||
if (is_car_on && (millis() - last_lin_activity_time > 5000)) {
|
||||
is_car_on = false;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
send_ir_for_button(7, i & 1);
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,45 @@ The Steering Wheel Module (SWM) sends frames on LIN ID `0x20` with the navigatio
|
||||
| **RIGHT** | `d0 & 0x08` | `4` | `0x800f0421` | Navigate Right |
|
||||
| **ENTER** | `d1 & 0x08` | `5` | `0x800f0422` | Select / OK |
|
||||
| **BACK** | `d1 & 0x01` | `6` | `0x800f0423` | Back / Exit |
|
||||
| **F12 (Shutdown)** | LIN Silent > 5s | `7` | `0x800f046f` | Trigger Shutdown (via MacroDroid) |
|
||||
|
||||
*Note: In previous revisions, `ENTER` and `BACK` were reversed. This has been corrected so that pressing `ENTER` maps to `0x800f0422` and `BACK` maps to `0x800f0423`.*
|
||||
|
||||
## Car-Off (Shutdown) Detection
|
||||
|
||||
To automatically power off the Raspberry Pi when the car is turned off:
|
||||
1. **Activity Monitor**: The ATtiny monitors LIN bus activity. The Central Electronic Module (CEM) continuously polls the LIN bus when the ignition is on.
|
||||
2. **Timeout**: If no LIN serial data is received for 5 seconds, the ATtiny assumes the car is off.
|
||||
3. **Shutdown Signal**: It transitions the car status to "off" and sends the MCE code `0x800f046f` (mapped to `KEY_F12`) 3 times to ensure transmission reliability.
|
||||
4. **State Protection**: It will not send the shutdown command again until the car is turned back on and LIN traffic resumes (which sets `is_car_on` back to `true`).
|
||||
|
||||
## Raspberry Pi Configuration
|
||||
|
||||
### 1. Keymap Setup
|
||||
Remap scancode `0x800f046f` to `KEY_F12` on the Raspberry Pi:
|
||||
- The custom TOML configuration is saved at `/data/rc-rc6-mce.toml` on the Pi.
|
||||
- To apply it dynamically:
|
||||
```bash
|
||||
/vendor/bin/ir-keytable -w /data/rc-rc6-mce.toml
|
||||
```
|
||||
|
||||
### 2. MacroDroid Persistence & Trigger
|
||||
Configure two macros in **MacroDroid** to manage keymap loading and shutdown:
|
||||
|
||||
- **Macro 1: Load Keymap on Boot**
|
||||
- **Trigger**: *Device Boot*
|
||||
- **Action**: *Run Shell Command* (Check **Run as Root**)
|
||||
```bash
|
||||
/vendor/bin/ir-keytable -w /data/rc-rc6-mce.toml
|
||||
```
|
||||
|
||||
- **Macro 2: Shutdown on F12**
|
||||
- **Trigger**: *Media / Key Pressed* -> Select **F12**
|
||||
- **Action**: *Run Shell Command* (Check **Run as Root**)
|
||||
```bash
|
||||
reboot -p
|
||||
```
|
||||
|
||||
## Protocol and Timing
|
||||
|
||||
- **Protocol**: RC-6 Mode 6A (MCE).
|
||||
@@ -46,3 +82,4 @@ The Steering Wheel Module (SWM) sends frames on LIN ID `0x20` with the navigatio
|
||||
Since SoftwareSerial RX interrupts consume about 1ms per byte, they will disrupt the precise microsecond-level timing of bit-banged IR frames. To avoid this, interrupts are disabled (`noInterrupts()`) during the 37ms window of IR transmission and re-enabled (`interrupts()`) immediately afterward.
|
||||
2. **Release detection**:
|
||||
The SWM continuously transmits frames on the LIN bus. If no button frames are detected or a frame with all 0s is received, the current active button resets to idle. A timeout of `200ms` ensures that if the LIN bus goes quiet, button repeats cease immediately.
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[[protocols]]
|
||||
name = "rc-rc6-mce"
|
||||
protocol = "rc-6"
|
||||
[protocols.scancodes]
|
||||
0x800f041e = "KEY_UP"
|
||||
0x800f041f = "KEY_DOWN"
|
||||
0x800f0420 = "KEY_LEFT"
|
||||
0x800f0421 = "KEY_RIGHT"
|
||||
0x800f0422 = "KEY_OK"
|
||||
0x800f0423 = "KEY_EXIT"
|
||||
0x800f046f = "KEY_F12"
|
||||
Reference in New Issue
Block a user