Add the serialdata tool draft

Mon, 28 Jan 2019 21:50:09 +0100

author
David Douard <david.douard@logilab.fr>
date
Mon, 28 Jan 2019 21:50:09 +0100
changeset 23
daf26b083899
parent 22
2f51221af82d
child 24
b43536c064f6

Add the serialdata tool

to read and decode serial data from the hp34970 using the dslogic.

serialdata/34970-long-session.sr file | annotate | diff | comparison | revisions
serialdata/34970.rd file | annotate | diff | comparison | revisions
serialdata/read-ds file | annotate | diff | comparison | revisions
serialdata/read-ds-continuous file | annotate | diff | comparison | revisions
serialdata/read-sr file | annotate | diff | comparison | revisions
serialdata/sr-info.py file | annotate | diff | comparison | revisions
serialdata/uart_filter.py file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
Binary file serialdata/34970-long-session.sr has changed
Binary file serialdata/34970.rd has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serialdata/read-ds	Mon Jan 28 21:50:09 2019 +0100
@@ -0,0 +1,1 @@
+sigrok-cli -d dreamsourcelab-dslogic --config samplerate=1000000 --samples=100000 -t 2=f --channels 1,2,3 -l 4 -P uart:baudrate=187500:parity_type=none:rx=1:tx=3 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serialdata/read-ds-continuous	Mon Jan 28 21:50:09 2019 +0100
@@ -0,0 +1,1 @@
+sigrok-cli -d dreamsourcelab-dslogic -c samplerate=1M:continuous=on --triggers 2=f --channels 1,2,3 -l 4 -P uart:baudrate=187500:parity_type=none:rx=1:tx=3 --continuous
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serialdata/read-sr	Mon Jan 28 21:50:09 2019 +0100
@@ -0,0 +1,1 @@
+sigrok-cli -i 34970-long-session.sr -P uart:baudrate=187500:parity_type=none:rx=RX:tx=TX -l 4 2>/dev/null | python3 uart_filter.py 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serialdata/sr-info.py	Mon Jan 28 21:50:09 2019 +0100
@@ -0,0 +1,27 @@
+import zipfile
+import configparser
+
+
+def extract_metadata(fname):
+    cfg = configparser.ConfigParser()
+    with zipfile.ZipFile(fname) as zf:
+        mdata = zf.open('metadata').read()
+    cfg.read_string(mdata.decode())
+    return cfg
+
+
+def print_metadata(mdata):
+    for kv in mdata['global'].items():
+        print('%s: %s' % kv)
+    for device, cfg in mdata.items():
+        if device in ('global', 'DEFAULT'):
+            continue
+        print('%s:' % device)
+        for kv in cfg.items():
+            print('  %s: %s' % kv)
+
+
+if __name__ == '__main__':
+    import sys
+    for fn in sys.argv[1:]:
+        print_metadata(extract_metadata(fn))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serialdata/uart_filter.py	Mon Jan 28 21:50:09 2019 +0100
@@ -0,0 +1,279 @@
+import sys
+import re
+import click
+
+F = 1e6
+
+reg = re.compile(r'^(?P<fr1>\d+)-(?P<fr2>\d+) .*: (?P<rxtx>rx|tx)-data: "(?P<value>..)"$')  # noqa
+
+
+class ProtocolError(Exception):
+    pass
+
+class ProtocolReset(Exception):
+    pass
+
+pkts = []
+
+
+class Packet:
+    def __init__(self, frame, rxtx, value):
+        self.frame = frame
+        self.rxtx = rxtx
+        self.value = value
+
+    @property
+    def timestamp(self):
+        return self.frame / F * 1000
+
+    @property
+    def relts(self):
+        return self.timestamp - pkts[0].timestamp
+
+    def __str__(self):
+        return '[%06.2f] %s: %02X' % (self.timestamp, self.rxtx, self.value)
+
+
+def read_line(seq):
+    for line in seq:
+        m = reg.match(line)
+        if m:
+            frame = int(m.group('fr1'))
+            v = int(m.group('value'), base=16)
+            rxtx = m.group('rxtx')
+            pkt = Packet(frame, rxtx, v)
+            pkts.append(pkt)
+            yield pkt
+
+
+def read_input(stream=None):
+    if stream is None:
+        stream = sys.stdin
+    for line in stream:
+        yield line
+
+
+def print_input():
+    t0 = None
+    for pkt in read_line(read_input()):
+        c = chr(pkt.value) if 32 <= pkt.value <= 127 else ''
+        if t0 is None:
+            t0 = pkt.timestamp
+        cnxdir = 'CPU-->DP' if pkt.rxtx == 'rx' else 'CPU<--DP'
+        print('[%s] %06.1f: %02X # %s' % (
+            cnxdir, (pkt.timestamp-t0), pkt.value, c))
+
+
+def flipdir(rxtx):
+    return 'rx' if rxtx == 'tx' else 'tx'
+
+
+def check_rxtx(cur, pkt):
+    if cur.rxtx == pkt.rxtx:
+        raise ProtocolError('Expected %s transmission %02X %02X' %
+                            (flipdir(cur.rxtx), cur.value, pkt.value))
+
+
+def check_sot_ack(ack, sot):
+    check_rxtx(ack, sot)
+    if ack.value != (0xFF - sot.value):
+        if ack.value == 0x66:
+            raise ProtocolReset()
+        raise ProtocolError('Expected ACK value %02X, got %02X' %
+                            (0xFF - sot.value, ack.value))
+
+
+def wait_for_sot(seq, sot_pkt=None):
+    if sot_pkt is None:
+        for sot_pkt in seq:
+            if sot_pkt.value not in SOT_VALUES:
+                print('Unexpected value %s: %02X' %
+                      (sot_pkt.rxtx, sot_pkt.value))
+            else:
+                break
+    for ack_pkt in seq:
+        try:
+            check_sot_ack(sot_pkt, ack_pkt)
+            # print('New packet %s' % sot_pkt)
+            return sot_pkt, ack_pkt
+        except ProtocolReset:
+            # print('reset')
+            sot_pkt = ack_pkt
+    raise StopIteration()
+
+
+SOT_VALUES = [0x33, 0x66]
+
+
+def recv_packet(seq):
+    sot_pkt = None
+    while True:
+        sot_pkt, ack_pkt = wait_for_sot(seq, sot_pkt)
+        payload = []
+        recv_char = None
+        may_stop = False
+
+        cur_pkt = ack_pkt
+        for pkt in seq:
+            if pkt.value == 0x66:
+                sot_pkt = pkt
+                break
+
+            check_rxtx(pkt, cur_pkt)
+            if recv_char is None:
+                if pkt.rxtx != sot_pkt.rxtx:
+                    raise ProtocolError()
+                recv_char = pkt.value
+                cur_pkt = pkt
+                if may_stop:
+                    if recv_char == 0x55:
+                        cur_pkt = None
+                        sot_pkt = None
+                        break
+            else:
+                if pkt.rxtx == sot_pkt.rxtx:
+                    raise ProtocolError()
+                if pkt.value == 0x00:
+                    payload.append(recv_char)
+                    if check_payload(sot_pkt, payload):
+                        may_stop = True
+                        yield (sot_pkt, payload)
+                    else:
+                        may_stop = False
+                elif pkt.value != 0xFF:
+                    # if FF, ignore the char (ie. its a NACK, so resend)
+                    raise ProtocolError('Not really but hey %02X [%02X] %s' %
+                                        (pkt.value, recv_char, payload))
+                recv_char = None
+                cur_pkt = pkt
+        else:
+            break
+
+
+def check_payload(sot, payload):
+    if sot.rxtx == 'tx':
+        if sot.value == 0x33:
+            return len(payload) == 2
+        else:
+            return len(payload) == 1
+    else:
+        if len(payload) > 1:
+            return len(payload) == (payload[1]+2)
+    return False
+
+
+KEYCODES = {
+    0x00: 'View',
+    0x01: 'Mon',
+    0x02: 'Sto/Rcl',
+    0x03: 'Scan',
+    0x04: 'Alarm',
+    0x05: 'Mx+B',
+    0x06: 'Measure',
+    0x07: 'Interval',
+    0x08: 'Card Reset',
+    0x09: 'Close',
+    0x0A: 'Open',
+    0x0B: 'Read',
+    0x0C: 'Shift',
+    0x0D: 'Write',
+    0x0E: 'Left',
+    0x0F: 'Right',
+    0x10: 'Advanced',
+    0x11: 'Step',
+    0x80: 'Knob right',
+    0x81: 'Knob left',
+    }
+
+
+FLAGS = [
+    ['<Bell>', 'Mx+B', 'Ch. frame', 'Channel', 'LO', 'Alarm', 'HI', 'Al. frame'],
+    ['2', '4', '3', '1', '4W', 'OC', '', 'AVG'],
+    ['MAX', 'MIN', 'LAST', 'MEM', '', 'ONCE', 'EXT', 'ERROR'],
+    ['REMOTE', 'ADRS', '*', 'VIEW', 'MON', 'SCAN', 'CONFIG', '']
+]
+
+
+def flag(payload):
+    flags = []
+    for flg, byte in zip(FLAGS, payload[2:]):
+        for i in range(8):
+            if byte & 2**i:
+                flags.append(flg[i])
+    return ','.join(flags)
+
+
+def flag_by_num(num):
+    for b in FLAGS:
+        for f in b:
+            if num == 0:
+                return f
+            num -= 1
+
+CMDS = {
+    0x00: ('DISPLAY ', lambda pl: ''.join(chr(x) for x in pl[2:])),
+    0x0C: ('CHANNEL ', lambda pl: ''.join(chr(x) for x in pl[2:])),
+    0x0A: ('FLAGS   ', flag),
+    0x01: ('UNSHIFT ', None),
+    0x86: ('SHUTDOWN', None),
+    0x0D: ('CHAR LO ', lambda pl: str(pl[2])),
+    0x08: ('FLAG LO ', lambda pl: flag_by_num(pl[2])),
+    0x09: ('FLAG HI ', lambda pl: flag_by_num(pl[2])),
+    0x02: ('RST?    ', None),
+    }
+
+
+def parse_packet(sot, payload):
+    if sot.value == 0x33:
+        return 'INIT KEY=%s' % KEYCODES.get(payload[1], 'None')
+    if sot.rxtx == 'tx':
+        kc = payload[0]
+        if kc in (0x80, 0x81):
+            return 'KNOB\t\t%s' % click.style(KEYCODES.get(kc), fg='magenta')
+        if kc & 0x40:
+            kc = kc & 0xBF
+            event = 'RELEASED'
+        else:
+            event = 'PRESSED '
+        return 'KEY %s\t%s' % (click.style(event, fg='green'),
+                               click.style(KEYCODES.get(kc), fg='cyan'))
+    lbl, dspfunc = CMDS[payload[0]]
+    if dspfunc:
+        lbl += '\t%s' % click.style(dspfunc(payload), fg='green')
+    return lbl
+
+
+@click.command()
+@click.option('-p', '--packets/--no-packets', default=False)
+def main(packets):
+    if packets:
+        try:
+            for sot, payload in recv_packet(read_line(read_input())):
+                cnxdir = 'CPU=>DP' if sot.rxtx == 'rx' else 'CPU<-DP'
+                print('[%s]: %02X=[%s]' %
+                      (cnxdir, sot.value,
+                       ','.join('%02x' % x for x in payload)))
+        except:
+            print('\n'.join(str(x) for x in pkts[-10:]))
+            raise
+    else:
+        try:
+            t0 = None
+            for sot, payload in recv_packet(read_line(read_input())):
+                cnxdir = '>>>' if sot.rxtx == 'rx' else '<<<'
+                if t0 is None:
+                    t0 = sot.timestamp
+                click.secho('%08.0f ' % sot.relts,
+                            fg='yellow', nl=False)
+                click.secho('[+%04.2f] ' % ((sot.timestamp - t0)/1000.),
+                            fg='blue', nl=False)
+                click.secho(cnxdir + ' ', fg='red', nl=False)
+                click.secho(parse_packet(sot, payload), fg='white')
+                t0 = sot.timestamp
+        except:
+            print('\n'.join(str(x) for x in pkts[-10:]))
+            raise
+
+
+if __name__ == '__main__':
+    main()
--- a/src/main.cpp	Wed Nov 07 20:00:52 2018 +0100
+++ b/src/main.cpp	Mon Jan 28 21:50:09 2019 +0100
@@ -188,12 +188,9 @@
 
 static DSP table[] =
 {
-  { 0x00, 0xF,   0x0,  0,  0, 0x01, MAX_BUFF, 245, Mono19x27}, // main display
-  { 0x0C, 0xF,   0x0,204, 38, 0x01, 3,        45,  Mono15x22}, // channels display
-  //  { 0x01, 0xF,   0x0,  0,  0, 0x80, MAX_BUFF, 0, Terminal6x8},
-  //  { 0x02, 0xF,   0x0,  0,  0, 0x80, MAX_BUFF, 0, Terminal6x8},
-  { 0x0A, 0xF,   0x0,  0, 57, 0x08, 4,        0, Terminal6x8}, // flags + bits
-  //  { 0xFF, 0xF,   0x0,  0,  0, 0x80, MAX_BUFF, 0, Terminal6x8},
+  { 0x00, 0xF, 0x0,  0,  0, 0x01, MAX_BUFF, 245, Mono19x27}, // main display
+  { 0x0C, 0xF, 0x0,196, 34, 0x01, 3,        45,  Mono15x22}, // channels display
+  { 0x0A, 0xF, 0x0,  0, 57, 0x08, 4,        0, Terminal6x8}, // flags + bits
 };
 
 // 9x10
@@ -228,9 +225,9 @@
 typedef struct _FLAG
 {
   uint8_t flag;
-  uint16_t zone;
   uint8_t x;
   uint8_t y;
+	bool reverse;
   const char* msg;
   const unsigned char* icon;
 } FLAG;
@@ -246,53 +243,47 @@
 
 static const FLAG flags[] =
   {
-    // flag, zone, x0, y0, msg, icon
+    // flag, zone, x0, y0, reverse, msg, icon
     // right-side icons area
-    { 0x00, 0x02, 0, 0,  NULL, icon_alarm}, // F1.0
-    { 0x01, 0x02, 0, 11, NULL, icon_curve}, // F1.1
-    //{ 0x14, 0x02, 0, 0,  "4W"},     // F2.4
-    //{ 0x15, 0x02, 0, 8,  "OC"},     // F2.5
+		{ 0x00, 246, 0,  false, NULL, icon_alarm}, // F1.0
+    { 0x01, 246, 11, false, NULL, icon_curve}, // F1.1
 
     // F1.2 == Channel frame
-    { 0x03, 0x04, 1, 2, "Channel"},  // F1.3
-	// F1.7 == Alarm frame
+    { 0x03, 197, 27, false, "Channel"},  // F1.3
+  	// F1.7 == Alarm frame
+
 
-    // col 1
-    { 0x34, 0x10, 0,  0,  "MON"},    // F4.4
-    { 0x33, 0x10, 0,  8,  "VIEW"},   // F4.3
-    { 0x35, 0x10, 0,  16, "SCAN"},   // F4.5
+    { 0x34, 0,  28+8,  false, "MON"},    // F4.4
+    { 0x33, 0,  28+16, false, "VIEW"},   // F4.3
+    { 0x35, 0,  28,    true, "SCAN"},   // F4.5
+    { 0x36, 0,  28+25, true, "CONFIG"},    // F4.6
 
-    //col 2
-    { 0x32, 0x20, 0, 0,   "*"},      // F4.2
-    { 0x36, 0x20, 0, 8,   "CONFIG"},    // F4.6
-    { 0x27, 0x20, 0, 16,  "ERROR"},    // F3.7
+    { 0x32, 40, 52,    false, "*"},      // F4.2
+    { 0x31, 50, 52,    false, "ADRS"},   // F4.1
+    { 0x30, 80, 52,    false, "RMT"},    // F4.0
+    { 0x27, 104, 52,   true, "ERROR"},    // F3.7
 
-    // col 3
-    { 0x41, 0x040, 0, 0,  "ADRS"},   // F4.1
-    { 0x40, 0x040, 0, 8,  "RMT"},    // F4.0
+    { 0x26, 140, 52,   false, "EXT"},    // F3.6
+    { 0x25, 164, 52,   false, "ONCE"},   // F3.5
 
-    // col 4
-    { 0x26, 0x080, 0, 0,  "EXT"},    // F3.6
-    { 0x25, 0x080, 0, 8,  "ONCE"},   // F3.5
-
-    { 0x23, 0x080, 0, 16, "MEM"},    // F3.3
+    { 0x23, 104, 28+16, false, "MEM"},    // F3.3
 
 
     // col 5
-    { 0x14, 0x100, 0, 0,  "4W"},     // F2.4
-    { 0x15, 0x100, 0, 8,  "OC"},     // F2.5
-    { 0x22, 0x100, 0, 16, "LAST"},   // F3.2
-    { 0x21, 0x100, 0, 16, "MIN"},    // F3.1
-    { 0x20, 0x100, 0, 16, "MAX"},    // F3.0
-    { 0x17, 0x100, 0, 16, "AVG"},    // F2.7
+    { 0x14, 244, 22,  false, "4W"},     // F2.4
+    { 0x15, 244, 30,  false, "OC"},     // F2.5
+    { 0x22, 129, 28+16, false, "LAST"},   // F3.2
+    { 0x21, 129, 28+16, false, "MIN"},    // F3.1
+    { 0x20, 129, 28+16, false, "MAX"},    // F3.0
+    { 0x17, 129, 28+16, false, "AVG"},    // F2.7
 
-    { 0x05, 0x08, 0,   0, "Alarm"},  // F1.5
-    { 0x06, 0x08, 0,  10, "H"},      // F1.6
-    { 0x13, 0x08, 6,  10, "1"},      // F2.3
-    { 0x10, 0x08, 12, 10, "2"},      // F2.0
-    { 0x12, 0x08, 18, 10, "3"},      // F2.2
-    { 0x11, 0x08, 24, 10, "4"},      // F2.1
-    { 0x04, 0x08, 30, 10, "L"},      // F1.4
+    { 0x05, 154+0,  17+10, false, "Alarm"},  // F1.5
+    { 0x06, 154+0,  17+20, false, "H"},      // F1.6
+    { 0x13, 154+6,  17+20, false, "1"},      // F2.3
+    { 0x10, 154+12, 17+20, false, "2"},      // F2.0
+    { 0x12, 154+18, 17+20, false, "3"},      // F2.2
+    { 0x11, 154+24, 17+20, false, "4"},      // F2.1
+    { 0x04, 154+30, 17+20, false, "L"},      // F1.4
 
   };
 
@@ -300,7 +291,7 @@
 { // flag, x0, y0, x1, y1
     { 0x001, 0,   0, 245, 27}, // main display area
     { 0x002, 246, 0, 255, 27}, // right notif area
-    { 0x004, 203, 28, 255, 54}, // channels display area
+    { 0x004, 208, 35, 254, 62}, // channels display area
     { 0x008, 160, 28, 202, 54}, // alarms area
     { 0x010, 0,   28, 32,  54}, // flags col1
     { 0x020, 33,  28, 70,  54}, // flags col2
@@ -313,8 +304,8 @@
 
 static const FRAME frames[] =
   {
-    { 0x02, 203, 35, 255, 54}, // F1.2 - channel frame
-    { 0x07, 160, 28, 202, 54}, // F1.7 - alarm frame
+    { 0x02, 194, 30, 243, 53}, // F1.2 - channel frame
+    { 0x07, 151, 30, 192, 46}, // F1.7 - alarm frame
   };
 
 
@@ -405,11 +396,8 @@
   printf("     DSP_DC=%d\r\n", DSP_DC);
   dsp = new SSD1322(20000000, DSP_MOSI, DSP_MISO, DSP_SCLK, DSP_CS,
 		    DSP_RST, DSP_DC, "SSD1322");
-  //dsp.set_orientation(3);
+
   printf("  configure DSP\r\n");
-  // myLCD.set_font((unsigned char*) Terminal6x8);
-  // myLCD.claim(stdout);      // send stdout to the LCD display
-  // myLCD.claim(stderr);      // send stderr to the LCD display
   dsp->background(Black);    // set background to black
   dsp->foreground(0xF);
   dsp->cls();
@@ -452,7 +440,6 @@
 void end_splashscreen(void)
 {
   printf("End of splash screen CB\r\n");
-  //dsp->cls();
   splashscreen = false;
 }
 
@@ -507,7 +494,8 @@
   }
 }
 
-void show(uint8_t cmd, const char *intxt, uint8_t nchar=0) {
+void show(uint8_t cmd, const char *intxt, uint8_t nchar=0)
+{
   uint8_t i, len;
   uint16_t bgcolor, fgcolor;
   char *oldv;
@@ -520,143 +508,140 @@
   }
   else
   {
-  txt = (char *)malloc(strlen(intxt)+1);
-  strcpy(txt, intxt);
-  txtp = txt;
+		txt = (char *)malloc(strlen(intxt)+1);
+		strcpy(txt, intxt);
+		txtp = txt;
+
+		pulse(1, true);
+
+		len = MAX_BUFF;
 
-  pulse(1, true);
+		for (i=0; i<sizeof(table)/sizeof(table[0]); ++i) {
+			if (table[i].cmd == cmd) {
+				bgcolor = table[i].bgcolor;
+				fgcolor = table[i].color;
+				dsp->background(bgcolor);
+				dsp->foreground(fgcolor);
+				dsp->set_font((unsigned char*) table[i].font);
+				oldv = table[i].buffer;
 
-  len = MAX_BUFF;
+				dsp->locate(table[i].x0, table[i].y0);
 
-  for (i=0; i<sizeof(table)/sizeof(table[0]); ++i) {
-    if (table[i].cmd == cmd) {
-      bgcolor = table[i].bgcolor;
-      fgcolor = table[i].color;
-      dsp->background(bgcolor);
-      dsp->foreground(fgcolor);
-      dsp->set_font((unsigned char*) table[i].font);
-      oldv = table[i].buffer;
-
-      dsp->locate(table[i].x0, table[i].y0);
+				if (table[i].fmt & 0x01 )  // ASCII text
+				{
+					if (strncmp(oldv, txt, table[i].maxsize) != 0)
+					{
+						if (table[i].width > 0)
+							dsp->fillrect(table[i].x0,
+														table[i].y0,
+														table[i].x0 + table[i].width,
+														table[i].y0 + table[i].font[2],
+														bgcolor);
+						for (uint8_t k=0; ;k++)
+						{
+							if (txtp[k] == 0x00)
+							{
+								dsp->printf(txtp);
+								break;
+							}
+							if (txtp[k] == 0x09)
+							{ // \t is a special char for 'unselected' display value
+								txtp[k] = 0x00;
+								dsp->printf(txtp);
 
-      if (table[i].fmt & 0x01 )
-	  {
-		if (strncmp(oldv, txt, table[i].maxsize) != 0)
-		{
-		  // ascii
-		  if (table[i].width > 0)
-			dsp->fillrect(table[i].x0,
-						  table[i].y0,
-						  table[i].x0 + table[i].width,
-						  table[i].y0 + table[i].font[2],
-						  bgcolor);
-		  for (uint8_t k=0; ;k++)
-		  {
-			if (txtp[k] == 0x00)
-			{
-			  dsp->printf(txtp);
-			  break;
+								if (fgcolor == table[i].color)
+									fgcolor /= 2;
+								else
+									fgcolor = table[i].color;
+								dsp->foreground(fgcolor);
+								txtp = &(txtp[k+1]);
+								k = 0;
+							}
+						}
+						if (cmd == 0x00) // main area
+							must_refresh |= 0x01;
+						if (cmd == 0x0C) // channels area
+							must_refresh |= 0x04;
+					}
+				}
+				/*
+					if (table[i].fmt & 0x02 ) {
+					// hex
+					for (uint8_t j=0;; j++) {
+					if (txt[j] == 0x00)
+					break;
+					dsp->printf("%02X ", txt[j]);
+					}
+					for (uint8_t j=3*strlen(txt); j<table[i].maxsize; j++)
+					dsp->printf(" ");
+					}
+				*/
+				if (table[i].fmt & 0x08 )  // flag indicators
+				{
+					// flags
+					for (uint8_t j=0; j<max(nchar, table[i].maxsize) ; j++)
+					{
+						for (uint8_t k=0; k<8; k++)
+						{
+							if (1)
+							{ //(txt[j] & (1 << k) ) != (oldv[j] & (1 << k))) {
+								for (uint8_t l=0;
+										 l<(sizeof(flags)/sizeof(flags[0])); ++l)
+								{
+									if (flags[l].flag == ((j<<4) + k)) {
+										if (txtp[j] & (1 << k))
+										{
+											dsp->foreground(flags[l].reverse ? bgcolor : fgcolor);
+											dsp->background(flags[l].reverse ? fgcolor : bgcolor);
+										}
+										else
+										{
+											dsp->foreground(bgcolor);
+											dsp->background(bgcolor);
+										}
+										if (flags[l].msg != NULL)
+										{ // a string
+											dsp->locate(flags[l].x, flags[l].y);
+											dsp->printf(flags[l].msg);}
+										else
+										{ // an icon
+											Bitmap_s pic = {9, 10, 2, (char*) flags[l].icon};
+											dsp->Bitmap_BW(pic, flags[l].x, flags[l].y);
+										}
+										must_refresh = 1; //|= zones[m].flag;
+										break;
+									}
+								}
+							}
+						}
+					}
+
+					// draw frames (Alarm and Channel)
+					for (uint8_t l=0;
+							 l<(sizeof(frames)/sizeof(frames[0])); ++l)
+					{
+						uint16_t color;
+						if (frames[l].flag & txt[0]) // frame flags are on the 1st byte only
+							color = fgcolor/6;
+						else
+							color = bgcolor;
+						dsp->hline(frames[l].x0+1, frames[l].x0+3, frames[l].y0, color);
+						dsp->hline(frames[l].x1-3, frames[l].x1-1, frames[l].y0, color);
+						dsp->hline(frames[l].x0+1, frames[l].x1-1, frames[l].y1, color);
+
+						dsp->vline(frames[l].x0, frames[l].y0+1, frames[l].y1-1, color);
+						dsp->vline(frames[l].x1, frames[l].y0+1, frames[l].y1-1, color);
+					}
+				}
+
+				for(uint8_t j=0; j<table[i].maxsize; j++)
+					oldv[j] = txt[j];
+				break;
 			}
-			if (txtp[k] == 0x09)
-			{ // \t is a special char for 'unselected' display value
-			  txtp[k] = 0x00;
-			  dsp->printf(txtp);
-
-			  if (fgcolor == table[i].color)
-				fgcolor /= 2;
-			  else
-				fgcolor = table[i].color;
-			  dsp->foreground(fgcolor);
-			  txtp = &(txtp[k+1]);
-			  k = 0;
-			}
-		  }
-		  if (cmd == 0x00) // main area
-			must_refresh |= 0x01;
-		  if (cmd == 0x0C) // channels area
-			must_refresh |= 0x04;
 		}
-      }
-      /*
-      if (table[i].fmt & 0x02 ) {
-      // hex
-	for (uint8_t j=0;; j++) {
-	  if (txt[j] == 0x00)
-	    break;
-	  dsp->printf("%02X ", txt[j]);
-	}
-	for (uint8_t j=3*strlen(txt); j<table[i].maxsize; j++)
-	  dsp->printf(" ");
-      }
-      */
-      if (table[i].fmt & 0x08 )
-	  {
-		// flags
-		for (uint8_t j=0; j<max(nchar, table[i].maxsize) ; j++)
-		{
-		  for (uint8_t k=0; k<8; k++)
-		  {
-			if (1)
-			{ //(txt[j] & (1 << k) ) != (oldv[j] & (1 << k))) {
-			  if (txtp[j] & (1 << k))
-				dsp->foreground(fgcolor);
-			  else
-				dsp->foreground(bgcolor);
-
-	      /*
-	      for (uint8_t l=0;
-		   l<(sizeof(frames)/sizeof(frames[0])); ++l) {
-		if (frames[l].flag & ((j<<4) + k))
-		  dsp->fillrect(frames[l].x0, frames[l].y0,
-			       frames[l].x1, frames[l].y1,
-			       fgcolor/8);
-		else
-		  dsp->fillrect(frames[l].x0, frames[l].y0,
-			       frames[l].x1, frames[l].y1,
-			       bgcolor);
-
-	      }
-	      */
-
-			  for (uint8_t l=0;
-				   l<(sizeof(flags)/sizeof(flags[0])); ++l)
-			  {
-				if (flags[l].flag == ((j<<4) + k)) {
-				  for (uint8_t m=0; m<(sizeof(zones)/sizeof(zones[0])); m++)
-				  {
-					if (flags[l].zone == zones[m].flag) {
-					  if (flags[l].msg != NULL)
-					  { // a string
-						  dsp->locate(flags[l].x + zones[m].x0,
-									  flags[l].y + zones[m].y0);
-						  dsp->printf(flags[l].msg);}
-					  else
-					  { // an icon
-						Bitmap_s pic = {9, 10, 2, (char*) flags[l].icon};
-						dsp->Bitmap_BW(pic,
-									   flags[l].x + zones[m].x0,
-									   flags[l].y + zones[m].y0);
-					  }
-					  must_refresh |= zones[m].flag;
-					  break;
-					}
-				  }
-				  break;
-				}
-			  }
-			}
-		  }
-		}
-      }
-
-      for(uint8_t j=0; j<table[i].maxsize; j++)
-		oldv[j] = txt[j];
-      break;
-    }
-  }
-  free(txt);
-  //dsp->copy_to_lcd();
-  pulse(1, false);
+		free(txt);
+		//dsp->copy_to_lcd();
+		pulse(1, false);
   }
 }
 

mercurial