tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/p1am/internal/cmd/gen_defines/main.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "go/format" 6 "io/ioutil" 7 "log" 8 "os" 9 "path/filepath" 10 "regexp" 11 "strings" 12 "text/template" 13 ) 14 15 var tmpl = template.Must(template.New("main").Parse(`package p1am 16 17 //go:generate go run ./internal/cmd/gen_defines 18 19 type ModuleProps struct { 20 ModuleID uint32 21 DI, DO, AI, AO, Status, Config, DataSize byte 22 Name string 23 } 24 25 var modules = []ModuleProps{ 26 {{.MDB -}} 27 } 28 29 var defaultConfig = map[uint32][]byte{ 30 {{range .Configs -}} 31 0x{{.ID}}: // {{.Name}} 32 {{index $.DefaultConfigs .Name}}, 33 {{end}} 34 } 35 36 {{range .Defines}} 37 const {{.Name}} = {{.Value}}{{.Comment -}} 38 {{end}} 39 `)) 40 41 func findLibrary() string { 42 home, err := os.UserHomeDir() 43 if err != nil { 44 log.Fatal(err) 45 } 46 for _, dir := range []string{ 47 "Documents/Arduino", 48 "Arduino", 49 } { 50 dir = filepath.Join(home, dir, "libraries/P1AM/src") 51 if _, err := os.Stat(dir); err == nil { 52 return dir 53 } 54 } 55 return "" 56 } 57 58 func definitions(path string, delim string) []string { 59 data, err := ioutil.ReadFile(path) 60 if err != nil { 61 log.Fatal(err) 62 } 63 return strings.Split(string(data), delim) 64 } 65 66 var ( 67 mdbRE = regexp.MustCompile(`(?s)mdb\[\] = \{\s*(.+)\}`) 68 configRE = regexp.MustCompile(`(?s)const char (.*?)\[\] = (.+)`) 69 caseRE = regexp.MustCompile(`(?s)case 0x([^:]+):\s+return \(char\*\)(.+)`) 70 defineRE = regexp.MustCompile(`(?ms)^\s*#define (\S+)\s+(\d+|0x[0-9a-fA-F]+)(\s+.*?)?\s*$`) 71 ) 72 73 func main() { 74 base := findLibrary() 75 if base == "" { 76 log.Fatal("can't find Arduino library") 77 } 78 var data = struct { 79 MDB string 80 DefaultConfigs map[string]string 81 Configs []struct { 82 ID string 83 Name string 84 } 85 Defines []struct { 86 Name string 87 Value string 88 Comment string 89 } 90 }{ 91 DefaultConfigs: make(map[string]string), 92 } 93 for _, line := range definitions(filepath.Join(base, "Module_List.h"), ";") { 94 if matches := mdbRE.FindStringSubmatch(line); matches != nil { 95 data.MDB = regexp.MustCompile(`}\s*//`).ReplaceAllString(matches[1], `}, //`) 96 } 97 if matches := configRE.FindStringSubmatch(line); matches != nil { 98 data.DefaultConfigs[matches[1]] = matches[2] 99 } 100 } 101 102 for _, line := range definitions(filepath.Join(base, "P1AM.cpp"), ";") { 103 if matches := caseRE.FindStringSubmatch(line); matches != nil { 104 data.Configs = append(data.Configs, struct{ ID, Name string }{ 105 ID: matches[1], 106 Name: matches[2], 107 }) 108 } 109 } 110 111 for _, line := range definitions(filepath.Join(base, "defines.h"), "\n") { 112 if matches := defineRE.FindStringSubmatch(line); matches != nil { 113 data.Defines = append(data.Defines, struct{ Name, Value, Comment string }{ 114 Name: matches[1], 115 Value: matches[2], 116 Comment: matches[3], 117 }) 118 } 119 } 120 121 var buf bytes.Buffer 122 if err := tmpl.Execute(&buf, &data); err != nil { 123 log.Fatal(err) 124 } 125 formatted, err := format.Source(buf.Bytes()) 126 if err != nil { 127 log.Printf("failed to compile %s", buf.Bytes()) 128 log.Fatal(err) 129 } 130 if err := ioutil.WriteFile("defines.go", formatted, 0666); err != nil { 131 log.Fatal(err) 132 } 133 }