Trying to turn serial data into a multi function button.

Hello everyone.

I'm to interface with my cars linbus system. The plan would be to read the buttons and then send a keyboard command to a pc ( I'm using a Pro Micro). I've got the hardware all set up and its working fine using this code. GitHub - laurynas/volvo_linbus: Volvo LIN bus reader which I've modified a bit. Now where I'm stuck is trying to implement a multi click /hold code like this Single, double and hold button - Syntax & Programs - Arduino Forum .

Currently I've tried reading all the bytes into a string which i could then compare to known data but i can't figure out how to proceed from there.

I'm still very new to programming so any help would be appreciated.

Code from laurynas that I've modified.

// https://github.com/zapta/linbus/tree/master/analyzer/arduino
#include "lin_frame.h"

// Pins we use for MCP2004

#define FAULT_PIN 8
#define CS_PIN 9

#define SYN_FIELD 0x55
#define SWM_ID 0x20

//Lbus = LIN BUS from Car
//Vss = Ground
//Vbb = +12V

// MCP2004 LIN bus frame:
// ZERO_BYTE SYN_BYTE ID_BYTE DATA_BYTES.. CHECKSUM_BYTE

// Volvo V50 2007 SWM key codes

// BTN_NEXT       20 0 10 0 0 EF // 3201600239
// BTN_PREV       20 0 2 0 0 FD //320200253
// BTN_VOL_UP     20 0 0 1 0 FE //320010254
// BTN_VOL_DOWN   20 0 80 0 0 7F
// BTN_BACK       20 0 1 0 0 F7
// BTN_ENTER      20 0 8 0 0 FE
// BTN_UP         20 1 0 0 0 FE
// BTN_DOWN       20 2 0 0 0 FD
// BTN_LEFT       20 4 0 0 0 FB
// BTN_RIGHT      20 8 0 0 0 F7

// IGN_KEY_ON     50 E 0 F1

String Message;
String MessageTemp;
byte b, i, n;
LinFrame frame;

void setup() {
  pinMode(17, OUTPUT);

  // Open serial communications to host (PC) and wait for port to open:
  Serial.begin(9600);
    
  Serial.println("LIN Debugging begins");

  Serial1.begin(9600);

  pinMode(CS_PIN, OUTPUT);
  digitalWrite(CS_PIN, HIGH);

  pinMode(FAULT_PIN, OUTPUT);
  digitalWrite(FAULT_PIN, HIGH);

  frame = LinFrame();
}

void loop() {
  if (Serial1.available()) {
    b = Serial1.read();
    n = frame.num_bytes();

    if (b == SYN_FIELD && n > 2 && frame.get_byte(n - 1) == 0) {
      digitalWrite(17, HIGH);
      frame.pop_byte();
      handle_frame();
      frame.reset();
      digitalWrite(17, LOW);
    }
    
    else if (n == LinFrame::kMaxBytes) {
      frame.reset();
    }
    
    else {
      frame.append_byte(b);
    }
  }

}

void handle_frame() {
 if (frame.get_byte(0) != SWM_ID)
   return;

  // skip zero values 20 0 0 0 0 FF
  if (frame.get_byte(5) == 0xFF)
    return;

  if (!frame.isValid())
    return;


  dump_frame();
}

void dump_frame() {
  for (i = 0; i < frame.num_bytes(); i++) {
    Serial.print(frame.get_byte(i), HEX);
    Serial.print(" ");
    MessageTemp = frame.get_byte(i);
   Message += MessageTemp;
   
  }
  Serial.print(Message);
  Message = "";
  Serial.println();
  
}

If I got this right, this is the code that printing the data to serial monitor:

void dump_frame() {
  for (i = 0; i < frame.num_bytes(); i++) {
    Serial.print(frame.get_byte(i), HEX);
    Serial.print(" ");
    MessageTemp = frame.get_byte(i);
   Message += MessageTemp;
   
  }
  Serial.print(Message);
  Message = "";
  Serial.println();
  
}

which is basically everything ie Breakfield,Sync, PID, Data and checksum, correct?

the good thing is that the order is fixed and you can do the compare without using string!

I would used the 'union' function but if you are not too familiar with that just use a 'for' loop to compare the received data bytes with the "Volvo V50 2007 SWM key codes" bytes put in an array.

if all the the bytes match then print out the respective key that was pressed! :slight_smile:

hope that helps.

Thanks for the help. I think I understand the loop idea but would I then need to have a for loop for every button? (every loop comparing to that buttons byte array) . How would be the best way to implement a hold and single click function? Inside the if(Serial1.available() ) condition?

MartinKa:
Thanks for the help. I think I understand the loop idea but would I then need to have a for loop for every button? (every loop comparing to that buttons byte array) .

not necessarily... as mentioned already union probably would be easier here, however if I were using loops this is how I would do it

1.put all the 'key's into a 2d array. (rows being the key frames and columns the individual bytes)

  1. use a 'while' loop to loop until the key is found and a 'for'loop within it to a compare the received data bytes with the "Volvo V50 2007 SWM key codes" array. Each time the 'while' loop loops you move to the next row is the array

MartinKa:
How would be the best way to implement a hold and single click function? Inside the if(Serial1.available() ) condition?

I would use a counter to count how many time the same data frame (key) is received.

if count > x that means 'hold' condition
else 'click' condition