Skip to content
Open
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
104 changes: 104 additions & 0 deletions src/modules/rf/protocols/decoders/manchester_helpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// Manchester decode helpers ported from Flipper Zero firmware
// (GPL-3.0-or-later), lib/subghz/blocks/decoder.c / manchester_advance.
#include "manchester_helpers.h"

static inline unsigned int mh_diff(unsigned int a, unsigned int b) {
return (a > b) ? (a - b) : (b - a);
}

void manchester_reset(ManchesterState &s) {
s.state = 0;
}

bool manchester_advance(ManchesterState &s, ManchesterEvent event, bool *data) {
bool result = false;
*data = false;

switch (s.state) {
case 0: // Start
switch (event) {
case ManchesterEventShortHigh:
s.state = 1; // MidBit
break;
case ManchesterEventShortLow:
s.state = 1; // MidBit
break;
case ManchesterEventLongHigh:
*data = true;
result = true;
break;
case ManchesterEventLongLow:
*data = true;
result = true;
break;
default:
break;
}
break;

case 1: // MidBit
switch (event) {
case ManchesterEventShortLow:
s.state = 2; // Done
break;
case ManchesterEventShortHigh:
s.state = 2; // Done
break;
case ManchesterEventLongLow:
*data = false;
result = true;
break;
case ManchesterEventLongHigh:
*data = false;
result = true;
break;
default:
break;
}
break;

case 2: // Done
switch (event) {
case ManchesterEventShortLow:
*data = true;
result = true;
s.state = 0;
break;
case ManchesterEventShortHigh:
s.state = 0;
break;
case ManchesterEventLongLow:
*data = false;
result = true;
s.state = 0;
break;
case ManchesterEventLongHigh:
s.state = 0;
break;
default:
break;
}
break;
}

return result;
}

ManchesterEvent manchester_event_for(bool level, unsigned int dur,
unsigned int te_short, unsigned int te_long,
unsigned int te_delta) {
if (!level) {
if (mh_diff(dur, te_short) < te_delta)
return ManchesterEventShortLow;
if (mh_diff(dur, te_long) < te_delta)
return ManchesterEventLongLow;
} else {
if (mh_diff(dur, te_short) < te_delta)
return ManchesterEventShortHigh;
if (mh_diff(dur, te_long) < te_delta)
return ManchesterEventLongHigh;
}
return ManchesterEventReset;
}
32 changes: 32 additions & 0 deletions src/modules/rf/protocols/decoders/manchester_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <stdint.h>
#include <vector>

// Manchester event types (mirrors Flipper Zero lib/subghz/blocks/const.h).
enum ManchesterEvent : uint8_t {
ManchesterEventReset = 0,
ManchesterEventShortLow,
ManchesterEventShortHigh,
ManchesterEventLongLow,
ManchesterEventLongHigh,
};

// Manchester decoder state (mirrors Flipper manchester_advance).
struct ManchesterState {
uint8_t state = 0; // 0=start, 1=mid_bit, 2=done
};

// Reset the Manchester state machine.
void manchester_reset(ManchesterState &s);

// Feed one event to the Manchester decoder. When a complete bit is decoded,
// sets `*data` to the bit value and returns true. Returns false when more
// events are needed.
bool manchester_advance(ManchesterState &s, ManchesterEvent event, bool *data);

// Map a (level, unsigned duration, te_short, te_long, te_delta) quad to a
// ManchesterEvent. Returns ManchesterEventReset if the duration doesn't match.
ManchesterEvent manchester_event_for(bool level, unsigned int dur,
unsigned int te_short, unsigned int te_long,
unsigned int te_delta);
90 changes: 90 additions & 0 deletions src/modules/rf/protocols/decoders/rf_decoder_bett.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
#include "rf_decoder_bett.h"
#include "../rf_config.h"

#define BETT_TE_SHORT 340
#define BETT_TE_LONG 2000
#define BETT_TE_DELTA 150
#define BETT_MIN_BITS 18

static inline unsigned int bett_diff(unsigned int a, unsigned int b) {
return (a > b) ? (a - b) : (b - a);
}

bool rf_decode_bett(const std::vector<int>& durations, RfCodes& out) {
if (durations.size() < 4) return false;

enum { ST_RESET, ST_CHECK, ST_DATA } step = ST_RESET;
uint64_t data = 0;
int bits = 0;

for (int raw : durations) {
bool level = raw > 0;
unsigned int dur = (unsigned int)(raw > 0 ? raw : -raw);

switch (step) {
case ST_RESET:
if (!level && bett_diff(dur, BETT_TE_SHORT * 44) < BETT_TE_DELTA * 15) {
data = 0; bits = 0;
step = ST_CHECK;
}
break;

case ST_CHECK:
if (level) {
if (bett_diff(dur, BETT_TE_LONG) < BETT_TE_DELTA * 3) {
data = (data << 1) | 1ULL;
bits++;
step = ST_DATA;
} else if (bett_diff(dur, BETT_TE_SHORT) < BETT_TE_DELTA) {
data = (data << 1) | 0ULL;
bits++;
step = ST_DATA;
} else {
step = ST_RESET;
}
} else {
step = ST_RESET;
}
break;

case ST_DATA:
if (!level) {
if (bett_diff(dur, BETT_TE_SHORT * 44) < BETT_TE_DELTA * 15) {
if (bits == BETT_MIN_BITS) {
out.key = data;
out.Bit = BETT_MIN_BITS;
out.te = BETT_TE_SHORT;
out.protocol = "Bett";
out.preset = "Ook270Async";
return true;
}
data = 0; bits = 0;
step = ST_CHECK;
} else if (bett_diff(dur, BETT_TE_SHORT) < BETT_TE_DELTA ||
bett_diff(dur, BETT_TE_LONG) < BETT_TE_DELTA * 3) {
step = ST_CHECK;
} else {
step = ST_RESET;
}
}
break;
}
}

return false;
}

bool rf_encode_bett(const RfCodes& in, std::vector<int>& out) {
if (in.Bit != BETT_MIN_BITS) return false;
for (int i = in.Bit - 1; i >= 0; i--) {
if ((in.key >> i) & 1ULL) {
out.push_back(BETT_TE_LONG);
out.push_back(-BETT_TE_SHORT);
} else {
out.push_back(BETT_TE_SHORT);
out.push_back(-BETT_TE_LONG);
}
}
return true;
}
6 changes: 6 additions & 0 deletions src/modules/rf/protocols/decoders/rf_decoder_bett.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once
#include <vector>
#include "../rf_protocol.h"

bool rf_decode_bett(const std::vector<int>& durations, RfCodes& out);
bool rf_encode_bett(const RfCodes& in, std::vector<int>& out);
142 changes: 142 additions & 0 deletions src/modules/rf/protocols/decoders/rf_decoder_came_atomo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
#include "rf_decoder_came_atomo.h"
#include "../rf_config.h"

#define CA_TE_SHORT 600
#define CA_TE_LONG 1200
#define CA_TE_DELTA 250
#define CA_MIN_BITS 62

static inline unsigned int ca_diff(unsigned int a, unsigned int b) {
return (a > b) ? (a - b) : (b - a);
}

typedef enum { ME_RESET, ME_LOW, ME_HIGH } manchester_state;

static bool manchester_advance(manchester_state& state, bool high_pulse, bool& bit) {
switch (state) {
case ME_RESET:
state = high_pulse ? ME_HIGH : ME_LOW;
return false;
case ME_LOW:
if (high_pulse) { state = ME_HIGH; return false; }
bit = 1; state = ME_LOW; return true;
case ME_HIGH:
if (!high_pulse) { state = ME_LOW; return false; }
bit = 0; state = ME_HIGH; return true;
}
return false;
}

static void manchester_reset(manchester_state& state) {
state = ME_RESET;
}

static const uint64_t ca_default_xor[32] = {
0x1fafef3ed0f7d9efULL, 0x185fcc1531ee86e7ULL, 0x184fa96912c567ffULL, 0x187f8a42f3dc38f7ULL,
0x186f63915492a5cdULL, 0x181f40bab58bfac5ULL, 0x180f25c696a01bddULL, 0x183f06ed77b944d5ULL,
0x182ef661d83d21a9ULL, 0x18ded54a39247ea1ULL, 0x18ceb0361a0f9fb9ULL, 0x18fe931dfb16c0b1ULL,
0x18ee7ace5c585d8bULL, 0x181e59e5bd410283ULL, 0x180e3c999e6ae39bULL, 0x183e1fb27f73bc93ULL,
0x184fcc1531ee86e7ULL, 0x18bfef3ed0f7d9efULL, 0x18af8a42f3dc38f7ULL, 0x189fa96912c567ffULL,
0x188f63915492a5cdULL, 0x187f40bab58bfac5ULL, 0x186f25c696a01bddULL, 0x185f06ed77b944d5ULL,
0x182ef661d83d21a9ULL, 0x18ded54a39247ea1ULL, 0x18ceb0361a0f9fb9ULL, 0x18fe931dfb16c0b1ULL,
0x18ee7ace5c585d8bULL, 0x181e59e5bd410283ULL, 0x180e3c999e6ae39bULL, 0x183e1fb27f73bc93ULL,
};

bool rf_decode_came_atomo(const std::vector<int>& durations, RfCodes& out) {
if (durations.size() < 4) return false;

enum { ST_RESET, ST_DATA } step = ST_RESET;
uint64_t data = 0;
int bits = 0;
manchester_state man_state;

for (int raw : durations) {
bool level = raw > 0;
unsigned int dur = (unsigned int)(raw > 0 ? raw : -raw);

switch (step) {
case ST_RESET:
if (!level && ca_diff(dur, CA_TE_LONG * 60) < CA_TE_DELTA * 40) {
data = 0; bits = 1;
manchester_reset(man_state);
bool dummy = false;
manchester_advance(man_state, false, dummy);
step = ST_DATA;
}
break;

case ST_DATA: {
if (!level) {
if (ca_diff(dur, CA_TE_SHORT) < CA_TE_DELTA) {
bool bit_out = false;
if (manchester_advance(man_state, false, bit_out)) {
data = (data << 1) | (bit_out ? 0ULL : 1ULL);
bits++;
}
} else if (ca_diff(dur, CA_TE_LONG) < CA_TE_DELTA) {
bool bit_out = false;
if (manchester_advance(man_state, false, bit_out)) {
data = (data << 1) | (bit_out ? 0ULL : 1ULL);
bits++;
}
} else if (dur >= (uint32_t)(CA_TE_LONG * 2 + CA_TE_DELTA)) {
if (bits == CA_MIN_BITS) {
uint16_t parcel_counter = (uint16_t)(data >> 48);
parcel_counter = parcel_counter ^ 0x185F;
parcel_counter >>= 4;
uint8_t ind = (parcel_counter + 1) % 32;
uint64_t temp_data = data & 0x0000FFFFFFFFFFFFULL;
uint64_t magic = ca_default_xor[ind];

temp_data = temp_data ^ magic;
uint32_t cnt = (uint32_t)(temp_data >> 36);
uint32_t serial = (uint32_t)((temp_data >> 4) & 0x000FFFFFFFFULL);
uint8_t btn = (uint8_t)(temp_data & 0xF);

out.key = data;
out.Bit = CA_MIN_BITS;
out.te = CA_TE_SHORT;
out.protocol = "CAME_Atomo";
out.preset = "Ook270Async";
out.serial = serial;
out.cnt = cnt;
out.btn = btn;
return true;
}
data = 0; bits = 1;
manchester_reset(man_state);
bool dummy = false;
manchester_advance(man_state, false, dummy);
} else {
step = ST_RESET;
}
} else {
if (ca_diff(dur, CA_TE_SHORT) < CA_TE_DELTA) {
bool bit_out = false;
if (manchester_advance(man_state, true, bit_out)) {
data = (data << 1) | (bit_out ? 0ULL : 1ULL);
bits++;
}
} else if (ca_diff(dur, CA_TE_LONG) < CA_TE_DELTA) {
bool bit_out = false;
if (manchester_advance(man_state, true, bit_out)) {
data = (data << 1) | (bit_out ? 0ULL : 1ULL);
bits++;
}
} else {
step = ST_RESET;
}
}
break;
}
}
}

return false;
}

bool rf_encode_came_atomo(const RfCodes& in, std::vector<int>& out) {
(void)in; (void)out;
return false;
}
7 changes: 7 additions & 0 deletions src/modules/rf/protocols/decoders/rf_decoder_came_atomo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include <vector>
#include "../rf_protocol.h"

bool rf_decode_came_atomo(const std::vector<int>& durations, RfCodes& out);
bool rf_encode_came_atomo(const RfCodes& in, std::vector<int>& out);
Loading
Loading