...

понедельник, 22 июня 2015 г.

[Из песочницы] Копирование ключей dallas. Запись на на rw1990(rw1990.1)

Здравствуйте! Сегодня хочу рассказать о том, как сделать устройство, которое позволяет копировать Touch Memory фирмы Dallas. Статья предназначена для тех, кто имеет опыт в программирование на языках C/C++. Рассказывать, как устроен протокол OneWire я не собираюсь, т.к. в интернете куча информации на эту тему.

Итак, что нам понадобится для изготовления данного устройства:

1) Atmega8
2) FTDI RL232, преобразующий USB в USART
3) Драйвер для FTDI RL232
4) Программатор(Я использовал USBasp)
5) Visual Studio
6) Atmel Studio
7) Макетная плата
С таким набором можно двигаться дальше. Для начала приготовьте плату, на которой будете размещать компоненты.
Я это сделал так:

image

image

image

image

Теперь давайте определимся с параметрами USART на atmega8. У меня они такие:
1) Стоповый бит — 1
2) 9600boud
3) Бит четности — нет

Я буду использовать внутренний генератор на 4Mhz, так что регистр UBRR я буду настраивать под эту частоту. Вот кусок кода, где идет настройка USART:

 DDRD|=(1<<1);
        DDRD&=~(1<<0);
        UBRRH=0;
        UBRRL=25;
        UCSRB|=(1<<RXEN)|(1<<TXEN);
        UCSRC|=(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);


Пришло время разобрать протокол записи на болванки rw1990. Команда считывания 8-байтного кода у них идентична с ключами dallas.

Запись на rw1990 происходит так:
1) Посылаем импульс reset, и ожидаем presence импульс;
2) Отправляем команду 0xD1, тем самым разрешаем запись;
3) Тайм-слот, посылаем логический «0» (смотреть рис.1);
4) Посылаем импульс reset и ожидаем presence импульс;
5) Отправляем команду записи, 0xD5;
6) Посылаем 8-байтный код(все биты инвертированы), передача отличается от протокола oneWire (смотреть рис.1);
7) Посылаем импульс reset и ожидаем presence импульс;
8) Отправляем команду 0xD1, тем самым запрещаем запись;
9) Тайм-слот, посылаем логический «1» (смотреть рис.1).

Рис.1:

image

Кусок кода, где происходит запись:

bool onewire_init(){
        onewire_low();
        _delay_us(480);
        onewire_high();
        _delay_us(2);
        for(uint8_t i= 60;i;i++){
                if(!onewire_level()){
                        while(!onewire_level());
                        return true;
                }
                _delay_us(1);
        }
        return false;
}

void time_slot(uint8_t data){
        onewire_low();
        if(data)
                _delay_us(6);
        else
                _delay_us(60);
        onewire_high();
        _delay_ms(10);
}

void rw1990_write_bit(uint8_t data){
        onewire_low();
        if (data)
                _delay_us(6);
        else
                _delay_us(60);
        onewire_high();
        _delay_ms(2);
}

void rw1990_write(uint8_t data){
        for(uint8_t i=0;i<8;i++){
                rw1990_write_bit(data & 0x01);
                data>>=1;
        }
}

bool rw1990_newcode(uint8_t* buf){
        if (onewire_init()){
                onewire_send(0xD1);
                time_slot(0);
        }else return false;
        if(onewire_init()){
                onewire_send(0xD5);
                for(uint8_t i=0;i<8;i++){
                        rw1990_write(~buf[i]);
                }
        }else return false;
        if (onewire_init()){
                onewire_send(0xD1);
                time_slot(1);
        }else return false;
        return true;
}


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

Впрочем, на видео все показано.

Исходный код для atmega8
#define F_CPU 4000000 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define ONEWIRE_PORT      PORTB
#define ONEWIRE_DDR       DDRB
#define ONEWIRE_PIN       PINB
#define ONEWIRE_PIN_NUM   0


void     usart_init();
void     onewire_high();
void     onewire_low();
uint8_t  onewire_level();
bool     onewire_init();
void     onewire_write_bit(uint8_t);
void     onewire_send(uint8_t);
uint8_t  onewire_read_bit();
uint8_t  onewire_read();
bool     onewire_readrom(uint8_t*);
void     time_slot(uint8_t);
void     rw1990_write_bit(uint8_t);
void     rw1990_write(uint8_t);
bool     rw1990_newcode(uint8_t*);
uint8_t  usart_read();


uint8_t rom[8];
uint8_t new_rom[8];
uint8_t t=0;


ISR (USART_UDRE_vect){
        UDR=t;
        UCSRB &=~(1<<UDRIE);
        t=0;
}


int main(void)
{
        usart_init();
        asm("sei");
    while(1)
    {
                
                uint8_t r=usart_read();
                if (r==0x40){
                        for(uint8_t i=0;i<8;i++){
                                new_rom[i]=usart_read();
                        }
                        if(rw1990_newcode(new_rom)){
                                t=0x45;
                                UCSRB |=(1<<UDRIE);
                        }else{
                                t=0x46;
                                UCSRB |=(1<<UDRIE);
                        }
                }else if(r==0x30){
                        if(onewire_readrom(rom)){
                                t=0x35;
                                UCSRB |= (1<<UDRIE);
                                for (uint8_t i=0;i<8;i++){
                                        t=rom[i];
                                        UCSRB |= (1<<UDRIE);
                                        _delay_ms(1);
                                }
                        }else{
                                t=0x36;
                                UCSRB |= (1<<UDRIE);
                        }
                }

        }
}


void onewire_high(){
        ONEWIRE_PORT &=~ (1<<ONEWIRE_PIN_NUM);
        ONEWIRE_DDR  &=~ (1<<ONEWIRE_PIN_NUM);
}

void onewire_low(){
        ONEWIRE_PORT &=~ (1<<ONEWIRE_PIN_NUM);
        ONEWIRE_DDR  |= (1<<ONEWIRE_PIN_NUM);
}

uint8_t onewire_level(){
        return ONEWIRE_PIN & (1<<ONEWIRE_PIN_NUM);
}

bool onewire_init(){
        onewire_low();
        _delay_us(480);
        onewire_high();
        _delay_us(2);
        for(uint8_t i= 60;i;i++){
                if(!onewire_level()){
                        while(!onewire_level());
                        return true;
                }
                _delay_us(1);
        }
        return false;
}

void onewire_write_bit(uint8_t bit){
        onewire_low();
        if(bit){
                _delay_us(5);
                onewire_high();
                _delay_us(90);
        }else{
                _delay_us(90);
                onewire_high();
                _delay_us(5);
        }
}

void onewire_send(uint8_t data){
        for(uint8_t i=0;i<8;i++){
                onewire_write_bit(data&0x01);
                data>>= 1;
        }
}

void usart_init(){
        DDRD|=(1<<1);
        DDRD&=~(1<<0);
        UBRRH=0;
        UBRRL=25;
        UCSRB|=(1<<RXEN)|(1<<TXEN);
        UCSRC|=(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);
}

uint8_t onewire_read_bit(){
        onewire_low();
        _delay_us(2);
        onewire_high();
        _delay_us(8);
        uint8_t r = onewire_level();
        _delay_us(80);
        return r;
}

uint8_t onewire_read(){
          uint8_t r = 0;
          for (uint8_t p = 8; p; p--) {
                  r >>= 1;
         if (onewire_read_bit())
                  r |= 0x80;
          }
          return r;
}

void time_slot(uint8_t data){
        onewire_low();
        if(data)
                _delay_us(6);
        else
                _delay_us(60);
        onewire_high();
        _delay_ms(10);
}

void rw1990_write_bit(uint8_t data){
        onewire_low();
        if (data)
                _delay_us(6);
        else
                _delay_us(60);
        onewire_high();
        _delay_ms(2);
}

void rw1990_write(uint8_t data){
        for(uint8_t i=0;i<8;i++){
                rw1990_write_bit(data & 0x01);
                data>>=1;
        }
}

bool rw1990_newcode(uint8_t* buf){
        if (onewire_init()){
                onewire_send(0xD1);
                time_slot(0);
        }else return false;
        if(onewire_init()){
                onewire_send(0xD5);
                for(uint8_t i=0;i<8;i++){
                        rw1990_write(~buf[i]);
                }
        }else return false;
        if (onewire_init()){
                onewire_send(0xD1);
                time_slot(1);
        }else return false;
        return true;
}

bool onewire_readrom(uint8_t* buf){
                if (onewire_init()){
                        onewire_send(0x33);
                        for(uint8_t i=0;i<8;i++){
                                buf[i]=onewire_read();
                        }
                }else return false;
                return true;
}

uint8_t  usart_read(){
while(!(UCSRA & (1 << RXC)));
        return UDR;
}



Конечно, можно было сделать все в ООП стиле, но почему-то я решил так.
Исходник так называемого мной терминала iButton
main.cpp
#include <Windows.h>
#include <iostream>
#include "ComPort.h"


using namespace std;

int main(){
        char buf_file[10];
        wchar_t file[10];
        char name[20];
        char command[10];
        unsigned char rom[8];

        cout<<"Enter COM port: ";
        cin>>buf_file;

        cout<<"Enter your name: ";
        cin>>name;

        mbstowcs(file,buf_file,10);
        ComPort port((LPCWSTR)file,CBR_9600);

        cout<<"Welcome "<<name<<"! "<<"If you need help, you can write command \"help\"."<<endl;
        while(strcmp(command,"exit")){
                cout<<name<<"> ";
                cin>>command;
                if(!strcmp(command,"write_rom")){
                        scanf("%x %x %x %x %x %x %x %x",&rom[0],&rom[1],&rom[2],&rom[3],&rom[4],&rom[5],&rom[6],&rom[7]);
                        for(int i=0;i<50;i++){
                                port.ComWrite(0x40);
                                port.ComWrite((char*)rom,sizeof(rom));
                                char recv=port.ComRead();
                                if(recv==0x45){ 
                                        cout<<"Device> write successfull!"<<endl;
                                        break;
                                }else if(recv==0x46){ 
                                        cout<<"Device> write fail!"<<endl;
                                }
                                Sleep(100);
                        }
                }else if(!strcmp(command,"read_rom")){
                        for(int i=0;i<50;i++){
                                port.ComWrite(0x30);
                                char recv=port.ComRead();
                                if(recv==0x35){ 
                                        for(int i=0;i<8;i++){
                                                rom[i]=port.ComRead();
                                        }
                                        cout<<"Device> read successfull!    ";
                                        printf("%02X %02X %02X %02X %02X %02X %02X %0X\n",rom[0],rom[1],rom[2],rom[3],rom[4],rom[5],rom[6],rom[7]);
                                        break;
                                }else if(recv==0x36){ 
                                        cout<<"Device> read fail!"<<endl;
                                }
                                Sleep(100);
                        }
                }
        }
}



ComPort.cpp
#include <Windows.h>
#include "ComPort.h"

ComPort::ComPort(LPCWSTR str,DWORD baud)
{
        hSerial=CreateFile(str,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
        ComPort::baud=baud;
        SerialParams.DCBlength=sizeof(SerialParams);
        if(!GetCommState(hSerial,&SerialParams))
                MessageBox(NULL,L"Getting state error!",L"Error!",MB_OK|MB_ICONERROR);
        SerialParams.BaudRate=baud;
        SerialParams.ByteSize=8;
        SerialParams.StopBits=ONESTOPBIT;
        SerialParams.Parity=NOPARITY;
        if(!SetCommState(hSerial,&SerialParams))
                MessageBox(NULL,L"Error setting serial port state!",L"Error!",MB_OK|MB_ICONERROR);

}

void ComPort::ComWrite(unsigned char buf)
{
        DWORD send;
        WriteFile(hSerial,&buf,1,&send,NULL);
}

void ComPort::ComWrite(char* buf,int size)
{
        DWORD send;
        WriteFile(hSerial,buf,size,&send,NULL);
}

bool ComPort::ComRead(char* buf,int size)
{
        DWORD recv;
        char recvchar;
        ZeroMemory(buf,size);
        for(int i=0;i<size;i++){
        ReadFile(hSerial,&recvchar,1,&recv,0);
        if(recvchar=='~')
                break;
        buf[i]=recvchar;
        }
        return true;
}

char ComPort::ComRead()
{
        DWORD recv;
        char recvchar;
        ReadFile(hSerial,&recvchar,1,&recv,0);
        return recvchar;
}

ComPort::~ComPort(void)
{
        CloseHandle(hSerial);
}




ComPort.h
class ComPort
{
private:
        HANDLE hSerial;
        DCB SerialParams;
        LPCWSTR sPort;
        int baud;
public:
        ComPort(LPCWSTR,DWORD);
        void ComWrite(unsigned char);
        void ComWrite(char*,int);
        bool ComRead(char*,int);
        char ComRead();
        ~ComPort(void);
};





Код, конечно, не самый лучший, т.к. я пытался быстрее написать, но все же он прекрасно работает.

Вот что получилось у меня в конце:

image

image

image

image

А вот видео:

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Комментариев нет:

Отправить комментарий