Could someone help me how to refactor old very complex code ?
Original used just setup and everything else was in single ISR. But as it was bigger and bigger, code is quite slow and quite random sometimes, even PC emulator did not helpped much (probably some long operations like printing are sometimes interrupted by next interrupt depending on analog values, buttons, etc.).
Is there any guide how to maintain such a project or is there only way out start again from scratch ?
As there are few important regulations also event queue would be needed, but not sure if there is any pattern or a template to start from in case of restart. A-Star 32U4 Micro has <32kB flash and code is hard to fit in yet (there are also big fonts).
Example of font unpack code, but hope this part is quite ok:
void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
uint16_t color, uint16_t bg, uint8_t size) {
...
uint8_t blockSize = 0;
if(packed) blockSize = pgm_read_byte(&bitmap[bo++]); // for first char pick 1st bit array only
BitStreamsReader bitStream(&bitmap[bo++], packed?blockSize:0); // ptr, blockSize(if packed)
BitXorBuffer rowXorBuf(w); // row XOR buffer (each row is XORed with)
bool chk;
for(yy=0; yy<h; yy++) {
rowXorBuf.rewind();
for(xx=0; xx<w; xx++) {
chk = bitStream; // read 1b
if(packed) chk = rowXorBuf.xorMove(chk); // xor with XOR buffer
if(chk) {
if(size == 1) {
writePixel(x+xo+xx, y+yo+yy, color);
} else {
writeFillRect(x+(xo16+xx)*size, y+(yo16+yy)*size,
size, size, color);
}
}
}
}
...
class BitStreamsReader {
public:
BitStreamsReader(uint8_t *arr, unsigned int maxSize) {
blockSize = maxSize;
bitMask = 0x80;
bytePtr = arr;
zerosCount = 0;
remainingBits = 0;
markBitInit();
}
operator bool() {
if(!blockSize) { // unpacked stream
bool retVal = !!(pgm_read_byte(bytePtr) & bitMask);
next();
return retVal;
} else if(remainingBits) {
bool retVal = !!(pgm_read_byte(bytePtr) & bitMask);
next();
if(!--remainingBits) {
markBitInit();
}
return retVal;
} else if(zerosCount) {
if(!--zerosCount) {
markBitInit();
}
return 0;
}
return 0; //throw "??";
}
private:
void markBitInit() {
if(blockSize) {
if(pgm_read_byte(bytePtr) & bitMask) {
remainingBits = blockSize;
} else {
zerosCount = blockSize;
}
next();
}
}
void next () {
if(bitMask == 0x01) {
bitMask = 0x80;
bytePtr++;
} else {
bitMask >>= 1;
}
};
uint8_t *bytePtr, bitMask, zerosCount, remainingBits, blockSize;
};
class BitXorBuffer {
public:
BitXorBuffer(int bufSize) {
bufSize = bufSize/8+!!(bufSize&7);
bitBuf = new uint8_t[bufSize];
memset(bitBuf, 0, bufSize);
rewind();
}
~BitXorBuffer() {
delete[] bitBuf;
}
void rewind() {
bitMask = 128;
bytePtr = bitBuf;
}
bool xorMove(bool by) {
if(bitMask & *bytePtr) by ^= true;
*bytePtr |= bitMask;
if(!by) {
*bytePtr ^= bitMask;
}
nextBit();
return by;
}
private:
void nextBit() {
if(bitMask > 1) {
bitMask >>= 1; // move bit in XOR buffer
} else {
bitMask = 128;
bytePtr++;
}
}
uint8_t *bytePtr, *bitBuf, bitMask;
};
digitalRead(). An ISR should be in-and-out in as few instruction cycles as possible.