Merge branch 'dev' into mrtd

This commit is contained in:
Chris van Marle
2022-09-02 22:38:26 +02:00
31 changed files with 1535 additions and 74 deletions
+13 -3
View File
@@ -45,6 +45,19 @@ jobs:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: 'Escape pull request title'
if: github.event_name == 'pull_request'
run: |
import json
import os
import shlex
with open('${{ github.event_path }}') as fh:
event = json.load(fh)
escaped = shlex.quote(event['pull_request']['title'])
with open(os.environ['GITHUB_ENV'], 'a') as fh:
print(f'PULL_NAME={escaped}', file=fh)
shell: python3 {0}
- name: 'Generate prefixes by commit'
id: names
run: |
@@ -58,7 +71,6 @@ jobs:
SHA="$(cut -c -8 <<< "$COMMIT_HASH")"
COMMIT_MSG="$(git log -1 --pretty=format:"%s")"
PULL_ID="${{github.event.pull_request.number}}"
PULL_NAME="${{github.event.pull_request.title}}"
fi
BRANCH_NAME=${REF#refs/*/}
SUFFIX=${BRANCH_NAME//\//_}-$(date +'%d%m%Y')-${SHA}
@@ -78,7 +90,6 @@ jobs:
mkdir artifacts
- name: 'Download build artifacts'
if: ${{ !github.event.pull_request.head.repo.fork }}
run: |
echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key;
chmod 600 ./deploy_key;
@@ -112,7 +123,6 @@ jobs:
export FREE_FLASH_SIZE="$(get_size ".free_flash")"
if [[ ${{ github.event_name }} == 'pull_request' ]]; then
export PULL_ID="${{steps.names.outputs.pull-id}}"
export PULL_NAME="${{steps.names.outputs.pull-name}}"
fi
python3 -m pip install mariadb
python3 scripts/amap_mariadb_insert.py \
+2 -2
View File
@@ -1,5 +1,5 @@
#
# Main Fipper Build System entry point
# Main Flipper Build System entry point
#
# This file is evaluated by scons (the build system) every time fbt is invoked.
# Scons constructs all referenced environments & their targets' dependency
@@ -15,7 +15,7 @@ DefaultEnvironment(tools=[])
# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15)
# This environment is created only for loading options & validating file/dir existance
# This environment is created only for loading options & validating file/dir existence
fbt_variables = SConscript("site_scons/commandline.scons")
cmd_environment = Environment(tools=[], variables=fbt_variables)
Help(fbt_variables.GenerateHelpText(cmd_environment))
@@ -25,7 +25,6 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == InfraredCustomEventTypeSignalReceived) {
infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL);
infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess);
scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess);
consumed = true;
@@ -38,6 +37,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) {
void infrared_scene_learn_on_exit(void* context) {
Infrared* infrared = context;
Popup* popup = infrared->popup;
infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL);
infrared_worker_rx_stop(infrared->worker);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
popup_set_icon(popup, 0, 0, NULL);
+111 -3
View File
@@ -190,12 +190,87 @@ ReturnCode picopass_read_card(PicopassBlock* AA1) {
return ERR_NONE;
}
ReturnCode picopass_write_card(PicopassBlock* AA1) {
rfalPicoPassIdentifyRes idRes;
rfalPicoPassSelectRes selRes;
rfalPicoPassReadCheckRes rcRes;
rfalPicoPassCheckRes chkRes;
ReturnCode err;
uint8_t div_key[8] = {0};
uint8_t mac[4] = {0};
uint8_t ccnr[12] = {0};
err = rfalPicoPassPollerIdentify(&idRes);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
return err;
}
err = rfalPicoPassPollerSelect(idRes.CSN, &selRes);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err);
return err;
}
err = rfalPicoPassPollerReadCheck(&rcRes);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
return err;
}
memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
loclass_diversifyKey(selRes.CSN, picopass_iclass_key, div_key);
loclass_opt_doReaderMAC(ccnr, div_key, mac);
err = rfalPicoPassPollerCheck(mac, &chkRes);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err);
return err;
}
for(size_t i = 6; i < 10; i++) {
FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", i);
uint8_t data[9] = {0};
data[0] = i;
memcpy(data + 1, AA1[i].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
loclass_doMAC_N(data, sizeof(data), div_key, mac);
FURI_LOG_D(
TAG,
"loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
i,
data[1],
data[2],
data[3],
data[4],
data[5],
data[6],
data[7],
data[8],
mac[0],
mac[1],
mac[2],
mac[3]);
err = rfalPicoPassPollerWriteBlock(i, AA1[i].data, mac);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err);
return err;
}
}
return ERR_NONE;
}
int32_t picopass_worker_task(void* context) {
PicopassWorker* picopass_worker = context;
picopass_worker_enable_field();
if(picopass_worker->state == PicopassWorkerStateDetect) {
picopass_worker_detect(picopass_worker);
} else if(picopass_worker->state == PicopassWorkerStateWrite) {
picopass_worker_write(picopass_worker);
}
picopass_worker_disable_field(ERR_NONE);
@@ -212,27 +287,60 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) {
PicopassPacs* pacs = &dev_data->pacs;
ReturnCode err;
PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
while(picopass_worker->state == PicopassWorkerStateDetect) {
if(picopass_detect_card(1000) == ERR_NONE) {
// Process first found device
err = picopass_read_card(AA1);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "picopass_read_card error %d", err);
nextState = PicopassWorkerEventFail;
}
err = picopass_device_parse_credential(AA1, pacs);
if(nextState == PicopassWorkerEventSuccess) {
err = picopass_device_parse_credential(AA1, pacs);
}
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "picopass_device_parse_credential error %d", err);
nextState = PicopassWorkerEventFail;
}
err = picopass_device_parse_wiegand(pacs->credential, &pacs->record);
if(nextState == PicopassWorkerEventSuccess) {
err = picopass_device_parse_wiegand(pacs->credential, &pacs->record);
}
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err);
nextState = PicopassWorkerEventFail;
}
// Notify caller and exit
if(picopass_worker->callback) {
picopass_worker->callback(PicopassWorkerEventSuccess, picopass_worker->context);
picopass_worker->callback(nextState, picopass_worker->context);
}
break;
}
furi_delay_ms(100);
}
}
void picopass_worker_write(PicopassWorker* picopass_worker) {
PicopassDeviceData* dev_data = picopass_worker->dev_data;
PicopassBlock* AA1 = dev_data->AA1;
ReturnCode err;
PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
while(picopass_worker->state == PicopassWorkerStateWrite) {
if(picopass_detect_card(1000) == ERR_NONE) {
err = picopass_write_card(AA1);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "picopass_write_card error %d", err);
nextState = PicopassWorkerEventFail;
}
// Notify caller and exit
if(picopass_worker->callback) {
picopass_worker->callback(nextState, picopass_worker->context);
}
break;
}
+1
View File
@@ -11,6 +11,7 @@ typedef enum {
PicopassWorkerStateReady,
// Main worker states
PicopassWorkerStateDetect,
PicopassWorkerStateWrite,
// Transition
PicopassWorkerStateStop,
} PicopassWorkerState;
@@ -31,3 +31,4 @@ void picopass_worker_change_state(PicopassWorker* picopass_worker, PicopassWorke
int32_t picopass_worker_task(void* context);
void picopass_worker_detect(PicopassWorker* picopass_worker);
void picopass_worker_write(PicopassWorker* picopass_worker);
@@ -9,3 +9,5 @@ ADD_SCENE(picopass, file_select, FileSelect)
ADD_SCENE(picopass, device_info, DeviceInfo)
ADD_SCENE(picopass, delete, Delete)
ADD_SCENE(picopass, delete_success, DeleteSuccess)
ADD_SCENE(picopass, write_card, WriteCard)
ADD_SCENE(picopass, write_card_success, WriteCardSuccess)
@@ -37,8 +37,6 @@ bool picopass_scene_read_card_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
consumed = true;
}
return consumed;
}
@@ -29,38 +29,57 @@ void picopass_scene_read_card_success_on_enter(void* context) {
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
Widget* widget = picopass->widget;
size_t bytesLength = 1 + pacs->record.bitLength / 8;
string_set_str(credential_str, "");
for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) {
string_cat_printf(credential_str, " %02X", pacs->credential[i]);
}
if(pacs->record.bitLength == 0) {
string_cat_printf(wiegand_str, "Read Failed");
if(pacs->record.valid) {
string_cat_printf(
wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber);
widget_add_button_element(
widget,
GuiButtonTypeLeft,
"Retry",
picopass_scene_read_card_success_widget_callback,
picopass);
widget_add_string_element(
widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str));
} else {
string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength);
size_t bytesLength = 1 + pacs->record.bitLength / 8;
string_set_str(credential_str, "");
for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) {
string_cat_printf(credential_str, " %02X", pacs->credential[i]);
}
if(pacs->record.valid) {
string_cat_printf(
wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber);
} else {
string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength);
}
widget_add_button_element(
widget,
GuiButtonTypeLeft,
"Retry",
picopass_scene_read_card_success_widget_callback,
picopass);
widget_add_button_element(
widget,
GuiButtonTypeRight,
"More",
picopass_scene_read_card_success_widget_callback,
picopass);
widget_add_string_element(
widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str));
widget_add_string_element(
widget,
64,
32,
AlignCenter,
AlignCenter,
FontSecondary,
string_get_cstr(credential_str));
}
widget_add_button_element(
widget,
GuiButtonTypeLeft,
"Retry",
picopass_scene_read_card_success_widget_callback,
picopass);
widget_add_button_element(
widget,
GuiButtonTypeRight,
"More",
picopass_scene_read_card_success_widget_callback,
picopass);
widget_add_string_element(
widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str));
widget_add_string_element(
widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(credential_str));
string_clear(credential_str);
string_clear(wiegand_str);
@@ -24,6 +24,8 @@ void picopass_scene_saved_menu_on_enter(void* context) {
picopass);
submenu_add_item(
submenu, "Info", SubmenuIndexInfo, picopass_scene_saved_menu_submenu_callback, picopass);
submenu_add_item(
submenu, "Write", SubmenuIndexWrite, picopass_scene_saved_menu_submenu_callback, picopass);
submenu_set_selected_item(
picopass->submenu,
@@ -46,6 +48,9 @@ bool picopass_scene_saved_menu_on_event(void* context, SceneManagerEvent event)
} else if(event.event == SubmenuIndexInfo) {
scene_manager_next_scene(picopass->scene_manager, PicopassSceneDeviceInfo);
consumed = true;
} else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteCard);
consumed = true;
}
}
@@ -0,0 +1,53 @@
#include "../picopass_i.h"
#include <dolphin/dolphin.h>
void picopass_write_card_worker_callback(PicopassWorkerEvent event, void* context) {
UNUSED(event);
Picopass* picopass = context;
view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventWorkerExit);
}
void picopass_scene_write_card_on_enter(void* context) {
Picopass* picopass = context;
DOLPHIN_DEED(DolphinDeedNfcSave);
// Setup view
Popup* popup = picopass->popup;
popup_set_header(popup, "Writing\npicopass\ncard", 68, 30, AlignLeft, AlignTop);
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
// Start worker
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup);
picopass_worker_start(
picopass->worker,
PicopassWorkerStateWrite,
&picopass->dev->dev_data,
picopass_write_card_worker_callback,
picopass);
picopass_blink_start(picopass);
}
bool picopass_scene_write_card_on_event(void* context, SceneManagerEvent event) {
Picopass* picopass = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == PicopassCustomEventWorkerExit) {
scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteCardSuccess);
consumed = true;
}
}
return consumed;
}
void picopass_scene_write_card_on_exit(void* context) {
Picopass* picopass = context;
// Stop worker
picopass_worker_stop(picopass->worker);
// Clear view
popup_reset(picopass->popup);
picopass_blink_stop(picopass);
}
@@ -0,0 +1,57 @@
#include "../picopass_i.h"
#include <dolphin/dolphin.h>
void picopass_scene_write_card_success_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
furi_assert(context);
Picopass* picopass = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(picopass->view_dispatcher, result);
}
}
void picopass_scene_write_card_success_on_enter(void* context) {
Picopass* picopass = context;
Widget* widget = picopass->widget;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Send notification
notification_message(picopass->notifications, &sequence_success);
widget_add_button_element(
widget,
GuiButtonTypeLeft,
"Retry",
picopass_scene_write_card_success_widget_callback,
picopass);
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
}
bool picopass_scene_write_card_success_on_event(void* context, SceneManagerEvent event) {
Picopass* picopass = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(picopass->scene_manager);
} else if(event.event == GuiButtonTypeRight) {
// Clear device name
picopass_device_set_name(picopass->dev, "");
scene_manager_next_scene(picopass->scene_manager, PicopassSceneCardMenu);
consumed = true;
}
}
return consumed;
}
void picopass_scene_write_card_success_on_exit(void* context) {
Picopass* picopass = context;
// Clear view
widget_reset(picopass->widget);
}
+12 -8
View File
@@ -114,19 +114,21 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
uint32_t frequency = 433920000;
uint32_t key = 0x0074BADE;
uint32_t repeat = 10;
uint32_t te = 403;
if(string_size(args)) {
int ret = sscanf(string_get_cstr(args), "%lx %lu %lu", &key, &frequency, &repeat);
if(ret != 3) {
int ret = sscanf(string_get_cstr(args), "%lx %lu %lu %lu", &key, &frequency, &te, &repeat);
if(ret != 4) {
printf(
"sscanf returned %d, key: %lx, frequency: %lu, repeat: %lu\r\n",
"sscanf returned %d, key: %lx, frequency: %lu, te:%lu, repeat: %lu\r\n",
ret,
key,
frequency,
te,
repeat);
cli_print_usage(
"subghz tx",
"<3 Byte Key: in hex> <Frequency: in Hz> <Repeat count>",
"<3 Byte Key: in hex> <Frequency: in Hz> <Te us> <Repeat count>",
string_get_cstr(args));
return;
}
@@ -139,9 +141,10 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
}
printf(
"Transmitting at %lu, key %lx, repeat %lu. Press CTRL+C to stop\r\n",
"Transmitting at %lu, key %lx, te %lu, repeat %lu. Press CTRL+C to stop\r\n",
frequency,
key,
te,
repeat);
string_t flipper_format_string;
@@ -149,12 +152,13 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
flipper_format_string,
"Protocol: Princeton\n"
"Bit: 24\n"
"Key: 00 00 00 00 00 %X %X %X\n"
"TE: 403\n"
"Key: 00 00 00 00 00 %02X %02X %02X\n"
"TE: %d\n"
"Repeat: %d\n",
(uint8_t)((key >> 16) & 0xFF),
(uint8_t)((key >> 8) & 0xFF),
(uint8_t)(key & 0xFF),
te,
repeat);
FlipperFormat* flipper_format = flipper_format_string_alloc();
Stream* stream = flipper_format_get_raw_stream(flipper_format);
@@ -425,7 +429,7 @@ static void subghz_cli_command_print_usage() {
printf("\tchat <frequency:in Hz>\t - Chat with other Flippers\r\n");
printf(
"\ttx <3 byte Key: in hex> <frequency: in Hz> <repeat: count>\t - Transmitting key\r\n");
"\ttx <3 byte Key: in hex> <frequency: in Hz> <te: us> <repeat: count>\t - Transmitting key\r\n");
printf("\trx <frequency:in Hz>\t - Reception key\r\n");
printf("\tdecode_raw <file_name: path_RAW_file>\t - Testing\r\n");
+18 -2
View File
@@ -13,7 +13,7 @@
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
#define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub")
#define TEST_RANDOM_COUNT_PARSE 196
#define TEST_RANDOM_COUNT_PARSE 208
#define TEST_TIMEOUT 10000
static SubGhzEnvironment* environment_handler;
@@ -127,7 +127,7 @@ static bool subghz_decode_random_test(const char* path) {
}
subghz_file_encoder_worker_free(file_worker_encoder_handler);
}
FURI_LOG_T(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count);
FURI_LOG_D(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count);
if(furi_get_tick() - test_start > TEST_TIMEOUT * 10) {
printf("\033[0;31mRandom test ERROR TimeOut\033[0m\r\n");
return false;
@@ -419,6 +419,14 @@ MU_TEST(subghz_decoder_magellen_test) {
"Test decoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n");
}
MU_TEST(subghz_decoder_intertechno_v3_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/intertechno_v3_raw.sub"),
SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME),
"Test decoder " SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME " error\r\n");
}
//test encoders
MU_TEST(subghz_encoder_princeton_test) {
mu_assert(
@@ -528,6 +536,12 @@ MU_TEST(subghz_encoder_magellen_test) {
"Test encoder " SUBGHZ_PROTOCOL_MAGELLEN_NAME " error\r\n");
}
MU_TEST(subghz_encoder_intertechno_v3_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/intertechno_v3.sub")),
"Test encoder " SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME " error\r\n");
}
MU_TEST(subghz_random_test) {
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
}
@@ -566,6 +580,7 @@ MU_TEST_SUITE(subghz) {
MU_RUN_TEST(subghz_decoder_phoenix_v2_test);
MU_RUN_TEST(subghz_decoder_honeywell_wdb_test);
MU_RUN_TEST(subghz_decoder_magellen_test);
MU_RUN_TEST(subghz_decoder_intertechno_v3_test);
MU_RUN_TEST(subghz_encoder_princeton_test);
MU_RUN_TEST(subghz_encoder_came_test);
@@ -585,6 +600,7 @@ MU_TEST_SUITE(subghz) {
MU_RUN_TEST(subghz_encoder_phoenix_v2_test);
MU_RUN_TEST(subghz_encoder_honeywell_wdb_test);
MU_RUN_TEST(subghz_encoder_magellen_test);
MU_RUN_TEST(subghz_encoder_intertechno_v3_test);
MU_RUN_TEST(subghz_random_test);
subghz_test_deinit();
@@ -0,0 +1,7 @@
Filetype: Flipper SubGhz Key File
Version: 1
Frequency: 433920000
Preset: FuriHalSubGhzPresetOok650Async
Protocol: Intertechno_V3
Bit: 32
Key: 00 00 00 00 3F 86 C5 9F
@@ -0,0 +1,13 @@
Filetype: Flipper SubGhz RAW File
Version: 1
Frequency: 433920000
Preset: FuriHalSubGhzPresetOok650Async
Protocol: RAW
RAW_Data: 15041 -66 15883 -66 12643 -66 12681 -66 3413 -68 2713 -68 33389 -66 1445 -66 1279 -68 1027 -66 6911 -98 25229 -66 3967 -100 3019 -100 6131 -66 955 -66 3605 -66 12411 -98 1419 -66 3593 -68 2753 -66 2457 -66 6007 -66 627 -100 1597 -66 3071 -98 22749 -66 333 -66 12829 -66 4313 -132 855 -66 44097 -64 20391 -98 29999 -66 3539 -98 557 -66 1489 -100 4081 -100 3857 -64 2895 -132 2261 -166 3089 -66 2429 -68 34467 -66 3585 -66 3087 -66 3329 -132 5287 -66 1063 -98 15259 -100 2535 -66 995 -66 13057 -100 24233 -68 531 -100 26415 -66 1761 -100 2717 -66 4071 -100 12191 -66 23367 -68 2323 -66 19809 -248 245 -1388 255 -242 275 -1358 273 -1370 277 -246 277 -1368 275 -246 275 -1362 275 -244 275 -1364 275 -244 275 -1362 275 -244 275 -1328 273 -278 273 -1358 275 -246 275 -238 263 -1384 275 -246 273 -1358 275 -244 273 -1358 275 -246 275 -1360 275 -1344 277 -246 275 -1358 275 -244 275 -234 263 -1382 277 -1344 277 -246 279 -1362 275 -246 271 -234 261 -1380 275 -246 273 -1360 275 -246 275 -1366 277 -1340 277 -248 279 -238 263 -1382 275 -1344 277 -246 279 -1364 277 -244 275 -234 263 -1382 277 -244 273 -1358 275 -1344 277 -248 279 -1368 275 -244 273 -1360 239 -280 271 -1358 275 -244 275 -1358 275 -174 269 -10298 289 -2660 267 -238 299 -1356 275 -244 275 -1356 275 -1344 277 -248 277 -1360 275 -246 275 -1328 309 -244 273 -1358 277 -244 275 -1356 275 -246 273 -1326 309 -244 275 -1356 275 -246 273 -234 263 -1380 277 -246 273 -1326 309 -244 273 -1356 277 -246 277 -1358 275 -1338 279 -248 279 -1364 275 -246 273 -234 261 -1380 277 -1344 279 -250 277 -1330 309 -244 273 -232 261 -1384 275 -246 273 -1356 275 -248 275 -1360 275 -1340 279 -248 277 -236 263 -1380 277 -1342 279 -248 279 -1366 275 -246 273 -234 263 -1380 275 -246 275 -1358 275 -1340 279 -248 281 -1336 309 -244 273 -1358 275 -246 273 -1360 275 -244 273 -1358 275 -176 267 -10306 257 -2646 299 -234 301 -1354 277 -246 275 -1356 277 -1340 279 -250 279 -1332 309 -244 275 -1358 275 -248 273 -1326 309 -246 273 -1326 309 -244 275 -1356 277 -248 275 -1328 309 -246 273 -234 261 -1382 277 -246 277 -1326 309 -244 275 -1358 277 -246 277 -1356 277 -1346 277 -250 277 -1358 277 -246 275 -234 263 -1382 279 -1346 279 -248 281 -1330 307 -246 273 -236 261 -1380 277 -246 277 -1360 277 -246 277 -1360 275 -1344 279 -248 279 -236 263 -1384 277 -1340 279 -250 281 -1338 307 -246 271 -234 261 -1384 277 -246 275 -1356 277 -1340 279 -250 283 -1336 309 -246 273 -1356 277 -246 273 -1360 277 -246
RAW_Data: 275 -1328 309 -174 269 -10296 289 -2648 267 -238 299 -1356 277 -246 275 -1324 307 -1342 279 -250 277 -1330 309 -244 275 -1362 277 -244 275 -1356 275 -248 273 -1328 309 -244 273 -1328 309 -244 275 -1360 277 -246 275 -234 259 -1384 277 -246 275 -1360 275 -246 273 -1358 277 -248 277 -1362 275 -1344 277 -248 277 -1328 307 -246 273 -236 261 -1384 277 -1348 279 -248 279 -1360 277 -246 273 -234 263 -1388 275 -246 275 -1360 277 -248 279 -1368 277 -1344 279 -248 279 -240 265 -1386 275 -1342 279 -286 247 -1372 275 -248 275 -238 265 -1386 277 -248 275 -1360 275 -1344 277 -286 247 -1374 275 -246 275 -1362 277 -246 275 -1360 277 -248 275 -1326 307 -174 269 -10290 287 -2654 269 -236 301 -1352 275 -248 273 -1326 311 -1340 277 -248 277 -1328 309 -244 273 -1358 275 -244 275 -1326 309 -244 273 -1356 277 -244 273 -1356 275 -246 275 -1358 275 -244 275 -234 261 -1382 277 -246 273 -1358 275 -246 273 -1360 277 -246 273 -1324 309 -1340 277 -248 277 -1328 307 -246 271 -234 259 -1382 277 -1346 279 -248 277 -1330 309 -244 271 -232 259 -1382 277 -244 275 -1356 277 -248 273 -1354 277 -1342 277 -248 275 -236 261 -1380 277 -1344 277 -248 279 -1330 307 -246 273 -234 261 -1378 277 -246 273 -1356 277 -1342 277 -248 277 -1330 309 -244 273 -1322 307 -246 273 -1326 309 -244 273 -1322 309 -176 267 -10298 257 -2682 265 -236 299 -1324 309 -248 273 -1324 311 -1342 277 -246 279 -1360 277 -244 275 -1362 275 -244 275 -1358 275 -244 275 -1360 275 -246 273 -1360 275 -244 277 -1360 275 -246 273 -234 263 -1384 275 -246 273 -1358 275 -246 275 -1360 277 -246 277 -1356 277 -1342 279 -248 277 -1364 275 -244 275 -234 261 -1384 275 -1344 277 -250 279 -1366 275 -246 273 -236 263 -1384 277 -246 275 -1358 277 -246 277 -1362 277 -1342 279 -248 279 -236 265 -1382 277 -1346 277 -248 281 -1366 275 -246 275 -234 265 -1384 275 -246 273 -1358 277 -1344 279 -248 279 -1364 275 -244 275 -1324 309 -246 273 -1324 307 -246 273 -1326 309 -174 267 -118796 133 -100 131 -892 329 -166 199 -132 131 -166 99 -100 265 -264 4663 -134 4889 -100 365 -98 5921 -100 5903 -68 4877 -98 2953 -98 1645 -64 1687 -66 981 -98 10769 -66 18319 -66 4831 -66 13301 -66 893 -132 5967 -100 15949 -66 3749 -66 497 -100 625 -66 1147 -66 469 -66 1261 -66 3651 -100 265 -100 26741 -68 6873 -66 4485 -100 2667 -68 3159 -68 2857 -132 2655 -66 12903 -66 1277 -66 1711 -66 787 -100 1327 -198 727 -64 1677 -100 1187 -66 1019 -66 891 -66 4303 -100 11297 -66 3923 -254 253 -1380 247 -292 253 -1344
RAW_Data: 277 -1346 277 -250 279 -1364 275 -244 275 -1362 275 -244 275 -1356 275 -246 273 -1358 241 -278 273 -1356 275 -246 273 -1360 275 -246 273 -234 263 -1382 275 -244 273 -1358 275 -246 273 -1360 275 -246 273 -1358 275 -1340 277 -248 277 -1362 275 -246 273 -234 261 -1380 277 -1344 277 -248 279 -1362 275 -244 273 -236 261 -1380 275 -244 275 -1360 275 -246 275 -1358 275 -1346 277 -246 275 -236 263 -1384 275 -1342 277 -248 277 -1364 277 -244 273 -234 261 -1378 277 -246 273 -1356 277 -1340 277 -248 281 -1334 307 -246 271 -1356 275 -246 273 -1358 275 -244 273 -1326 309 -174 267 -10296 257 -2650 297 -232 263 -1384 277 -244 273 -1358 275 -1340 279 -248 279 -1328 309 -244 275 -1328 307 -244 273 -1356 275 -244 275 -1358 275 -246 273 -1324 309 -244 275 -1328 307 -244 273 -234 261 -1382 275 -246 273 -1326 309 -244 273 -1358 275 -246 273 -1358 275 -1338 279 -248 279 -1330 309 -244 273 -232 261 -1380 277 -1344 279 -248 279 -1330 309 -244 271 -234 261 -1382 275 -246 273 -1358 277 -244 275 -1330 309 -1338 277 -246 277 -236 263 -1380 277 -1342 277 -248 279 -1364 275 -246 273 -232 261 -1380 275 -248 275 -1328 307 -1338 277 -248 279 -1334 309 -244 271 -1358 275 -244 275 -1324 307 -246 271 -1328 309 -174 265 -10270 291 -2640 297 -232 297 -1350 277 -248 275 -1326 309 -1340 277 -248 277 -1328 309 -244 273 -1358 275 -246 273 -1326 309 -244 273 -1354 275 -246 273 -1330 307 -244 273 -1358 275 -246 273 -234 263 -1380 275 -246 273 -1358 275 -246 273 -1360 275 -244 273 -1358 275 -1340 277 -248 279 -1364 275 -244 273 -232 261 -1380 277 -1342 279 -250 279 -1332 307 -244 271 -234 261 -1378 277 -246 273 -1358 275 -248 275 -1360 275 -1340 277 -248 275 -236 263 -1382 277 -1344 277 -246 277 -1364 275 -246 273 -234 259 -1380 275 -246 273 -1362 275 -1342 275 -248 277 -1334 309 -244 271 -1356 275 -244 275 -1326 307 -244 273 -1356 275 -176 267 -10290 289 -2644 267 -238 301 -1320 309 -246 273 -1324 309 -1340 277 -248 277 -1328 307 -246 273 -1326 307 -246 273 -1324 309 -246 273 -1322 309 -246 273 -1322 307 -246 275 -1326 309 -246 273 -234 259 -1382 275 -246 275 -1322 309 -246 273 -1326 309 -246 273 -1326 309 -1340 277 -248 275 -1326 309 -246 273 -232 261 -1380 279 -1346 277 -250 277 -1328 309 -244 271 -232 261 -1380 277 -246 273 -1358 275 -248 273 -1328 307 -1340 277 -248 277 -236 261 -1380 277 -1344 277 -248 279 -1328 309 -244 275 -232 261 -1378 277 -248 273 -1326 309 -1344 277 -248 277 -1358 277 -246 273 -1328 307 -244 271 -1324 309 -244
RAW_Data: 273 -1324 309 -174 267 -10270 289 -2638 297 -234 297 -1352 275 -248 275 -1328 307 -1340 277 -248 275 -1330 309 -244 273 -1358 275 -244 275 -1326 309 -244 271 -1356 275 -244 275 -1326 307 -246 273 -1326 309 -244 273 -234 261 -1378 275 -248 275 -1326 309 -244 271 -1356 277 -248 273 -1328 309 -1338 277 -248 277 -1328 309 -244 271 -232 261 -1380 277 -1348 279 -248 277 -1328 307 -246 271 -234 259 -1384 275 -244 275 -1356 277 -246 275 -1326 309 -1344 275 -248 275 -236 261 -1378 277 -1342 277 -250 279 -1334 309 -244 271 -232 261 -1380 277 -246 273 -1326 307 -1344 277 -248 277 -1328 309 -246 273 -1326 309 -244 271 -1324 309 -244 273 -1324 307 -176 267 -10288 287 -2618 299 -236 299 -1354 277 -244 273 -1326 307 -1340 279 -248 275 -1328 309 -244 275 -1326 309 -246 273 -1324 307 -246 273 -1322 309 -244 273 -1322 309 -244 275 -1328 309 -246 273 -232 261 -1380 277 -246 275 -1324 309 -244 273 -1356 277 -246 275 -1324 309 -1340 279 -246 277 -1328 309 -244 273 -232 261 -1382 277 -1344 279 -250 277 -1324 309 -246 273 -234 261 -1380 277 -246 273 -1358 277 -246 273 -1328 309 -1340 277 -248 275 -236 261 -1380 275 -1344 279 -248 279 -1360 277 -244 273 -234 261 -1380 277 -246 275 -1354 277 -1344 277 -248 277 -1328 311 -246 273 -1324 307 -244 273 -1324 309 -244 273 -1320 309 -176 269 -118210 761 -168 267 -66 563 -132 99 -132 3543 -66 5345 -100 4355 -66 4617 -68 20503 -166 2379 -132 293 -98 4117 -66 1151 -98 3353 -66 3485 -66 2491 -66 6133 -66 233 -68 16307 -68 16959 -98 357 -66 5419 -134 799 -100 327 -100 791 -66 2481 -66 963 -100 3481 -98 1679 -134 2473 -100 227 -68 3087 -66 11527 -130 4305 -98 435 -66 563 -100 2887 -100 267 -66 1787 -66 9655 -66 4793 -100 2119 -66 359 -98 1313 -132 3393 -234 995 -66 2681 -98 99 -130 1379 -100 3757 -100 21695 -132 5135 -100 693 -98 4631 -100 2325 -68 4937 -66 10409 -98 897 -100 1287 -66 2565 -66 3753 -66 4055 -66 2023 -68 1961 -68 629 -66 431 -66 5039 -66 2155 -100 2673 -66 1163 -98 6539 -100 825 -66 1197 -100 3053 -66 13973 -68 15515 -100 1861 -66 1027 -66 797 -98 959 -98 787 -132 787 -64 3811 -132 1747 -66 6683 -66 1033 -68 24927 -66 1259 -100 1125 -68 663 -66 1687 -66 4357 -132 4567 -66 3969 -98 3317 -132 433 -134 6043 -66 3249 -100 431 -98 2367 -100 11265 -66 5085 -68 2355 -64 1815 -66 1395 -274 241 -1366 275 -244 275 -1362 275 -1338 277 -284 243 -1368 239 -278 275 -1362 275 -244 275 -1360 241 -278 273 -1356 275 -246 275 -1360 239 -280 275 -1360
RAW_Data: 275 -244 275 -234 263 -1386 239 -280 273 -1356 275 -244 273 -1360 275 -244 277 -1364 275 -1336 277 -248 277 -1366 275 -244 273 -234 263 -1386 275 -1340 277 -248 279 -1364 275 -244 275 -234 263 -1384 273 -244 275 -1358 275 -244 275 -1364 275 -1342 275 -248 277 -236 265 -1384 275 -1340 277 -282 243 -1366 275 -246 273 -236 263 -1382 277 -244 275 -1358 275 -1342 277 -248 277 -1364 275 -246 275 -1360 239 -280 273 -1358 241 -278 275 -1356 275 -210 233 -10302 257 -2652 297 -232 297 -1354 277 -244 275 -1358 275 -1340 279 -248 279 -1360 275 -246 275 -1360 275 -246 273 -1360 275 -244 275 -1328 309 -242 273 -1324 309 -244 275 -1360 275 -246 273 -234 261 -1384 275 -246 273 -1358 275 -244 275 -1358 277 -248 273 -1358 275 -1340 279 -248 277 -1334 307 -242 273 -232 261 -1380 277 -1348 277 -250 277 -1364 275 -244 275 -234 261 -1380 277 -244 275 -1358 277 -246 277 -1360 277 -1342 275 -248 275 -236 263 -1380 277 -1344 277 -248 279 -1368 275 -244 275 -232 261 -1382 277 -244 275 -1356 275 -1344 277 -248 279 -1362 275 -246 275 -1360 275 -246 273 -1356 275 -246 273 -1356 275 -176 267 -10302 257 -2648 299 -234 297 -1352 277 -246 275 -1326 309 -1340 279 -248 277 -1330 309 -244 275 -1328 309 -244 273 -1324 309 -244 275 -1324 309 -246 273 -1324 307 -246 275 -1328 309 -244 273 -234 261 -1378 277 -248 275 -1328 309 -244 273 -1356 277 -248 275 -1326 309 -1344 277 -248 275 -1326 309 -246 273 -234 259 -1380 277 -1348 281 -248 279 -1328 307 -246 273 -234 259 -1382 277 -246 275 -1360 275 -248 275 -1324 309 -1340 279 -248 277 -238 261 -1382 277 -1344 277 -248 279 -1330 311 -244 273 -234 259 -1378 277 -248 275 -1326 309 -1340 279 -248 279 -1336 307 -246 271 -1324 309 -244 275 -1324 307 -246 273 -1326 309 -174 269 -10296 257 -2648 299 -234 297 -1352 277 -248 273 -1326 309 -1342 277 -248 277 -1328 309 -246 275 -1328 309 -244 273 -1326 309 -244 273 -1322 309 -244 273 -1328 307 -244 275 -1328 309 -246 273 -234 261 -1382 277 -246 275 -1326 309 -244 273 -1352 277 -248 275 -1330 309 -1340 277 -248 277 -1328 309 -244 275 -232 261 -1384 277 -1342 279 -250 279 -1328 309 -244 273 -234 263 -1380 277 -246 273 -1360 277 -246 275 -1326 309 -1340 277 -250 277 -236 263 -1382 277 -1342 277 -248 279 -1362 277 -246 273 -234 263 -1382 277 -244 275 -1356 277 -1340 279 -248 279 -1362 275 -246 275 -1328 307 -246 273 -1356 275 -246 273 -1356 275 -174 269 -10292 287 -2650 269 -236 301 -1354 275 -248 273 -1358 275 -1340 279 -248 277 -1332 307 -246 275 -1328
RAW_Data: 309 -244 273 -1324 309 -244 273 -1356 275 -246 273 -1358 275 -244 277 -1330 309 -244 273 -234 261 -1382 277 -244 275 -1358 275 -246 273 -1356 277 -248 275 -1360 275 -1340 277 -248 277 -1360 275 -246 273 -236 261 -1382 279 -1344 279 -248 279 -1360 277 -244 273 -234 261 -1380 277 -246 275 -1360 277 -246 273 -1360 275 -1342 279 -248 275 -236 263 -1382 275 -1344 279 -248 279 -1362 277 -246 273 -234 263 -1380 277 -246 275 -1356 275 -1342 277 -248 281 -1336 307 -246 271 -1354 277 -246 275 -1328 307 -244 273 -1352 277 -176 269 -10300 257 -2650 299 -232 297 -1354 277 -246 275 -1356 277 -1342 277 -248 279 -1328 309 -244 275 -1360 275 -246 273 -1328 307 -246 273 -1356 277 -246 277 -1326 309 -244 277 -1360 277 -246 273 -234 263 -1384 277 -246 275 -1324 309 -246 275 -1358 277 -246 277 -1360 277 -1344 277 -248 277 -1326 309 -246 273 -236 261 -1382 277 -1348 279 -250 281 -1330 307 -246 273 -234 263 -1386 277 -244 275 -1356 277 -248 277 -1362 277 -1342 277 -250 277 -238 263 -1384 277 -1342 277 -250 281 -1332 309 -246 273 -234 263 -1380 277 -246 275 -1360 277 -1342 279 -248 281 -1334 307 -246 273 -1356 275 -248 275 -1328 309 -244 275 -1324 309 -176 269 -115034 163 -362 67 -894 529 -166 14663 -98 4135 -66 3681 -100 299 -68 9829 -66 3517 -64 21569 -66 3251 -66 2209 -64 23701 -66 3359 -68 1057 -66 723 -66 299 -134 765 -66 589 -98 1687 -134 2153 -66 3081 -68 10447 -66 11643 -66 2451 -66 2277 -66 2897 -66 755 -100 5539 -64 5117 -132 4867 -134 3931 -64 625 -66 1317 -98 11597 -66 2255 -66 1165 -66 1123 -66 6371 -100 699 -68 1811 -66 621 -68 2191 -64 1291 -134 3003 -66 2423 -64 1463 -66 663 -100 1127 -100 6169 -100 489 -100 6087 -100 2027 -66 1195 -66 13195 -66 557 -66 40423 -98 1919 -100 1061 -132 201 -66 2553 -132 12549 -66 1789 -100 921 -134 1067 -66 729 -66 10029 -66 3909 -100 265 -100 16017 -134 21177 -68 2461 -66 2215 -68 1197 -66 5911 -66 2645 -66 3419 -132 16275 -64 5091 -68 2123 -66 2677 -64 10305 -66 12381 -100 427 -166 25331 -66 2457 -66 11859 -248 279 -1368 275 -246 275 -1360 275 -1340 277 -246 279 -1364 239 -278 275 -1358 275 -244 275 -1362 239 -278 273 -1358 239 -280 271 -1360 241 -278 273 -1360 275 -244 275 -234 261 -1384 239 -280 273 -1356 275 -244 273 -1360 275 -244 275 -1358 275 -1344 277 -248 275 -1358 275 -244 273 -236 261 -1384 275 -1342 279 -246 279 -1360 275 -244 275 -234 263 -1384 239 -278 273 -1358 275 -244 275 -1362 275 -1342 275 -248 275 -238 263 -1382 275 -1344 275 -248
RAW_Data: 277 -1364 275 -244 273 -234 263 -1380 275 -246 273 -1358 275 -1342 277 -246 279 -1366 275 -244 273 -1362 239 -278 239 -1386 275 -246 273 -1360 241 -208 269 -10290 257 -2686 265 -232 265 -1384 275 -246 275 -1358 275 -1344 277 -248 275 -1358 275 -246 275 -1360 277 -244 273 -1326 309 -244 271 -1354 275 -244 275 -1358 275 -246 273 -1358 275 -246 273 -234 263 -1378 275 -246 275 -1360 275 -244 273 -1356 275 -246 275 -1360 275 -1342 277 -246 277 -1360 275 -246 273 -232 261 -1382 277 -1342 279 -248 279 -1360 275 -244 275 -232 261 -1380 277 -244 275 -1356 277 -246 277 -1360 275 -1342 277 -246 275 -236 263 -1384 275 -1342 277 -248 277 -1362 275 -246 273 -234 261 -1378 277 -246 275 -1328 307 -1340 277 -246 279 -1366 275 -244 273 -1326 307 -244 273 -1324 309 -244 273 -1356 275 -174 267 -10304 255 -2648 297 -230 263 -1382 277 -244 275 -1330 307 -1338 277 -248 277 -1330 309 -244 273 -1356 275 -246 273 -1362 275 -244 273 -1356 275 -244 273 -1326 307 -244 273 -1360 273 -246 273 -236 261 -1380 275 -244 275 -1328 307 -244 273 -1358 275 -244 275 -1360 275 -1342 277 -246 277 -1364 275 -244 271 -232 261 -1384 277 -1340 279 -248 279 -1360 275 -246 273 -234 261 -1380 275 -244 275 -1360 277 -244 275 -1356 275 -1342 279 -246 277 -236 263 -1382 275 -1340 277 -248 279 -1366 275 -246 271 -234 261 -1382 277 -244 275 -1354 275 -1342 277 -248 277 -1364 273 -246 273 -1362 275 -244 271 -1360 275 -244 273 -1358 275 -174 267 -10272 289 -2646 265 -262 261 -1382 277 -244 275 -1356 275 -1342 277 -248 277 -1364 275 -244 275 -1360 275 -244 273 -1358 275 -244 273 -1358 275 -244 273 -1326 307 -244 275 -1358 275 -246 273 -234 261 -1382 275 -246 273 -1358 275 -244 273 -1358 275 -246 275 -1360 275 -1338 277 -248 277 -1362 277 -244 271 -234 261 -1380 277 -1344 279 -248 277 -1332 273 -278 271 -234 261 -1382 275 -244 275 -1356 277 -246 275 -1360 277 -1340 277 -246 277 -234 263 -1384 275 -1342 277 -248 277 -1366 275 -244 273 -234 261 -1380 275 -246 273 -1360 275 -1340 277 -246 279 -1334 307 -244 273 -1356 275 -246 273 -1360 275 -244 271 -1354 277 -174 269 -10300 257 -2648 297 -230 263 -1384 277 -244 273 -1356 277 -1342 277 -248 277 -1362 275 -244 275 -1330 307 -244 273 -1324 309 -244 273 -1324 307 -246 273 -1326 307 -244 273 -1358 275 -246 273 -234 261 -1380 277 -246 273 -1358 275 -244 275 -1354 277 -248 275 -1360 275 -1338 279 -246 277 -1360 275 -244 273 -234 261 -1378 279 -1344 279 -248 279 -1330 309 -244 271 -232 261 -1380 277 -246 273 -1360
RAW_Data: 277 -244 275 -1360 275 -1340 277 -246 277 -236 261 -1380 275 -1346 277 -248 277 -1362 275 -246 273 -234 263 -1380 275 -244 275 -1358 275 -1340 277 -248 279 -1334 309 -244 273 -1324 307 -246 273 -1356 275 -244 273 -1356 275 -174 269 -10302 257 -2644 297 -232 263 -1384 277 -246 275 -1354 275 -1344 277 -248 275 -1360 275 -246 275 -1358 275 -246 273 -1326 307 -246 273 -1324 307 -244 273 -1328 307 -244 273 -1358 275 -244 273 -236 261 -1380 275 -246 273 -1358 275 -244 273 -1358 275 -246 273 -1360 275 -1344 275 -248 275 -1360 275 -244 273 -234 261 -1378 277 -1344 279 -248 277 -1362 275 -246 273 -234 261 -1378 275 -244 275 -1360 275 -246 275 -1358 275 -1344 277 -246 277 -234 263 -1380 275 -1338 279 -246 281 -1368 275 -244 271 -234 261 -1386 275 -244 271 -1358 275 -1342 277 -246 279 -1362 275 -244 275 -1326 273 -278 273 -1358 239 -278 273 -1358 275 -174 267 -127478 195 -964 2317 -66 763 -98 1455 -100 16109 -66 5683 -98 11469 -66 34413 -66 5443 -66 11613 -66 2737 -66 12191 -66 2951 -68 1851 -68 1895 -68 2643
+3 -1
View File
@@ -124,7 +124,9 @@ bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) {
}
nfc_data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) |
(cuid_start[3]);
} else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB) {
} else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB ||
dev_list[0].type == RFAL_NFC_LISTEN_TYPE_ST25TB)
{
nfc_data->type = FuriHalNfcTypeB;
} else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCF) {
nfc_data->type = FuriHalNfcTypeF;
+1 -1
View File
@@ -26,7 +26,7 @@ enum {
RFAL_PICOPASS_CMD_READCHECK = 0x88,
RFAL_PICOPASS_CMD_CHECK = 0x05,
RFAL_PICOPASS_CMD_READ = 0x0C,
RFAL_PICOPASS_CMD_WRITE = 0x0C,
RFAL_PICOPASS_CMD_WRITE = 0x87,
};
typedef struct {
+7 -9
View File
@@ -2,6 +2,8 @@
#include "rfal_picopass.h"
#include "utils.h"
#define TAG "RFAL_PICOPASS"
typedef struct {
uint8_t CMD;
uint8_t CSN[RFAL_PICOPASS_UID_LEN];
@@ -169,18 +171,14 @@ ReturnCode rfalPicoPassPollerWriteBlock(uint8_t blockNum, uint8_t data[8], uint8
uint16_t recvLen = 0;
uint32_t flags = RFAL_PICOPASS_TXRX_FLAGS;
uint32_t fwt = rfalConvMsTo1fc(20);
rfalPicoPassReadBlockRes readRes;
rfalPicoPassReadBlockRes block;
ret = rfalTransceiveBlockingTxRx(
txBuf,
sizeof(txBuf),
(uint8_t*)&readRes,
sizeof(rfalPicoPassReadBlockRes),
&recvLen,
flags,
fwt);
txBuf, sizeof(txBuf), (uint8_t*)&block, sizeof(block), &recvLen, flags, fwt);
// TODO: compare response
if(ret == ERR_NONE) {
// TODO: compare response
}
return ret;
}
+4
View File
@@ -13,6 +13,8 @@
#include "protocol_jablotron.h"
#include "protocol_paradox.h"
#include "protocol_pac_stanley.h"
#include "protocol_keri.h"
#include "protocol_gallagher.h"
const ProtocolBase* lfrfid_protocols[] = {
[LFRFIDProtocolEM4100] = &protocol_em4100,
@@ -29,4 +31,6 @@ const ProtocolBase* lfrfid_protocols[] = {
[LFRFIDProtocolJablotron] = &protocol_jablotron,
[LFRFIDProtocolParadox] = &protocol_paradox,
[LFRFIDProtocolPACStanley] = &protocol_pac_stanley,
[LFRFIDProtocolKeri] = &protocol_keri,
[LFRFIDProtocolGallagher] = &protocol_gallagher,
};
+2
View File
@@ -22,6 +22,8 @@ typedef enum {
LFRFIDProtocolJablotron,
LFRFIDProtocolParadox,
LFRFIDProtocolPACStanley,
LFRFIDProtocolKeri,
LFRFIDProtocolGallagher,
LFRFIDProtocolMax,
} LFRFIDProtocol;
+300
View File
@@ -0,0 +1,300 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <toolbox/manchester_decoder.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
#define GALLAGHER_CLOCK_PER_BIT (32)
#define GALLAGHER_ENCODED_BIT_SIZE (96)
#define GALLAGHER_ENCODED_BYTE_SIZE ((GALLAGHER_ENCODED_BIT_SIZE) / 8)
#define GALLAGHER_PREAMBLE_BIT_SIZE (16)
#define GALLAGHER_PREAMBLE_BYTE_SIZE ((GALLAGHER_PREAMBLE_BIT_SIZE) / 8)
#define GALLAGHER_ENCODED_BYTE_FULL_SIZE \
(GALLAGHER_ENCODED_BYTE_SIZE + GALLAGHER_PREAMBLE_BYTE_SIZE)
#define GALLAGHER_DECODED_DATA_SIZE 8
#define GALLAGHER_READ_SHORT_TIME (128)
#define GALLAGHER_READ_LONG_TIME (256)
#define GALLAGHER_READ_JITTER_TIME (60)
#define GALLAGHER_READ_SHORT_TIME_LOW (GALLAGHER_READ_SHORT_TIME - GALLAGHER_READ_JITTER_TIME)
#define GALLAGHER_READ_SHORT_TIME_HIGH (GALLAGHER_READ_SHORT_TIME + GALLAGHER_READ_JITTER_TIME)
#define GALLAGHER_READ_LONG_TIME_LOW (GALLAGHER_READ_LONG_TIME - GALLAGHER_READ_JITTER_TIME)
#define GALLAGHER_READ_LONG_TIME_HIGH (GALLAGHER_READ_LONG_TIME + GALLAGHER_READ_JITTER_TIME)
typedef struct {
uint8_t data[GALLAGHER_DECODED_DATA_SIZE];
uint8_t encoded_data[GALLAGHER_ENCODED_BYTE_FULL_SIZE];
uint8_t encoded_data_index;
bool encoded_polarity;
ManchesterState decoder_manchester_state;
} ProtocolGallagher;
ProtocolGallagher* protocol_gallagher_alloc(void) {
ProtocolGallagher* proto = malloc(sizeof(ProtocolGallagher));
return (void*)proto;
};
void protocol_gallagher_free(ProtocolGallagher* protocol) {
free(protocol);
};
uint8_t* protocol_gallagher_get_data(ProtocolGallagher* protocol) {
return protocol->data;
};
static void protocol_gallagher_scramble(uint8_t* data, size_t length) {
const uint8_t lut[] = {
0xa3, 0xb0, 0x80, 0xc6, 0xb2, 0xf4, 0x5c, 0x6c, 0x81, 0xf1, 0xbb, 0xeb, 0x55, 0x67, 0x3c,
0x05, 0x1a, 0x0e, 0x61, 0xf6, 0x22, 0xce, 0xaa, 0x8f, 0xbd, 0x3b, 0x1f, 0x5e, 0x44, 0x04,
0x51, 0x2e, 0x4d, 0x9a, 0x84, 0xea, 0xf8, 0x66, 0x74, 0x29, 0x7f, 0x70, 0xd8, 0x31, 0x7a,
0x6d, 0xa4, 0x00, 0x82, 0xb9, 0x5f, 0xb4, 0x16, 0xab, 0xff, 0xc2, 0x39, 0xdc, 0x19, 0x65,
0x57, 0x7c, 0x20, 0xfa, 0x5a, 0x49, 0x13, 0xd0, 0xfb, 0xa8, 0x91, 0x73, 0xb1, 0x33, 0x18,
0xbe, 0x21, 0x72, 0x48, 0xb6, 0xdb, 0xa0, 0x5d, 0xcc, 0xe6, 0x17, 0x27, 0xe5, 0xd4, 0x53,
0x42, 0xf3, 0xdd, 0x7b, 0x24, 0xac, 0x2b, 0x58, 0x1e, 0xa7, 0xe7, 0x86, 0x40, 0xd3, 0x98,
0x97, 0x71, 0xcb, 0x3a, 0x0f, 0x01, 0x9b, 0x6e, 0x1b, 0xfc, 0x34, 0xa6, 0xda, 0x07, 0x0c,
0xae, 0x37, 0xca, 0x54, 0xfd, 0x26, 0xfe, 0x0a, 0x45, 0xa2, 0x2a, 0xc4, 0x12, 0x0d, 0xf5,
0x4f, 0x69, 0xe0, 0x8a, 0x77, 0x60, 0x3f, 0x99, 0x95, 0xd2, 0x38, 0x36, 0x62, 0xb7, 0x32,
0x7e, 0x79, 0xc0, 0x46, 0x93, 0x2f, 0xa5, 0xba, 0x5b, 0xaf, 0x52, 0x1d, 0xc3, 0x75, 0xcf,
0xd6, 0x4c, 0x83, 0xe8, 0x3d, 0x30, 0x4e, 0xbc, 0x08, 0x2d, 0x09, 0x06, 0xd9, 0x25, 0x9e,
0x89, 0xf2, 0x96, 0x88, 0xc1, 0x8c, 0x94, 0x0b, 0x28, 0xf0, 0x47, 0x63, 0xd5, 0xb3, 0x68,
0x56, 0x9c, 0xf9, 0x6f, 0x41, 0x50, 0x85, 0x8b, 0x9d, 0x59, 0xbf, 0x9f, 0xe2, 0x8e, 0x6a,
0x11, 0x23, 0xa1, 0xcd, 0xb5, 0x7d, 0xc7, 0xa9, 0xc8, 0xef, 0xdf, 0x02, 0xb8, 0x03, 0x6b,
0x35, 0x3e, 0x2c, 0x76, 0xc9, 0xde, 0x1c, 0x4b, 0xd1, 0xed, 0x14, 0xc5, 0xad, 0xe9, 0x64,
0x4a, 0xec, 0x8d, 0xf7, 0x10, 0x43, 0x78, 0x15, 0x87, 0xe4, 0xd7, 0x92, 0xe1, 0xee, 0xe3,
0x90};
for(size_t i = 0; i < length; i++) {
data[i] = lut[data[i]];
}
}
static void protocol_gallagher_descramble(uint8_t* data, size_t length) {
const uint8_t lut[] = {
0x2f, 0x6e, 0xdd, 0xdf, 0x1d, 0x0f, 0xb0, 0x76, 0xad, 0xaf, 0x7f, 0xbb, 0x77, 0x85, 0x11,
0x6d, 0xf4, 0xd2, 0x84, 0x42, 0xeb, 0xf7, 0x34, 0x55, 0x4a, 0x3a, 0x10, 0x71, 0xe7, 0xa1,
0x62, 0x1a, 0x3e, 0x4c, 0x14, 0xd3, 0x5e, 0xb2, 0x7d, 0x56, 0xbc, 0x27, 0x82, 0x60, 0xe3,
0xae, 0x1f, 0x9b, 0xaa, 0x2b, 0x95, 0x49, 0x73, 0xe1, 0x92, 0x79, 0x91, 0x38, 0x6c, 0x19,
0x0e, 0xa9, 0xe2, 0x8d, 0x66, 0xc7, 0x5a, 0xf5, 0x1c, 0x80, 0x99, 0xbe, 0x4e, 0x41, 0xf0,
0xe8, 0xa6, 0x20, 0xab, 0x87, 0xc8, 0x1e, 0xa0, 0x59, 0x7b, 0x0c, 0xc3, 0x3c, 0x61, 0xcc,
0x40, 0x9e, 0x06, 0x52, 0x1b, 0x32, 0x8c, 0x12, 0x93, 0xbf, 0xef, 0x3b, 0x25, 0x0d, 0xc2,
0x88, 0xd1, 0xe0, 0x07, 0x2d, 0x70, 0xc6, 0x29, 0x6a, 0x4d, 0x47, 0x26, 0xa3, 0xe4, 0x8b,
0xf6, 0x97, 0x2c, 0x5d, 0x3d, 0xd7, 0x96, 0x28, 0x02, 0x08, 0x30, 0xa7, 0x22, 0xc9, 0x65,
0xf8, 0xb7, 0xb4, 0x8a, 0xca, 0xb9, 0xf2, 0xd0, 0x17, 0xff, 0x46, 0xfb, 0x9a, 0xba, 0x8f,
0xb6, 0x69, 0x68, 0x8e, 0x21, 0x6f, 0xc4, 0xcb, 0xb3, 0xce, 0x51, 0xd4, 0x81, 0x00, 0x2e,
0x9c, 0x74, 0x63, 0x45, 0xd9, 0x16, 0x35, 0x5f, 0xed, 0x78, 0x9f, 0x01, 0x48, 0x04, 0xc1,
0x33, 0xd6, 0x4f, 0x94, 0xde, 0x31, 0x9d, 0x0a, 0xac, 0x18, 0x4b, 0xcd, 0x98, 0xb8, 0x37,
0xa2, 0x83, 0xec, 0x03, 0xd8, 0xda, 0xe5, 0x7a, 0x6b, 0x53, 0xd5, 0x15, 0xa4, 0x43, 0xe9,
0x90, 0x67, 0x58, 0xc0, 0xa5, 0xfa, 0x2a, 0xb1, 0x75, 0x50, 0x39, 0x5c, 0xe6, 0xdc, 0x89,
0xfc, 0xcf, 0xfe, 0xf9, 0x57, 0x54, 0x64, 0xa8, 0xee, 0x23, 0x0b, 0xf1, 0xea, 0xfd, 0xdb,
0xbd, 0x09, 0xb5, 0x5b, 0x05, 0x86, 0x13, 0xf3, 0x24, 0xc5, 0x3f, 0x44, 0x72, 0x7c, 0x7e,
0x36};
for(size_t i = 0; i < length; i++) {
data[i] = lut[data[i]];
}
}
static void protocol_gallagher_decode(ProtocolGallagher* protocol) {
bit_lib_remove_bit_every_nth(protocol->encoded_data, 16, 9 * 8, 9);
protocol_gallagher_descramble(protocol->encoded_data + 2, 8);
// Region code
bit_lib_set_bits(protocol->data, 0, (protocol->encoded_data[5] & 0x1E) >> 1, 4);
// Issue Level
bit_lib_set_bits(protocol->data, 4, (protocol->encoded_data[9] & 0x0F), 4);
// Facility Code
uint32_t fc = (protocol->encoded_data[7] & 0x0F) << 12 | protocol->encoded_data[3] << 4 |
((protocol->encoded_data[9] >> 4) & 0x0F);
protocol->data[3] = (uint8_t)fc;
protocol->data[2] = (uint8_t)(fc >>= 8);
protocol->data[1] = (uint8_t)(fc >>= 8);
// Card Number
uint32_t card = protocol->encoded_data[2] << 16 | (protocol->encoded_data[6] & 0x1F) << 11 |
protocol->encoded_data[4] << 3 | (protocol->encoded_data[5] & 0xE0) >> 5;
protocol->data[7] = (uint8_t)card;
protocol->data[6] = (uint8_t)(card >>= 8);
protocol->data[5] = (uint8_t)(card >>= 8);
protocol->data[4] = (uint8_t)(card >>= 8);
}
static bool protocol_gallagher_can_be_decoded(ProtocolGallagher* protocol) {
// check 16 bits preamble
if(bit_lib_get_bits_16(protocol->encoded_data, 0, 16) != 0b0111111111101010) return false;
// check next 16 bits preamble
if(bit_lib_get_bits_16(protocol->encoded_data, 96, 16) != 0b0111111111101010) return false;
uint8_t checksum_arr[8] = {0};
for(int i = 0, pos = 0; i < 8; i++) {
// Following the preamble, every 9th bit is a checksum-bit for the preceding byte
pos = 16 + (9 * i);
checksum_arr[i] = bit_lib_get_bits(protocol->encoded_data, pos, 8);
}
uint8_t crc = bit_lib_get_bits(protocol->encoded_data, 16 + (9 * 8), 8);
uint8_t calc_crc = bit_lib_crc8(checksum_arr, 8, 0x7, 0x2c, false, false, 0x00);
// crc
if(crc != calc_crc) return false;
return true;
}
void protocol_gallagher_decoder_start(ProtocolGallagher* protocol) {
memset(protocol->encoded_data, 0, GALLAGHER_ENCODED_BYTE_FULL_SIZE);
manchester_advance(
protocol->decoder_manchester_state,
ManchesterEventReset,
&protocol->decoder_manchester_state,
NULL);
};
bool protocol_gallagher_decoder_feed(ProtocolGallagher* protocol, bool level, uint32_t duration) {
bool result = false;
ManchesterEvent event = ManchesterEventReset;
if(duration > GALLAGHER_READ_SHORT_TIME_LOW && duration < GALLAGHER_READ_SHORT_TIME_HIGH) {
if(!level) {
event = ManchesterEventShortHigh;
} else {
event = ManchesterEventShortLow;
}
} else if(duration > GALLAGHER_READ_LONG_TIME_LOW && duration < GALLAGHER_READ_LONG_TIME_HIGH) {
if(!level) {
event = ManchesterEventLongHigh;
} else {
event = ManchesterEventLongLow;
}
}
if(event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
protocol->decoder_manchester_state, event, &protocol->decoder_manchester_state, &data);
if(data_ok) {
bit_lib_push_bit(protocol->encoded_data, GALLAGHER_ENCODED_BYTE_FULL_SIZE, data);
if(protocol_gallagher_can_be_decoded(protocol)) {
protocol_gallagher_decode(protocol);
result = true;
}
}
}
return result;
};
bool protocol_gallagher_encoder_start(ProtocolGallagher* protocol) {
// Preamble
bit_lib_set_bits(protocol->encoded_data, 0, 0b01111111, 8);
bit_lib_set_bits(protocol->encoded_data, 8, 0b11101010, 8);
uint8_t rc = bit_lib_get_bits(protocol->data, 0, 4);
uint8_t il = bit_lib_get_bits(protocol->data, 4, 4);
uint32_t fc = bit_lib_get_bits_32(protocol->data, 8, 24);
uint32_t cn = bit_lib_get_bits_32(protocol->data, 32, 32);
uint8_t payload[8] = {0};
payload[0] = (cn & 0xffffff) >> 16;
payload[1] = (fc & 0xfff) >> 4;
payload[2] = (cn & 0x7ff) >> 3;
payload[3] = (cn & 0x7) << 5 | (rc & 0xf) << 1;
payload[4] = (cn & 0xffff) >> 11;
payload[5] = (fc & 0xffff) >> 12;
payload[6] = 0;
payload[7] = (fc & 0xf) << 4 | (il & 0xf);
// Gallagher scramble
protocol_gallagher_scramble(payload, 8);
for(int i = 0; i < 8; i++) {
// data byte
bit_lib_set_bits(protocol->encoded_data, 16 + (i * 9), payload[i], 8);
// every byte is followed by a bit which is the inverse of the last bit
bit_lib_set_bit(protocol->encoded_data, 16 + (i * 9) + 8, !(payload[i] & 0x1));
}
// checksum
uint8_t crc = bit_lib_crc8(payload, 8, 0x7, 0x2c, false, false, 0x00);
bit_lib_set_bits(protocol->encoded_data, 16 + (9 * 8), crc, 8);
return true;
};
LevelDuration protocol_gallagher_encoder_yield(ProtocolGallagher* protocol) {
bool level = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_data_index);
uint32_t duration = GALLAGHER_CLOCK_PER_BIT / 2;
if(protocol->encoded_polarity) {
protocol->encoded_polarity = false;
} else {
level = !level;
protocol->encoded_polarity = true;
bit_lib_increment_index(protocol->encoded_data_index, GALLAGHER_ENCODED_BIT_SIZE);
}
return level_duration_make(level, duration);
};
bool protocol_gallagher_write_data(ProtocolGallagher* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_gallagher_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] =
(LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_32 |
(3 << LFRFID_T5577_MAXBLOCK_SHIFT));
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.blocks_to_write = 4;
result = true;
}
return result;
};
void protocol_gallagher_render_data(ProtocolGallagher* protocol, string_t result) {
UNUSED(protocol);
uint8_t rc = bit_lib_get_bits(protocol->data, 0, 4);
uint8_t il = bit_lib_get_bits(protocol->data, 4, 4);
uint32_t fc = bit_lib_get_bits_32(protocol->data, 8, 24);
uint32_t card_id = bit_lib_get_bits_32(protocol->data, 32, 32);
string_cat_printf(result, "Region: %u, Issue Level: %u\r\n", rc, il);
string_cat_printf(result, "FC: %u, C: %lu\r\n", fc, card_id);
};
const ProtocolBase protocol_gallagher = {
.name = "Gallagher",
.manufacturer = "Gallagher",
.data_size = GALLAGHER_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_gallagher_alloc,
.free = (ProtocolFree)protocol_gallagher_free,
.get_data = (ProtocolGetData)protocol_gallagher_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_gallagher_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_gallagher_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_gallagher_encoder_start,
.yield = (ProtocolEncoderYield)protocol_gallagher_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_gallagher_render_data,
.render_brief_data = (ProtocolRenderData)protocol_gallagher_render_data,
.write_data = (ProtocolWriteData)protocol_gallagher_write_data,
};
@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_gallagher;
+264
View File
@@ -0,0 +1,264 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
#define KERI_PREAMBLE_BIT_SIZE (33)
#define KERI_PREAMBLE_DATA_SIZE (5)
#define KERI_ENCODED_BIT_SIZE (64)
#define KERI_ENCODED_DATA_SIZE (((KERI_ENCODED_BIT_SIZE) / 8) + KERI_PREAMBLE_DATA_SIZE)
#define KERI_ENCODED_DATA_LAST ((KERI_ENCODED_BIT_SIZE) / 8)
#define KERI_DECODED_BIT_SIZE (28)
#define KERI_DECODED_DATA_SIZE (4)
#define KERI_US_PER_BIT (255)
#define KERI_ENCODER_PULSES_PER_BIT (16)
typedef struct {
uint8_t data_index;
uint8_t bit_clock_index;
bool last_bit;
bool current_polarity;
bool pulse_phase;
} ProtocolKeriEncoder;
typedef struct {
uint8_t encoded_data[KERI_ENCODED_DATA_SIZE];
uint8_t negative_encoded_data[KERI_ENCODED_DATA_SIZE];
uint8_t corrupted_encoded_data[KERI_ENCODED_DATA_SIZE];
uint8_t corrupted_negative_encoded_data[KERI_ENCODED_DATA_SIZE];
uint8_t data[KERI_DECODED_DATA_SIZE];
ProtocolKeriEncoder encoder;
} ProtocolKeri;
ProtocolKeri* protocol_keri_alloc(void) {
ProtocolKeri* protocol = malloc(sizeof(ProtocolKeri));
return protocol;
};
void protocol_keri_free(ProtocolKeri* protocol) {
free(protocol);
};
uint8_t* protocol_keri_get_data(ProtocolKeri* protocol) {
return protocol->data;
};
void protocol_keri_decoder_start(ProtocolKeri* protocol) {
memset(protocol->encoded_data, 0, KERI_ENCODED_DATA_SIZE);
memset(protocol->negative_encoded_data, 0, KERI_ENCODED_DATA_SIZE);
memset(protocol->corrupted_encoded_data, 0, KERI_ENCODED_DATA_SIZE);
memset(protocol->corrupted_negative_encoded_data, 0, KERI_ENCODED_DATA_SIZE);
};
static bool protocol_keri_check_preamble(uint8_t* data, size_t bit_index) {
// Preamble 11100000 00000000 00000000 00000000 1
if(*(uint32_t*)&data[bit_index / 8] != 0b00000000000000000000000011100000) return false;
if(bit_lib_get_bit(data, bit_index + 32) != 1) return false;
return true;
}
static bool protocol_keri_can_be_decoded(uint8_t* data) {
if(!protocol_keri_check_preamble(data, 0)) return false;
if(!protocol_keri_check_preamble(data, 64)) return false;
///if(bit_lib_get_bit(data, 61) != 0) return false;
//if(bit_lib_get_bit(data, 60) != 0) return false;
return true;
}
static bool protocol_keri_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) {
time += (KERI_US_PER_BIT / 2);
size_t bit_count = (time / KERI_US_PER_BIT);
bool result = false;
if(bit_count < KERI_ENCODED_BIT_SIZE) {
for(size_t i = 0; i < bit_count; i++) {
bit_lib_push_bit(data, KERI_ENCODED_DATA_SIZE, polarity);
if(protocol_keri_can_be_decoded(data)) {
result = true;
break;
}
}
}
return result;
}
static void protocol_keri_descramble(uint32_t* fc, uint32_t* cn, uint32_t* internal_id) {
const uint8_t card_to_id[] = {255, 255, 255, 255, 13, 12, 20, 5, 16, 6, 21,
17, 8, 255, 0, 7, 10, 15, 255, 11, 4, 1,
255, 18, 255, 19, 2, 14, 3, 9, 255, 255};
const uint8_t card_to_fc[] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 0, 255, 255, 255, 255, 2, 255, 255, 255,
3, 255, 4, 255, 255, 255, 255, 255, 1, 255};
*fc = 0;
*cn = 0;
for(uint8_t card_idx = 0; card_idx < 32; card_idx++) {
bool bit = (*internal_id >> card_idx) & 1;
// Card ID
if(card_to_id[card_idx] < 32) {
*cn = *cn | (bit << card_to_id[card_idx]);
}
// Card FC
if(card_to_fc[card_idx] < 32) {
*fc = *fc | (bit << card_to_fc[card_idx]);
}
}
}
static void protocol_keri_decoder_save(uint8_t* data_to, const uint8_t* data_from) {
uint32_t id = bit_lib_get_bits_32(data_from, 32, 32);
data_to[3] = (uint8_t)id;
data_to[2] = (uint8_t)(id >>= 8);
data_to[1] = (uint8_t)(id >>= 8);
data_to[0] = (uint8_t)(id >>= 8);
}
bool protocol_keri_decoder_feed(ProtocolKeri* protocol, bool level, uint32_t duration) {
bool result = false;
if(duration > (KERI_US_PER_BIT / 2)) {
if(protocol_keri_decoder_feed_internal(level, duration, protocol->encoded_data)) {
protocol_keri_decoder_save(protocol->data, protocol->encoded_data);
result = true;
return result;
}
if(protocol_keri_decoder_feed_internal(!level, duration, protocol->negative_encoded_data)) {
protocol_keri_decoder_save(protocol->data, protocol->negative_encoded_data);
result = true;
return result;
}
}
if(duration > (KERI_US_PER_BIT / 4)) {
// Try to decode wrong phase synced data
if(level) {
duration += 120;
} else {
if(duration > 120) {
duration -= 120;
}
}
if(protocol_keri_decoder_feed_internal(level, duration, protocol->corrupted_encoded_data)) {
protocol_keri_decoder_save(protocol->data, protocol->corrupted_encoded_data);
result = true;
return result;
}
if(protocol_keri_decoder_feed_internal(
!level, duration, protocol->corrupted_negative_encoded_data)) {
protocol_keri_decoder_save(protocol->data, protocol->corrupted_negative_encoded_data);
result = true;
return result;
}
}
return result;
};
bool protocol_keri_encoder_start(ProtocolKeri* protocol) {
memset(protocol->encoded_data, 0, KERI_ENCODED_DATA_SIZE);
*(uint32_t*)&protocol->encoded_data[0] = 0b00000000000000000000000011100000;
bit_lib_copy_bits(protocol->encoded_data, 32, 32, protocol->data, 0);
protocol->encoder.last_bit =
bit_lib_get_bit(protocol->encoded_data, KERI_ENCODED_BIT_SIZE - 1);
protocol->encoder.data_index = 0;
protocol->encoder.current_polarity = true;
protocol->encoder.pulse_phase = true;
protocol->encoder.bit_clock_index = 0;
return true;
};
LevelDuration protocol_keri_encoder_yield(ProtocolKeri* protocol) {
LevelDuration level_duration;
ProtocolKeriEncoder* encoder = &protocol->encoder;
if(encoder->pulse_phase) {
level_duration = level_duration_make(encoder->current_polarity, 1);
encoder->pulse_phase = false;
} else {
level_duration = level_duration_make(!encoder->current_polarity, 1);
encoder->pulse_phase = true;
encoder->bit_clock_index++;
if(encoder->bit_clock_index >= KERI_ENCODER_PULSES_PER_BIT) {
encoder->bit_clock_index = 0;
bool current_bit = bit_lib_get_bit(protocol->encoded_data, encoder->data_index);
if(current_bit != encoder->last_bit) {
encoder->current_polarity = !encoder->current_polarity;
}
encoder->last_bit = current_bit;
bit_lib_increment_index(encoder->data_index, KERI_ENCODED_BIT_SIZE);
}
}
return level_duration;
};
void protocol_keri_render_data(ProtocolKeri* protocol, string_t result) {
uint32_t data = bit_lib_get_bits_32(protocol->data, 0, 32);
uint32_t internal_id = data & 0x7FFFFFFF;
uint32_t fc = 0;
uint32_t cn = 0;
protocol_keri_descramble(&fc, &cn, &data);
string_printf(result, "Internal ID: %u\r\nFC: %u, Card: %u\r\n", internal_id, fc, cn);
}
bool protocol_keri_write_data(ProtocolKeri* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_keri_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_TESTMODE_DISABLED | LFRFID_T5577_X_MODE |
LFRFID_T5577_MODULATION_PSK1 | LFRFID_T5577_PSKCF_RF_2 |
(2 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[0] |= 0xF << 18;
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.blocks_to_write = 3;
result = true;
}
return result;
};
const ProtocolBase protocol_keri = {
.name = "Keri",
.manufacturer = "Keri",
.data_size = KERI_DECODED_DATA_SIZE,
.features = LFRFIDFeaturePSK,
.validate_count = 6,
.alloc = (ProtocolAlloc)protocol_keri_alloc,
.free = (ProtocolFree)protocol_keri_free,
.get_data = (ProtocolGetData)protocol_keri_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_keri_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_keri_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_keri_encoder_start,
.yield = (ProtocolEncoderYield)protocol_keri_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_keri_render_data,
.render_brief_data = (ProtocolRenderData)protocol_keri_render_data,
.write_data = (ProtocolWriteData)protocol_keri_write_data,
};
+4
View File
@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_keri;
+12 -8
View File
@@ -13,6 +13,9 @@
*/
#define TAG "SubGhzProtocolCAME"
#define CAME_24_COUNT_BIT 24
#define PRASTEL_COUNT_BIT 25
#define PRASTEL_NAME "Prastel"
static const SubGhzBlockConst subghz_protocol_came_const = {
.te_short = 320,
@@ -114,9 +117,9 @@ static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* i
//Send header
instance->encoder.upload[index++] = level_duration_make(
false,
((instance->generic.data_count_bit == subghz_protocol_came_const.min_count_bit_for_found) ?
(uint32_t)subghz_protocol_came_const.te_short * 39 :
(uint32_t)subghz_protocol_came_const.te_short * 76));
((instance->generic.data_count_bit == CAME_24_COUNT_BIT) ?
(uint32_t)subghz_protocol_came_const.te_short * 76 :
(uint32_t)subghz_protocol_came_const.te_short * 39));
//Send start bit
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short);
@@ -150,8 +153,8 @@ bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flip
}
if((instance->generic.data_count_bit !=
subghz_protocol_came_const.min_count_bit_for_found) &&
(instance->generic.data_count_bit !=
2 * subghz_protocol_came_const.min_count_bit_for_found)) {
(instance->generic.data_count_bit != CAME_24_COUNT_BIT) &&
(instance->generic.data_count_bit != PRASTEL_COUNT_BIT)) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
@@ -309,8 +312,8 @@ bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flip
}
if((instance->generic.data_count_bit !=
subghz_protocol_came_const.min_count_bit_for_found) &&
(instance->generic.data_count_bit !=
2 * subghz_protocol_came_const.min_count_bit_for_found)) {
(instance->generic.data_count_bit != CAME_24_COUNT_BIT) &&
(instance->generic.data_count_bit != PRASTEL_COUNT_BIT)) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
@@ -335,7 +338,8 @@ void subghz_protocol_decoder_came_get_string(void* context, string_t output) {
"%s %dbit\r\n"
"Key:0x%08lX\r\n"
"Yek:0x%08lX\r\n",
instance->generic.protocol_name,
(instance->generic.data_count_bit == PRASTEL_COUNT_BIT ? PRASTEL_NAME :
instance->generic.protocol_name),
instance->generic.data_count_bit,
code_found_lo,
code_found_reverse_lo);
+472
View File
@@ -0,0 +1,472 @@
#include "intertechno_v3.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolIntertechnoV3"
#define CH_PATTERN "%c%c%c%c"
#define CNT_TO_CH(ch) \
(ch & 0x8 ? '1' : '0'), (ch & 0x4 ? '1' : '0'), (ch & 0x2 ? '1' : '0'), (ch & 0x1 ? '1' : '0')
#define INTERTECHNO_V3_DIMMING_COUNT_BIT 36
static const SubGhzBlockConst subghz_protocol_intertechno_v3_const = {
.te_short = 275,
.te_long = 1375,
.te_delta = 150,
.min_count_bit_for_found = 32,
};
struct SubGhzProtocolDecoderIntertechno_V3 {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
};
struct SubGhzProtocolEncoderIntertechno_V3 {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
IntertechnoV3DecoderStepReset = 0,
IntertechnoV3DecoderStepStartSync,
IntertechnoV3DecoderStepFoundSync,
IntertechnoV3DecoderStepStartDuration,
IntertechnoV3DecoderStepSaveDuration,
IntertechnoV3DecoderStepCheckDuration,
IntertechnoV3DecoderStepEndDuration,
} IntertechnoV3DecoderStep;
const SubGhzProtocolDecoder subghz_protocol_intertechno_v3_decoder = {
.alloc = subghz_protocol_decoder_intertechno_v3_alloc,
.free = subghz_protocol_decoder_intertechno_v3_free,
.feed = subghz_protocol_decoder_intertechno_v3_feed,
.reset = subghz_protocol_decoder_intertechno_v3_reset,
.get_hash_data = subghz_protocol_decoder_intertechno_v3_get_hash_data,
.serialize = subghz_protocol_decoder_intertechno_v3_serialize,
.deserialize = subghz_protocol_decoder_intertechno_v3_deserialize,
.get_string = subghz_protocol_decoder_intertechno_v3_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_intertechno_v3_encoder = {
.alloc = subghz_protocol_encoder_intertechno_v3_alloc,
.free = subghz_protocol_encoder_intertechno_v3_free,
.deserialize = subghz_protocol_encoder_intertechno_v3_deserialize,
.stop = subghz_protocol_encoder_intertechno_v3_stop,
.yield = subghz_protocol_encoder_intertechno_v3_yield,
};
const SubGhzProtocol subghz_protocol_intertechno_v3 = {
.name = SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load |
SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_intertechno_v3_decoder,
.encoder = &subghz_protocol_intertechno_v3_encoder,
};
void* subghz_protocol_encoder_intertechno_v3_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolEncoderIntertechno_V3* instance =
malloc(sizeof(SubGhzProtocolEncoderIntertechno_V3));
instance->base.protocol = &subghz_protocol_intertechno_v3;
instance->generic.protocol_name = instance->base.protocol->name;
instance->encoder.repeat = 10;
instance->encoder.size_upload = 256;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;
}
void subghz_protocol_encoder_intertechno_v3_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderIntertechno_V3* instance = context;
free(instance->encoder.upload);
free(instance);
}
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance
* @return true On success
*/
static bool subghz_protocol_encoder_intertechno_v3_get_upload(
SubGhzProtocolEncoderIntertechno_V3* instance) {
furi_assert(instance);
size_t index = 0;
//Send header
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short * 38);
//Send sync
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short * 10);
//Send key data
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if((instance->generic.data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) && (i == 9)) {
//send bit dimm
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
} else if(bit_read(instance->generic.data, i - 1)) {
//send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_intertechno_v3_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_intertechno_v3_const.te_long);
}
}
instance->encoder.size_upload = index;
return true;
}
bool subghz_protocol_encoder_intertechno_v3_deserialize(
void* context,
FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderIntertechno_V3* instance = context;
bool res = false;
do {
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
if((instance->generic.data_count_bit !=
subghz_protocol_intertechno_v3_const.min_count_bit_for_found) &&
(instance->generic.data_count_bit != INTERTECHNO_V3_DIMMING_COUNT_BIT)) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
//optional parameter parameter
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
subghz_protocol_encoder_intertechno_v3_get_upload(instance);
instance->encoder.is_running = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_intertechno_v3_stop(void* context) {
SubGhzProtocolEncoderIntertechno_V3* instance = context;
instance->encoder.is_running = false;
}
LevelDuration subghz_protocol_encoder_intertechno_v3_yield(void* context) {
SubGhzProtocolEncoderIntertechno_V3* instance = context;
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
instance->encoder.is_running = false;
return level_duration_reset();
}
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
if(++instance->encoder.front == instance->encoder.size_upload) {
instance->encoder.repeat--;
instance->encoder.front = 0;
}
return ret;
}
void* subghz_protocol_decoder_intertechno_v3_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolDecoderIntertechno_V3* instance =
malloc(sizeof(SubGhzProtocolDecoderIntertechno_V3));
instance->base.protocol = &subghz_protocol_intertechno_v3;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_intertechno_v3_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderIntertechno_V3* instance = context;
free(instance);
}
void subghz_protocol_decoder_intertechno_v3_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderIntertechno_V3* instance = context;
instance->decoder.parser_step = IntertechnoV3DecoderStepReset;
}
void subghz_protocol_decoder_intertechno_v3_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderIntertechno_V3* instance = context;
switch(instance->decoder.parser_step) {
case IntertechnoV3DecoderStepReset:
if((!level) &&
(DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short * 37) <
subghz_protocol_intertechno_v3_const.te_delta * 15)) {
instance->decoder.parser_step = IntertechnoV3DecoderStepStartSync;
}
break;
case IntertechnoV3DecoderStepStartSync:
if(level && (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) <
subghz_protocol_intertechno_v3_const.te_delta)) {
instance->decoder.parser_step = IntertechnoV3DecoderStepFoundSync;
} else {
instance->decoder.parser_step = IntertechnoV3DecoderStepReset;
}
break;
case IntertechnoV3DecoderStepFoundSync:
if(!level && (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short * 10) <
subghz_protocol_intertechno_v3_const.te_delta * 3)) {
instance->decoder.parser_step = IntertechnoV3DecoderStepStartDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else {
instance->decoder.parser_step = IntertechnoV3DecoderStepReset;
}
break;
case IntertechnoV3DecoderStepStartDuration:
if(level && (DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) <
subghz_protocol_intertechno_v3_const.te_delta)) {
instance->decoder.parser_step = IntertechnoV3DecoderStepSaveDuration;
} else {
instance->decoder.parser_step = IntertechnoV3DecoderStepReset;
}
break;
case IntertechnoV3DecoderStepSaveDuration:
if(!level) { //save interval
if(duration >= (subghz_protocol_intertechno_v3_const.te_short * 11)) {
instance->decoder.parser_step = IntertechnoV3DecoderStepStartSync;
if((instance->decoder.decode_count_bit ==
subghz_protocol_intertechno_v3_const.min_count_bit_for_found) ||
(instance->decoder.decode_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT)) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
break;
}
instance->decoder.te_last = duration;
instance->decoder.parser_step = IntertechnoV3DecoderStepCheckDuration;
} else {
instance->decoder.parser_step = IntertechnoV3DecoderStepReset;
}
break;
case IntertechnoV3DecoderStepCheckDuration:
if(level) {
//Add 0 bit
if((DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_intertechno_v3_const.te_short) <
subghz_protocol_intertechno_v3_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) <
subghz_protocol_intertechno_v3_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = IntertechnoV3DecoderStepEndDuration;
} else if(
//Add 1 bit
(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_intertechno_v3_const.te_long) <
subghz_protocol_intertechno_v3_const.te_delta * 2) &&
(DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) <
subghz_protocol_intertechno_v3_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = IntertechnoV3DecoderStepEndDuration;
} else if(
//Add dimm_state
(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_intertechno_v3_const.te_short) <
subghz_protocol_intertechno_v3_const.te_delta * 2) &&
(DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) <
subghz_protocol_intertechno_v3_const.te_delta) &&
(instance->decoder.decode_count_bit == 27)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = IntertechnoV3DecoderStepEndDuration;
} else
instance->decoder.parser_step = IntertechnoV3DecoderStepReset;
} else {
instance->decoder.parser_step = IntertechnoV3DecoderStepReset;
}
break;
case IntertechnoV3DecoderStepEndDuration:
if(!level && ((DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_short) <
subghz_protocol_intertechno_v3_const.te_delta) ||
(DURATION_DIFF(duration, subghz_protocol_intertechno_v3_const.te_long) <
subghz_protocol_intertechno_v3_const.te_delta * 2))) {
instance->decoder.parser_step = IntertechnoV3DecoderStepStartDuration;
} else {
instance->decoder.parser_step = IntertechnoV3DecoderStepReset;
}
break;
}
}
/**
* Analysis of received data
* @param instance Pointer to a SubGhzBlockGeneric* instance
*/
static void subghz_protocol_intertechno_v3_check_remote_controller(SubGhzBlockGeneric* instance) {
/*
* A frame is either 32 or 36 bits:
*
* _
* start bit: | |__________ (T,10T)
* _ _
* '0': | |_| |_____ (T,T,T,5T)
* _ _
* '1': | |_____| |_ (T,5T,T,T)
* _ _
* dimm: | |_| |_ (T,T,T,T)
*
* _
* stop bit: | |____...____ (T,38T)
*
* if frame 32 bits
* SSSSSSSSSSSSSSSSSSSSSSSSSS all_ch on/off ~ch
* Key:0x3F86C59F => 00111111100001101100010110 0 1 1111
*
* if frame 36 bits
* SSSSSSSSSSSSSSSSSSSSSSSSSS all_ch dimm ~ch dimm_level
* Key:0x42D2E8856 => 01000010110100101110100010 0 X 0101 0110
*
*/
if(instance->data_count_bit == subghz_protocol_intertechno_v3_const.min_count_bit_for_found) {
instance->serial = (instance->data >> 6) & 0x3FFFFFF;
if((instance->data >> 5) & 0x1) {
instance->cnt = 1 << 5;
} else {
instance->cnt = (~instance->data & 0xF);
}
instance->btn = (instance->data >> 4) & 0x1;
} else if(instance->data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) {
instance->serial = (instance->data >> 10) & 0x3FFFFFF;
if((instance->data >> 9) & 0x1) {
instance->cnt = 1 << 5;
} else {
instance->cnt = (~(instance->data >> 4) & 0xF);
}
instance->btn = (instance->data) & 0xF;
} else {
instance->serial = 0;
instance->cnt = 0;
instance->btn = 0;
}
}
uint8_t subghz_protocol_decoder_intertechno_v3_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderIntertechno_V3* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_intertechno_v3_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzPresetDefinition* preset) {
furi_assert(context);
SubGhzProtocolDecoderIntertechno_V3* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
}
bool subghz_protocol_decoder_intertechno_v3_deserialize(
void* context,
FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderIntertechno_V3* instance = context;
bool ret = false;
do {
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if((instance->generic.data_count_bit !=
subghz_protocol_intertechno_v3_const.min_count_bit_for_found) &&
(instance->generic.data_count_bit != INTERTECHNO_V3_DIMMING_COUNT_BIT)) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
}
void subghz_protocol_decoder_intertechno_v3_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderIntertechno_V3* instance = context;
subghz_protocol_intertechno_v3_check_remote_controller(&instance->generic);
string_cat_printf(
output,
"%.11s %db\r\n"
"Key:0x%08llX\r\n"
"Sn:%07lX\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
instance->generic.data,
instance->generic.serial);
if(instance->generic.data_count_bit ==
subghz_protocol_intertechno_v3_const.min_count_bit_for_found) {
if(instance->generic.cnt >> 5) {
string_cat_printf(
output, "Ch: All Btn:%s\r\n", (instance->generic.btn ? "On" : "Off"));
} else {
string_cat_printf(
output,
"Ch:" CH_PATTERN " Btn:%s\r\n",
CNT_TO_CH(instance->generic.cnt),
(instance->generic.btn ? "On" : "Off"));
}
} else if(instance->generic.data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) {
string_cat_printf(
output,
"Ch:" CH_PATTERN " Dimm:%d%%\r\n",
CNT_TO_CH(instance->generic.cnt),
(int)(6.67 * (float)instance->generic.btn));
}
}
+111
View File
@@ -0,0 +1,111 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME "Intertechno_V3"
typedef struct SubGhzProtocolDecoderIntertechno_V3 SubGhzProtocolDecoderIntertechno_V3;
typedef struct SubGhzProtocolEncoderIntertechno_V3 SubGhzProtocolEncoderIntertechno_V3;
extern const SubGhzProtocolDecoder subghz_protocol_intertechno_v3_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_intertechno_v3_encoder;
extern const SubGhzProtocol subghz_protocol_intertechno_v3;
/**
* Allocate SubGhzProtocolEncoderIntertechno_V3.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolEncoderIntertechno_V3* pointer to a SubGhzProtocolEncoderIntertechno_V3 instance
*/
void* subghz_protocol_encoder_intertechno_v3_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolEncoderIntertechno_V3.
* @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance
*/
void subghz_protocol_encoder_intertechno_v3_free(void* context);
/**
* Deserialize and generating an upload to send.
* @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
bool subghz_protocol_encoder_intertechno_v3_deserialize(
void* context,
FlipperFormat* flipper_format);
/**
* Forced transmission stop.
* @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance
*/
void subghz_protocol_encoder_intertechno_v3_stop(void* context);
/**
* Getting the level and duration of the upload to be loaded into DMA.
* @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance
* @return LevelDuration
*/
LevelDuration subghz_protocol_encoder_intertechno_v3_yield(void* context);
/**
* Allocate SubGhzProtocolDecoderIntertechno_V3.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolDecoderIntertechno_V3* pointer to a SubGhzProtocolDecoderIntertechno_V3 instance
*/
void* subghz_protocol_decoder_intertechno_v3_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolDecoderIntertechno_V3.
* @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance
*/
void subghz_protocol_decoder_intertechno_v3_free(void* context);
/**
* Reset decoder SubGhzProtocolDecoderIntertechno_V3.
* @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance
*/
void subghz_protocol_decoder_intertechno_v3_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void subghz_protocol_decoder_intertechno_v3_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance
* @return hash Hash sum
*/
uint8_t subghz_protocol_decoder_intertechno_v3_get_hash_data(void* context);
/**
* Serialize data SubGhzProtocolDecoderIntertechno_V3.
* @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzPresetDefinition
* @return true On success
*/
bool subghz_protocol_decoder_intertechno_v3_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzPresetDefinition* preset);
/**
* Deserialize data SubGhzProtocolDecoderIntertechno_V3.
* @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
bool subghz_protocol_decoder_intertechno_v3_deserialize(
void* context,
FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance
* @param output Resulting text
*/
void subghz_protocol_decoder_intertechno_v3_get_string(void* context, string_t output);
+5 -4
View File
@@ -360,11 +360,11 @@ static void subghz_protocol_magellen_check_remote_controller(SubGhzBlockGeneric*
* 0x1275EC => 0x12-event codes, 0x75EC-serial (dec 117236)
*
* event codes
* bit_0: 1-alarm, 0-close
* bit_0: 1-Open/Motion, 0-close/ok
* bit_1: 1-Tamper On (alarm), 0-Tamper Off (ok)
* bit_2: ?
* bit_3: 1-power on
* bit_4: model type - door alarm
* bit_4: model type - wireless reed
* bit_5: model type - motion sensor
* bit_6: ?
* bit_7: ?
@@ -379,11 +379,12 @@ static void subghz_protocol_magellen_get_event_serialize(uint8_t event, string_t
string_cat_printf(
output,
"%s%s%s%s%s%s%s%s",
(event & 0x1 ? " Alarm" : "Ok"),
((event >> 4) & 0x1 ? (event & 0x1 ? " Open" : " Close") :
(event & 0x1 ? " Motion" : " Ok")),
((event >> 1) & 0x1 ? ", Tamper On (Alarm)" : ""),
((event >> 2) & 0x1 ? ", ?" : ""),
((event >> 3) & 0x1 ? ", Power On" : ""),
((event >> 4) & 0x1 ? ", MT:Door_Alarm" : ""),
((event >> 4) & 0x1 ? ", MT:Wireless_Reed" : ""),
((event >> 5) & 0x1 ? ", MT:Motion_Sensor" : ""),
((event >> 6) & 0x1 ? ", ?" : ""),
((event >> 7) & 0x1 ? ", ?" : ""));
+1 -1
View File
@@ -11,7 +11,7 @@ const SubGhzProtocol* subghz_protocol_registry[] = {
&subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek,
&subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec,
&subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2,
&subghz_protocol_honeywell_wdb, &subghz_protocol_magellen,
&subghz_protocol_honeywell_wdb, &subghz_protocol_magellen, &subghz_protocol_intertechno_v3,
};
+1
View File
@@ -34,6 +34,7 @@
#include "phoenix_v2.h"
#include "honeywell_wdb.h"
#include "magellen.h"
#include "intertechno_v3.h"
/**
* Registration by name SubGhzProtocol.