mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-21 06:59:02 +00:00
Add Superrollo (GW60/HCS361) TX and RX (#3290)
keeloqtx: Superrollo 67-bit transmit mode with rolling counter. subghzd: GW60 receive decoder (reports as KeeLoq; manufacturer key read from KEELOQKEYS/MFCODES). The manufacturer key is not included; add a Superrollo entry to MFCODES to enable TX/RX.
This commit is contained in:
@@ -74,7 +74,7 @@ void SubGhzDRecentEntryDetailView::update_data() {
|
||||
console.writeln("Action: 0x" + to_string_hex(func_code));
|
||||
}
|
||||
|
||||
if (entry_.sensorType == FPS_KEELOQ) {
|
||||
if (entry_.sensorType == FPS_KEELOQ || entry_.sensorType == FPS_SUPERROLLO) {
|
||||
console.writeln("Fix: " + to_string_hex(fix));
|
||||
console.writeln("Encrypted: " + to_string_hex(encrypted));
|
||||
console.writeln("Manufacturer: " + mf_name);
|
||||
@@ -243,6 +243,8 @@ const char* SubGhzDView::getSensorTypeName(FPROTO_SUBGHZD_SENSOR type) {
|
||||
return "Ido 11x";
|
||||
case FPS_INTERTECHNOV3:
|
||||
return "InterTehcno v3";
|
||||
case FPS_SUPERROLLO:
|
||||
return "Superrollo";
|
||||
case FPS_KEELOQ:
|
||||
return "KeeLoq";
|
||||
case FPS_KINGGATESSTYLO4K:
|
||||
@@ -671,7 +673,7 @@ void SubGhzDRecentEntryDetailView::parseProtocol() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry_.sensorType == FPS_KEELOQ) {
|
||||
if (entry_.sensorType == FPS_KEELOQ || entry_.sensorType == FPS_SUPERROLLO) {
|
||||
uint64_t data_rev = FProtoGeneral::subghz_protocol_blocks_reverse_key(entry_.data, 64);
|
||||
|
||||
btn = data_rev >> 60;
|
||||
|
||||
+38
-2
@@ -34,7 +34,7 @@ void KeeloqTXView::update_hop() {
|
||||
|
||||
hop = data.btn << 28 | (apri_serial & 0xFFF) << 16 | data.counter;
|
||||
} else if (
|
||||
data.mf_name == "DTM_Neo" || data.mf_name == "FAAC_RC,XT" || data.mf_name == "Mutanco_Mutancode" || data.mf_name == "Came_Space" || data.mf_name == "Genius_Bravo" || data.mf_name == "GSN" || data.mf_name == "Rosh" || data.mf_name == "Rossi" || data.mf_name == "Peccinin" || data.mf_name == "Steelmate" || data.mf_name == "Cardin_S449") {
|
||||
data.mf_name == "DTM_Neo" || data.mf_name == "FAAC_RC,XT" || data.mf_name == "Mutanco_Mutancode" || data.mf_name == "Came_Space" || data.mf_name == "Genius_Bravo" || data.mf_name == "GSN" || data.mf_name == "Rosh" || data.mf_name == "Rossi" || data.mf_name == "Peccinin" || data.mf_name == "Steelmate" || data.mf_name == "Cardin_S449" || data.mf_name == "Superrollo") {
|
||||
hop = data.btn << 28 | (data.serial & 0xFFF) << 16 | data.counter;
|
||||
} else if (
|
||||
data.mf_name == "NICE_Smilo" || data.mf_name == "NICE_MHOUSE" || data.mf_name == "JCM_Tech") {
|
||||
@@ -75,6 +75,12 @@ void KeeloqTXView::update_payload() {
|
||||
}
|
||||
}
|
||||
|
||||
if (data.mf_name == "Superrollo") {
|
||||
text_payload.set(to_string_hex((uint64_t)(uint32_t)encrypt));
|
||||
encode_data_gw60((uint32_t)encrypt);
|
||||
return;
|
||||
}
|
||||
|
||||
payload = (uint64_t)fix << 32 | encrypt;
|
||||
|
||||
uint64_t preview_payload = FProtoGeneral::subghz_protocol_blocks_reverse_key(payload, 64);
|
||||
@@ -83,6 +89,34 @@ void KeeloqTXView::update_payload() {
|
||||
encode_data();
|
||||
}
|
||||
|
||||
// Superrollo GW60 (HCS361) 67-bit OOK frame at Te=450us.
|
||||
void KeeloqTXView::encode_data_gw60(uint32_t hop_enc) {
|
||||
int bits[67];
|
||||
for (uint32_t i = 0; i < 32; i++) bits[i] = (hop_enc >> i) & 1;
|
||||
for (uint32_t i = 0; i < 28; i++) bits[32 + i] = (data.serial >> i) & 1;
|
||||
for (uint32_t i = 0; i < 4; i++) bits[60 + i] = (data.btn >> i) & 1;
|
||||
bits[64] = 1;
|
||||
|
||||
int crc0 = 0, crc1 = 0;
|
||||
for (uint32_t i = 0; i < 65; i++) {
|
||||
int new_crc1 = crc0 ^ bits[i];
|
||||
int new_crc0 = new_crc1 ^ crc1;
|
||||
crc0 = new_crc0 & 1;
|
||||
crc1 = new_crc1 & 1;
|
||||
}
|
||||
bits[65] = crc0;
|
||||
bits[66] = crc1;
|
||||
|
||||
std::string s{};
|
||||
for (int i = 0; i < 9; i++) s += "100";
|
||||
s += "11111111110000000000";
|
||||
for (int i = 0; i < 67; i++) s += keeloq_fragments[bits[i]];
|
||||
for (int i = 0; i < 18; i++) s += "0";
|
||||
|
||||
encoded_data = s;
|
||||
pause_duration = 0;
|
||||
}
|
||||
|
||||
void KeeloqTXView::encode_data() {
|
||||
std::string fragments{};
|
||||
|
||||
@@ -206,9 +240,11 @@ void KeeloqTXView::start_tx() {
|
||||
|
||||
transmitter_model.enable();
|
||||
|
||||
const double te_us = (data.mf_name == "Superrollo") ? 450.0 : 400.0;
|
||||
|
||||
baseband::set_ook_data(
|
||||
bitstream_length,
|
||||
OOK_SAMPLERATE * (400.0 / 1000000.0),
|
||||
OOK_SAMPLERATE * (te_us / 1000000.0),
|
||||
repeat,
|
||||
pause_duration);
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ class KeeloqTXView : public View {
|
||||
std::string encoded_data{};
|
||||
|
||||
void encode_data();
|
||||
void encode_data_gw60(uint32_t hop_enc);
|
||||
|
||||
uint32_t repeat = 4;
|
||||
uint32_t pause_duration = 0;
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
|
||||
#ifndef __FPROTO_SUPERROLLO_H__
|
||||
#define __FPROTO_SUPERROLLO_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
// Superrollo GW60 (HCS361) 67-bit OOK decoder. Reports FPS_SUPERROLLO; SubGhzD
|
||||
// treats FPS_SUPERROLLO like KeeLoq for decrypt/display (see ui_subghzd.cpp), so
|
||||
// the "Superrollo" keystore key decrypts it while it stays identifiable in logs.
|
||||
|
||||
typedef enum : uint8_t {
|
||||
SuperrolloStepReset = 0,
|
||||
SuperrolloStepPreambleLow,
|
||||
SuperrolloStepSyncLow,
|
||||
SuperrolloStepSaveDuration,
|
||||
SuperrolloStepCheckDuration,
|
||||
} SuperrolloDecoderStep;
|
||||
|
||||
class FProtoSubGhzDSuperrollo : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDSuperrollo() {
|
||||
sensorType = FPS_SUPERROLLO;
|
||||
te_short = 450;
|
||||
te_long = 900;
|
||||
te_delta = 200;
|
||||
min_count_bit_for_found = 64;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case SuperrolloStepReset:
|
||||
if (level) {
|
||||
if (DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
header_count++;
|
||||
parser_step = SuperrolloStepPreambleLow;
|
||||
} else if (
|
||||
(header_count >= 4) &&
|
||||
(DURATION_DIFF(duration, te_short * 10) < te_delta * 10)) {
|
||||
parser_step = SuperrolloStepSyncLow;
|
||||
} else {
|
||||
header_count = 0;
|
||||
}
|
||||
} else {
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SuperrolloStepPreambleLow:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
parser_step = SuperrolloStepReset;
|
||||
} else {
|
||||
parser_step = SuperrolloStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SuperrolloStepSyncLow:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 10) < te_delta * 10)) {
|
||||
parser_step = SuperrolloStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = SuperrolloStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SuperrolloStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = SuperrolloStepCheckDuration;
|
||||
} else if (duration >= te_short * 12) {
|
||||
endFrame();
|
||||
}
|
||||
break;
|
||||
|
||||
case SuperrolloStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
if (decode_count_bit < min_count_bit_for_found)
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
else
|
||||
decode_count_bit++;
|
||||
parser_step = SuperrolloStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
if (decode_count_bit < min_count_bit_for_found)
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
else
|
||||
decode_count_bit++;
|
||||
parser_step = SuperrolloStepSaveDuration;
|
||||
} else if (duration >= te_short * 12) {
|
||||
endFrame();
|
||||
} else {
|
||||
parser_step = SuperrolloStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
} else {
|
||||
parser_step = SuperrolloStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t header_count = 0;
|
||||
|
||||
private:
|
||||
void endFrame() {
|
||||
if ((decode_count_bit >= min_count_bit_for_found) &&
|
||||
(decode_count_bit <= min_count_bit_for_found + 3)) {
|
||||
data_count_bit = min_count_bit_for_found;
|
||||
if (callback) callback(this);
|
||||
}
|
||||
parser_step = SuperrolloStepReset;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
header_count = 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -29,6 +29,7 @@ So include here the .hpp, and add a new element to the protos vector in the cons
|
||||
#include "s-ido.hpp"
|
||||
#include "s-intertechnov3.hpp"
|
||||
#include "s-keeloq.hpp"
|
||||
#include "s-superrollo.hpp"
|
||||
#include "s-kinggates_stylo_4k.hpp"
|
||||
#include "s-linear.hpp"
|
||||
#include "s-linear_delta3.hpp"
|
||||
@@ -85,6 +86,7 @@ class SubGhzDProtos : public FProtoListGeneral {
|
||||
protos[FPS_IDO] = new FProtoSubGhzDIdo();
|
||||
protos[FPS_INTERTECHNOV3] = new FProtoSubGhzDIntertechnoV3();
|
||||
protos[FPS_KEELOQ] = new FProtoSubGhzDKeeLoq();
|
||||
protos[FPS_SUPERROLLO] = new FProtoSubGhzDSuperrollo();
|
||||
protos[FPS_KINGGATESSTYLO4K] = new FProtoSubGhzDKinggatesStylo4K();
|
||||
protos[FPS_LINEAR] = new FProtoSubGhzDLinear();
|
||||
protos[FPS_LINEARDELTA3] = new FProtoSubGhzDLinearDelta3();
|
||||
|
||||
@@ -60,6 +60,7 @@ enum FPROTO_SUBGHZD_SENSOR : uint8_t {
|
||||
FPS_MARANTEC24,
|
||||
FPS_HOLTEKHT6P20B,
|
||||
FPS_RESTAURANT_PAGER,
|
||||
FPS_SUPERROLLO,
|
||||
FPS_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Superrollo;BADBEEF;1;5
|
||||
@@ -0,0 +1 @@
|
||||
Superrollo;BADBEEF;1;7
|
||||
@@ -0,0 +1 @@
|
||||
Superrollo;BADBEEF;1;3
|
||||
Reference in New Issue
Block a user