feat(gas-logger): добавь непрерывный логгер и JSON-карту
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
#include "gas_logger.h"
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
static uint16_t width(const gas_logger *l) { return l->config.channels + GL_HEADER_WORDS; }
|
||||
static int service(const gl_config *c, uint16_t a)
|
||||
{
|
||||
uint32_t end = (uint32_t)c->base + GL_DATA_OFFSET +
|
||||
(uint32_t)c->capacity * (c->channels + GL_HEADER_WORDS);
|
||||
return a >= c->base && (uint32_t)a < end;
|
||||
}
|
||||
gl_result gl_init(gas_logger *l, const gl_config *c, const gl_port *p,
|
||||
uint16_t *b0, uint16_t *b1, uint32_t words)
|
||||
{
|
||||
uint16_t i,j;
|
||||
uint32_t needed;
|
||||
if (!l || !c || !p || !b0 || !b1 || b0 == b1 || !c->map ||
|
||||
!p->enter || !p->leave || !p->source || !c->capacity ||
|
||||
!c->channels || c->channels > GL_MAX_CHANNELS) return GL_ARGUMENT;
|
||||
needed = (uint32_t)c->capacity * (c->channels + GL_HEADER_WORDS);
|
||||
if (needed > words || (uint32_t)c->base + GL_DATA_OFFSET + needed > 65536UL)
|
||||
return GL_ARGUMENT;
|
||||
for (i=0;i<c->channels;i++) {
|
||||
if (service(c,c->map[i].gas) || service(c,c->map[i].modbus) ||
|
||||
service(c,c->map[i].can)) return GL_ARGUMENT;
|
||||
for (j=0;j<i;j++)
|
||||
if (c->map[i].gas == c->map[j].gas ||
|
||||
c->map[i].modbus == c->map[j].modbus ||
|
||||
c->map[i].can == c->map[j].can) return GL_ARGUMENT;
|
||||
}
|
||||
memset(l,0,sizeof(*l)); l->config=*c; l->port=*p; l->banks[0]=b0; l->banks[1]=b1;
|
||||
return GL_OK;
|
||||
}
|
||||
gl_result gl_capture(gas_logger *l, uint32_t time, uint16_t event)
|
||||
{
|
||||
uint16_t values[GL_MAX_CHANNELS],i,*record;
|
||||
uint32_t irq = l->port.enter(l->port.user);
|
||||
if (!l->recording) { l->port.leave(l->port.user,irq); return GL_BUSY; }
|
||||
for (i=0;i<l->config.channels;i++) {
|
||||
if (!l->port.source(l->port.user,l->config.map[i].gas,&values[i])) {
|
||||
l->source_errors++; l->port.leave(l->port.user,irq); return GL_SOURCE_ERROR;
|
||||
}
|
||||
}
|
||||
record=l->banks[l->active]+(uint32_t)l->next*width(l);
|
||||
record[0]=(uint16_t)time; record[1]=(uint16_t)(time>>16);
|
||||
record[2]=(uint16_t)l->sequence; record[3]=(uint16_t)(l->sequence>>16);
|
||||
record[4]=event;
|
||||
for (i=0;i<l->config.channels;i++) record[GL_HEADER_WORDS+i]=values[i];
|
||||
l->sequence++;
|
||||
if (++l->next == l->config.capacity) l->next=0;
|
||||
if (l->count < l->config.capacity) l->count++;
|
||||
l->port.leave(l->port.user,irq); return GL_OK;
|
||||
}
|
||||
static gl_result snapshot(gas_logger *l)
|
||||
{
|
||||
if (l->pinned) { l->missed++; return GL_BUSY; }
|
||||
if (!l->count) return GL_EMPTY;
|
||||
l->snap_count=l->count; l->snap_next=l->next;
|
||||
l->active^=1U; l->count=0; l->next=0; l->pinned=1;
|
||||
l->generation++; if (!l->generation) l->generation=1;
|
||||
return GL_OK;
|
||||
}
|
||||
gl_result gl_snapshot(gas_logger *l)
|
||||
{
|
||||
uint32_t irq=l->port.enter(l->port.user);
|
||||
gl_result r=snapshot(l); l->port.leave(l->port.user,irq); return r;
|
||||
}
|
||||
static uint16_t status(const gas_logger *l, uint16_t offset)
|
||||
{
|
||||
switch(offset) {
|
||||
case 0:return GL_MAGIC; case 1:return GL_VERSION;
|
||||
case 2:return l->recording | (l->pinned<<1);
|
||||
case 3:return l->config.channels; case 4:return width(l);
|
||||
case 5:return l->config.capacity; case 6:return l->count; case 7:return l->snap_count;
|
||||
case 8:return (uint16_t)l->generation; case 9:return (uint16_t)(l->generation>>16);
|
||||
case 10:return (uint16_t)l->config.schema_id; case 11:return (uint16_t)(l->config.schema_id>>16);
|
||||
case 12:return (uint16_t)l->sequence; case 13:return (uint16_t)(l->sequence>>16);
|
||||
case 14:return (uint16_t)l->missed; case 15:return (uint16_t)(l->missed>>16);
|
||||
case 16:return (uint16_t)l->source_errors; case 17:return (uint16_t)(l->source_errors>>16);
|
||||
default:return 0;
|
||||
}
|
||||
}
|
||||
static gl_result read_locked(gas_logger *l, uint16_t a, uint16_t *out, uint16_t n)
|
||||
{
|
||||
uint16_t i,j,slot;
|
||||
uint32_t off;
|
||||
if (a>=l->config.base && (uint32_t)a+n <= (uint32_t)l->config.base+18) {
|
||||
for(i=0;i<n;i++) out[i]=status(l,(uint16_t)(a+i-l->config.base));
|
||||
return GL_OK;
|
||||
}
|
||||
if ((uint32_t)a >= (uint32_t)l->config.base+GL_DATA_OFFSET) {
|
||||
off=(uint32_t)a-l->config.base-GL_DATA_OFFSET;
|
||||
if (l->pinned && off+n <= (uint32_t)l->snap_count*width(l)) {
|
||||
for(i=0;i<n;i++) {
|
||||
slot=(uint16_t)((off+i)/width(l));
|
||||
if(l->snap_count==l->config.capacity)
|
||||
slot=(uint16_t)(((uint32_t)slot+l->snap_next)%l->config.capacity);
|
||||
out[i]=l->banks[l->active^1U][(uint32_t)slot*width(l)+(off+i)%width(l)];
|
||||
}
|
||||
return GL_OK;
|
||||
}
|
||||
}
|
||||
/* A live signal block must be completely mapped before any read. */
|
||||
for(i=0;i<n;i++) {
|
||||
for(j=0;j<l->config.channels;j++) if(l->config.map[j].gas==a+i) break;
|
||||
if(j==l->config.channels) return GL_ADDRESS;
|
||||
}
|
||||
for(i=0;i<n;i++)
|
||||
if(!l->port.source(l->port.user,(uint16_t)(a+i),&out[i])) return GL_SOURCE_ERROR;
|
||||
return GL_OK;
|
||||
}
|
||||
gl_result gl_read(gas_logger *l, uint16_t a, uint16_t *out, uint16_t n)
|
||||
{
|
||||
uint16_t temp[125],i;
|
||||
uint32_t irq;
|
||||
gl_result r;
|
||||
if(!out || !n || n>125 || (uint32_t)a+n>65536UL) return GL_ARGUMENT;
|
||||
irq=l->port.enter(l->port.user); r=read_locked(l,a,temp,n);
|
||||
if(r==GL_OK) for(i=0;i<n;i++) out[i]=temp[i];
|
||||
l->port.leave(l->port.user,irq); return r;
|
||||
}
|
||||
gl_result gl_write(gas_logger *l, uint16_t a, uint16_t v)
|
||||
{
|
||||
uint32_t irq=l->port.enter(l->port.user);
|
||||
gl_result r=GL_OK;
|
||||
if((uint32_t)a==(uint32_t)l->config.base+GL_RELEASE_LO)
|
||||
l->release_generation=(l->release_generation&0xFFFF0000UL)|v;
|
||||
else if((uint32_t)a==(uint32_t)l->config.base+GL_RELEASE_HI)
|
||||
l->release_generation=(l->release_generation&0xFFFFUL)|((uint32_t)v<<16);
|
||||
else if((uint32_t)a!=(uint32_t)l->config.base+GL_COMMAND) r=GL_ADDRESS;
|
||||
else if(v==GL_START) l->recording=1;
|
||||
else if(v==GL_SNAPSHOT) r=snapshot(l);
|
||||
else if(v==GL_RELEASE) {
|
||||
if(!l->pinned || l->release_generation!=l->generation) r=GL_STALE;
|
||||
else { l->pinned=0; l->snap_count=0; }
|
||||
} else r=GL_ARGUMENT;
|
||||
l->port.leave(l->port.user,irq); return r;
|
||||
}
|
||||
static gl_result alias_read(gas_logger *l,uint16_t a,uint16_t *out,uint16_t n,int can)
|
||||
{
|
||||
uint16_t i,j,gas=0,found;
|
||||
if(!n || n>125 || (uint32_t)a+n>65536UL) return GL_ARGUMENT;
|
||||
if(service(&l->config,a)) return gl_read(l,a,out,n);
|
||||
for(i=0;i<n;i++) {
|
||||
found=0;
|
||||
for(j=0;j<l->config.channels;j++)
|
||||
if((can?l->config.map[j].can:l->config.map[j].modbus)==a+i) {
|
||||
if(!i) gas=l->config.map[j].gas;
|
||||
if((uint32_t)gas+i!=l->config.map[j].gas) return GL_ADDRESS;
|
||||
found=1;break;
|
||||
}
|
||||
if(!found) return GL_ADDRESS;
|
||||
}
|
||||
return gl_read(l,gas,out,n);
|
||||
}
|
||||
gl_result gl_modbus_read(gas_logger *l,uint16_t a,uint16_t *o,uint16_t n)
|
||||
{ return alias_read(l,a,o,n,0); }
|
||||
gl_result gl_can_read(gas_logger *l,uint16_t a,uint16_t *o,uint16_t n)
|
||||
{ return alias_read(l,a,o,n,1); }
|
||||
gl_result gl_modbus_write(gas_logger *l,uint16_t a,uint16_t v)
|
||||
{ return gl_write(l,a,v); }
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "gas_logger_pcan.h"
|
||||
static pcan_gas_status_t result(gl_result r)
|
||||
{ return r==GL_OK ? PCAN_GAS_OK : r==GL_ADDRESS ? PCAN_GAS_NO_REG : PCAN_GAS_REJECTED; }
|
||||
static pcan_gas_status_t read_word(const pcan_gas_region_t *r,uint16_t o,uint16_t *v)
|
||||
{ return result(gl_can_read(r->user,(uint16_t)(r->base+o),v,1)); }
|
||||
static pcan_gas_status_t write_word(const pcan_gas_region_t *r,uint16_t o,uint16_t v)
|
||||
{ return result(gl_write(r->user,(uint16_t)(r->base+o),v)); }
|
||||
void gl_pcan_region_init(pcan_gas_region_t *r,gas_logger *l)
|
||||
{
|
||||
r->base=l->config.base;
|
||||
r->count=(uint16_t)(GL_DATA_OFFSET+(uint32_t)l->config.capacity*(l->config.channels+GL_HEADER_WORDS));
|
||||
r->storage=0;r->read=read_word;r->write=write_word;r->flags=0;r->user=l;r->name="gas-logger";
|
||||
}
|
||||
Reference in New Issue
Block a user