src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
284 / 346
82.1%
Branches:
337 / 590
57.1%
Functions:
13 / 14
92.9%

SomfyFrame.cpp
Line Branch Exec Source
1 #include <Arduino.h>
2 #include "esp_log.h"
3 #include "SomfyFrame.h"
4
5 static const char *TAG = "Somfy";
6
7 30 somfy_commands translateSomfyCommand(const String& string) {
8
3/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 28 times.
30 if (string.equalsIgnoreCase("My")) return somfy_commands::My;
9
3/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 26 times.
28 else if (string.equalsIgnoreCase("Up")) return somfy_commands::Up;
10
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 26 times.
26 else if (string.equalsIgnoreCase("MyUp")) return somfy_commands::MyUp;
11
3/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 24 times.
26 else if (string.equalsIgnoreCase("Down")) return somfy_commands::Down;
12
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 24 times.
24 else if (string.equalsIgnoreCase("MyDown")) return somfy_commands::MyDown;
13
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 24 times.
24 else if (string.equalsIgnoreCase("UpDown")) return somfy_commands::UpDown;
14
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 24 times.
24 else if (string.equalsIgnoreCase("MyUpDown")) return somfy_commands::MyUpDown;
15
3/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 22 times.
24 else if (string.equalsIgnoreCase("Prog")) return somfy_commands::Prog;
16
3/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 21 times.
22 else if (string.equalsIgnoreCase("SunFlag")) return somfy_commands::SunFlag;
17
3/4
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 20 times.
21 else if (string.equalsIgnoreCase("StepUp")) return somfy_commands::StepUp;
18
3/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 19 times.
20 else if (string.equalsIgnoreCase("StepDown")) return somfy_commands::StepDown;
19
3/4
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 17 times.
19 else if (string.equalsIgnoreCase("Flag")) return somfy_commands::Flag;
20
3/4
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 16 times.
17 else if (string.equalsIgnoreCase("Sensor")) return somfy_commands::Sensor;
21
3/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 14 times.
16 else if (string.equalsIgnoreCase("Toggle")) return somfy_commands::Toggle;
22
3/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 13 times.
14 else if (string.equalsIgnoreCase("Favorite")) return somfy_commands::Favorite;
23
3/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 12 times.
13 else if (string.equalsIgnoreCase("Stop")) return somfy_commands::Stop;
24 // The names translateSomfyCommand(cmd) reports so they parse back.
25
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 11 times.
12 else if (string.equalsIgnoreCase("Sun Flag")) return somfy_commands::SunFlag;
26
3/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 10 times.
11 else if (string.equalsIgnoreCase("Step Up")) return somfy_commands::StepUp;
27
3/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 9 times.
10 else if (string.equalsIgnoreCase("Step Down")) return somfy_commands::StepDown;
28
3/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 8 times.
9 else if (string.equalsIgnoreCase("My+Up")) return somfy_commands::MyUp;
29
3/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 7 times.
8 else if (string.equalsIgnoreCase("Up+Down")) return somfy_commands::UpDown;
30
3/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 6 times.
7 else if (string.equalsIgnoreCase("My+Down")) return somfy_commands::MyDown;
31
3/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 5 times.
6 else if (string.equalsIgnoreCase("My+Up+Down")) return somfy_commands::MyUpDown;
32
12/22
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 1 time.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 4 times.
✓ Branch 16 taken 4 times.
✓ Branch 17 taken 1 time.
✓ Branch 19 taken 5 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 time.
✓ Branch 23 taken 4 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
5 else if (string.startsWith("fav") || string.startsWith("FAV")) return somfy_commands::Favorite;
33
12/22
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1 time.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✓ Branch 17 taken 1 time.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 time.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
4 else if (string.startsWith("mud") || string.startsWith("MUD")) return somfy_commands::MyUpDown;
34
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("md") || string.startsWith("MD")) return somfy_commands::MyDown;
35
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("ud") || string.startsWith("UD")) return somfy_commands::UpDown;
36
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("mu") || string.startsWith("MU")) return somfy_commands::MyUp;
37
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("su") || string.startsWith("SU")) return somfy_commands::StepUp;
38
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("sd") || string.startsWith("SD")) return somfy_commands::StepDown;
39
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("sen") || string.startsWith("SEN")) return somfy_commands::Sensor;
40
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("p") || string.startsWith("P")) return somfy_commands::Prog;
41
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("u") || string.startsWith("U")) return somfy_commands::Up;
42
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("d") || string.startsWith("D")) return somfy_commands::Down;
43
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("m") || string.startsWith("M")) return somfy_commands::My;
44
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("f") || string.startsWith("F")) return somfy_commands::Flag;
45
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("s") || string.startsWith("S")) return somfy_commands::SunFlag;
46
9/22
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
3 else if (string.startsWith("t") || string.startsWith("T")) return somfy_commands::Toggle;
47
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
3 else if (string.length() == 1) return static_cast<somfy_commands>(strtol(string.c_str(), nullptr, 16));
48 2 else return somfy_commands::My;
49 }
50 51 String translateSomfyCommand(const somfy_commands cmd) {
51
17/17
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 1 time.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 1 time.
✓ Branch 12 taken 1 time.
✓ Branch 13 taken 2 times.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 1 time.
✓ Branch 16 taken 1 time.
51 switch (cmd) {
52 12 case somfy_commands::Up:
53 12 return "Up";
54 9 case somfy_commands::Down:
55 9 return "Down";
56 7 case somfy_commands::My:
57 7 return "My";
58 2 case somfy_commands::MyUp:
59 2 return "My+Up";
60 1 case somfy_commands::UpDown:
61 1 return "Up+Down";
62 1 case somfy_commands::MyDown:
63 1 return "My+Down";
64 1 case somfy_commands::MyUpDown:
65 1 return "My+Up+Down";
66 5 case somfy_commands::Prog:
67 5 return "Prog";
68 2 case somfy_commands::SunFlag:
69 2 return "Sun Flag";
70 1 case somfy_commands::Flag:
71 1 return "Flag";
72 2 case somfy_commands::StepUp:
73 2 return "Step Up";
74 1 case somfy_commands::StepDown:
75 1 return "Step Down";
76 1 case somfy_commands::Sensor:
77 1 return "Sensor";
78 2 case somfy_commands::Toggle:
79 2 return "Toggle";
80 2 case somfy_commands::Favorite:
81 2 return "Favorite";
82 1 case somfy_commands::Stop:
83 1 return "Stop";
84 1 default:
85
4/8
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 time.
✗ Branch 9 not taken.
✓ Branch 11 taken 1 time.
✗ Branch 12 not taken.
2 return "Unknown(" + String((uint8_t)cmd) + ")";
86 }
87 }
88 14 somfy_commands flipCommand(somfy_commands cmd) {
89
7/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 6 times.
14 switch(cmd) {
90 2 case somfy_commands::Up:
91 2 return somfy_commands::Down;
92 1 case somfy_commands::MyUp:
93 1 return somfy_commands::MyDown;
94 2 case somfy_commands::Down:
95 2 return somfy_commands::Up;
96 1 case somfy_commands::MyDown:
97 1 return somfy_commands::MyUp;
98 1 case somfy_commands::StepUp:
99 1 return somfy_commands::StepDown;
100 1 case somfy_commands::StepDown:
101 1 return somfy_commands::StepUp;
102 6 default:
103 6 return cmd;
104 }
105 }
106
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 somfy_commands sunFlagCommand(bool on) { return on ? somfy_commands::SunFlag : somfy_commands::Flag; }
107 34 byte somfy_frame_t::calc80Checksum(byte b0, byte b1, byte b2) {
108 34 byte cs80 = 0;
109 34 cs80 = (((b0 & 0xF0) >> 4) ^ ((b1 & 0xF0) >> 4));
110 34 cs80 ^= ((b2 & 0xF0) >> 4);
111 34 cs80 ^= (b0 & 0x0F);
112 34 cs80 ^= (b1 & 0x0F);
113 34 return cs80;
114 }
115
116 37 void somfy_frame_t::decodeFrame(byte* frame) {
117 byte decoded[10];
118 37 decoded[0] = frame[0];
119 // The last 3 bytes are not encoded even on 80-bits. Go figure.
120 37 decoded[7] = frame[7];
121 37 decoded[8] = frame[8];
122 37 decoded[9] = frame[9];
123
2/2
✓ Branch 0 taken 222 times.
✓ Branch 1 taken 37 times.
259 for (byte i = 1; i < 7; i++) {
124 222 decoded[i] = frame[i] ^ frame[i - 1];
125 }
126 37 byte checksum = 0;
127 // We only want the upper nibble for the command byte.
128
2/2
✓ Branch 0 taken 259 times.
✓ Branch 1 taken 37 times.
296 for (byte i = 0; i < 7; i++) {
129
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 222 times.
259 if (i == 1) checksum = checksum ^ (decoded[i] >> 4);
130 222 else checksum = checksum ^ decoded[i] ^ (decoded[i] >> 4);
131 }
132 37 checksum &= 0b1111; // We keep the last 4 bits only
133
134 37 this->checksum = decoded[1] & 0b1111;
135 37 this->encKey = decoded[0];
136 // Lets first determine the protocol.
137 37 this->rawCmd = decoded[1] >> 4;
138 37 this->cmd = (somfy_commands)(this->rawCmd);
139
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 32 times.
37 if(this->cmd == somfy_commands::RTWProto) {
140
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4 times.
5 if(this->encKey >= 160) {
141 1 this->proto = radio_proto::RTS;
142
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if(this->encKey == 164) this->cmd = somfy_commands::Toggle;
143 }
144
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 else if(this->encKey > 148) {
145 2 this->proto = radio_proto::RTV;
146 2 this->cmd = (somfy_commands)(this->encKey - 148);
147 }
148
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if(this->encKey >= 133) {
149 2 this->proto = radio_proto::RTW;
150 2 this->cmd = (somfy_commands)(this->encKey - 132);
151 }
152 }
153 32 else this->proto = radio_proto::RTS;
154 // We reuse this memory address so we must reset the processed
155 // flag. This will ensure we can see frames on the first beat.
156 37 this->processed = false;
157 37 this->rollingCode = decoded[3] + (decoded[2] << 8);
158 37 this->remoteAddress = (decoded[6] + (decoded[5] << 8) + (decoded[4] << 16));
159
6/6
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 1 time.
37 this->valid = this->checksum == checksum && this->remoteAddress > 0 && this->remoteAddress < 16777215;
160
4/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 3 times.
37 if (this->cmd != somfy_commands::Sensor && this->valid) this->valid = (this->rollingCode > 0);
161 // Next lets process some of the RTS extensions for 80-bit frames
162
6/6
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 15 times.
37 if(this->valid && this->proto == radio_proto::RTS && this->bitLength == 80) {
163 // Do a parity checksum on the 80 bit data.
164
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 13 times.
14 if((decoded[9] & 0x0F) != this->calc80Checksum(decoded[7], decoded[8], decoded[9])) this->valid = false;
165
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 time.
14 if(this->valid) {
166 // Translate extensions for stop and favorite.
167
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if(this->cmd == somfy_commands::My) this->cmd = (somfy_commands)((decoded[1] >> 4) | ((decoded[8] & 0x0F) << 4));
168 // Bit packing to get the step size prohibits translation on the byte.
169
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 else if(this->cmd == somfy_commands::StepDown) this->cmd = (somfy_commands)((decoded[1] >> 4) | ((decoded[8] & 0x08) << 4));
170 }
171 }
172
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 5 times.
37 if (this->valid) {
173
174 // Check for valid command.
175
3/5
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
32 switch (this->cmd) {
176 //case somfy_commands::Unknown0:
177 24 case somfy_commands::My:
178 case somfy_commands::Up:
179 case somfy_commands::MyUp:
180 case somfy_commands::Down:
181 case somfy_commands::MyDown:
182 case somfy_commands::UpDown:
183 case somfy_commands::MyUpDown:
184 case somfy_commands::Prog:
185 case somfy_commands::Flag:
186 case somfy_commands::SunFlag:
187 case somfy_commands::Sensor:
188 24 break;
189 ✗ case somfy_commands::UnknownD:
190 case somfy_commands::RTWProto:
191 ✗ this->valid = false;
192 ✗ break;
193 4 case somfy_commands::StepUp:
194 case somfy_commands::StepDown:
195 // Decode the step size.
196 4 this->stepSize = ((decoded[8] & 0x07) << 4) | ((decoded[9] & 0xF0) >> 4);
197 4 break;
198 4 case somfy_commands::Toggle:
199 case somfy_commands::Favorite:
200 case somfy_commands::Stop:
201 4 break;
202 ✗ default:
203 ✗ this->valid = false;
204 ✗ break;
205 }
206 }
207
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 31 times.
37 if(this->valid && this->encKey == 0) this->valid = false;
208
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 31 times.
37 if (!this->valid) {
209 ESP_LOGW(TAG, "INVALID FRAME KEY:%d ADDR:%d CMD:%s RCODE:%d",
210 this->encKey, this->remoteAddress,
211 translateSomfyCommand(this->cmd).c_str(), this->rollingCode);
212 ESP_LOGD(TAG, " KEY 1 2 3 4 5 6 ");
213 ESP_LOGD(TAG, "--------------------------------");
214 char enc_buf[64], dec_buf[64];
215 6 int enc_pos = 0, dec_pos = 0;
216 6 enc_pos += snprintf(enc_buf + enc_pos, sizeof(enc_buf) - enc_pos, "ENC ");
217 6 dec_pos += snprintf(dec_buf + dec_pos, sizeof(dec_buf) - dec_pos, "DEC ");
218
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 6 times.
66 for (byte i = 0; i < 10; i++) {
219 60 enc_pos += snprintf(enc_buf + enc_pos, sizeof(enc_buf) - enc_pos, "%3d ", frame[i]);
220 60 dec_pos += snprintf(dec_buf + dec_pos, sizeof(dec_buf) - dec_pos, "%3d ", decoded[i]);
221 }
222 ESP_LOGD(TAG, "%s", enc_buf);
223 ESP_LOGD(TAG, "%s", dec_buf);
224 }
225 37 }
226 18 byte somfy_frame_t::encode80Byte7(byte start, uint8_t repeat) {
227
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 while((repeat * 4) + start > 255) repeat -= 15;
228 18 return start + (repeat * 4);
229 }
230 20 void somfy_frame_t::encode80BitFrame(byte *frame, uint8_t repeat) {
231
8/9
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
20 switch(this->cmd) {
232 // Step up and down commands encode the step size into the last 3 bytes.
233 2 case somfy_commands::StepUp:
234
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(repeat == 0) frame[1] = (static_cast<byte>(somfy_commands::StepDown) << 4) | (frame[1] & 0x0F);
235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(this->stepSize == 0) this->stepSize = 1;
236 2 frame[7] = 132; // For simplicity this appears to be constant.
237 2 frame[8] = ((this->stepSize & 0x70) >> 4) | 0x38;
238 2 frame[9] = ((this->stepSize & 0x0F) << 4);
239 2 frame[9] |= this->calc80Checksum(frame[7], frame[8], frame[9]);
240 2 break;
241 2 case somfy_commands::StepDown:
242
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(repeat == 0) frame[1] = (static_cast<byte>(somfy_commands::StepDown) << 4) | (frame[1] & 0x0F);
243
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(this->stepSize == 0) this->stepSize = 1;
244 2 frame[7] = 132; // For simplicity this appears to be constant.
245 2 frame[8] = ((this->stepSize & 0x70) >> 4) | 0x30;
246 2 frame[9] = ((this->stepSize & 0x0F) << 4);
247 2 frame[9] |= this->calc80Checksum(frame[7], frame[8], frame[9]);
248 2 break;
249 1 case somfy_commands::Favorite:
250
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if(repeat == 0) frame[1] = (static_cast<byte>(somfy_commands::My) << 4) | (frame[1] & 0x0F);
251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 frame[7] = repeat > 0 ? 132 : 196;
252 1 frame[8] = 44;
253 1 frame[9] = 0x90;
254 1 frame[9] |= this->calc80Checksum(frame[7], frame[8], frame[9]);
255 1 break;
256 1 case somfy_commands::Stop:
257
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if(repeat == 0) frame[1] = (static_cast<byte>(somfy_commands::My) << 4) | (frame[1] & 0x0F);
258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 frame[7] = repeat > 0 ? 132 : 196;
259 1 frame[8] = 47;
260 1 frame[9] = 0xF0;
261 1 frame[9] |= this->calc80Checksum(frame[7], frame[8], frame[9]);
262 1 break;
263 2 case somfy_commands::Toggle:
264 2 frame[0] = 164;
265 2 frame[1] |= 0xF0;
266 2 frame[7] = this->encode80Byte7(196, repeat);
267 2 frame[8] = 0;
268 2 frame[9] = 0x10;
269 2 frame[9] |= this->calc80Checksum(frame[7], frame[8], frame[9]);
270 2 break;
271 6 case somfy_commands::Up:
272 6 frame[7] = this->encode80Byte7(196, repeat);
273 6 frame[8] = 32;
274 6 frame[9] = 0x00;
275 6 frame[9] |= this->calc80Checksum(frame[7], frame[8], frame[9]);
276 6 break;
277 4 case somfy_commands::Down:
278 4 frame[7] = this->encode80Byte7(196, repeat);
279 4 frame[8] = 44;
280 4 frame[9] = 0x80;
281 4 frame[9] |= this->calc80Checksum(frame[7], frame[8], frame[9]);
282 4 break;
283 2 case somfy_commands::Prog:
284 case somfy_commands::UpDown:
285 case somfy_commands::MyDown:
286 case somfy_commands::MyUp:
287 case somfy_commands::MyUpDown:
288 case somfy_commands::My:
289 2 frame[7] = this->encode80Byte7(196, repeat);
290 2 frame[8] = 0x00;
291 2 frame[9] = 0x10;
292 2 frame[9] |= this->calc80Checksum(frame[7], frame[8], frame[9]);
293 2 break;
294
295 ✗ default:
296 ✗ break;
297 }
298 20 }
299 88 void somfy_frame_t::encodeFrame(byte *frame) {
300 88 const byte btn = static_cast<byte>(cmd);
301 88 this->valid = true;
302 88 frame[0] = this->encKey; // Encryption key. Doesn't matter much
303 88 frame[1] = (btn & 0x0F) << 4; // Which button did you press? The 4 LSB will be the checksum
304 88 frame[2] = this->rollingCode >> 8; // Rolling code (big endian)
305 88 frame[3] = this->rollingCode; // Rolling code
306 88 frame[4] = this->remoteAddress >> 16; // Remote address
307 88 frame[5] = this->remoteAddress >> 8; // Remote address
308 88 frame[6] = this->remoteAddress; // Remote address
309 88 frame[7] = 132;
310 88 frame[8] = 0;
311 88 frame[9] = 29;
312 // Ok so if this is an RTW things are a bit different.
313
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 86 times.
88 if(this->proto == radio_proto::RTW) {
314 2 frame[1] = 0xF0;
315
2/11
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
2 switch(this->cmd) {
316 ✗ case somfy_commands::My:
317 ✗ frame[0] = 133;
318 ✗ break;
319 1 case somfy_commands::Up:
320 1 frame[0] = 134;
321 1 break;
322 ✗ case somfy_commands::MyUp:
323 ✗ frame[0] = 135;
324 ✗ break;
325 1 case somfy_commands::Down:
326 1 frame[0] = 136;
327 1 break;
328 ✗ case somfy_commands::MyDown:
329 ✗ frame[0] = 137;
330 ✗ break;
331 ✗ case somfy_commands::UpDown:
332 ✗ frame[0] = 138;
333 ✗ break;
334 ✗ case somfy_commands::MyUpDown:
335 ✗ frame[0] = 139;
336 ✗ break;
337 ✗ case somfy_commands::Prog:
338 ✗ frame[0] = 140;
339 ✗ break;
340 ✗ case somfy_commands::SunFlag:
341 ✗ frame[0] = 141;
342 ✗ break;
343 ✗ case somfy_commands::Flag:
344 ✗ frame[0] = 142;
345 ✗ break;
346 ✗ default:
347 ✗ break;
348 }
349 }
350
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 84 times.
86 else if(this->proto == radio_proto::RTV) {
351 2 frame[1] = 0xF0;
352
2/11
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
2 switch(this->cmd) {
353 ✗ case somfy_commands::My:
354 ✗ frame[0] = 149;
355 ✗ break;
356 1 case somfy_commands::Up:
357 1 frame[0] = 150;
358 1 break;
359 ✗ case somfy_commands::MyUp:
360 ✗ frame[0] = 151;
361 ✗ break;
362 1 case somfy_commands::Down:
363 1 frame[0] = 152;
364 1 break;
365 ✗ case somfy_commands::MyDown:
366 ✗ frame[0] = 153;
367 ✗ break;
368 ✗ case somfy_commands::UpDown:
369 ✗ frame[0] = 154;
370 ✗ break;
371 ✗ case somfy_commands::MyUpDown:
372 ✗ frame[0] = 155;
373 ✗ break;
374 ✗ case somfy_commands::Prog:
375 ✗ frame[0] = 156;
376 ✗ break;
377 ✗ case somfy_commands::SunFlag:
378 ✗ frame[0] = 157;
379 ✗ break;
380 ✗ case somfy_commands::Flag:
381 ✗ frame[0] = 158;
382 ✗ break;
383 ✗ default:
384 ✗ break;
385 }
386
387 }
388 else {
389
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 64 times.
84 if(this->bitLength == 80) this->encode80BitFrame(&frame[0], this->repeats);
390 }
391 88 byte checksum = 0;
392
393
2/2
✓ Branch 0 taken 616 times.
✓ Branch 1 taken 88 times.
704 for (byte i = 0; i < 7; i++) {
394 616 checksum = checksum ^ frame[i] ^ (frame[i] >> 4);
395 }
396 88 checksum &= 0b1111; // We keep the last 4 bits only
397 // Checksum integration
398 88 frame[1] |= checksum;
399 // Obfuscation: a XOR of all the bytes
400
2/2
✓ Branch 0 taken 528 times.
✓ Branch 1 taken 88 times.
616 for (byte i = 1; i < 7; i++) {
401 528 frame[i] ^= frame[i - 1];
402 }
403 88 }
404 ✗ void somfy_frame_t::print() {
405 ESP_LOGD(TAG, "----------- Receiving -------------");
406 ESP_LOGD(TAG, "RSSI:%d LQI:%d", this->rssi, this->lqi);
407 ESP_LOGD(TAG, "CMD:%s ADDR:%d RCODE:%d",
408 translateSomfyCommand(this->cmd).c_str(), this->remoteAddress, this->rollingCode);
409 ESP_LOGD(TAG, "KEY:%02X CS:%d", this->encKey, this->checksum);
410 ✗ }
411
5/6
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 15 times.
26 bool somfy_frame_t::isSynonym(somfy_frame_t &frame) { return this->remoteAddress == frame.remoteAddress && this->cmd != frame.cmd && this->rollingCode == frame.rollingCode; }
412
5/6
✓ Branch 0 taken 136 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 110 times.
✓ Branch 5 taken 10 times.
136 bool somfy_frame_t::isRepeat(somfy_frame_t &frame) { return this->remoteAddress == frame.remoteAddress && this->cmd == frame.cmd && this->rollingCode == frame.rollingCode; }
413 136 void somfy_frame_t::copy(somfy_frame_t &frame) {
414
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 26 times.
136 if(this->isRepeat(frame)) {
415 110 this->repeats++;
416 110 this->rssi = frame.rssi;
417 110 this->lqi = frame.lqi;
418 }
419 else {
420 26 this->synonym = this->isSynonym(frame);
421 26 this->valid = frame.valid;
422
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 1 time.
26 if(!this->synonym) this->processed = frame.processed;
423 26 this->rssi = frame.rssi;
424 26 this->lqi = frame.lqi;
425 26 this->cmd = frame.cmd;
426 26 this->remoteAddress = frame.remoteAddress;
427 26 this->rollingCode = frame.rollingCode;
428 26 this->encKey = frame.encKey;
429 26 this->checksum = frame.checksum;
430 26 this->hwsync = frame.hwsync;
431 26 this->repeats = frame.repeats;
432 }
433 136 }
434 30 bool startsMovement(somfy_commands cmd) {
435
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 1 time.
30 switch(cmd) {
436 29 case somfy_commands::My:
437 case somfy_commands::Up:
438 case somfy_commands::Down:
439 case somfy_commands::StepUp:
440 case somfy_commands::StepDown:
441 case somfy_commands::Toggle:
442 case somfy_commands::Favorite:
443 29 return true;
444 1 default:
445 1 return false;
446 }
447 }
448