Example #1
0
// process message "brightness"
void process_brightness(MessageTypeEnum messagetype)
{
	// "Set" or "SetGet" -> modify dimmer state and abort any running animation
	if ((messagetype == MESSAGETYPE_SET) || (messagetype == MESSAGETYPE_SETGET))
	{
		start_brightness = end_brightness = msg_dimmer_brightness_get_brightness();

		UART_PUTF("Requested Brightness: %u%%;", start_brightness);
		
		animation_length = 0;
		animation_mode = 0;
		animation_position = 0;

		setPWMDutyCyclePercent(start_brightness);
						
		/* TODO: Write to EEPROM (?)
		// write back switch state to EEPROM
		switch_state[i] = req_state;
		switch_timeout[i] = req_timeout;
		
		eeprom_write_word((uint16_t*)EEPROM_POS_SWITCH_STATE + i * 2, u16);
		*/
	}

	// remember some values before the packet buffer is destroyed
	uint32_t acksenderid = pkg_header_get_senderid();
	uint32_t ackpacketcounter = pkg_header_get_packetcounter();

	inc_packetcounter();

	// "Set" -> send "Ack"
	if (messagetype == MESSAGETYPE_SET)
	{
		pkg_header_init_dimmer_brightness_ack();

		UART_PUTS("Sending Ack\r\n");
	}
	// "Get" or "SetGet" -> send "AckStatus"
	else
	{
		pkg_header_init_dimmer_brightness_ackstatus();
		
		// set message data
		msg_dimmer_brightness_set_brightness(start_brightness);

		UART_PUTS("Sending AckStatus\r\n");
	}

	// set common fields
	pkg_header_set_senderid(device_id);
	pkg_header_set_packetcounter(packetcounter);
	
	pkg_headerext_common_set_acksenderid(acksenderid);
	pkg_headerext_common_set_ackpacketcounter(ackpacketcounter);
	pkg_headerext_common_set_error(false); // FIXME: Move code for the Ack to a function and also return an Ack when errors occur before!
	
	pkg_header_calc_crc32();
	
	rfm12_send_bufx();
}
Example #2
0
void print_switch_state(uint8_t max)
{
	uint8_t i;
	uint16_t u16;

	for (i = 1; i <= max; i++)
	{
		u16 = getBuf16(4 + i * 2);
		
		UART_PUTF(";Switch %u=", i);
		
		if (u16 & 0b1)
		{
			UART_PUTS("ON");
		}
		else
		{
			UART_PUTS("OFF");
		}
		
		u16 = u16 >> 1;
		
		if (u16)
		{		
			UART_PUTF2(";Timeout %u=%us", i, u16);
		}
	}
}
Example #3
0
// Assume a request as acknowledged and delete it from the request_buffer and request_queue.
void remove_request(uint8_t sender_id, uint8_t request_sender_id, uint32_t packet_counter)
{
	if (request_sender_id != 0) // if acknowledge is not meant for the base station (which has device id 0)
	{			
		UART_PUTS("Ignoring ack (request not from this device).\r\n");
	}
	else
	{
		uint8_t rq_slot;
		
		for (rq_slot = 0; rq_slot < REQUEST_QUEUE_RECEIVERS; rq_slot++)
		{
			if (request_queue[rq_slot][0] == sender_id)
			{
				// Because we use a fifo queue, the first buffered element has to be the one that is acknowledged.
				// We don't need to check the others.
				uint8_t rb_slot = request_queue[rq_slot][1];
				{
					if (request_buffer[rb_slot].packet_counter == packet_counter)
					{
						uint8_t i;
						
						UART_PUTF("Removing request from request buffer slot %u.\r\n", rb_slot);
						
						// remove from request buffer
						request_buffer[rb_slot].command_id = RS_UNUSED;
						
						// remove from request queue
						for (i = 1; i < REQUEST_QUEUE_PACKETS; i++)
						{
							request_queue[rq_slot][i] = request_queue[rq_slot][i + 1];
						}
						
						request_queue[rq_slot][REQUEST_QUEUE_PACKETS] = RS_UNUSED;
						
						// delete request queue entry if no more packets in this queue_request
						if (request_queue[rq_slot][1] == RS_UNUSED)
						{
							UART_PUTF("Request queue %u is now empty.\r\n", rq_slot);
							request_queue[rq_slot][0] = RS_UNUSED;
						}
						
						print_request_queue();
					}
					else
					{
						UART_PUTS("Warning: Sender ID from ack found in queue, but Packet Counter does not match.\r\n");
					}
					
					return;
				}
			}
		}
		
		// After the last retry, a packet is immediately removed from the queue, and therefore not found if it is acknowledged.
		UART_PUTS("Warning: Acknowledged request not found in queue (could have been the last retry).\r\n");
	}
}
// Only for debugging...
void print_request_queue(void)
{
    uint8_t i, j;
    bool empty = true;

    for (i = 0; i < REQUEST_BUFFER_SIZE; i++)
    {

        if (request_buffer[i].message_type != MESSAGETYPE_UNUSED)
        {
            UART_PUTF("Request Buffer %u: ", i);
            UART_PUTF4("MessageType %u, PacketCounter %lu, Timeout %u, Retry %u, Data", request_buffer[i].message_type, request_buffer[i].packet_counter, request_buffer[i].timeout, request_buffer[i].retry_count);

            // TODO: only show bytes of real data length
            for (j = 0; j < request_buffer[i].data_bytes; j++)
            {
                UART_PUTF(" %02x", request_buffer[i].data[j]);
            }

            UART_PUTS("\r\n");
        }
    }

    for (i = 0; i < REQUEST_QUEUE_RECEIVERS; i++)
    {
        if (request_queue[i][0] != SLOT_UNUSED)
        {
            empty = false;

            UART_PUTF("Request Queue %u: ", i);
            UART_PUTF("ReceiverID %u, Buffer slots", request_queue[i][0]);

            for (j = 0; j < REQUEST_QUEUE_PACKETS; j++)
            {
                if (request_queue[i][j + 1] == SLOT_UNUSED)
                {
                    UART_PUTS(" -");
                }
                else
                {
                    UART_PUTF(" %u", request_queue[i][j + 1]);
                }
            }

            UART_PUTS("\r\n");
        }
    }

    if (empty)
    {
        UART_PUTS("Request Queue empty");
    }

    UART_PUTS("\r\n");
}
Example #5
0
// Only for debugging...
void print_request_queue(void)
{
	uint8_t i, j;
	bool empty = true;
	
	for (i = 0; i < REQUEST_BUFFER_SIZE; i++)
	{
		
		if (request_buffer[i].command_id != RS_UNUSED)
		{
			UART_PUTF("Request buffer %u: ", i);
			UART_PUTF4("Command ID %u, Packet Counter %lu, Timeout %u, Retry %u, Data", request_buffer[i].command_id, request_buffer[i].packet_counter, request_buffer[i].timeout, request_buffer[i].retry_count);
			
			for (j = 0; j < 5; j++)
			{
				UART_PUTF(" %02x", request_buffer[i].data[j]);
			}
			
			UART_PUTS("\r\n");
		}
	}

	for (i = 0; i < REQUEST_QUEUE_RECEIVERS; i++)
	{
		if (request_queue[i][0] != RS_UNUSED)
		{
			empty = false;
			
			UART_PUTF("Request Queue %u: ", i);
			UART_PUTF("Receiver ID %u, Buffer slots", request_queue[i][0]);
			
			for (j = 0; j < REQUEST_QUEUE_PACKETS; j++)
			{
				if (request_queue[i][j + 1] == RS_UNUSED)
				{
					UART_PUTS(" -");
				}
				else
				{
					UART_PUTF(" %u", request_queue[i][j + 1]);
				}
			}
			
			UART_PUTS("\r\n");
		}
	}

	if (empty)
	{
		UART_PUTS("Request Queue empty");
	}

	UART_PUTS("\r\n");
}
Example #6
0
void send_dimmer_status(void)
{
	UART_PUTS("Sending Dimmer Status:\r\n");

	// set device ID
	bufx[0] = device_id;
	
	// update packet counter
	packetcounter++;
	
	if (packetcounter % PACKET_COUNTER_WRITE_CYCLE == 0)
	{
		eeprom_write_dword((uint32_t*)0, packetcounter);
	}

	setBuf32(1, packetcounter);

	// set command ID "Dimmer Status"
	bufx[5] = 30; // TODO: Move command IDs to global definition file as defines

	// set current brightness
	bufx[6] = (uint8_t)(current_brightness * 255 / 100);
	
	// set end brightness
	bufx[7] = end_brightness;
	
	// set total animation time
	setBuf16(8, (uint16_t)(animation_length * ANIMATION_CYCLE_MS / 1000));

	// set time until animation finishes
	setBuf16(10, (uint16_t)((animation_length - animation_position) * ANIMATION_CYCLE_MS / 1000));

	// set CRC32
	uint32_t crc = crc32(bufx, 12);
	setBuf32(12, crc);

	// show info
	UART_PUTF("CRC32: %lx\r\n", crc);
	uart_putstr("Unencrypted: ");
	printbytearray(bufx, 16);

	rfm12_sendbuf();
	
	UART_PUTS("Send encrypted: ");
	printbytearray(bufx, 16);
	UART_PUTS("\r\n");
}
Example #7
0
void send_packet(uint8_t aes_key_nr, uint8_t data_len)
{
	// set device ID (base station has ID 0 by definition)
	bufx[0] = 0;

	// update packet counter
	packetcounter++;
	
	if (packetcounter % PACKET_COUNTER_WRITE_CYCLE == 0)
	{
		eeprom_write_dword((uint32_t*)0, packetcounter);
	}

	setBuf32(1, packetcounter);

	// set CRC32
	uint32_t crc = crc32(bufx, data_len + 6);
	setBuf32(data_len + 6, crc);

	// load AES key (0 is first AES key)
	if (aes_key_nr >= AES_KEY_EEPROM_COUNT)
	{
		aes_key_nr = AES_KEY_EEPROM_COUNT - 1;
	}
	
	eeprom_read_block (aes_key, (uint8_t *)(EEPROM_POS_AES_KEY + aes_key_nr * 32), 32);
	
	// show info
	decode_data(data_len + 6);
	UART_PUTF("       AES key: %u\r\n", aes_key_nr);
	
	UART_PUTF("         CRC32: %02lx\r\n", crc);
	UART_PUTS("   Unencrypted: ");
	printbytearray(bufx, data_len + 10);

	// encrypt and send
	uint8_t aes_byte_count = rfm12_sendbuf(data_len + 10);
	
	UART_PUTS("Send encrypted: ");
	printbytearray(bufx, aes_byte_count);

	UART_PUTS("\r\n");
}
Example #8
0
// printf for floating point numbers takes ~1500 bytes program size.
// Therefore, we use a smaller special function instead
// as long it is used so rarely.
void printSigned(int16_t i)
{
	if (i < 0)
	{
		UART_PUTS("-");
		i = -i;
	}
	
	UART_PUTF2("%d.%02d;", i / 100, i % 100);
}
Example #9
0
void printbytearray(uint8_t * b, uint8_t len)
{
	uint8_t i;
	
	for (i = 0; i < len; i++)
	{
		UART_PUTF("%02x ", b[i]);
	}
	
	UART_PUTS ("\r\n");
}
Example #10
0
// printf for floating point numbers takes ~1500 bytes program size.
// Therefore, we use a smaller special function instead
// as long it is used so rarely.
void print_signed(int16_t i)
{
#ifdef UART_DEBUG
	if (i < 0)
	{
		UART_PUTS("-");
		i = -i;
	}
	
	UART_PUTF2("%d.%02d", i / 100, i % 100);
#endif // UART_DEBUG
}
Example #11
0
void printbytearray(uint8_t * b, uint8_t len)
{
#ifdef UART_DEBUG
	uint8_t i;
	
	for (i = 0; i < len; i++)
	{
		UART_PUTF("%02x ", b[i]);
	}
	
	UART_PUTS ("\r\n");
#endif
}
Example #12
0
void process_cmd(void)
{
	uart_putstr("Processing command: ");
	uart_putstr(cmdbuf);
	UART_PUTS("\r\n");
	
	if ((cmdbuf[0] == 'w') && (strlen(cmdbuf) == 5))
	{
		if (enable_write_eeprom)
		{
			uint16_t adr = hex_to_byte((uint8_t)cmdbuf[1]) * 16 + hex_to_byte((uint8_t)cmdbuf[2]);
			uint8_t val = hex_to_uint8((uint8_t *)cmdbuf, 3);
			UART_PUTF2("Writing data 0x%x to EEPROM pos 0x%x.\r\n", val, adr);
			eeprom_write_byte((uint8_t *)adr, val);
		}
		else
		{
			UART_PUTS("Ignoring EEPROM write, since write mode is DISABLED.\r\n");
		}
	}
	else if ((cmdbuf[0] == 'r') && (strlen(cmdbuf) == 3))
	{
		
		uint16_t adr = hex_to_byte((uint8_t)cmdbuf[1]) * 16 + hex_to_byte((uint8_t)cmdbuf[2]);
		uint8_t val = eeprom_read_byte((uint8_t *)adr);
		UART_PUTF2("EEPROM value at position 0x%x is 0x%x.\r\n", adr, val);
	}
	else if ((cmdbuf[0] == 's') && (strlen(cmdbuf) > 4))
	{
		strcpy(sendbuf, cmdbuf + 1);
		send_data_avail = true;
	}
	else
	{
		UART_PUTS("Unknown command.\r\n");
	}
}
Example #13
0
void send_dimmer_status(void)
{
	UART_PUTS("Sending Dimmer Status:\r\n");

	inc_packetcounter();
	uint8_t bri = (uint8_t)current_brightness;
	
	// Set packet content
	pkg_header_init_dimmer_brightness_status();
	pkg_header_set_senderid(device_id);
	pkg_header_set_packetcounter(packetcounter);
	msg_dimmer_brightness_set_brightness(bri);

	pkg_header_calc_crc32();
	
	UART_PUTF("CRC32 is %lx (added as first 4 bytes)\r\n", getBuf32(0));
	UART_PUTF("Brightness: %u%%\r\n", bri);

	rfm12_send_bufx();
}
Example #14
0
// Show info about the received packets.
// This is only for debugging and only few messages are supported. The definition
// of all packets must be known at the PC program that's processing the data.
void decode_data(uint8_t len)
{
	uint32_t u32, messagegroupid, messageid;
	uint16_t u16;
	
	pkg_header_adjust_offset();

	uint16_t senderid = pkg_header_get_senderid();
	uint32_t packetcounter = pkg_header_get_packetcounter();
	MessageTypeEnum messagetype = pkg_header_get_messagetype();

	UART_PUTF("Packet Data: SenderID=%u;", senderid);
	UART_PUTF("PacketCounter=%lu;", packetcounter);
	UART_PUTF("MessageType=%u;", messagetype);

	// show ReceiverID for all requests
	if ((messagetype == MESSAGETYPE_GET) || (messagetype == MESSAGETYPE_SET) || (messagetype == MESSAGETYPE_SETGET))
	{
		uint16_t receiverid = pkg_headerext_common_get_receiverid();
		UART_PUTF("ReceiverID=%u;", receiverid);
	}
	
	uint16_t acksenderid = 65000;
	uint32_t ackpacketcounter = 0;

	// show AckSenderID, AckPacketCounter and Error for "Ack" and "AckStatus"
	if ((messagetype == MESSAGETYPE_ACK) || (messagetype == MESSAGETYPE_ACKSTATUS))
	{
		acksenderid = pkg_headerext_common_get_acksenderid();
		ackpacketcounter = pkg_headerext_common_get_ackpacketcounter();
		uint8_t error = pkg_headerext_common_get_error();
		UART_PUTF("AckSenderID=%u;", acksenderid);
		UART_PUTF("AckPacketCounter=%lu;", ackpacketcounter);
		UART_PUTF("Error=%u;", error);
	}

	// show MessageGroupID and MessageID for all MessageTypes except "Ack"
	if (messagetype != MESSAGETYPE_ACK)
	{
		messagegroupid = pkg_headerext_common_get_messagegroupid();
		messageid = pkg_headerext_common_get_messageid();
		UART_PUTF("MessageGroupID=%u;", messagegroupid);
		UART_PUTF("MessageID=%u;", messageid);
	}
	
	// show raw message data for all MessageTypes with data (= all except "Get" and "Ack")
	if ((messagetype != MESSAGETYPE_GET) && (messagetype != MESSAGETYPE_ACK))
	{
		uint8_t i;
		uint8_t start = __HEADEROFFSETBITS / 8;
		uint8_t shift = __HEADEROFFSETBITS % 8;
		uint16_t count = (((uint16_t)len * 8) - __HEADEROFFSETBITS + 7) / 8;
	
		//UART_PUTF4("\r\n\r\nLEN=%u, START=%u, SHIFT=%u, COUNT=%u\r\n\r\n", len, start, shift, count);
	
		UART_PUTS("MessageData=");
	
		for (i = start; i < start + count; i++)
		{
			UART_PUTF("%02x", array_read_UIntValue8(i, shift, 8, 0, 255, bufx));
		}
		
		UART_PUTS(";");

		// additionally decode the message data for a small number of messages
		switch (messagegroupid)
		{
			case MESSAGEGROUP_GENERIC:

				switch (messageid)
				{
					case MESSAGEID_GENERIC_VERSION:
						UART_PUTF("Major=%u;", msg_generic_version_get_major());
						UART_PUTF("Minor=%u;", msg_generic_version_get_minor());
						UART_PUTF("Patch=%u;", msg_generic_version_get_patch());
						UART_PUTF("Hash=%08lx;", msg_generic_version_get_hash());
						break;
						
					case MESSAGEID_GENERIC_BATTERYSTATUS:
						UART_PUTF("Percentage=%u;", msg_generic_batterystatus_get_percentage());
						break;
						
					/*DateTime Status:
					UART_PUTS("Command Name=DateTime Status;");
					UART_PUTF3("Date=%u-%02u-%02u;", bufx[6] + 2000, bufx[7], bufx[8]);
					UART_PUTF3("Time=%02u:%02u:%02u", bufx[9], bufx[10], bufx[11]);*/
				
					default:
						break;
				}
				
				break;

			case MESSAGEGROUP_WEATHER:
				
				switch (messageid)
				{
					case MESSAGEID_WEATHER_TEMPERATURE:
						UART_PUTS("Temperature=");
						print_signed(msg_weather_temperature_get_temperature());
						UART_PUTS(";");
						break;
					case MESSAGEID_WEATHER_HUMIDITYTEMPERATURE:
						u16 = msg_weather_humiditytemperature_get_humidity();
						UART_PUTF2("Humidity=%u.%u;Temperature=", u16 / 10, u16 % 10);
						print_signed(msg_weather_humiditytemperature_get_temperature());
						UART_PUTS(";");
						break;
					case MESSAGEID_WEATHER_BAROMETRICPRESSURETEMPERATURE:
						u32 = msg_weather_barometricpressuretemperature_get_barometricpressure();
						UART_PUTF("Pressure=%ld;Temperature=", u32);
						print_signed(msg_weather_barometricpressuretemperature_get_temperature());
						UART_PUTS(";");
						break;
					default:
						break;
				}
				
				break;

			case MESSAGEGROUP_POWERSWITCH:
				
				switch (messageid)
				{
					case MESSAGEID_POWERSWITCH_SWITCHSTATE:
						UART_PUTF("On=%u;", msg_powerswitch_switchstate_get_on());
						UART_PUTF("TimeoutSec=%u;", msg_powerswitch_switchstate_get_timeoutsec());
						break;
					default:
						break;
				}
				
				break;
			
			default:
				break;
		}
	}

	UART_PUTS("\r\n");
	
	// Detect and process Acknowledges to base station, whose requests have to be removed from the request queue
	if ((messagetype == MESSAGETYPE_ACK) || (messagetype == MESSAGETYPE_ACKSTATUS))
	{
		if (acksenderid == device_id) // request sent from base station
		{
			remove_request(senderid, device_id, ackpacketcounter);
		}
	}
}
Example #15
0
int main(void)
{
	uint8_t aes_key_nr;
	uint8_t loop = 0;
	uint8_t loop2 = 0;
	
	// delay 1s to avoid further communication with uart or RFM12 when my programmer resets the MC after 500ms...
	_delay_ms(1000);

	util_init();

	check_eeprom_compatibility(DEVICETYPE_BASESTATION);

	request_queue_init();

	// read packetcounter, increase by cycle and write back
	packetcounter = e2p_generic_get_packetcounter() + PACKET_COUNTER_WRITE_CYCLE;
	e2p_generic_set_packetcounter(packetcounter);

	// read device specific config
	aes_key_count = e2p_basestation_get_aeskeycount();

	device_id = e2p_generic_get_deviceid();

	uart_init();
	UART_PUTS("\r\n");
	UART_PUTF4("smarthomatic Base Station v%u.%u.%u (%08lx)\r\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_HASH);
	UART_PUTS("(c) 2012..2014 Uwe Freese, www.smarthomatic.org\r\n");
	UART_PUTF("Device ID: %u\r\n", device_id);
	UART_PUTF("Packet counter: %lu\r\n", packetcounter);
	UART_PUTF("AES key count: %u\r\n", aes_key_count);
	UART_PUTS("Waiting for incoming data. Press h for help.\r\n\r\n");

	led_blink(500, 500, 3);

	rfm12_init();
	sei();
	
	// ENCODE TEST (Move to unit test some day...)
	/*
	uint8_t testlen = 32;
	uint8_t aes_key_num = 0;
	
	memset(&bufx[0], 0, sizeof(bufx));
	bufx[0] = 0xff;
	bufx[1] = 0xb0;
	bufx[2] = 0xa0;
	bufx[3] = 0x3f;
	bufx[4] = 0x01;
	bufx[5] = 0x70;
	bufx[6] = 0x00;
	bufx[7] = 0x0c;
	bufx[8] = 0xa8;
	bufx[9] = 0x00;
	bufx[10] = 0x20;
	bufx[20] = 0x20;

	eeprom_read_block (aes_key, (uint8_t *)(EEPROM_AESKEYS_BYTE + aes_key_num * 32), 32);
	UART_PUTS("Using AES key ");
	print_bytearray((uint8_t *)aes_key, 32);
	
	UART_PUTS("Before encryption: ");
	print_bytearray(bufx, testlen);
	
	uint8_t aes_byte_count = aes256_encrypt_cbc(bufx, testlen);
	
	UART_PUTF("byte count = %u\r\n", aes_byte_count);
	
	UART_PUTS("After encryption: ");
	print_bytearray(bufx, aes_byte_count);
	
	aes256_decrypt_cbc(bufx, aes_byte_count);
  
	UART_PUTS("After decryption: ");
	print_bytearray(bufx, testlen);
	
	while(1);
	*/

	while (42)
	{
		if (rfm12_rx_status() == STATUS_COMPLETE)
		{
			uint8_t len = rfm12_rx_len();
			
			if ((len == 0) || (len % 16 != 0))
			{
				UART_PUTF("Received garbage (%u bytes not multiple of 16): ", len);
				print_bytearray(bufx, len);
			}
			else // try to decrypt with all keys stored in EEPROM
			{
				bool crcok = false;

				for (aes_key_nr = 0; aes_key_nr < aes_key_count ; aes_key_nr++)
				{
					memcpy(bufx, rfm12_rx_buffer(), len);

					/*if (aes_key_nr == 0)
					{
						UART_PUTS("Before decryption: ");
						print_bytearray(bufx, len);
					}*/
				
					e2p_basestation_get_aeskey(aes_key_nr, aes_key);
					//UART_PUTS("Trying AES key 2 ");
					//print_bytearray((uint8_t *)aes_key, 32);

					aes256_decrypt_cbc(bufx, len);

					//UART_PUTS("Decrypted bytes: ");
					//print_bytearray(bufx, len);
					
					crcok = pkg_header_check_crc32(len);
					
					if (crcok)
					{
						//UART_PUTS("CRC correct, AES key found!\r\n");
						UART_PUTF("Received (AES key %u): ", aes_key_nr);
						print_bytearray(bufx, len);
						
						decode_data(len);
						
						break;
					}
				}
				
				if (!crcok)
				{
					UART_PUTS("Received garbage (CRC wrong after decryption): ");
					memcpy(bufx, rfm12_rx_buffer(), len);
					print_bytearray(bufx, len);
				}
				
				UART_PUTS("\r\n");
			}

			//uart_hexdump((char *)bufcontents, rfm12_rx_len());
			//UART_PUTS("\r\n");

			// tell the implementation that the buffer can be reused for the next data.
			rfm12_rx_clear();
		}

		// send data, if waiting in send buffer
		if (send_data_avail)
		{
			uint8_t i;
			
			// set AES key nr
			aes_key_nr = hex_to_uint8((uint8_t *)cmdbuf, 1);
			//UART_PUTF("AES KEY = %u\r\n", aes_key_nr);

			// init packet buffer
			memset(&bufx[0], 0, sizeof(bufx));

			// set message type
			uint8_t message_type = hex_to_uint8((uint8_t *)cmdbuf, 3);
			pkg_header_set_messagetype(message_type);
			pkg_header_adjust_offset();
			//UART_PUTF("MessageType = %u\r\n", message_type);

			uint8_t string_offset_data = 0;
			
			/*
			UART_PUTS("sKK00RRRRGGMM.............Get\r\n");
			UART_PUTS("sKK01RRRRGGMMDD...........Set\r\n");
			UART_PUTS("sKK02RRRRGGMMDD...........SetGet\r\n");
			UART_PUTS("sKK08GGMMDD...............Status\r\n");
			UART_PUTS("sKK09SSSSPPPPPPEE.........Ack\r\n");
			UART_PUTS("sKK0ASSSSPPPPPPEEGGMMDD...AckStatus\r\n");
			*/
			
			// set header extension fields to the values given as hex string in the user input
			switch (message_type)
			{
				case MESSAGETYPE_GET:
				case MESSAGETYPE_SET:
				case MESSAGETYPE_SETGET:
					pkg_headerext_common_set_receiverid(hex_to_uint16((uint8_t *)cmdbuf, 5));
					pkg_headerext_common_set_messagegroupid(hex_to_uint8((uint8_t *)cmdbuf, 9));
					pkg_headerext_common_set_messageid(hex_to_uint8((uint8_t *)cmdbuf, 11));
					string_offset_data = 12;
					break;
				case MESSAGETYPE_STATUS:
					pkg_headerext_common_set_messagegroupid(hex_to_uint8((uint8_t *)cmdbuf, 5));
					pkg_headerext_common_set_messageid(hex_to_uint8((uint8_t *)cmdbuf, 7));
					string_offset_data = 8;
					break;
				case MESSAGETYPE_ACK:
					pkg_headerext_common_set_acksenderid(hex_to_uint16((uint8_t *)cmdbuf, 5));
					pkg_headerext_common_set_ackpacketcounter(hex_to_uint24((uint8_t *)cmdbuf, 9));
					pkg_headerext_common_set_error(hex_to_uint8((uint8_t *)cmdbuf, 15));
					// fallthrough!
				case MESSAGETYPE_ACKSTATUS:
					pkg_headerext_common_set_messagegroupid(hex_to_uint8((uint8_t *)cmdbuf, 17));
					pkg_headerext_common_set_messageid(hex_to_uint8((uint8_t *)cmdbuf, 19));
					string_offset_data = 20;
					break;
			}

			uint8_t data_len_raw = 0;

			// copy message data, which exists in all packets except in Get and Ack packets
			if ((message_type != MESSAGETYPE_GET) && (message_type != MESSAGETYPE_ACK))
			{
				uint8_t data_len_raw = (strlen(cmdbuf) - 1 - string_offset_data) / 2;
				//UART_PUTF("Data bytes = %u\r\n", data_len_raw);
				
				uint8_t start = __HEADEROFFSETBITS / 8;
				uint8_t shift = __HEADEROFFSETBITS % 8;

				// copy message data, using __HEADEROFFSETBITS value and string_offset_data
				for (i = 0; i < data_len_raw; i++)
				{
					uint8_t val = hex_to_uint8((uint8_t *)cmdbuf, string_offset_data + 2 * i + 1);
					array_write_UIntValue(start + i, shift, 8, val, bufx);
				}
			}
			
			// round packet length to x * 16 bytes
			uint8_t packet_len = ((uint16_t)__HEADEROFFSETBITS + (uint16_t)data_len_raw * 8) / 8;
			packet_len = ((packet_len - 1) / 16 + 1) * 16;

			// send packet which doesn't require an acknowledge immediately
			if ((message_type != MESSAGETYPE_GET) && (message_type != MESSAGETYPE_SET) && (message_type != MESSAGETYPE_SETGET))
			{
				send_packet(aes_key_nr, packet_len);
			}
			else // enqueue request (don't send immediately)
			{
				// header size = 9 bytes!
				if (queue_request(pkg_headerext_common_get_receiverid(), message_type, aes_key_nr, bufx + 9, packet_len - 9))
				{
					UART_PUTF("Request added to queue (%u bytes packet).\r\n", packet_len);
				}
				else
				{
					UART_PUTS("Warning! Request queue full. Packet will not be sent.\r\n");
				}

				print_request_queue();
			}
		
			// clear cmdbuf to receive more input from UART
			send_data_avail = false;

			rfm12_tick();

			led_blink(200, 0, 1);
		}

		// flash LED every second to show the device is alive
		if (loop == 50)
		{
			led_blink(10, 10, 1);
			
			loop = 0;
			
			request_t* request = find_request_to_repeat(packetcounter + 1);

			if (request != 0) // if request to repeat was found in queue
			{
				UART_PUTS("Repeating request.\r\n");					
				send_packet((*request).aes_key, (*request).data_bytes + 9); // header size = 9 bytes!
				print_request_queue();
			}
			
			// Auto-send something for debugging purposes...
			if (loop2 == 50)
			{
				//strcpy(cmdbuf, "s000102828300");
				//send_data_avail = true;
				
				loop2 = 0;
			}
			else
			{
				loop2++;
			}
		}
		else
		{
			_delay_ms(20);
		}

		rfm12_tick();

		loop++;
		
		process_rxbuf();
		
		if (uart_timeout > 0)
		{
			uart_timeout--;
			
			if (uart_timeout == 0)
			{
				UART_PUTS("*** UART user timeout. Input was ignored. ***\r\n");
			}
		}
	}
	
	// never called
	// aes256_done(&aes_ctx);
}
Example #16
0
// Process all bytes in the UART RX ringbuffer ("rxbuf"). This function should be called in the
// main loop. It can be interrupted by a UART RX interrupt, so additional bytes can be added
// into the ringbuffer while this function is running.
void process_rxbuf(void)
{
	// Only process characters if the cmdbuf is clear to be overwritten.
	// If not, wait for the main loop to clear it by processing the user "send" command.	
	if (send_data_avail)
	{
		return;
	}
	
	while (rxbuf_count > 0)
	{
		char input;
		
		// get one char from the ringbuffer and reduce its size without interruption through the UART ISR
		cli();
		input = rxbuf[rxbuf_startpos];
		rxbuf_startpos = (rxbuf_startpos + 1) % RXBUF_LENGTH;
		rxbuf_count--;
		sei();
		
		// process character	
		if (uart_timeout == 0)
		{
			bytes_to_read = bytes_pos = 0;
		}
		
		if (bytes_to_read > bytes_pos)
		{
			if (input == 13)
			{
				bytes_to_read = bytes_pos;
			}
			else if (((input >= 48) && (input <= 57)) || ((input >= 65) && (input <= 70)) || ((input >= 97) && (input <= 102)))
			{
				cmdbuf[bytes_pos] = input;
				bytes_pos++;
				UART_PUTF("*** 0x%x\r\n", hex_to_byte(input));
			}
			else
			{
				UART_PUTS("*** Illegal character. Use only 0..9, a..f, A..F. ***\r\n");
			}
			
			if (bytes_pos == bytes_to_read)
			{
				cmdbuf[bytes_pos] = '\0';
				//led_dbg(1);
				process_cmd();
			}
		}	
		else if (input == 'h')
		{
			UART_PUTS("*** Help ***\r\n");
			UART_PUTS("h..............this help\r\n");
			UART_PUTS("rAA............read EEPROM at hex address AA\r\n");
			UART_PUTS("wAAXX..........write EEPROM at hex address AA to hex value XX\r\n");
			UART_PUTS("x..............enable writing to EEPROM\r\n");
			UART_PUTS("z..............disable writing to EEPROM\r\n");
			UART_PUTS("sKKTT{D}.......Use AES key KK to send a packet with MessageType TT, followed\r\n");
			UART_PUTS("               by all necessary extension header fields and message data D.\r\n");
			UART_PUTS("               Fields are: ReceiverID (RRRR), MessageGroup (GG), MessageID (MM)\r\n");
			UART_PUTS("               AckSenderID (SSSS), AckPacketCounter (PPPPPP), Error (EE).\r\n");
			UART_PUTS("               MessageData (DD) can be 0..17 bytes with bits moved to the left.\r\n");
			UART_PUTS("               End data with ENTER. SenderID, PacketCounter and CRC are automatically added.\r\n");
			UART_PUTS("sKK00RRRRGGMMDD...........Get\r\n");
			UART_PUTS("sKK01RRRRGGMMDD...........Set\r\n");
			UART_PUTS("sKK02RRRRGGMMDD...........SetGet\r\n");
			UART_PUTS("sKK08GGMMDD...............Status\r\n");
			UART_PUTS("sKK09SSSSPPPPPPEE.........Ack\r\n");
			UART_PUTS("sKK0ASSSSPPPPPPEEGGMMDD...AckStatus\r\n");
			UART_PUTS("cKKTT{D}{CRC}..Same as s..., but a CRC32 checksum of the command has to be appended.\r\n");
			UART_PUTS("               If it doesn't match, the command is ignored.\r\n");
		}
		else if (input == 'x')
		{
			enable_write_eeprom = true;
			UART_PUTS("*** Writing to EEPROM is now ENABLED. ***\r\n");
		}
		else if (input == 'z')
		{
			enable_write_eeprom = false;
			UART_PUTS("*** Writing to EEPROM is now DISABLED. ***\r\n");
		}
		else if (input == 'r')
		{
			UART_PUTS("*** Read from EEPROM. Enter address (2 characters). ***\r\n");
			cmdbuf[0] = 'r';
			bytes_to_read = 3;
			bytes_pos = 1;
		}
		else if (input == 'w')
		{
			UART_PUTS("*** Write to EEPROM. Enter address and data (4 characters). ***\r\n");
			cmdbuf[0] = 'w';
			bytes_to_read = 5;
			bytes_pos = 1;
		}
		else if (input == 's')
		{
			UART_PUTS("*** Enter data, finish with ENTER. ***\r\n");
			cmdbuf[0] = 's';
			bytes_to_read = 54; // 2 characters for key nr + 2 characters for MessageType + 16 characters for hdr.ext. + 2*17 characters for data
			bytes_pos = 1;
		}
		else if (input == 'c')
		{
			UART_PUTS("*** Enter data, finish with ENTER. ***\r\n");
			cmdbuf[0] = 'c';
			bytes_to_read = 62; // 2 characters for key nr + 2 characters for MessageType + 16 characters for hdr.ext. + 2*17 characters for data + 8 characters for CRC
			bytes_pos = 1;
		}
		else
		{
			UART_PUTS("*** Character ignored. Press h for help. ***\r\n");
		}
		
		// enable user timeout if waiting for further input
		uart_timeout = bytes_to_read == bytes_pos ? 0 : 255;
	}
}
Example #17
0
int main(void)
{
	uint16_t send_status_timeout = 25;
	uint32_t pos;
	uint8_t button_state = 0;
	uint8_t manual_dim_direction = 0;

	// delay 1s to avoid further communication with uart or RFM12 when my programmer resets the MC after 500ms...
	_delay_ms(1000);

	util_init();
	
	check_eeprom_compatibility(DEVICETYPE_DIMMER);
	
	// read packetcounter, increase by cycle and write back
	packetcounter = e2p_generic_get_packetcounter() + PACKET_COUNTER_WRITE_CYCLE;
	e2p_generic_set_packetcounter(packetcounter);

	// read device id
	device_id = e2p_generic_get_deviceid();

	// pwm translation table is not used if first byte is 0xFF
	use_pwm_translation = (0xFF != eeprom_read_UIntValue8(EEPROM_BRIGHTNESSTRANSLATIONTABLE_BYTE,
		EEPROM_BRIGHTNESSTRANSLATIONTABLE_BIT, 8, 0, 0xFF));
	
	// TODO: read (saved) dimmer state from before the eventual powerloss
	/*for (i = 0; i < SWITCH_COUNT; i++)
	{
		uint16_t u16 = eeprom_read_word((uint16_t*)EEPROM_POS_SWITCH_STATE + i * 2);
		switch_state[i] = (uint8_t)(u16 & 0b1);
		switch_timeout[i] = u16 >> 1;
	}*/
	
	// read last received station packetcounter
	station_packetcounter = e2p_dimmer_get_basestationpacketcounter();
	
	led_blink(500, 500, 3);

	osccal_init();

	uart_init();
	UART_PUTS ("\r\n");
	UART_PUTF4("smarthomatic Dimmer v%u.%u.%u (%08lx)\r\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_HASH);
	UART_PUTS("(c) 2013..2014 Uwe Freese, www.smarthomatic.org\r\n");
	osccal_info();
	UART_PUTF ("DeviceID: %u\r\n", device_id);
	UART_PUTF ("PacketCounter: %lu\r\n", packetcounter);
	UART_PUTF ("Use PWM translation table: %u\r\n", use_pwm_translation);
	UART_PUTF ("Last received base station PacketCounter: %u\r\n\r\n", station_packetcounter);

	// init AES key
	eeprom_read_block (aes_key, (uint8_t *)EEPROM_AESKEY_BYTE, 32);

	rfm12_init();
	PWM_init();
	io_init();
	setPWMDutyCyclePercent(0);
	timer0_init();

	// DEMO to measure the voltages of different PWM settings to calculate the pwm_lookup table
	/*while (42)
	{
		uint16_t i;
		
		for (i = 0; i <= 1024; i = i + 100)
		{
			UART_PUTF ("PWM value OCR1A: %u\r\n", i);
			OCR1A = i;
			led_blink(500, 6500, 1);
		}
	}*/
	
	// DEMO 0..100..0%, using the pwm_lookup table and the translation table in EEPROM.
	/*while (42)
	{
		float i;
		
		for (i = 0; i <= 100; i = i + 0.05)
		{
			led_blink(10, 10, 1);
			setPWMDutyCycle(i);
		}
		
		for (i = 99.95; i > 0; i = i - 0.05)
		{
			led_blink(10, 10, 1);
			setPWMDutyCycle(i);
		}
	}*/

	// set initial switch state
	/*for (i = 0; i < SWITCH_COUNT; i++)
	{
		switchRelais(i, switch_state[i]);
	}*/

	sei();

	// DEMO 30s
	/*animation_length = 30;
	animation_length = (uint32_t)((float)animation_length * 1000 / ANIMATION_CYCLE_MS);
	start_brightness = 0;
	end_brightness = 255;
	animation_position = 0;*/
	
	while (42)
	{
		if (rfm12_rx_status() == STATUS_COMPLETE)
		{
			uint8_t len = rfm12_rx_len();
			
			if ((len == 0) || (len % 16 != 0))
			{
				UART_PUTF("Received garbage (%u bytes not multiple of 16): ", len);
				print_bytearray(bufx, len);
			}
			else // try to decrypt with all keys stored in EEPROM
			{
				memcpy(bufx, rfm12_rx_buffer(), len);
				
				UART_PUTS("Before decryption: ");
				print_bytearray(bufx, len);
					
				aes256_decrypt_cbc(bufx, len);

				UART_PUTS("Decrypted bytes: ");
				print_bytearray(bufx, len);
				
				if (!pkg_header_check_crc32(len))
				{
					UART_PUTS("Received garbage (CRC wrong after decryption).\r\n");
				}
				else
				{
					process_packet(len);
				}		
			}

			// tell the implementation that the buffer can be reused for the next data.
			rfm12_rx_clear();
		}

		_delay_ms(ANIMATION_UPDATE_MS);
		
		// React on button press.
		// - abort animation
		// - switch off, when brightness > 0
		// - switch on otherwise
		if (!(BUTTON_PORT & (1 << BUTTON_PIN))) // button press
		{
			if (button_state == 0)
			{
				UART_PUTS("Button pressed\r\n");
				animation_length = 0;
				animation_position = 0;
			}
			
			if (button_state < 5)
			{
				button_state++;
			}
			else // manual dimming
			{
				if (manual_dim_direction) // UP
				{
					if (current_brightness < 100)
					{
						current_brightness = (uint8_t)current_brightness / 2 * 2 + 2;
						setPWMDutyCyclePercent(current_brightness);
					}
					else
					{
						UART_PUTS("manual dimming DOWN\r\n");
						manual_dim_direction = 0;
					}
				}
				else // DOWN
				{
					if (current_brightness > 0)
					{
						current_brightness = (((uint8_t)current_brightness - 1) / 2) * 2;
						setPWMDutyCyclePercent(current_brightness);
					}
					else
					{
						UART_PUTS("manual dimming UP\r\n");
						manual_dim_direction = 1;
					}
				}
				
			}
		}
		else if (button_state && (BUTTON_PORT & (1 << BUTTON_PIN))) // button release
		{
			UART_PUTS("Button released\r\n");
			
			if (button_state < 5) // short button press
			{
				if (current_brightness > 0)
				{
					UART_PUTS(" -> 0%\r\n");
					setPWMDutyCyclePercent(0);
				}
				else
				{
					UART_PUTS(" -> 100%\r\n");
					setPWMDutyCyclePercent(100);
				}
			}
			else
			{
				// reverse dim direction
				manual_dim_direction = !manual_dim_direction;
			}
			
			button_state = 0;
		}
				
		// update brightness according animation_position, updated by timer0
		if (animation_length > 0)
		{
			pos = animation_position; // copy value to avoid that it changes in between by timer interrupt
			UART_PUTF2("%lu/%lu, ", pos, animation_length);
			
			if (pos == animation_length)
			{
				UART_PUTF("END Brightness %u%%, ", end_brightness);
				setPWMDutyCyclePercent((float)end_brightness);
				animation_length = 0;
				animation_position = 0;
			}
			else
			{			
				float brightness = (start_brightness + ((float)end_brightness - start_brightness) * pos / animation_length);
				UART_PUTF("Br.%u%%, ", (uint32_t)(brightness));
				setPWMDutyCyclePercent(brightness);
			}
		}			
		
		// send status from time to time
		if (send_status_timeout == 0)
		{
			send_status_timeout = SEND_STATUS_EVERY_SEC * (1000 / ANIMATION_UPDATE_MS);
			send_dimmer_status();
			led_blink(200, 0, 1);
		}
		else if (version_status_cycle >= SEND_VERSION_STATUS_CYCLE)
		{
			version_status_cycle = 0;
			send_version_status();
			led_blink(200, 0, 1);
		}

		rfm12_tick();
		send_status_timeout--;
		checkSwitchOff();
	}
	
	// never called
	// aes256_done(&aes_ctx);
}
Example #18
0
int main ( void )
{
	uint8_t aes_key_nr;
	uint8_t loop = 0;
	uint8_t loop2 = 0;
	
	uint8_t data[22];

	sbi(LED_DDR, LED_PIN);

	// delay 1s to avoid further communication with uart or RFM12 when my programmer resets the MC after 500ms...
	_delay_ms(1000);

	request_queue_init();
	
	// read packetcounter, increase by cycle and write back
	packetcounter = eeprom_read_dword((uint32_t*)EEPROM_POS_PACKET_COUNTER) + PACKET_COUNTER_WRITE_CYCLE;
	eeprom_write_dword((uint32_t*)0, packetcounter);

	uart_init(true);
	UART_PUTS ("\r\n");
	UART_PUTS ("Open Home Control Base Station V1.0\r\n");
	UART_PUTS ("(c) 2012 Uwe Freese, www.open-home-control.com\r\n");
	UART_PUTF ("Packet counter: %lu\r\n", packetcounter);
	UART_PUTS ("Waiting for incoming data. Press h for help.\r\n");

	rfm12_init();
	sei();
	
	// ENCODE TEST
	/*
	uint8_t testlen = 64;
	
	eeprom_read_block (aes_key, (uint8_t *)EEPROM_POS_AES_KEY, 32);
	UART_PUTS("Using AES key ");
	printbytearray((uint8_t *)aes_key, 32);
			
	UART_PUTS("Before encryption: ");
	printbytearray(bufx, testlen);
  
	unsigned long crc = crc32(bufx, testlen);
	UART_PUTF("CRC32 is %lx (added as last 4 bytes)\r\n", crc);
	
	UART_PUTS("1\r\n");
	crc = crc32(bufx, testlen - 4);
	UART_PUTS("2\r\n");
	setBuf32(testlen - 4, crc);
	
	UART_PUTS("Before encryption (CRC added): ");
	printbytearray(bufx, testlen);

	UART_PUTS("1\r\n");
	uint8_t aes_byte_count = aes256_encrypt_cbc(bufx, testlen);
	UART_PUTS("2\r\n");
  
	UART_PUTS("After encryption: ");
	printbytearray(bufx, aes_byte_count);
	
	UART_PUTF("String len = %u\r\n", aes_byte_count);
	
	UART_PUTS("1\r\n");
	aes256_decrypt_cbc(bufx, aes_byte_count);
	UART_PUTS("2\r\n");
  
	UART_PUTS("After decryption: ");
	printbytearray(bufx, testlen);
	
	crc = getBuf32(testlen - 4);
	UART_PUTF("CRC32 is %lx (last 4 bytes from decrypted message)\r\n", crc);
	printbytearray(bufx, testlen);
	
	UART_PUTS("After decryption (CRC removed): ");
	printbytearray(bufx, testlen);
	
	UART_PUTF("String len = %u\r\n", testlen);
  
	while(1);
	*/

	while (42)
	{
		if (rfm12_rx_status() == STATUS_COMPLETE)
		{
			uint8_t len = rfm12_rx_len();
			
			if ((len == 0) || (len % 16 != 0))
			{
				UART_PUTF("Received garbage (%u bytes not multiple of 16): ", len);
				printbytearray(bufx, len);
			}
			else // try to decrypt with all keys stored in EEPROM
			{
				uint32_t assumed_crc;
				uint32_t actual_crc;

				for(aes_key_nr = 0; aes_key_nr < AES_KEY_EEPROM_COUNT ; aes_key_nr++)
				{
					//strncpy((char *)bufx, (char *)rfm12_rx_buffer(), len);
					memcpy(bufx, rfm12_rx_buffer(), len);

					/*if (aes_key_nr == 0)
					{
						UART_PUTS("Before decryption: ");
						printbytearray(bufx, len);
					}*/
				
					eeprom_read_block (aes_key, (uint8_t *)(EEPROM_POS_AES_KEY + aes_key_nr * 32), 32);
					//UART_PUTS("Trying AES key ");
					//printbytearray((uint8_t *)aes_key, 32);

					aes256_decrypt_cbc(bufx, len);

					//UART_PUTS("Decrypted bytes: ");
					//printbytearray(bufx, len);

					assumed_crc = getBuf32(len - 4);
					actual_crc = crc32(bufx, len - 4);
					
					//UART_PUTF("Received CRC32 would be %lx\r\n", assumed_crc);
					//UART_PUTF("Re-calculated CRC32 is  %lx\r\n", actual_crc);
					
					if (assumed_crc == actual_crc)
					{
						//UART_PUTS("CRC correct, AES key found!\r\n");
						UART_PUTF("Received (AES key %u): ", aes_key_nr);
						printbytearray(bufx, len - 4);
						
						decode_data(len - 4);
						
						break;
					}
				}
				
				if (assumed_crc != actual_crc)
				{
					UART_PUTS("Received garbage (CRC wrong after decryption).\r\n");
				}
				
				UART_PUTS("\r\n");
			}

			//uart_hexdump((char *)bufcontents, rfm12_rx_len());
			//UART_PUTS("\r\n");

			// tell the implementation that the buffer can be reused for the next data.
			rfm12_rx_clear();
		}

		// send data, if waiting in send buffer
		if (send_data_avail)
		{
			uint8_t i;
			
			uint8_t data_len_raw = strlen(sendbuf) / 2 - 2;
			
			// round data length to 6 + 16 bytes (including padding bytes)
			uint8_t data_len = (((data_len_raw + 9) / 16) + 1) * 16 - 10;
	
			// set aes key nr
			aes_key_nr = hex_to_uint8((uint8_t *)sendbuf, 0);
			
			//UART_PUTF("AES KEY = %u\r\n", aes_key_nr);

			// set command id
			uint8_t command_id = hex_to_uint8((uint8_t *)sendbuf, 2);

			// set data
			for (i = 0; i < data_len_raw; i++)
			{
				data[i] = hex_to_uint8((uint8_t *)sendbuf, 4 + 2 * i);
			}
			
			// set padding bytes
			for (i = data_len_raw; i < data_len; i++)
			{
				data[i] = 0;
			}

			// send status packet immediately (command IDs are less than 128)
			if (command_id < 128)
			{
				// set command id
				bufx[5] = command_id;
				
				// set data
				memcpy(bufx + 6, data, data_len);
				
				send_packet(aes_key_nr, data_len);
			}
			else // enqueue request (don't send immediately)
			{
				if (queue_request(data[0], command_id, aes_key_nr, data + 1))
				{
					UART_PUTS("Adding request to queue.\r\n");
				}
				else
				{
					UART_PUTS("Warning! Request queue full. Packet will not be sent.\r\n");
				}

				print_request_queue();
			}
		
			// clear send text buffer
			send_data_avail = false;

			rfm12_tick();

			led_blink(200, 0, 1);
		}

		// flash LED every second to show the device is alive
		if (loop == 50)
		{
			led_blink(10, 10, 1);
			
			loop = 0;

			if (set_repeat_request(packetcounter + 1)) // if request to repeat was found in queue
			{
				UART_PUTS("Repeating request.\r\n");					
				send_packet(0, 6);
				print_request_queue();
			}
			
			// Auto-send something for debugging purposes...
			if (loop2 == 50)
			{
				//strcpy(sendbuf, "008c0001003d");
				//send_data_avail = true;
				
				loop2 = 0;
			}
			else
			{
				loop2++;
			}
		}
		else
		{
			_delay_ms(20);
		}

		rfm12_tick();

		loop++;
		
		process_rxbuf();
		
		if (uart_timeout > 0)
		{
			uart_timeout--;
			
			if (uart_timeout == 0)
			{
				UART_PUTS("*** UART user timeout. Input was ignored. ***\r\n");
			}
		}
	}
	
	// never called
	// aes256_done(&aes_ctx);
}
Example #19
0
// Process all bytes in the rxbuffer. This function should be called in the main loop.
// It can be interrupted by a UART RX interrupt, so additional bytes can be added into the ringbuffer while this function is running.
void process_rxbuf(void)
{
	while (rxbuf_count > 0)
	{
		char input;
		
		// get one char from the ringbuffer and reduce it's size without interruption through the UART ISR
		cli();
		input = rxbuf[rxbuf_startpos];
		rxbuf_startpos = (rxbuf_startpos + 1) % RXBUF_LENGTH;
		rxbuf_count--;
		sei();
		
		// process character	
		if (uart_timeout == 0)
		{
			bytes_to_read = bytes_pos = 0;
		}
		
		if (bytes_to_read > bytes_pos)
		{
			if (input == 13)
			{
				bytes_to_read = bytes_pos;
			}
			else if (((input >= 48) && (input <= 57)) || ((input >= 65) && (input <= 70)) || ((input >= 97) && (input <= 102)))
			{
				cmdbuf[bytes_pos] = input;
				bytes_pos++;
				UART_PUTF4("*** Received character %c (ASCII %u) = value 0x%x, %u bytes to go. ***\r\n", input, input, hex_to_byte(input), bytes_to_read - bytes_pos);
			}
			else
			{
				UART_PUTS("*** Illegal character. Use only 0..9, a..f, A..F. ***\r\n");
			}
			
			if (bytes_pos == bytes_to_read)
			{
				cmdbuf[bytes_pos] = '\0';
				process_cmd();
			}
		}	
		else if (input == 'h')
		{
			UART_PUTS("*** Help ***\r\n");
			UART_PUTS("h.........this help\r\n");
			UART_PUTS("rAA.......read EEPROM at hex address AA\r\n");
			UART_PUTS("wAAXX.....write EEPROM at hex address AA to hex value XX\r\n");
			UART_PUTS("x.........enable writing to EEPROM\r\n");
			UART_PUTS("z.........disable writing to EEPROM\r\n");
			UART_PUTS("sKKCCXX...Use AES key KK to send a packet with command ID CC and data XX (0..22 bytes).\r\n");
			UART_PUTS("          End data with ENTER. Packet number and CRC are automatically added.\r\n");
		}
		else if (input == 'x')
		{
			enable_write_eeprom = true;
			UART_PUTS("*** Writing to EEPROM is now ENABLED. ***\r\n");
		}
		else if (input == 'z')
		{
			enable_write_eeprom = false;
			UART_PUTS("*** Writing to EEPROM is now DISABLED. ***\r\n");
		}
		else if (input == 'r')
		{
			UART_PUTS("*** Read from EEPROM. Enter address (2 characters). ***\r\n");
			cmdbuf[0] = 'r';
			bytes_to_read = 3;
			bytes_pos = 1;
		}
		else if (input == 'w')
		{
			UART_PUTS("*** Write to EEPROM. Enter address and data (4 characters). ***\r\n");
			cmdbuf[0] = 'w';
			bytes_to_read = 5;
			bytes_pos = 1;
		}
		else if (input == 's')
		{
			UART_PUTS("*** Enter AES key nr, command ID and data in hex format to send, finish with ENTER. ***\r\n");
			cmdbuf[0] = 's';
			bytes_to_read = 49; // 's' + 2 characters for key nr + 2 characters for command ID + 2*22 characters for data
			bytes_pos = 1;
		}
		else
		{
			UART_PUTS("*** Character ignored. Press h for help. ***\r\n");
		}
		
		// enable user timeout if waiting for further input
		uart_timeout = bytes_to_read == bytes_pos ? 0 : 255;
	}
}
Example #20
0
// Show info about the received packets.
// This is only for debugging. The definition of all packets must be known at the PC program
// that's processing the data.
void decode_data(uint8_t len)
{
	uint16_t u16;
	int16_t s16;
	uint32_t u32;	

	UART_PUTF("Sender ID=%u;", bufx[0]);
	UART_PUTF("Packet Counter=%lu;", getBuf32(1));
	uint8_t cmd = bufx[5];
	UART_PUTF("Command ID=%u;", cmd);

	switch (cmd)
	{
		case 1: // Generic Acknowledge
			u32 = getBuf32(7);
			UART_PUTS("Command Name=Generic Acknowledge;");
			UART_PUTF("Request Sender ID=%u;", bufx[6]);
			UART_PUTF("Request Packet Counter=%lu\r\n", u32);
			remove_request(bufx[0], bufx[6], u32);
			break;

		case 10: // Temperature Sensor Status
			UART_PUTS("Command Name=Temperature Sensor Status;");
			s16 = (int16_t)getBuf16(7);
			UART_PUTF("Battery=%u;", bufx[6]);
			UART_PUTS("Temperature=");
			printSigned(s16);
			u16 = getBuf16(9);
			UART_PUTF2("Humidity=%u.%02u;", u16 / 100, u16 % 100);
			UART_PUTF("Brightness=%u", bufx[11]);
			break;
			
		case 20: // Power Switch Status
			UART_PUTS("Command Name=Power Switch Status");
			print_switch_state(3);
			break;

		case 21: // Power Switch Status Extended
			UART_PUTS("Command Name=Power Switch Status Extended");
			print_switch_state(8);
			break;

		case 30: // DateTime Status
			UART_PUTS("Command Name=DateTime Status;");
			UART_PUTF3("Date=%u-%02u-%02u;", bufx[6] + 2000, bufx[7], bufx[8]);
			UART_PUTF3("Time=%02u:%02u:%02u", bufx[9], bufx[10], bufx[11]);
			break;
		
		case 140: // Power Switch Request
			UART_PUTS("Command Name=Power Switch Request;");
			uint16_t u16 = getBuf16(8);
			UART_PUTF("Receiver ID=%u;", bufx[6]);
			UART_PUTF("Switch Bitmask=%u;", bufx[7]); // TODO: Set binary mode like 00010110
			UART_PUTF("Requested State=%u;", u16 & 0b1);
			UART_PUTF("Timeout=%u", u16 >> 1);
			break;
			
		case 141: // Dimmer Request
			UART_PUTS("Command Name=Dimmer Request;");
			UART_PUTF("Receiver ID=%u;", bufx[6]);
			UART_PUTF("Animation Mode=%u;", bufx[7] >> 5);
			UART_PUTF("Dimmer Bitmask=%u;", bufx[7] & 0b111);
			UART_PUTF("Timeout=%u;", getBuf16(8));
			UART_PUTF("Start Brightness=%u;", bufx[10]);
			UART_PUTF("End Brightness=%u", bufx[11]);
			break;
			
		default:
			UART_PUTS("Command Name=Unknown;");
			UART_PUTS("Data=");
			printbytearray(bufx + 6, len - 6);
	}

	if (cmd != 1)
	{
		UART_PUTS("\r\n");
	}
}
Example #21
0
void process_packet(uint8_t len)
{
	pkg_header_adjust_offset();

	UART_PUTS("Received: ");
	print_bytearray(bufx, len);
	
	// check SenderID
	uint32_t senderID = pkg_header_get_senderid();
	UART_PUTF("SenderID:%u;", senderID);
	
	if (senderID != 0)
	{
		UART_PUTS("\r\nERR: Illegal SenderID.\r\n");
		return;
	}

	// check PacketCounter
	// TODO: Reject if packet counter lower than remembered!!
	uint32_t packcnt = pkg_header_get_packetcounter();
	UART_PUTF("PacketCounter:%lu;", packcnt);

	if (0) // packcnt <= station_packetcounter ??
	{
		UART_PUTF("\r\nERR: Received PacketCounter < %lu.\r\n", station_packetcounter);
		return;
	}
	
	// write received counter
	station_packetcounter = packcnt;
	
	e2p_dimmer_set_basestationpacketcounter(station_packetcounter);
	
	// check MessageType
	MessageTypeEnum messagetype = pkg_header_get_messagetype();
	UART_PUTF("MessageType:%u;", messagetype);
	
	if ((messagetype != MESSAGETYPE_GET) && (messagetype != MESSAGETYPE_SET) && (messagetype != MESSAGETYPE_SETGET))
	{
		UART_PUTS("\r\nERR: Unsupported MessageType.\r\n");
		return;
	}
	
	// check device id
	uint8_t rcv_id = pkg_headerext_common_get_receiverid();

	UART_PUTF("ReceiverID:%u;", rcv_id);
	
	if (rcv_id != device_id)
	{
		UART_PUTS("\r\nWRN: DeviceID does not match.\r\n");
		return;
	}
	
	// check MessageGroup + MessageID
	uint32_t messagegroupid = pkg_headerext_common_get_messagegroupid();
	uint32_t messageid = pkg_headerext_common_get_messageid();
	
	UART_PUTF("MessageGroupID:%u;", messagegroupid);
	
	if (messagegroupid != MESSAGEGROUP_DIMMER)
	{
		UART_PUTS("\r\nERR: Unsupported MessageGroupID.\r\n");
		return;
	}
	
	UART_PUTF("MessageID:%u;", messageid);

	switch (messageid)
	{
		case MESSAGEID_DIMMER_BRIGHTNESS:
			process_brightness(messagetype);
			break;
		case MESSAGEID_DIMMER_ANIMATION:
			process_animation(messagetype);
			break;
		default:
			UART_PUTS("\r\nERR: Unsupported MessageID.\r\n");
			break;
	}
}
Example #22
0
int main(void)
{
	uint16_t send_status_timeout = 25;
	uint32_t station_packetcounter;
	uint32_t pos;
	uint8_t button_state = 0;
	uint8_t manual_dim_direction = 0;

	// delay 1s to avoid further communication with uart or RFM12 when my programmer resets the MC after 500ms...
	_delay_ms(1000);

	util_init();
	check_eeprom_compatibility(DEVICE_TYPE_DIMMER);

	osccal_init();
	
	// read packetcounter, increase by cycle and write back
	packetcounter = eeprom_read_dword((uint32_t*)EEPROM_POS_PACKET_COUNTER) + PACKET_COUNTER_WRITE_CYCLE;
	eeprom_write_dword((uint32_t*)EEPROM_POS_PACKET_COUNTER, packetcounter);

	// read device id and write to send buffer
	device_id = eeprom_read_byte((uint8_t*)EEPROM_POS_DEVICE_ID);	
	use_pwm_translation = 1; //eeprom_read_byte((uint8_t*)EEPROM_POS_USE_PWM_TRANSLATION);	
	
	// TODO: read (saved) dimmer state from before the eventual powerloss
	/*for (i = 0; i < SWITCH_COUNT; i++)
	{
		uint16_t u16 = eeprom_read_word((uint16_t*)EEPROM_POS_SWITCH_STATE + i * 2);
		switch_state[i] = (uint8_t)(u16 & 0b1);
		switch_timeout[i] = u16 >> 1;
	}*/
	
	// read last received station packetcounter
	station_packetcounter = eeprom_read_dword((uint32_t*)EEPROM_POS_STATION_PACKET_COUNTER);

	led_blink(200, 200, 5);

#ifdef UART_DEBUG
	uart_init(false);
	UART_PUTS ("\r\n");
	UART_PUTS ("smarthomatic Dimmer V1.0 (c) 2013 Uwe Freese, www.smarthomatic.org\r\n");
	osccal_info();
	UART_PUTF ("Device ID: %u\r\n", device_id);
	UART_PUTF ("Packet counter: %lu\r\n", packetcounter);
	UART_PUTF ("Use PWM translation table: %u\r\n", use_pwm_translation);
	UART_PUTF ("Last received station packet counter: %u\r\n\r\n", station_packetcounter);
#endif

	// init AES key
	eeprom_read_block (aes_key, (uint8_t *)EEPROM_POS_AES_KEY, 32);

	rfm12_init();
	PWM_init();
	io_init();
	setPWMDutyCycle(0);
	timer0_init();

	// DEMO to measure the voltages of different PWM settings to calculate the pwm_lookup table
	/*while (42)
	{
		uint16_t i;
		
		for (i = 0; i <= 1024; i = i + 100)
		{
			UART_PUTF ("PWM value OCR1A: %u\r\n", i);
			OCR1A = i;
			led_blink(500, 6500, 1);
		}
	}*/
	
	// DEMO 0..100..0%, using the pwm_lookup table and the translation table in EEPROM.
	/*while (42)
	{
		float i;
		
		for (i = 0; i <= 100; i = i + 0.05)
		{
			led_blink(10, 10, 1);
			setPWMDutyCycle(i);
		}
		
		for (i = 99.95; i > 0; i = i - 0.05)
		{
			led_blink(10, 10, 1);
			setPWMDutyCycle(i);
		}
	}*/

	// set initial switch state
	/*for (i = 0; i < SWITCH_COUNT; i++)
	{
		switchRelais(i, switch_state[i]);
	}*/

	sei();

	// DEMO 30s
	/*animation_length = 30;
	animation_length = (uint32_t)((float)animation_length * 1000 / ANIMATION_CYCLE_MS);
	start_brightness = 0;
	end_brightness = 255;
	animation_position = 0;*/
	
	while (42)
	{
		if (rfm12_rx_status() == STATUS_COMPLETE)
		{
			uint8_t len = rfm12_rx_len();
			
			if ((len == 0) || (len % 16 != 0))
			{
				UART_PUTF("Received garbage (%u bytes not multiple of 16): ", len);
				printbytearray(bufx, len);
			}
			else // try to decrypt with all keys stored in EEPROM
			{
				memcpy(bufx, rfm12_rx_buffer(), len);
				
				//UART_PUTS("Before decryption: ");
				//printbytearray(bufx, len);
					
				aes256_decrypt_cbc(bufx, len);

				//UART_PUTS("Decrypted bytes: ");
				//printbytearray(bufx, len);

				uint32_t assumed_crc = getBuf32(len - 4);
				uint32_t actual_crc = crc32(bufx, len - 4);
				
				//UART_PUTF("Received CRC32 would be %lx\r\n", assumed_crc);
				//UART_PUTF("Re-calculated CRC32 is  %lx\r\n", actual_crc);
				
				if (assumed_crc != actual_crc)
				{
					UART_PUTS("Received garbage (CRC wrong after decryption).\r\n");
				}
				else
				{
					//UART_PUTS("CRC correct, AES key found!\r\n");
					UART_PUTS("         Received: ");
					printbytearray(bufx, len - 4);
					
					// decode command and react
					uint8_t sender = bufx[0];
					
					UART_PUTF("           Sender: %u\r\n", sender);
					
					if (sender != 0)
					{
						UART_PUTF("Packet not from base station. Ignoring (Sender ID was: %u).\r\n", sender);
					}
					else
					{
						uint32_t packcnt = getBuf32(1);

						UART_PUTF("   Packet Counter: %lu\r\n", packcnt);

						// check received counter
						if (0) //packcnt <= station_packetcounter)
						{
							UART_PUTF2("Received packet counter %lu is lower than last received counter %lu. Ignoring packet.\r\n", packcnt, station_packetcounter);
						}
						else
						{
							// write received counter
							station_packetcounter = packcnt;
							eeprom_write_dword((uint32_t*)EEPROM_POS_STATION_PACKET_COUNTER, station_packetcounter);
							
							// check command ID
							uint8_t cmd = bufx[5];

							UART_PUTF("       Command ID: %u\r\n", cmd);
							
							if (cmd != 141) // ID 141 == Dimmer Request
							{
								UART_PUTF("Received unknown command ID %u. Ignoring packet.\r\n", cmd);
							}
							else
							{
								// check device id
								uint8_t rcv_id = bufx[6];

								UART_PUTF("      Receiver ID: %u\r\n", rcv_id);
								
								if (rcv_id != device_id)
								{
									UART_PUTF("Device ID %u does not match. Ignoring packet.\r\n", rcv_id);
								}
								else
								{
									// read animation mode and parameters
									uint8_t animation_mode = bufx[7] >> 5;
									
									// TODO: Implement support for multiple dimmers (e.g. RGB)
									// uint8_t dimmer_bitmask = bufx[7] & 0b111;
									
									animation_length = getBuf16(8);
									start_brightness = bufx[10];
									end_brightness = bufx[11];

									UART_PUTF("   Animation Mode: %u\r\n", animation_mode); // TODO: Set binary mode like 00010110
									//UART_PUTF("   Dimmer Bitmask: %u\r\n", dimmer_bitmask);
									UART_PUTF("   Animation Time: %us\r\n", animation_length);
									UART_PUTF(" Start Brightness: %u\r\n", start_brightness);
									UART_PUTF("   End Brightness: %u\r\n", end_brightness);
									
									animation_length = (uint32_t)((float)animation_length * 1000 / ANIMATION_CYCLE_MS);
									animation_position = 0;
									
									/* TODO: Write to EEPROM (?)
									// write back switch state to EEPROM
									switch_state[i] = req_state;
									switch_timeout[i] = req_timeout;
									
									eeprom_write_word((uint16_t*)EEPROM_POS_SWITCH_STATE + i * 2, u16);
									
									*/
									
									// send acknowledge
									UART_PUTS("Sending ACK:\r\n");

									// set device ID (base station has ID 0 by definition)
									bufx[0] = device_id;
									
									// update packet counter
									packetcounter++;
									
									if (packetcounter % PACKET_COUNTER_WRITE_CYCLE == 0)
									{
										eeprom_write_dword((uint32_t*)0, packetcounter);
									}

									setBuf32(1, packetcounter);

									// set command ID "Generic Acknowledge"
									bufx[5] = 1;
									
									// set sender ID of request
									bufx[6] = sender;
									
									// set Packet counter of request
									setBuf32(7, station_packetcounter);

									// zero unused bytes
									bufx[11] = 0;
									
									// set CRC32
									uint32_t crc = crc32(bufx, 12);
									setBuf32(12, crc);

									// show info
									UART_PUTF("            CRC32: %lx\r\n", crc);
									uart_putstr("      Unencrypted: ");
									printbytearray(bufx, 16);

									rfm12_sendbuf();
									
									UART_PUTS("   Send encrypted: ");
									printbytearray(bufx, 16);
									UART_PUTS("\r\n");
								
									rfm12_tick();
									
									led_blink(200, 0, 1);
									
									send_status_timeout = 25;
								}
							}
						}
					}
				}
				
			}

			// tell the implementation that the buffer can be reused for the next data.
			rfm12_rx_clear();
		}

		_delay_ms(ANIMATION_UPDATE_MS);
		
		// React on button press.
		// - abort animation
		// - switch off, when brightness > 0
		// - switch on otherwise
		if (!(BUTTON_PORT & (1 << BUTTON_PIN))) // button press
		{
			if (button_state == 0)
			{
				UART_PUTS("Button pressed\r\n");
				animation_length = 0;
				animation_position = 0;
			}
			
			if (button_state < 5)
			{
				button_state++;
			}
			else // manual dimming
			{
				if (manual_dim_direction) // UP
				{
					if (current_brightness < 100)
					{
						current_brightness = (uint8_t)current_brightness / 2 * 2 + 2;
						setPWMDutyCycle(current_brightness);
					}
					else
					{
						UART_PUTS("manual dimming DOWN\r\n");
						manual_dim_direction = 0;
					}
				}
				else // DOWN
				{
					if (current_brightness > 0)
					{
						current_brightness = (((uint8_t)current_brightness - 1) / 2) * 2;
						setPWMDutyCycle(current_brightness);
					}
					else
					{
						UART_PUTS("manual dimming UP\r\n");
						manual_dim_direction = 1;
					}
				}
				
			}
		}
		else if (button_state && (BUTTON_PORT & (1 << BUTTON_PIN))) // button release
		{
			UART_PUTS("Button released\r\n");
			
			if (button_state < 5) // short button press
			{
				if (current_brightness > 0)
				{
					UART_PUTS(" -> 0%\r\n");
					setPWMDutyCycle(0);
				}
				else
				{
					UART_PUTS(" -> 100%\r\n");
					setPWMDutyCycle(100);
				}
			}
			else
			{
				// reverse dim direction
				manual_dim_direction = !manual_dim_direction;
			}
			
			button_state = 0;
		}
				
		// update brightness according animation_position, updated by timer0
		if (animation_length > 0)
		{
			pos = animation_position; // copy value to avoid that it changes in between by timer interrupt
			UART_PUTF2("%lu/%lu, ", pos, animation_length);
			
			if (pos == animation_length)
			{
				UART_PUTF("END Brightness %u%%, ", end_brightness * 100 / 255);
				setPWMDutyCycle((float)end_brightness * 100 / 255);
				animation_length = 0;
				animation_position = 0;
			}
			else
			{			
				float brightness = (start_brightness + ((float)end_brightness - start_brightness) * pos / animation_length) * 100 / 255;
				UART_PUTF("Br.%u%%, ", (uint32_t)(brightness));
				setPWMDutyCycle(brightness);
			}
		}			
		
		// send status from time to time
		if (send_status_timeout == 0)
		{
			send_status_timeout = SEND_STATUS_EVERY_SEC * (1000 / ANIMATION_UPDATE_MS);
			send_dimmer_status();
			led_blink(200, 0, 1);
		}

		rfm12_tick();
		send_status_timeout--;
		checkSwitchOff();
	}
Example #23
0
// Process the user command now contained in the cmdbuf array.
void process_cmd(void)
{
	uart_putstr("Processing command: ");
	uart_putstr(cmdbuf);
	UART_PUTS("\r\n");
	
	if ((cmdbuf[0] == 'w') && (strlen(cmdbuf) == 5)) // E2P write command
	{
		if (enable_write_eeprom)
		{
			uint16_t adr = hex_to_uint8((uint8_t *)cmdbuf, 1);
			uint8_t val = hex_to_uint8((uint8_t *)cmdbuf, 3);
			UART_PUTF2("Writing data 0x%x to EEPROM pos 0x%x.\r\n", val, adr);
			eeprom_write_byte((uint8_t *)adr, val);
		}
		else
		{
			UART_PUTS("Ignoring EEPROM write, since write mode is DISABLED.\r\n");
		}
	}
	else if ((cmdbuf[0] == 'r') && (strlen(cmdbuf) == 3)) // E2P read command
	{
		uint16_t adr = hex_to_uint8((uint8_t *)cmdbuf, 1);
		uint8_t val = eeprom_read_byte((uint8_t *)adr);
		UART_PUTF2("EEPROM value at position 0x%x is 0x%x.\r\n", adr, val);
	}
	else if ((cmdbuf[0] == 's') && (strlen(cmdbuf) > 6)) // "send" command
	{
		send_data_avail = true;
	}
	else if ((cmdbuf[0] == 'c') && (strlen(cmdbuf) > 14)) // "send" command with CRC
	{
		uint8_t len = strlen(cmdbuf);
		
		// Warning! The following two lines were originally in the reverse order.
		// This obviously should not change anything.
		// But the "avr-gcc (GCC) 4.7.2" on my linux machine produced a firmware
		// which resulted in a wrong "calculated_crc" (whereas the
		// "avr-gcc (WinAVR 20100110) 4.3.3" on my Windows machine didn't).
		// I could recalculate the calculated_crc a 2nd time, call a UART_PUTS
		// or some other commands, which all produced a firmware which did not
		// have this issue. It's unknown why the GCC 4.7.2 produced this
		// wrong output.
		// Current workaround: I reversed the following two lines.

		uint32_t given_crc = hex_to_uint32((uint8_t *)cmdbuf, len - 8);
		uint32_t calculated_crc = crc32((uint8_t *)cmdbuf, len - 8);
		
		if (calculated_crc != given_crc)
		{
			UART_PUTF("CRC Error! %08lx does not match. Ignoring command.\r\n", calculated_crc);
		}
		else
		{
			cmdbuf[len - 8] = 0; // strip CRC from command
			send_data_avail = true;
		}
	}
	else
	{
		UART_PUTS("Unknown command.\r\n");
	}
}
int main(void)
{
	uint8_t i;
	uint16_t wakeup_sec;
	bool send;

	// delay 1s to avoid further communication with uart or RFM12 when my programmer resets the MC after 500ms...
	_delay_ms(1000);

	util_init();
	
	check_eeprom_compatibility(DEVICETYPE_SOILMOISTUREMETER);
	
	// configure power pin for 74HC14D as output
	sbi(TRIGGERPWR_DDR, TRIGGERPWR_PIN);

	// read packetcounter, increase by cycle and write back
	packetcounter = e2p_generic_get_packetcounter() + PACKET_COUNTER_WRITE_CYCLE;
	e2p_generic_set_packetcounter(packetcounter);

	// read device id
	device_id = e2p_generic_get_deviceid();

	dry_thr = e2p_soilmoisturemeter_get_drythreshold();
	if (dry_thr == 0) // set default value if never initialized
	{
		dry_thr = 40000;
	}

	counter_min = e2p_soilmoisturemeter_get_minval();
	if (counter_min == 0) // set default value if never initialized
	{
		counter_min = 30000;
	}

	avgIntInit = e2p_soilmoisturemeter_get_averagingintervalinit();
	avgInt = e2p_soilmoisturemeter_get_averaginginterval();
	smoothing_percentage = e2p_soilmoisturemeter_get_smoothingpercentage();

	osccal_init();

	uart_init();

	UART_PUTS ("\r\n");
	UART_PUTF4("smarthomatic Soil Moisture Meter v%u.%u.%u (%08lx)\r\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_HASH);
	UART_PUTS("(c) 2014..2015 Uwe Freese, www.smarthomatic.org\r\n");
	osccal_info();
	UART_PUTF ("DeviceID: %u\r\n", device_id);
	UART_PUTF ("PacketCounter: %lu\r\n", packetcounter);
	UART_PUTF ("AveragingInterval for initialization: %u\r\n", avgIntInit);
	UART_PUTF ("AveragingInterval for normal operation: %u\r\n", avgInt);
	UART_PUTF ("Dry threshold: %u\r\n", dry_thr);
	UART_PUTF ("Min value: %u\r\n", counter_min);
	UART_PUTF ("Smoothing percentage: %u\r\n", smoothing_percentage);

	adc_init();

	// init AES key
	e2p_generic_get_aeskey(aes_key);

	// set pull-up for BUTTON_DDR
	sbi(BUTTON_PORT, BUTTON_PIN);
	_delay_ms(10);

	// set DIDR for all ADC channels and AINs, switch off digital input buffers to reduce ADC noise and to save power
	DIDR0 = 63;
	DIDR1 = 3;
	
	// If button pressed at start up, go to sleep for idle power consumption test.
	// Don't communicate with RFM12, which may not have been connected yet.
	if (BUTTON)
	{
		led_blink(50, 50, 20);
		power_down(true);
	}

	led_blink(500, 500, 3);

	rfm12_init();
	wakeup_sec = init_wakeup();

	// init interrupt for button (falling edge)
	sbi(EICRA, ISC11);
	sbi(EIMSK, INT1);
	
	sei();

	for (i = 0; i < SEND_STATUS_TIMES_AT_STARTUP; i++)
	{
		prepare_deviceinfo_status();
		send_prepared_message();
		_delay_ms(800);
		prepare_battery_status();
		send_prepared_message();
		_delay_ms(800);
	}

	while (42)
	{
		if (BUTTON)
		{
			led_blink(100, 0, 1);
			UART_PUTS("Button pressed!\r\n");
			
			uint8_t cnt = 0;
			
			while (BUTTON && (cnt < 250))
			{
				_delay_ms(10);
				cnt++;
			}
			
			if (cnt == 250)
			{
				UART_PUTS("Long press -> initiate measure mode!\r\n");
				
				while (BUTTON)
				{
					led_blink(100, 100, 1);
				}

				init_mode = true;
				wupCnt = 0;
				counter_meas = 0;
				init_wakeup(); // to usually shorter value
				
				UART_PUTS("Button released!\r\n");
				_delay_ms(10);
			}
		}
		else
		{
			send = true;

			//UART_PUTF("version_status_cycle = %u\r\n", version_status_cycle);
		
			if (!measure_humidity())
			{
				if (battery_status_cycle > 0)
					battery_status_cycle--;

				if (version_status_cycle > 0)
					version_status_cycle--;

				if (version_status_cycle == 0)
				{
					version_status_cycle = SEND_VERSION_STATUS_CYCLE;
					prepare_deviceinfo_status();
				}
				else if (battery_status_cycle == 0)
				{
					battery_status_cycle = SEND_BATTERY_STATUS_CYCLE;
					prepare_battery_status();
				}
				else
				{
					send = false;
				}
			}

			if (send)
			{
				send_prepared_message();
			}
		}
		
		power_down(true);
	}
	
	// never called
	// aes256_done(&aes_ctx);
}