Skip to content

Commit f96f1c6

Browse files
authored
Added ITypedCANSignal<SignalType> to allow for arrays of CANSignals of the same type, but with different other parameters (#26)
* Passes unit tests with ITypedCANSignal<SignalType> * Added unit test for ITypedCANSignal * Actually run typed CAN signal test
1 parent 0b2c907 commit f96f1c6

2 files changed

Lines changed: 54 additions & 22 deletions

File tree

include/can_interface.h

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,30 @@ constexpr uint64_t generate_mask(uint8_t position, uint8_t length)
4141
{
4242
return 0xFFFFFFFFFFFFFFFFull << (64 - length) >> (64 - (length + position));
4343
}
44+
45+
template <typename SignalType>
46+
class ITypedCANSignal : public ICANSignal
47+
{
48+
public:
49+
SignalType &value_ref() { return signal_; }
50+
51+
void operator=(const SignalType &signal) { signal_ = signal; }
52+
53+
operator SignalType() const { return signal_; }
54+
55+
protected:
56+
SignalType signal_;
57+
};
58+
59+
// Needed so compiler knows these template classes exist
60+
template class ITypedCANSignal<uint8_t>;
61+
template class ITypedCANSignal<uint16_t>;
62+
template class ITypedCANSignal<uint32_t>;
63+
template class ITypedCANSignal<int8_t>;
64+
template class ITypedCANSignal<int16_t>;
65+
template class ITypedCANSignal<int32_t>;
66+
template class ITypedCANSignal<float>;
67+
4468
static constexpr int kCANTemplateFloatDenominator{1 << 16}; // 2^16
4569
constexpr int CANTemplateConvertFloat(float value) { return value * kCANTemplateFloatDenominator; }
4670
constexpr float CANTemplateGetFloat(int value) { return static_cast<float>(value) / kCANTemplateFloatDenominator; }
@@ -86,7 +110,7 @@ template <typename SignalType,
86110
bool unity_factor = factor == CANTemplateConvertFloat(1)
87111
&& offset == 0> // unity_factor is used for increased precision on unity-factor 64-bit
88112
// signals by getting rid of floating point error
89-
class CANSignal : public ICANSignal
113+
class CANSignal : public ITypedCANSignal<SignalType>
90114
{
91115
using underlying_type = typename GetCANRawType<signed_raw>::type;
92116

@@ -100,25 +124,25 @@ class CANSignal : public ICANSignal
100124
{
101125
if (unity_factor)
102126
{
103-
if (byte_order == ByteOrder::kLittleEndian)
127+
if (byte_order == ICANSignal::ByteOrder::kLittleEndian)
104128
{
105-
*buffer |= (static_cast<underlying_type>(signal_) << position) & mask;
129+
*buffer |= (static_cast<underlying_type>(this->signal_) << position) & mask;
106130
}
107131
else
108132
{
109133
uint8_t temp_reversed_buffer[8]{0};
110134
*reinterpret_cast<underlying_type *>(temp_reversed_buffer) |=
111-
(static_cast<underlying_type>(signal_) << (64 - (position + length)));
135+
(static_cast<underlying_type>(this->signal_) << (64 - (position + length)));
112136
std::reverse(std::begin(temp_reversed_buffer), std::end(temp_reversed_buffer));
113137
*buffer |= *reinterpret_cast<underlying_type *>(temp_reversed_buffer) & mask;
114138
}
115139
}
116140
else
117141
{
118-
if (byte_order == ByteOrder::kLittleEndian)
142+
if (byte_order == ICANSignal::ByteOrder::kLittleEndian)
119143
{
120144
*buffer |= (static_cast<underlying_type>(
121-
((signal_ - CANTemplateGetFloat(offset)) / CANTemplateGetFloat(factor)))
145+
((this->signal_ - CANTemplateGetFloat(offset)) / CANTemplateGetFloat(factor)))
122146
<< position)
123147
& mask;
124148
}
@@ -127,7 +151,7 @@ class CANSignal : public ICANSignal
127151
uint8_t temp_reversed_buffer[8]{0};
128152
*reinterpret_cast<underlying_type *>(temp_reversed_buffer) |=
129153
(static_cast<underlying_type>(
130-
((signal_ - CANTemplateGetFloat(offset)) / CANTemplateGetFloat(factor)))
154+
((this->signal_ - CANTemplateGetFloat(offset)) / CANTemplateGetFloat(factor)))
131155
<< (64 - (position + length)));
132156
std::reverse(std::begin(temp_reversed_buffer), std::end(temp_reversed_buffer));
133157
*buffer |= *reinterpret_cast<underlying_type *>(temp_reversed_buffer) & mask;
@@ -139,29 +163,29 @@ class CANSignal : public ICANSignal
139163
{
140164
if (unity_factor)
141165
{
142-
if (byte_order == ByteOrder::kLittleEndian)
166+
if (byte_order == ICANSignal::ByteOrder::kLittleEndian)
143167
{
144168
uint8_t temp_buffer[8]{0};
145169
*reinterpret_cast<underlying_type *>(temp_buffer) = *buffer & mask;
146-
signal_ = static_cast<SignalType>(
170+
this->signal_ = static_cast<SignalType>(
147171
(*reinterpret_cast<underlying_type *>(temp_buffer)) << (64 - (position + length)) >> (64 - length));
148172
}
149173
else
150174
{
151175
uint8_t temp_buffer[8]{0};
152176
*reinterpret_cast<underlying_type *>(temp_buffer) = *buffer & mask;
153177
std::reverse(std::begin(temp_buffer), std::end(temp_buffer));
154-
signal_ = static_cast<SignalType>((*reinterpret_cast<underlying_type *>(temp_buffer)) << position
155-
>> (64 - length));
178+
this->signal_ = static_cast<SignalType>((*reinterpret_cast<underlying_type *>(temp_buffer)) << position
179+
>> (64 - length));
156180
}
157181
}
158182
else
159183
{
160-
if (byte_order == ByteOrder::kLittleEndian)
184+
if (byte_order == ICANSignal::ByteOrder::kLittleEndian)
161185
{
162186
uint8_t temp_buffer[8]{0};
163187
*reinterpret_cast<underlying_type *>(temp_buffer) = *buffer & mask;
164-
signal_ = static_cast<SignalType>(
188+
this->signal_ = static_cast<SignalType>(
165189
(((*reinterpret_cast<underlying_type *>(temp_buffer)) << (64 - (position + length))
166190
>> (64 - length))
167191
* CANTemplateGetFloat(factor))
@@ -172,22 +196,15 @@ class CANSignal : public ICANSignal
172196
uint8_t temp_buffer[8]{0};
173197
*reinterpret_cast<underlying_type *>(temp_buffer) = *buffer & mask;
174198
std::reverse(std::begin(temp_buffer), std::end(temp_buffer));
175-
signal_ = static_cast<SignalType>(
199+
this->signal_ = static_cast<SignalType>(
176200
(((*reinterpret_cast<underlying_type *>(temp_buffer)) << position >> (64 - length))
177201
* CANTemplateGetFloat(factor))
178202
+ CANTemplateGetFloat(offset));
179203
}
180204
}
181205
}
182206

183-
SignalType &value_ref() { return signal_; }
184-
185-
void operator=(const SignalType &signal) { signal_ = signal; }
186-
187-
operator SignalType() const { return signal_; }
188-
189-
private:
190-
SignalType signal_;
207+
void operator=(const SignalType &signal) { ITypedCANSignal<SignalType>::operator=(signal); }
191208
};
192209

193210
// Macros for making signed and unsigned little-endian CAN signals

test/test_main.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,27 @@ void BigEndianCanSignalTest(void)
6969
TEST_ASSERT_EQUAL_HEX16(0xFF00, test_signal);
7070
}
7171

72+
void TypedCanSignalTest(void)
73+
{
74+
CANSignal<uint8_t, 0, 8, CANTemplateConvertFloat(1), 0> actual_test_signal;
75+
ITypedCANSignal<uint8_t>& test_signal = actual_test_signal;
76+
test_signal = 0;
77+
uint64_t test_buf{0};
78+
test_signal.EncodeSignal(&test_buf);
79+
TEST_ASSERT_EQUAL_HEX64(0, test_buf);
80+
test_signal = 0xFF;
81+
TEST_ASSERT_EQUAL_HEX16(0xFF, test_signal);
82+
test_signal.EncodeSignal(&test_buf);
83+
TEST_ASSERT_EQUAL_HEX64(0xFF, test_buf);
84+
}
85+
7286
int runUnityTests(void)
7387
{
7488
UNITY_BEGIN();
7589
RUN_TEST(CanSignalTest);
7690
RUN_TEST(BigEndianCanSignalTest);
7791
RUN_TEST(SignedCanSignalTest);
92+
RUN_TEST(TypedCanSignalTest);
7893
return UNITY_END();
7994
}
8095

0 commit comments

Comments
 (0)