This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
commit 962d90bb6e248fd8c6cae13010ce5e2eb454338f Author: raiden00pl <[email protected]> AuthorDate: Sun Jul 5 09:52:09 2026 +0200 examples: add Lely CANopen master example add Lely CANopen master example Signed-off-by: raiden00pl <[email protected]> --- examples/lely_master/CMakeLists.txt | 53 +++ examples/lely_master/Kconfig | 50 +++ examples/lely_master/Make.defs | 25 ++ examples/lely_master/Makefile | 47 +++ examples/lely_master/candev.h | 44 +++ examples/lely_master/candev_char.c | 173 +++++++++ examples/lely_master/candev_sock.c | 197 ++++++++++ examples/lely_master/master_main.c | 358 ++++++++++++++++++ examples/lely_master/sdev.h | 41 +++ examples/lely_master/sdev_master.c | 714 ++++++++++++++++++++++++++++++++++++ 10 files changed, 1702 insertions(+) diff --git a/examples/lely_master/CMakeLists.txt b/examples/lely_master/CMakeLists.txt new file mode 100644 index 000000000..003c3e9fb --- /dev/null +++ b/examples/lely_master/CMakeLists.txt @@ -0,0 +1,53 @@ +# ############################################################################## +# apps/examples/lely_master/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +if(CONFIG_EXAMPLES_LELYMASTER) + + set(LELY_INCDIR ${NUTTX_APPS_DIR}/canutils/lely-canopen/lely-core/include) + + set(SRCS master_main.c sdev_master.c) + + if(CONFIG_EXAMPLES_LELYMASTER_CHARDEV) + list(APPEND SRCS candev_char.c) + endif() + + if(CONFIG_EXAMPLES_LELYMASTER_SOCKET) + list(APPEND SRCS candev_sock.c) + endif() + + nuttx_add_application( + NAME + comaster + PRIORITY + ${CONFIG_EXAMPLES_LELYMASTER_PRIORITY} + STACKSIZE + ${CONFIG_EXAMPLES_LELYMASTER_STACKSIZE} + MODULE + ${CONFIG_EXAMPLES_LELYMASTER} + COMPILE_FLAGS + -Wno-undef + INCLUDE_DIRECTORIES + ${LELY_INCDIR} + SRCS + ${SRCS}) + +endif() diff --git a/examples/lely_master/Kconfig b/examples/lely_master/Kconfig new file mode 100644 index 000000000..b370ea1f9 --- /dev/null +++ b/examples/lely_master/Kconfig @@ -0,0 +1,50 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_LELYMASTER + tristate "Lely CANopen master example" + default n + depends on CANUTILS_LELYCANOPEN && CANUTILS_LELYCANOPEN_SDEV + depends on CANUTILS_LELYCANOPEN_TIME && CANUTILS_LELYCANOPEN_OBJUPLOAD + depends on CANUTILS_LELYCANOPEN_MASTER + ---help--- + Enable the Lely CANopen master (comaster) example application. + +if EXAMPLES_LELYMASTER + +choice + prompt "CAN backend" + default EXAMPLES_LELYMASTER_CHARDEV + +config EXAMPLES_LELYMASTER_CHARDEV + bool "CAN character driver" + depends on CAN + +config EXAMPLES_LELYMASTER_SOCKET + bool "SocketCAN" + depends on NET_CAN + select NETUTILS_NETLIB + +endchoice + +config EXAMPLES_LELYMASTER_DEVPATH + string "CAN character device path" + default "/dev/can0" + depends on EXAMPLES_LELYMASTER_CHARDEV + +config EXAMPLES_LELYMASTER_INTF + string "SocketCAN interface" + default "can0" + depends on EXAMPLES_LELYMASTER_SOCKET + +config EXAMPLES_LELYMASTER_PRIORITY + int "Task priority" + default 100 + +config EXAMPLES_LELYMASTER_STACKSIZE + int "Stack size" + default DEFAULT_TASK_STACKSIZE + +endif diff --git a/examples/lely_master/Make.defs b/examples/lely_master/Make.defs new file mode 100644 index 000000000..d47806ad6 --- /dev/null +++ b/examples/lely_master/Make.defs @@ -0,0 +1,25 @@ +############################################################################ +# apps/examples/lely_master/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_LELYMASTER),) +CONFIGURED_APPS += $(APPDIR)/examples/lely_master +endif diff --git a/examples/lely_master/Makefile b/examples/lely_master/Makefile new file mode 100644 index 000000000..68db84998 --- /dev/null +++ b/examples/lely_master/Makefile @@ -0,0 +1,47 @@ +############################################################################ +# apps/examples/lely_master/Makefile +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +PROGNAME = comaster +PRIORITY = $(CONFIG_EXAMPLES_LELYMASTER_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_LELYMASTER_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_LELYMASTER) + +CFLAGS += -DHAVE_CONFIG_H=1 + +# Lely headers use bare "#if __cplusplus"; silence -Wundef like the library + +CFLAGS += -Wno-undef + +CSRCS = sdev_master.c + +ifeq ($(CONFIG_EXAMPLES_LELYMASTER_CHARDEV),y) +CSRCS += candev_char.c +endif +ifeq ($(CONFIG_EXAMPLES_LELYMASTER_SOCKET),y) +CSRCS += candev_sock.c +endif + +MAINSRC = master_main.c + +include $(APPDIR)/Application.mk diff --git a/examples/lely_master/candev.h b/examples/lely_master/candev.h new file mode 100644 index 000000000..47a6fb8a9 --- /dev/null +++ b/examples/lely_master/candev.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * apps/examples/lely_master/candev.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_LELY_MASTER_CANDEV_H +#define __APPS_EXAMPLES_LELY_MASTER_CANDEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <canutils/lely/config.h> + +#include <lely/can/msg.h> + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int comaster_candev_init(void); +int comaster_candev_send(FAR const struct can_msg *msg); +int comaster_candev_recv(FAR struct can_msg *msg); + +#endif /* __APPS_EXAMPLES_LELY_MASTER_CANDEV_H */ diff --git a/examples/lely_master/candev_char.c b/examples/lely_master/candev_char.c new file mode 100644 index 000000000..3506b75d9 --- /dev/null +++ b/examples/lely_master/candev_char.c @@ -0,0 +1,173 @@ +/**************************************************************************** + * apps/examples/lely_master/candev_char.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <nuttx/can/can.h> + +#include "candev.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static int g_candev_fd; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: comaster_candev_init + ****************************************************************************/ + +int comaster_candev_init(void) +{ + struct canioc_bittiming_s bt; + int ret; + + /* Non-blocking so the main loop keeps servicing the CANopen timers */ + + g_candev_fd = open(CONFIG_EXAMPLES_LELYMASTER_DEVPATH, + O_RDWR | O_NONBLOCK); + if (g_candev_fd < 0) + { + ret = -errno; + printf("ERROR: open %s failed %d\n", + CONFIG_EXAMPLES_LELYMASTER_DEVPATH, errno); + return ret; + } + + ret = ioctl(g_candev_fd, CANIOC_GET_BITTIMING, &bt); + if (ret < 0) + { + printf("Bit timing not available: %d\n", errno); + } + else + { + printf("Bit timing:\n"); + printf(" Baud: %lu\n", (unsigned long)bt.bt_baud); + printf(" TSEG1: %u\n", bt.bt_tseg1); + printf(" TSEG2: %u\n", bt.bt_tseg2); + printf(" SJW: %u\n", bt.bt_sjw); + } + + return OK; +} + +/**************************************************************************** + * Name: comaster_candev_send + ****************************************************************************/ + +int comaster_candev_send(FAR const struct can_msg *msg) +{ + struct can_msg_s txmsg; + ssize_t nwritten; + int i; + + txmsg.cm_hdr.ch_id = msg->id; + txmsg.cm_hdr.ch_rtr = (msg->flags & CAN_FLAG_RTR) != 0; + txmsg.cm_hdr.ch_dlc = msg->len; +#ifdef CONFIG_CAN_EXTID + txmsg.cm_hdr.ch_extid = (msg->flags & CAN_FLAG_IDE) != 0; +#endif +#ifdef CONFIG_CAN_ERRORS + txmsg.cm_hdr.ch_error = 0; +#endif + txmsg.cm_hdr.ch_tcf = 0; + + for (i = 0; i < msg->len; i++) + { + txmsg.cm_data[i] = msg->data[i]; + } + + nwritten = write(g_candev_fd, &txmsg, CAN_MSGLEN(txmsg.cm_hdr.ch_dlc)); + if (nwritten != CAN_MSGLEN(txmsg.cm_hdr.ch_dlc)) + { + return -1; + } + + return 0; +} + +/**************************************************************************** + * Name: comaster_candev_recv + ****************************************************************************/ + +int comaster_candev_recv(FAR struct can_msg *msg) +{ + struct can_msg_s rxmsg; + ssize_t nread; + int i; + + nread = read(g_candev_fd, &rxmsg, sizeof(struct can_msg_s)); + if (nread < 0) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + { + return 0; + } + + return -1; + } + + if (nread < CAN_MSGLEN(0)) + { + return 0; + } + + msg->id = rxmsg.cm_hdr.ch_id; + msg->flags = 0; + +#ifdef CONFIG_CAN_EXTID + if (rxmsg.cm_hdr.ch_extid) + { + msg->flags |= CAN_FLAG_IDE; + } +#endif + + if (rxmsg.cm_hdr.ch_rtr) + { + msg->flags |= CAN_FLAG_RTR; + } + + msg->len = rxmsg.cm_hdr.ch_dlc; + + for (i = 0; i < rxmsg.cm_hdr.ch_dlc; i++) + { + msg->data[i] = rxmsg.cm_data[i]; + } + + return 1; +} diff --git a/examples/lely_master/candev_sock.c b/examples/lely_master/candev_sock.c new file mode 100644 index 000000000..46c30ddc6 --- /dev/null +++ b/examples/lely_master/candev_sock.c @@ -0,0 +1,197 @@ +/**************************************************************************** + * apps/examples/lely_master/candev_sock.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> + +#include <net/if.h> +#include <sys/socket.h> + +#include <nuttx/can.h> + +#include "netutils/netlib.h" +#include "candev.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static int g_candev_sock; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: comaster_candev_init + ****************************************************************************/ + +int comaster_candev_init(void) +{ + struct sockaddr_can addr; + struct ifreq ifr; + int on = 1; + int ret; + + g_candev_sock = socket(PF_CAN, SOCK_RAW, CAN_RAW); + if (g_candev_sock < 0) + { + ret = -errno; + printf("ERROR: socket failed %d\n", errno); + return ret; + } + + strlcpy(ifr.ifr_name, CONFIG_EXAMPLES_LELYMASTER_INTF, IFNAMSIZ); + + /* SocketCAN silently drops traffic while the interface is down, so bring + * it up here. This lets the example run without a separate "ifup" step. + */ + + if (netlib_ifup(ifr.ifr_name) < 0) + { + ret = -errno; + printf("ERROR: netlib_ifup %s failed %d\n", ifr.ifr_name, errno); + goto errout; + } + + ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name); + if (ifr.ifr_ifindex == 0) + { + ret = -errno; + printf("ERROR: if_nametoindex %s failed %d\n", ifr.ifr_name, errno); + goto errout; + } + + setsockopt(g_candev_sock, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, + &on, sizeof(on)); + + memset(&addr, 0, sizeof(addr)); + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + if (bind(g_candev_sock, (FAR struct sockaddr *)&addr, sizeof(addr)) < 0) + { + ret = -errno; + printf("ERROR: bind failed %d\n", errno); + goto errout; + } + + ret = fcntl(g_candev_sock, F_SETFL, O_NONBLOCK); + if (ret < 0) + { + ret = -errno; + goto errout; + } + + return OK; + +errout: + close(g_candev_sock); + g_candev_sock = -1; + return ret; +} + +/**************************************************************************** + * Name: comaster_candev_send + ****************************************************************************/ + +int comaster_candev_send(FAR const struct can_msg *msg) +{ + struct can_frame frame; + ssize_t nwritten; + + memset(&frame, 0, sizeof(frame)); + + frame.can_id = msg->id; + if (msg->flags & CAN_FLAG_IDE) + { + frame.can_id |= CAN_EFF_FLAG; + } + + if (msg->flags & CAN_FLAG_RTR) + { + frame.can_id |= CAN_RTR_FLAG; + } + + frame.can_dlc = msg->len; + memcpy(frame.data, msg->data, msg->len); + + nwritten = write(g_candev_sock, &frame, sizeof(frame)); + if (nwritten != sizeof(frame)) + { + return -1; + } + + return 0; +} + +/**************************************************************************** + * Name: comaster_candev_recv + ****************************************************************************/ + +int comaster_candev_recv(FAR struct can_msg *msg) +{ + struct can_frame frame; + ssize_t nread; + + nread = read(g_candev_sock, &frame, sizeof(frame)); + if (nread < 0) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + { + return 0; + } + + return -1; + } + + if (nread < sizeof(frame)) + { + return 0; + } + + msg->id = frame.can_id & CAN_EFF_MASK; + msg->flags = 0; + if (frame.can_id & CAN_EFF_FLAG) + { + msg->flags |= CAN_FLAG_IDE; + } + + if (frame.can_id & CAN_RTR_FLAG) + { + msg->flags |= CAN_FLAG_RTR; + } + + msg->len = frame.can_dlc; + memcpy(msg->data, frame.data, frame.can_dlc); + + return 1; +} diff --git a/examples/lely_master/master_main.c b/examples/lely_master/master_main.c new file mode 100644 index 000000000..4148d0d1c --- /dev/null +++ b/examples/lely_master/master_main.c @@ -0,0 +1,358 @@ +/**************************************************************************** + * apps/examples/lely_master/master_main.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <time.h> +#include <unistd.h> + +#include <canutils/lely/config.h> + +#include <lely/co/csdo.h> +#include <lely/co/dev.h> +#include <lely/co/nmt.h> +#include <lely/co/sdev.h> +#include <lely/co/sdo.h> +#include <lely/co/time.h> + +#include "sdev.h" +#include "candev.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SLAVE_ID 0x02 +#define OBJ_COUNTER 0x2100 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum master_phase_e +{ + PHASE_WAIT, /* wait for the slave, then read its info via SDO */ + PHASE_SDO, /* SDO request in flight */ + PHASE_RUN /* network operational, streaming PDO data */ +}; + +struct co_net_s +{ + can_net_t *net; + co_dev_t *dev; + co_nmt_t *nmt; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct co_net_s g_net; +static bool g_sdo_done; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: elapsed_ms + ****************************************************************************/ + +static long elapsed_ms(const struct timespec *a, const struct timespec *b) +{ + return (a->tv_sec - b->tv_sec) * 1000 + + (a->tv_nsec - b->tv_nsec) / 1000000; +} + +/**************************************************************************** + * Name: on_can_send + ****************************************************************************/ + +static int on_can_send(const struct can_msg *msg, void *data) +{ + UNUSED(data); + + return comaster_candev_send(msg); +} + +/**************************************************************************** + * Name: nmt_start_remote + ****************************************************************************/ + +static void nmt_start_remote(co_unsigned8_t id) +{ + struct can_msg msg; + + /* NMT command frame: COB-ID 0x000, {command specifier, node-ID} */ + + memset(&msg, 0, sizeof(msg)); + msg.len = 2; + msg.data[0] = CO_NMT_CS_START; + msg.data[1] = id; + + comaster_candev_send(&msg); +} + +/**************************************************************************** + * Name: on_sdo_up + ****************************************************************************/ + +static void on_sdo_up(co_csdo_t *sdo, co_unsigned16_t idx, + co_unsigned8_t subidx, co_unsigned32_t ac, + const void *ptr, size_t n, void *data) +{ + co_unsigned32_t val; + + UNUSED(sdo); + UNUSED(idx); + UNUSED(subidx); + UNUSED(data); + + if (ac == 0 && n >= sizeof(co_unsigned32_t)) + { + memcpy(&val, ptr, sizeof(val)); + printf("SDO: slave device type (0x1000) = 0x%08x\n", (unsigned)val); + } + else + { + printf("SDO: read failed, abort code 0x%08x\n", (unsigned)ac); + } + + g_sdo_done = true; +} + +/**************************************************************************** + * Name: on_time + ****************************************************************************/ + +static void on_time(co_time_t *time, const struct timespec *tp, void *data) +{ + UNUSED(time); + UNUSED(data); + + /* Update the wall clock */ + + clock_settime(CLOCK_REALTIME, tp); +} + +/**************************************************************************** + * Name: on_nmt_cs + ****************************************************************************/ + +static void on_nmt_cs(co_nmt_t *nmt, co_unsigned8_t cs, void *data) +{ + UNUSED(data); + + switch (cs) + { + case CO_NMT_CS_START: + case CO_NMT_CS_ENTER_PREOP: + { + co_time_set_ind(co_nmt_get_time(nmt), &on_time, NULL); + break; + } + + case CO_NMT_CS_RESET_NODE: + { + exit(0); + break; + } + + case CO_NMT_CS_STOP: + case CO_NMT_CS_RESET_COMM: + default: + { + break; + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + struct timespec now; + struct can_msg msg; + struct timespec t0; + co_unsigned32_t last = 0xffffffff; + int phase = PHASE_WAIT; + int ret; + co_csdo_t *csdo; + co_unsigned32_t v; + + memset(&g_net, 0, sizeof(g_net)); + g_sdo_done = false; + setvbuf(stdout, NULL, _IONBF, 0); + + ret = comaster_candev_init(); + if (ret < 0) + { + printf("ERROR: comaster_candev_init failed %d\n", ret); + goto errout; + } + + g_net.net = can_net_create(); + if (!g_net.net) + { + printf("ERROR: can_net_create failed\n"); + goto errout; + } + + can_net_set_send_func(g_net.net, &on_can_send, NULL); + + clock_gettime(CLOCK_MONOTONIC, &now); + can_net_set_time(g_net.net, &now); + + /* Create dev from struct */ + + g_net.dev = co_dev_create_from_sdev(&g_sdev_master); + if (!g_net.dev) + { + printf("ERROR: co_dev_create_from_sdev failed\n"); + goto errout; + } + + g_net.nmt = co_nmt_create(g_net.net, g_net.dev); + if (!g_net.nmt) + { + printf("ERROR: co_nmt_create failed\n"); + goto errout; + } + + /* Start the NMT service by resetting the node */ + + co_nmt_cs_ind(g_net.nmt, CO_NMT_CS_RESET_NODE); + + /* Set the NMT indication function after the initial reset */ + + co_nmt_set_cs_ind(g_net.nmt, &on_nmt_cs, NULL); + + printf("lely CANopen master running (node 0x%02x)\n", g_sdev_master.id); + + clock_gettime(CLOCK_MONOTONIC, &t0); + + while (1) + { + clock_gettime(CLOCK_MONOTONIC, &now); + can_net_set_time(g_net.net, &now); + + while (comaster_candev_recv(&msg) > 0) + { + can_net_recv(g_net.net, &msg); + } + + switch (phase) + { + /* Give the slave time to boot, then read its device type with + * a Client-SDO transfer (works while both nodes are pre-op). + */ + + case PHASE_WAIT: + { + if (elapsed_ms(&now, &t0) >= 500) + { + csdo = co_nmt_get_csdo(g_net.nmt, 1); + if (csdo != NULL && co_csdo_up_req( + csdo, 0x1000, 0x00, &on_sdo_up, NULL) == 0) + { + phase = PHASE_SDO; + } + else + { + t0 = now; + } + } + + break; + } + + /* Once the SDO completes, bring the network to OPERATIONAL: + * the master itself and the slave (NMT start). PDO/SYNC then + * flow. + */ + + case PHASE_SDO: + { + if (g_sdo_done) + { + co_nmt_cs_ind(g_net.nmt, CO_NMT_CS_START); + nmt_start_remote(SLAVE_ID); + printf("NMT: master + slave 0x%02x OPERATIONAL\n", + SLAVE_ID); + phase = PHASE_RUN; + } + + break; + } + + /* The slave's synchronous TPDO lands in object 0x2100 via the + * RPDO mapping; print it whenever it changes. + */ + + case PHASE_RUN: + { + v = co_dev_get_val_u32(g_net.dev, OBJ_COUNTER, 0x00); + if (v != last) + { + printf("PDO rx: counter = %u\n", (unsigned)v); + last = v; + } + + break; + } + } + + usleep(1000); + } + +errout: + if (g_net.nmt) + { + co_nmt_destroy(g_net.nmt); + } + + if (g_net.dev) + { + co_dev_destroy(g_net.dev); + } + + if (g_net.net) + { + can_net_destroy(g_net.net); + } + + return 0; +} diff --git a/examples/lely_master/sdev.h b/examples/lely_master/sdev.h new file mode 100644 index 000000000..559b8468d --- /dev/null +++ b/examples/lely_master/sdev.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * apps/examples/lely_master/sdev.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_LELY_SDEV_H +#define __APPS_EXAMPLES_LELY_SDEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <canutils/lely/config.h> +#include <lely/co/sdev.h> + +/**************************************************************************** + * Public data + ****************************************************************************/ + +extern const struct co_sdev g_sdev_master; + +#endif /* __APPS_EXAMPLES_LELY_SDEV_H */ diff --git a/examples/lely_master/sdev_master.c b/examples/lely_master/sdev_master.c new file mode 100644 index 000000000..34d5c6620 --- /dev/null +++ b/examples/lely_master/sdev_master.c @@ -0,0 +1,714 @@ +/**************************************************************************** + * apps/examples/lely_master/sdev_master.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include "sdev.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CO_SDEV_STRING(s) s + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Object 0x1000 sub-objects */ + +static const struct co_ssub g_1000_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Device type"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = CO_UNSIGNED32_MIN, +#endif + .val.u32 = CO_UNSIGNED32_MIN, + .access = CO_ACCESS_RO, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x1001 sub-objects */ + +static const struct co_ssub g_1001_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Error register"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED8, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u8 = CO_UNSIGNED8_MIN, + .max.u8 = CO_UNSIGNED8_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u8 = CO_UNSIGNED8_MIN, +#endif + .val.u8 = CO_UNSIGNED8_MIN, + .access = CO_ACCESS_RO, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x1005 sub-objects */ + +static const struct co_ssub g_1005_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("COB-ID SYNC message"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = 0x40000080lu, +#endif + .val.u32 = 0x40000080lu, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x1006 sub-objects */ + +static const struct co_ssub g_1006_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Communication cycle period"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = 0x000186a0lu, +#endif + .val.u32 = 0x000186a0lu, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x1012 sub-objects */ + +static const struct co_ssub g_1012_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("COB-ID time stamp object"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = 0x80000100lu, +#endif + .val.u32 = 0x80000100lu, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x1017 sub-objects */ + +static const struct co_ssub g_1017_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Producer heartbeat time"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED16, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u16 = CO_UNSIGNED16_MIN, + .max.u16 = CO_UNSIGNED16_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u16 = 0x0032, +#endif + .val.u16 = 0x0032, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x1018 sub-objects */ + +static const struct co_ssub g_1018_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Highest sub-index supported"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED8, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u8 = CO_UNSIGNED8_MIN, + .max.u8 = CO_UNSIGNED8_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u8 = 0x04, +#endif + .val.u8 = 0x04, + .access = CO_ACCESS_CONST, + .pdo_mapping = 0, + .flags = 0 + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Vendor-ID"), +#endif + .subidx = 0x01, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = 0x00000360lu, +#endif + .val.u32 = 0x00000360lu, + .access = CO_ACCESS_RO, + .pdo_mapping = 0, + .flags = 0 + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Product code"), +#endif + .subidx = 0x02, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = CO_UNSIGNED32_MIN, +#endif + .val.u32 = CO_UNSIGNED32_MIN, + .access = CO_ACCESS_RO, + .pdo_mapping = 0, + .flags = 0 + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Revision number"), +#endif + .subidx = 0x03, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = CO_UNSIGNED32_MIN, +#endif + .val.u32 = CO_UNSIGNED32_MIN, + .access = CO_ACCESS_RO, + .pdo_mapping = 0, + .flags = 0 + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Serial number"), +#endif + .subidx = 0x04, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = CO_UNSIGNED32_MIN, +#endif + .val.u32 = CO_UNSIGNED32_MIN, + .access = CO_ACCESS_RO, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x1280 sub-objects */ + +static const struct co_ssub g_1280_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Highest sub-index supported"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED8, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u8 = CO_UNSIGNED8_MIN, + .max.u8 = CO_UNSIGNED8_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u8 = 0x03, +#endif + .val.u8 = 0x03, + .access = CO_ACCESS_CONST, + .pdo_mapping = 0, + .flags = 0 + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("COB-ID client to server"), +#endif + .subidx = 0x01, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = 0x00000602lu, +#endif + .val.u32 = 0x00000602lu, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("COB-ID server to client"), +#endif + .subidx = 0x02, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = 0x00000582lu, +#endif + .val.u32 = 0x00000582lu, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Node-ID of the SDO server"), +#endif + .subidx = 0x03, + .type = CO_DEFTYPE_UNSIGNED8, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u8 = CO_UNSIGNED8_MIN, + .max.u8 = CO_UNSIGNED8_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u8 = 0x02, +#endif + .val.u8 = 0x02, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x1400 sub-objects */ + +static const struct co_ssub g_1400_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Highest sub-index supported"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED8, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u8 = CO_UNSIGNED8_MIN, + .max.u8 = CO_UNSIGNED8_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u8 = 0x02, +#endif + .val.u8 = 0x02, + .access = CO_ACCESS_CONST, + .pdo_mapping = 0, + .flags = 0 + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("COB-ID"), +#endif + .subidx = 0x01, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = 0x00000182lu, +#endif + .val.u32 = 0x00000182lu, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Transmission type"), +#endif + .subidx = 0x02, + .type = CO_DEFTYPE_UNSIGNED8, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u8 = CO_UNSIGNED8_MIN, + .max.u8 = CO_UNSIGNED8_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u8 = 0x01, +#endif + .val.u8 = 0x01, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x1600 sub-objects */ + +static const struct co_ssub g_1600_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Number of mapped objects"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED8, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u8 = CO_UNSIGNED8_MIN, + .max.u8 = CO_UNSIGNED8_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u8 = 0x01, +#endif + .val.u8 = 0x01, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Mapping 1"), +#endif + .subidx = 0x01, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = 0x21000020lu, +#endif + .val.u32 = 0x21000020lu, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x1f80 sub-objects */ + +static const struct co_ssub g_1f80_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("NMT startup"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = CO_UNSIGNED32_MIN, +#endif + .val.u32 = 0x00000000lu, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + | CO_OBJ_FLAGS_PARAMETER_VALUE + } +}; + +/* Object 0x2000 sub-objects */ + +static const struct co_ssub g_2000_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Object with custom SDO download callback"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = CO_UNSIGNED32_MIN, +#endif + .val.u32 = CO_UNSIGNED32_MIN, + .access = CO_ACCESS_RW, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x2001 sub-objects */ + +static const struct co_ssub g_2001_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Object with custom SDO upload callback"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = CO_UNSIGNED32_MIN, +#endif + .val.u32 = CO_UNSIGNED32_MIN, + .access = CO_ACCESS_RO, + .pdo_mapping = 0, + .flags = 0 + } +}; + +/* Object 0x2100 sub-objects */ + +static const struct co_ssub g_2100_sub[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Counter"), +#endif + .subidx = 0x00, + .type = CO_DEFTYPE_UNSIGNED32, +#if !LELY_NO_CO_OBJ_LIMITS + .min.u32 = CO_UNSIGNED32_MIN, + .max.u32 = CO_UNSIGNED32_MAX, +#endif +#if !LELY_NO_CO_OBJ_DEFAULT + .def.u32 = CO_UNSIGNED32_MIN, +#endif + .val.u32 = CO_UNSIGNED32_MIN, + .access = CO_ACCESS_RW, + .pdo_mapping = 1, + .flags = 0 + } +}; + +/* Object dictionary */ + +static const struct co_sobj g_g_sdev_master_objs[] = +{ + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Device type"), +#endif + .idx = 0x1000, + .code = CO_OBJECT_VAR, + .nsub = 1, + .subs = g_1000_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Error register"), +#endif + .idx = 0x1001, + .code = CO_OBJECT_VAR, + .nsub = 1, + .subs = g_1001_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("COB-ID SYNC message"), +#endif + .idx = 0x1005, + .code = CO_OBJECT_VAR, + .nsub = 1, + .subs = g_1005_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Communication cycle period"), +#endif + .idx = 0x1006, + .code = CO_OBJECT_VAR, + .nsub = 1, + .subs = g_1006_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("COB-ID time stamp object"), +#endif + .idx = 0x1012, + .code = CO_OBJECT_VAR, + .nsub = 1, + .subs = g_1012_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Producer heartbeat time"), +#endif + .idx = 0x1017, + .code = CO_OBJECT_VAR, + .nsub = 1, + .subs = g_1017_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Identity object"), +#endif + .idx = 0x1018, + .code = CO_OBJECT_RECORD, + .nsub = 5, + .subs = g_1018_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("SDO client parameter"), +#endif + .idx = 0x1280, + .code = CO_OBJECT_RECORD, + .nsub = 4, + .subs = g_1280_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("RPDO communication parameter"), +#endif + .idx = 0x1400, + .code = CO_OBJECT_RECORD, + .nsub = 3, + .subs = g_1400_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("RPDO mapping parameter"), +#endif + .idx = 0x1600, + .code = CO_OBJECT_RECORD, + .nsub = 2, + .subs = g_1600_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("NMT startup"), +#endif + .idx = 0x1f80, + .code = CO_OBJECT_VAR, + .nsub = 1, + .subs = g_1f80_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Object with custom SDO download callback"), +#endif + .idx = 0x2000, + .code = CO_OBJECT_VAR, + .nsub = 1, + .subs = g_2000_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Object with custom SDO upload callback"), +#endif + .idx = 0x2001, + .code = CO_OBJECT_VAR, + .nsub = 1, + .subs = g_2001_sub + }, + { +#if !LELY_NO_CO_OBJ_NAME + .name = CO_SDEV_STRING("Counter"), +#endif + .idx = 0x2100, + .code = CO_OBJECT_VAR, + .nsub = 1, + .subs = g_2100_sub + } +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct co_sdev g_sdev_master = +{ + .id = 0x01, + .name = NULL, + .vendor_name = CO_SDEV_STRING("Apache NuttX RTOS"), + .vendor_id = 0x00000000, + .product_name = NULL, + .product_code = 0x00000000, + .revision = 0x00000000, + .order_code = NULL, + .baud = CO_BAUD_125, + .rate = 0, + .lss = 0, + .dummy = 0x000000fe, + .nobj = 14, + .objs = g_g_sdev_master_objs +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/
