воскресенье, 30 сентября 2012 г.

AVR32: simple C pitfall

Often programmers like to convert pointer to one type to pointer to another. It's a usually (and INCORRECT!) "method" to pick-up some integer from byte array. From C standard we know that pointer to one type IS NOT EQUAL to pointer to another. But programmers ignores this fact on x86 :)
They will not ignore this on AVR/AVR32 architecture :)

среда, 19 сентября 2012 г.

Simplest (and fastest) allocator in C

I need to allocate strings (in UI) with the same length in my MCU program, so I can use: 1) static local buffer in functions or use 2) common buffer. 1) cons: implicit memory "eating" 2) cons: funcs are not reenterable. I use next simple (simplest!) and fast allocator - it allocate strings with the same length. It has only to necessary functions in it's API: allocate and free. Here is the code:
#include <stdint.h>
#include "bset.h"
/** string count */
#define GUI_TMPSTR_N 3
/** max string length */
#define GUI_TMPSTR_MAXLEN 64
/// block of temporary strings with the same length
typedef struct gui_tmpstr_buf_t {
        bset_t pool;
        char buf[GUI_TMPSTR_N][GUI_TMPSTR_MAXLEN];
} gui_tmpstr_buf_t;

#define GUI_TMPSTR_BUF_INITIALIZER() { \
        .pool = BSET_INITIALIZER(), \
        .buf = {0} \
}

// global blocks for allocation
gui_tmpstr_buf_t _tmpstrbuf = GUI_TMPSTR_BUF_INITIALIZER();

/// allocate temporary string
char*
gui_tmpstr_alloc(void) {
        int i;
        BSET_FORCLR(i, &_tmpstrbuf.pool) {
                if (i >= GUI_TMPSTR_N)
                        break;
                BSET_SET(i, &_tmpstrbuf.pool);
                return (_tmpstrbuf.buf[i]);
        }
        return (NULL);
}

/// free allocated tmp. string
void
gui_tmpstr_free(char* ptr) {
        intptr_t i = ((intptr_t)ptr - (intptr_t)_tmpstrbuf.buf);
        if (i <= 0) {
                // ptr is BEFORE base addr (buf)
                return;
        }
        if (i % GUI_TMPSTR_MAXLEN) {
                // ptr is not align on GUI_TMPSTR_MAXLEN
                return;
        }
        i /= GUI_TMPSTR_MAXLEN;
        if (BSET_ISSET(i, &_tmpstrbuf.pool)) {
                // free in pool
                BSET_CLR(i, &_tmpstrbuf.pool);
        }
}
GUI_TMPSTR_MAXLEN defines length of each string, GUI_TMPSTR_N defines available strings number. I used such string in UI (cutting strings, modifing, so on...).

Used bset.h is modified BSD select.h with API (macroses): BSET_SET(), BSET_CLR(), BSET_TGL(), BSET_ISSET(), BSET_FOREACH(), BSET_FORSET(), BSET_FORCLR(), BSET_FOREACHBYTE(), BSET_FOREACHMASK(), BSET_BYTE(), BSET_MASK(), BSET_COPY(), BSET_ZERO().

Most interesting are BSET_CLR() - clear item from bit's set, BSET_SET() - set item in bit's set, BSET_FORCLR() - iterate over cleared items in bit's set - looking for free strings in pool.

Little example:
char* ptr = gui_tmpstr_alloc();
if (ptr) {
  // USAGE of ptr
  ...
  // free:
  gui_tmpstr_free(ptr);
}

понедельник, 17 сентября 2012 г.

ASF: simple utility for font editing

Used fonts in Atmel Software Framework are simple: each glyph is described with array of bytes - each set bit is pixel, no bit - no pixel :)
Next is the very-very simple Tcl utility to convert glyph bytes into console image of symbol and vice-verse.

# parsing and loading font
#------------------------------------------------------------------------------
proc parsesymb str {
    # Parse one symbol in notation like:
    # "0x06,0x08,0x08,0x00,0x00,0x00,0x00,0x00"

    set bytes [regexp -all -inline {0[xX][0-9a-fA-F]{2}} $str]
    return $bytes
}

proc putsymbline byte {
    # put on screen one line of a symbol

    set mask 0b10000000
    for {set i 0} {$i<8 data-blogger-escaped-bit="bit" data-blogger-escaped-byte="byte" data-blogger-escaped-expr="expr" data-blogger-escaped-i="i" data-blogger-escaped-incr="incr" data-blogger-escaped-mask="mask" data-blogger-escaped-set="set">>1}]
        if $bit {
            puts -nonewline "#"
        } else {
            puts -nonewline " "
        }
    }
}

proc putsymb symb_bytes {
    # put on screen all symbol (all it's lines)

    puts "+--------+"
    foreach sb $symb_bytes {
        puts -nonewline "|"
        putsymbline $sb
        puts "|"
    }
    puts "+--------+"
}

# Compile glyphs to font in C format
#-------------------------------------------------------------------------------
proc compsymbline line {
    # Compile line like "# # # # " to 0xAA

    set bits [string map { " " 0 # 1} $line]
    return [format 0x%02X "0b$bits"]
}

proc compsymb symb_lines {
    # Compile lines of symbol (what out 'putsymb')

    set read 0
    set res {}
    foreach line $symb_lines {
        if {0 == $read} {
            if {$line eq "+--------+"} {
                set read 1
            }
        } else {
            if {$line eq "+--------+"} {
                break
            } else {
                set line [string trim $line "|"]
                lappend res [compsymbline $line]
            }
        }
    }
    return [join $res ","]
}

proc getlines {} {
    set lines {}
    while {[gets stdin line] >= 0} {
        lappend lines $line
    }
    return $lines
}

proc main args {
    global argc argv
    if {$argc} {
        set argv0 [lindex $argv 0]
        if {$argv0 eq "comp"} {
            set lines [getlines]
            puts [compsymb $lines]
            return
        } elseif {$argv0 eq "put"} {
            set line [gets stdin]
            puts [putsymb [parsesymb $line]]
            return
        }
    }
    puts {\
Syntax on Linux:
    1. cat file|PRG comp
    2. cat file|PRG put
Syntax on Windows:
    1. more file|PRG comp
    2. more file|PRG put

This means:
    1. Compile glyph image into C hex array
    2. Put glyph hex array on the screen as glyph image

Glyph images and its' hex arrays are inverse}
}

main
}
Example of usage:
$echo 0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00|tclkitsh font.tcl put
+--------+
|  #     |
| ####   |
|# #     |
| ###    |
|  # #   |
|####    |
|  #     |
|        |
+--------+
$
This is the "$" symbol. It's bytes I get from et024006dhu.c (see const unsigned char FONT6x8[97][8]) From another hand, you can save this glyph (with ASCII-box!) in some file and then call:
$cat somefile.txt|tclkitsh font.tcl comp
0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00
$
to get bytes of the glyph.