Skip to content

Commit

Permalink
feat: adjustments in examples - still under construction
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Hirschenberger committed Jun 2, 2024
1 parent a44663f commit f03eb6b
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 88 deletions.
Original file line number Diff line number Diff line change
@@ -1,122 +1,161 @@
/* Brandon Matthews
* Developed for Arduino UNO and MCP2515
* Modified for PKP-3500-SI-MT
* Stefan Hirschenberger
* Example for PKP-3500-SI-MT on Adafruit Feather M4 Can
*/

// This library depends on and requires TimerOne library, SPI library, and autowp mcp2515 library v1.03
#include <BlinkMarinePkpCanOpen.h>
#include <mcp2515.h>
#define KEYPAD_BASE_ID 0x15

#define CS_PIN 10
#define INTERRUPT_PIN 3
#define KEYPAD_BASE_ID 0x15
#define ENABLE_PASSCODE false
#include <Adafruit_NeoPixel.h>
#include <BlinkMarinePkpCanOpen.h>
#include <CANSAME5x.h>

MCP2515 mcp2515(CS_PIN);
PkpKeypad keypad(mcp2515, INTERRUPT_PIN, KEYPAD_BASE_ID, ENABLE_PASSCODE);
//Prototype for hardware specific callback function
uint8_t transmittMessageCallBack(const struct can_frame& txMsg);

unsigned long currentMillis;
unsigned long key9OnTime = 0;
bool lastKey9State;
CANSAME5x CAN;
Pkp keypad(KEYPAD_BASE_ID, transmittMessageCallBack);
Adafruit_NeoPixel pixel(1, 8, NEO_GRB + NEO_KHZ800);

void setup() {

pinMode(LED_BUILTIN, OUTPUT);

Serial.begin(115200);
keypad.setSerial(&Serial); // Required for the keypad library to print things out to serial
while (!Serial) {
digitalWrite(LED_BUILTIN, (millis() % 500 > 250));
delay(10);
if (millis() > 5000) {
break;
}
}
digitalWrite(LED_BUILTIN, LOW);
Serial.println(F("PKP-3500-SI-MT Example Sketch started."));

// start the CAN bus at 250 kbps
if (!CAN.begin(250000)) {
Serial.println("Starting CAN failed!");
while (1) {
delay(10);
}
}
Serial.println("Starting CAN!");

uint8_t keypadPasscode[4] = {1, 2, 3, 4};
keypad.setKeypadPassword(keypadPasscode);
keypad.setKeyBrightness(70);
keypad.setBacklight(BACKLIGHT_AMBER, 10);
// register the receive callback
CAN.onReceive(onReceive);

// Set Key color and blink states
uint8_t colors1[4] = {PKP_COLOR_BLANK, PKP_COLOR_YELLOW, PKP_COLOR_BLANK,
PKP_COLOR_YELLOW}; // array for the 4 possible key states' respective colors
uint8_t blinks1[4] = {PKP_COLOR_BLANK, PKP_COLOR_BLANK, PKP_COLOR_CYAN, PKP_COLOR_BLANK};

keypad.setKeyColor(PKP_KEY_2, colors1, blinks1);
keypad.setKeyColor(PKP_KEY_3, colors1, blinks1);
keypad.setKeyColor(PKP_KEY_4, colors1, blinks1);
keypad.setKeyColor(PKP_KEY_5, colors1, blinks1);
keypad.setKeyColor(PKP_KEY_6, colors1, blinks1);
colors1[1] = PKP_COLOR_GREEN;
keypad.setKeyColor(PKP_KEY_7, colors1, blinks1);
keypad.setKeyColor(PKP_KEY_8, colors1, blinks1);
keypad.setKeyColor(PKP_KEY_9, colors1, blinks1);
keypad.setKeyColor(PKP_KEY_10, colors1, blinks1);
colors1[1] = PKP_COLOR_RED;
colors1[2] = PKP_COLOR_GREEN;
colors1[3] = PKP_COLOR_BLUE;
keypad.setKeyColor(PKP_KEY_12, colors1, blinks1);
keypad.setKeyColor(PKP_KEY_13, colors1, blinks1);
keypad.setKeyColor(PKP_KEY_14, colors1, blinks1);
keypad.setKeyColor(PKP_KEY_15, colors1, blinks1);

keypad.setKeyMode(PKP_KEY_1, PkpKeypad::KEY_MODE_MOMENTARY);
keypad.setKeyMode(PKP_KEY_2, PkpKeypad::KEY_MODE_MOMENTARY);
keypad.setKeyMode(PKP_KEY_3, PkpKeypad::KEY_MODE_MOMENTARY);
keypad.setKeyMode(PKP_KEY_4, PkpKeypad::KEY_MODE_MOMENTARY);
keypad.setKeyMode(PKP_KEY_5, PkpKeypad::KEY_MODE_MOMENTARY);
keypad.setKeyMode(PKP_KEY_6, PkpKeypad::KEY_MODE_MOMENTARY);
keypad.setKeyMode(PKP_KEY_7, PkpKeypad::KEY_MODE_TOGGLE);
keypad.setKeyMode(PKP_KEY_8, PkpKeypad::KEY_MODE_TOGGLE);
keypad.setKeyMode(PKP_KEY_9, PkpKeypad::KEY_MODE_TOGGLE);
keypad.setKeyMode(PKP_KEY_10, PkpKeypad::KEY_MODE_TOGGLE);
keypad.setKeyMode(PKP_KEY_11, PkpKeypad::KEY_MODE_MOMENTARY);
keypad.setKeyMode(PKP_KEY_12, PkpKeypad::KEY_MODE_CYCLE4);
keypad.setKeyMode(PKP_KEY_13, PkpKeypad::KEY_MODE_TOGGLE);
keypad.setKeyMode(PKP_KEY_14, PkpKeypad::KEY_MODE_TOGGLE);
keypad.setKeyMode(PKP_KEY_15, PkpKeypad::KEY_MODE_CYCLE4);


uint8_t defaultStates[PKP_MAX_KEY_AMOUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t colors1[4] = {Pkp::KEY_COLOR_BLANK, Pkp::KEY_COLOR_GREEN, Pkp::KEY_COLOR_BLANK, Pkp::KEY_COLOR_RED};
uint8_t blinks1[4] = {Pkp::KEY_COLOR_BLANK, Pkp::KEY_COLOR_BLANK, Pkp::KEY_COLOR_GREEN, Pkp::KEY_COLOR_BLANK};

keypad.setKeyColor(Pkp::KEY_2, colors1, blinks1);
keypad.setKeyColor(Pkp::KEY_3, colors1, blinks1);
keypad.setKeyColor(Pkp::KEY_4, colors1, blinks1);
keypad.setKeyColor(Pkp::KEY_5, colors1, blinks1);
keypad.setKeyColor(Pkp::KEY_6, colors1, blinks1);
colors1[1] = Pkp::KEY_COLOR_GREEN;
keypad.setKeyColor(Pkp::KEY_7, colors1, blinks1);
keypad.setKeyColor(Pkp::KEY_8, colors1, blinks1);
keypad.setKeyColor(Pkp::KEY_9, colors1, blinks1);
keypad.setKeyColor(Pkp::KEY_10, colors1, blinks1);
colors1[1] = Pkp::KEY_COLOR_RED;
colors1[2] = Pkp::KEY_COLOR_GREEN;
colors1[3] = Pkp::KEY_COLOR_BLUE;
keypad.setKeyColor(Pkp::KEY_12, colors1, blinks1);
keypad.setKeyColor(Pkp::KEY_13, colors1, blinks1);
keypad.setKeyColor(Pkp::KEY_14, colors1, blinks1);
keypad.setKeyColor(Pkp::KEY_15, colors1, blinks1);

keypad.setKeyMode(Pkp::KEY_1, Pkp::KEY_MODE_TOGGLE);
keypad.setKeyMode(Pkp::KEY_2, Pkp::KEY_MODE_MOMENTARY);
keypad.setKeyMode(Pkp::KEY_3, Pkp::KEY_MODE_MOMENTARY);
keypad.setKeyMode(Pkp::KEY_4, Pkp::KEY_MODE_MOMENTARY);
keypad.setKeyMode(Pkp::KEY_5, Pkp::KEY_MODE_MOMENTARY);
keypad.setKeyMode(Pkp::KEY_6, Pkp::KEY_MODE_MOMENTARY);
keypad.setKeyMode(Pkp::KEY_7, Pkp::KEY_MODE_TOGGLE);
keypad.setKeyMode(Pkp::KEY_8, Pkp::KEY_MODE_TOGGLE);
keypad.setKeyMode(Pkp::KEY_9, Pkp::KEY_MODE_TOGGLE);
keypad.setKeyMode(Pkp::KEY_10, Pkp::KEY_MODE_TOGGLE);
keypad.setKeyMode(Pkp::KEY_11, Pkp::KEY_MODE_MOMENTARY);
keypad.setKeyMode(Pkp::KEY_12, Pkp::KEY_MODE_CYCLE4);
keypad.setKeyMode(Pkp::KEY_13, Pkp::KEY_MODE_TOGGLE);
keypad.setKeyMode(Pkp::KEY_14, Pkp::KEY_MODE_TOGGLE);
keypad.setKeyMode(Pkp::KEY_15, Pkp::KEY_MODE_CYCLE4);


int8_t defaultStates[PKP_MAX_KEY_AMOUNT] = {0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0};
keypad.presetDefaultKeyStates(defaultStates);

keypad.applyDefaultKeyStates();
keypad.setKeyBrightness(70);
keypad.setBacklight(Pkp::BACKLIGHT_BLUE, 50);
keypad.initializeEncoder(0, 16, 5);
keypad.initializeEncoder(1, 16, 10);

keypad.begin(CAN_1000KBPS, MCP_8MHZ); // These are MCP settings to be passed
keypad.begin();
}

//----------------------------------------------------------------------------

uint8_t brightness = 0;
uint32_t lastIncrement = 0;
int16_t encoder = 0;

void loop() {
currentMillis = millis();

keypad.process(); // must have this in main loop.
static uint32_t key9OnTime = 0;
static bool lastKey9State = 0;
static uint32_t lastIncrement = 0;
uint32_t currentMillis = millis();

if (keypad._keyState[PKP_KEY_1] == 1) {
if (keypad.getKeyState(Pkp::KEY_1) == 1) {
// do stuff
}

// if key 9 is pressed, turn off after 2 seconds
if (keypad._keyState[PKP_KEY_9] == 1 && lastKey9State == 0) {
// if key 9 is release, blink for two seconds and turn off afterwards
uint8_t key9State = keypad.getKeyState(Pkp::KEY_9);
if (key9State == 0 && lastKey9State == 1) {
key9OnTime = currentMillis;
keypad.setKeyStateOverride(Pkp::KEY_9, 2);
}
lastKey9State = keypad._keyState[PKP_KEY_9];
if (lastKey9State == 1 && (currentMillis - key9OnTime) > 2000) {
keypad._keyState[PKP_KEY_9] = 0;
keypad.update();
if (key9OnTime + 2000 < currentMillis) {
keypad.setKeyStateOverride(Pkp::KEY_9, -1);
}
lastKey9State = key9State;

int encoderOld = encoder;
bool newData = false;
uint16_t leds = 0;
encoder += keypad.getRelativeEncoderTicks(0);
encoder = constrain(encoder, 0, 16);

if (encoder != encoderOld) {
for (int i = 0; i < encoder; i++) {
leds |= 1 << i;
bool newData = false;
int32_t leds[2] = {-1, -1};
for (int i = 0; i < 2; i++) {
int16_t encoder = keypad.getEncoderPosition(i);
for (int j = 0; j < encoder; j++) {
leds[i] |= 1 << j;
}
newData = 1;
}
keypad.setEncoderLeds(leds);

if (keypad.getStatus() != Pkp::KPS_RX_WITHIN_LAST_SECOND) {
pixel.setPixelColor(0, pixel.Color(255, 0, 0));
pixel.show();
delay(100);
// Turn off the pixel
pixel.setPixelColor(0, pixel.Color(0, 0, 0));
pixel.show();
delay(300);
}
}

if (newData && lastIncrement + 50 < currentMillis) {
keypad.setEncoderLed(0, leds);
lastIncrement = currentMillis;
uint8_t transmittMessageCallBack(const struct can_frame& txMsg) {
CAN.beginPacket(txMsg.can_id, txMsg.can_dlc);
for (int i = 0; i < txMsg.can_dlc; i++) {
CAN.write(txMsg.data[i]);
}
CAN.endPacket();
return 0;
}

void onReceive(int packetSize) {
struct can_frame rxMsg;
rxMsg.can_id = CAN.packetId();
rxMsg.can_dlc = CAN.packetDlc();
packetSize = min(packetSize, sizeof(rxMsg.data) / sizeof(rxMsg.data[0]));
for (int i = 0; i < packetSize; i++) {
if (CAN.peek() == -1) {
break;
}
rxMsg.data[i] = (char)CAN.read();
}
keypad.process(rxMsg);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// This sketch provides a basic configuration for your keyboard without using the actual classes from the library

#include <SPI.h>
#include <mcp2515.h>
#define TRANSMIT_MSG(data) transmitMsg(data, sizeof(data))
#define TRANSMIT_MSG(data, id) transmitMsg(data, sizeof(data), id)
#define LIMIT(x, min, max) (x < min ? min : ((x > max) ? max : x))


#define CS_PIN_MCP 10
#define MCP_CLOCK_SPEED MCP_8MHZ
MCP2515 mcp2515(CS_PIN_MCP, MCP_CLOCK_SPEED);

enum BaudRate_e : uint8_t {
PKP_BAUDRATE_0020k = 0x07,
PKP_BAUDRATE_0050k = 0x06,
PKP_BAUDRATE_0125k = 0x04,
PKP_BAUDRATE_0250k = 0x03,
PKP_BAUDRATE_0500k = 0x02,
PKP_BAUDRATE_1000k = 0x00
};

enum keyBacklight_e : uint8_t {
BACKLIGHT_DEFAULT = 0x00,
BACKLIGHT_RED = 0x01,
BACKLIGHT_GREEN = 0x02,
BACKLIGHT_BLUE = 0x03,
BACKLIGHT_YELLOW = 0x04,
BACKLIGHT_CYAN = 0x05,
BACKLIGHT_VIOLET = 0x06,
BACKLIGHT_WHITE = 0x07,
BACKLIGHT_AMBER = 0x08,
BACKLIGHT_YELLOWGREEN = 0x09
};

////////////////////////////
// CONFIGURE THESE VALUES //
////////////////////////////
// IF YOU WANT A VALUE TO BE UNCHANGED SET IT TO -1
constexpr uint8_t ACT_CAN_ID = 0x15;
constexpr int8_t NEW_CAN_ID = 0x16;
constexpr int8_t NEW_BAUD_RATE = PKP_BAUDRATE_1000k;
constexpr int8_t ACTIVE_AT_STARTUP = 1; //1: enable, 0: disable
constexpr int8_t STARTUP_LED_SHOW = 1; //1: complete show (default), 0: disable, 2: fast flash
constexpr int8_t PERIODIC_KEY_INTERVAL = 0; //0: eventbased pdo transmission, otherwise pdo interval [ms]
constexpr int8_t PERIODIC_AI_INTERVAL = 0;
constexpr int8_t DEFAULT_BACKGROUND_COLOR = BACKLIGHT_WHITE;
constexpr int8_t DEFAULT_BACKGROUND_BRIGHTNESS = 10;
constexpr uint8_t DEFAULT_KEY_LED_BRIGHTNESS = 70;
constexpr int8_t BOOTUP_SERVICE_MESAGE = 1;
constexpr int16_t PROD_HEARTBEAT_INTERVAL = 500; // 10 to 65279ms (0 to disable heartbeat production)
constexpr int8_t DEMO_MODE = 0;
constexpr uint8_t RESTORE_DEFAULTS = 0;

/////////////////////////////////////////////////
// CAN FRAME PAYLOADS - NO CHANGES NEEDED HERE //
/////////////////////////////////////////////////
constexpr uint8_t setCanProtocol[] = {0x04, 0x1B, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
constexpr uint8_t setBaudRate[] = {0x2F, 0x10, 0x20, 0x00, 0x02};
constexpr uint8_t setNodeId[] = {0x2F, 0x13, 0x20, 0x00, NEW_CAN_ID};
constexpr uint8_t startUpShow[] = {0x2F, 0x14, 0x20, 0x00, STARTUP_LED_SHOW};
constexpr uint8_t EventBasedKeyTx[] = {0x2F, 0x00, 0x18, 0x02, 0xFE};
constexpr uint8_t PeriodicKeyTx[] = {0x2F, 0x00, 0x18, 0x05, 0x01};
constexpr uint8_t PeriodicKeyTxTime[] = {0x2B, 0x00, 0x18, 0x05, PERIODIC_TX_INTERVAL & 0xFF, PERIODIC_TX_INTERVAL >> 8};
constexpr uint8_t PeriodicAnalogInTxTime[] = {0x2F, 0x06, 0x20, 0x00, LIMIT((PERIODIC_AI_INTERVAL / 10), 0x08, 0xC8)};
constexpr uint8_t ActiveAtStartUp[] = {0x2F, 0x12, 0x20, 0x00, ACTIVE_AT_STARTUP};
constexpr uint8_t defaultBackBrightness[] = {0x2F, 0x03, 0x20, 0x06, DEFAULT_BACKGROUND_BRIGHTNESS};
constexpr uint8_t defaultBackColor[] = {0x2F, 0x03, 0x20, 0x04, DEFAULT_BACKGROUND_COLOR};
constexpr uint8_t defaultKeyBrightness[] = {0x2F, 0x03, 0x20, 0x05, DEFAULT_KEY_LED_BRIGHTNESS};
constexpr uint8_t setBootUpService[] = {0x2F, 0x11, 0x20, 0x00, BOOTUP_SERVICE_MESAGE};
constexpr uint8_t setProducerHeartbeat[] = {0x2B, 0x17, 0x10, 0x00, PROD_HEARTBEAT_INTERVAL & 0xFF, PROD_HEARTBEAT_INTERVAL >> 8};
constexpr uint8_t activateDemoMode[] = {0x2F, 0x00, 0x21, 0x00, DEMO_MODE};
constexpr uint8_t restoreDefaults[] = {0x23, 0x11, 0x10, 0x01, 0x6C 0x6F 0x61, 0x64};
constexpr uint8_t resetKeypad[] = {0x81, NEW_CAN_ID}

///////////////////////////////////////
// FUNCTIONS TO CONFIGURE THE KEYPAD //
///////////////////////////////////////
void setup() {
Serial.begin(115200);

while (mcp2515.reset() != MCP2515::ERROR_OK) {
Serial.println("MCP reset failed. Retrying...");
delay(100);
}
Serial.println("MCP OK");
mcp2515.setBitrate(mcpBaudrate, mcpClockSpeed);
mcp2515.setNormalMode();
}

void configureKeypad() {

TRANSMIT_MSG(setCanProtocol);
TRANSMIT_MSG(setBaudRate);


TRANSMIT_MSG(EventBasedKeyTx);
TRANSMIT_MSG(PeriodicKeyTx);
TRANSMIT_MSG(PeriodicKeyTxTime);
TRANSMIT_MSG(PeriodicAnalogInTxTime);

if (DEFAULT_BACKGROUND_BRIGHTNESS > -1) {
TRANSMIT_MSG(defaultBackBrightness);
}
if (DEFAULT_BACKGROUND_COLOR > -1) {
TRANSMIT_MSG(defaultBackColor);
}
if (DEFAULT_KEY_LED_BRIGHTNESS > -1) {
TRANSMIT_MSG(defaultKeyBrightness);
}
if (BOOTUP_SERVICE_MESAGE > -1) {
TRANSMIT_MSG(setBootUpService);
}
if (PROD_HEARTBEAT_INTERVAL > -1) {
TRANSMIT_MSG(setProducerHeartbeat);
}
if (DEMO_MODE > -1) {
TRANSMIT_MSG(activateDemoMode);
}
if (STARTUP_LED_SHOW > -1) {
TRANSMIT_MSG(startUpShow);
}


if (ACT_CAN_ID != NEW_CAN_ID && NEW_CAN_ID > -1) {
TRANSMIT_MSG(setNodeId);
} else if (RESTORE_DEFAULTS) {
TRANSMIT_MSG(restoreDefaults);
}
TRANSMIT_MSG(resetKeypad);
}

void loop() {
}

void transmitMsg(const uint8_t* data, uint8_t length, uint8_t, nodeId = ACT_CAN_ID) {

can_frame msg = {0};
msg.id = nodeId;
msg.length = length;
memcpy(msg.data, data, length);

mcp2515.sendMessage(&msg);
}

0 comments on commit f03eb6b

Please sign in to comment.