Files
Codesys-Library-Atom-Modbus/src/atom_bridge.c
T
2026-09-30 21:17:41 -06:00

87 lines
3.6 KiB
C

#include "atom_bridge.h"
#include "atom_mb.h"
#include <stdio.h>
#include <string.h>
typedef struct { am_client c; uint32_t generation; int used, retired; } slot;
static slot slots[AM_POOL_SIZE];
static uint32_t token(unsigned i) { return (slots[i].generation<<8)|(i+1u); }
static slot *lookup(uint32_t h) {
unsigned n=h&255u;
if(!n || n>AM_POOL_SIZE) return NULL;
slot *s=&slots[n-1];
return s->used && s->generation==(h>>8)?s:NULL;
}
static void snapshot(const am_client *c,uint32_t h,uint32_t *s) {
s[0]=h; s[1]=(uint32_t)c->state; s[2]=(uint32_t)c->busy;
s[3]=(uint32_t)c->done; s[4]=(uint32_t)c->error; s[5]=(uint32_t)c->result;
s[6]=(uint32_t)c->last_error; s[7]=(uint32_t)c->socket_error;
s[8]=c->exception; s[9]=(uint32_t)c->write_uncertain;
s[10]=c->connect_attempts; s[11]=c->reconnects; s[12]=c->completed; s[13]=c->failed;
s[14]=(uint32_t)c->has_success; s[15]=(uint32_t)c->last_success_ms;
s[16]=(uint32_t)(c->last_success_ms>>32); s[17]=c->quantity;
s[18]=c->function; s[19]=c->unit; s[20]=(uint32_t)c->enabled;
s[21]=c->connect_timeout_ms; s[22]=c->response_timeout_ms; s[23]=c->retry_delay_ms;
}
uint32_t ab_call(uint32_t cmd,uint32_t h,uint32_t ip,uint16_t port,
uint8_t unit,uint8_t f,uint16_t addr,uint16_t q,uint16_t *data,uint32_t cap,
uint32_t *status,uint32_t sc,uint64_t now,uint32_t ct,uint32_t rt,uint32_t retry) {
slot *s; unsigned i; uint32_t result=0;
if(!status || sc<AM_STATUS_WORDS) return AB_BAD_CAPACITY;
/* Caller must provide distinct data/status buffers with declared capacities. */
if(cmd==AB_OPEN) {
char text[16];
memset(status,0,AM_STATUS_WORDS*sizeof(*status));
if(!port) return AM_ARGUMENT;
for(i=0;i<AM_POOL_SIZE;i++) if(!slots[i].used && !slots[i].retired) break;
if(i==AM_POOL_SIZE) return AB_POOL_FULL;
s=&slots[i];
snprintf(text,sizeof(text),"%u.%u.%u.%u",(unsigned)(ip>>24),(unsigned)((ip>>16)&255u),
(unsigned)((ip>>8)&255u),(unsigned)(ip&255u));
if(!am_init(&s->c,text,port)) return AM_ARGUMENT;
s->generation++; s->used=1; h=token(i);
snapshot(&s->c,h,status); return 0;
}
s=lookup(h);
if(!s) { memset(status,0,AM_STATUS_WORDS*sizeof(*status)); return AB_BAD_HANDLE; }
switch(cmd) {
case AB_CLOSE:
am_close(&s->c); s->used=0;
/* Never recycle a generation after wrap: stale handles stay invalid. */
if(s->generation==0xffffffu) s->retired=1;
snapshot(&s->c,0,status); return 0;
case AB_ENABLE: am_enable(&s->c,1,now); break;
case AB_DISABLE: am_enable(&s->c,0,now); break;
case AB_TICK: am_tick(&s->c,now); break;
case AB_RECONNECT: am_reconnect(&s->c,now); break;
case AB_CONFIGURE:
if(s->c.enabled) result=AM_BUSY;
else if(!ct || !rt || !retry) result=AM_ARGUMENT;
else { s->c.connect_timeout_ms=ct; s->c.response_timeout_ms=rt; s->c.retry_delay_ms=retry; }
break;
case AB_SUBMIT:
if((f==5 || f==6 || f==15 || f==16) && (!data || cap<q)) result=AB_BAD_CAPACITY;
else result=(uint32_t)am_request(&s->c,unit,f,addr,q,data,now);
break;
case AB_COPY_READ:
if(!s->c.done || s->c.function>4 || s->c.function<1) result=AM_ARGUMENT;
else if(!data || cap<s->c.quantity) result=AB_BAD_CAPACITY;
else memcpy(data,s->c.data,s->c.quantity*sizeof(*data));
break;
case AB_ACK: s->c.done=0; s->c.error=0; break;
case AB_REQUEST_TIMEOUT:
if(s->c.busy) result=AM_BUSY;
else if(!rt) result=AM_ARGUMENT;
else s->c.response_timeout_ms=rt;
break;
default: result=AB_BAD_COMMAND; break;
}
snapshot(&s->c,h,status); return result;
}
void ab_shutdown(void) {
unsigned i;
for(i=0;i<AM_POOL_SIZE;i++) if(slots[i].used) {
am_close(&slots[i].c); slots[i].used=0;
if(slots[i].generation==0xffffffu) slots[i].retired=1;
}
}