package proto import ( "bytes" "encoding/json" "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"` } 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"` } 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 { CenumPCTOESP Cenum CenumESPTOPC Cenum PayloadStructs []PayloadStruct MessagesPCtoESP []ProtoMessage MessagesESPtoPC []ProtoMessage } var tmpl *template.Template func InitTemplates() { funcs := template.FuncMap{ "snake": toSnakeCase, "isLast": isLast, } Ntmpl, err := template.New("all").Funcs(funcs).ParseGlob("templates/*.tmpl") 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{ 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{ 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 }