blob: 9a0e1dbf5d14b2954f9f23015beb07612029368a [file] [log] [blame]
/*
* Copyright (c) 2018 Alexander Wachter
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <kernel.h>
#include <misc/printk.h>
#include <device.h>
#include <can.h>
#include <gpio.h>
#define TX_THREAD_STACK_SIZE 512
#define LED_THREAD_STACK_SIZE 512
#define RX_STR_THREAD_STACK_SIZE 512
#define TX_THREAD_PRIORITY 2
#define LED_MSG_ID (0x10)
#define BUTTON_MSG_ID (0x01)
#define STR_MSG_ID (0x12345)
#define SET_LED 0
#define RESET_LED 1
#define NUM_LEDS_STR STRINGIFY(NUM_LEDS)
K_THREAD_STACK_DEFINE(tx_thread_stack, TX_THREAD_STACK_SIZE);
K_THREAD_STACK_DEFINE(led_thread_stack, LED_THREAD_STACK_SIZE);
K_THREAD_STACK_DEFINE(rx_str_thread_stack, RX_STR_THREAD_STACK_SIZE);
struct k_thread tx_thread_data;
struct k_thread led_thread_data;
struct k_thread rx_str_thread_data;
struct k_sem tx_sem;
static struct gpio_callback gpio_cb;
CAN_DEFINE_MSGQ(led_msgq, 2);
CAN_DEFINE_MSGQ(str_msgq, 5);
void tx_irq_callback(u32_t error_flags)
{
if (error_flags) {
printk("Callback! error-code: %d\n", error_flags);
}
}
void button_callback(struct device *port,
struct gpio_callback *cb, u32_t pins)
{
k_sem_give(&tx_sem);
}
void send_string(char *string, struct device *can_dev)
{
struct can_msg msg;
int str_len;
msg.ext_id = STR_MSG_ID;
msg.id_type = CAN_EXTENDED_IDENTIFIER;
msg.dlc = 0;
msg.rtr = CAN_DATAFRAME;
for (str_len = strlen(string); str_len; ) {
msg.dlc = str_len >= 8 ? 8 : str_len;
str_len -= msg.dlc;
memcpy(msg.data, string, msg.dlc);
string += msg.dlc;
can_send(can_dev, &msg, 10, tx_irq_callback);
}
}
void tx_thread(void *can_dev_param, void *unused2, void *unused3)
{
u8_t toggle = SET_LED;
u16_t button_press_cnt = 0;
struct can_msg msg;
struct can_msg msg_button_cnt;
struct device *can_dev = can_dev_param;
msg.std_id = LED_MSG_ID;
msg.id_type = CAN_STANDARD_IDENTIFIER;
msg.dlc = 1;
msg.rtr = CAN_DATAFRAME;
msg.data[0] = 0;
msg_button_cnt.std_id = BUTTON_MSG_ID;
msg_button_cnt.id_type = CAN_STANDARD_IDENTIFIER;
msg_button_cnt.dlc = 2;
msg_button_cnt.rtr = CAN_DATAFRAME;
msg_button_cnt.data[0] = 0;
msg_button_cnt.data[1] = 0;
printk("TX thread is running.\n");
while (1) {
k_sem_take(&tx_sem, K_FOREVER);
button_press_cnt++;
toggle = (toggle == SET_LED) ? RESET_LED : SET_LED;
printk("Button pressed! Send message %u\n", toggle);
msg.data[0] = toggle;
msg_button_cnt.data[0] = button_press_cnt & 0xFF;
msg_button_cnt.data[1] = (button_press_cnt >> 8) & 0xFF;
can_send(can_dev, &msg, 10, tx_irq_callback);
can_send(can_dev, &msg_button_cnt, 10, NULL);
if (toggle == SET_LED) {
send_string("String sent over CAN\n", can_dev);
}
}
}
void rx_str_thread(void *msgq, void *can_dev_param, void *unused)
{
struct can_msg msg;
const struct can_filter filter = {
.id_type = CAN_EXTENDED_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.ext_id = STR_MSG_ID,
.rtr_mask = 1,
.ext_id_mask = CAN_EXT_ID_MASK
};
struct device *can_dev = can_dev_param;
can_attach_msgq(can_dev, msgq, &filter);
while (1) {
k_msgq_get((struct k_msgq *)msgq, &msg, K_FOREVER);
for (int i = 0; i < msg.dlc; i++)
printk("%c", msg.data[i]);
}
}
void led_thread(void *msgq, void *can_dev_param, void *gpio_dev_param)
{
const struct can_filter filter = {
.id_type = CAN_STANDARD_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.std_id = LED_MSG_ID,
.rtr_mask = 1,
.std_id_mask = CAN_STD_ID_MASK
};
struct device *can_dev = can_dev_param;
struct device *gpio_dev = gpio_dev_param;
struct can_msg msg;
int ret;
int filter_id;
ret = gpio_pin_configure(gpio_dev, CONFIG_PIN_LED_1, GPIO_DIR_OUT);
gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 0);
if (ret) {
printk("ERROR configure pins\n");
return;
}
filter_id = can_attach_msgq(can_dev, msgq, &filter);
printk("filter id: %d\n", filter_id);
while (1) {
k_msgq_get((struct k_msgq *)msgq, &msg, K_FOREVER);
if (msg.dlc != 1) {
continue;
}
switch (msg.data[0]) {
case SET_LED:
gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 1);
break;
case RESET_LED:
gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 0);
break;
}
}
}
void rx_button_isr(struct can_msg *msg)
{
u16_t cnt = msg->data[0] | (msg->data[1] << 8);
printk("Button pressed %d times\n", cnt);
}
void main(void)
{
const struct can_filter filter = {
.id_type = CAN_STANDARD_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.std_id = BUTTON_MSG_ID,
.rtr_mask = 1,
.std_id_mask = CAN_STD_ID_MASK
};
struct device *can_dev, *led_gpio_dev, *button_gpio_dev;
int ret;
can_dev = device_get_binding(CONFIG_CAN_DEV);
if (!can_dev) {
printk("CAN: Device driver not found.\n");
return;
}
#ifdef CONFIG_LOOPBACK_MODE
can_configure(can_dev, CAN_LOOPBACK_MODE, 250000);
#endif
led_gpio_dev = device_get_binding(CONFIG_GPIO_LED_DEV);
if (!led_gpio_dev) {
printk("LED: Device driver not found.\n");
return;
}
k_sem_init(&tx_sem, 0, INT_MAX);
button_gpio_dev = device_get_binding(CONFIG_GPIO_BUTTON_DEV);
if (!button_gpio_dev) {
printk("Button: Device driver not found.\n");
return;
}
ret = gpio_pin_configure(button_gpio_dev, CONFIG_PIN_USER_BUTTON,
(GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE));
if (ret) {
printk("Error configuring button pin\n");
}
gpio_init_callback(&gpio_cb, button_callback,
BIT(CONFIG_PIN_USER_BUTTON));
ret = gpio_add_callback(button_gpio_dev, &gpio_cb);
if (ret) {
printk("Cannot setup callback!\n");
}
ret = gpio_pin_enable_callback(button_gpio_dev, CONFIG_PIN_USER_BUTTON);
if (ret) {
printk("Error enabling callback!\n");
}
can_attach_isr(can_dev, rx_button_isr, &filter);
k_tid_t tx_tid = k_thread_create(&tx_thread_data, tx_thread_stack,
K_THREAD_STACK_SIZEOF(tx_thread_stack),
tx_thread,
can_dev, NULL, NULL,
TX_THREAD_PRIORITY, 0, K_NO_WAIT);
if (!tx_tid) {
printk("ERROR spawning tx_thread\n");
}
k_tid_t led_tid = k_thread_create(&led_thread_data, led_thread_stack,
K_THREAD_STACK_SIZEOF(led_thread_stack),
led_thread,
&led_msgq, can_dev, led_gpio_dev,
TX_THREAD_PRIORITY, 0, K_NO_WAIT);
if (!led_tid) {
printk("ERROR spawning led_thread\n");
}
k_tid_t str_tid = k_thread_create(&rx_str_thread_data,
rx_str_thread_stack,
K_THREAD_STACK_SIZEOF(rx_str_thread_stack),
rx_str_thread,
&str_msgq, can_dev, NULL,
TX_THREAD_PRIORITY, 0, K_NO_WAIT);
if (!str_tid) {
printk("ERROR spawning str_thread\n");
}
printk("Finished init. waiting for Interrupts\n");
}