canbus: canopen: add LED indicator support

Add support for CANopen LED indicators according to the CAN in
Automation (CiA) 303-3 specification.

This fixes #15278.

Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
Henrik Brix Andersen 2019-09-28 21:45:44 +02:00 committed by Carles Cufí
commit 308f204952
4 changed files with 133 additions and 0 deletions

View file

@ -86,6 +86,32 @@ int canopen_storage_save(enum canopen_storage storage);
*/ */
int canopen_storage_erase(enum canopen_storage storage); int canopen_storage_erase(enum canopen_storage storage);
/**
* @typedef canopen_led_callback_t
* @brief CANopen LED indicator callback function signature.
*
* @param value true if the LED indicator shall be turned on, false otherwise.
* @param arg argument that was passed when LEDs were initialized.
*/
typedef void (*canopen_led_callback_t)(bool value, void *arg);
/**
* @brief Initialize CANopen LED indicators.
*
* Initialize CANopen LED indicators and attach callbacks for setting
* their state. Two LED indicators, a red and a green, are supported
* according to CiA 303-3.
*
* @param nmt CANopenNode NMT object.
* @param green_cb callback for changing state on the green LED indicator.
* @param green_arg argument to pass to the green LED indicator callback.
* @param red_cb callback for changing state on the red LED indicator.
* @param red_arg argument to pass to the red LED indicator callback.
*/
void canopen_leds_init(CO_NMT_t *nmt,
canopen_led_callback_t green_cb, void *green_arg,
canopen_led_callback_t red_cb, void *red_arg);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -4,4 +4,5 @@ zephyr_library()
zephyr_library_sources_ifdef(CONFIG_CANOPEN CO_driver.c) zephyr_library_sources_ifdef(CONFIG_CANOPEN CO_driver.c)
zephyr_library_sources_ifdef(CONFIG_CANOPEN_SYNC_THREAD canopen_sync.c) zephyr_library_sources_ifdef(CONFIG_CANOPEN_SYNC_THREAD canopen_sync.c)
zephyr_library_sources_ifdef(CONFIG_CANOPEN_STORAGE canopen_storage.c) zephyr_library_sources_ifdef(CONFIG_CANOPEN_STORAGE canopen_storage.c)
zephyr_library_sources_if_kconfig(canopen_leds.c)
zephyr_include_directories(.) zephyr_include_directories(.)

View file

@ -65,6 +65,21 @@ config CANOPEN_STORAGE_HANDLER_ERASES_EEPROM
Erase CANopen object dictionary EEPROM entries upon write to Erase CANopen object dictionary EEPROM entries upon write to
object dictionary index 0x1011 subindex 1. object dictionary index 0x1011 subindex 1.
config CANOPEN_LEDS
bool "CANopen LED indicators"
default y
help
Enable support for CANopen LED indicators according to the CiA
303-3 specification.
config CANOPEN_LEDS_BICOLOR
bool "CANopen bicolor LED indicator"
depends on CANOPEN_LEDS
help
Handle CANopen LEDs as one bicolor LED, favoring the red LED
over the green LED in accordance with the CiA 303-3
specification.
config CANOPEN_SYNC_THREAD config CANOPEN_SYNC_THREAD
bool "CANopen SYNC thread" bool "CANopen SYNC thread"
default y default y

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2019 Vestas Wind Systems A/S
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <CANopen.h>
#include <canbus/canopen.h>
struct canopen_leds_state {
CO_NMT_t *nmt;
canopen_led_callback_t green_cb;
void *green_arg;
canopen_led_callback_t red_cb;
void *red_arg;
bool green : 1;
bool red : 1;
};
static struct canopen_leds_state canopen_leds;
static void canopen_leds_update(struct k_timer *timer_id)
{
bool green = false;
bool red = false;
ARG_UNUSED(timer_id);
CO_NMT_blinkingProcess50ms(canopen_leds.nmt);
green = LED_GREEN_RUN(canopen_leds.nmt);
red = LED_RED_ERROR(canopen_leds.nmt);
#ifdef CONFIG_CANOPEN_LEDS_BICOLOR
if (red && canopen_leds.red_cb) {
green = false;
}
#endif
if (canopen_leds.green_cb) {
if (green != canopen_leds.green) {
canopen_leds.green_cb(green, canopen_leds.green_arg);
canopen_leds.green = green;
}
}
if (canopen_leds.red_cb) {
if (red != canopen_leds.red) {
canopen_leds.red_cb(red, canopen_leds.red_arg);
canopen_leds.red = red;
}
}
}
K_TIMER_DEFINE(canopen_leds_timer, canopen_leds_update, NULL);
void canopen_leds_init(CO_NMT_t *nmt,
canopen_led_callback_t green_cb, void *green_arg,
canopen_led_callback_t red_cb, void *red_arg)
{
k_timer_stop(&canopen_leds_timer);
canopen_leds.nmt = nmt;
/* Call existing callbacks to turn off LEDs */
if (canopen_leds.green_cb) {
canopen_leds.green_cb(false, canopen_leds.green_arg);
}
if (canopen_leds.red_cb) {
canopen_leds.red_cb(false, canopen_leds.red_arg);
}
canopen_leds.green_cb = green_cb;
canopen_leds.green_arg = green_arg;
canopen_leds.green = false;
canopen_leds.red_cb = red_cb;
canopen_leds.red_arg = red_arg;
canopen_leds.red = false;
/* Call new callbacks to turn off LEDs */
if (canopen_leds.green_cb) {
canopen_leds.green_cb(false, canopen_leds.green_arg);
}
if (canopen_leds.red_cb) {
canopen_leds.red_cb(false, canopen_leds.red_arg);
}
if (nmt && (green_cb || red_cb)) {
k_timer_start(&canopen_leds_timer, K_MSEC(50), K_MSEC(50));
}
}