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
+}

Reply via email to