|
| 1 | +/* |
| 2 | + * Copyright (c) 2018 Alexander Wachter |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr.h> |
| 8 | +#include <kernel.h> |
| 9 | +#include <misc/printk.h> |
| 10 | +#include <device.h> |
| 11 | +#include <can.h> |
| 12 | +#include <gpio.h> |
| 13 | + |
| 14 | +#define TX_THREAD_STACK_SIZE 512 |
| 15 | +#define LED_THREAD_STACK_SIZE 512 |
| 16 | +#define RX_STR_THREAD_STACK_SIZE 512 |
| 17 | +#define TX_THREAD_PRIORITY 2 |
| 18 | +#define LED_MSG_ID (0x10) |
| 19 | +#define BUTTON_MSG_ID (0x01) |
| 20 | +#define STR_MSG_ID (0x12345) |
| 21 | + |
| 22 | +#define SET_LED 0 |
| 23 | +#define RESET_LED 1 |
| 24 | + |
| 25 | + |
| 26 | +#define NUM_LEDS_STR STRINGIFY(NUM_LEDS) |
| 27 | + |
| 28 | +K_THREAD_STACK_DEFINE(tx_thread_stack, TX_THREAD_STACK_SIZE); |
| 29 | +K_THREAD_STACK_DEFINE(led_thread_stack, LED_THREAD_STACK_SIZE); |
| 30 | +K_THREAD_STACK_DEFINE(rx_str_thread_stack, RX_STR_THREAD_STACK_SIZE); |
| 31 | +struct k_thread tx_thread_data; |
| 32 | +struct k_thread led_thread_data; |
| 33 | +struct k_thread rx_str_thread_data; |
| 34 | +struct k_sem tx_sem; |
| 35 | +static struct gpio_callback gpio_cb; |
| 36 | +CAN_DEFINE_MSGQ(led_msgq, 2); |
| 37 | +CAN_DEFINE_MSGQ(str_msgq, 5); |
| 38 | + |
| 39 | +void tx_irq_callback(u32_t error_flags) |
| 40 | +{ |
| 41 | + if (error_flags) { |
| 42 | + printk("Callback! error-code: %d\n", error_flags); |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +void button_callback(struct device *port, |
| 47 | + struct gpio_callback *cb, u32_t pins) |
| 48 | +{ |
| 49 | + k_sem_give(&tx_sem); |
| 50 | +} |
| 51 | + |
| 52 | +void send_string(char *string, struct device *can_dev) |
| 53 | +{ |
| 54 | + struct can_msg msg; |
| 55 | + int str_len; |
| 56 | + |
| 57 | + msg.ext_id = STR_MSG_ID; |
| 58 | + msg.id_type = CAN_EXTENDED_IDENTIFIER; |
| 59 | + msg.dlc = 0; |
| 60 | + msg.rtr = CAN_DATAFRAME; |
| 61 | + |
| 62 | + for (str_len = strlen(string); str_len; ) { |
| 63 | + msg.dlc = str_len >= 8 ? 8 : str_len; |
| 64 | + str_len -= msg.dlc; |
| 65 | + memcpy(msg.data, string, msg.dlc); |
| 66 | + string += msg.dlc; |
| 67 | + can_send(can_dev, &msg, 10, tx_irq_callback); |
| 68 | + } |
| 69 | +} |
| 70 | + |
| 71 | +void tx_thread(void *can_dev_param, void *unused2, void *unused3) |
| 72 | +{ |
| 73 | + u8_t toggle = SET_LED; |
| 74 | + u16_t button_press_cnt = 0; |
| 75 | + struct can_msg msg; |
| 76 | + struct can_msg msg_button_cnt; |
| 77 | + struct device *can_dev = can_dev_param; |
| 78 | + |
| 79 | + msg.std_id = LED_MSG_ID; |
| 80 | + msg.id_type = CAN_STANDARD_IDENTIFIER; |
| 81 | + msg.dlc = 1; |
| 82 | + msg.rtr = CAN_DATAFRAME; |
| 83 | + msg.data[0] = 0; |
| 84 | + |
| 85 | + msg_button_cnt.std_id = BUTTON_MSG_ID; |
| 86 | + msg_button_cnt.id_type = CAN_STANDARD_IDENTIFIER; |
| 87 | + msg_button_cnt.dlc = 2; |
| 88 | + msg_button_cnt.rtr = CAN_DATAFRAME; |
| 89 | + msg_button_cnt.data[0] = 0; |
| 90 | + msg_button_cnt.data[1] = 0; |
| 91 | + |
| 92 | + printk("TX thread is running.\n"); |
| 93 | + while (1) { |
| 94 | + k_sem_take(&tx_sem, K_FOREVER); |
| 95 | + button_press_cnt++; |
| 96 | + toggle = (toggle == SET_LED) ? RESET_LED : SET_LED; |
| 97 | + printk("Button pressed! Send message %u\n", toggle); |
| 98 | + msg.data[0] = toggle; |
| 99 | + msg_button_cnt.data[0] = button_press_cnt & 0xFF; |
| 100 | + msg_button_cnt.data[1] = (button_press_cnt >> 8) & 0xFF; |
| 101 | + can_send(can_dev, &msg, 10, tx_irq_callback); |
| 102 | + can_send(can_dev, &msg_button_cnt, 10, NULL); |
| 103 | + if (toggle == SET_LED) { |
| 104 | + send_string("String sent over CAN\n", can_dev); |
| 105 | + } |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +void rx_str_thread(void *msgq, void *can_dev_param, void *unused) |
| 110 | +{ |
| 111 | + struct can_msg msg; |
| 112 | + const struct can_filter filter = { |
| 113 | + .id_type = CAN_EXTENDED_IDENTIFIER, |
| 114 | + .rtr = CAN_DATAFRAME, |
| 115 | + .ext_id = STR_MSG_ID, |
| 116 | + .rtr_mask = 1, |
| 117 | + .ext_id_mask = CAN_EXT_ID_MASK |
| 118 | + }; |
| 119 | + struct device *can_dev = can_dev_param; |
| 120 | + |
| 121 | + can_attach_msgq(can_dev, msgq, &filter); |
| 122 | + |
| 123 | + while (1) { |
| 124 | + k_msgq_get((struct k_msgq *)msgq, &msg, K_FOREVER); |
| 125 | + for (int i = 0; i < msg.dlc; i++) |
| 126 | + printk("%c", msg.data[i]); |
| 127 | + } |
| 128 | +} |
| 129 | + |
| 130 | +void led_thread(void *msgq, void *can_dev_param, void *gpio_dev_param) |
| 131 | +{ |
| 132 | + const struct can_filter filter = { |
| 133 | + .id_type = CAN_STANDARD_IDENTIFIER, |
| 134 | + .rtr = CAN_DATAFRAME, |
| 135 | + .std_id = LED_MSG_ID, |
| 136 | + .rtr_mask = 1, |
| 137 | + .std_id_mask = CAN_STD_ID_MASK |
| 138 | + }; |
| 139 | + struct device *can_dev = can_dev_param; |
| 140 | + struct device *gpio_dev = gpio_dev_param; |
| 141 | + struct can_msg msg; |
| 142 | + int ret; |
| 143 | + int filter_id; |
| 144 | + |
| 145 | + ret = gpio_pin_configure(gpio_dev, CONFIG_PIN_LED_1, GPIO_DIR_OUT); |
| 146 | + gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 0); |
| 147 | + |
| 148 | + if (ret) { |
| 149 | + printk("ERROR configure pins\n"); |
| 150 | + return; |
| 151 | + } |
| 152 | + |
| 153 | + filter_id = can_attach_msgq(can_dev, msgq, &filter); |
| 154 | + printk("filter id: %d\n", filter_id); |
| 155 | + |
| 156 | + while (1) { |
| 157 | + k_msgq_get((struct k_msgq *)msgq, &msg, K_FOREVER); |
| 158 | + |
| 159 | + if (msg.dlc != 1) { |
| 160 | + continue; |
| 161 | + } |
| 162 | + |
| 163 | + switch (msg.data[0]) { |
| 164 | + case SET_LED: |
| 165 | + gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 1); |
| 166 | + |
| 167 | + break; |
| 168 | + case RESET_LED: |
| 169 | + gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 0); |
| 170 | + break; |
| 171 | + } |
| 172 | + } |
| 173 | +} |
| 174 | + |
| 175 | +void rx_button_isr(struct can_msg *msg) |
| 176 | +{ |
| 177 | + u16_t cnt = msg->data[0] | (msg->data[1] << 8); |
| 178 | + |
| 179 | + printk("Button pressed %d times\n", cnt); |
| 180 | +} |
| 181 | + |
| 182 | +void main(void) |
| 183 | +{ |
| 184 | + const struct can_filter filter = { |
| 185 | + .id_type = CAN_STANDARD_IDENTIFIER, |
| 186 | + .rtr = CAN_DATAFRAME, |
| 187 | + .std_id = BUTTON_MSG_ID, |
| 188 | + .rtr_mask = 1, |
| 189 | + .std_id_mask = CAN_STD_ID_MASK |
| 190 | + }; |
| 191 | + struct device *can_dev, *led_gpio_dev, *button_gpio_dev; |
| 192 | + int ret; |
| 193 | + |
| 194 | + can_dev = device_get_binding(CONFIG_CAN_DEV); |
| 195 | + if (!can_dev) { |
| 196 | + printk("CAN: Device driver not found.\n"); |
| 197 | + return; |
| 198 | + } |
| 199 | + |
| 200 | +#ifdef CONFIG_LOOPBACK_MODE |
| 201 | + can_configure(can_dev, CAN_LOOPBACK_MODE, 250000); |
| 202 | +#endif |
| 203 | + |
| 204 | + led_gpio_dev = device_get_binding(CONFIG_GPIO_LED_DEV); |
| 205 | + if (!led_gpio_dev) { |
| 206 | + printk("LED: Device driver not found.\n"); |
| 207 | + return; |
| 208 | + } |
| 209 | + |
| 210 | + k_sem_init(&tx_sem, 0, INT_MAX); |
| 211 | + |
| 212 | + button_gpio_dev = device_get_binding(CONFIG_GPIO_BUTTON_DEV); |
| 213 | + if (!button_gpio_dev) { |
| 214 | + printk("Button: Device driver not found.\n"); |
| 215 | + return; |
| 216 | + } |
| 217 | + |
| 218 | + ret = gpio_pin_configure(button_gpio_dev, CONFIG_PIN_USER_BUTTON, |
| 219 | + (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | |
| 220 | + GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE)); |
| 221 | + if (ret) { |
| 222 | + printk("Error configuring button pin\n"); |
| 223 | + } |
| 224 | + |
| 225 | + gpio_init_callback(&gpio_cb, button_callback, |
| 226 | + BIT(CONFIG_PIN_USER_BUTTON)); |
| 227 | + |
| 228 | + ret = gpio_add_callback(button_gpio_dev, &gpio_cb); |
| 229 | + if (ret) { |
| 230 | + printk("Cannot setup callback!\n"); |
| 231 | + } |
| 232 | + |
| 233 | + ret = gpio_pin_enable_callback(button_gpio_dev, CONFIG_PIN_USER_BUTTON); |
| 234 | + if (ret) { |
| 235 | + printk("Error enabling callback!\n"); |
| 236 | + } |
| 237 | + |
| 238 | + can_attach_isr(can_dev, rx_button_isr, &filter); |
| 239 | + |
| 240 | + k_tid_t tx_tid = k_thread_create(&tx_thread_data, tx_thread_stack, |
| 241 | + K_THREAD_STACK_SIZEOF(tx_thread_stack), |
| 242 | + tx_thread, |
| 243 | + can_dev, NULL, NULL, |
| 244 | + TX_THREAD_PRIORITY, 0, K_NO_WAIT); |
| 245 | + if (!tx_tid) { |
| 246 | + printk("ERROR spawning tx_thread\n"); |
| 247 | + } |
| 248 | + |
| 249 | + k_tid_t led_tid = k_thread_create(&led_thread_data, led_thread_stack, |
| 250 | + K_THREAD_STACK_SIZEOF(led_thread_stack), |
| 251 | + led_thread, |
| 252 | + &led_msgq, can_dev, led_gpio_dev, |
| 253 | + TX_THREAD_PRIORITY, 0, K_NO_WAIT); |
| 254 | + if (!led_tid) { |
| 255 | + printk("ERROR spawning led_thread\n"); |
| 256 | + } |
| 257 | + |
| 258 | + k_tid_t str_tid = k_thread_create(&rx_str_thread_data, |
| 259 | + rx_str_thread_stack, |
| 260 | + K_THREAD_STACK_SIZEOF(rx_str_thread_stack), |
| 261 | + rx_str_thread, |
| 262 | + &str_msgq, can_dev, NULL, |
| 263 | + TX_THREAD_PRIORITY, 0, K_NO_WAIT); |
| 264 | + if (!str_tid) { |
| 265 | + printk("ERROR spawning str_thread\n"); |
| 266 | + } |
| 267 | + |
| 268 | + printk("Finished init. waiting for Interrupts\n"); |
| 269 | +} |
0 commit comments