Копирование ключей 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

А вот видео:

ссылка на оригинал статьи http://habrahabr.ru/post/260891/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *