This is an automated email from the ASF dual-hosted git repository. ccollins pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git
commit 3fd440474030cbd633d57e3649279939da4fdc01 Author: Christopher Collins <ccoll...@apache.org> AuthorDate: Tue Nov 20 17:51:46 2018 -0800 Add `flashmap` package This is a thin package implemented on top of the artifact library's `flash` pacakge. --- newt/flashmap/flashmap.go | 353 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 353 insertions(+) diff --git a/newt/flashmap/flashmap.go b/newt/flashmap/flashmap.go new file mode 100644 index 0000000..68fa699 --- /dev/null +++ b/newt/flashmap/flashmap.go @@ -0,0 +1,353 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package flashmap + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "sort" + "strings" + + log "github.com/Sirupsen/logrus" + "github.com/spf13/cast" + + "mynewt.apache.org/newt/artifact/flash" + "mynewt.apache.org/newt/newt/newtutil" + "mynewt.apache.org/newt/util" +) + +const HEADER_PATH = "sysflash/sysflash.h" +const C_VAR_NAME = "sysflash_map_dflt" +const C_VAR_COMMENT = `/** + * This flash map definition is used for two purposes: + * 1. To locate the meta area, which contains the true flash map definition. + * 2. As a fallback in case the meta area cannot be read from flash. + */ +` + +type FlashMap struct { + Areas map[string]flash.FlashArea + Overlaps [][]flash.FlashArea + IdConflicts [][]flash.FlashArea +} + +func newFlashMap() FlashMap { + return FlashMap{ + Areas: map[string]flash.FlashArea{}, + Overlaps: [][]flash.FlashArea{}, + } +} + +func flashAreaErr(areaName string, format string, args ...interface{}) error { + return util.NewNewtError( + "failure while parsing flash area \"" + areaName + "\": " + + fmt.Sprintf(format, args...)) +} + +func parseSize(val string) (int, error) { + lower := strings.ToLower(val) + + multiplier := 1 + if strings.HasSuffix(lower, "kb") { + multiplier = 1024 + lower = strings.TrimSuffix(lower, "kb") + } + + num, err := util.AtoiNoOct(lower) + if err != nil { + return 0, err + } + + return num * multiplier, nil +} + +func parseFlashArea( + name string, ymlFields map[string]interface{}) (flash.FlashArea, error) { + + area := flash.FlashArea{ + Name: name, + } + + idPresent := false + devicePresent := false + offsetPresent := false + sizePresent := false + + var isSystem bool + area.Id, isSystem = flash.SYSTEM_AREA_NAME_ID_MAP[name] + + var err error + + fields := cast.ToStringMapString(ymlFields) + for k, v := range fields { + switch k { + case "user_id": + if isSystem { + return area, flashAreaErr(name, + "system areas cannot specify a user ID") + } + userId, err := util.AtoiNoOct(v) + if err != nil { + return area, flashAreaErr(name, "invalid user id: %s", v) + } + area.Id = userId + flash.AREA_USER_ID_MIN + idPresent = true + + case "device": + area.Device, err = util.AtoiNoOct(v) + if err != nil { + return area, flashAreaErr(name, "invalid device: %s", v) + } + devicePresent = true + + case "offset": + area.Offset, err = util.AtoiNoOct(v) + if err != nil { + return area, flashAreaErr(name, "invalid offset: %s", v) + } + offsetPresent = true + + case "size": + area.Size, err = parseSize(v) + if err != nil { + return area, flashAreaErr(name, err.Error()) + } + sizePresent = true + + default: + util.StatusMessage(util.VERBOSITY_QUIET, + "Warning: flash area \"%s\" contains unrecognized field: %s", + name, k) + } + } + + if !isSystem && !idPresent { + return area, flashAreaErr(name, "required field \"user_id\" missing") + } + if !devicePresent { + return area, flashAreaErr(name, "required field \"device\" missing") + } + if !offsetPresent { + return area, flashAreaErr(name, "required field \"offset\" missing") + } + if !sizePresent { + return area, flashAreaErr(name, "required field \"size\" missing") + } + + return area, nil +} + +func (flashMap FlashMap) unSortedAreas() []flash.FlashArea { + areas := make([]flash.FlashArea, 0, len(flashMap.Areas)) + for _, area := range flashMap.Areas { + areas = append(areas, area) + } + + return areas +} + +func (flashMap FlashMap) SortedAreas() []flash.FlashArea { + areas := flashMap.unSortedAreas() + return flash.SortFlashAreasById(areas) +} + +func (flashMap FlashMap) DeviceIds() []int { + deviceMap := map[int]struct{}{} + + for _, area := range flashMap.Areas { + deviceMap[area.Device] = struct{}{} + } + + devices := make([]int, 0, len(deviceMap)) + for device, _ := range deviceMap { + devices = append(devices, device) + } + sort.Ints(devices) + + return devices +} + +func areasDistinct(a flash.FlashArea, b flash.FlashArea) bool { + var lo flash.FlashArea + var hi flash.FlashArea + + if a.Offset < b.Offset { + lo = a + hi = b + } else { + lo = b + hi = a + } + + return lo.Device != hi.Device || lo.Offset+lo.Size <= hi.Offset +} + +func (flashMap *FlashMap) detectOverlaps() { + flashMap.Overlaps, flashMap.IdConflicts = + flash.DetectErrors(flashMap.unSortedAreas()) +} + +func (flashMap FlashMap) ErrorText() string { + return flash.ErrorText(flashMap.Overlaps, flashMap.IdConflicts) +} + +func Read(ymlFlashMap map[string]interface{}) (FlashMap, error) { + flashMap := newFlashMap() + + ymlAreas := ymlFlashMap["areas"] + if ymlAreas == nil { + return flashMap, util.NewNewtError( + "\"areas\" mapping missing from flash map definition") + } + + areaMap := cast.ToStringMap(ymlAreas) + for k, v := range areaMap { + if _, ok := flashMap.Areas[k]; ok { + return flashMap, flashAreaErr(k, "name conflict") + } + + ymlArea := cast.ToStringMap(v) + area, err := parseFlashArea(k, ymlArea) + if err != nil { + return flashMap, flashAreaErr(k, err.Error()) + } + + flashMap.Areas[k] = area + } + + flashMap.detectOverlaps() + + return flashMap, nil +} + +func flashMapVarDecl(fm FlashMap) string { + return fmt.Sprintf("const struct flash_area %s[%d]", C_VAR_NAME, + len(fm.Areas)) +} + +func writeFlashAreaHeader(w io.Writer, area flash.FlashArea) { + fmt.Fprintf(w, "#define %-40s %d\n", area.Name, area.Id) +} + +func writeFlashMapHeader(w io.Writer, fm FlashMap) { + fmt.Fprintf(w, newtutil.GeneratedPreamble()) + + fmt.Fprintf(w, "#ifndef H_MYNEWT_SYSFLASH_\n") + fmt.Fprintf(w, "#define H_MYNEWT_SYSFLASH_\n") + fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "#include \"flash_map/flash_map.h\"\n") + fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "%s", C_VAR_COMMENT) + fmt.Fprintf(w, "extern %s;\n", flashMapVarDecl(fm)) + fmt.Fprintf(w, "\n") + + for _, area := range fm.SortedAreas() { + writeFlashAreaHeader(w, area) + } + + fmt.Fprintf(w, "\n#endif\n") +} + +func sizeComment(size int) string { + if size%1024 != 0 { + return "" + } + + return fmt.Sprintf(" /* %d kB */", size/1024) +} + +func writeFlashAreaSrc(w io.Writer, area flash.FlashArea) { + fmt.Fprintf(w, " /* %s */\n", area.Name) + fmt.Fprintf(w, " {\n") + fmt.Fprintf(w, " .fa_id = %d,\n", area.Id) + fmt.Fprintf(w, " .fa_device_id = %d,\n", area.Device) + fmt.Fprintf(w, " .fa_off = 0x%08x,\n", area.Offset) + fmt.Fprintf(w, " .fa_size = %d,%s\n", area.Size, + sizeComment(area.Size)) + fmt.Fprintf(w, " },\n") +} + +func writeFlashMapSrc(w io.Writer, fm FlashMap) { + fmt.Fprintf(w, newtutil.GeneratedPreamble()) + + fmt.Fprintf(w, "#include \"%s\"\n", HEADER_PATH) + fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "%s", C_VAR_COMMENT) + fmt.Fprintf(w, "%s = {", flashMapVarDecl(fm)) + + for _, area := range fm.SortedAreas() { + fmt.Fprintf(w, "\n") + writeFlashAreaSrc(w, area) + } + + fmt.Fprintf(w, "};\n") +} + +func ensureFlashMapWrittenGen(path string, contents []byte) error { + writeReqd, err := util.FileContentsChanged(path, contents) + if err != nil { + return err + } + if !writeReqd { + log.Debugf("flash map unchanged; not writing file (%s).", path) + return nil + } + + log.Debugf("flash map changed; writing file (%s).", path) + + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return util.NewNewtError(err.Error()) + } + + if err := ioutil.WriteFile(path, contents, 0644); err != nil { + return util.NewNewtError(err.Error()) + } + + return nil +} + +func EnsureFlashMapWritten( + fm FlashMap, + srcDir string, + includeDir string, + targetName string) error { + + buf := bytes.Buffer{} + writeFlashMapSrc(&buf, fm) + if err := ensureFlashMapWrittenGen( + fmt.Sprintf("%s/%s-sysflash.c", srcDir, targetName), + buf.Bytes()); err != nil { + + return err + } + + buf = bytes.Buffer{} + writeFlashMapHeader(&buf, fm) + if err := ensureFlashMapWrittenGen( + includeDir+"/"+HEADER_PATH, buf.Bytes()); err != nil { + return err + } + + return nil +}