Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up encoders #337

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions include/radio/rmt/CaiXianlinEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@

namespace OpenShock::Rmt::CaiXianlinEncoder {
size_t GetBufferSize();
bool FillBuffer(rmt_data_t* data, uint16_t shockerId, uint8_t channelId, ShockerCommandType type, uint8_t intensity);
}
uint64_t MakePayload(uint16_t shockerId, uint8_t channel, ShockerCommandType type, uint8_t intensity);
void EncodePayload(rmt_data_t* data, uint64_t payload);
} // namespace OpenShock::Rmt::CaiXianlinEncoder
12 changes: 0 additions & 12 deletions include/radio/rmt/Petrainer998DREncoder.h

This file was deleted.

6 changes: 4 additions & 2 deletions include/radio/rmt/PetrainerEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@

namespace OpenShock::Rmt::PetrainerEncoder {
size_t GetBufferSize();
bool FillBuffer(rmt_data_t* data, uint16_t shockerId, ShockerCommandType type, uint8_t intensity);
}
uint64_t MakePayload(uint16_t shockerId, uint8_t channel, ShockerCommandType type, uint8_t intensity);
void EncodeType1Payload(rmt_data_t* data, uint64_t payload);
void EncodeType2Payload(rmt_data_t* data, uint64_t payload);
} // namespace OpenShock::Rmt::PetrainerEncoder
5 changes: 3 additions & 2 deletions include/radio/rmt/T330Encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@

namespace OpenShock::Rmt::T330Encoder {
size_t GetBufferSize();
bool FillBuffer(rmt_data_t* data, uint16_t shockerId, ShockerCommandType type, uint8_t intensity);
}
uint64_t MakePayload(uint16_t shockerId, uint8_t channel, ShockerCommandType type, uint8_t intensity);
void EncodePayload(rmt_data_t* data, uint64_t payload);
} // namespace OpenShock::Rmt::T330Encoder
2 changes: 1 addition & 1 deletion include/radio/rmt/internal/Shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace OpenShock::Rmt::Internal {
template<size_t N, typename T>
constexpr void EncodeBits(rmt_data_t* sequence, T data, const rmt_data_t& rmtOne, const rmt_data_t& rmtZero)
constexpr void EncodeBits(rmt_data_t* sequence, T data, rmt_data_t rmtOne, rmt_data_t rmtZero)
{
static_assert(std::is_unsigned<T>::value, "T must be an unsigned integer");
static_assert(N > 0, "N must be greater than 0");
Expand Down
24 changes: 12 additions & 12 deletions src/radio/rmt/CaiXianlinEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,8 @@ size_t Rmt::CaiXianlinEncoder::GetBufferSize()
return 44;
}

bool Rmt::CaiXianlinEncoder::FillBuffer(rmt_data_t* sequence, uint16_t shockerId, uint8_t channelId, ShockerCommandType type, uint8_t intensity)
uint64_t Rmt::CaiXianlinEncoder::MakePayload(uint16_t shockerId, uint8_t channel, ShockerCommandType type, uint8_t intensity)
{
// Intensity must be between 0 and 99
intensity = std::min(intensity, static_cast<uint8_t>(99));

uint8_t typeVal = 0;
switch (type) {
case ShockerCommandType::Shock:
Expand All @@ -40,11 +37,14 @@ bool Rmt::CaiXianlinEncoder::FillBuffer(rmt_data_t* sequence, uint16_t shockerId
intensity = 0; // Sound intensity must be 0 for some shockers, otherwise it wont work, or they soft lock until restarted
break;
default:
return false; // Invalid type
return 0; // Invalid type
}

// Payload layout: [shockerId:16][channelId:4][type:4][intensity:8]
uint32_t payload = (static_cast<uint32_t>(shockerId) << 16) | (static_cast<uint32_t>(channelId & 0xF) << 12) | (static_cast<uint32_t>(typeVal & 0xF) << 8) | static_cast<uint32_t>(intensity);
// Intensity must be between 0 and 99
intensity = std::min(intensity, static_cast<uint8_t>(99));

// Payload layout: [shockerId:16][channel:4][type:4][intensity:8]
uint32_t payload = (static_cast<uint32_t>(shockerId) << 16) | (static_cast<uint32_t>(channel & 0xF) << 12) | (static_cast<uint32_t>(typeVal) << 8) | static_cast<uint32_t>(intensity);

// Calculate the checksum of the payload
uint8_t checksum = Checksum::Sum8(payload);
Expand All @@ -53,11 +53,11 @@ bool Rmt::CaiXianlinEncoder::FillBuffer(rmt_data_t* sequence, uint16_t shockerId
uint64_t data = (static_cast<uint64_t>(payload) << 8) | static_cast<uint64_t>(checksum);

// Shift the data left by 3 bits to add the postamble (3 bits of 0)
data <<= 3;
return data << 3;
}

// Generate the sequence
void Rmt::CaiXianlinEncoder::EncodePayload(rmt_data_t* sequence, uint64_t payload)
{
sequence[0] = kRmtPreamble;
Rmt::Internal::EncodeBits<43>(sequence + 1, data, kRmtOne, kRmtZero);

return true;
Rmt::Internal::EncodeBits<43>(sequence + 1, payload, kRmtOne, kRmtZero);
}
35 changes: 30 additions & 5 deletions src/radio/rmt/MainEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const char* const TAG = "RmtMainEncoder";

#include "Logging.h"
#include "radio/rmt/CaiXianlinEncoder.h"
#include "radio/rmt/Petrainer998DREncoder.h"
#include "radio/rmt/PetrainerEncoder.h"
#include "radio/rmt/T330Encoder.h"

Expand All @@ -16,7 +15,6 @@ static size_t getSequenceBufferSize(ShockerModelType shockerModelType)
case ShockerModelType::CaiXianlin:
return Rmt::CaiXianlinEncoder::GetBufferSize();
case ShockerModelType::Petrainer998DR:
return Rmt::Petrainer998DREncoder::GetBufferSize();
case ShockerModelType::Petrainer:
return Rmt::PetrainerEncoder::GetBufferSize();
default:
Expand All @@ -39,11 +37,38 @@ bool Rmt::MainEncoder::fillSequence(ShockerCommandType commandType, uint8_t inte
{
switch (m_shockerModel) {
case ShockerModelType::CaiXianlin:
return Rmt::CaiXianlinEncoder::FillBuffer(m_data, m_shockerId, 0, commandType, intensity) && Rmt::CaiXianlinEncoder::FillBuffer(m_data + m_size, m_shockerId, 0, ShockerCommandType::Vibrate, 0);
{
uint64_t payload = Rmt::CaiXianlinEncoder::MakePayload(m_shockerId, 0, commandType, intensity);
uint64_t terminator = Rmt::CaiXianlinEncoder::MakePayload(m_shockerId, 0, ShockerCommandType::Vibrate, 0);
if (payload == 0 || terminator == 0) return false;

Rmt::CaiXianlinEncoder::EncodePayload(m_data, payload);
Rmt::CaiXianlinEncoder::EncodePayload(m_data + m_size, terminator);

return true;
}
case ShockerModelType::Petrainer:
return Rmt::PetrainerEncoder::FillBuffer(m_data, m_shockerId, commandType, intensity) && Rmt::PetrainerEncoder::FillBuffer(m_data + m_size, m_shockerId, ShockerCommandType::Vibrate, 0);
case ShockerModelType::Petrainer998DR:
return Rmt::Petrainer998DREncoder::FillBuffer(m_data, m_shockerId, commandType, intensity) && Rmt::Petrainer998DREncoder::FillBuffer(m_data + m_size, m_shockerId, ShockerCommandType::Vibrate, 0);
{
uint64_t payload = Rmt::PetrainerEncoder::MakePayload(m_shockerId, 1, commandType, intensity);
uint64_t terminator = Rmt::PetrainerEncoder::MakePayload(m_shockerId, 1, ShockerCommandType::Vibrate, 0);
if (payload == 0 || terminator == 0) return false;

switch (m_shockerModel) {
case ShockerModelType::Petrainer:
Rmt::PetrainerEncoder::EncodeType1Payload(m_data, payload);
Rmt::PetrainerEncoder::EncodeType1Payload(m_data + m_size, terminator);
break;
case ShockerModelType::Petrainer998DR:
Rmt::PetrainerEncoder::EncodeType2Payload(m_data, payload);
Rmt::PetrainerEncoder::EncodeType2Payload(m_data + m_size, terminator);
break;
default:
return false;
}

return true;
}
default:
OS_LOGE(TAG, "Unknown shocker model: %u", m_shockerModel);
return false;
Expand Down
61 changes: 0 additions & 61 deletions src/radio/rmt/Petrainer998DREncoder.cpp

This file was deleted.

76 changes: 53 additions & 23 deletions src/radio/rmt/PetrainerEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@

#include "radio/rmt/internal/Shared.h"

#include "Checksum.h"

#include <algorithm>

const rmt_data_t kRmtPreamble = {750, 1, 750, 0};
const rmt_data_t kRmtOne = {200, 1, 1500, 0};
const rmt_data_t kRmtZero = {200, 1, 750, 0};
const rmt_data_t kRmtPostamble = {200, 1, 7000, 0};
// Base
const rmt_data_t kV1RmtPreamble = {750, 1, 750, 0};
const rmt_data_t kV1RmtOne = {200, 1, 1500, 0};
const rmt_data_t kV1RmtZero = {200, 1, 750, 0};
const rmt_data_t kV1RmtPostamble = {200, 1, 7000, 0};

// 998DR Type 1
const rmt_data_t kV2RmtPreamble = {1500, 1, 750, 0};
const rmt_data_t kV2RmtOne = {750, 1, 250, 0};
const rmt_data_t kV2RmtZero = {250, 1, 750, 0};
const rmt_data_t kV2RmtPostamble = {250, 1, 3750, 0}; // Some subvariants expect a quiet period between commands, this is a last 1 bit followed by a very long pause

using namespace OpenShock;

Expand All @@ -16,39 +25,60 @@ size_t Rmt::PetrainerEncoder::GetBufferSize()
return 42;
}

bool Rmt::PetrainerEncoder::FillBuffer(rmt_data_t* sequence, uint16_t shockerId, ShockerCommandType type, uint8_t intensity)
uint64_t Rmt::PetrainerEncoder::MakePayload(uint16_t shockerId, uint8_t channel, ShockerCommandType type, uint8_t intensity)
{
// Intensity must be between 0 and 100
intensity = std::min(intensity, static_cast<uint8_t>(100));

uint8_t nShift = 0;
uint8_t typeVal = 0;
switch (type) {
case ShockerCommandType::Shock:
nShift = 0;
typeVal = 0b0001;
break;
case ShockerCommandType::Vibrate:
nShift = 1;
typeVal = 0b0010;
break;
case ShockerCommandType::Sound:
nShift = 2;
typeVal = 0b0100;
break;
case ShockerCommandType::Light:
typeVal = 0b1000;
break;
default:
return 0; // Invalid command type
}

uint8_t channelVal = 0;
switch (channel) {
case 1:
typeVal = 0b1000;
break;
case 2:
typeVal = 0b1111;
break;
default:
return false; // Invalid type
return 0; // Invalid channel
}

// Type is 0x80 | (0x01 << nShift)
uint8_t typeVal = (0x80 | (0x01 << nShift)) & 0xFF;
// Intensity must be between 0 and 100
intensity = std::min(intensity, static_cast<uint8_t>(100));

// TypeSum is NOT(0x01 | (0x80 >> nShift))
uint8_t typeSum = (~(0x01 | (0x80 >> nShift))) & 0xFF;
uint8_t channelInvert = Checksum::ReverseInverseNibble(channelVal);
uint8_t typeInvert = Checksum::ReverseInverseNibble(typeVal);

// Payload layout: [methodBit:8][shockerId:16][intensity:8][methodChecksum:8]
uint64_t data = (static_cast<uint64_t>(typeVal) << 32) | (static_cast<uint64_t>(shockerId) << 16) | (static_cast<uint64_t>(intensity) << 8) | static_cast<uint64_t>(typeSum);
// Payload layout: [channel:4][type:4][shockerID:16][intensity:8][typeInvert:4][channelInvert:4] (40 bits)
return static_cast<uint64_t>(channelVal) << 36 | static_cast<uint64_t>(typeVal) << 32 | static_cast<uint64_t>(shockerId) << 16 | static_cast<uint64_t>(intensity) << 8 | static_cast<uint64_t>(typeInvert) << 4 | static_cast<uint64_t>(channelInvert);
}

void Rmt::PetrainerEncoder::EncodeType1Payload(rmt_data_t* sequence, uint64_t payload)
{
// Generate the sequence
sequence[0] = kRmtPreamble;
Rmt::Internal::EncodeBits<40>(sequence + 1, data, kRmtOne, kRmtZero);
sequence[41] = kRmtPostamble;
sequence[0] = kV1RmtPreamble;
Rmt::Internal::EncodeBits<40>(sequence + 1, payload, kV1RmtOne, kV1RmtZero);
sequence[41] = kV1RmtPostamble;
}

return true;
void Rmt::PetrainerEncoder::EncodeType2Payload(rmt_data_t* sequence, uint64_t payload)
{
// Generate the sequence
sequence[0] = kV2RmtPreamble;
Rmt::Internal::EncodeBits<40>(sequence + 1, payload, kV2RmtOne, kV2RmtZero);
sequence[41] = kV2RmtPostamble;
}
38 changes: 24 additions & 14 deletions src/radio/rmt/T330Encoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@ size_t Rmt::T330Encoder::GetBufferSize()
return 43;
}

bool Rmt::T330Encoder::FillBuffer(rmt_data_t* sequence, uint16_t shockerId, ShockerCommandType type, uint8_t intensity)
uint64_t Rmt::T330Encoder::MakePayload(uint16_t shockerId, uint8_t channel, ShockerCommandType type, uint8_t intensity)
{
// Intensity must be between 0 and 100
intensity = std::min(intensity, static_cast<uint8_t>(100));

uint8_t typeVal = 0;
switch (type) {
case ShockerCommandType::Shock:
Expand All @@ -34,22 +31,35 @@ bool Rmt::T330Encoder::FillBuffer(rmt_data_t* sequence, uint16_t shockerId, Shoc
intensity = 0; // The remote always sends 0, I don't know what happens if you send something else.
break;
default:
return false; // Invalid type
return 0; // Invalid type
}

uint8_t channelId = 0; // CH1 is 0b0000 and CH2 is 0b1110 on my remote but other values probably work.
uint8_t channelVal = 0; // CH1 is 0b0000 and CH2 is 0b1110 on my remote but other values probably work.
switch (channel) {
case 1:
channelVal = 0b0000;
break;
case 2:
channelVal = 0b1110;
break;
default:
return 0; // Invalid channel
}

// Payload layout: [channelId:4][typeU:4][transmitterId:16][intensity:8][typeL:4][channelId:4]
uint64_t data = (static_cast<uint64_t>(channelId & 0xF) << 36) | (static_cast<uint64_t>(typeVal & 0xF0) << 28) | (static_cast<uint64_t>(shockerId) << 16) | (static_cast<uint64_t>(intensity) << 8) | (static_cast<uint64_t>(typeVal & 0xF) << 4)
| static_cast<uint64_t>(channelId & 0xF);
// Intensity must be between 0 and 100
intensity = std::min(intensity, static_cast<uint8_t>(100));

// Payload layout: [channel:4][typeU:4][transmitterId:16][intensity:8][typeL:4][channel:4]
uint64_t payload = (static_cast<uint64_t>(channelVal) << 36) | (static_cast<uint64_t>(typeVal & 0xF0) << 28) | (static_cast<uint64_t>(shockerId) << 16) | (static_cast<uint64_t>(intensity) << 8) | (static_cast<uint64_t>(typeVal & 0xF) << 4)
| static_cast<uint64_t>(channelVal);

// Shift the data left by 1 bit to append a zero
data <<= 1;
return payload << 1;
}

// Generate the sequence
void Rmt::T330Encoder::EncodePayload(rmt_data_t* sequence, uint64_t payload)
{
sequence[0] = kRmtPreamble;
Rmt::Internal::EncodeBits<41>(sequence + 1, data, kRmtOne, kRmtZero);
Rmt::Internal::EncodeBits<41>(sequence + 1, payload, kRmtOne, kRmtZero);
sequence[42] = kRmtPostamble;

return true;
}
Loading