11#if PC_ENABLE_SOUTHBOUND && PC_ENABLE_MODBUS_MASTER
21int sb_modbus_read_span(pc_sb_modbus_ctx *c, uint32_t first, int32_t *out,
size_t n)
24 if (n == 0 || n > 125 || first > 0xFFFFu || first + n > 0x10000u)
26 return Sb::SB_ERR_ARG;
31 pc_modbus_build_read((uint8_t)c->fc, c->txid++, c->unit, (uint16_t)first, (uint16_t)n, req,
sizeof(req));
34 return Sb::SB_ERR_ARG;
37 uint8_t resp[MODBUS_ADU_MAX];
38 int pn = c->txn(c->io, req, rn, resp,
sizeof(resp));
46 int got = pc_modbus_parse_response(resp, (
size_t)pn, regs, n, &ex);
49 return Sb::SB_ERR_ARG;
51 c->last_exception = ex;
54 return PC_SB_MODBUS_EXCEPTION;
56 for (
int i = 0; i < got; i++)
58 out[i] = (int32_t)regs[i];
63int sb_modbus_read(
void *vctx, uint32_t point, int32_t *value_out)
65 pc_sb_modbus_ctx *c = (pc_sb_modbus_ctx *)vctx;
66 int got = sb_modbus_read_span(c, point, value_out, 1);
71 return (got == 1) ? Sb::SB_OK : Sb::SB_ERR_ARG;
74int sb_modbus_read_block(
void *vctx, uint32_t first, int32_t *out,
size_t n)
76 return sb_modbus_read_span((pc_sb_modbus_ctx *)vctx, first, out, n);
83int sb_modbus_write_txn(pc_sb_modbus_ctx *c,
const uint8_t *req,
size_t req_len)
85 uint8_t resp[MODBUS_ADU_MAX];
86 int pn = c->txn(c->io, req, req_len, resp,
sizeof(resp));
92 int w = pc_modbus_parse_write_response(resp, (
size_t)pn,
nullptr, &ex);
95 return Sb::SB_ERR_ARG;
97 c->last_exception = ex;
100 return PC_SB_MODBUS_EXCEPTION;
105int sb_modbus_write(
void *vctx, uint32_t point, int32_t value)
107 pc_sb_modbus_ctx *c = (pc_sb_modbus_ctx *)vctx;
108 if (point > 0xFFFFu || value < 0 || value > 0xFFFF)
110 return Sb::SB_ERR_ARG;
113 size_t rn = pc_modbus_build_write_single(c->txid++, c->unit, (uint16_t)point, (uint16_t)value, req,
sizeof(req));
116 return Sb::SB_ERR_ARG;
118 int w = sb_modbus_write_txn(c, req, rn);
123 return (w == 1) ? Sb::SB_OK : Sb::SB_ERR_ARG;
126int sb_modbus_write_block(
void *vctx, uint32_t first,
const int32_t *in,
size_t n)
128 pc_sb_modbus_ctx *c = (pc_sb_modbus_ctx *)vctx;
130 if (n == 0 || n > 123 || first > 0xFFFFu || first + n > 0x10000u)
132 return Sb::SB_ERR_ARG;
135 for (
size_t i = 0; i < n; i++)
137 if (in[i] < 0 || in[i] > 0xFFFF)
139 return Sb::SB_ERR_ARG;
141 vals[i] = (uint16_t)in[i];
143 uint8_t req[13 + 2 * 123];
145 pc_modbus_build_write_multiple(c->txid++, c->unit, (uint16_t)first, vals, (uint16_t)n, req,
sizeof(req));
148 return Sb::SB_ERR_ARG;
150 return sb_modbus_write_txn(c, req, rn);
154int pc_sb_modbus_init(pc_sb_modbus_ctx *ctx, pc_sb_modbus_txn txn,
void *io, ModbusFunction fc, uint8_t unit)
158 return Sb::SB_ERR_ARG;
160 if (fc != ModbusFunction::MODBUS_FC_READ_HOLDING_REGS && fc != ModbusFunction::MODBUS_FC_READ_INPUT_REGS)
162 return Sb::SB_ERR_ARG;
169 ctx->last_exception = 0;
173int pc_sb_modbus_driver(SouthboundDriver *drv_out,
const char *name, pc_sb_modbus_ctx *ctx)
175 if (!drv_out || !name || !ctx || !ctx->txn)
177 return Sb::SB_ERR_ARG;
181 bool writable = (ctx->fc == ModbusFunction::MODBUS_FC_READ_HOLDING_REGS);
182 drv_out->name = name;
183 drv_out->read = &sb_modbus_read;
184 drv_out->write = writable ? &sb_modbus_write :
nullptr;
185 drv_out->read_block = &sb_modbus_read_block;
186 drv_out->write_block = writable ? &sb_modbus_write_block :
nullptr;
Modbus-master southbound driver adapter (PC_ENABLE_SOUTHBOUND && PC_ENABLE_MODBUS_MASTER).