protgen/proto/proto.go
simon 41437f0f2f
All checks were successful
Build / Build (push) Successful in 1m26s
Embedded the Templates in the go binary
2025-05-19 21:46:38 +02:00

197 lines
4.1 KiB
Go

package proto
import (
"bytes"
"encoding/json"
"io/fs"
"log"
"strconv"
"text/template"
"unicode"
)
type HexByte byte
type ProtocolHeader struct {
StartByte HexByte `json:"start_byte"`
MessageLength int `json:"message_length"`
MaxPayload int `json:"max_payload"`
Checksum string `json:"checksum"`
}
type ProtoMessage struct {
Name string `json:"name"`
ID HexByte `json:"id"`
Payload []ProtoMessagePayload `json:"payload,omitempty"` // optional falls kein payload
}
type ProtoMessagePayload struct {
Name string `json:"name"`
DataType string `json:"type"`
ArrayLength int `json:"array,omitempty"` // optional falls kein array
}
type Proto struct {
ProtocolHeader ProtocolHeader `json:"protocol"`
ESP_TO_PC []ProtoMessage `json:"messages_esp_to_pc"`
PC_TO_ESP []ProtoMessage `json:"messages_pc_to_esp"`
FileName string `json:"filename,omitempty"`
}
func (h *HexByte) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil { // turn into go string
return err
}
i, err := strconv.ParseUint(s, 0, 8)
if err != nil {
return err
}
*h = HexByte(i)
return nil
}
type Cenum struct {
EnumName string
Entries []ProtoMessage
}
type PayloadStruct struct {
Name string
Entries []ProtoMessagePayload
}
type CStyleData struct {
FileName string
CenumPCTOESP Cenum
CenumESPTOPC Cenum
PayloadStructs []PayloadStruct
MessagesPCtoESP []ProtoMessage
MessagesESPtoPC []ProtoMessage
}
var tmpl *template.Template
func InitTemplates(fsys fs.FS, pattern string) {
funcs := template.FuncMap{
"snake": toSnakeCase,
"isLast": isLast,
}
Ntmpl, err := template.New("all").Funcs(funcs).ParseFS(fsys, pattern)
if err != nil {
log.Fatalf("failed to parse templates: %v", err)
}
tmpl = Ntmpl
}
func CreateCStyleHeader(proto *Proto) (string, error) {
payloads := []PayloadStruct{}
for _, payload := range proto.PC_TO_ESP {
tmp := PayloadStruct{
Name: payload.Name,
Entries: payload.Payload,
}
payloads = append(payloads, tmp)
}
for _, payload := range proto.ESP_TO_PC {
tmp := PayloadStruct{
Name: payload.Name,
Entries: payload.Payload,
}
payloads = append(payloads, tmp)
}
var data = CStyleData{
FileName: proto.FileName,
CenumPCTOESP: Cenum{
EnumName: "PC_TO_ESP_MESSAGE_IDS",
Entries: proto.PC_TO_ESP,
},
CenumESPTOPC: Cenum{
EnumName: "ESP_TO_PC_MESSAGE_IDS",
Entries: proto.ESP_TO_PC,
},
PayloadStructs: payloads,
MessagesPCtoESP: proto.PC_TO_ESP,
MessagesESPtoPC: proto.ESP_TO_PC,
}
var buf bytes.Buffer
err := tmpl.ExecuteTemplate(&buf, "cpartHeader", data)
if err != nil {
log.Printf("Error Rendering template: %v", err)
}
return buf.String(), nil
}
func CreateCStyleSource(proto *Proto) (string, error) {
payloads := []PayloadStruct{}
for _, payload := range proto.PC_TO_ESP {
tmp := PayloadStruct{
Name: payload.Name,
Entries: payload.Payload,
}
payloads = append(payloads, tmp)
}
for _, payload := range proto.ESP_TO_PC {
tmp := PayloadStruct{
Name: payload.Name,
Entries: payload.Payload,
}
payloads = append(payloads, tmp)
}
var data = CStyleData{
FileName: proto.FileName,
CenumPCTOESP: Cenum{
EnumName: "PC_TO_ESP_MESSAGE_IDS",
Entries: proto.PC_TO_ESP,
},
CenumESPTOPC: Cenum{
EnumName: "ESP_TO_PC_MESSAGE_IDS",
Entries: proto.ESP_TO_PC,
},
PayloadStructs: payloads,
MessagesPCtoESP: proto.PC_TO_ESP,
MessagesESPtoPC: proto.ESP_TO_PC,
}
var buf bytes.Buffer
err := tmpl.ExecuteTemplate(&buf, "cpartSource", data)
if err != nil {
log.Printf("Error Rendering template: %v", err)
}
return buf.String(), nil
}
func toSnakeCase(str string) string {
var out []rune
for i, r := range str {
if unicode.IsUpper(r) {
if i != 0 {
out = append(out, '_')
}
out = append(out, unicode.ToLower(r))
} else {
out = append(out, r)
}
}
return string(out)
}
// just a helper function, pass the length of your array and your current index
func isLast(datalen int, index int) bool {
return index == datalen-1
}