Теперь немного о другом. Рискую утомить читателя, поэтому-кратко.
0. Код под Winavr
1. В EEPROM имеется несколько наборов параметров, активный набор обозначен селектором:
Код
uint8_t EEMEM Selector=0x00;
#define Max_Applicable_Paramsets 4
typedef struct {
uint16_t Cap_Chg_Time; // ==0 then continuous mode
uint16_t Cap_Charge_Volt; // chg to volt
uint16_t Cap_Discharge_Volt; // disch downto this value (volts)
uint16_t Operating_Current; // ==0 then voltage mode
uint8_t Amplitude; // used for voltage mode boost
uint16_t PWMfreq;
uint16_t Expose_Time; // in 10ms step
uint8_t Rly_Mode; // ==0 none rly is turned on at selection
} App_Param_Record;
// eeprom implementation
App_Param_Record EEMEM Parameter_set[Max_Applicable_Paramsets] =
{{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}};
2. В памяти программ есть дескрипторы этих параметров, но только для активной страницы
Код
//дескриптор параметра
typedef struct {
uint8_t xcmd; // параметр соответствует некоторой команде, получаемой извне
void *ojaddr; // адрес параметра
uint8_t ojsize;// размер данных+ здесь же добавил опции размещения (см ниже) этих данных
} Cm_Xref_;
typedef Cm_Xref_ PROGMEM Cm_Xref_t; // объявили
// опции размещения данных
#define Fitter_mask 0xC0
// размещено во флеше (т.е. данные будут только для чтения)
#define Flash_Fit 0x80
// размещено ЕЕ
#define EE_Fit 0xC0
// размещено в ОЗУ и только для чтения
#define Sram_Fit_RO 0x40 //fitted in sram and read only
// Размещено в буфере типа App_Param_Record, в который будет копироваться страница параметров
#define Relative_Fit 0x00 // relative to struct
// Команды на чтение 0x00..0x7F на запись 0x80..0xFF
#define Inhibit_read_write_mask 0x7F
//собсно описания
static App_Param_Record Edited_Record; // sram shadow
#define Rel_Param(member) &Edited_Record.member,Relative_Fit+sizeof(Edited_Record.member)
static Cm_Xref_t Cm_Xref[Max_cmd+1]=
{
{cm_Brief,0,0}, // version crc
{cm_NetLocate,&Net_ID,EE_Fit+1},
{cm_Set_Selector,&Selector,EE_Fit+1},
{cm_Charge_Time,Rel_Param(Cap_Chg_Time)},
{cm_Charge_Volt,Rel_Param(Cap_Charge_Volt)},
{cm_Discharge_Volt,Rel_Param(Cap_Discharge_Volt)},
{cm_Operating_Current,Rel_Param(Operating_Current)},
{cm_Amplitude,Rel_Param(Amplitude) },
{cm_Expose_Time,Rel_Param(Expose_Time)},
{cm_Rly_Mode,Rel_Param(Rly_Mode)}
};
Сложняк ?
Да. Для описания параметров из активной страницы пришлось принять, что эту страницу мы будем копировать в буфер. По-другому никак. Потому что, иначе мы разрушаем переносимость программы.
3. Проглотил я, короче, эти сложности - в конце концов памяти программ я пока не потерял.
В общем, дело доходит до реализации. Обрезал я поиск команды. Оставил обращение типа Cm_Xref[command].
Привожу процедуру без купюр и особых комментов. Все названия сторонних функций - сами за себя говорят.
Код
void Track_Pult(void)
{
uint8_t buffer[8],Rsz,*addr,k;
Packet_Layout *pack;
Cm_Xref_ xref,*xr;
Rsz = RS485_pack_ready();
if (!Rsz) return;
// <datasize> <receiver> <sender> <command> <data> <crc>
pack = &RS_buff;
if((pack->receiver) != Get_Net_ID()) goto Catch;
// else -continue parsing received pack
Sender_Addr = pack->sender;// store sender
Rsz -= 5;
k = pack->command & Inhibit_read_write_mask;
if (k == cm_Remote_Start){
Set_Start_Status();
Send_error(er_OK); // :) no errors
goto Catch; }
if (k == cm_Remote_Stop) {
Set_Stop_Status();
Send_error(er_OK);
goto Catch; }
if (k >= Max_cmd) {Send_error(er_Unknown_cmd);goto Catch;}
xr = memcpy_P(&xref,&(Cm_Xref[k]),sizeof(xref));
uint8_t options,objsize;
void *compaddr;
options = xref.ojsize;
objsize = options & (~Fitter_mask);
options &= Fitter_mask;
addr = xref.ojaddr;
k = pack->command != k;
if (Dev_Status.IsWorking) {Send_error(er_Busy); goto Catch;}
if (Rsz != objsize) {Send_error(er_InvParam); goto Catch;}
switch (options){
case Flash_Fit:
if (k) Send_error(er_Read_Only);
else Send_data(er_OK,memcpy_P(&buffer,addr,objsize),objsize);
break;
case EE_Fit:
eeprom_read_block(&buffer,addr,objsize);
if (k) {eeprom_write_block(addr,&(pack->data),objsize);Send_error(er_OK);}
else Send_data(er_OK,&buffer,objsize);
break;
case Relative_Fit:
compaddr = Paramset();
eeprom_read_block(&Edited_Record,compaddr,sizeof(Edited_Record));
if (k) {eeprom_write_block(&Edited_Record,compaddr,sizeof(Edited_Record)); Send_error(er_OK);}
else Send_data(er_OK, addr,objsize);
break;
}
Catch:
RS485_purge_received();
return;
}
Утомил?
Могу сказать одно - на асме эта байда была бы существенно проще. Я уже не говорю про смысл записи в EEPROM значений, которые не изменились.

Если я еще чего туда наверну, мне памяти точно не хватит.
Если все-же кто-то "асилил" то, что я накрапал, подскажите, как бороться со сложняком в системе описания параметров. Через "C", ессно.
З.Ы. О цифрах забыл размер кода 364 байт. Время - пофиг. Оптимизация -Os
З.З.Ы. Подчистил грязь - исправил "caller" на "receiver"