Compare commits

..

6 Commits

13 changed files with 775 additions and 38 deletions

View File

@ -20,6 +20,12 @@ buildIdf:
flashMini: flashMini:
idf.py flash -p /dev/ttyACM0 idf.py flash -p /dev/ttyACM0
flashMini2:
idf.py flash -p /dev/ttyACM1
flashMini3:
idf.py flash -p /dev/ttyACM2
monitorMini: monitorMini:
idf.py monitor -p /dev/ttyACM0 idf.py monitor -p /dev/ttyACM0

24
goTool/go.mod Normal file
View File

@ -0,0 +1,24 @@
module alox.tool
go 1.24.5
require (
github.com/pterm/pterm v0.12.81
go.bug.st/serial v1.6.4
)
require (
atomicgo.dev/cursor v0.2.0 // indirect
atomicgo.dev/keyboard v0.2.9 // indirect
atomicgo.dev/schedule v0.1.0 // indirect
github.com/containerd/console v1.0.5 // indirect
github.com/creack/goselect v0.1.2 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.26.0 // indirect
)

124
goTool/go.sum Normal file
View File

@ -0,0 +1,124 @@
atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg=
atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ=
atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw=
atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU=
atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8=
atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ=
atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs=
atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU=
github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs=
github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8=
github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII=
github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k=
github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI=
github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c=
github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE=
github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4=
github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY=
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI=
github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg=
github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE=
github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU=
github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE=
github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8=
github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s=
github.com/pterm/pterm v0.12.81 h1:ju+j5I2++FO1jBKMmscgh5h5DPFDFMB7epEjSoKehKA=
github.com/pterm/pterm v0.12.81/go.mod h1:TyuyrPjnxfwP+ccJdBTeWHtd/e0ybQHkOS/TakajZCw=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A=
go.bug.st/serial v1.6.4/go.mod h1:nofMJxTeNVny/m6+KaafC6vJGj3miwQZ6vW4BZUGJPI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

318
goTool/main.go Normal file
View File

@ -0,0 +1,318 @@
package main
import (
"context"
"encoding/binary"
"fmt"
"log"
"github.com/pterm/pterm"
"go.bug.st/serial"
)
type ParserState int
const (
WAITING_FOR_START_BYTE ParserState = iota
ESCAPED_MESSAGE_ID
GET_MESSAGE_ID
IN_PAYLOD
ESCAPED_PAYLOAD_BYTE
)
const (
START_BYTE = 0xAA
ESCAPE_BYTE = 0xBB
END_BYTE = 0xCC
)
type ParseError int
const (
WRONG_CHECKSUM ParseError = iota
UNEXPECETD_BYTE
)
type MessageReceive struct {
raw_message []byte
parsed_message []byte
checksum byte
error ParseError
state ParserState
write_index int
raw_write_index int
}
func initMessageReceive(mr *MessageReceive) {
mr.raw_message = make([]byte, 1024*4)
mr.parsed_message = make([]byte, 1024*4)
mr.checksum = 0
mr.error = 0
mr.write_index = 0
mr.raw_write_index = 0
mr.state = WAITING_FOR_START_BYTE
}
func addByteToRawBuffer(mr *MessageReceive, pbyte byte) {
mr.raw_message[mr.raw_write_index] = pbyte
mr.raw_write_index += 1
}
func addByteToParsedBuffer(mr *MessageReceive, pbyte byte) {
mr.parsed_message[mr.write_index] = pbyte
mr.write_index += 1
mr.checksum ^= pbyte
}
func parse_03_payload(payloadBuffer []byte, payload_len int) {
type payload_data struct {
ClientID uint8
IsAvailable uint8
SlotIsUsed uint8
MACAddr [6]uint8
LastPing uint32
LastSuccessfulPing uint32
Version uint16
}
tableHeaders := pterm.TableData{
{"Client ID", "Verfügbar", "Genutzt", "MAC-Adresse", "Last Ping", "Letzter Erfolg Ping", "Version"},
}
tableData := tableHeaders
currentOffset := 2
const (
ENTRY_LEN = 19
OFFSET_MAC_ADDR = 3
OFFSET_LAST_PING = 9
OFFSET_LAST_SUCCESS_PING = 13
OFFSET_VERSION = 17
)
for i := 0; i < int(payloadBuffer[1]); i++ {
if currentOffset+ENTRY_LEN > payload_len {
fmt.Printf("Fehler: Payload zu kurz für Client-Eintrag %d\n", i)
break
}
entryBytes := payloadBuffer[currentOffset : currentOffset+ENTRY_LEN]
var clientData payload_data
clientData.ClientID = entryBytes[0]
clientData.IsAvailable = entryBytes[1]
clientData.SlotIsUsed = entryBytes[2]
copy(clientData.MACAddr[:], entryBytes[OFFSET_MAC_ADDR:OFFSET_MAC_ADDR+6])
clientData.LastPing = binary.LittleEndian.Uint32(entryBytes[OFFSET_LAST_PING : OFFSET_LAST_PING+4])
clientData.LastSuccessfulPing = binary.LittleEndian.Uint32(entryBytes[OFFSET_LAST_SUCCESS_PING : OFFSET_LAST_SUCCESS_PING+4])
clientData.Version = binary.LittleEndian.Uint16(entryBytes[OFFSET_VERSION : OFFSET_VERSION+2])
// Füge die geparsten Daten als String-Slice zur Tabelle hinzu
tableData = append(tableData, []string{
fmt.Sprintf("%d", clientData.ClientID),
fmt.Sprintf("%d", clientData.IsAvailable),
fmt.Sprintf("%d", clientData.SlotIsUsed),
fmt.Sprintf("%X:%X:%X:%X:%X:%X",
clientData.MACAddr[0], clientData.MACAddr[1], clientData.MACAddr[2],
clientData.MACAddr[3], clientData.MACAddr[4], clientData.MACAddr[5]),
fmt.Sprintf("%d", clientData.LastPing),
fmt.Sprintf("%d", clientData.LastSuccessfulPing),
fmt.Sprintf("%d", clientData.Version),
})
currentOffset += ENTRY_LEN
}
err := pterm.DefaultTable.WithHasHeader().WithBoxed().WithData(tableData).Render()
if err != nil {
fmt.Printf("Fehler beim Rendern der Tabelle: %s\n", err)
}
}
func message_receive_callback(mr MessageReceive) {
log.Printf("Message Received: % 02X\n", mr.raw_message[:mr.raw_write_index])
switch mr.parsed_message[0] {
case 0x01:
break
case 0x02:
break
case 0x03:
parse_03_payload(mr.parsed_message, mr.write_index)
break
}
}
func message_receive_failed_callback(mr MessageReceive) {
log.Printf("Error Message Received: % 02X\n", mr.raw_message[:mr.raw_write_index])
}
func parseByte(mr *MessageReceive, pbyte byte) {
addByteToRawBuffer(mr, pbyte)
switch mr.state {
case WAITING_FOR_START_BYTE:
if pbyte == START_BYTE {
initMessageReceive(mr)
mr.state = GET_MESSAGE_ID
addByteToRawBuffer(mr, pbyte)
}
// ignore every other byte
break
case GET_MESSAGE_ID:
if pbyte == ESCAPE_BYTE {
mr.state = ESCAPED_MESSAGE_ID
} else {
addByteToParsedBuffer(mr, pbyte)
mr.state = IN_PAYLOD
}
break
case ESCAPED_MESSAGE_ID:
addByteToParsedBuffer(mr, pbyte)
mr.state = IN_PAYLOD
break
case IN_PAYLOD:
if pbyte == ESCAPE_BYTE {
mr.state = ESCAPED_PAYLOAD_BYTE
break
}
if pbyte == START_BYTE {
mr.error = UNEXPECETD_BYTE
message_receive_failed_callback(*mr)
initMessageReceive(mr)
return
}
if pbyte == END_BYTE {
if mr.checksum != 0 { // checksum wrong
mr.error = WRONG_CHECKSUM
message_receive_failed_callback(*mr)
initMessageReceive(mr)
return
}
message_receive_callback(*mr)
initMessageReceive(mr)
break
}
// normal case
addByteToParsedBuffer(mr, pbyte)
break
case ESCAPED_PAYLOAD_BYTE:
addByteToParsedBuffer(mr, pbyte)
mr.state = IN_PAYLOD
break
default:
panic(fmt.Sprintf("unexpected main.ParserState: %#v", mr.state))
}
}
func buildMessage(payloadBuffer []byte, payload_len int, sendBuffer []byte) int {
var writeIndex int
checksum := byte(0x00)
writeIndex = 0
sendBuffer[writeIndex] = START_BYTE
writeIndex++
for i := range payload_len {
b := payloadBuffer[i]
if b == START_BYTE || b == ESCAPE_BYTE || b == END_BYTE {
sendBuffer[writeIndex] = ESCAPE_BYTE
writeIndex++
}
sendBuffer[writeIndex] = b
writeIndex++
checksum ^= b
}
sendBuffer[writeIndex] = checksum
writeIndex++
sendBuffer[writeIndex] = END_BYTE
writeIndex++
return writeIndex
}
func sendMessage(port serial.Port, sendBuffer []byte) {
n, err := port.Write(sendBuffer)
if err != nil {
log.Printf("Could not Send %v to Serial Port", sendBuffer)
}
if n < len(sendBuffer) {
log.Printf("Did not send all data %v, only send %v", len(sendBuffer), n)
}
fmt.Printf("Send Message % 02X\n", sendBuffer[:n])
}
func main() {
mode := &serial.Mode{
BaudRate: 115200,
}
port, err := serial.Open("/dev/ttyUSB0", mode)
if err != nil {
log.Fatal(err)
}
ctx, cancle := context.WithCancel(context.Background())
defer cancle()
go func() {
buff := make([]byte, 1024)
mr := MessageReceive{}
initMessageReceive(&mr)
for {
select {
case <-ctx.Done():
return
default:
n, err := port.Read(buff)
if err != nil {
log.Print(err)
break
}
if n == 0 {
fmt.Println("\nEOF")
break
}
for _, b := range buff[:n] {
parseByte(&mr, b)
}
//fmt.Printf("Empfangen: % 02X\n", string(buff[:n]))
break
}
}
}()
for {
var input string
_, err := fmt.Scanln(&input)
if err != nil {
log.Fatalf("Could not read from stdin")
}
fmt.Printf("Input %v", input)
switch input {
case "q":
return
case "1":
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = 0x01
n := buildMessage(payload_buffer, 1, send_buffer)
sendMessage(port, send_buffer[:n])
break
case "2":
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = 0x02
n := buildMessage(payload_buffer, 1, send_buffer)
sendMessage(port, send_buffer[:n])
break
case "3":
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = 0x03
n := buildMessage(payload_buffer, 1, send_buffer)
sendMessage(port, send_buffer[:n])
break
default:
fmt.Printf("Not a valid input")
}
}
}

View File

@ -1,4 +1,4 @@
idf_component_register(SRCS "main.c" "uart_handler.c" "communication_handler.c" "client_handler.c" "message_parser.c" "message_builder.c" "message_handler.c" idf_component_register(SRCS "main.c" "uart_handler.c" "communication_handler.c" "client_handler.c" "message_parser.c" "message_builder.c" "message_handler.c" "ota_update.c"
INCLUDE_DIRS ".") INCLUDE_DIRS ".")
# Get the short Git commit hash of the current HEAD. # Get the short Git commit hash of the current HEAD.

View File

@ -28,6 +28,7 @@ typedef struct {
uint8_t macAddr[MAC_LENGTH]; uint8_t macAddr[MAC_LENGTH];
TickType_t lastSuccessfullPing; TickType_t lastSuccessfullPing;
TickType_t lastPing; TickType_t lastPing;
uint16_t clientVersion;
} ClientInfo; } ClientInfo;
typedef struct { typedef struct {

View File

@ -12,26 +12,29 @@
static const char *TAG = "ALOX - COM"; static const char *TAG = "ALOX - COM";
QueueHandle_t messageQueue = NULL; // Warteschlange für empfangene Nachrichten QueueHandle_t messageQueue = NULL; // Warteschlange für empfangene Nachrichten
bool hasMaster = false; static bool hasMaster = false;
static ClientList *esp_client_list; static ClientList *esp_client_list;
static uint8_t channelNumber = 0;
#define MAC_STRING_BUFFER_SIZE 18 #define MAC_STRING_BUFFER_SIZE 18
void init_com(ClientList *clients) { int init_com(ClientList *clients, uint8_t wifi_channel) {
// Initialisiere die Kommunikations-Warteschlange // Initialisiere die Kommunikations-Warteschlange
messageQueue = xQueueCreate(MESSAGE_QUEUE_SIZE, sizeof(BaseMessage)); messageQueue = xQueueCreate(MESSAGE_QUEUE_SIZE, sizeof(BaseMessage));
if (messageQueue == NULL) { if (messageQueue == NULL) {
ESP_LOGE(TAG, "Message queue creation failed"); ESP_LOGE(TAG, "Message queue creation failed");
return -1;
} }
esp_client_list = clients; esp_client_list = clients;
hasMaster = false; hasMaster = false;
channelNumber = wifi_channel;
return 0;
} }
void add_peer(uint8_t *macAddr) { int add_peer(uint8_t *macAddr) {
esp_now_peer_info_t peerInfo = { esp_now_peer_info_t peerInfo = {
.channel = .channel = channelNumber,
0, // Standardkanal, sollte uit den anderen Geräten übereinstimmen
.ifidx = ESP_IF_WIFI_STA, .ifidx = ESP_IF_WIFI_STA,
.encrypt = false, // Keine Verschlüsselung (kann geändert werden) .encrypt = false, // Keine Verschlüsselung (kann geändert werden)
}; };
@ -47,6 +50,7 @@ void add_peer(uint8_t *macAddr) {
ESP_LOGE(TAG, "Client could not be added to client handler, removing " ESP_LOGE(TAG, "Client could not be added to client handler, removing "
"it from esp now client list!"); "it from esp now client list!");
esp_now_del_peer(peerInfo.peer_addr); esp_now_del_peer(peerInfo.peer_addr);
return -1;
} }
ESP_LOGI(TAG, "New client added."); ESP_LOGI(TAG, "New client added.");
} }
@ -59,7 +63,9 @@ void add_peer(uint8_t *macAddr) {
} }
} else { } else {
ESP_LOGE(TAG, "Failed to add peer: %s", esp_err_to_name(result)); ESP_LOGE(TAG, "Failed to add peer: %s", esp_err_to_name(result));
return -1;
} }
return 0;
} }
BaseMessage MessageBuilder(CommandPages commandPage, PayloadUnion payload, BaseMessage MessageBuilder(CommandPages commandPage, PayloadUnion payload,
@ -94,7 +100,6 @@ void master_broadcast_task(void *param) {
void master_broadcast_ping(void *param) { void master_broadcast_ping(void *param) {
while (1) { while (1) {
// BroadCastPayload payload = {};
PingPayload payload = {}; PingPayload payload = {};
payload.timestamp = esp_timer_get_time(); payload.timestamp = esp_timer_get_time();
BaseMessage message = BaseMessage message =
@ -129,10 +134,18 @@ void master_receive_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) { const uint8_t *data, int data_len) {
ESP_LOGI(TAG, "MASTER GOT MESSAGE"); ESP_LOGI(TAG, "MASTER GOT MESSAGE");
BaseMessage replyMessage = {};
const BaseMessage *message = (const BaseMessage *)data; const BaseMessage *message = (const BaseMessage *)data;
int id;
switch (message->commandPage) { switch (message->commandPage) {
case StatusPage: case StatusPage:
ESP_LOGI(TAG, "GOT STATUS MESSAGE"); ESP_LOGI(TAG, "GOT STATUS MESSAGE");
id = get_client_id(esp_client_list, esp_now_info->src_addr);
if (id >= 0) {
esp_client_list->Clients[id].clientVersion =
message->payload.status_payload.version;
}
break; break;
case PingPage: case PingPage:
ESP_LOGI(TAG, "GOT PING MESSAGE"); ESP_LOGI(TAG, "GOT PING MESSAGE");
@ -143,7 +156,7 @@ void master_receive_callback(const esp_now_recv_info_t *esp_now_info,
message->payload.ping_payload.timestamp, currentTime, diff, message->payload.ping_payload.timestamp, currentTime, diff,
diff / 1000); // ping in ms diff / 1000); // ping in ms
int id = get_client_id(esp_client_list, esp_now_info->src_addr); id = get_client_id(esp_client_list, esp_now_info->src_addr);
if (id >= 0) { if (id >= 0) {
esp_client_list->Clients[id].lastSuccessfullPing = xTaskGetTickCount(); esp_client_list->Clients[id].lastSuccessfullPing = xTaskGetTickCount();
esp_client_list->Clients[id].lastPing = (diff / 1000); esp_client_list->Clients[id].lastPing = (diff / 1000);
@ -179,6 +192,15 @@ void master_receive_callback(const esp_now_recv_info_t *esp_now_info,
case (ESP_ERR_ESPNOW_NOT_FOUND): case (ESP_ERR_ESPNOW_NOT_FOUND):
ESP_LOGI(TAG, "CLIENT WIRD IN DIE LISTE AUFGENOMMEN"); ESP_LOGI(TAG, "CLIENT WIRD IN DIE LISTE AUFGENOMMEN");
add_peer(esp_now_info->src_addr); add_peer(esp_now_info->src_addr);
ESP_LOGI(TAG, "FRAGE CLIENT STATUS AN");
GetStatusPayload payload = {};
replyMessage = MessageBuilder(GetStatusPage, *(PayloadUnion *)&payload,
sizeof(payload));
ESP_ERROR_CHECK(esp_now_send(esp_now_info->src_addr,
(uint8_t *)&replyMessage,
sizeof(BaseMessage)));
break; break;
default: default:
ESP_LOGI(TAG, "Unknown Message %i", checkPeer); ESP_LOGI(TAG, "Unknown Message %i", checkPeer);
@ -189,6 +211,7 @@ void master_receive_callback(const esp_now_recv_info_t *esp_now_info,
break; break;
} }
} }
void client_receive_callback(const esp_now_recv_info_t *esp_now_info, void client_receive_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) { const uint8_t *data, int data_len) {
ESP_LOGI(TAG, "SLAVE GOT MESSAGE"); ESP_LOGI(TAG, "SLAVE GOT MESSAGE");
@ -203,6 +226,20 @@ void client_receive_callback(const esp_now_recv_info_t *esp_now_info,
case StatusPage: case StatusPage:
ESP_LOGI(TAG, "GOT STATUS MESSAGE"); ESP_LOGI(TAG, "GOT STATUS MESSAGE");
break; break;
case GetStatusPage: {
StatusPayload payload = {
.status = 1,
.runningPartition = 1,
.uptime = 100,
.version = 0x0002,
};
replyMessage =
MessageBuilder(StatusPage, *(PayloadUnion *)&payload, sizeof(payload));
ESP_ERROR_CHECK(esp_now_send(
esp_now_info->src_addr, (uint8_t *)&replyMessage, sizeof(BaseMessage)));
} break;
case PingPage: case PingPage:
ESP_LOGI(TAG, "GOT PING MESSAGE"); ESP_LOGI(TAG, "GOT PING MESSAGE");
replyMessage = MessageBuilder(PingPage, *(PayloadUnion *)&message->payload, replyMessage = MessageBuilder(PingPage, *(PayloadUnion *)&message->payload,
@ -239,17 +276,14 @@ void client_data_sending_task(void *param) {
while (1) { while (1) {
const char *dataToSend = "DATA:42"; const char *dataToSend = "DATA:42";
ESP_LOGI(TAG, "SEND DATA"); ESP_LOGI(TAG, "SEND DATA");
esp_now_send(NULL, (uint8_t *)dataToSend, esp_now_send(NULL, (uint8_t *)dataToSend, strlen(dataToSend));
strlen(dataToSend));
vTaskDelay(pdMS_TO_TICKS(5000)); vTaskDelay(pdMS_TO_TICKS(5000));
} }
} }
void client_monitor_task(void *pvParameters) { void client_monitor_task(void *pvParameters) {
TickType_t timeout_ticks = TickType_t timeout_ticks = pdMS_TO_TICKS(CLIENT_TIMEOUT_MS);
pdMS_TO_TICKS(CLIENT_TIMEOUT_MS); TickType_t interval_ticks = pdMS_TO_TICKS(CHECK_INTERVAL_MS);
TickType_t interval_ticks =
pdMS_TO_TICKS(CHECK_INTERVAL_MS);
while (1) { while (1) {
TickType_t now = xTaskGetTickCount(); TickType_t now = xTaskGetTickCount();

View File

@ -11,6 +11,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/types.h>
#define BROADCAST_INTERVAL_MS 500 #define BROADCAST_INTERVAL_MS 500
@ -27,37 +28,67 @@ static uint8_t broadcast_address[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF,
#define MESSAGE_QUEUE_SIZE 10 #define MESSAGE_QUEUE_SIZE 10
typedef enum { typedef enum {
BroadCastPage,
StatusPage, StatusPage,
GetStatusPage,
ConfigPage,
PingPage, PingPage,
BroadCastPage,
RegisterPage, RegisterPage,
FirmwarePrepPage,
FirmwarePayloadPage,
} CommandPages; } CommandPages;
typedef struct { typedef struct __attribute__((packed)) {
uint32_t uptime; uint16_t version; // software version
uint8_t runningPartition;
uint8_t status; uint8_t status;
uint32_t uptime;
} StatusPayload; } StatusPayload;
typedef struct { typedef struct __attribute__((packed)) {
} GetStatusPayload;
typedef struct __attribute__((packed)) {
uint8_t timeslot;
} ConfigPayload;
typedef struct __attribute__((packed)) {
uint32_t timestamp; uint32_t timestamp;
} PingPayload; } PingPayload;
typedef struct { typedef struct __attribute__((packed)) {
} BroadCastPayload; } BroadCastPayload;
typedef struct { typedef struct __attribute__((packed)) {
bool familierClient; bool familierClient;
} RegisterPayload; } RegisterPayload;
typedef union { // TODO: Check checksum fields
typedef struct __attribute__((packed)) {
uint16_t length; // length of complete firmware
uint8_t checksum; // checksum of firmware
} FirmwarePrepPayload;
// TODO: Check checksum fields
typedef struct __attribute__((packed)) {
uint8_t length;
uint8_t checksum;
uint32_t address;
uint8_t payload[240]; // TODO: need a way to figure out a safe value for this
} FirmwarePayload;
typedef union __attribute__((packed)) {
StatusPayload status_payload; StatusPayload status_payload;
ConfigPayload config_payload;
PingPayload ping_payload; PingPayload ping_payload;
BroadCastPayload broadcast_payload; BroadCastPayload broadcast_payload;
RegisterPayload register_payload; RegisterPayload register_payload;
FirmwarePrepPayload firmware_prep_payload;
FirmwarePayload firmware_payload;
} PayloadUnion; } PayloadUnion;
typedef struct { typedef struct __attribute__((packed)) {
uint16_t version; uint16_t version; // protcol version
CommandPages commandPage; CommandPages commandPage;
uint16_t length; uint16_t length;
PayloadUnion payload; PayloadUnion payload;
@ -66,9 +97,9 @@ typedef struct {
static_assert(sizeof(BaseMessage) <= 255, static_assert(sizeof(BaseMessage) <= 255,
"BaseMessage darf nicht größer als 255 sein"); "BaseMessage darf nicht größer als 255 sein");
void init_com(ClientList *clients); int init_com(ClientList *clients, uint8_t wifi_channel);
int getNextFreeClientId(); int getNextFreeClientId();
void add_peer(uint8_t *macAddr); int add_peer(uint8_t *macAddr);
BaseMessage MessageBuilder(CommandPages commandPage, PayloadUnion payload, BaseMessage MessageBuilder(CommandPages commandPage, PayloadUnion payload,
size_t payload_size); size_t payload_size);
@ -81,6 +112,7 @@ void master_receive_callback(const esp_now_recv_info_t *esp_now_info,
void client_receive_callback(const esp_now_recv_info_t *esp_now_info, void client_receive_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len); const uint8_t *data, int data_len);
void client_data_sending_task(void *param); void client_data_sending_task(void *param);
void client_send_random_data_task(void *param);
void client_monitor_task(void *pvParameters); void client_monitor_task(void *pvParameters);
#endif #endif

View File

@ -1,7 +1,11 @@
#include "client_handler.h" #include "client_handler.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_log_buffer.h"
#include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_phy_init.h" #include "esp_phy_init.h"
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
#include "esp_timer.h" #include "esp_timer.h"
@ -10,6 +14,7 @@
#include "hal/uart_types.h" #include "hal/uart_types.h"
#include "message_handler.h" #include "message_handler.h"
#include "message_parser.h" #include "message_parser.h"
#include "nvs.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "communication_handler.h" #include "communication_handler.h"
@ -22,11 +27,12 @@
#include <sys/types.h> #include <sys/types.h>
#include "message_builder.h" #include "message_builder.h"
#include "uart_msg_ids.h"
static const char *TAG = "ALOX - MAIN"; static const char *TAG = "ALOX - MAIN";
static const uint16_t version = 0x0001; static const uint16_t version = 0x0001;
static uint8_t send_message_buffer[1024]; static uint8_t send_message_buffer[1024];
static uint8_t send_message_payload_buffer[512 - 4]; static uint8_t send_message_payload_buffer[512];
static MessageBrokerTaskParams_t broker_task_params; static MessageBrokerTaskParams_t broker_task_params;
@ -36,8 +42,8 @@ void echoCallback(uint8_t msgid, const uint8_t *payload, size_t payload_len,
uint8_t *send_payload_buffer, size_t send_payload_buffer_size, uint8_t *send_payload_buffer, size_t send_payload_buffer_size,
uint8_t *send_buffer, size_t send_buffer_size) { uint8_t *send_buffer, size_t send_buffer_size) {
ESP_LOGI(TAG, "Echo command 0x01..."); ESP_LOGI(TAG, "Echo command 0x01...");
int len = int len = build_message(UART_ECHO, payload, payload_len, send_buffer,
build_message(0x01, payload, payload_len, send_buffer, send_buffer_size); send_buffer_size);
if (len < 0) { if (len < 0) {
ESP_LOGE(TAG, ESP_LOGE(TAG,
"Error Building UART Message: payload_len, %d, sendbuffer_size: " "Error Building UART Message: payload_len, %d, sendbuffer_size: "
@ -67,7 +73,9 @@ void versionCallback(uint8_t msgid, const uint8_t *payload, size_t payload_len,
send_payload_buffer[1] = (uint8_t)((version >> 8) & 0xFF); send_payload_buffer[1] = (uint8_t)((version >> 8) & 0xFF);
memcpy(&send_payload_buffer[2], &BUILD_GIT_HASH, git_build_hash_len); memcpy(&send_payload_buffer[2], &BUILD_GIT_HASH, git_build_hash_len);
int len = build_message(0x02, send_payload_buffer, needed_buffer_size, // currently running partition
int len = build_message(UART_VERSION, send_payload_buffer, needed_buffer_size,
send_buffer, send_buffer_size); send_buffer, send_buffer_size);
if (len < 0) { if (len < 0) {
ESP_LOGE(TAG, ESP_LOGE(TAG,
@ -76,7 +84,7 @@ void versionCallback(uint8_t msgid, const uint8_t *payload, size_t payload_len,
payload_len, send_buffer_size, len); payload_len, send_buffer_size, len);
return; return;
} }
uart_write_bytes(MASTER_UART, send_buffer, len); uart_write_bytes(MASTER_UART, send_buffer, len - 1);
} }
void clientInfoCallback(uint8_t msgid, const uint8_t *payload, void clientInfoCallback(uint8_t msgid, const uint8_t *payload,
@ -84,7 +92,7 @@ void clientInfoCallback(uint8_t msgid, const uint8_t *payload,
size_t send_payload_buffer_size, uint8_t *send_buffer, size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size) { size_t send_buffer_size) {
ESP_LOGI(TAG, "Client Info Command 0x03..."); ESP_LOGI(TAG, "Client Info Command 0x03...");
static uint8_t entryLength = 17; static uint8_t entryLength = 19;
uint8_t needed_buffer_size = 1 + entryLength * clientList.ClientCount; uint8_t needed_buffer_size = 1 + entryLength * clientList.ClientCount;
if (send_payload_buffer_size < needed_buffer_size) { if (send_payload_buffer_size < needed_buffer_size) {
@ -126,11 +134,16 @@ void clientInfoCallback(uint8_t msgid, const uint8_t *payload,
4); 4);
memcpy(&send_payload_buffer[offset + 13], memcpy(&send_payload_buffer[offset + 13],
&clientList.Clients[i].lastSuccessfullPing, 4); &clientList.Clients[i].lastSuccessfullPing, 4);
memcpy(&send_payload_buffer[offset + 17],
&clientList.Clients[i].clientVersion, 2);
} }
} }
int len = build_message(0x04, send_payload_buffer, needed_buffer_size, int len = build_message(UART_CLIENT_INFO, send_payload_buffer,
send_buffer, send_buffer_size); needed_buffer_size, send_buffer, send_buffer_size);
ESP_LOG_BUFFER_HEX("SEND BUFFER: ", send_buffer, send_buffer_size);
if (len < 0) { if (len < 0) {
ESP_LOGE(TAG, ESP_LOGE(TAG,
"Error Building UART Message: payload_len, %d, sendbuffer_size: " "Error Building UART Message: payload_len, %d, sendbuffer_size: "
@ -166,8 +179,7 @@ void app_main(void) {
wifi_config_t wifi_config = { wifi_config_t wifi_config = {
.sta = .sta =
{ {
.channel = 1, // Kanal 1, stelle sicher, dass alle Geräte .channel = 1,
// denselben Kanal verwenden
}, },
}; };
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
@ -181,7 +193,70 @@ void app_main(void) {
ESP_ERROR_CHECK(esp_now_register_recv_cb(client_receive_callback)); ESP_ERROR_CHECK(esp_now_register_recv_cb(client_receive_callback));
} }
init_com(&clientList); ret = init_com(&clientList, 1);
if (ret < 0) {
ESP_LOGE(TAG, "Could not Init ESP NOW Communication!");
}
esp_partition_iterator_t partition_iter = esp_partition_find(
ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
while (partition_iter != NULL) {
const esp_partition_t *part1 = esp_partition_get(partition_iter);
ESP_LOGI(TAG, "Partition: %s, Address: %d, Size %d", part1->label,
part1->address, part1->size);
partition_iter = esp_partition_next(partition_iter);
}
const esp_partition_t *running = esp_ota_get_running_partition();
ESP_LOGI(TAG, "OTA: Running Partition: %s", running->label);
uint8_t ota_part_count = esp_ota_get_app_partition_count();
ESP_LOGI(TAG, "OTA: Got %d OTA Partitions", ota_part_count);
esp_ota_img_states_t ota_state;
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
ESP_LOGI(TAG, "OTA: Partition State : %d", ota_state);
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
// run diagnostic function ...
bool diagnostic_is_ok = true; // TODO: a real function that checks if
// everything is running properly
if (diagnostic_is_ok) {
ESP_LOGI(
TAG,
"Diagnostics completed successfully! Continuing execution ...");
// esp_ota_mark_app_valid_cancel_rollback();
} else {
ESP_LOGE(
TAG,
"Diagnostics failed! Start rollback to the previous version ...");
// esp_ota_mark_app_invalid_rollback_and_reboot();
}
}
}
const char nvs_part_name[] = "nvs_data";
const char nvs_namespace_name[] = "saved_clients";
ret = nvs_flash_init_partition(nvs_part_name);
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase_partition(nvs_part_name));
ret = nvs_flash_init_partition(nvs_part_name);
}
ESP_ERROR_CHECK(ret);
nvs_handle_t nt;
ESP_ERROR_CHECK(nvs_open_from_partition(nvs_part_name, nvs_namespace_name,
NVS_READWRITE, &nt));
int32_t outval;
ret = nvs_get_i32(nt, "test_entry", &outval);
if (ret == ESP_ERR_NVS_NOT_FOUND) {
ESP_ERROR_CHECK(nvs_set_i32(nt, "test_entry", 6969));
ESP_ERROR_CHECK(nvs_commit(nt));
ESP_LOGE(TAG, "Nichts im Flash gefunden hab was dahin geschrieben");
} else if (ret == ESP_OK) {
ESP_LOGE(TAG, "DAS WAR IM FLASH %d", outval);
}
nvs_close(nt);
// Tasks starten basierend auf Master/Client // Tasks starten basierend auf Master/Client
if (isMaster) { if (isMaster) {
@ -219,7 +294,7 @@ void app_main(void) {
// NULL); // NULL);
} else { } else {
ESP_LOGI(TAG, "Started in Slavemode"); ESP_LOGI(TAG, "Started in Slavemode");
xTaskCreate(client_data_sending_task, "ClientDataSending", 4096, NULL, 1, // xTaskCreate(client_data_sending_task, "ClientDataSending", 4096, NULL, 1,
NULL); // NULL);
} }
} }

50
main/ota_update.c Normal file
View File

@ -0,0 +1,50 @@
#include "ota_update.h"
#include "esp_log.h"
#include "message_handler.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
static uint8_t updateBuffer[4000];
static const char *TAG = "ALOX - OTA";
void start_uart_update(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size) {
ESP_LOGI(TAG, "OTA Update Uart Command");
// prepare for writing new partition with ota api
// will get 200 bytes each uart message
// fill update buffer
// write update buffer complete
/*int len = build_message(0x02, send_payload_buffer, needed_buffer_size,
send_buffer, send_buffer_size);
if (len < 0) {
ESP_LOGE(TAG,
"Error Building UART Message: payload_len, %d, sendbuffer_size: "
"%d, mes_len(error): %d",
payload_len, send_buffer_size, len);
return;
}
uart_write_bytes(MASTER_UART, send_buffer, len - 1);*/
}
void payload_uart_update(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size) {
ESP_LOGI(TAG, "OTA Update Uart Command");
}
void end_uart_update(uint8_t msgid, const uint8_t *payload, size_t payload_len,
uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size) {
ESP_LOGI(TAG, "OTA Update Uart Command");
}
void init_ota() {
RegisterCallback(uint8_t msgid, RegisterFunctionCallback callback);
}

4
main/ota_update.h Normal file
View File

@ -0,0 +1,4 @@
#ifndef OTA_UPDATE_H
#define OTA_UPDATE_H
#endif

17
main/uart_msg_ids.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef UART_MSG_IDS_H
#define UART_MSG_IDS_H
enum UART_MSG_IDS {
// MISC
UART_ECHO = 0x01,
UART_VERSION = 0x02,
UART_CLIENT_INFO = 0x03,
// OTA
UART_OTA_START = 0x10,
UART_OTA_PAYLOAD = 0x11,
UART_OTA_END = 0x12,
UART_OTA_STATUS = 0x13,
};
#endif

View File

@ -177,3 +177,55 @@ techn. Anforderungen hinreichend gut umsetzen lassen.
und ob diese den ursprünglichen Anforderungen entsprechen. und ob diese den ursprünglichen Anforderungen entsprechen.
## OTA-Update Technische Umsetzung:
### Vorrausetzung:
- Update File steht bereit und ist unter 2MB groß.
- UART Verbindung steht
- ESP Funktioniert einwandfrei
- ESP Läuft auf Partition A, Partition B soll geupdated werden
### Erste Schritt:
- Update in 200Byte stücke zerhacken und stück für stück per UART an den Master schicken
- Uart Protokol hat schon eine fehlercheck für die Übertragung drinnen
- Firmware wird in Partition B geschrieben
- OTA API Validiert Firmware am ende
#### Hier könnte man schon einen Neustart machen und Validieren ob die Firmware für den Master läuft!
#### Denn angeblich kann man beim ESP die aktuell laufende Partition auslesen
### Zweiter Schritt:
- Master liest in 200Byte stücken die Firmware aus seiner Partition B aus
- Und schickt per Broadcast die ersten 20 Packete an die Clients
- Die clients haben 4KB Buffer vorgesehen wo sie die 20 Packete unterbringen können
- Master Forder Ack Bitmaske an zur Validierung das alle 20 Packete da sind
- Sollten in der Bitmaske zeilen fehlen gibt der Master per unicast die fehlenden Zeilen an die Entsprechend Clients erneut
- ESP NOW kümmert sich hier um die Datenintigrität
- Wenn alle ihre ersten 20 packete haben gibt der master das go und alle schreiben die ersten 20 packete weg.
- Der master aktuallisiert den fortschritt für alle clients -> dann kann man das auch abfragen per uart und hat eine Fortschrittsanzeige
- Alle melden sich zurück wenn sie fertig sind mit dem schreiben per ota und der buffer leer ist.
- Repeat bis alle Daten da sind
Hier hab ich mal grob gerechnet:
2MB in 200Byte Schritten -> 10.000 Packete
10.000 Packete in 20er Schritten -> 500 Sequencen
Retries und Acks mal aussen vor hab ich leider keinen richtigen anhaltspunkt wie lang das dauern kann.
Aber 500* ca 300ms => ist schonmal 150sekunden nur für das acken das die Packete da sind. Annahme hier das die maximal latenz beim Ping mit 16 Clients ca 300ms sind.
Entsprechend mit Daten und retries... ja kp, Gemini schätzt max 10min. Wird sich zeigen. Da addiert sich zu viel auf.
- Alle Clients validieren ihren firmware
- Sollte das bei einem nicht klappen muss man hier nochmal gucken ob man den ganzen process nochmal von vorne anstößt nur mit dem fehlenden client...
### Dritter Schritt:
- Alle Clients rebooten
- Clients geben rückmeldung ob das Update funktioniert
#### Hier müssten war noch entscheiden was passiert wenn das Update bei nur ein paar funktionert hat?
#### Was passiert wenn das Update garnicht funktioniert hat, behält der master dann auch seinen stand?
#### Entsprechend hätte man ihn vorher auch nicht neustarten dürfen
- Sollten alle Clients ihr go geben startet der Master auch neu
#### Wenn das Master Update jetzt fehlschlägt sagt er den clients bescheid und die booten auch wieder um?
Gibt halt noch ein zwar sachen die man sich überlegen muss aber ich denke den rest hab ich soweit ausgearbeitet