Skip to content

unit BoardInfo

em.utils/BoardInfo.em
package em.utils

from em$distro import BoardMeta as Meta

host module BoardInfo

    const PROP_BOARD_CHAIN: string = "em.lang.BoardChain_"
    const PROP_BOARD_KIND: string = "em.lang.BoardKind"

    type PinMap: Meta.PinMap
    type DrvDesc: Meta.DrvDesc
    type Record: Meta.Record

    function getKind(): string
    function readRecordH(): Record&

private:

    function cacheGet(kind: string): Record&
    function cacheSet(kind: string, rec: Record&)

    function collapse(kind: string, db: ptr_t, set: ptr_t): ptr_t

    function init()

    function mergeBrd(baseBrd: ptr_t, extBrd: ptr_t)
    function mergeDb(baseDb: ptr_t, extDb: ptr_t)

    config baseFileLoc: string
    config localFileLoc: string

    config attrs: string[]
    config pins: string[]

    config boardKind: string

    var initFlg: bool
    var recCache: ptr_t

end

def em$configure()
    readRecordH()
end

def cacheGet(kind)
    ^^if (!BoardInfo.recCache) BoardInfo.recCache = {}^^
    return ^^BoardInfo.recCache[kind]^^
end

def cacheSet(kind, rec)
    ^^BoardInfo.recCache[kind] = rec^^
end

def collapse(kind, db, set)
    return ^^db.$DEFAULTS^^ if ^^!kind || kind == '$DEFAULTS'^^
    var ext: ptr_t = ^^db[kind]^^
    if !ext
        printf "*** unknown board kind: '%s'\n", kind
        fail
    end
    if ^^set.has(kind)^^
        printf "*** circular inheritance chain: '%s'\n", kind
        fail
    end
    ^^set.add(kind)^^
    var base: ptr_t = collapse(^^ext.$inherits^^, db, set)
    mergeBrd(base, ext)
    return base
end

def getKind()
    init()
    return boardKind
end

def init()
    return if initFlg
    initFlg = true
    attrs = Meta.attrNames
    pins = Meta.pinNames
    baseFileLoc = Meta.baseFileLoc
    auto path = ^^$Path.join(em$session.getRootDir(), 'em-boards-local')^^
    localFileLoc = ^^$Fs.existsSync(path) ? path : null^^
    boardKind = ^^em$props.get^^(PROP_BOARD_KIND)
end

def mergeBrd(baseBrd, extBrd)
    ^^var aTab = []^^
    ^^for (a in extBrd) { aTab[a] = true; aTab.push(a) }^^
    for a in attrs
        ^^baseBrd[a] = extBrd[a]^^ if ^^a in extBrd^^
        ^^aTab[a] = false^^
    end
    for i: uint8 = 0; i < ^^aTab.length^^; i++
        var an: string = ^^aTab[i]^^
        if an != "pins" && an != "drvDescs" && an != "nvsFiles" && ^^aTab[an]^^
            printf "*** unknown attribute name: %s\n", an
            fail
        end
    end
    #
    ^^var pTab = []^^
    ^^for (p in extBrd.pins) { pTab[p] = true; pTab.push(p) }^^
    ^^baseBrd.pins = {}^^ if ^^!baseBrd.pins^^
    for p in pins
        ^^baseBrd.pins[p] = extBrd.pins[p]^^ if ^^extBrd.pins && p in extBrd.pins^^
        ^^pTab[p] = false^^
    end
    for i: uint8 = 0; i < ^^pTab.length^^; i++
        var pn: string = ^^pTab[i]^^
        continue if ^^pn[0] == '$'^^
        if ^^pTab[pn]^^
            printf "*** unknown pin name: %s\n", pn
            fail
        end
    end
    #
    ^^baseBrd.drvDescs = extBrd.drvDescs^^ if ^^extBrd.drvDescs^^
    ^^baseBrd.nvsFiles = extBrd.nvsFiles^^ if ^^extBrd.nvsFiles^^
end

def mergeDb(baseDb, extDb)
    ^^var brdSet = {}^^
    ^^var brdArr = []^^
    ^^for (b in baseDb) brdSet[b] = true^^
    ^^for (b in extDb) brdSet[b] = true^^
    ^^for (b in brdSet) brdArr.push(b)^^
    for i: uint8 = 0; i < ^^brdArr.length^^; i++
        ^^var brdKind = brdArr[i]^^
        ^^var baseBrd = baseDb[brdKind]^^
        ^^var extBrd = extDb[brdKind]^^
        if ^baseBrd && ^extBrd
            if ^^extBrd.$overrides^^
                mergeBrd(^baseBrd, ^extBrd)
            else
                printf "*** missing '$overrides' for %s\n", ^brdKind
                fail
            end
        elif ^extBrd
            if ^^extBrd.$overrides^^
                printf "*** no platform definition for '$overrides' for %s\n", ^brdKind
                fail
            else
                ^^baseDb[brdKind] = extDb[brdKind]^^
            end
        end
    end
end

def readRecordH()
    init()
    if boardKind == null
        printf "*** null board kind\n"
        fail
    end
    var rec: Record& = cacheGet(boardKind)
    return rec if rec
    var baseLoc: string = ^em$find(baseFileLoc)
    var baseDb: ptr_t = ^^$Yaml.load($Fs.readFileSync(baseLoc), 'utf-8')^^
    if localFileLoc != null
        var localDb: ptr_t = ^^$Yaml.load($Fs.readFileSync(localFileLoc), 'utf-8')^^
        mergeDb(baseDb, localDb)                    
    end
    var set: ptr_t = ^^new Set^^
    var base: ptr_t = collapse(boardKind, baseDb, set)
    var chain: ptr_t = ^^Array.from(set.values()).join('--')^^
    ^^em$props.set^^(PROP_BOARD_CHAIN, chain)
    rec = new <Record>
    rec.pinMap = new <PinMap>
    for a in attrs
        ^^rec[a] = base[a]^^
    end
    for p in pins
        ^^rec.pinMap[p] = base.pins[p]^^
    end
    ^^for (n in base.drvDescs) {^^
        ^^var o = base.drvDescs[n]^^
        rec.drvDescs[rec.drvDescs.length++] = new <DrvDesc> {
            name: ^n, driver: ^^o.driver^^, params: ^^o.params^^
        }
    ^^}^^
    cacheSet(boardKind, rec)
    return rec
end