Использование SPI девайса нодой

О программировании Arduino, использование библиотек, примеры и общие вопросы программирования.
Ответить
lanket
Сообщения: 17
Зарегистрирован: 08 июн 2017, 07:07

Использование SPI девайса нодой

Сообщение lanket »

По случаю утери брелка от бассейна вспомнил про валяющийся RFID реадер MFRC522.

Вникнув в принцып работы MiFare чипов с шифрованием, понял что единственный способ откопировать это подобрать ключ.
Отступать уже не интересно, поэтому прокрутив 65535 вариантов ключей , замерив потраченное время, разделя на 65535 и умножив на все возможные варианты ключей получилось что atmegs 328 на 16 мегагерцах переберет все возможные ключи за один месяц при условии что будет работать круглосуточно. Но месяц это если ключ будут FF FF FF FF FF FF ... Как вариант оповещения что ключ подобран решил прикрутить НРФ и пусть мне об успешном подборе ключа сообщит мажорик через МУС.

Потом конечно можно использовать такую ноду, правда переделав скетч, для контроля доступа. Но сейчас хочется добыиться результата. Очень интересно получиться ли подобрать ключ.

И сталкнулся с проблемкой, если присоединить реадер то перестает работать НРФ. Отключаешь реадер , нода сразу начинает работать в сети. До превращения скетча в ноду и без физического подключения НРФ подбиралка ключа работала
Что я делаю не так?

NRF подключена по схеме:
9 CE
10 CSN/CS
13 SCK
11 MOSI
12 MISO

Реадер вот так:
RST/Reset RST 7
SPI SS SDA(SS) 8
SPI MOSI MOSI 11
SPI MISO MISO 12
SPI SCK SCK 13

Код: Выделить всё

#include <SPI.h>
#include <MFRC522.h>

bool Ack, err;
String strrep;
byte count;

#define RST_PIN    7
#define SS_PIN    8 

// Enable debug prints to serial monitor
#define MY_DEBUG 
#define DEBUG 

// Enable and select radio type attached
#define MY_RADIO_NRF24
#define MY_RF24_CE_PIN 9
//#define MY_RADIO_RFM69 

#define MY_NODE_ID 22
// #define MY_PARENT_NODE_ID AUTO
// #define MY_REPEATER_FEATURE
#define MY_PARENT_NODE_ID 0
#define MY_PARENT_NODE_IS_STATIC

#include <MySensors.h>
#include <avr/wdt.h>

#define SKETCH_NAME "HackMiFare"
#define SKETCH_MAJOR_VER "1"
#define SKETCH_MINOR_VER "1.0"
#define CHILD_ID_RFID 1

MyMessage rfid(CHILD_ID_RFID, V_CUSTOM);

MFRC522 mfrc522(SS_PIN, RST_PIN); 
MFRC522::MIFARE_Key key;

void before()  
{  
  wdt_disable();
    // Fix the PWM timer. Without this the LEDs will flicker.
  TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
  wdt_enable(WDTO_8S);
}

void setup() {
  Serial.begin(9600); 
  SPI.begin(); 
  mfrc522.PCD_Init(); 
  Serial.println("ok");
}

void loop() {
wdt_reset();
key.keyByte[0]=0x00;
key.keyByte[1]=0x00;
key.keyByte[2]=0x00;
key.keyByte[3]=0x00;
key.keyByte[4]=0x00;
key.keyByte[5]=0x00;

//Перебор байтов по порядку
while(key.keyByte[5]<0xFF){
if (key.keyByte[0]==0xFF) key.keyByte[1]+=0x01;
if (key.keyByte[1]==0xFF) key.keyByte[2]+=0x01;
if (key.keyByte[2]==0xFF) key.keyByte[3]+=0x01;
if (key.keyByte[3]==0xFF) key.keyByte[4]+=0x01;
if (key.keyByte[4]==0xFF) key.keyByte[5]+=0x01;

if ( ! mfrc522.PICC_IsNewCardPresent()) {return;}
if ( ! mfrc522.PICC_ReadCardSerial()) {return;}
byte status, len;
  
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid));
//Ограничения выводимой информации для мониторинга
if (key.keyByte[0]==0xFF){
   Serial.print(key.keyByte[0], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[1], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[2], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[3], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[4], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[5], HEX);
   Serial.print(" ");  
    Serial.print("status:"); Serial.println(status); 
   strrep = String(key.keyByte[0], HEX) + ' ' + String(key.keyByte[1], HEX) + ' ' + String(key.keyByte[2], HEX)
     + ' ' + String(key.keyByte[3], HEX) + ' ' + String(key.keyByte[4], HEX) + ' ' + String(key.keyByte[5], HEX)
      + ' St=' + status;
    send(rfid.set(strrep));
}

//Если ключ верный 
if (status==1){
   Serial.print("OK:"); Serial.println(status); 
    Serial.print("Key is:");
    Serial.print(key.keyByte[0], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[1], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[2], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[3], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[4], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[5], HEX);
   Serial.print(" "); 
   strrep = 'Key is: ' + String(key.keyByte[0], HEX) + ' ' + String(key.keyByte[1], HEX) + ' ' + String(key.keyByte[2], HEX)
     + ' ' + String(key.keyByte[3], HEX) + ' ' + String(key.keyByte[4], HEX) + ' ' + String(key.keyByte[5], HEX);
    bool send_data = send(rfid.set(strrep), true);
  wait(100, 1, V_STATUS);                                      // Ждём подтверждения отправки
  if ((send_data == 1)&&(Ack == 1)){                            // Если сообщение отправлено и доставлено
    Ack = 0;                                                   // Сбрасываем флаг доставки
    Serial.println("Message sent and delivered");              // Вывести в сериал "Сообщение отправлено и доставлено"
  } else {                                                     // Иначе
  while ((send_data == 0) || (Ack == 0)) {                     // Пока статус отправки или доставки ложь
      count++;                                                 // Включаем счётчик
      Serial.print("Sending a message, try No.");              // Выводим в монитор порта попытку отправки
      Serial.println(count);                                   // и её номер
      send_data = send(rfid.set(strrep), true); // Отправляем сообщение повторно
      wait(1000, 1, V_STATUS);                                 // Ждём подтверждения отправки
      if ((send_data == 1)&&(Ack == 1)){                        // Если сообщение отправлено и доставлено
        Ack = 0;                                               // Сбрасываем флаг доставки
        count = 0;                                             // и счётчик
        Serial.println("Message sent and delivered");          // Вывести в сериал "Сообщение отправлено и доставлено"
      if ((count ==  3 )&& (Ack == 0)){                        // Если сделано 3 попытки и нет подтверждения доставки
        count = 0;                                             // Обнуляем счётчик
        Ack = 1;
        send_data = 1;                                         // Выходим из цикла
        Serial.println("Delivery failed");                     // Выводим сообщение "Доставка не удалась"
        }
        }
   }
  }
    
};
 
key.keyByte[0]+=0x01;}
}

void receive(const MyMessage &message) {  
  if (message.isAck()){
    bool Ack = 0;
  }

  if (message.sensor == 1)
  {
  if (message.type == V_CUSTOM) {
    Serial.println( "Start whith" );
  } else {
    Serial.println( "Invalid command received..." );
    return;
  }
  }
  else 
  {
    Serial.print("Wrong child id in incoming command");     
  }
    
}

void  presentation() { 
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER"."SKETCH_MINOR_VER);
  
  present(CHILD_ID_RFID, S_CUSTOM, "Hack RFID");    
}

void send_status(const MyMessage &message) 
{
  Serial.println( "send status to sensor: ");
  Serial.println(message.sensor);
  switch(message.sensor){
    case CHILD_ID_RFID:
   strrep = String(key.keyByte[0], HEX) + ' ' + String(key.keyByte[1], HEX) + ' ' + String(key.keyByte[2], HEX)
     + ' ' + String(key.keyByte[3], HEX) + ' ' + String(key.keyByte[4], HEX) + ' ' + String(key.keyByte[5], HEX);
    send(rfid.set(strrep));
    break;
  }
}
Вложения
IMG_20180204_010227_1.jpg
IMG_20180204_010227_1.jpg (102.11 КБ) 5401 просмотр
lanket
Сообщения: 17
Зарегистрирован: 08 июн 2017, 07:07

Re: Использование SPI девайса нодой

Сообщение lanket »

Собственно это возможно. Работает.
Так как NRF висит тоже на этом же интерфейсе то каждому устройству надо назначить разные дефайны SDA/CE или SS .
Не сразу заработало из за подводного камня. Люди более углубленные в написания библиотек или, как еще описать, больше знакомые с нутром библитек SPI и MYS думаю сразу же догадались о правильном решении.
По сути я был рядом с решением. Уважаемый BERK дал наводку на решение такой же задачи с точки зрения железа, даже железяка таже. Там в конце есть переделанный скетч под библиотеку 2.*

Для того чтобы все заработало надо правильно соблюсти последовательность include библиотек и инициализации их. Собственно именно это и обсуждалось на англоязычном форуме MYS.

Суть последовательности:
  • обявить дефайны для MYS

    Код: Выделить всё

    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    #define MY_RF24_CE_PIN 9
    
  • потом подключить сначала библиотеку MYS
  • потом SPI
  • потом бииблитеку девайса который будет работать через SPI
  • ну и другие библиотеки по мере надобности

    Код: Выделить всё

    #include <MySensors.h>
    #include <SPI.h>
    #include <MFRC522.h>
    #include <avr/wdt.h>
    
  • обявить дефайн пина для SS девайса естественно отличный от CE NRF

    Код: Выделить всё

    #define SS_PIN 8  //  MFRC
    
  • создать контейнеры для хранения и передачи информации девайса

    Код: Выделить всё

    MFRC522 mfrc522(SS_PIN, RST_PIN); 
    MFRC522::MIFARE_Key key;
    
  • создать контейнеры для хранения и передачи информации mys

    Код: Выделить всё

    MyMessage rfid(CHILD_ID_RFID, V_TEXT);
    
  • в void before установить режим вывода пинов SS предназначенных для девайса

    Код: Выделить всё

      pinMode(SS_PIN, OUTPUT);     
      digitalWrite(SS_PIN, LOW);
    
  • и последнее условие успешного запуска девайса в void setup инициализировать библиотеку SPI и девайса

    Код: Выделить всё

      SPI.begin(); 
      mfrc522.PCD_Init(); 
    
Вот что получилось:

Код: Выделить всё

/*   Typical pin layout used:
   -----------------------------------------------------------------------------------------
               MFRC522      Arduino
               Reader/PCD   Nano v3
   Signal      Pin          Pin    
   -----------------------------------------------------------------------------------------
   RST/Reset   RST          D7      
   SPI SS      SDA(SS)      D8      
   SPI MOSI    MOSI         D11     
   SPI MISO    MISO         D12     
   SPI SCK     SCK          D13     
*/

// Enable debug prints to serial monitor
#define MY_DEBUG 
#define DEBUG 

// Enable and select radio type attached
#define MY_RADIO_NRF24
#define MY_RF24_CE_PIN 9
//#define MY_RADIO_RFM69 

#define MY_NODE_ID 22
// #define MY_PARENT_NODE_ID AUTO
// #define MY_REPEATER_FEATURE
#define MY_PARENT_NODE_ID 0
#define MY_PARENT_NODE_IS_STATIC

#include <MySensors.h>
#include <SPI.h>
#include <MFRC522.h>
#include <avr/wdt.h>


#define RST_PIN 7 //  MFRC
#define SS_PIN 8  //  MFRC


MFRC522 mfrc522(SS_PIN, RST_PIN); 
MFRC522::MIFARE_Key key;


bool Ack, err;
String strrep;
byte count;


#define SKETCH_NAME "HackMiFare"
#define SKETCH_MAJOR_VER "1"
#define SKETCH_MINOR_VER "1.0"
#define CHILD_ID_RFID 1
MyMessage rfid(CHILD_ID_RFID, V_TEXT);

void before()  
{  
  wdt_disable();
    // Fix the PWM timer. Without this the LEDs will flicker.
  TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
  // Make sure MFRC will be disabled on the SPI bus
  pinMode(RST_PIN, OUTPUT);     
  digitalWrite(RST_PIN, LOW);
  pinMode(SS_PIN, OUTPUT);     
  digitalWrite(SS_PIN, LOW);
  wdt_enable(WDTO_8S);
}

void setup() {
//  Serial.begin(9600); 

  SPI.begin(); 
  mfrc522.PCD_Init(); 
  Serial.println("ok");
}

void loop() {
key.keyByte[0]=0x00;
key.keyByte[1]=0x00;
key.keyByte[2]=0x00;
key.keyByte[3]=0x00;
key.keyByte[4]=0x00;
key.keyByte[5]=0x00;

//Перебор байтов по порядку
while(key.keyByte[5]<0xFF){
wdt_reset();
if (key.keyByte[0]==0xFF) key.keyByte[1]+=0x01;
if (key.keyByte[1]==0xFF) key.keyByte[2]+=0x01;
if (key.keyByte[2]==0xFF) key.keyByte[3]+=0x01;
if (key.keyByte[3]==0xFF) key.keyByte[4]+=0x01;
if (key.keyByte[4]==0xFF) key.keyByte[5]+=0x01;

if ( ! mfrc522.PICC_IsNewCardPresent()) {return;}
if ( ! mfrc522.PICC_ReadCardSerial()) {return;}
byte status, len;
  
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid));
//Ограничения выводимой информации для мониторинга
if (key.keyByte[0]==0xFF){
/*   Serial.print(key.keyByte[0], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[1], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[2], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[3], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[4], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[5], HEX);
   Serial.print(" ");  
    Serial.print("status:"); Serial.println(status); 
*/
   strrep = String(status) + ':' + String(key.keyByte[0], HEX) + ',' + String(key.keyByte[1], HEX) + ',' + String(key.keyByte[2], HEX)
     + ',' + String(key.keyByte[3], HEX) + ',' + String(key.keyByte[4], HEX) + ',' + String(key.keyByte[5], HEX);
   Serial.println(strrep);
    // send(rfid.set(strrep));
    send(rfid.setDestination(0).setSensor(1).set(strrep.c_str()));
}

//Если ключ верный 
if (status==1){
/*   Serial.print("OK:"); Serial.println(status); 
    Serial.print("Key is:");
    Serial.print(key.keyByte[0], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[1], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[2], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[3], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[4], HEX);
   Serial.print(" "); 
    Serial.print(key.keyByte[5], HEX);
   Serial.print(" "); 
*/
   strrep = 'Key is: ' + String(key.keyByte[0], HEX) + ' ' + String(key.keyByte[1], HEX) + ' ' + String(key.keyByte[2], HEX)
     + ' ' + String(key.keyByte[3], HEX) + ' ' + String(key.keyByte[4], HEX) + ' ' + String(key.keyByte[5], HEX);
   Serial.println(strrep);
   bool send_data = send(rfid.setDestination(0).setSensor(1).set(strrep.c_str()),true);
  wait(100, 1, V_STATUS);                                      // Ждём подтверждения отправки
  if ((send_data == 1)&&(Ack == 1)){                            // Если сообщение отправлено и доставлено
    Ack = 0;                                                   // Сбрасываем флаг доставки
    Serial.println("Message sent and delivered");              // Вывести в сериал "Сообщение отправлено и доставлено"
  } else {                                                     // Иначе
  while ((send_data == 0) || (Ack == 0)) {                     // Пока статус отправки или доставки ложь
      count++;                                                 // Включаем счётчик
      Serial.print("Sending a message, try No.");              // Выводим в монитор порта попытку отправки
      Serial.println(count);                                   // и её номер
      send_data = send(rfid.setDestination(0).setSensor(1).set(strrep.c_str()),true); // Отправляем сообщение повторно
      wait(1000, 1, V_STATUS);                                 // Ждём подтверждения отправки
      if ((send_data == 1)&&(Ack == 1)){                        // Если сообщение отправлено и доставлено
        Ack = 0;                                               // Сбрасываем флаг доставки
        count = 0;                                             // и счётчик
        Serial.println("Message sent and delivered");          // Вывести в сериал "Сообщение отправлено и доставлено"
      if ((count ==  3 )&& (Ack == 0)){                        // Если сделано 3 попытки и нет подтверждения доставки
        count = 0;                                             // Обнуляем счётчик
        Ack = 1;
        send_data = 1;                                         // Выходим из цикла
        Serial.println("Delivery failed");                     // Выводим сообщение "Доставка не удалась"
        }
        }
   }
  }
    
};
 
key.keyByte[0]+=0x01;}
}

void receive(const MyMessage &message) {  
  if (message.isAck()){
    bool Ack = 0;
  }

  if (message.sensor == 1)
  {
  if (message.type == V_TEXT) {
    Serial.println( "Start whith" );
  } else {
    Serial.println( "Invalid command received..." );
    return;
  }
  }
  else 
  {
    Serial.print("Wrong child id in incoming command");     
  }
    
}

void  presentation() { 
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER"."SKETCH_MINOR_VER);
  
  present(CHILD_ID_RFID, S_INFO, "Hack RFID");    
}

void send_status(const MyMessage &message) 
{
  Serial.println( "send status to sensor: ");
  Serial.println(message.sensor);
  switch(message.sensor){
    case CHILD_ID_RFID:
   strrep = String(key.keyByte[0], HEX) + ' ' + String(key.keyByte[1], HEX) + ' ' + String(key.keyByte[2], HEX)
     + ' ' + String(key.keyByte[3], HEX) + ' ' + String(key.keyByte[4], HEX) + ' ' + String(key.keyByte[5], HEX);
    send(rfid.set(strrep));
    break;
  }
}
Ну и если любопытно по поводу подбора пароля.
За сутки счетчик докрутился до "ff,81,0,1f,0,0 " , да последовательность задом наперед.
Исходя из этого можно вычислить что для того чтобы прокрутить все возможные варианты потребуется бесперерывной работы 256*256*8 = 524288 суток. А это 1472 года. ГЫ. Чето я в первый раз запутался в вычислениях. Зато интересно было.

Ну а собставенно кому надо прямое назначение данного реадера то по ссылке выше из этого поста думаю вполне рабочий вариант. Не проверял. По крайней мере радио завелось и ридер проинициализировался.
Ответить