[FL-2393][FL-2381] iButton, OneWire: move to plain C (#1068)
* iButton: getting started on the worker concept * Hal delay: added global instructions_per_us variable * iButton: one wire slave * iButton: ibutton key setter * iButton: one wire host, use ibutton_hal * iButton\RFID: common pulse decoder concept * iButton: cyfral decoder * iButton: worker thread concept * iButton: metakom decoder * iButton: write key through worker * iButton: worker mode holder * iButton: worker improvements * iButton: Cyfral encoder * iButton: Metakom encoder * lib: pulse protocol helpers * iButton: Metakom decoder * iButton: Cyfral decoder * iButton worker: separate modes * iButton: libs documentation * HAL: iButton gpio modes * iButton worker: rename modes file * iButton worker, hal: move to LL * iButton CLI: worker for reading and emulation commands * iButton HAL: correct init and emulation sequence * iButton cli: moved to plain C * iButton: move to worker, small step to plain C * Libs, one wire: move to plain C * Libs: added forgotten files to compilation * iButton writer: get rid of manual disable/enable irq
This commit is contained in:
256
lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.c
Normal file
256
lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.c
Normal file
@@ -0,0 +1,256 @@
|
||||
#include "protocol_cyfral.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <furi/check.h>
|
||||
#include <furi_hal_delay.h>
|
||||
|
||||
#define CYFRAL_DATA_SIZE 2
|
||||
#define CYFRAL_MAX_PERIOD_US 230
|
||||
|
||||
typedef enum {
|
||||
CYFRAL_BIT_WAIT_FRONT_HIGH,
|
||||
CYFRAL_BIT_WAIT_FRONT_LOW,
|
||||
} CyfralBitState;
|
||||
|
||||
typedef enum {
|
||||
CYFRAL_WAIT_START_NIBBLE,
|
||||
CYFRAL_READ_NIBBLE,
|
||||
CYFRAL_READ_STOP_NIBBLE,
|
||||
} CyfralState;
|
||||
|
||||
struct ProtocolCyfral {
|
||||
PulseProtocol* protocol;
|
||||
|
||||
CyfralState state;
|
||||
CyfralBitState bit_state;
|
||||
|
||||
// ready flag, key is read and valid
|
||||
// TODO: atomic access
|
||||
bool ready;
|
||||
// key data storage
|
||||
uint16_t key_data;
|
||||
// high + low period time
|
||||
uint32_t period_time;
|
||||
// temporary nibble storage
|
||||
uint8_t nibble;
|
||||
// data valid flag
|
||||
// MUST be checked only in READ_STOP_NIBBLE state
|
||||
bool data_valid;
|
||||
// nibble index, we expect 8 nibbles
|
||||
uint8_t index;
|
||||
// bit index in nibble, 4 bit per nibble
|
||||
uint8_t bit_index;
|
||||
// max period, 230us x clock per us
|
||||
uint32_t max_period;
|
||||
};
|
||||
|
||||
static void cyfral_pulse(void* context, bool polarity, uint32_t length);
|
||||
static void cyfral_reset(void* context);
|
||||
static void cyfral_get_data(void* context, uint8_t* data, size_t length);
|
||||
static bool cyfral_decoded(void* context);
|
||||
|
||||
ProtocolCyfral* protocol_cyfral_alloc() {
|
||||
ProtocolCyfral* cyfral = malloc(sizeof(ProtocolCyfral));
|
||||
cyfral_reset(cyfral);
|
||||
|
||||
cyfral->protocol = pulse_protocol_alloc();
|
||||
|
||||
pulse_protocol_set_context(cyfral->protocol, cyfral);
|
||||
pulse_protocol_set_pulse_cb(cyfral->protocol, cyfral_pulse);
|
||||
pulse_protocol_set_reset_cb(cyfral->protocol, cyfral_reset);
|
||||
pulse_protocol_set_get_data_cb(cyfral->protocol, cyfral_get_data);
|
||||
pulse_protocol_set_decoded_cb(cyfral->protocol, cyfral_decoded);
|
||||
|
||||
return cyfral;
|
||||
}
|
||||
|
||||
void protocol_cyfral_free(ProtocolCyfral* cyfral) {
|
||||
furi_assert(cyfral);
|
||||
pulse_protocol_free(cyfral->protocol);
|
||||
free(cyfral);
|
||||
}
|
||||
|
||||
PulseProtocol* protocol_cyfral_get_protocol(ProtocolCyfral* cyfral) {
|
||||
furi_assert(cyfral);
|
||||
return cyfral->protocol;
|
||||
}
|
||||
|
||||
static void cyfral_get_data(void* context, uint8_t* data, size_t length) {
|
||||
furi_assert(context);
|
||||
furi_check(length >= CYFRAL_DATA_SIZE);
|
||||
ProtocolCyfral* cyfral = context;
|
||||
memcpy(data, &cyfral->key_data, CYFRAL_DATA_SIZE);
|
||||
}
|
||||
|
||||
static bool cyfral_decoded(void* context) {
|
||||
furi_assert(context);
|
||||
ProtocolCyfral* cyfral = context;
|
||||
bool decoded = cyfral->ready;
|
||||
return decoded;
|
||||
}
|
||||
|
||||
static void cyfral_reset(void* context) {
|
||||
furi_assert(context);
|
||||
ProtocolCyfral* cyfral = context;
|
||||
cyfral->state = CYFRAL_WAIT_START_NIBBLE;
|
||||
cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW;
|
||||
|
||||
cyfral->period_time = 0;
|
||||
cyfral->bit_index = 0;
|
||||
cyfral->ready = false;
|
||||
cyfral->index = 0;
|
||||
|
||||
cyfral->key_data = 0;
|
||||
cyfral->nibble = 0;
|
||||
cyfral->data_valid = true;
|
||||
|
||||
cyfral->max_period = CYFRAL_MAX_PERIOD_US * instructions_per_us;
|
||||
}
|
||||
|
||||
static bool cyfral_process_bit(
|
||||
ProtocolCyfral* cyfral,
|
||||
bool polarity,
|
||||
uint32_t length,
|
||||
bool* bit_ready,
|
||||
bool* bit_value) {
|
||||
bool result = true;
|
||||
*bit_ready = false;
|
||||
|
||||
// bit start from low
|
||||
switch(cyfral->bit_state) {
|
||||
case CYFRAL_BIT_WAIT_FRONT_LOW:
|
||||
if(polarity == true) {
|
||||
cyfral->period_time += length;
|
||||
|
||||
*bit_ready = true;
|
||||
if(cyfral->period_time <= cyfral->max_period) {
|
||||
if((cyfral->period_time / 2) > length) {
|
||||
*bit_value = false;
|
||||
} else {
|
||||
*bit_value = true;
|
||||
}
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
|
||||
cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_HIGH;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
case CYFRAL_BIT_WAIT_FRONT_HIGH:
|
||||
if(polarity == false) {
|
||||
cyfral->period_time = length;
|
||||
cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cyfral_pulse(void* context, bool polarity, uint32_t length) {
|
||||
furi_assert(context);
|
||||
ProtocolCyfral* cyfral = context;
|
||||
|
||||
bool bit_ready;
|
||||
bool bit_value;
|
||||
|
||||
if(cyfral->ready) return;
|
||||
|
||||
switch(cyfral->state) {
|
||||
case CYFRAL_WAIT_START_NIBBLE:
|
||||
// wait for start word
|
||||
if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) {
|
||||
if(bit_ready) {
|
||||
cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F;
|
||||
if(cyfral->nibble == 0b0001) {
|
||||
cyfral->nibble = 0;
|
||||
cyfral->state = CYFRAL_READ_NIBBLE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cyfral_reset(cyfral);
|
||||
}
|
||||
|
||||
break;
|
||||
case CYFRAL_READ_NIBBLE:
|
||||
// read nibbles
|
||||
if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) {
|
||||
if(bit_ready) {
|
||||
cyfral->nibble = (cyfral->nibble << 1) | bit_value;
|
||||
|
||||
cyfral->bit_index++;
|
||||
|
||||
//convert every nibble to 2-bit index
|
||||
if(cyfral->bit_index == 4) {
|
||||
switch(cyfral->nibble) {
|
||||
case 0b1110:
|
||||
cyfral->key_data = (cyfral->key_data << 2) | 0b11;
|
||||
break;
|
||||
case 0b1101:
|
||||
cyfral->key_data = (cyfral->key_data << 2) | 0b10;
|
||||
break;
|
||||
case 0b1011:
|
||||
cyfral->key_data = (cyfral->key_data << 2) | 0b01;
|
||||
break;
|
||||
case 0b0111:
|
||||
cyfral->key_data = (cyfral->key_data << 2) | 0b00;
|
||||
break;
|
||||
default:
|
||||
cyfral->data_valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
cyfral->nibble = 0;
|
||||
cyfral->bit_index = 0;
|
||||
cyfral->index++;
|
||||
}
|
||||
|
||||
// succefully read 8 nibbles
|
||||
if(cyfral->index == 8) {
|
||||
cyfral->state = CYFRAL_READ_STOP_NIBBLE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cyfral_reset(cyfral);
|
||||
}
|
||||
break;
|
||||
case CYFRAL_READ_STOP_NIBBLE:
|
||||
// read stop nibble
|
||||
if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) {
|
||||
if(bit_ready) {
|
||||
cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F;
|
||||
cyfral->bit_index++;
|
||||
|
||||
switch(cyfral->bit_index) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
if(cyfral->nibble == 0b0001) {
|
||||
// validate data
|
||||
if(cyfral->data_valid) {
|
||||
cyfral->ready = true;
|
||||
} else {
|
||||
cyfral_reset(cyfral);
|
||||
}
|
||||
} else {
|
||||
cyfral_reset(cyfral);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cyfral_reset(cyfral);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cyfral_reset(cyfral);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
38
lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.h
Normal file
38
lib/one_wire/ibutton/pulse_protocols/protocol_cyfral.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file protocol_cyfral.h
|
||||
*
|
||||
* Cyfral pulse format decoder
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "../../pulse_protocols/pulse_protocol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ProtocolCyfral ProtocolCyfral;
|
||||
|
||||
/**
|
||||
* Allocate decoder
|
||||
* @return ProtocolCyfral*
|
||||
*/
|
||||
ProtocolCyfral* protocol_cyfral_alloc();
|
||||
|
||||
/**
|
||||
* Deallocate decoder
|
||||
* @param cyfral
|
||||
*/
|
||||
void protocol_cyfral_free(ProtocolCyfral* cyfral);
|
||||
|
||||
/**
|
||||
* Get protocol interface
|
||||
* @param cyfral
|
||||
* @return PulseProtocol*
|
||||
*/
|
||||
PulseProtocol* protocol_cyfral_get_protocol(ProtocolCyfral* cyfral);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
262
lib/one_wire/ibutton/pulse_protocols/protocol_metakom.c
Normal file
262
lib/one_wire/ibutton/pulse_protocols/protocol_metakom.c
Normal file
@@ -0,0 +1,262 @@
|
||||
#include "protocol_metakom.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <furi/check.h>
|
||||
#include <furi_hal_delay.h>
|
||||
|
||||
#define METAKOM_DATA_SIZE 4
|
||||
#define METAKOM_PERIOD_SAMPLE_COUNT 10
|
||||
|
||||
typedef enum {
|
||||
METAKOM_WAIT_PERIOD_SYNC,
|
||||
METAKOM_WAIT_START_BIT,
|
||||
METAKOM_WAIT_START_WORD,
|
||||
METAKOM_READ_WORD,
|
||||
METAKOM_READ_STOP_WORD,
|
||||
} MetakomState;
|
||||
|
||||
typedef enum {
|
||||
METAKOM_BIT_WAIT_FRONT_HIGH,
|
||||
METAKOM_BIT_WAIT_FRONT_LOW,
|
||||
} MetakomBitState;
|
||||
|
||||
struct ProtocolMetakom {
|
||||
PulseProtocol* protocol;
|
||||
|
||||
// high + low period time
|
||||
uint32_t period_time;
|
||||
uint32_t low_time_storage;
|
||||
uint8_t period_sample_index;
|
||||
uint32_t period_sample_data[METAKOM_PERIOD_SAMPLE_COUNT];
|
||||
|
||||
// ready flag
|
||||
// TODO: atomic access
|
||||
bool ready;
|
||||
|
||||
uint8_t tmp_data;
|
||||
uint8_t tmp_counter;
|
||||
|
||||
uint32_t key_data;
|
||||
uint8_t key_data_index;
|
||||
|
||||
MetakomBitState bit_state;
|
||||
MetakomState state;
|
||||
};
|
||||
|
||||
static void metakom_pulse(void* context, bool polarity, uint32_t length);
|
||||
static void metakom_reset(void* context);
|
||||
static void metakom_get_data(void* context, uint8_t* data, size_t length);
|
||||
static bool metakom_decoded(void* context);
|
||||
|
||||
ProtocolMetakom* protocol_metakom_alloc() {
|
||||
ProtocolMetakom* metakom = malloc(sizeof(ProtocolMetakom));
|
||||
metakom_reset(metakom);
|
||||
|
||||
metakom->protocol = pulse_protocol_alloc();
|
||||
|
||||
pulse_protocol_set_context(metakom->protocol, metakom);
|
||||
pulse_protocol_set_pulse_cb(metakom->protocol, metakom_pulse);
|
||||
pulse_protocol_set_reset_cb(metakom->protocol, metakom_reset);
|
||||
pulse_protocol_set_get_data_cb(metakom->protocol, metakom_get_data);
|
||||
pulse_protocol_set_decoded_cb(metakom->protocol, metakom_decoded);
|
||||
|
||||
return metakom;
|
||||
}
|
||||
|
||||
void protocol_metakom_free(ProtocolMetakom* metakom) {
|
||||
furi_assert(metakom);
|
||||
pulse_protocol_free(metakom->protocol);
|
||||
free(metakom);
|
||||
}
|
||||
|
||||
PulseProtocol* protocol_metakom_get_protocol(ProtocolMetakom* metakom) {
|
||||
furi_assert(metakom);
|
||||
return metakom->protocol;
|
||||
}
|
||||
|
||||
static void metakom_get_data(void* context, uint8_t* data, size_t length) {
|
||||
furi_assert(context);
|
||||
furi_check(length >= METAKOM_DATA_SIZE);
|
||||
ProtocolMetakom* metakom = context;
|
||||
memcpy(data, &metakom->key_data, METAKOM_DATA_SIZE);
|
||||
}
|
||||
|
||||
static bool metakom_decoded(void* context) {
|
||||
furi_assert(context);
|
||||
ProtocolMetakom* metakom = context;
|
||||
bool decoded = metakom->ready;
|
||||
return decoded;
|
||||
}
|
||||
|
||||
static void metakom_reset(void* context) {
|
||||
furi_assert(context);
|
||||
ProtocolMetakom* metakom = context;
|
||||
|
||||
metakom->ready = false;
|
||||
metakom->period_sample_index = 0;
|
||||
metakom->period_time = 0;
|
||||
metakom->tmp_counter = 0;
|
||||
metakom->tmp_data = 0;
|
||||
for(uint8_t i = 0; i < METAKOM_PERIOD_SAMPLE_COUNT; i++) {
|
||||
metakom->period_sample_data[i] = 0;
|
||||
};
|
||||
metakom->state = METAKOM_WAIT_PERIOD_SYNC;
|
||||
metakom->bit_state = METAKOM_BIT_WAIT_FRONT_LOW;
|
||||
metakom->key_data = 0;
|
||||
metakom->key_data_index = 0;
|
||||
metakom->low_time_storage = 0;
|
||||
}
|
||||
|
||||
static bool metakom_parity_check(uint8_t data) {
|
||||
uint8_t ones_count = 0;
|
||||
bool result;
|
||||
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
if((data >> i) & 0b00000001) {
|
||||
ones_count++;
|
||||
}
|
||||
}
|
||||
|
||||
result = (ones_count % 2 == 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool metakom_process_bit(
|
||||
ProtocolMetakom* metakom,
|
||||
bool polarity,
|
||||
uint32_t time,
|
||||
uint32_t* high_time,
|
||||
uint32_t* low_time) {
|
||||
bool result = false;
|
||||
|
||||
switch(metakom->bit_state) {
|
||||
case METAKOM_BIT_WAIT_FRONT_LOW:
|
||||
if(polarity == false) {
|
||||
*low_time = metakom->low_time_storage;
|
||||
*high_time = time;
|
||||
result = true;
|
||||
metakom->bit_state = METAKOM_BIT_WAIT_FRONT_HIGH;
|
||||
}
|
||||
break;
|
||||
case METAKOM_BIT_WAIT_FRONT_HIGH:
|
||||
if(polarity == true) {
|
||||
metakom->low_time_storage = time;
|
||||
metakom->bit_state = METAKOM_BIT_WAIT_FRONT_LOW;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void metakom_pulse(void* context, bool polarity, uint32_t time) {
|
||||
furi_assert(context);
|
||||
ProtocolMetakom* metakom = context;
|
||||
|
||||
if(metakom->ready) return;
|
||||
|
||||
uint32_t high_time = 0;
|
||||
uint32_t low_time = 0;
|
||||
|
||||
switch(metakom->state) {
|
||||
case METAKOM_WAIT_PERIOD_SYNC:
|
||||
if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) {
|
||||
metakom->period_sample_data[metakom->period_sample_index] = high_time + low_time;
|
||||
metakom->period_sample_index++;
|
||||
|
||||
if(metakom->period_sample_index == METAKOM_PERIOD_SAMPLE_COUNT) {
|
||||
for(uint8_t i = 0; i < METAKOM_PERIOD_SAMPLE_COUNT; i++) {
|
||||
metakom->period_time += metakom->period_sample_data[i];
|
||||
};
|
||||
metakom->period_time /= METAKOM_PERIOD_SAMPLE_COUNT;
|
||||
|
||||
metakom->state = METAKOM_WAIT_START_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case METAKOM_WAIT_START_BIT:
|
||||
if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) {
|
||||
metakom->tmp_counter++;
|
||||
if(high_time > metakom->period_time) {
|
||||
metakom->tmp_counter = 0;
|
||||
metakom->state = METAKOM_WAIT_START_WORD;
|
||||
}
|
||||
|
||||
if(metakom->tmp_counter > 40) {
|
||||
metakom_reset(metakom);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case METAKOM_WAIT_START_WORD:
|
||||
if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) {
|
||||
if(low_time < (metakom->period_time / 2)) {
|
||||
metakom->tmp_data = (metakom->tmp_data << 1) | 0b0;
|
||||
} else {
|
||||
metakom->tmp_data = (metakom->tmp_data << 1) | 0b1;
|
||||
}
|
||||
metakom->tmp_counter++;
|
||||
|
||||
if(metakom->tmp_counter == 3) {
|
||||
if(metakom->tmp_data == 0b010) {
|
||||
metakom->tmp_counter = 0;
|
||||
metakom->tmp_data = 0;
|
||||
metakom->state = METAKOM_READ_WORD;
|
||||
} else {
|
||||
metakom_reset(metakom);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case METAKOM_READ_WORD:
|
||||
if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) {
|
||||
if(low_time < (metakom->period_time / 2)) {
|
||||
metakom->tmp_data = (metakom->tmp_data << 1) | 0b0;
|
||||
} else {
|
||||
metakom->tmp_data = (metakom->tmp_data << 1) | 0b1;
|
||||
}
|
||||
metakom->tmp_counter++;
|
||||
|
||||
if(metakom->tmp_counter == 8) {
|
||||
if(metakom_parity_check(metakom->tmp_data)) {
|
||||
metakom->key_data = (metakom->key_data << 8) | metakom->tmp_data;
|
||||
metakom->key_data_index++;
|
||||
metakom->tmp_data = 0;
|
||||
metakom->tmp_counter = 0;
|
||||
|
||||
if(metakom->key_data_index == 4) {
|
||||
// check for stop bit
|
||||
if(high_time > metakom->period_time) {
|
||||
metakom->state = METAKOM_READ_STOP_WORD;
|
||||
} else {
|
||||
metakom_reset(metakom);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
metakom_reset(metakom);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case METAKOM_READ_STOP_WORD:
|
||||
if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) {
|
||||
if(low_time < (metakom->period_time / 2)) {
|
||||
metakom->tmp_data = (metakom->tmp_data << 1) | 0b0;
|
||||
} else {
|
||||
metakom->tmp_data = (metakom->tmp_data << 1) | 0b1;
|
||||
}
|
||||
metakom->tmp_counter++;
|
||||
|
||||
if(metakom->tmp_counter == 3) {
|
||||
if(metakom->tmp_data == 0b010) {
|
||||
metakom->ready = true;
|
||||
} else {
|
||||
metakom_reset(metakom);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
38
lib/one_wire/ibutton/pulse_protocols/protocol_metakom.h
Normal file
38
lib/one_wire/ibutton/pulse_protocols/protocol_metakom.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file protocol_metakom.h
|
||||
*
|
||||
* Metakom pulse format decoder
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "../../pulse_protocols/pulse_protocol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ProtocolMetakom ProtocolMetakom;
|
||||
|
||||
/**
|
||||
* Allocate decoder
|
||||
* @return ProtocolMetakom*
|
||||
*/
|
||||
ProtocolMetakom* protocol_metakom_alloc();
|
||||
|
||||
/**
|
||||
* Free decoder
|
||||
* @param metakom
|
||||
*/
|
||||
void protocol_metakom_free(ProtocolMetakom* metakom);
|
||||
|
||||
/**
|
||||
* Get protocol interface
|
||||
* @param metakom
|
||||
* @return PulseProtocol*
|
||||
*/
|
||||
PulseProtocol* protocol_metakom_get_protocol(ProtocolMetakom* metakom);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user