#include "atom_bridge.h" #include "atom_mb.h" #include #include 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>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 || capc,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 || capc.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