Skip to content

Commit

Permalink
Clean up encoders
Browse files Browse the repository at this point in the history
Merge petrainer encoders
  • Loading branch information
hhvrc committed Jan 22, 2025
1 parent 4793d97 commit 5b415a2
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 132 deletions.
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
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 & 0xF) << 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;
}
36 changes: 23 additions & 13 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 @@ -37,19 +34,32 @@ bool Rmt::T330Encoder::FillBuffer(rmt_data_t* sequence, uint16_t shockerId, Shoc
return false; // 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 false; // 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 & 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>(channelVal & 0xF);

// 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;
}

0 comments on commit 5b415a2

Please # to comment.