Update `struct gpio_dt_spec` use with gpio_is_ready_dt() Signed-off-by: Nick Ward <nix.ward@gmail.com>
167 lines
3.2 KiB
C
167 lines
3.2 KiB
C
/*
|
|
* Copyright (c) 2020 PHYTEC Messtechnik GmbH
|
|
* Copyright (c) 2022 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/sys/util.h>
|
|
#include <zephyr/drivers/gpio.h>
|
|
#include <zephyr/modbus/modbus.h>
|
|
#include <zephyr/usb/usb_device.h>
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(mbs_sample, LOG_LEVEL_INF);
|
|
|
|
static uint16_t holding_reg[8];
|
|
static uint8_t coils_state;
|
|
|
|
static const struct gpio_dt_spec led_dev[] = {
|
|
GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios),
|
|
GPIO_DT_SPEC_GET(DT_ALIAS(led1), gpios),
|
|
GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios),
|
|
};
|
|
|
|
static int coil_rd(uint16_t addr, bool *state)
|
|
{
|
|
if (addr >= ARRAY_SIZE(led_dev)) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
if (coils_state & BIT(addr)) {
|
|
*state = true;
|
|
} else {
|
|
*state = false;
|
|
}
|
|
|
|
LOG_INF("Coil read, addr %u, %d", addr, (int)*state);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int coil_wr(uint16_t addr, bool state)
|
|
{
|
|
bool on;
|
|
|
|
if (addr >= ARRAY_SIZE(led_dev)) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
|
|
if (state == true) {
|
|
coils_state |= BIT(addr);
|
|
on = true;
|
|
} else {
|
|
coils_state &= ~BIT(addr);
|
|
on = false;
|
|
}
|
|
|
|
gpio_pin_set(led_dev[addr].port, led_dev[addr].pin, (int)on);
|
|
|
|
LOG_INF("Coil write, addr %u, %d", addr, (int)state);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int holding_reg_rd(uint16_t addr, uint16_t *reg)
|
|
{
|
|
if (addr >= ARRAY_SIZE(holding_reg)) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
*reg = holding_reg[addr];
|
|
|
|
LOG_INF("Holding register read, addr %u", addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int holding_reg_wr(uint16_t addr, uint16_t reg)
|
|
{
|
|
if (addr >= ARRAY_SIZE(holding_reg)) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
holding_reg[addr] = reg;
|
|
|
|
LOG_INF("Holding register write, addr %u", addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct modbus_user_callbacks mbs_cbs = {
|
|
.coil_rd = coil_rd,
|
|
.coil_wr = coil_wr,
|
|
.holding_reg_rd = holding_reg_rd,
|
|
.holding_reg_wr = holding_reg_wr,
|
|
};
|
|
|
|
const static struct modbus_iface_param server_param = {
|
|
.mode = MODBUS_MODE_RTU,
|
|
.server = {
|
|
.user_cb = &mbs_cbs,
|
|
.unit_id = 1,
|
|
},
|
|
.serial = {
|
|
.baud = 19200,
|
|
.parity = UART_CFG_PARITY_NONE,
|
|
},
|
|
};
|
|
|
|
#define MODBUS_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_modbus_serial)
|
|
|
|
static int init_modbus_server(void)
|
|
{
|
|
const char iface_name[] = {DEVICE_DT_NAME(MODBUS_NODE)};
|
|
int iface;
|
|
|
|
iface = modbus_iface_get_by_name(iface_name);
|
|
|
|
if (iface < 0) {
|
|
LOG_ERR("Failed to get iface index for %s", iface_name);
|
|
return iface;
|
|
}
|
|
|
|
return modbus_init_server(iface, server_param);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
int err;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(led_dev); i++) {
|
|
if (!gpio_is_ready_dt(&led_dev[i])) {
|
|
LOG_ERR("LED%u GPIO device not ready", i);
|
|
return 0;
|
|
}
|
|
|
|
err = gpio_pin_configure_dt(&led_dev[i], GPIO_OUTPUT_INACTIVE);
|
|
if (err != 0) {
|
|
LOG_ERR("Failed to configure LED%u pin", i);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#if DT_NODE_HAS_COMPAT(DT_PARENT(MODBUS_NODE), zephyr_cdc_acm_uart)
|
|
const struct device *const dev = DEVICE_DT_GET(DT_PARENT(MODBUS_NODE));
|
|
uint32_t dtr = 0;
|
|
|
|
if (!device_is_ready(dev) || usb_enable(NULL)) {
|
|
return 0;
|
|
}
|
|
|
|
while (!dtr) {
|
|
uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr);
|
|
k_sleep(K_MSEC(100));
|
|
}
|
|
|
|
LOG_INF("Client connected to server on %s", dev->name);
|
|
#endif
|
|
|
|
if (init_modbus_server()) {
|
|
LOG_ERR("Modbus RTU server initialization failed");
|
|
}
|
|
return 0;
|
|
}
|