Compare commits
3 commits
b57552a3e7
...
fb7c5498fa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb7c5498fa | ||
|
|
b26a64514c | ||
|
|
267ad36409 |
1 changed files with 103 additions and 99 deletions
204
leia/leia.c
204
leia/leia.c
|
|
@ -60,8 +60,8 @@ const char revision[] = Id;
|
|||
#define VERSION 1
|
||||
|
||||
struct conf {
|
||||
unsigned int magic; // 0
|
||||
unsigned char version; // 2
|
||||
uint16_t magic; // 0
|
||||
uint8_t version; // 2
|
||||
uint8_t flags; // 3
|
||||
uint16_t period; // 4
|
||||
uint16_t slen; // 6
|
||||
|
|
@ -72,20 +72,26 @@ struct conf {
|
|||
uint8_t reset; // 12
|
||||
uint8_t dir; // 13
|
||||
uint16_t n_steps; // 14
|
||||
uint16_t dac; // 16
|
||||
uint16_t dac_ramp; // 18
|
||||
uint16_t dac_step; // 20
|
||||
uint8_t adc_idx; // 22
|
||||
uint8_t adc_incr; // 23
|
||||
uint8_t adc_period; // 24
|
||||
uint8_t pad[7]; // 25
|
||||
uint8_t adc_ch[16]; // 32
|
||||
} conf; // 64
|
||||
|
||||
enum {
|
||||
FLAG_WDT = 1,
|
||||
};
|
||||
|
||||
struct stat {
|
||||
uint16_t adc[16]; // 48
|
||||
uint16_t dac; // 80
|
||||
uint8_t adc_idx; // 82
|
||||
uint8_t pad[45]; //128
|
||||
};
|
||||
|
||||
struct vars {
|
||||
struct conf conf;
|
||||
struct stat stat;
|
||||
} v;
|
||||
|
||||
#define STEP_RESOLUTION 23148L // ns
|
||||
#define STEP_NS(ns) (((ns)+STEP_RESOLUTION/2)/STEP_RESOLUTION)
|
||||
#define TICK_RESOLUTION 92593L // ns
|
||||
|
|
@ -132,12 +138,12 @@ void stepper_init()
|
|||
// 16-bit Timer 1 PWM by OCR1A, prescaled by 256
|
||||
TCCR1A = 1<<WGM10 | 1<<WGM11 ;
|
||||
TCCR1B = 1<<WGM12 | 1<<WGM13 | 4<<CS10;
|
||||
OCR1AH = conf.period >> 8;
|
||||
OCR1AL = conf.period;
|
||||
OCR1BH = conf.slen >> 8;
|
||||
OCR1BL = conf.slen;
|
||||
RESET_PORT = conf.enable & ~conf.reset;
|
||||
DIR_PORT = conf.dir;
|
||||
OCR1AH = v.conf.period >> 8;
|
||||
OCR1AL = v.conf.period;
|
||||
OCR1BH = v.conf.slen >> 8;
|
||||
OCR1BL = v.conf.slen;
|
||||
RESET_PORT = v.conf.enable & ~v.conf.reset;
|
||||
DIR_PORT = v.conf.dir;
|
||||
STEP_PORT = 0;
|
||||
DDRB = MISO | RESET | ENABLE | SLEEP | LEDON;
|
||||
DDRD = STEP1 | STEP2;
|
||||
|
|
@ -147,8 +153,8 @@ void stepper_init()
|
|||
static inline
|
||||
void stepper_start(uint8_t reset)
|
||||
{
|
||||
RESET_PORT = conf.enable & ~reset;
|
||||
DIR_PORT = conf.dir;
|
||||
RESET_PORT = v.conf.enable & ~reset;
|
||||
DIR_PORT = v.conf.dir;
|
||||
TCNT1H = 0;
|
||||
TCNT1L = 0;
|
||||
TIMSK1 = (1<<OCIE1B);
|
||||
|
|
@ -169,13 +175,13 @@ char stepper_status()
|
|||
#if 1
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
if (!conf.n_steps || (LIMIT_PORT & conf.lmask) != conf.lval) {
|
||||
if (!v.conf.n_steps || (LIMIT_PORT & v.conf.lmask) != v.conf.lval) {
|
||||
STEP_PORT = 0;
|
||||
TIMSK1 = 0;
|
||||
return;
|
||||
}
|
||||
conf.n_steps--;
|
||||
STEP_PORT = conf.step;
|
||||
v.conf.n_steps--;
|
||||
STEP_PORT = v.conf.step;
|
||||
}
|
||||
#else
|
||||
ISR(TIMER1_COMPA_vect, ISR_NAKED)
|
||||
|
|
@ -215,10 +221,10 @@ ISR(TIMER1_COMPA_vect, ISR_NAKED)
|
|||
"out __SREG__, r24" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
:[N] "+m" (conf.n_steps)
|
||||
:[M] "m" (conf.lmask),
|
||||
[V] "m" (conf.lval),
|
||||
[S] "m" (conf.step),
|
||||
:[N] "+m" (v.conf.n_steps)
|
||||
:[M] "m" (v.conf.lmask),
|
||||
[V] "m" (v.conf.lval),
|
||||
[S] "m" (v.conf.step),
|
||||
[MSK] "n" (_SFR_MEM_ADDR(TIMSK1)),
|
||||
[P] "n" (_SFR_IO_ADDR(STEP_PORT)),
|
||||
[L] "n" (_SFR_IO_ADDR(LIMIT_PORT))
|
||||
|
|
@ -230,7 +236,7 @@ ISR(TIMER1_COMPA_vect, ISR_NAKED)
|
|||
ISR(TIMER1_COMPB_vect)
|
||||
{
|
||||
STEP_PORT = 0;
|
||||
RESET_PORT = conf.enable;
|
||||
RESET_PORT = v.conf.enable;
|
||||
TIMSK1 = TIFR1 = 1<<OCIE1B | 1<<OCIE1A;
|
||||
}
|
||||
#else
|
||||
|
|
@ -252,7 +258,7 @@ ISR(TIMER1_COMPB_vect, ISR_NAKED)
|
|||
[IFR] "n" (_SFR_IO_ADDR(TIFR1)),
|
||||
[RES] "n" (_SFR_IO_ADDR(RESET_PORT)),
|
||||
[STP] "n" (_SFR_IO_ADDR(STEP_PORT)),
|
||||
[ENA] "m" (conf.enable),
|
||||
[ENA] "m" (v.conf.enable),
|
||||
[IE] "n" (1<<OCIE1B | 1<<OCIE1A)
|
||||
);
|
||||
}
|
||||
|
|
@ -261,19 +267,19 @@ ISR(TIMER1_COMPB_vect, ISR_NAKED)
|
|||
#if 1
|
||||
ISR(TIMER0_COMPA_vect)
|
||||
{
|
||||
uint16_t d = conf.dac;
|
||||
if (d == conf.dac_ramp) {
|
||||
uint16_t d = v.stat.dac;
|
||||
if (d == v.conf.dac_ramp) {
|
||||
TIMSK0 = 0;
|
||||
return;
|
||||
}
|
||||
uint16_t s = conf.dac_step;
|
||||
if (d > conf.dac_ramp)
|
||||
uint16_t s = v.conf.dac_step;
|
||||
if (d > v.conf.dac_ramp)
|
||||
d -= s;
|
||||
else
|
||||
d += s;
|
||||
DACL = d;
|
||||
DACH = d>>8;
|
||||
conf.dac = d;
|
||||
v.stat.dac = d;
|
||||
}
|
||||
#else
|
||||
// Avoid some push, pop, cp, and jumps
|
||||
|
|
@ -330,9 +336,9 @@ ISR(TIMER0_COMPA_vect, ISR_NAKED)
|
|||
"out __SREG__, r24" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
:[D] "+m" (conf.dac)
|
||||
:[R] "m" (conf.dac_ramp),
|
||||
[S] "m" (conf.dac_step),
|
||||
:[D] "+m" (v.stat.dac)
|
||||
:[R] "m" (v.conf.dac_ramp),
|
||||
[S] "m" (v.conf.dac_step),
|
||||
[MSK] "n" (_SFR_MEM_ADDR(TIMSK0)),
|
||||
[DH] "n" (_SFR_MEM_ADDR(DACH)),
|
||||
[DL] "n" (_SFR_MEM_ADDR(DACL))
|
||||
|
|
@ -347,13 +353,13 @@ void dac_set(uint16_t d)
|
|||
DACL = d;
|
||||
DACH = d>>8;
|
||||
DACON = 1<<DALA | 1<<DAEN | 1<<DAOE;
|
||||
conf.dac = conf.dac_ramp = d;
|
||||
v.stat.dac = v.conf.dac_ramp = d;
|
||||
}
|
||||
|
||||
static
|
||||
void dac_ramp(uint16_t d)
|
||||
{
|
||||
uint16_t s = conf.dac_step;
|
||||
uint16_t s = v.conf.dac_step;
|
||||
if (!s) {
|
||||
dac_set(d);
|
||||
return;
|
||||
|
|
@ -362,9 +368,9 @@ void dac_ramp(uint16_t d)
|
|||
d &= s;
|
||||
TIMSK0 = 0;
|
||||
DACON = 1<<DALA | 1<<DAEN | 1<<DAOE;
|
||||
conf.dac = DAC & s;
|
||||
conf.dac_ramp = d;
|
||||
if (d != conf.dac)
|
||||
v.stat.dac = DAC & s;
|
||||
v.conf.dac_ramp = d;
|
||||
if (d != v.stat.dac)
|
||||
TIMSK0 = 1<<OCIE0A;
|
||||
}
|
||||
|
||||
|
|
@ -383,9 +389,9 @@ static
|
|||
void adc_start(uint8_t i)
|
||||
{
|
||||
i &= 15;
|
||||
conf.adc_idx = i<<4;
|
||||
OCR0A = OCR0B = conf.adc_period;
|
||||
uint8_t ch = conf.adc_ch[i];
|
||||
v.stat.adc_idx = i<<4;
|
||||
OCR0A = OCR0B = v.conf.adc_period;
|
||||
uint8_t ch = v.conf.adc_ch[i];
|
||||
if (!(ch & 1<<REFS0))
|
||||
return;
|
||||
ADMUX = ch;
|
||||
|
|
@ -399,8 +405,6 @@ void adc_stop()
|
|||
ADCSRA = 1<<ADEN | 1<<ADIF | 6<<ADPS0;
|
||||
}
|
||||
|
||||
uint16_t adc[16];
|
||||
|
||||
#if 1
|
||||
ISR(ADC_vect)
|
||||
{
|
||||
|
|
@ -410,17 +414,17 @@ ISR(ADC_vect)
|
|||
a |= ADCH<<8;
|
||||
}
|
||||
else {
|
||||
a = adc[conf.adc_idx >> 4];
|
||||
a = v.stat.adc[v.stat.adc_idx >> 4];
|
||||
a -= a>>6;
|
||||
a += ADCL;
|
||||
a += ADCH<<8;
|
||||
}
|
||||
adc[conf.adc_idx >> 4] = a;
|
||||
conf.adc_idx += conf.adc_incr;
|
||||
uint8_t ch = conf.adc_ch[conf.adc_idx >> 4];
|
||||
v.stat.adc[v.stat.adc_idx >> 4] = a;
|
||||
v.stat.adc_idx += v.conf.adc_incr;
|
||||
uint8_t ch = v.conf.adc_ch[v.stat.adc_idx >> 4];
|
||||
if (!(ch & 1<<REFS0)) {
|
||||
conf.adc_idx = 0;
|
||||
ch = conf.adc_ch[0];
|
||||
v.stat.adc_idx = 0;
|
||||
ch = v.conf.adc_ch[0];
|
||||
}
|
||||
if (!(ch & 1<<REFS0))
|
||||
adc_stop();
|
||||
|
|
@ -522,10 +526,10 @@ ISR(ADC_vect, ISR_NAKED)
|
|||
"out __SREG__, r24" "\n\t"
|
||||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
:[I] "+m" (conf.adc_idx),
|
||||
[D] "+m" (adc)
|
||||
:[C] "m" (conf.adc_ch),
|
||||
[II] "m" (conf.adc_incr),
|
||||
:[I] "+m" (v.stat.adc_idx),
|
||||
[D] "+m" (v.stat.adc)
|
||||
:[C] "m" (v.conf.adc_ch),
|
||||
[II] "m" (v.conf.adc_incr),
|
||||
[AL] "n" (_SFR_MEM_ADDR(ADCL)),
|
||||
[AH] "n" (_SFR_MEM_ADDR(ADCH)),
|
||||
[X] "n" (_SFR_MEM_ADDR(ADMUX)),
|
||||
|
|
@ -543,8 +547,8 @@ static void conf_init()
|
|||
{
|
||||
cli();
|
||||
adc_init();
|
||||
adc_start(conf.adc_idx>>4);
|
||||
dac_set(conf.dac_ramp);
|
||||
adc_start(v.stat.adc_idx>>4);
|
||||
dac_set(v.conf.dac_ramp);
|
||||
stepper_init();
|
||||
}
|
||||
|
||||
|
|
@ -563,7 +567,7 @@ ISR(EE_READY_vect)
|
|||
eewr_n = --n;
|
||||
EEAR = eewr_a + n;
|
||||
EECR |= 1<<EERE;
|
||||
uint8_t d = ((uint8_t*)&conf)[n];
|
||||
uint8_t d = ((uint8_t*)&v.conf)[n];
|
||||
if (EEDR == d)
|
||||
continue;
|
||||
EEDR = d;
|
||||
|
|
@ -598,8 +602,8 @@ ISR(EE_READY_vect, ISR_NAKED)
|
|||
"adc r30, r31" "\n\t"
|
||||
"out %[AH], r30" "\n\t"
|
||||
"sbi %[C], %[RE]" "\n\t"
|
||||
"ldi r30, lo8(conf)" "\n\t"
|
||||
"ldi r31, hi8(conf)" "\n\t"
|
||||
"ldi r30, lo8(%[V])" "\n\t"
|
||||
"ldi r31, hi8($[V])" "\n\t"
|
||||
"add r30, r24" "\n\t"
|
||||
"brcc 3f" "\n\t"
|
||||
"subi r31, -1" "\n"
|
||||
|
|
@ -624,7 +628,8 @@ ISR(EE_READY_vect, ISR_NAKED)
|
|||
"pop r24" "\n\t"
|
||||
"reti" "\n"
|
||||
:
|
||||
:[C] "n" (_SFR_IO_ADDR(EECR)),
|
||||
:[V] "m" (v.conf),
|
||||
[C] "n" (_SFR_IO_ADDR(EECR)),
|
||||
[AL] "n" (_SFR_IO_ADDR(EEARL)),
|
||||
[AH] "n" (_SFR_IO_ADDR(EEARH)),
|
||||
[D] "n" (_SFR_IO_ADDR(EEDR)),
|
||||
|
|
@ -640,12 +645,10 @@ ISR(EE_READY_vect, ISR_NAKED)
|
|||
static inline
|
||||
uint8_t eeprom_save(uint16_t a)
|
||||
{
|
||||
// eeprom_update_block(&conf, (void*)a, sizeof(conf));
|
||||
|
||||
if (EECR & 1<<EERIE)
|
||||
return 1;
|
||||
eewr_a = a;
|
||||
eewr_n = sizeof(conf);
|
||||
eewr_n = sizeof(struct conf);
|
||||
GPIOR2 = 0;
|
||||
EECR = 1<<EERIE;
|
||||
return 0;
|
||||
|
|
@ -654,14 +657,13 @@ uint8_t eeprom_save(uint16_t a)
|
|||
static inline
|
||||
uint8_t eeprom_load(uint16_t a)
|
||||
{
|
||||
// eeprom_read_block(&conf, (void*)a, sizeof(conf));
|
||||
cli();
|
||||
if (EECR & 1<<EEWE) {
|
||||
sei();
|
||||
return 1;
|
||||
}
|
||||
uint8_t n = sizeof(conf);
|
||||
uint8_t *c = (uint8_t*)&conf;
|
||||
uint8_t n = sizeof(struct conf);
|
||||
uint8_t *c = (uint8_t*)&v.conf;
|
||||
while (n--) {
|
||||
EEAR = a++;
|
||||
EECR |= 1<<EERE;
|
||||
|
|
@ -789,7 +791,7 @@ void reg88(uint8_t *v1, uint8_t *v2, unsigned char *r, const unsigned char *c)
|
|||
// 'Z': eeprom what, a
|
||||
// what=='e' or 'E": read eeprom from address a*4 to conf
|
||||
// what=='F': ignore magic/version mismatch
|
||||
// what=='E' or 'F': reinitialize with conf.
|
||||
// what=='E' or 'F': reinitialize with v.conf.
|
||||
// 'y': peek a
|
||||
// 'Y': poke a, v
|
||||
|
||||
|
|
@ -798,7 +800,9 @@ void reg88(uint8_t *v1, uint8_t *v2, unsigned char *r, const unsigned char *c)
|
|||
// interrupts are disabled, so that the SPI reciever can respond to
|
||||
// all bytes in time. All commands execute fast, the master µC shall
|
||||
// not time out while waiting for the reponse. The stepping timer is
|
||||
// restarted after command execution, when any steps are commanded.
|
||||
// restarted after command execution, when any steps are pending.
|
||||
// The CPU sleeps while waiting for a command from the SPI, until SSEL
|
||||
// goes low.
|
||||
//
|
||||
// Interrupts
|
||||
// PCINT2: disable global interrupts
|
||||
|
|
@ -817,13 +821,13 @@ int main()
|
|||
DDRB = MISO;
|
||||
eeprom_load(0);
|
||||
adc_init();
|
||||
if (conf.magic == MAGIC && conf.version == VERSION)
|
||||
if (v.conf.magic == MAGIC && v.conf.version == VERSION)
|
||||
conf_init();
|
||||
|
||||
while (1) {
|
||||
unsigned char cmd[3];
|
||||
unsigned char resp[3];
|
||||
if (!stepper_status() && conf.step && conf.n_steps)
|
||||
if (!stepper_status() && v.conf.step && v.conf.n_steps)
|
||||
stepper_start(0);
|
||||
if (spi_slave_Rx(cmd, 3)) {
|
||||
spi_slave_Tx((const unsigned char*)"\xff\xff\xff" "EEY", 6);
|
||||
|
|
@ -832,7 +836,7 @@ int main()
|
|||
stepper_stop();
|
||||
char up = upcase(cmd[0]);
|
||||
if (up)
|
||||
conf.step = 0;
|
||||
v.conf.step = 0;
|
||||
resp[0] = cmd[0];
|
||||
uint8_t i;
|
||||
switch (cmd[0] | 0x20) {
|
||||
|
|
@ -841,49 +845,49 @@ int main()
|
|||
resp[1] = 'E';
|
||||
resp[2] = cmd[0];
|
||||
break;
|
||||
case 'm': reg88(&conf.lmask, &conf.lval, resp, cmd); break;
|
||||
case 'q': reg16(&conf.period, resp, cmd);
|
||||
if (0) case 'l': reg16(&conf.slen, resp, cmd);
|
||||
case 'm': reg88(&v.conf.lmask, &v.conf.lval, resp, cmd); break;
|
||||
case 'q': reg16(&v.conf.period, resp, cmd);
|
||||
if (0) case 'l': reg16(&v.conf.slen, resp, cmd);
|
||||
if (up)
|
||||
stepper_init();
|
||||
break;
|
||||
case 'o': reg8f(&conf.enable, resp, cmd);
|
||||
case 'o': reg8f(&v.conf.enable, resp, cmd);
|
||||
if (up)
|
||||
RESET_PORT = conf.enable;
|
||||
RESET_PORT = v.conf.enable;
|
||||
break;
|
||||
case '0': conf.step = 0;
|
||||
if (0) case '1': conf.step = STEP1;
|
||||
if (0) case '2': conf.step = STEP2;
|
||||
conf.dir = cmd[1] & 0xf;
|
||||
case '0': v.conf.step = 0;
|
||||
if (0) case '1': v.conf.step = STEP1;
|
||||
if (0) case '2': v.conf.step = STEP2;
|
||||
v.conf.dir = cmd[1] & 0xf;
|
||||
if (cmd[2])
|
||||
conf.n_steps = cmd[2] << ((cmd[1]>>4) & 7);
|
||||
v.conf.n_steps = cmd[2] << ((cmd[1]>>4) & 7);
|
||||
// fall through, return n_steps
|
||||
case 's': reg16(&conf.n_steps, resp, cmd); break;
|
||||
case 'r': reg8(&conf.reset, resp, cmd);
|
||||
case 's': reg16(&v.conf.n_steps, resp, cmd); break;
|
||||
case 'r': reg8(&v.conf.reset, resp, cmd);
|
||||
resp[2] = cmd[2];
|
||||
if (cmd[2]) {
|
||||
conf.step = 0;
|
||||
v.conf.step = 0;
|
||||
if (cmd[2] & 0x80)
|
||||
stepper_init();
|
||||
if (cmd[2] & 1)
|
||||
stepper_start(conf.reset);
|
||||
stepper_start(v.conf.reset);
|
||||
}
|
||||
break;
|
||||
case 'd': reg16(&conf.dac, resp, cmd);
|
||||
dac_ramp(conf.dac);
|
||||
case 'd': reg16(&v.stat.dac, resp, cmd);
|
||||
dac_ramp(v.stat.dac);
|
||||
break;
|
||||
case 'p': reg16(&conf.dac_step, resp, cmd); break;
|
||||
case 'p': reg16(&v.conf.dac_step, resp, cmd); break;
|
||||
case 'a':
|
||||
resp[2] = cmd[2];
|
||||
i = cmd[2] & 15;
|
||||
switch ((cmd[2]>>4) & 7) {
|
||||
case 0: int2frame(adc[i], resp+1);
|
||||
if (up) adc[i] = 0;
|
||||
case 0: int2frame(v.stat.adc[i], resp+1);
|
||||
if (up) v.stat.adc[i] = 0;
|
||||
break;
|
||||
case 1: reg8(conf.adc_ch+i, resp, cmd); break;
|
||||
case 2: reg8(&conf.adc_idx, resp, cmd); break;
|
||||
case 3: reg8(&conf.adc_incr, resp, cmd); break;
|
||||
case 4: reg8(&conf.adc_period, resp, cmd); break;
|
||||
case 1: reg8(v.conf.adc_ch+i, resp, cmd); break;
|
||||
case 2: reg8(&v.stat.adc_idx, resp, cmd); break;
|
||||
case 3: reg8(&v.conf.adc_incr, resp, cmd); break;
|
||||
case 4: reg8(&v.conf.adc_period, resp, cmd); break;
|
||||
case 5: reg8(&ADMUX, resp, cmd); break;
|
||||
case 6: reg8(&ADCSRA, resp, cmd); break;
|
||||
case 7: reg8(&ADCH, resp, cmd); break;
|
||||
|
|
@ -905,7 +909,7 @@ int main()
|
|||
break;
|
||||
case 'z': // Load/Save conf
|
||||
resp[1] = cmd[1];
|
||||
resp[2] = sizeof(conf);
|
||||
resp[2] = sizeof(struct conf);
|
||||
if (!up) {
|
||||
if (cmd[1]!='W' || eeprom_save(cmd[2]*4)) {
|
||||
resp[0] = 'E';
|
||||
|
|
@ -922,9 +926,9 @@ int main()
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (conf.magic != MAGIC || conf.version != VERSION) {
|
||||
if (v.conf.magic != MAGIC || v.conf.version != VERSION) {
|
||||
resp[0] = 'E';
|
||||
resp[2] = conf.version;
|
||||
resp[2] = v.conf.version;
|
||||
if (cmd[1] != 'F')
|
||||
break;
|
||||
}
|
||||
|
|
@ -933,14 +937,14 @@ int main()
|
|||
break;
|
||||
case 'x': // conf Byte
|
||||
resp[2] = cmd[1];
|
||||
if (cmd[1] >= sizeof(conf)) {
|
||||
if (cmd[1] >= sizeof(struct vars)) {
|
||||
resp[0] = 'E';
|
||||
resp[1] = sizeof(conf);
|
||||
resp[1] = sizeof(struct vars);
|
||||
break;
|
||||
}
|
||||
resp[1] = ((unsigned char *)(&conf))[cmd[1]];
|
||||
resp[1] = ((unsigned char *)(&v))[cmd[1]];
|
||||
if (up)
|
||||
((unsigned char *)(&conf))[cmd[1]] = cmd[2];
|
||||
((unsigned char *)(&v))[cmd[1]] = cmd[2];
|
||||
break;
|
||||
case 'y': // peek, poke
|
||||
resp[2] = cmd[1];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue