internal/stm32CubeMX/mxDevice.go
/*
* Copyright (c) 2023-2024 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package stm32cubemx
import (
"bufio"
"errors"
"io/fs"
"math"
"os"
"path"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"time"
)
type PinDefinition struct {
p string
pin string
port string
mode string
pull string
speed string
alternate string
}
func ReadContexts(iocFile string, params []BridgeParamType) error {
contextMap, err := createContextMap(iocFile)
if err != nil {
return err
}
contexts, err := getContexts(contextMap)
if err != nil {
return err
}
workDir := path.Dir(iocFile)
mainFolder := contextMap["ProjectManager"]["MainLocation"]
if mainFolder == "" {
return errors.New("main location missing")
}
for _, context := range contexts {
for _, parm := range params {
if parm.CubeContext == context {
srcFolderPath := path.Join(path.Join(workDir, parm.CubeContextFolder), mainFolder)
var mspName string
err = filepath.Walk(srcFolderPath, func(path string, f fs.FileInfo, err error) error {
if f.Mode().IsRegular() && strings.HasSuffix(f.Name(), "_hal_msp.c") {
mspName = filepath.Base(path)
return nil
}
return nil
})
if err != nil {
return err
}
if mspName == "" {
return errors.New("*_hal_msp.c not found")
}
var cfgPath string
cfgPath = path.Dir(workDir)
cfgPath = path.Join(cfgPath, "MX_Device")
if parm.CubeContextFolder != "" {
cfgPath = path.Join(cfgPath, parm.CubeContextFolder)
}
err := writeMXdeviceH(contextMap, srcFolderPath, mspName, cfgPath, context)
if err != nil {
return err
}
break
}
}
}
return nil
}
func createContextMap(iocFile string) (map[string]map[string]string, error) {
contextMap := make(map[string]map[string]string)
var xMap map[string]string
fIoc, err := os.Open(iocFile)
if err != nil {
return nil, err
}
defer fIoc.Close()
iocScan := bufio.NewScanner(fIoc)
iocScan.Split(bufio.ScanLines)
for iocScan.Scan() {
split := strings.Split(iocScan.Text(), "=")
if len(split) > 1 {
leftParts := strings.Split(split[0], ".")
if len(leftParts) > 1 {
if contextMap[leftParts[0]] == nil {
xMap = make(map[string]string)
contextMap[leftParts[0]] = xMap
}
xMap[leftParts[1]] = split[1]
}
}
}
return contextMap, nil
}
func writeMXdeviceH(contextMap map[string]map[string]string, srcFolder string, mspName string, cfgPath string, context string) error {
srcFolderAbs, err := filepath.Abs(srcFolder)
if err != nil {
return err
}
main := path.Join(srcFolderAbs, "main.c")
main = filepath.Clean(main)
main = filepath.ToSlash(main)
fMain, err := os.Open(main)
if err != nil {
return err
}
defer fMain.Close()
msp := path.Join(srcFolderAbs, mspName)
msp = filepath.Clean(msp)
msp = filepath.ToSlash(msp)
fMsp, err := os.Open(msp)
if err != nil {
return err
}
defer fMsp.Close()
fName := "MX_Device.h"
fPath := filepath.Clean(cfgPath)
fPath = filepath.ToSlash(fPath)
if _, err := os.Stat(fPath); err != nil {
err = os.MkdirAll(fPath, 0750)
if err != nil {
return err
}
}
fPath = path.Join(fPath, fName)
fPath = filepath.Clean(fPath)
fPath = filepath.ToSlash(fPath)
fMxDevice, err := os.Create(fPath)
if err != nil {
return err
}
defer fMxDevice.Close()
out := bufio.NewWriter(fMxDevice)
defer out.Flush()
err = mxDeviceWriteHeader(out, fName)
if err != nil {
return err
}
peripherals, err := getPeripherals(contextMap, context)
if err != nil {
return err
}
sort.Strings(peripherals)
for _, peripheral := range peripherals {
vmode := getVirtualMode(contextMap, peripheral)
i2cInfo, err := getI2cInfo(fMain, peripheral)
if err != nil {
return err
}
usbHandle, err := getUSBHandle(fMain, peripheral)
if err != nil {
return err
}
mciMode, err := getMCIMode(fMain, peripheral)
if err != nil {
return err
}
freq := getI2CFreq(contextMap, peripheral)
if freq == "" {
freq = getMMCFreq(contextMap, peripheral)
}
if freq == "" {
freq = getSPIFreq(fMain, contextMap, peripheral)
}
pins, err := getPins(contextMap, fMsp, peripheral)
if err != nil {
return err
}
err = mxDeviceWritePeripheralCfg(out, peripheral, vmode, freq, i2cInfo, usbHandle, mciMode, pins)
if err != nil {
return err
}
}
_, err = out.WriteString("\n#endif /* MX_DEVICE_H__ */\n")
if err != nil {
return err
}
return nil
}
/*
func createPinConfigMap(mspName string) (map[string]PinDefinition, error) {
pinConfigMap := make(map[string]PinDefinition)
var instance string
fIoc, err := os.Open(mspName)
if err != nil {
return nil, err
}
defer fIoc.Close()
mspScan := bufio.NewScanner(fIoc)
mspScan.Split(bufio.ScanLines)
s := "->Instance=="
h := "HAL_GPIO_Init"
for mspScan.Scan() {
line := mspScan.Text()
if line == "}" { // end of function
instance = "" // reset instance
}
if len(instance) == 0 { // no instance yet
idx := strings.Index(line, s)
if idx != -1 {
inst := strings.Split(line[idx:], ")")[0]
if len(inst) > 0 {
instance = inst
}
}
} else { // there was an instance
idx := strings.Index(line, h)
if idx != -1 {
pinConfigMap[instance] = pinDef
}
}
}
return pinConfigMap, nil
}
*/
func getContexts(contextMap map[string]map[string]string) (map[int]string, error) {
contexts := make(map[int]string)
head := contextMap["Mcu"]
if len(head) > 0 {
for key, content := range head {
if strings.HasPrefix(key, "Context") {
l := len(key)
if l > 0 && key[l-1] >= '0' && key[l-1] <= '9' {
i, err := strconv.Atoi(string(key[l-1]))
if err != nil {
return nil, err
}
contexts[i] = content
}
}
}
}
if len(contexts) == 0 {
contexts[0] = ""
}
return contexts, nil
}
func getPeripherals(contextMap map[string]map[string]string, context string) ([]string, error) {
PERIPHERALS := [...]string{"USART", "UART", "LPUART", "SPI", "I2C", "ETH", "SDMMC", "CAN", "USB", "SDIO", "FDCAN"}
var peripherals []string
var contextIpsLine string
if len(context) > 0 {
contextIps, ok := contextMap[context]
if !ok {
return nil, errors.New("context not found in ioc")
}
contextIpsLine, ok = contextIps["IPs"]
if !ok {
return nil, errors.New("IPs not found in context")
}
}
mcu := contextMap["Mcu"]
if mcu != nil {
for ip, peri := range mcu {
if strings.HasPrefix(ip, "IP") {
if len(context) == 0 || strings.Contains(contextIpsLine, peri) {
for _, peripheral := range PERIPHERALS {
if strings.HasPrefix(peri, peripheral) {
peripherals = append(peripherals, peri)
break
}
}
}
}
}
} else {
return nil, errors.New("peripheral not found in Mcu")
}
return peripherals, nil
}
func getVirtualMode(contextMap map[string]map[string]string, peripheral string) string {
peri := contextMap[peripheral]
if len(peri) > 0 {
for vm, vmode := range peri {
if strings.HasPrefix(vm, "VirtualMode") {
return vmode
}
}
}
return ""
}
func getPins(contextMap map[string]map[string]string, fMsp *os.File, peripheral string) (map[string]PinDefinition, error) {
pinsName := make(map[string]string)
pinsLabel := make(map[string]string)
pinsInfo := make(map[string]PinDefinition)
for key, signal := range contextMap {
if !strings.HasPrefix(key, "VP") {
peri := signal["Signal"]
if strings.HasPrefix(peri, peripheral) {
pinsName[key] = peri
label, ok := signal["GPIO_Label"]
if ok {
label = strings.Split(label, "[")[0]
label = strings.TrimRight(label, " ")
label = replaceSpecialChars(label, "_")
pinsLabel[key] = strings.ReplaceAll(label, ".", "_")
}
}
}
}
for pin, name := range pinsName {
p := strings.Split(pin, "\\")[0]
p = strings.Split(p, "(")[0]
p = strings.Split(p, " ")[0]
p = strings.Split(p, "_")[0]
p = strings.Split(p, "-")[0]
label := pinsLabel[pin]
info, err := getPinConfiguration(fMsp, peripheral, p, label)
if err != nil {
return nil, err
}
if info.port != "" {
pinsInfo[name] = info
}
}
return pinsInfo, nil
}
func getDigitAtEnd(pin string) string {
re := regexp.MustCompile("[0-9]+$")
numbers := re.FindAllString(pin, -1)
if numbers != nil {
return numbers[0]
}
return ""
}
func replaceSpecialChars(label string, ch string) string {
specialCharacter := [...]string{"!", "@", "#", "$", "%", "^", "&", "*", "(", "+", "=", "-", "_", "[", "]", "{", "}",
";", ":", ",", ".", "?", "/", "\\", "|", "~", "`", "\"", "'", "<", ">", " "}
for _, spec := range specialCharacter {
label = strings.ReplaceAll(label, spec, ch)
}
return label
}
// Get i2c info (filter, coefficients)
func getI2cInfo(fMain *os.File, peripheral string) (map[string]string, error) {
info := make(map[string]string)
if strings.HasPrefix(peripheral, "I2C") {
_, err := fMain.Seek(0, 0)
if err != nil {
return nil, err
}
section := false
mainScan := bufio.NewScanner(fMain)
mainScan.Split(bufio.ScanLines)
for mainScan.Scan() {
line := mainScan.Text()
if !section {
if strings.HasPrefix(line, "static void MX_"+peripheral+"_Init") && !strings.Contains(line, ";") {
section = true // Start of section: static void MX_I2Cx_Init
}
} else { // Parse section: static void MX_I2Cx_Init
if strings.HasPrefix(line, "}") {
break // End of section: static void MX_I2Cx_Init
}
if strings.Contains(line, "HAL_I2CEx_ConfigAnalogFilter") {
if strings.Contains(line, "I2C_ANALOGFILTER_ENABLE") {
info["ANF_ENABLE"] = "1"
} else {
info["ANF_ENABLE"] = "0"
}
}
if strings.Contains(line, "HAL_I2CEx_ConfigDigitalFilter") {
dnf := strings.Split(strings.Split(line, ",")[1], ")")[0]
dnf = strings.TrimRight(strings.TrimLeft(dnf, "\t "), "\t ")
info["DNF"] = dnf
}
}
}
}
return info, nil
}
// Get USB Handle
func getUSBHandle(fMain *os.File, peripheral string) (string, error) {
if strings.HasPrefix(peripheral, "USB") {
_, err := fMain.Seek(0, 0)
if err != nil {
return "", err
}
mainScan := bufio.NewScanner(fMain)
mainScan.Split(bufio.ScanLines)
for mainScan.Scan() {
line := mainScan.Text()
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "PCD_HandleTypeDef") || strings.HasPrefix(line, "HCD_HandleTypeDef") {
line = strings.TrimSuffix(line, ";")
lineSplit := strings.Split(line, " ")
if len(lineSplit) < 2 {
continue
}
handle := lineSplit[1]
index := getDigitAtEnd(peripheral)
if index != "" {
if getDigitAtEnd(handle) != index {
continue
}
}
if strings.Contains(peripheral, "_HS") && !strings.Contains(handle, "_HS") {
continue
}
return handle, nil
}
}
}
return "", nil
}
// Get MCI Mode
func getMCIMode(fMain *os.File, peripheral string) (string, error) {
if strings.HasPrefix(peripheral, "SDMMC") || strings.HasPrefix(peripheral, "SDIO") {
_, err := fMain.Seek(0, 0)
if err != nil {
return "", err
}
mainScan := bufio.NewScanner(fMain)
mainScan.Split(bufio.ScanLines)
for mainScan.Scan() {
line := mainScan.Text()
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "MMC_HandleTypeDef") || strings.HasPrefix(line, "SD_HandleTypeDef") {
line = strings.TrimSuffix(line, ";")
lineSplit := strings.Split(line, " ")
if len(lineSplit) < 2 {
continue
}
handle := lineSplit[1]
index := getDigitAtEnd(peripheral)
if index != "" {
if getDigitAtEnd(handle) != index {
continue
}
}
mciMode := ""
if strings.HasPrefix(line, "MMC_HandleTypeDef") {
mciMode = "MMC"
}
if strings.HasPrefix(line, "SD_HandleTypeDef") {
mciMode = "SD"
}
return mciMode, nil
}
}
}
return "", nil
}
// Get MMC Freq
func getMMCFreq(contextMap map[string]map[string]string, peripheral string) string {
var freq string
if !strings.HasPrefix(peripheral, "SDMMC") && !strings.HasPrefix(peripheral, "SDIO") {
return ""
}
freq = getUserConstant(contextMap, peripheral+"_PERIPH_CLOCK_FREQ")
if freq != "" {
// Frequency defined by user in CubeMX
return freq
}
peri := contextMap["RCC"]
if len(peri) > 0 {
periphStrings := [2]string{peripheral, strings.TrimRight(peripheral, getDigitAtEnd(peripheral))}
for _, ps := range periphStrings {
for p, freq := range peri {
if strings.HasPrefix(p, ps) && strings.Contains(p, "Freq_Value") {
return freq
}
}
}
}
return ""
}
// Get I2C Freq
func getI2CFreq(contextMap map[string]map[string]string, peripheral string) string {
var freq string
if !strings.HasPrefix(peripheral, "I2C") {
return ""
}
freq = getUserConstant(contextMap, peripheral+"_PERIPH_CLOCK_FREQ")
if freq != "" {
// Frequency defined by user in CubeMX
return freq
}
peri := contextMap["RCC"]
if len(peri) > 0 {
for p, freq := range peri {
if strings.HasPrefix(p, "I2C") && strings.Contains(p, "Freq_Value") {
split := strings.Split(p, "I2C")[1]
pIdx := strings.Split(split, "Freq_Value")[0]
digit := getDigitAtEnd(peripheral)
if strings.Contains(pIdx, digit) {
return freq
}
}
}
}
return ""
}
// Get SPI Freq
func getSPIFreq(fMain *os.File, contextMap map[string]map[string]string, peripheral string) string {
var freq string
if !strings.HasPrefix(peripheral, "SPI") {
return ""
}
freq = getUserConstant(contextMap, peripheral+"_PERIPH_CLOCK_FREQ")
if freq != "" {
// Frequency defined by user in CubeMX
return freq
}
// Search for "RCC.I2C1Freq_Value" in ioc
peri := contextMap["RCC"]
if len(peri) > 0 {
for key, value := range peri {
if strings.HasPrefix(key, "SPI") && strings.Contains(key, "Freq_Value") {
split := strings.Split(key, "SPI")[1]
pIdx := strings.Split(split, "Freq_Value")[0]
digit := getDigitAtEnd(peripheral)
if strings.Contains(pIdx, digit) {
return value
}
}
}
}
// Search for "SPIx.CalculateBaudRate=" and "SPIx.CalculateBaudRate=" in ioc
calcBR := ""
prescaler := ""
peri = contextMap[peripheral]
if len(peri) > 0 {
for key, value := range peri {
if key == "CalculateBaudRate" {
calcBR = value
}
if key == "BaudRatePrescaler" {
prescaler = value
}
}
}
if calcBR == "" {
// CalculateBaudRate should beavailable in .ioc
return ""
}
if prescaler == "" {
// try to find prescaler in main.c
_, err := fMain.Seek(0, 0)
if err != nil {
return ""
}
section := false
mainScan := bufio.NewScanner(fMain)
mainScan.Split(bufio.ScanLines)
for mainScan.Scan() {
line := mainScan.Text()
if !section {
if strings.HasPrefix(line, "static void MX_"+peripheral+"_Init") && !strings.Contains(line, ";") {
section = true // Start of section: static void MX_SPIx_Init
}
} else { // Parse section: static void MX_SPIx_Init
if strings.HasPrefix(line, "}") {
break // End of section: static void MX_SPICx_Init
}
if strings.Contains(line, "BaudRatePrescaler") {
ps := strings.Split(line, "=")[1]
ps = strings.TrimSuffix(ps, ";")
ps = strings.Trim(ps, " ")
prescaler = ps
break
}
}
}
}
if prescaler != "" {
mul := 1
if strings.Contains(calcBR, "KBits") {
mul = 1000
}
if strings.Contains(calcBR, "MBits") {
mul = 1000000
}
calcBR = strings.Split(calcBR, " ")[0]
f, err := strconv.ParseFloat(calcBR, 32)
if err != nil {
return ""
}
br := f * float64(mul)
prescaler = strings.Split(prescaler, "SPI_BAUDRATEPRESCALER_")[1]
pr, err := strconv.Atoi(prescaler)
if err != nil {
return ""
}
freq = strconv.Itoa(int(math.Round(float64(pr) * br)))
}
return freq
}
func getUserConstant(contextMap map[string]map[string]string, constant string) string {
// Search for "Mcu.UserConstants" in ioc
peri := contextMap["Mcu"]
if len(peri) > 0 {
for key, value := range peri {
if key == "UserConstants" {
constants := strings.Split(value, ";")
for _, c := range constants {
split := strings.Split(c, ",")
if split[0] == constant {
return strings.Trim(split[1], " ")
}
}
}
}
}
return ""
}
func getPinConfiguration(fMsp *os.File, peripheral string, pin string, label string) (PinDefinition, error) {
var pinInfo PinDefinition
pinNum := getDigitAtEnd(pin)
gpioPin := "GPIO_PIN_" + pinNum
port := strings.Split(strings.Split(pin, "P")[1], pinNum)[0]
gpioPort := "GPIO" + port
section := false
_, err := fMsp.Seek(0, 0)
if err != nil {
return PinDefinition{}, err
}
mspScan := bufio.NewScanner(fMsp)
mspScan.Split(bufio.ScanLines)
s := "->Instance=="
h := "HAL_GPIO_Init"
addLine := false
value := ""
for mspScan.Scan() {
line := mspScan.Text()
if line == "}" { // end of function
section = false // reset instance
}
if strings.Contains(line, s) && strings.Contains(line, peripheral) {
section = true
}
if section {
if strings.Contains(line, h) {
if strings.Contains(line, gpioPort) || strings.Contains(line, label+"_GPIO_Port") {
values := strings.Split(pinInfo.pin, "|")
for _, val := range values {
val = strings.TrimRight(strings.TrimLeft(val, "\t "), "\t ")
if val == gpioPin || val == (label+"_Pin") {
pinInfo.p = pin
pinInfo.pin = gpioPin
pinInfo.port = gpioPort
return pinInfo, nil
}
}
}
}
if addLine {
value += strings.TrimLeft(line, " ")
if strings.Contains(value, ";") {
pinInfo.pin = strings.Split(value, ";")[0]
addLine = false
}
} else {
assign := strings.Split(line, "=")
if len(assign) > 1 {
left := assign[0]
value = strings.TrimLeft(assign[1], " ")
switch {
case strings.Contains(left, ".Pin"):
if strings.Contains(value, ";") {
pinInfo.pin = strings.Split(value, ";")[0]
} else {
addLine = true
}
case strings.Contains(left, ".Port"):
pinInfo.port = strings.Split(value, ";")[0]
case strings.Contains(left, ".Mode"):
pinInfo.mode = strings.Split(value, ";")[0]
case strings.Contains(left, ".Pull"):
pinInfo.pull = strings.Split(value, ";")[0]
case strings.Contains(left, ".Speed"):
pinInfo.speed = strings.Split(value, ";")[0]
case strings.Contains(left, ".Alternate"):
pinInfo.alternate = strings.Split(value, ";")[0]
}
}
}
}
}
return PinDefinition{}, nil
}
func mxDeviceWriteHeader(out *bufio.Writer, fName string) error {
now := time.Now()
dtString := now.Format("02/01/2006 15:04:05")
var err error
if _, err = out.WriteString("/******************************************************************************\n"); err != nil {
return err
}
if _, err = out.WriteString(" * File Name : " + fName + "\n"); err != nil {
return err
}
if _, err = out.WriteString(" * Date : " + dtString + "\n"); err != nil {
return err
}
if _, err = out.WriteString(" * Description : STM32Cube MX parameter definitions\n"); err != nil {
return err
}
if _, err = out.WriteString(" * Note : This file is generated with a generator out of the\n"); err != nil {
return err
}
if _, err = out.WriteString(" * STM32CubeMX project and its generated files (DO NOT EDIT!)\n"); err != nil {
return err
}
if _, err = out.WriteString(" ******************************************************************************/\n\n"); err != nil {
return err
}
if _, err = out.WriteString("#ifndef MX_DEVICE_H__\n"); err != nil {
return err
}
if _, err = out.WriteString("#define MX_DEVICE_H__\n\n"); err != nil {
return err
}
if _, err = out.WriteString("/* MX_Device.h version */\n"); err != nil {
return err
}
_, err = out.WriteString("#define MX_DEVICE_VERSION 0x01000000\n\n")
return err
}
func mxDeviceWritePeripheralCfg(out *bufio.Writer, peripheral string, vmode string, freq string, i2cInfo map[string]string, usbHandle string, mciMode string, pins map[string]PinDefinition) error {
var err error
str := "\n/*------------------------------ " + peripheral
if len(str) < 49 {
str += strings.Repeat(" ", 49-len(str))
}
str += "-----------------------------*/\n"
if _, err = out.WriteString(str); err != nil {
return err
}
if err = writeDefine(out, peripheral, "1\n"); err != nil {
return err
}
if len(i2cInfo) > 0 {
if _, err = out.WriteString("/* Filter Settings */\n"); err != nil {
return err
}
var i2cInfoItems []string
for item := range i2cInfo {
i2cInfoItems = append(i2cInfoItems, item)
}
sort.Strings(i2cInfoItems)
for _, item := range i2cInfoItems {
if err = writeDefine(out, peripheral+"_"+item, i2cInfo[item]); err != nil {
return err
}
}
if _, err = out.WriteString("\n"); err != nil {
return err
}
}
if usbHandle != "" {
if _, err = out.WriteString("/* Handle */\n"); err != nil {
return err
}
if err = writeDefine(out, peripheral+"_HANDLE", usbHandle); err != nil {
return err
}
if _, err = out.WriteString("\n"); err != nil {
return err
}
}
if mciMode != "" {
if _, err = out.WriteString("/* Mode */\n"); err != nil {
return err
}
if err = writeDefine(out, peripheral+"_MODE_"+mciMode, "1"); err != nil {
return err
}
if _, err = out.WriteString("\n"); err != nil {
return err
}
}
if vmode != "" {
if _, err = out.WriteString("/* Virtual mode */\n"); err != nil {
return err
}
if err = writeDefine(out, peripheral+"_VM", vmode); err != nil {
return err
}
if err = writeDefine(out, peripheral+"_"+vmode, "1"); err != nil {
return err
}
if _, err = out.WriteString("\n"); err != nil {
return err
}
}
if freq != "" {
if _, err = out.WriteString("/* Peripheral Clock Frequency */\n"); err != nil {
return err
}
if err = writeDefine(out, peripheral+"_PERIPH_CLOCK_FREQ", freq); err != nil {
return err
}
if _, err = out.WriteString("\n"); err != nil {
return err
}
}
if len(pins) != 0 {
if _, err = out.WriteString("/* Pins */\n"); err != nil {
return err
}
var pinNames []string
for pin := range pins {
pinNames = append(pinNames, pin)
}
sort.Strings(pinNames)
for pinName := range pinNames {
pin := pinNames[pinName]
pinDef := pins[pin]
if _, err = out.WriteString("\n/* " + pin + " */\n"); err != nil {
return err
}
if err = writeDefine(out, pin+"_Pin", pinDef.p); err != nil {
return err
}
if err = writeDefine(out, pin+"_GPIO_Pin", pinDef.pin); err != nil {
return err
}
if err = writeDefine(out, pin+"_GPIOx", pinDef.port); err != nil {
return err
}
if err = writeDefine(out, pin+"_GPIO_Mode", pinDef.mode); err != nil {
return err
}
if err = writeDefine(out, pin+"_GPIO_PuPd", pinDef.pull); err != nil {
return err
}
if err = writeDefine(out, pin+"_GPIO_Speed", pinDef.speed); err != nil {
return err
}
if err = writeDefine(out, pin+"_GPIO_AF", pinDef.alternate); err != nil {
return err
}
}
}
return nil
}
func writeDefine(out *bufio.Writer, name string, value string) error {
invalidChars := [...]string{"=", " ", "/", "(", ")", "[", "]", "\\", "-"}
if len(value) == 0 {
return nil
}
for _, ch := range invalidChars {
name = strings.ReplaceAll(name, ch, "_")
value = strings.ReplaceAll(value, ch, "_")
}
name = "MX_" + name
if len(name) < 40 {
name += strings.Repeat(" ", 40-len(name))
}
_, err := out.WriteString("#define " + name + value + "\n")
return err
}