avr-fw-modules/core/src/i2cee_save.c

88 lines
1.5 KiB
C
Executable File

#include <sys/i2ceeprom.h>
#include <sys/errno.h>
#include <sys/assert.h>
#include <hwo/i2c.h>
#include <stdlib.h>
#include <string.h>
#define DEVICE(x) ((x >> 16)&0x07)
#define PAGE(x) (x >> 7)
#define PAGEBASE(x) (x & 0xFF80)
#define PAGEOFFSET(x) (x & 0x007F)
struct i2cee_state {
uint16_t offset;
uint16_t len;
uint8_t *p;
};
static int i2cee_save_cb(void *p,int n,int ch){
switch (n){
case 0:
return (((struct i2cee_state*)p)->offset >> 8) & 0xFF;
case 1:
return (((struct i2cee_state*)p)->offset) & 0xFF;
default:
if ( (n-2) < ((struct i2cee_state*)p)->len )
return ((struct i2cee_state*)p)->p[n-2];
return -1;
};
};
int i2cee_save(int32_t base,void *p,int16_t len){
uint8_t *b = p;
uint16_t ilen,slen;
int32_t offset = base;
struct i2cee_state
state;
uint8_t n;
int r;
MUTEXED(&i2c.mutex);
slen = 0;
while (len){
if (!(i2cee.emask & (1<<DEVICE(offset))))
return -ENOFILE;
ilen = 128 - PAGEOFFSET(offset);
if (ilen > len) {
ilen = len;
};
state.offset = offset;
state.len = ilen;
state.p = b;
r = i2c_transfer_ex( 0xA0 + (DEVICE(offset) << 1), i2cee_save_cb, &state);
noassert(r);
if ((r >= 0) && (r != (ilen+2))){
return -ESHORT;
};
for (n=0;n<10;n++){
r = i2c_transfer( 0xA0 + (DEVICE(offset) << 1), (void*)&offset, 2);
if (r >= 0) {
break;
} else if (r == -EFAIL) {
wait_ms(1);
continue;
} else {
noassert(r);
return r;
};
};
assert(r);
len -= ilen;
b += ilen;
offset += ilen;
slen += ilen;
};
return slen;
};