Итак, выкладываю скетч для ардуино приема и дешифровки брелков. Основан на исходниках приема пакета KEELOQ отсюда
http://arduino.ru/forum/apparatnye-voprosy/biblioteka-chteniya-id-brelkov-signalizatsiii-hcs301-keeloq и функции дешифрования отсюда
https://github.com/RobTillaart/Arduino-1/commit/329d451886eab4fc1257812b70ec2d243d6c9510Код:
#define KeeLoq_NLF 0x3A5C742EUL
#define ManufacLow 0x89ABCDEF //мануфактурный код младшие разряды
#define ManufacHigh 0x01234567 //мануфактурный код старшие разряды
#define ValidWindow 256 //окно валидности счетчика синхронизации
word MyCointer[10]={0,0,0,0,0,0,0,0,0,0}; //Счетчики синхронизации брелков
unsigned long KeyHigh[10]; //Ключи шифрования для каждого брелка (старшие разряды)
unsigned long KeyLow[10]; //Ключи шифрования для каждого брелка (младшие разряды)
unsigned long MySerialNum[10]={1,2,3,4,5,6,7,8,9,10}; //Серийные номера моих брелков
// Радиобрелки ///////////////////////////////////////////////////////////////////////////////////////
#define HCS_RECIEVER_PIN 2 // пин к которому подключен приемник для брелков
class HCS301 {
public:
unsigned BattaryLow : 1; // На брелке села батарейка
unsigned Repeat : 1; // повторная посылка
unsigned BtnNoSound : 1;
unsigned BtnOpen : 1;
unsigned BtnClose : 1;
unsigned BtnRing : 1;
unsigned long SerialNum;
unsigned long Encript;
void print();
};
volatile boolean HCS_Listening = true;
byte HCS_preamble_count = 0;
uint32_t HCS_last_change = 0;
//uint32_t HCS_start_preamble = 0;
uint8_t HCS_bit_counter; // счетчик считанных бит данных
uint8_t HCS_bit_array[66]; // массив считанных бит данных
#define HCS_TE 400 // типичная длительность имульса Te
#define HCS_Te2_3 600 // HCS_TE * 3 / 2
HCS301 hcs301;
void setup()
{
Serial.begin(9600);
// Брелки
pinMode(HCS_RECIEVER_PIN, INPUT);
attachInterrupt(0, HCS_interrupt, CHANGE);
Serial.println("Setup OK");
}
unsigned long Keeloqdecrypt(unsigned long data, unsigned long keyHigh, unsigned long keyLow)
{
unsigned long x = data;
unsigned long r;
int keyBitNo, index;
unsigned long keyBitVal,bitVal;
for (r = 0; r < 528; r++)
{
keyBitNo = (15-r) & 63;
if(keyBitNo < 32)
keyBitVal = bitRead(keyLow,keyBitNo);
else
keyBitVal = bitRead(keyHigh, keyBitNo - 32);
index = 1 * bitRead(x,0) + 2 * bitRead(x,8) + 4 * bitRead(x,19) + 8 * bitRead(x,25) + 16 * bitRead(x,30);
bitVal = bitRead(x,31) ^ bitRead(x, 15) ^ bitRead(KeeLoq_NLF,index) ^ keyBitVal;
x = (x<<1) ^ bitVal;
}
return x;
}
byte ReadKeeloq()
{
byte i=0;
byte btn=0;
byte btndecrypt;
unsigned long decrypt=0;
unsigned long cointer=0;
word cointer_=0;
unsigned long TempSerNum=0;
unsigned long diskriminant;
boolean MyBrelok = false;
if(HCS_Listening == false)
{
HCS301 msg;
memcpy(&msg,&hcs301,sizeof(HCS301));
//Serial.println(String("KeyFb#")+String(msg.SerialNum));
msg.print();
for (i = 0; i < 10; i++)
{
if (msg.SerialNum==MySerialNum[i]) //Если номер свой
{
if (MyCointer[i]==0) //Если счетчик для этого брелка равен 0
{ //расчитываем ключи шифрования
TempSerNum=msg.SerialNum;
TempSerNum&=0x0FFFFFFF;
TempSerNum|=0x20000000;
KeyLow[i] =Keeloqdecrypt(TempSerNum,ManufacHigh,ManufacLow);
TempSerNum&=0x0FFFFFFF;
TempSerNum|=0x60000000;
KeyHigh[i]=Keeloqdecrypt(TempSerNum,ManufacHigh,ManufacLow);
}
decrypt=Keeloqdecrypt(msg.Encript,KeyHigh[i],KeyLow[i]); //Дешифруем закрытую часть кода
Serial.println(String("Dcrypt HEX#")+String(decrypt,HEX));
diskriminant=decrypt&0x03FF0000;
diskriminant=diskriminant>>16;
Serial.println(String("Diskriminant#")+String(diskriminant));
if (diskriminant==0)
{
//вычисление принятого счетчика синхронизации
cointer_=word(decrypt&0x0000FFFF);
Serial.println(String("MyCointer#")+String(MyCointer[i]));
Serial.println(String("Cointer#")+String(cointer_));
if (MyCointer[i]==0) {MyCointer[i]=cointer_;MyBrelok=true;} //если брелок используется в первый раз, то синхронизируемся, Иначе проверка на валиднось счетчика
else {if (cointer_-MyCointer[i]<ValidWindow){MyCointer[i]=cointer_;MyBrelok=true;}}
if (MyBrelok)
{
if (msg.BtnRing == 1) btn += 1;
if (msg.BtnClose == 1) btn += 2;
if (msg.BtnOpen == 1) btn += 4;
if (msg.BtnNoSound == 1) btn += 8;
Serial.println(String("Button_free#")+String(btn));
btndecrypt=byte(decrypt>>28);
if (btndecrypt!=btn){btn=0;}
Serial.println(String("Button_decrypt#")+String(btndecrypt));
}
}
break;
}
}
// включаем слушанье брелков снова
HCS_Listening = true;
}
//Serial.println(String("KeyFb#")+String(msg.SerialNum));
return btn;
}
void loop()
{
byte readkeeloq=ReadKeeloq();
if (readkeeloq !=0){Serial.println(readkeeloq);}
}
// Функции класса HCS301 для чтения брелков
void HCS301::print(){
String btn;
if (BtnRing == 1) btn += "Ring";
if (BtnClose == 1) btn += "Close";
if (BtnOpen == 1) btn += "Open";
if (BtnNoSound == 1) btn += "NoSound";
String it2;
it2 += "Encript ";
it2 += Encript;
it2 += " Serial ";
it2 += SerialNum;
it2 += " ";
it2 += btn;
it2 += " BattaryLow=";
it2 += BattaryLow;
it2 += " Rep=";
it2 += Repeat;
Serial.println(it2);
}
void HCS_interrupt(){
if(HCS_Listening == false){
return;
}
uint32_t cur_timestamp = micros();
uint8_t cur_status = digitalRead(HCS_RECIEVER_PIN);
uint32_t pulse_duration = cur_timestamp - HCS_last_change;
HCS_last_change = cur_timestamp;
// ловим преамбулу
if(HCS_preamble_count < 12){
if(cur_status == HIGH){
if( ((pulse_duration > 150) && (pulse_duration < 500)) || HCS_preamble_count == 0){
// начало импульса преамбулы
//if(HCS_preamble_count == 0){
// HCS_start_preamble = cur_timestamp; // Отметим время старта преамбулы
//}
} else {
// поймали какую то фигню, неправильная пауза между импульсами
HCS_preamble_count = 0; // сбрасываем счетчик пойманных импульсов преамбулы
goto exit;
}
} else {
// конец импульса преамбулы
if((pulse_duration > 300) && (pulse_duration < 600)){
// поймали импульс преамбулы
HCS_preamble_count ++;
if(HCS_preamble_count == 12){
// словили преамбулу
//HCS_Te = (cur_timestamp - HCS_start_preamble) / 23; // вычисляем длительность базового импульса Te
//HCS_Te2_3 = HCS_Te * 3 / 2;
HCS_bit_counter = 0;
goto exit;
}
} else {
// поймали какую то фигню
HCS_preamble_count = 0; // сбрасываем счетчик пойманных импульсов преамбулы
goto exit;
}
}
}
// ловим данные
if(HCS_preamble_count == 12){
if(cur_status == HIGH){
if(((pulse_duration > 250) && (pulse_duration < 900)) || HCS_bit_counter == 0){
// начало импульса данных
} else {
// неправильная пауза между импульсами
HCS_preamble_count = 0;
goto exit;
}
} else {
// конец импульса данных
if((pulse_duration > 250) && (pulse_duration < 900)){
HCS_bit_array[65 - HCS_bit_counter] = (pulse_duration > HCS_Te2_3) ? 0 : 1; // импульс больше, чем половина от Те * 3 поймали 0, иначе 1
HCS_bit_counter++;
if(HCS_bit_counter == 66){
// поймали все биты данных
HCS_Listening = false; // отключем прослушку приемника, отправляем пойманные данные на обработку
HCS_preamble_count = 0; // сбрасываем счетчик пойманных импульсов преамбулы
hcs301.Repeat = HCS_bit_array[0];
hcs301.BattaryLow = HCS_bit_array[1];
hcs301.BtnNoSound = HCS_bit_array[2];
hcs301.BtnOpen = HCS_bit_array[3];
hcs301.BtnClose = HCS_bit_array[4];
hcs301.BtnRing = HCS_bit_array[5];
hcs301.SerialNum = 0;
for(int i = 6; i < 34;i++){
hcs301.SerialNum = (hcs301.SerialNum << 1) + HCS_bit_array[i];
};
uint32_t Encript = 0;
for(int i = 34; i < 66;i++){
Encript = (Encript << 1) + HCS_bit_array[i];
};
hcs301.Encript = Encript;
}
} else {
// поймали хрень какую то, отключаемся
HCS_preamble_count = 0;
goto exit;
}
}
}
exit:;
}
В скетче функция ReadKeeloq() возвращает 0 если ничего не принято или принят сигнал от чужих брелков или выдает число от 1 до 15 (четыре бита нажатых кнопок) Отладочные принты убирать не стал.