* iButton, helpers: add destructor * iButton app: new approach to cli commands, cli read * iButton app: cli write * iButton app: cli emulate * iButton app: remove old cli commands * iButton app: use unique_ptr for worker * iButton app: remove obsolete cli help * iButton app: fix help and key type parsing
		
			
				
	
	
		
			204 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "key-emulator.h"
 | 
						|
#include <callback-connector.h>
 | 
						|
 | 
						|
KeyEmulator::~KeyEmulator() {
 | 
						|
    stop();
 | 
						|
}
 | 
						|
 | 
						|
KeyEmulator::KeyEmulator(OneWireSlave* _onewire_slave)
 | 
						|
    : dallas_key{0, 0, 0, 0, 0, 0, 0} {
 | 
						|
    onewire_slave = _onewire_slave;
 | 
						|
 | 
						|
    auto cb = cbc::obtain_connector(this, &KeyEmulator::result_callback);
 | 
						|
    onewire_slave->set_result_callback(cb, this);
 | 
						|
}
 | 
						|
 | 
						|
void KeyEmulator::start(iButtonKey* key) {
 | 
						|
    anything_emulated = false;
 | 
						|
    stop();
 | 
						|
 | 
						|
    switch(key->get_key_type()) {
 | 
						|
    case iButtonKeyType::KeyDallas:
 | 
						|
        start_dallas_emulate(key);
 | 
						|
        break;
 | 
						|
    case iButtonKeyType::KeyCyfral:
 | 
						|
        start_cyfral_emulate(key);
 | 
						|
        break;
 | 
						|
    case iButtonKeyType::KeyMetakom:
 | 
						|
        start_metakom_emulate(key);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
bool KeyEmulator::emulated() {
 | 
						|
    bool result = false;
 | 
						|
 | 
						|
    if(anything_emulated) {
 | 
						|
        anything_emulated = false;
 | 
						|
        result = true;
 | 
						|
    }
 | 
						|
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
void KeyEmulator::stop() {
 | 
						|
    onewire_slave->stop();
 | 
						|
    pulser.stop();
 | 
						|
}
 | 
						|
 | 
						|
void KeyEmulator::start_cyfral_emulate(iButtonKey* key) {
 | 
						|
    furi_assert(key->get_key_type() == iButtonKeyType::KeyCyfral);
 | 
						|
    furi_assert(key->get_type_data_size() == 2);
 | 
						|
 | 
						|
    const uint32_t cyfral_period_full = 8000;
 | 
						|
    const uint32_t cyfral_period_one[2] = {
 | 
						|
        uint32_t(cyfral_period_full * 0.33f), uint32_t(cyfral_period_full * 0.66f)};
 | 
						|
    const uint32_t cyfral_period_zero[2] = {
 | 
						|
        uint32_t(cyfral_period_full * 0.66f), uint32_t(cyfral_period_full * 0.33f)};
 | 
						|
    uint8_t pd_index = 0;
 | 
						|
    uint8_t* key_data = key->get_data();
 | 
						|
 | 
						|
    // start nibble
 | 
						|
    set_pulse_data_cyfral(pd_index, cyfral_period_zero);
 | 
						|
    pd_index++;
 | 
						|
    set_pulse_data_cyfral(pd_index, cyfral_period_zero);
 | 
						|
    pd_index++;
 | 
						|
    set_pulse_data_cyfral(pd_index, cyfral_period_zero);
 | 
						|
    pd_index++;
 | 
						|
    set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
    pd_index++;
 | 
						|
 | 
						|
    // data nibbles x 8
 | 
						|
    for(int8_t i = key->get_type_data_size() - 1; i >= 0; i--) {
 | 
						|
        for(int8_t j = 3; j >= 0; j--) {
 | 
						|
            switch((key_data[i] >> (j * 2)) & 0b00000011) {
 | 
						|
            case 0b11:
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_zero);
 | 
						|
                pd_index++;
 | 
						|
                break;
 | 
						|
            case 0b10:
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_zero);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                break;
 | 
						|
            case 0b01:
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_zero);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                break;
 | 
						|
            case 0b00:
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_zero);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                set_pulse_data_cyfral(pd_index, cyfral_period_one);
 | 
						|
                pd_index++;
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                // cannot be anyway
 | 
						|
                furi_check(false);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // 4 (nibbles) x (8 data + 1 start) = 4 x 9 = 36
 | 
						|
    if(pd_index != 36) {
 | 
						|
        // something is very wrong
 | 
						|
        furi_check(false);
 | 
						|
    }
 | 
						|
 | 
						|
    pulser.set_periods(pulse_data, 72, false);
 | 
						|
    pulser.start();
 | 
						|
}
 | 
						|
 | 
						|
void KeyEmulator::start_metakom_emulate(iButtonKey* key) {
 | 
						|
    furi_assert(key->get_key_type() == iButtonKeyType::KeyMetakom);
 | 
						|
    furi_assert(key->get_type_data_size() == 4);
 | 
						|
 | 
						|
    const uint32_t metakom_period_full = 8000;
 | 
						|
    const uint32_t metakom_period_zero[2] = {
 | 
						|
        uint32_t(metakom_period_full * 0.33f), uint32_t(metakom_period_full * 0.66f)};
 | 
						|
    const uint32_t metakom_period_one[2] = {
 | 
						|
        uint32_t(metakom_period_full * 0.66f), uint32_t(metakom_period_full * 0.33f)};
 | 
						|
    uint8_t pd_index = 0;
 | 
						|
 | 
						|
    uint8_t* key_data = key->get_data();
 | 
						|
 | 
						|
    // start pulse
 | 
						|
    pulse_data[0] = metakom_period_full * 4;
 | 
						|
 | 
						|
    // start triplet
 | 
						|
    set_pulse_data_metakom(pd_index, metakom_period_zero);
 | 
						|
    pd_index++;
 | 
						|
    set_pulse_data_metakom(pd_index, metakom_period_one);
 | 
						|
    pd_index++;
 | 
						|
    set_pulse_data_metakom(pd_index, metakom_period_zero);
 | 
						|
    pd_index++;
 | 
						|
 | 
						|
    for(int8_t i = key->get_type_data_size() - 1; i >= 0; i--) {
 | 
						|
        for(int8_t j = 7; j >= 0; j--) {
 | 
						|
            if(((key_data[i] >> j) & 0b00000001) == 1) {
 | 
						|
                set_pulse_data_metakom(pd_index, metakom_period_one);
 | 
						|
                pd_index++;
 | 
						|
            } else {
 | 
						|
                set_pulse_data_metakom(pd_index, metakom_period_zero);
 | 
						|
                pd_index++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // 4 byte x 8 bits + 3 start bits = 35
 | 
						|
    if(pd_index != 35) {
 | 
						|
        // something is very wrong
 | 
						|
        furi_check(false);
 | 
						|
    }
 | 
						|
 | 
						|
    pulser.set_periods(pulse_data, 71, false);
 | 
						|
    pulser.start();
 | 
						|
}
 | 
						|
 | 
						|
void KeyEmulator::start_dallas_emulate(iButtonKey* key) {
 | 
						|
    furi_assert(key->get_key_type() == iButtonKeyType::KeyDallas);
 | 
						|
    furi_assert(key->get_type_data_size() == 8);
 | 
						|
 | 
						|
    onewire_slave->deattach();
 | 
						|
    memcpy(dallas_key.id_storage, key->get_data(), key->get_type_data_size());
 | 
						|
    onewire_slave->attach(&dallas_key);
 | 
						|
    onewire_slave->start();
 | 
						|
}
 | 
						|
 | 
						|
void KeyEmulator::set_pulse_data_cyfral(uint8_t index, const uint32_t* data) {
 | 
						|
    pulse_data[index * 2] = data[0];
 | 
						|
    pulse_data[index * 2 + 1] = data[1];
 | 
						|
}
 | 
						|
 | 
						|
void KeyEmulator::set_pulse_data_metakom(uint8_t index, const uint32_t* data) {
 | 
						|
    // damn start pulse
 | 
						|
    pulse_data[(index * 2) + 1] = data[0];
 | 
						|
    pulse_data[(index * 2) + 2] = data[1];
 | 
						|
}
 | 
						|
 | 
						|
void KeyEmulator::result_callback(bool success, void* ctx) {
 | 
						|
    KeyEmulator* _this = static_cast<KeyEmulator*>(ctx);
 | 
						|
 | 
						|
    _this->anything_emulated = true;
 | 
						|
} |