From: b <rowerynaksiezycu@gmail.com>
Date: Sat, 27 Jun 2020 11:05:01 +0000 (+0200)
Subject: bidirectional transmission at 9600, new commands
X-Git-Tag: v2.1
X-Git-Url: http://bicyclesonthemoon.info/git-projects/?a=commitdiff_plain;h=f7f0fc325d072235ae83dd91f3c233cffeda53c4;p=staf%2Fstaf

bidirectional transmission at 9600, new commands
---

diff --git a/.gitignore b/.gitignore
index 6c90a9d..d3aa545 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 *.a43
 *.elf
 *.hex
+*.map
diff --git a/definitions.h b/definitions.h
index 804f506..90da63b 100644
--- a/definitions.h
+++ b/definitions.h
@@ -1,8 +1,8 @@
-// SilentTimer Action Figure software, v1.5
+// SilentTimer Action Figure software, v2.1
 // definitions.h
 // Definitions used by the code.
 // 
-// 03.05.2020
+// 09.06.2020
 // Copyright (C) 2014-2017, 2020  Balthasar Szczepański
 //
 // This program is free software: you can redistribute it and/or modify
@@ -39,7 +39,23 @@
 
 //7 segment display
 
-#if defined OLD_HARDWARE
+#if defined NEW_DISPLAY
+
+#define SEG_A 0xfb
+#define SEG_B 0xf7 //    aaaa
+#define SEG_C 0xfd //   f    b
+#define SEG_D 0x7f //   f    b
+#define SEG_E 0xbf //hh  gggg
+#define SEG_F 0xfe //   e    c
+#define SEG_G 0xdf //   e    c
+#define SEG_H 0xef //    dddd 
+
+#define PIN_AB 0x23
+#define PIN_CD 0x17
+#define PIN_EF 0x60
+#define PIN_GH 0x54
+
+#elif defined OLD_HARDWARE
 
 #define SEG_A 0xdf
 #define SEG_B 0xef //    aaaa
@@ -50,6 +66,11 @@
 #define SEG_G 0xf7 //   e    c
 #define SEG_H 0xfe //    dddd 
 
+#define PIN_AB 0x54
+#define PIN_CD 0x67
+#define PIN_EF 0x12
+#define PIN_GH 0x30
+
 #else
 
 #define SEG_A 0xfd
@@ -61,6 +82,11 @@
 #define SEG_G 0xbf //   e    c
 #define SEG_H 0xf7 //    dddd 
 
+#define PIN_AB 0x14
+#define PIN_CD 0x20
+#define PIN_EF 0x57
+#define PIN_GH 0x63
+
 #endif
 
 #define SYMB_0   (SEG_A & SEG_B & SEG_C & SEG_D & SEG_E & SEG_F        )
@@ -132,11 +158,22 @@
 
 #define EVENTS    0x1f
 
+#define EVENT_ALARM 0x20
+#define EVENT_0     0x40
+
 #define ALARMVALUE 0xa5
 
+
+//rs232
 #define RXBUFSIZE 11
 #define RXDATASIZE 5
 
+#define TXBUFSIZE 32
+#define TXBUFMASK 31
+
+#define BAUDCOUNT 625 //6MHz/625 = 9600Hz (buzz. 4.8kHz)
+#define BAUDHALF  (313+200) //determined by oscilloscope observation
+
 
 unsigned char bcd_add_byte (unsigned char, unsigned char);
 void          lpm3         ();
diff --git a/main.c b/main.c
index 994cfda..8d6ede5 100644
--- a/main.c
+++ b/main.c
@@ -1,8 +1,8 @@
-// SilentTimer Action Figure software, v1.5
+// SilentTimer Action Figure software, v2.1
 // main.c
 // The main c file.
 // 
-// 03.05.2020
+// 27.06.2020
 // Copyright (C) 2014-2017, 2020  Balthasar Szczepański
 // 
 // This program is free software: you can redistribute it and/or modify
@@ -18,6 +18,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 	
+	// #define NEW_DISPLAY
 	// #define OLD_HARDWARE
 	// #define DEBAG
 	#include "msp430.h"
@@ -42,6 +43,7 @@
 	         unsigned char changed; //changed value during edit
 	         unsigned char run; //switch used in some states
 	         unsigned char cont; //continued calculation
+	         unsigned char buzzmode=0; //buzzer, 0-normal, 1-mute, 2-always on.
 	
 	//for RS232 receiving
 	volatile unsigned char rxbyte=0;
@@ -52,7 +54,16 @@
 	         unsigned char rxdata[RXDATASIZE];
 	         unsigned char rxcmd;
 	
+	volatile unsigned char txbyte;
+	volatile unsigned char txcount=0;
+	volatile unsigned char txindW=0;
+	volatile unsigned char txindR=0;
+	volatile unsigned char txpin=1;
+	volatile unsigned char txbuf[TXBUFSIZE];
+	volatile unsigned char txbuzz=0;
+	
 	volatile unsigned char event=0;
+	         unsigned char eventmask=0;
 	
 	const    unsigned char symbol[16] ={
 		SYMB_0,
@@ -81,6 +92,10 @@
 	void leave(void);
 	void showvalue(void);
 	
+	void send(unsigned char data);
+	void sendhex(unsigned char data);
+	void sendevent(unsigned char data);
+	
 	void display(
 		unsigned char *data);
 	void spi(
@@ -91,26 +106,81 @@
 		unsigned short n);
 	
 	int main( void );
-
+	
+	void send(unsigned char data)
+	{
+		if (data == '\n')
+			send ('\r');
+		
+		while (((txindW - txindR) & TXBUFMASK) == TXBUFMASK) {} //wait for free buffer
+		
+		//put byte to output buffer
+		txbuf[txindW] = data;
+		++txindW;
+		txindW &= TXBUFMASK;
+		
+		if (!(TACCTL0 & CCIE))
+		{
+			TACCTL0 &= ~CCIFG;
+			TACCTL0 |= CCIE;
+		}
+	}
+	
+	void sendhex (unsigned char data)
+	{
+		unsigned char i,j;
+		
+		for (i=0; i<2; ++i)
+		{
+			j = i? (data & 0x0f) : (data>>4);
+			
+			if (j>9)
+				j += 87;
+			else
+				j += 48;
+			
+			send(j);
+		}
+	}
+	
+	void sendevent (unsigned char data)
+	{
+		if (data & eventmask)
+		{
+			send('O');
+			sendhex(data);
+			send('\n');
+		}
+	}
+	
 	void display(unsigned char *data)
 	{
-		//lsd
-		P1OUT =data[0];
-		P3OUT |=0x80; //74hc373 latch enable
-		P3OUT &=0x0f;
+		unsigned char i,j;
 		
-		P1OUT =data[1];
-		P3OUT |=0x40;
-		P3OUT &=0x0f;
+		for(i=0,j=0x80; i<4; ++i, j>>=1)
+		// for(i=0,j=0x80; i<2; ++i, j>>=1)
+		{
+			P1OUT = data[i];
+			P3OUT |= j;
+			P3OUT &= ~j;
+		}
+		// //lsd
+		// P1OUT =data[0];
+		// P3OUT |=0x80; //74hc373 latch enable
+		// P3OUT &=0x0f;
+		
+		// P1OUT =data[1];
+		// P3OUT |=0x40;
+		// P3OUT &=0x0f;
 		
-		P1OUT =data[2];
-		P3OUT |=0x20;
-		P3OUT &=0x0f;
+		// P1OUT =data[2];
+		// P3OUT |=0x20;
+		// P3OUT &=0x0f;
 		
-		//msd
-		P1OUT =data[3];
-		P3OUT |=0x10;
-		P3OUT &=0x0f;
+		// //msd
+		// P1OUT =data[3];
+		// P3OUT |=0x10;
+		// P3OUT &=0x0f;
 	}
 
 	void spi(
@@ -207,58 +277,126 @@
 	#pragma vector=TIMERA0_VECTOR
 	__interrupt void TA0_ISR()
 	{
+		// P3OUT |=0x10;
+		
 		rxpin = P2IN & 0x10; //quickly capture state of P2.4
 		
-		TACCTL0 &= ~CCIFG;
+		if(txpin)
+			P2OUT |=  0x04;
+		else
+			P2OUT &= ~0x04;
 		
-		++rxcount;
+		TACCTL0 &= ~CCIFG;
 		
-		if (!(rxcount & 0x01)) //only every second count
+		if (rxcount) // receive mode
 		{
-			if (rxcount == 2) //start bit
-			{
-				if (rxpin) //start fail
-				{
-					rxcount = 0;
-					TACCTL0 &= ~CCIE; //abort
-				}
-			}
-			else if (rxcount >= 20) //stop bit
-			{
-				if (rxpin) //correct stop bit
+			++rxcount;
+			
+			// if (!(rxcount & 0x01)) //only every second count
+			// {
+				if (rxcount == 2) //start bit
 				{
-					if (rxbyte == 0x0d || rxbyte == 0x0a) // CR or NL, end of frame
+					if (rxpin) //start fail
 					{
-						if(rxind)
-						{
-							rxind = 0;
-							event |= EVENT_RS; //signal 
-						}
+						rxcount = 0;
+						txcount = 0;
+						txindR = txindW;
+						P2OUT |=  0x04;
+						TACCTL0 &= ~CCIE; //abort
 					}
-					else
+				}
+				else if (rxcount >= 11) //stop bit
+				{
+					if (rxpin) //correct stop bit
 					{
-						if (rxbyte >= 'g' && rxbyte <= 'z') //new command
+						if (rxbyte == 0x0d || rxbyte == 0x0a) // CR or NL, end of frame
 						{
-							rxind=0;
+							if(rxind)
+							{
+								rxind = 0;
+								event |= EVENT_RS; //signal 
+							}
 						}
-						if (rxind < RXBUFSIZE) //still place in buffer
+						else
 						{
-							rxbuf[rxind] = rxbyte; //put byte to buffer
-							++rxind;
+							if ((rxbyte >= 'g' && rxbyte <= 'z') || (rxbyte >= 'G' && rxbyte <= 'Z')) //new command
+							{
+								rxind=0;
+							}
+							if (rxind < RXBUFSIZE) //still place in buffer
+							{
+								rxbuf[rxind] = rxbyte; //put byte to buffer
+								++rxind;
+							}
 						}
 					}
+					rxcount = 0;
+					txcount = 0;
+					txindR = txindW;
+					P2OUT |=  0x04;
+					TACCTL0 &= ~CCIE; //stop receiving
 				}
-				rxcount = 0;
-				TACCTL0 &= ~CCIE; //stop receiving
-			}
-			else //receive single bit
+				else //receive single bit
+				{
+					rxbyte >>= 1;
+					rxbyte |= rxpin ? 0x80 : 0x00;
+				}
+			// }
+			if(event)
+				_BIC_SR_IRQ(OSCOFF|CPUOFF|SCG1|SCG0);
+		}
+		
+		else if ((txindR != txindW)  || txcount) //transmit mode
+		{
+			if(txcount)
+				--txcount;
+			
+			if (!txcount) //reached end of byte
 			{
-				rxbyte >>= 1;
-				rxbyte |= rxpin ? 0x80 : 0x00;
+				if (txindR != txindW) //bytes to send available
+				{
+					txbyte=txbuf[txindR];
+					++txindR; //next byte
+					txindR &= TXBUFMASK;
+					txcount = 10;
+				}
+				
+				else  if (txbuzz) //buzzer should be done
+				{
+					txbyte = 0x55;
+					txcount = 10;
+				}
 			}
+			
+			// if (!(txcount & 0x01)) //every second count
+			// {
+				if ((txcount == 1) || (txcount == 0)) //stop bit
+					txpin = 1;
+				else if (txcount == 10) //start bit
+					txpin = 0;
+				else if (txcount < 10) //data bits
+				{
+					txpin = txbyte & 0x01;
+					txbyte >>= 1;
+				}
+				else //before start
+					txpin = 1;
+			// }
 		}
-		if(event)
-			_BIC_SR_IRQ(OSCOFF|CPUOFF|SCG1|SCG0);
+		
+		else if (txbuzz) //buzzer should be done
+		{
+			txcount = 2; //start buzzer from stop bit
+		}
+			
+		
+		else //nothing left to do
+		{
+			txpin = 1;
+			TACCTL0 &= ~CCIE;
+		}
+		
+		// P3OUT &= ~0x10;
 		return;
 	}
 	
@@ -287,17 +425,27 @@
 		}
 		else if(P2IFG&0x10) // RS232
 		{
+			// P3OUT |= 0x10;
 			P2IFG &= ~0x10;
 			
 			if(!rxcount) //start bit detected
 			{
-				TACTL |= TACLR; //reset timer
+				// TACTL |= TACLR; //reset timer
+				TACTL &= ~MC_3; //stop timer
+				TAR = BAUDHALF; //set timer to half count
+				TACTL |= MC_1; //start timer
 				TACCTL0 &= ~CCIFG; //clear any waiting timer interrupt
 				TACCTL0 |= CCIE; //enable timer interrupts
 				
 				rxcount = 1;
 				rxbyte = 0;
+				
+				txcount = 0; //cancel transmission
+				// txindW = 0;
+				txindR = txindW;
+				txpin = 1;
 			}
+			// P3OUT &= ~0x10;
 		}
 		else
 			P2IFG=0;
@@ -335,6 +483,7 @@ void gettime(void)
 		mode=MODE_ALARM;
 		alarm[0]=0; //alarm removed after activated
 		spi(RTC_WRITE,0x20,inbuf,alarm,1);
+		sendevent(EVENT_ALARM);
 	}
 	
 	
@@ -498,7 +647,7 @@ void leave (void) //to execute when leaving an edit state
 		else
 		{
 			alarm[0]=0;
-			spi(RTC_WRITE,0x20,inbuf,outbuf,1);
+			spi(RTC_WRITE,0x20,inbuf,alarm,1);
 		}
 		mode=MODE_TIME;
 		break;
@@ -664,7 +813,7 @@ void exec (void) //execute every second
 		event |= EVENT_RTC;
 		break;
 	case MODE_DOWN:
-		if(run && (settime[1] | settime[0]))
+		if(run && (settime[1] || settime[0]))
 		{
 			if(settime[0])
 				settime[0]=bcd_add_byte(settime[0],0x99);
@@ -673,6 +822,8 @@ void exec (void) //execute every second
 				settime[0]=0x59;
 				settime[1]=bcd_add_byte(settime[1],0x99);
 			}
+			if (!(settime[1] || settime[0]))
+				sendevent(EVENT_0);
 		}
 		else
 			run=0;
@@ -839,7 +990,7 @@ void showvalue () //determine what to show on display
 			break;
 		case MODE_VER:
 			dispvalue[4] = SYMB_NUL;
-			dispvalue[5] = SYMB_0;
+			dispvalue[5] = SYMB_1;
 			dispvalue[6] = SYMB_2;
 			dispvalue[7] = SYMB_NUL;
 			dot |= 0x02; //.
@@ -928,20 +1079,35 @@ void showvalue () //determine what to show on display
 		if(dot & (1<<i))
 			dispvalue[i] &= SYMB_DOT;
 	}
-	if (dot & 0x80)
-		P2SEL ^=  0x04;
-	else
-		P2SEL &= ~0x04;
+	if (buzzmode & 0x01) //force mute
+		txbuzz = 0;
+	else if (buzzmode & 0x02) //force buzzer
+		txbuzz = 1;
+	else if (dot & 0x80) //beep
+		txbuzz = !txbuzz;
+	else //no action
+		txbuzz = 0;
 	
+	if (txbuzz && !(TACCTL0 & CCIE))
+	{
+		TACCTL0 &= ~CCIFG;
+		TACCTL0 |= CCIE;
+	}
 }
 
 int main( void )
 {
 	unsigned char i,j;
+	unsigned char *p;
 	
 	//watchdog:
 	WDTCTL = WDTPW + WDTHOLD;
 	
+	//rs232 output
+	P2OUT |=  0x04;
+	P2SEL &= ~0x04;
+	P2DIR |=  0x04;
+	
 	//init 7 segment display
 	
 	P1OUT =0xff; //display data on p1
@@ -1088,7 +1254,7 @@ int main( void )
 	}
 	
 	//init timer:
-	TACCR0 = 625-1; //6MHz/625 = 9600Hz (buzz. 4.8kHz)
+	TACCR0 = BAUDCOUNT - 1;
 	TACCTL0=   //also, compare, not capture
 		// CCIE| //enable interupt
 		OUTMOD_4; //toggle
@@ -1098,9 +1264,6 @@ int main( void )
 		MC_1| //up mode
 		TACLR; //reset
 	// P2SEL|=0x04; //P2.2 timer output.
-	P2OUT &= ~0x04;
-	P2SEL &= ~0x04;
-	P2DIR |=  0x04;
 	
 	// Init interrupts
 	P2IE=
@@ -1117,14 +1280,8 @@ int main( void )
 		mode=MODE_CALIB;
 	else if(!(P2IN&0x01)) //button B pressed at start?
 	{
-		calcdata[0] = 0x00;
-		calcdata[1] = 0x00;
-		calcdata[2] = 0x00;
-		calcdata[3] = 0x00;
-		calcdata[4] = 0x00;
-		calcdata[5] = 0x00;
-		calcdata[6] = 0x00;
-		calcdata[7] = 0x00;
+		for (i=0; i<8; ++i)
+			calcdata[i] = 0x00;
 		mode=MODE_CALC;
 	}
 	else if(!(P2IN&0x20)) //button C pressed at start?
@@ -1146,6 +1303,7 @@ int main( void )
 			if (event & EVENT_A)
 			{
 				event &= ~ EVENT_A;
+				sendevent(EVENT_A);
 				
 				if (mode & MODE_EDIT) 
 				{
@@ -1180,14 +1338,8 @@ int main( void )
 					case MODE_CALC:
 						if (calcdata[7] || calcdata[1] || calcdata[0]) //if error on non-0
 						{
-							calcdata[0]=0x00;
-							calcdata[1]=0x00;
-							calcdata[2]=0x00;
-							calcdata[3]=0x00;
-							calcdata[4]=0x00;
-							calcdata[5]=0x00;
-							calcdata[6]=0x00;
-							calcdata[7]=0x00;
+							for (j=0; j<8; ++j)
+								calcdata[j] = 0x00;
 						}
 						else
 							mode = MODE_TIME;
@@ -1220,6 +1372,7 @@ int main( void )
 			else if (event & EVENT_B)
 			{
 				event &= ~ EVENT_B;
+				sendevent(EVENT_B);
 				
 				if (mode & MODE_EDIT) 
 				{
@@ -1266,14 +1419,8 @@ int main( void )
 					case MODE_CALC:
 						if(calcdata[7])
 						{
-							calcdata[0]=0x00;
-							calcdata[1]=0x00;
-							calcdata[2]=0x00;
-							calcdata[3]=0x00;
-							calcdata[4]=0x00;
-							calcdata[5]=0x00;
-							calcdata[6]=0x00;
-							calcdata[7]=0x00;
+							for (j=0; j<8; ++j)
+								calcdata[j] = 0x00;
 						}
 						else
 						{
@@ -1319,6 +1466,7 @@ int main( void )
 			else if (event & EVENT_C)
 			{
 				event &= ~ EVENT_C;
+				sendevent(EVENT_C);
 				
 				if (mode & MODE_EDIT) 
 				{
@@ -1357,14 +1505,8 @@ int main( void )
 					case MODE_CALC:
 						if(calcdata[7])
 						{
-							calcdata[0]=0x00;
-							calcdata[1]=0x00;
-							calcdata[2]=0x00;
-							calcdata[3]=0x00;
-							calcdata[4]=0x00;
-							calcdata[5]=0x00;
-							calcdata[6]=0x00;
-							calcdata[7]=0x00;
+							for (j=0; j<8; ++j)
+								calcdata[j] = 0x00;
 						}
 						else
 						{
@@ -1426,116 +1568,205 @@ int main( void )
 						rxdata[i>>1] = j<<4;
 				}
 				
-				switch (rxcmd)
+				if(rxcmd & 0x20) //lowercase
 				{
-				case 'g': //force display value
-					forcedisp[0]=rxdata[0];
-					forcedisp[1]=rxdata[1];
-					forcedisp[2]=rxdata[2];
-					forcedisp[3]=rxdata[3];
-					forcedisp[4]=1;
-					break;
-				case 'h': //free display value
-					forcedisp[4]=0;
-					break;
-				case 'i': //trigger event
-					event |= rxdata[0];
-					break;
-				case 'j': //go to mode
-					mode = rxdata[0];
-					enter();
-					break;
-				case 'k': //select digit
-					digit = rxdata[0];
-					break;
-				case 'l': //value under digit
-					i = digit >> 1;
-					j = settime[i];
-					if (digit & 0x01)
-					{	
-						j &= 0x0f;
-						j |= rxdata[0]<<4;
-					}
-					else
+					switch (rxcmd)
 					{
-						j &= 0xf0;
-						j |= rxdata[0]&0x0f;
+					case 'g': //force display value
+						for (i=0; i<4; ++i)
+							forcedisp[i]=rxdata[i];
+						forcedisp[4]=1;
+						break;
+					case 'h': //free display value
+						forcedisp[4]=0;
+						break;
+					case 'i': //trigger event
+						event |= rxdata[0];
+						break;
+					case 'j': //go to mode
+						mode = rxdata[0];
+						enter();
+						break;
+					case 'k': //select digit
+						digit = rxdata[0];
+						break;
+					case 'l': //value under digit
+						i = digit >> 1;
+						j = settime[i];
+						if (digit & 0x01)
+						{	
+							j &= 0x0f;
+							j |= rxdata[0]<<4;
+						}
+						else
+						{
+							j &= 0xf0;
+							j |= rxdata[0]&0x0f;
+						}
+						settime[i] = j;
+						break;
+					case 'm': //confirm editing
+						changed=1;
+						leave();
+						enter();
+						break;
+					case 'n':
+					case 'o':
+					case 'p':
+					case 'q':
+					case 'r':
+					case 's':
+					case 't':
+					case 'u':
+					case 'v': //enter values
+						changed = 1;
+						settime[0] = rxdata[0];
+						settime[1] = rxdata[1];
+						settime[2] = rxdata[2];
+						switch (rxcmd)
+						{
+						case 'n': //set time
+							mode = MODE_EDIT | MODE_SETTIME;
+							break;
+						case 'o': //set alarm
+							mode = MODE_EDIT | MODE_SETALARM;
+							if(settime[0]==0xff && settime[1]==0xff)
+							{
+								changed=0;
+								alarm[0]=ALARMVALUE;
+							}
+							break;
+						case 'p': //set date
+							mode = MODE_EDIT | MODE_SETDATE;
+							break;
+						case 'q': //set year
+							mode = MODE_EDIT | MODE_SETYEAR;
+							break;
+						case 'r': //set countdown
+							mode = MODE_EDIT | MODE_SETDOWN;
+							run=0;
+							break;
+						case 's': //set calibration
+							mode = MODE_EDIT | MODE_SETCALIB;
+							break;
+						case 't': //set debug address
+							mode = MODE_EDIT | MODE_SETDEBUGADDR;
+							break;
+						case 'u': //set debug value
+							mode = MODE_EDIT | MODE_SETDEBUGVAL;
+							break;
+						case 'v': //perform calculation
+							calcdata[0]=0x00;
+							calcdata[1]=0x00;
+							for (i=0; i<5; ++i)
+							calcdata[i+2]=rxdata[i];
+							// calcdata[3]=rxdata[1];
+							// calcdata[4]=rxdata[2];
+							// calcdata[5]=rxdata[3];
+							// calcdata[6]=rxdata[4];
+							calcdata[7]=0;
+							run = 1;
+							cont = 0xFF;
+							mode = MODE_EDIT | MODE_SETCALCNUM;
+						}
+						leave();
+						break;
+					case 'w': //set value
+						settime[0]=rxdata[0];
+						settime[1]=rxdata[1];
+						settime[2]=rxdata[2];
+						break;
+					case 'x': //set run/pause
+						run = rxdata[0];
+						break;
+					case 'y': //set buzzer mode
+						buzzmode = rxdata[0];
+						break;
+					case 'z': //set memory
+						p = (unsigned char*)(*((unsigned short*)rxdata));
+						*p = rxdata[2];
+						break;
 					}
-					settime[i] = j;
-					break;
-				case 'm': //confirm editing
-					changed=1;
-					leave();
-					enter();
-					break;
-				case 'n':
-				case 'o':
-				case 'p':
-				case 'q':
-				case 'r':
-				case 's':
-				case 't':
-				case 'u':
-				case 'v': //enter values
-					changed = 1;
-					settime[0] = rxdata[0];
-					settime[1] = rxdata[1];
-					settime[2] = rxdata[2];
+				}
+				else //uppercase
+				{
+					send(rxcmd);
 					switch (rxcmd)
 					{
-					case 'n': //set time
-						mode = MODE_EDIT | MODE_SETTIME;
+					case 'G': //get time
+						gettime();
+						for (i=0; i<8; ++i)
+						{
+							if (i != 4)
+								sendhex(time[i]); //hs
+						}
+						sendhex(lastyear[4]); //yL
 						break;
-					case 'o': //set alarm
-						mode = MODE_EDIT | MODE_SETALARM;
-						if(settime[0]==0xff && settime[1]==0xff)
-							changed=0;
+					case 'H': //get state
+						sendhex(mode);
 						break;
-					case 'p': //set date
-						mode = MODE_EDIT | MODE_SETDATE;
+					case 'I': //get display
+						for (i=0; i<4; ++i)
+							sendhex(dispvalue[i]);
 						break;
-					case 'q': //set year
-						mode = MODE_EDIT | MODE_SETYEAR;
+					case 'J': //get value
+						sendhex(settime[0]);
+						sendhex(settime[1]);
+						sendhex(settime[2]);
 						break;
-					case 'r': //set countdown
-						mode = MODE_EDIT | MODE_SETDOWN;
-						run=0;
+					case 'K': //get calculation
+						for (i=0; i<8; ++i)
+							sendhex(calcdata[i]);
 						break;
-					case 's': //set calibration
-						mode = MODE_EDIT | MODE_SETCALIB;
+					case 'L': //get run state
+						sendhex(run);
 						break;
-					case 't': //set debug address
-						mode = MODE_EDIT | MODE_SETDEBUGADDR;
+					case 'M': //get version
+						sendhex(1);
+						sendhex(2);
 						break;
-					case 'u': //set debug value
-						mode = MODE_EDIT | MODE_SETDEBUGVAL;
+					case 'N': //get pinout
+						sendhex(PIN_AB);
+						sendhex(PIN_CD);
+						sendhex(PIN_EF);
+						sendhex(PIN_GH);
+						break;
+					case 'O': //subscribe for events
+						eventmask = rxdata[0];
+						sendhex(0);
+						break;
+					case 'P': //get alarm
+						if(alarm[0])
+						{
+							sendhex(alarm[1]);
+							sendhex(alarm[2]);
+						}
+						else
+						{
+							sendhex(0xFF);
+							sendhex(0xFF);
+						}
+						break;
+					case 'Q': //get diit
+						sendhex(digit);
+						break;
+					case 'R': //set memory
+						p = (unsigned char*)(*((unsigned short*)rxdata));
+						sendhex(*p);
 						break;
-					case 'v': //perform calculation
-						calcdata[0]=0x00;
-						calcdata[1]=0x00;
-						calcdata[2]=rxdata[0];
-						calcdata[3]=rxdata[1];
-						calcdata[4]=rxdata[2];
-						calcdata[5]=rxdata[3];
-						calcdata[6]=rxdata[4];
-						calcdata[7]=0;
-						run = 1;
-						cont = 0xFF;
-						mode = MODE_EDIT | MODE_SETCALCNUM;
 					}
-					leave();
-					break;
+					send('\n');
 				}
 			}
 			else if (event & EVENT_RTC)
 			{
 				event &= ~ EVENT_RTC;
+				sendevent(EVENT_RTC);
 				gettime();
 				exec();
 			}
 			
 			showvalue();
-			
 			display(forcedisp[4]?forcedisp:dispvalue);
 		}
 		else //go to low power mode if nothing's going on
diff --git a/makefile b/makefile
index 55c300b..623bf44 100644
--- a/makefile
+++ b/makefile
@@ -1,8 +1,8 @@
-# SilentTimer Action Figure software, v1.5
+# SilentTimer Action Figure software, v2.1
 # makefile
 # 
-# 29.02.2016
-# Copyright (C) 2014-2016  Balthasar Szczepański
+# 27.06.2020
+# Copyright (C) 2014-2016, 2020  Balthasar Szczepański
 # 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -19,13 +19,19 @@
 
 CC=msp430-gcc
 CF=-g -Wa,-g,-L -Os -mmcu=msp430f1232
-# OC=msp430-objcopy
-# OF=-O ihex
+OC=msp430-objcopy
+OF=-O ihex
 
-all: st.elf
+all: st.elf st_AB.elf st_ID.elf st.hex st_AB.hex st_ID.hex
 
 main.o: main.c definitions.h makefile
-	msp430-gcc -g -c -Os -mmcu=msp430f1232 -o main.o main.c
+	msp430-gcc -g -c -Os -mmcu=msp430f1232 -o main.o    main.c
+
+main_AB.o: main.c definitions.h makefile
+	msp430-gcc -g -c -Os -mmcu=msp430f1232 -o main_AB.o main.c -D OLD_HARDWARE
+
+main_ID.o: main.c definitions.h makefile
+	msp430-gcc -g -c -Os -mmcu=msp430f1232 -o main_ID.o main.c -D NEW_DISPLAY
 
 asmp.s: asm.S makefile
 	msp430-gcc    -E     -mmcu=msp430f1232 -o asmp.s asm.S
@@ -34,9 +40,19 @@ asm.o: asmp.s makefile
 	msp430-as  -g        -mmcu=msp430f1232 -o asm.o  asmp.s
 
 st.elf: main.o asm.o makefile
-	msp430-gcc -g        -mmcu=msp430f1232 -o st.elf main.o asm.o
-#st.elf: main.c asm.S definitions.h makefile
-#	$(CC) $(CF) -o st.elf asm.S main.c
+	msp430-gcc -g        -mmcu=msp430f1232 -o st.elf    main.o asm.o -Xlinker -Map=st.map
 	
-# st.hex: st.elf makefile
-# 	$(OC) $(OF) st.elf st.hex
+st_AB.elf: main_AB.o asm.o makefile
+	msp430-gcc -g        -mmcu=msp430f1232 -o st_AB.elf main_AB.o asm.o -Xlinker -Map=st_AB.map
+
+st_ID.elf: main_ID.o asm.o makefile
+	msp430-gcc -g        -mmcu=msp430f1232 -o st_ID.elf main_ID.o asm.o -Xlinker -Map=st_ID.map
+
+st.hex: st.elf makefile
+	$(OC) $(OF) st.elf    st.hex
+
+st_AB.hex: st_AB.elf makefile
+	$(OC) $(OF) st_AB.elf st_AB.hex
+
+st_ID.hex: st_ID.elf makefile
+	$(OC) $(OF) st_ID.elf st_ID.hex