RS 232 SPY


Автор: Александр
  Частенько приходится отлаживать совместную работу пары, а то и более, микроконтроллеров (иногда и ПО компьютерного) связанных между собой по интерфейсу rs232 (или его эквивалента с ttl уровнями). При этом желательно видеть какое устройство в какой момент времени что передаёт с учётом хронологии...
last update: Декабрь 2008



... конечно, можно для этого подключить линии RXD TXD ко входам двух COM-портов на компьютере, написать программку для созерцания и надеяться на то, что винда не задерживает данные на неопределённый срок времени.. но.
Win имеет такое занятное свойство - тормозить. Причём тормозит неодинаково для всего. Бывает и такое, что данные с одного COM порта приходят раньше чем с другого. О разделении данных во времени в пределах 10мс вообще говорить не получается.

Попутно к этому, комп не умеет работать с 9-и битными символами, что делает невозможным просмотр на компе обмен такими посылками.

Ещё для полноты картины иногда надо видеть состоянии каких-либо дискретных линий. С учётом хронологии, естественно.

Всё это вынудило затеить устройство, рабочий вариант которого здесь представлен..

ТТХ:
  • скорости: 9600/19200
  • чётность: чёт/нечёт/отсутствует
  • разрядность байта: 5,6,7,8,9 бит
  • разбиение пакетов по устанавливаемому таймауту: от 1мс с дискретностью 0.1мс
  • разбиение пакетов по линии: первая/вторая
  • наблюдение состояния дискретных линий
Применение:
  • отладка самопального программного протокола с физическим уровнем RS232
  • логирование обмена данными в готовых устройствах


Схема в кратце накидана такая:

Принципиальная схема:

Кликабельно


Забавно, не правда ли?

IN0, IN1 - входы данных с ТТЛ уровнями.. именно из-за них устройство и затеяно. Для подключения к линиям RS232 надо будет использовать преобразователь уровня типа ADM232.

D1..D4 - Дискретные входы.

DB9 - интерфейс к компу. Так как в имевшемся микроконтроллере есть всего 2 USART модуля, пришлось к компу подключать софтовый. Это плохо, да, я знаю. Но ничего поделать не могу. Надо было срочно иметь такое устройство.
Так как uart реализован программно, то и полярность сигналов я могу менять своими руками как угодно. Это и сделано для упрощения схемы - нет ADM232 для общения с компом.
Дополнительно использована линия CTS, запрещающая компу передавать данные, потому как одновременно принимать и передавать данные софтовым uart - накладно сильно.

В будущем ближайшем, это устройство будет усовершенствовано. В качестве основного изменения будет замена софтового uart, катастрофически ограничивающего возможности устройства, на FT245RL. Это позволит увеличить пропускную способность MCU<->PC до мегабита как минимум. А это, в свою очередь, позволит отлаживать интерфейсы на скоростях до 115кбод, я надеюсь.

С стороны компа всё это подключается к обычной терминалке для созерцания/логгирования.
Пример вывода:
timeout
uart 1:  DA  05  87  98  A7
uart 0:  DA  06  87  FC  E1  CA
timeout
uart 1:  DA  05  88  6F  5F
uart 0:  DA  2E  88  46  28  52  55  53  29  2D  30  32  2D  4D  57  20...
    ...  46  4C  2D  42  44  77  30  34  56  30  12  35  2D  33  33  20...
    ...  32  38  4D  41  52  30  36  20  32  44  31  37  40  1A
timeout
uart 1:  DA  05  89  E6  4E
uart 0:  DA  09  89  42  33  31  39  BA  9D
timeout
uart 1:  DA  05  8A  7D  7C
uart 0:  DA  25  8A  61  00  01  00  62  00  05  00  63  27  01  01  64...
    ...  27  05  01  65  27  0A  01  66  27  32  01  67  27  64  01  68...
    ...  00  32  02  73  B5
timeout


Данные выводятся в шестнадцатиричном формате по мере их поступления. Так как протокол двусторонний, то при смене направления передачи выводится и имя передающего.
Если количество данные в "пакете" превышает 16 байт, то вывод переносится на следующую строку "для красоты".
Если при приёме будут ошибки чётности и тп, то вместо неверно принятого байта будет отображена именно ошибка.

Настройка устройства производится через ту же терминалку. Достаточно передать устройству "1", и вы увидете меню:
-----------------------------------------
(1) spy stop
(2) spy start
(3) baudrate:     9600
(4) parity:       even
(5) stops:        1
(6) charsize:     8
(7/&) timeout:    0000010000 us

Нажимая указанные кнопки можно настроить нужные параметры передачи и перейти обратно к созерцанию.

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

Ну а теперь код...
Написано за пару дней с перерывами на чай, коментариев минимум, сам код местами неоптимален, местами ужасен.
Предложения по оптимизации в почту.
//============================================================================
//
//	name:					rs232spy
//
//	author:					Alexander
//
//	hardware and firmware design:
//							Alexander
//
//	hardware ver:			0.1
//	last update:			2008.11.20
//
//	firmware ver:			0.1
//	last update:			2008.12.08
//
//	target:					atmega1281
//	clk:					14745600 Hz
//	compiller:				avr gcc (WinAVR + AVR Studio)
//	optimization:			speed -Os
//
//============================================================================

//============================================================================
//	INCLUDES	//////////////////////////////////////////////////////////////
//============================================================================
#include <avr/io.h>						//
#include <avr/interrupt.h>				//обработка прерываний
#include <avr/pgmspace.h>				//доступ к пзу
#include <avr/iom1281.h>				//символьные имена регистров и тп.

#define BAUD_9600 95
#define BAUD_19200 47
#define BAUD_57600 15
#define BAUD_115200 7  //(((14745600)/(16*115200))-1);

#define bufferlength 512
volatile unsigned int buffer[bufferlength];
volatile unsigned int buffer_w_index=0;
volatile unsigned int buffer_r_index=0;
volatile unsigned int buffer_cnt=0;

volatile unsigned int rx_timeout = 0;

volatile unsigned int spy_timeout = 100;



//============================================================================
SIGNAL (TIMER0_COMPA_vect)
{
	char sreg = SREG;
	static char flag;
	if (rx_timeout)
	{
		rx_timeout--;
		flag = 1;
	}
	if ((rx_timeout==0)&&(flag!=0))
	{
		flag=0;
		buffer[buffer_w_index] = (2<<12);
		if ((++buffer_w_index) == bufferlength) buffer_w_index = 0;
		if ((++buffer_cnt) == bufferlength) buffer_cnt = 0;
	}
	SREG = sreg;
}

//============================================================================
SIGNAL (SIG_USART1_RECV)
{
	char sreg = SREG;

	buffer[buffer_w_index]	=	(1<<12);

	if(UCSR1A & (1<<FE1))	buffer[buffer_w_index]	+=	(1<<11);
	if(UCSR1A & (1<<DOR1))	buffer[buffer_w_index]	+=	(1<<10);
	if(UCSR1A & (1<<UPE1))	buffer[buffer_w_index]	+=	(1<<9);
	if(UCSR1B & (1<<RXB81)) buffer[buffer_w_index]	+=	(1<<8);

	buffer[buffer_w_index] += UDR1;

	if ((++buffer_w_index) == bufferlength) buffer_w_index = 0;
	if ((++buffer_cnt) == bufferlength) buffer_cnt = 0;
	rx_timeout = spy_timeout;
	SREG = sreg;
}

//============================================================================
SIGNAL (SIG_USART0_RECV)
{
	char sreg = SREG;
	buffer[buffer_w_index]	=	(0<<12);

	if(UCSR0A & (1<<FE0))	buffer[buffer_w_index]	+=	(1<<11);
	if(UCSR0A & (1<<DOR0))	buffer[buffer_w_index]	+=	(1<<10);
	if(UCSR0A & (1<<UPE0))	buffer[buffer_w_index]	+=	(1<<9);
	if(UCSR0B & (1<<RXB80)) buffer[buffer_w_index]	+=	(1<<8);


	buffer[buffer_w_index] += UDR0;

	if ((++buffer_w_index) == bufferlength) buffer_w_index = 0;
	if ((++buffer_cnt) == bufferlength) buffer_cnt = 0;
	rx_timeout = spy_timeout;
	SREG = sreg;
}

//============================================================================
unsigned int get_buff_word ()
{
	while (buffer_cnt==0);
	unsigned int data;
	data =  buffer[buffer_r_index];
	if ((++buffer_r_index) == bufferlength) buffer_r_index=0;
	cli();
	--buffer_cnt;
	sei();
	return data;
}
//============================================================================
unsigned int test_buff_word ()
{
	return buffer_cnt;
}

#define parity_disabled		0
#define parity_none			0
#define parity_even			2
#define parity_odd			3
#define stopbit1			0
#define stopbit2			1
#define charsize5			0
#define charsize6			1
#define charsize7			2
#define charsize8			3
#define charsize9			7


//============================================================================
void uart1_init(unsigned int baudrate, unsigned char parity, unsigned char charsize, unsigned char stops)
{
	PORTD	|=	(3<<2);	//единици на второй и третий разряд
	DDRD	|=	(1<<3);
	DDRD	&=	~(1<<2);	//сбросить
	UBRR1H	=	baudrate>>8;
	UBRR1L	=	baudrate;
	UCSR1A	=	0x00;

	UCSR1B	=	(1<<RXCIE1)|(0<<TXCIE1)|(0<<UDRIE1)|
				(1<<RXEN1)|(0<<TXEN1)|
				((charsize>>2)<<UCSZ12)|
				(0<<RXB81)|(0<<TXB81);

	UCSR1C	=	(0<<UMSEL11)|(0<<UMSEL10)|
				(parity<<UPM10)|
				(stops<<USBS1)|//(1<<UCSZ10)|(1<<UCSZ11)|
				((charsize & 0x03)<<UCSZ10)|
				(0<<UCPOL1);
}
//============================================================================
void uart1_stop(void)
{
	UCSR1B	=	(0<<RXCIE1)|(0<<TXCIE1)|(0<<UDRIE1)|
				(0<<RXEN1)|(0<<TXEN1)|
				(0<<UCSZ12)|
				(0<<RXB81)|(0<<TXB81);
}

//============================================================================
void uart0_init(unsigned int baudrate, unsigned char parity, unsigned char charsize, unsigned char stops)
{
	PORTD	|=	(3<<2);	//единици на второй и третий разряд
	DDRD	|=	(1<<3);
	DDRD	&=	~(1<<2);	//сбросить
	UBRR0H	=	baudrate>>8;
	UBRR0L	=	baudrate;
	UCSR0A	=	0x00;

	UCSR0B	=	(1<<RXCIE0)|(0<<TXCIE0)|(0<<UDRIE0)|
				(1<<RXEN0)|(0<<TXEN0)|
				((charsize>>2)<<UCSZ02)|
				(0<<RXB80)|(0<<TXB80);

	UCSR0C	=	(0<<UMSEL01)|(0<<UMSEL00)|
				(parity<<UPM00)|
				(stops<<USBS0)|//(1<<UCSZ00)|(1<<UCSZ01)|
				((charsize & 0x03)<<UCSZ00)|
				(0<<UCPOL0);
}
//============================================================================
void uart0_stop(void)
{
	UCSR0B	=	(0<<RXCIE0)|(0<<TXCIE0)|(0<<UDRIE0)|
				(0<<RXEN0)|(0<<TXEN0)|
				(0<<UCSZ02)|
				(0<<RXB80)|(0<<TXB80);
}







//============================================================================
SIGNAL (INT4_vect)
{
	char sreg = SREG;
	if (( PINE & (1<<4) ) == 0)
	{
		buffer[buffer_w_index] = (3<<12) + 0x40;
		EICRB	|=	(1<<ISC40);
	}
	else
	{
		buffer[buffer_w_index] = (3<<12) + 0x41;
		EICRB	&=	~(1<<ISC40);
	}
	if ((++buffer_w_index) == bufferlength) buffer_w_index = 0;
	if ((++buffer_cnt) == bufferlength) buffer_cnt = 0;
	SREG = sreg;
}
SIGNAL (INT5_vect)
{
	char sreg = SREG;
	if (( PINE & (1<<5) ) == 0)
	{
		buffer[buffer_w_index] = (3<<12) + 0x50;
		EICRB	|=	(1<<ISC50);
	}
	else
	{
		buffer[buffer_w_index] = (3<<12) + 0x51;
		EICRB	&=	~(1<<ISC50);
	}
	if ((++buffer_w_index) == bufferlength) buffer_w_index = 0;
	if ((++buffer_cnt) == bufferlength) buffer_cnt = 0;
	SREG = sreg;
}
SIGNAL (INT6_vect)
{
	char sreg = SREG;
	if (( PINE & (1<<6) ) == 0)
	{
		buffer[buffer_w_index] = (3<<12) + 0x60;
		EICRB	|=	(1<<ISC60);
	}
	else
	{
		buffer[buffer_w_index] = (3<<12) + 0x61;
		EICRB	&=	~(1<<ISC60);
	}
	if ((++buffer_w_index) == bufferlength) buffer_w_index = 0;
	if ((++buffer_cnt) == bufferlength) buffer_cnt = 0;
	SREG = sreg;
}
SIGNAL (INT7_vect)
{
	char sreg = SREG;
	if (( PINE & (1<<7) ) == 0)
	{
		buffer[buffer_w_index] = (3<<12) + 0x70;
		EICRB	|=	(1<<ISC70);
	}
	else
	{
		buffer[buffer_w_index] = (3<<12) + 0x71;
		EICRB	&=	~(1<<ISC70);
	}
	if ((++buffer_w_index) == bufferlength) buffer_w_index = 0;
	if ((++buffer_cnt) == bufferlength) buffer_cnt = 0;
	SREG = sreg;
}








//============================================================================
volatile unsigned char uarts_bitcnt;
volatile unsigned char uarts_byte;
volatile unsigned char uarts_byter;
volatile unsigned char uarts_flags=0;
#define uarts_rxf 0x80
#define uarts_txf 0x40
#define uarts_rxcf 0x20
#define uarts_rxline (1<<1)
#define uarts_txline (1<<0)
#define uarts_rtsline (1<<4)

#define usart_invert

#define uarts_bits 10
void uarts_init ()
{
	DDRD	|=	uarts_txline;		//первый на выход
	DDRD	|=	uarts_rtsline;		//контроль передачи на выход
	DDRD	&=	~uarts_rxline;	//второй на вход
	PORTD	&=	~(uarts_txline|uarts_rxline);
	TCCR2A	=	(0<<COM2A1)|(0<<COM2A0)|
				(0<<COM2B1)|(0<<COM2B0)|
				(1<<WGM21)|(0<<WGM20);
	TCCR2B	=	(0<<FOC2A)|(0<<FOC2B)|
				(0<<WGM22)|
				(0<<CS22)|(0<<CS21)|(0<<CS20);	//clk/0
	TIMSK2	=	(0<<OCIE2B)|(1<<OCIE2A)|(0<<TOIE2);

#ifndef usart_invert
	EICRA	|=	(1<<ISC11)|(0<<ISC10);
#else
	EICRA	|=	(1<<ISC11)|(1<<ISC10);
#endif

	EIMSK	|=	(1<<INT1);
}

//============================================================================
unsigned char uarts_putchar (unsigned char a)
{
	if (
		((uarts_flags & uarts_rxf)==0)&&
		((uarts_flags & uarts_txf)==0)
	)
	{
		#ifndef usart_invert
			PORTD			|=	uarts_rtsline;
		#else
			PORTD			&=	~uarts_rtsline;
		#endif


		uarts_flags		|=	uarts_txf;
		uarts_bitcnt	=	uarts_bits;
		uarts_byte		=	a;
		TCNT2			=	0;
		OCR2A			=	95;		//14745600/8/38400 = 48
		TCCR2B			|=	(0<<CS22)|(1<<CS21)|(0<<CS20);
		#ifndef usart_invert
			PORTD			&=	~uarts_txline;		//стартовый бит
		#else
			PORTD			|=	uarts_txline;		//стартовый бит
		#endif
		return 0;
	}
	else
	{
		return 0xff;
	}
}

//============================================================================
SIGNAL (INT1_vect)
{
	char sreg = SREG;
	if (
		((uarts_flags & uarts_rxf)==0)&&
		((uarts_flags & uarts_txf)==0)
	)
	{
		OCR2A			=	47;		//для контроля стартового бита ждём его середины
		TCCR2B			|=	(0<<CS22)|(1<<CS21)|(0<<CS20);
		uarts_flags 	&=	~uarts_rxcf;	//сбросим флаг готовности приёма
		uarts_flags 	|=	uarts_rxf;
		EIMSK			&=	~(1<<INT1);
		uarts_bitcnt	=	10;
	}
	SREG = sreg;
}

//============================================================================
SIGNAL (TIMER2_COMPA_vect)
{
	char sreg = SREG;
	if (
		((uarts_flags & uarts_rxf)==0)&&
		((uarts_flags & uarts_txf)!=0)		//если идёт передача
	)
	{
		uarts_bitcnt--;
		if ((uarts_byte & 0x01) != 0)
		{
			#ifndef usart_invert
				PORTD	|=	uarts_txline;
			#else
				PORTD	&=	~uarts_txline;
			#endif
		}
		else
		{
			#ifndef usart_invert
					PORTD	&=	~uarts_txline;
			#else
					PORTD	|=	uarts_txline;
			#endif
		}
		uarts_byte >>=1;
//		#ifndef usart_invert
			uarts_byte	|= 0x80;
//		#else
//			uarts_byte	&= ~0x80;
//		#endif
		if(uarts_bitcnt == 0)
		{
			TCCR2B	&=	~(1<<CS21);		//останавливаем таймер
			uarts_flags &= ~uarts_txf;
			#ifndef usart_invert
				PORTD			&=	~uarts_rtsline;
			#else
				PORTD			|=	uarts_rtsline;
			#endif
		}
	}
	else
	if (
		((uarts_flags & uarts_rxf)!=0)&&
		((uarts_flags & uarts_txf)==0)
	)
	{
		uarts_bitcnt--;
		if(uarts_bitcnt == 9)
		{
			OCR2A			=	95;		//до середины следующего бита
//			if(!(PIND & uarts_rxline))			//только если нормальный стартовый бит
//			{
//				TCCR2B	&=	~(1<<CS21);		//останавливаем таймер
//				uarts_flags &= ~uarts_rxf;
//				EIFR	|=	(1<<INTF1);
//				EIMSK	|=	(1<<INT1);
//			}
//необъяснимо, но проверка не работает
		}
		else
		if(uarts_bitcnt == 0)
		{
			TCCR2B	&=	~(1<<CS21);		//останавливаем таймер
			uarts_flags &= ~uarts_rxf;
			#ifndef usart_invert
				if((PIND & uarts_rxline)!=0)		//только если нормальный стоповый бит
			#else
				if((PIND & uarts_rxline)==0)
			#endif
			{
				uarts_flags |= uarts_rxcf;	//индицируем готовность
			}
			EIFR	|=	(1<<INTF1);
			EIMSK	|=	(1<<INT1);
		}
		else
		{
			uarts_byter >>=1;
			#ifndef usart_invert
				if((PIND & uarts_rxline)!=0)		//только если нормальный стоповый бит
			#else
				if((PIND & uarts_rxline)==0)
			#endif
			{
				uarts_byter |= 0x80;
			}
		}
	}
	SREG = sreg;
}

//============================================================================























//------------------------------------------------------------------------------
void terminal_putc(const char c)
{
	while (uarts_flags & uarts_txf);	//только когда закончатся все процессы.
	uarts_putchar(c);
}
//------------------------------------------------------------------------------
void terminal_putf(const char *data)
{
	while (pgm_read_byte(data) != 0x00)
		terminal_putc(pgm_read_byte(data++));
}
//------------------------------------------------------------------------------
void terminal_putret(void)
{
	terminal_putc(0x0d);
	terminal_putc(0x0a);
}
//------------------------------------------------------------------------------
void terminal_puthex(unsigned int a)
{
	terminal_putc(' ');

	if ((0x0100 & a) != 0 )
		terminal_putc('1');
	else
		terminal_putc(' ');


	if ((0x00f0 & a) > 0x0090)
		terminal_putc('A' + ((a & 0x00f0)>>4) - 0x000a);
	else
		terminal_putc('0' + ((a & 0x00f0)>>4));

	if ((0x000f & a) > 0x0009)
		terminal_putc('A' + (a & 0x000f) - 0x000a);
	else
		terminal_putc('0' + (a & 0x000f));
}


void t_bin32_2_bcd(signed long chislo, unsigned char *psymbol)
{
	unsigned char index;
	unsigned long vichet;

	vichet = 1000000000; index = 0;
	while (1){chislo -= vichet;if (chislo < 0) break; index++;};
	chislo += vichet; *psymbol = index;	psymbol++;

	vichet = 100000000; index = 0;
	while (1){chislo -= vichet;if (chislo < 0) break; index++;};
	chislo += vichet; *psymbol = index;	psymbol++;

	vichet = 10000000; index = 0;
	while (1){chislo -= vichet;if (chislo < 0) break; index++;};
	chislo += vichet; *psymbol = index;	psymbol++;

	vichet = 1000000; index = 0;
	while (1){chislo -= vichet;if (chislo < 0) break; index++;};
	chislo += vichet; *psymbol = index;	psymbol++;

	vichet = 100000; index = 0;
	while (1){chislo -= vichet;if (chislo < 0) break; index++;};
	chislo += vichet; *psymbol = index;	psymbol++;

	vichet = 10000; index = 0;
	while (1){chislo -= vichet;if (chislo < 0) break; index++;};
	chislo += vichet; *psymbol = index;	psymbol++;

	vichet = 1000; index = 0;
	while (1){chislo -= vichet;if (chislo < 0) break; index++;};
	chislo += vichet; *psymbol = index;	psymbol++;

	vichet = 100; index = 0;
	while (1){chislo -= vichet;if (chislo < 0) break; index++;};
	chislo += vichet; *psymbol = index;	psymbol++;

	vichet = 10; index = 0;
	while (1){chislo -= vichet;if (chislo < 0) break; index++;};
	chislo += vichet; *psymbol = index;	psymbol++;

    *psymbol = chislo;
}

//------------------------------------------------------------------------------
void terminal_putnum(unsigned long ddd)
{
	unsigned char symbols[10];
	unsigned char i;
	t_bin32_2_bcd(ddd, symbols);
	for (i=0;i<10;i++)
	{
		terminal_putc(symbols[i]+0x30);
	}
}








//============================================================================
//	MAIN	//////////////////////////////////////////////////////////////////
//============================================================================
int main (void)
{
	unsigned char spy_status = 4;

	unsigned char spy_ch = 0;
	unsigned char spy_nch = 0;
	unsigned int spy_bn = 0;

	unsigned char spy_baudr = BAUD_9600;
	unsigned char spy_parity = parity_even;
	unsigned char spy_stops = stopbit1;
	unsigned char spy_chars = charsize8;

	unsigned int temp;


	//таймер для отсчёта интервалов в 100мкс
	TCCR0A	=	(0<<COM0A1)|(0<<COM0A0)|
				(0<<COM0B1)|(0<<COM0B0)|
				(1<<WGM01)|(0<<WGM00);
	TCCR0B	=	(0<<FOC0A)|(0<<FOC0B)|
				(0<<WGM02)|
				(0<<CS02)|(1<<CS01)|(1<<CS00);
	OCR0A	=	23;
	TIMSK0	=	(0<<OCIE0B)|(1<<OCIE0A)|(0<<TOIE0);

	//----------------------------------------------
	PORTE	|=	0x30;
	DDRE	&=	~0xf0;
	EICRB	=	(1<<ISC71)|(1<<ISC70)|
				(1<<ISC61)|(1<<ISC60)|
				(1<<ISC51)|(1<<ISC50)|
				(1<<ISC41)|(1<<ISC40);
	EIMSK	=	(1<<INT7)|
				(1<<INT6)|
				(1<<INT5)|
				(1<<INT4);

	sei();//-----------------------------------


	uarts_init();

	terminal_putret();terminal_putret();terminal_putret();
	terminal_putret();terminal_putret();terminal_putret();
	terminal_putf(PSTR("Initialization\0"));
	terminal_putret();
	terminal_putf(PSTR("RS232SPY v0.1 by Alexander\0"));
	terminal_putret();

	//-------------------------------------
	for(;;)
	{
		switch (spy_status)
		{
			//-------------------------------
			case 0:
				if (uarts_flags & uarts_rxcf)
				{
					uarts_flags &= ~uarts_rxcf;
					switch (uarts_byter)
					{
						//------------------
						case '2':
							spy_status = 3;
						break;
						//------------------
						case '3':
							switch (spy_baudr)
							{
								case BAUD_9600:
									spy_baudr=BAUD_19200;
								break;
								case BAUD_19200:
									spy_baudr=BAUD_9600;
								break;
							}
							spy_status = 4;
						break;
						//------------------
						case '4':
							switch (spy_parity)
							{
								case parity_even:
									spy_parity=parity_none;
								break;
								case parity_none:
									spy_parity=parity_odd;
								break;
								case parity_odd:
									spy_parity=parity_even;
								break;
							}
							spy_status = 4;
						break;
						//------------------
						case '5':
							switch (spy_stops)
							{
								case stopbit1:
									spy_stops=stopbit2;
								break;
								case stopbit2:
									spy_stops=stopbit1;
								break;
							}
							spy_status = 4;
						break;
						//------------------
						case '6':
							switch (spy_chars)
							{
								case charsize5:
									spy_chars=charsize6;
								break;
								case charsize6:
									spy_chars=charsize7;
								break;
								case charsize7:
									spy_chars=charsize8;
								break;
								case charsize8:
									spy_chars=charsize9;
								break;
								case charsize9:
									spy_chars=charsize5;
								break;
							}
							spy_status = 4;
						break;
						//------------------
						case '7':
							spy_timeout += 10;
							spy_status = 4;
						break;
						//------------------
						case '&':
							if (spy_timeout>10)spy_timeout -= 10;
							spy_status = 4;
						break;
					}
				}
			break;

			//-----------------------------------
			case 1:
				if (test_buff_word())
				{
					temp = get_buff_word();
					spy_nch = (unsigned int)((temp & 0x3800)>>12);

					if (spy_nch == 3)
					{
						terminal_putret();
						terminal_putf(PSTR("inp \0"));
						terminal_putc(((temp & 0xf0)>>4) + 0x30);
						terminal_putc(':');
						if ((temp & 0x0f) == 0x01)terminal_putf(PSTR(" UP\0"));
						else if ((temp & 0x0f) == 0x00)terminal_putf(PSTR(" DOWN\0"));
					}
					if (spy_nch == 2)
					{
						terminal_putret();
						spy_bn = 0;

						temp = get_buff_word();
						spy_nch = (unsigned int)((temp & 0x3800)>>12);

						if (spy_ch == spy_nch)
						{
							terminal_putf(PSTR("uart \0"));
							terminal_putc(spy_nch + 0x30);
							terminal_putc(':');
						}
						else
						{
							terminal_putf(PSTR("timeout\0"));
						}
					}
					if ((spy_nch == 0) ||
						(spy_nch == 1) )
					{
						if(spy_ch != spy_nch)
						{
							terminal_putret();
							terminal_putf(PSTR("uart \0"));
							terminal_putc(spy_nch + 0x30);
							terminal_putc(':');
							spy_ch = spy_nch;
							spy_bn = 0;
						}
						if ( temp & ((1<<10)|(1<<9)))
						{
							if ( temp & (1<<11))terminal_putf(PSTR("!FE!\0"));
							if ( temp & (1<<10))terminal_putf(PSTR("!DO!\0"));
							if ( temp & (1<<9 ))terminal_putf(PSTR("!PE!\0"));
						}
						else
						{
							terminal_puthex(temp & 0x01ff);
							spy_bn ++;
							spy_bn &= 0x0f;
							if (spy_bn == 0)
							{
								terminal_putf(PSTR("...\0"));
								terminal_putret();
								terminal_putf(PSTR("    ...\0"));
							}
						}
					}
				}


				if ((uarts_flags & uarts_rxcf) != 0)
				{
					uarts_flags &= ~uarts_rxcf;
					if(uarts_byter=='1')
					{
						spy_status = 2;
					}
				}
			break;

			//-------------------------------
			case 2:
				uart0_stop();
				uart0_stop();
				spy_status = 4;
			break;

			//-------------------------------
			case 3:
				spy_status = 1;
				buffer_cnt = 0;
				buffer_w_index = 0;
				buffer_r_index = 0;
				uart1_init(spy_baudr,spy_parity,spy_chars,spy_stops);
				uart0_init(spy_baudr,spy_parity,spy_chars,spy_stops);
			break;

			//-------------------------------
			case 4:
				spy_status = 0;

				terminal_putret();terminal_putret();terminal_putret();
				terminal_putf(PSTR("-----------------------------------------\0"));
				terminal_putret();
				terminal_putf(PSTR("(1) spy stop\0"));
				terminal_putret();
				terminal_putf(PSTR("(2) spy start\0"));

				//-------
				terminal_putret();
				terminal_putf(PSTR("(3) baudrate:     \0"));
				switch (spy_baudr)
				{
					case BAUD_9600:
						terminal_putf(PSTR("9600\0"));
					break;
					case BAUD_19200:
						terminal_putf(PSTR("19200\0"));
					break;
				}
				//-------
				terminal_putret();
				terminal_putf(PSTR("(4) parity:       \0"));
				switch (spy_parity)
				{
					case parity_even:
						terminal_putf(PSTR("even\0"));
					break;
					case parity_none:
						terminal_putf(PSTR("none\0"));
					break;
					case parity_odd:
						terminal_putf(PSTR("odd\0"));
					break;
				}
				//-------
				terminal_putret();
				terminal_putf(PSTR("(5) stops:        \0"));
				switch (spy_stops)
				{
					case stopbit1:
						terminal_putf(PSTR("1\0"));
					break;
					case stopbit2:
						terminal_putf(PSTR("2\0"));
					break;
				}
				//-------
				terminal_putret();
				terminal_putf(PSTR("(6) charsize:     \0"));
				switch (spy_chars)
				{
					case charsize5:
						terminal_putf(PSTR("5\0"));
					break;
					case charsize6:
						terminal_putf(PSTR("6\0"));
					break;
					case charsize7:
						terminal_putf(PSTR("7\0"));
					break;
					case charsize8:
						terminal_putf(PSTR("8\0"));
					break;
					case charsize9:
						terminal_putf(PSTR("9\0"));
					break;
				}
				//-------
				terminal_putret();
				terminal_putf(PSTR("(7/&) timeout:    \0"));
				terminal_putnum(spy_timeout*100);
				terminal_putf(PSTR(" us\0"));

				terminal_putret();
//				uart0_init(spy_baudr,spy_parity,spy_chars,spy_stops);
//				terminal_puthex(UCSR0C);
//				terminal_putret();
			break;
		}
	}
}


//end