This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push: new a85121b16 netutils: Add plcatool a85121b16 is described below commit a85121b16844655298f52a0b8830431001edc9ec Author: michal matias <mich4l.mat...@gmail.com> AuthorDate: Fri Aug 29 06:08:51 2025 +0200 netutils: Add plcatool Add plcatool - simple tool for managing PLCA configuration in 10BASE-T1S PHYs. Signed-off-by: michal matias <mich4l.mat...@gmail.com> --- netutils/plcatool/CMakeLists.txt | 33 ++ netutils/plcatool/Kconfig | 12 + netutils/plcatool/Make.defs | 25 ++ netutils/plcatool/Makefile | 32 ++ netutils/plcatool/oa_tc14.h | 85 +++++ netutils/plcatool/plcatool.c | 713 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 900 insertions(+) diff --git a/netutils/plcatool/CMakeLists.txt b/netutils/plcatool/CMakeLists.txt new file mode 100644 index 000000000..dae7401d8 --- /dev/null +++ b/netutils/plcatool/CMakeLists.txt @@ -0,0 +1,33 @@ +# ############################################################################## +# apps/netutils/plcatool/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_NETUTILS_PLCATOOL) + nuttx_add_application( + NAME + plcatool + STACKSIZE + ${CONFIG_DEFAULT_TASK_STACKSIZE} + MODULE + ${CONFIG_NETUTILS_PLCATOOL} + SRCS + plcatool.c) +endif() diff --git a/netutils/plcatool/Kconfig b/netutils/plcatool/Kconfig new file mode 100644 index 000000000..59f156809 --- /dev/null +++ b/netutils/plcatool/Kconfig @@ -0,0 +1,12 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config NETUTILS_PLCATOOL + bool "plcatool support" + default n + ---help--- + Build in support for the plcatool command. This command allows configuring + the PLCA access method in 10BASE-T1S network adapters supporting PLCA. + Syntax of the plcatool is inspired by the corresponding syntax used by the ethtool. diff --git a/netutils/plcatool/Make.defs b/netutils/plcatool/Make.defs new file mode 100644 index 000000000..a24cb72dd --- /dev/null +++ b/netutils/plcatool/Make.defs @@ -0,0 +1,25 @@ +############################################################################ +# apps/netutils/plcatool/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_NETUTILS_PLCATOOL),) +CONFIGURED_APPS += $(APPDIR)/netutils/plcatool +endif diff --git a/netutils/plcatool/Makefile b/netutils/plcatool/Makefile new file mode 100644 index 000000000..7ae73ada5 --- /dev/null +++ b/netutils/plcatool/Makefile @@ -0,0 +1,32 @@ +############################################################################ +# apps/netutils/plcatool/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 + +MAINSRC = plcatool.c + +PROGNAME = plcatool +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE) +MODULE = $(CONFIG_NETUTILS_PLCATOOL) + +include $(APPDIR)/Application.mk diff --git a/netutils/plcatool/oa_tc14.h b/netutils/plcatool/oa_tc14.h new file mode 100644 index 000000000..bfcfe19f8 --- /dev/null +++ b/netutils/plcatool/oa_tc14.h @@ -0,0 +1,85 @@ +/**************************************************************************** + * apps/netutils/plcatool/oa_tc14.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_NETUTILS_PLCATOOL_OA_TC14_H +#define __APPS_NETUTILS_PLCATOOL_OA_TC14_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/bits.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define OA_TC14_PLCA_MMD 31 + +#define OA_TC14_IDVER_ADDR 0xCA00 +#define OA_TC14_IDVER_IDM_MASK GENMASK(15, 8) +#define OA_TC14_IDVER_IDM_POS 8 +#define OA_TC14_IDVER_VER_MASK GENMASK(7, 0) +#define OA_TC14_IDVER_VER_POS 0 +#define OA_TC14_IDVER_VAL 0x0A10 + +#define OA_TC14_CTRL0_ADDR 0xCA01 +#define OA_TC14_CTRL0_EN_MASK BIT(15) +#define OA_TC14_CTRL0_EN_POS 15 +#define OA_TC14_CTRL0_RST_MASK BIT(14) +#define OA_TC14_CTRL0_RST_POS 14 + +#define OA_TC14_CTRL1_ADDR 0xCA02 +#define OA_TC14_CTRL1_NCNT_MASK GENMASK(15, 8) +#define OA_TC14_CTRL1_NCNT_POS 8 +#define OA_TC14_CTRL1_ID_MASK GENMASK(7, 0) +#define OA_TC14_CTRL1_ID_POS 0 + +#define OA_TC14_STATUS_ADDR 0xCA03 +#define OA_TC14_STATUS_PST_MASK BIT(15) +#define OA_TC14_STATUS_PST_POS 15 + +#define OA_TC14_TOTMR_ADDR 0xCA04 +#define OA_TC14_TOTMR_TOT_MASK GENMASK(7, 0) +#define OA_TC14_TOTMR_TOT_POS 0 + +#define OA_TC14_BURST_ADDR 0xCA05 +#define OA_TC14_BURST_MAXBC_MASK GENMASK(15, 8) +#define OA_TC14_BURST_MAXBC_POS 8 +#define OA_TC14_BURST_BTMR_MASK GENMASK(7, 0) +#define OA_TC14_BURST_BTMR_POS 0 + +#define OA_TC14_DIAG_ADDR 0xCA06 +#define OA_TC14_DIAG_RXINTO_MASK BIT(2) +#define OA_TC14_DIAG_RXINTO_POS 2 +#define OA_TC14_DIAG_UNEXPB_MASK BIT(1) +#define OA_TC14_DIAG_UNEXPB_POS 1 +#define OA_TC14_DIAG_BCNBFTO_MASK BIT(0) +#define OA_TC14_DIAG_BCNBFTO_POS 0 + +#define oa_tc14_get_field(r, fieldname) \ + (((r) & OA_TC14_##fieldname##_MASK) >> OA_TC14_##fieldname##_POS) + +#define oa_tc14_field(val, fieldname) \ + ((val << OA_TC14_##fieldname##_POS) & OA_TC14_##fieldname##_MASK) + +#endif /* __APPS_NETUTILS_PLCATOOL_OA_TC14_H */ diff --git a/netutils/plcatool/plcatool.c b/netutils/plcatool/plcatool.c new file mode 100644 index 000000000..9d170968b --- /dev/null +++ b/netutils/plcatool/plcatool.c @@ -0,0 +1,713 @@ +/**************************************************************************** + * apps/netutils/plcatool/plcatool.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 <stdint.h> +#include <string.h> +#include <errno.h> + +#include <net/if.h> +#include <sys/ioctl.h> + +#include "oa_tc14.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ARGS_REMAIN(argc, pos) ((argc) - (pos)) + +#define PLCATOOL_CFG_SET_BIT 0x8000 +#define PLCATOOL_CFG_SET(cfg, field, val) \ + do {(cfg)->field = PLCATOOL_CFG_SET_BIT | ((val) & 0xff);} while (0) + +#define PLCATOOL_CFG_VAL(cfg, field) ((cfg)->field & 0xff) + +#define NODE_ID_MIN 0 +#define NODE_ID_MAX 255 + +#define NODE_CNT_MIN 1 +#define NODE_CNT_MAX 255 + +#define TO_TMR_MIN 0 +#define TO_TMR_MAX 255 + +#define BURST_CNT_MIN 0 +#define BURST_CNT_MAX 255 + +#define BURST_TMR_MIN 0 +#define BURST_TMR_MAX 255 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum plcatool_cmd_e +{ + PLCA_CMD_SET, + PLCA_CMD_GET, + PLCA_CMD_STATUS, + PLCA_CMD_HELP +}; + +/* Lower 8 bits are value, the most significant bit indicates whether set */ + +struct plcatool_cfg_s +{ + enum plcatool_cmd_e cmd; + + FAR char *ifname; + + uint8_t phy; + + uint16_t enable; + uint16_t node_cnt; + uint16_t node_id; + uint16_t to_tmr; + uint16_t burst_cnt; + uint16_t burst_tmr; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int get_num(FAR const char *str, FAR int *result); +static int parse_args(int argc, FAR char *argv[], + FAR struct plcatool_cfg_s *cfg); +static int write_plca_mmd(FAR const char *ifname, int phy, + uint16_t address, uint16_t data); +static int read_plca_mmd(FAR const char *ifname, int phy, + uint16_t address, FAR uint16_t *data); +static int verify_support(FAR struct plcatool_cfg_s *cfg, + FAR bool *supported); +static int plcatool_set(FAR struct plcatool_cfg_s *cfg); +static int plcatool_get(FAR struct plcatool_cfg_s *cfg); +static int plcatool_status(FAR struct plcatool_cfg_s *cfg); +static void plcatool_usage(bool err); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int get_num(FAR const char *str, FAR int *result) +{ + FAR char *endptr; + *result = (int)strtol(str, &endptr, 0); + + if (*endptr != '\0') + { + return ERROR; + } + + return OK; +} + +static int parse_args(int argc, FAR char *argv[], + FAR struct plcatool_cfg_s *cfg) +{ + FAR const char *cmd; + int argpos = 1; + + if (argc < 2) + { + return ERROR; + } + + if (strcmp(argv[argpos++], "--phy") == 0) + { + int phynum; + + if (ARGS_REMAIN(argc, argpos) < 3) /* at least phynum, cmd, intf */ + { + return ERROR; + } + + if (get_num(argv[argpos++], &phynum)) + { + return ERROR; + } + + if (0 <= phynum && phynum <= 31) + { + cfg->phy = phynum; + } + else + { + return ERROR; + } + } + else + { + argpos = 1; + cfg->phy = 0; + } + + cmd = argv[argpos++]; + + if (strcmp(cmd, "set") == 0) + { + cfg->cmd = PLCA_CMD_SET; + + if (ARGS_REMAIN(argc, argpos) < 3) /* name, at least one param-value */ + { + return ERROR; + } + + cfg->ifname = argv[argpos++]; + + while (ARGS_REMAIN(argc, argpos) >= 2) /* at least one param-value */ + { + FAR const char *param = argv[argpos++]; + FAR const char *value = argv[argpos++]; + + if (strcmp(param, "enable") == 0) + { + if (cfg->enable) + { + return ERROR; + } + + if (strcmp(value, "on") == 0) + { + PLCATOOL_CFG_SET(cfg, enable, 1); + } + else if (strcmp(value, "off") == 0) + { + PLCATOOL_CFG_SET(cfg, enable, 0); + } + else + { + return ERROR; + } + } + else if (strcmp(param, "node-id") == 0) + { + int n; + + if (cfg->node_id) + { + return ERROR; + } + + if (get_num(value, &n)) + { + return ERROR; + } + + if (NODE_ID_MIN <= n && n <= NODE_ID_MAX) + { + PLCATOOL_CFG_SET(cfg, node_id, n); + } + else + { + fprintf(stderr, "node-id out of range\n"); + return ERROR; + } + } + else if (strcmp(param, "node-cnt") == 0) + { + int n; + + if (cfg->node_cnt) + { + return ERROR; + } + + if (get_num(value, &n)) + { + fprintf(stderr, "Not a valid integer\n"); + return ERROR; + } + + if (NODE_CNT_MIN <= n && n <= NODE_CNT_MAX) + { + PLCATOOL_CFG_SET(cfg, node_cnt, n); + } + else + { + fprintf(stderr, "node-cnt out of range\n"); + return ERROR; + } + } + else if (strcmp(param, "to-tmr") == 0) + { + int n; + + if (cfg->to_tmr) + { + return ERROR; + } + + if (get_num(value, &n)) + { + fprintf(stderr, "Not a valid integer\n"); + return ERROR; + } + + if (TO_TMR_MIN <= n && n <= TO_TMR_MAX) + { + PLCATOOL_CFG_SET(cfg, to_tmr, n); + } + else + { + fprintf(stderr, "to_tmr out of range\n"); + return ERROR; + } + } + else if (strcmp(param, "burst-cnt") == 0) + { + int n; + + if (cfg->burst_cnt) + { + return ERROR; + } + + if (get_num(value, &n)) + { + fprintf(stderr, "Not a valid integer\n"); + return ERROR; + } + + if (BURST_CNT_MIN <= n && n <= BURST_CNT_MAX) + { + PLCATOOL_CFG_SET(cfg, burst_cnt, n); + } + else + { + fprintf(stderr, "burst-cnt out of range\n"); + return ERROR; + } + } + else if (strcmp(param, "burst-tmr") == 0) + { + int n; + + if (cfg->burst_tmr) + { + return ERROR; + } + + if (get_num(value, &n)) + { + fprintf(stderr, "Not a valid integer\n"); + return ERROR; + } + + if (BURST_TMR_MIN <= n && n <= BURST_TMR_MAX) + { + PLCATOOL_CFG_SET(cfg, burst_tmr, n); + } + else + { + fprintf(stderr, "burst-tmr out of range\n"); + return ERROR; + } + } + else + { + return ERROR; + } + } + + if (ARGS_REMAIN(argc, argpos) != 0) + { + return ERROR; + } + } + else if (strcmp(cmd, "get") == 0) + { + cfg->cmd = PLCA_CMD_GET; + + if (ARGS_REMAIN(argc, argpos) != 1) /* ifname */ + { + return ERROR; + } + + cfg->ifname = argv[argpos++]; + if (strlen(cfg->ifname) > IFNAMSIZ) + { + fprintf(stderr, "No such interface\n"); + return ERROR; + } + } + else if (strcmp(cmd, "status") == 0) + { + cfg->cmd = PLCA_CMD_STATUS; + + if (ARGS_REMAIN(argc, argpos) != 1) /* ifname */ + { + return ERROR; + } + + cfg->ifname = argv[argpos++]; + if (strlen(cfg->ifname) > IFNAMSIZ) + { + fprintf(stderr, "No such interface\n"); + return ERROR; + } + } + else if (strcmp(cmd, "-h") == 0) + { + cfg->cmd = PLCA_CMD_HELP; + + if (ARGS_REMAIN(argc, argpos) != 0) + { + return ERROR; + } + } + else + { + return ERROR; + } + + return OK; +} + +static int write_plca_mmd(FAR const char *ifname, int phy, + uint16_t address, uint16_t data) +{ + struct ifreq req; + int retval; + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + strcpy(req.ifr_name, ifname); + req.ifr_ifru.ifru_mii_data.phy_id = mdio_phy_id_c45(OA_TC14_PLCA_MMD, phy); + req.ifr_ifru.ifru_mii_data.reg_num = address; + req.ifr_ifru.ifru_mii_data.val_in = data; + retval = ioctl(sockfd, SIOCSMIIREG, (unsigned long)(&req)); + if (retval) + { + close(sockfd); + fprintf(stderr, "Write unsuccessful\n"); + return ERROR; + } + + close(sockfd); + return OK; +} + +static int read_plca_mmd(FAR const char *ifname, int phy, + uint16_t address, FAR uint16_t *data) +{ + struct ifreq req; + int retval; + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + strcpy(req.ifr_name, ifname); + req.ifr_ifru.ifru_mii_data.phy_id = mdio_phy_id_c45(OA_TC14_PLCA_MMD, phy); + req.ifr_ifru.ifru_mii_data.reg_num = address; + + retval = ioctl(sockfd, SIOCGMIIREG, (unsigned long)(&req)); + if (retval) + { + close(sockfd); + fprintf(stderr, "Read unsuccessful\n"); + return ERROR; + } + + *data = req.ifr_ifru.ifru_mii_data.val_out; + + close(sockfd); + return OK; +} + +static int verify_support(FAR struct plcatool_cfg_s *cfg, + FAR bool *supported) +{ + uint16_t reg; + if (read_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_IDVER_ADDR, ®)) + { + return ERROR; + } + + *supported = reg == OA_TC14_IDVER_VAL ? true : false; + + return OK; +} + +static int plcatool_set(FAR struct plcatool_cfg_s *cfg) +{ + uint16_t reg; + bool supported; + + /* Verify the correct address map code */ + + if (verify_support(cfg, &supported)) + { + return EIO; + } + + if (!supported) + { + fprintf(stderr, "Device not supported\n"); + return EINVAL; + } + + /* node-cnt, node-id */ + + if (cfg->node_cnt || cfg->node_id) + { + if (read_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_CTRL1_ADDR, ®)) + { + return EIO; + } + + if (cfg->node_cnt) + { + int val = PLCATOOL_CFG_VAL(cfg, node_cnt); + reg &= ~OA_TC14_CTRL1_NCNT_MASK; + reg |= oa_tc14_field(val, CTRL1_NCNT); + } + + if (cfg->node_id) + { + int val = PLCATOOL_CFG_VAL(cfg, node_id); + reg &= ~OA_TC14_CTRL1_ID_MASK; + reg |= oa_tc14_field(val, CTRL1_ID); + } + + if (write_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_CTRL1_ADDR, reg)) + { + return EIO; + } + } + + /* to-tmr */ + + if (cfg->to_tmr) + { + int val = PLCATOOL_CFG_VAL(cfg, to_tmr); + reg = oa_tc14_field(val, TOTMR_TOT); + + if (write_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_TOTMR_ADDR, reg)) + { + return EIO; + } + } + + /* burst-cnt, burst-tmr */ + + if (cfg->burst_cnt || cfg->burst_tmr) + { + if (read_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_BURST_ADDR, ®)) + { + return EIO; + } + + if (cfg->burst_cnt) + { + int val = PLCATOOL_CFG_VAL(cfg, burst_cnt); + reg &= ~OA_TC14_BURST_MAXBC_MASK; + reg |= oa_tc14_field(val, BURST_MAXBC); + } + + if (cfg->burst_tmr) + { + int val = PLCATOOL_CFG_VAL(cfg, burst_tmr); + reg &= ~OA_TC14_BURST_BTMR_MASK; + reg |= oa_tc14_field(val, BURST_BTMR); + } + + if (write_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_BURST_ADDR, reg)) + { + return EIO; + } + } + + /* enable */ + + if (cfg->enable) + { + int val; + if (read_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_CTRL0_ADDR, ®)) + { + return EIO; + } + + val = PLCATOOL_CFG_VAL(cfg, enable); + reg &= ~OA_TC14_CTRL0_EN_MASK; + reg |= oa_tc14_field(val, CTRL0_EN); + + if (write_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_CTRL0_ADDR, reg)) + { + return EIO; + } + + read_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_CTRL0_ADDR, ®); + } + + return OK; +} + +static int plcatool_get(FAR struct plcatool_cfg_s *cfg) +{ + uint16_t ctrl0; + uint16_t ctrl1; + uint16_t totmr; + uint16_t burst; + bool supported; + + /* Verify the correct address map code */ + + if (verify_support(cfg, &supported)) + { + return EIO; + } + + if (!supported) + { + fprintf(stderr, "Device not supported\n"); + return EINVAL; + } + + if (read_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_CTRL0_ADDR, &ctrl0) || + read_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_CTRL1_ADDR, &ctrl1) || + read_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_TOTMR_ADDR, &totmr) || + read_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_BURST_ADDR, &burst)) + { + return EIO; + } + + cfg->enable = oa_tc14_get_field(ctrl0, CTRL0_EN); + cfg->node_id = oa_tc14_get_field(ctrl1, CTRL1_ID); + cfg->node_cnt = oa_tc14_get_field(ctrl1, CTRL1_NCNT); + cfg->to_tmr = oa_tc14_get_field(totmr, TOTMR_TOT); + cfg->burst_cnt = oa_tc14_get_field(burst, BURST_MAXBC); + cfg->burst_tmr = oa_tc14_get_field(burst, BURST_BTMR); + + printf("PLCA settings for %s\n", cfg->ifname); + printf("\tEnabled: %s\n", cfg->enable ? "Yes" : "No"); + printf("\tlocal node ID: %d (%s)\n", cfg->node_id, + cfg->node_id == 0 ? "coordinator" : + (cfg->node_id == 255 ? "unconfigured" : "follower")); + printf("\tNode count: %d%s\n", cfg->node_cnt, + cfg->node_id ? " (ignored)" : ""); + printf("\tTO timer: %d BT\n", cfg->to_tmr); + printf("\tBurst count: %d (%s)\n", cfg->burst_cnt, + cfg->burst_cnt > 0 ? "enabled" : "disabled"); + printf("\tBurst timer: %d BT\n", cfg->burst_tmr); + + return OK; +} + +static int plcatool_status(FAR struct plcatool_cfg_s *cfg) +{ + uint16_t status; + bool supported; + + /* Verify the correct address map code */ + + if (verify_support(cfg, &supported)) + { + return EIO; + } + + if (!supported) + { + fprintf(stderr, "Device not supported\n"); + return EINVAL; + } + + if (read_plca_mmd(cfg->ifname, cfg->phy, OA_TC14_STATUS_ADDR, &status)) + { + return EIO; + } + + printf("PLCA status of %s\n", cfg->ifname); + printf("\tStatus: %s\n", + oa_tc14_get_field(status, STATUS_PST) ? "on" : "off"); + + return OK; +} + +static void plcatool_usage(bool err) +{ + FAR FILE *out = err ? stderr : stdout; + + fprintf(out, "Usage:\n"); + fprintf(out, " plcatool [--phy N] status <ifname>\n"); + fprintf(out, " plcatool [--phy N] get <ifname>\n"); + fprintf(out, " plcatool [--phy N] set <ifname> <param> <value> " + "[<param> <value>] ...\n"); + fprintf(out, " Accepted <param> <value> pairs:\n"); + fprintf(out, " enable on | off\n"); + fprintf(out, " node-id N in [%d .. %d]\n", + NODE_ID_MIN, NODE_ID_MAX); + fprintf(out, " node-cnt N in [%d .. %d]\n", + NODE_CNT_MIN, NODE_CNT_MAX); + fprintf(out, " to-tmr N in [%d .. %d]\n", + TO_TMR_MIN, TO_TMR_MAX); + fprintf(out, " burst-cnt N in [%d .. %d]\n", + BURST_CNT_MIN, BURST_CNT_MAX); + fprintf(out, " burst-tmr N in [%d .. %d]\n", + BURST_TMR_MIN, BURST_TMR_MAX); + fprintf(out, " plcatool -h\n"); + fprintf(out, " --phy N defaults to 0\n"); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + struct plcatool_cfg_s cfg; + memset(&cfg, 0, sizeof(cfg)); + + int err = parse_args(argc, argv, &cfg); + if (err) + { + plcatool_usage(err); + return EINVAL; + } + + switch (cfg.cmd) + { + case PLCA_CMD_SET: + return plcatool_set(&cfg); + + case PLCA_CMD_GET: + return plcatool_get(&cfg); + + case PLCA_CMD_STATUS: + return plcatool_status(&cfg); + + case PLCA_CMD_HELP: + plcatool_usage(false); + break; + } + + return OK; +}