При изготовлении устройства 409, 502, возникает по сути единственная сложность, это ослепление приемника после глушения. Это явление вызвано тем, что после «глушения» есть промежуток времени когда приемник не способен принимать сигнал, потому что, его чувствительность резко упала (характерно не для всех приемников). Это очень неприятно, во-первых сбивается синхронизация приема, а во-вторых время «слепоты» может быть слишком большое.
Для эффективного использования методов 409 и 502, необходимо знать время «слепоты» (или время восстановления после глушения) своего устройства. Про мой способ замера и пойдет речь в этой статье.
Для начала посмотрим на мой виртуальный осциллограф (рис1).
Первая строка (желтая) это то что видит приемник (немного отфильтрованный эфир), вторая (синяя) это выход передатчика, третья это эфир без помех (в реальных условиях его нельзя увидеть).
Посмотрим что будет при глушении (рис2). На этом рисунке видно, что после появлении помехи мы тоже не можем принимать сигнал (кто бы сомневался?), но есть и еще одна проблема когда помеха прекращается мы оказываемся в несинхронном состоянии, и не знаем какой бит сейчас будем принимать. Но самое главное, что мы попадаем в неизвестное место, как видно на помеченном стрелочкой месте, мы принимаем только часть и именно в подобных местах наш алгоритм разбора кодировки может решить, что прием закончен и завершить действие алгоритма. Таким образом минимальное что нам нужно сделать после глушения это пропустить некоторое количество ошибок.
Но где же тут слепота? И что замерять? Дело все в том что изображенная на рис2. ситуация возможна только при наличии идеального приемника, которым мы не располагаем. Поэтому посмотрим на рис3.
Этот случай уже более близок к реальному, как можно видеть после того как глушение сигнала прекратилось, какое-то время наш приемник принимает не реальный сигнал (на картинке самый нижний) а лишь помехи эфира. Собственно, это время, время когда приемник «слепой» мы и хотим измерить, время «А» на картинке.
Я решил воспользоваться тем, что пульт за раз выкидывает множество одинаковых посылок, и их тайминги в приделах одной «сессии» не сильно различаются. Мы делим замер на 3 этапа (хотя первый чисто условный и может быть опущен). На первом этапе мы выясняем к какому типу кодировок относиться принимаемый сигнал. На втором этапе запоминаем время между битами. На третьем этапе глушим часть сигнала, а потом сравнивая побитно значения от конца к началу, находим расхождения. Далее выводим сколько бит и времени приемник был слепой, теперь более подробно и с псевдокодом (возможно позже когда прошивка будет готова к взору общественности я поделюсь кодом целиком, пока к сожалению, она просто не готова).
Считается что читатель уже разобрался как принимается сигналы в различных кодировках.
Все начинается с такой незамысловатой конструкции:
void aften()
{
switch(state)
{
}
}
Вызов функции aften, происходит после обработки сигнала
if(mode == logger){
AlarmManager::makeProcess();
}
aften();
Приведу набор констант которые использую я, их смысл будет понятен дальше из кода.
const unsigned char control_bit = 8;
const unsigned char start_bit = 8;
const unsigned char end_bit = 16;
Теперь будем разбирать по этапам:
case 1:
for(int i=0; i<alarmTypes_sz; i++){
if(alarmTypes[i]->dat_bit==control_bit) {
alarm_type = i;
origin = alarmTypes[i];
}
}
if(old != _i) {
old=_i;
state=2;
}
break;
На этом этапе мы просто узнаем тип сигнала (сохраняем в alarm_type) с которым будем работать и сохраняем указатель на пакет который в дальнейшем будем использовать как эталон (сохраняем в origin). Следует обратить внимание на код в конце, он необходим чтобы перейти к новому этапу когда заканчивается прием текущего пакета. Это код используется на всех этапах.
case 2:
if(alarmTypes[alarm_type]->state == 2) {
time_array[time_array_index++] = am_len;
if(alarmTypes[alarm_type]->dat_bit==start_bit) start_noise=timer;
if(alarmTypes[alarm_type]->dat_bit==end_bit) end_noise=timer;
}
if(old != _i) {
old=_i;
state=3;
}
break;
На данном этапе мы делаем сразу 2 вещи. Во-первых, это заполняем массив time_array (здесь желательно добавить улучшение и заполнять синхронизируясь с приемом бит), а во-вторых мы запоминаем время выпадения определённых бит, для того чтобы вычислить время глушения.
case 3:
if(alarmTypes[alarm_type]->dat_bit==start_bit) {
bad = alarmTypes[alarm_type];
alarmTypes[alarm_type]->dat_bit+=end_bit-start_bit;
alarmTypes[alarm_type]->ignore_errors=10;
mode=none;
make_noise(end_noise-start_noise);
}
if(old != _i) {
old=_i;
state=4;
}
break;
Здесь мы запоминаем «битый» пакет, пропускаем нужное количество бит и начинаем глушить сигнал. Также мы ставим ignore_errors равную 10, но об этом чуть позже.
Приведу мою реализацию «шума» (не самая лучшая, делал на скорую руку):
unsigned long _make_noise_timer;
unsigned char _make_noise_flag;
// вызывается каждый тик
void inline make_noise_timer()
{
if(_make_noise_flag) {
if(!_make_noise_timer) {
RT_AM_LO;
_make_noise_flag=0;
mode=logger;
}
_make_noise_timer—;
}
}
void inline make_noise(unsigned long t)
{
RT_AM_HI;
_make_noise_timer = t/*/TIMER_DIV*/;
_make_noise_flag = 1;
}
Теперь поговорим об ignore_errors, эта переменная нужда для того, что после глушения мы можем попасть непонятно куда, и нас алгоритм разбора пакета, может решить, что пакет закончился, чтобы этого не случилось мы должны проигнорировать некоторое количество ошибок. Кроме ошибок еще желательно пропускать и некоторые начальные биты, ведь шум может сойти за «правильный» бит. Приведу свою реализацию парсера старлайна, с добавлением нужного функционала:
case 2: //dat
if(am_len>=SL_MIN_ONE && am_len<=SL_MAX_ONE) {
b=1;
}
else if(am_len>=SL_MIN_ZERO && am_len<=SL_MAX_ZERO) {
b=0;
} // пропускаем ошибки
else if(ignore_errors) {
ignore_errors—;
break;
}
else if(dat_bit>=SL_MIN_BITS) {
state=3;
break;
}
else {
state=0;
break;
}
if(!RX_AM_STATE) {
// перестаем игнорировать ошибки только после того как набралось «критическое» количество бит
if(ignore_errors && dat_bit>18) {
_ignore_error=ignore_errors;
ignore_errors=0;
}
if(b) {
data[dat_bit/8]|=(1<<(dat_bit%8));
}
if(++dat_bit>=SL_MAX_BITS) {
state=3;
}
}
break;
Наконец добрались до сравнения пакетов и вычисления количество битых бит/времени «слепоты»:
// вызываеть из основного цикла программы
void make_result()
{
if(pk_calibrating::state == 4) {
/*signed char*/ a = origin->dat_bit-1;
signed char b = bad->dat_bit-1;
state=0;
// сравниваем биты
for(; b>16; a—, b—) {
if( (bool)(origin->data[a/8]&(1<<(a%8))) != (bool)(bad->data[b/8]&(1<<(b%8))) ) {
break;
}
}// считаем время слепоты
unsigned long noise_time=0;
for(int i=end_bit*2;i<a*2;i++) {
noise_time += time_array[i];
}printf(«error bit: %d\n», a);
printf(«silence bits: %d\n», a-16);
printf(«silence time: %d\n», noise_time);
}
}
Здесь все достаточно просто, мы ищем в цикле первый «неправильный» бит, потом смотрим сколько бит между последним заглушенным и первым правильным, это и будет число «проспанных» бит, и с помощью массива time_array подсчитываем время «слепоты» (примерно естественно).
Надеюсь моя статья оказалась полезна, лично я с помощью данного метода выяснил что мне необходимо улучшить качество приема и достаточно сильно уменьшить время ослепления приемника.
Обсуждение тут https://phreaker.ru/forum/showthread.php?t=1391
kra
(c) www.PhreakerClub.com