// 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"); }
// 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"); }
// Prepare message with device info void prepare_deviceinfo_status(void) { UART_PUTF("Send DeviceInfo: DeviceType %u,", DEVICETYPE_SOILMOISTUREMETER); UART_PUTF4(" v%u.%u.%u (%08lx)\r\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_HASH); // Set packet content pkg_header_init_generic_deviceinfo_status(); msg_generic_deviceinfo_set_devicetype(DEVICETYPE_SOILMOISTUREMETER); msg_generic_deviceinfo_set_versionmajor(VERSION_MAJOR); msg_generic_deviceinfo_set_versionminor(VERSION_MINOR); msg_generic_deviceinfo_set_versionpatch(VERSION_PATCH); msg_generic_deviceinfo_set_versionhash(VERSION_HASH); }
void send_version_status(void) { inc_packetcounter(); UART_PUTF4("Sending Version: v%u.%u.%u (%08lx)\r\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_HASH); // Set packet content pkg_header_init_generic_version_status(); pkg_header_set_senderid(device_id); pkg_header_set_packetcounter(packetcounter); msg_generic_version_set_major(VERSION_MAJOR); msg_generic_version_set_minor(VERSION_MINOR); msg_generic_version_set_patch(VERSION_PATCH); msg_generic_version_set_hash(VERSION_HASH); pkg_header_calc_crc32(); rfm12_send_bufx(); }
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); }
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); }
// Measure humidity, calculate relative value in permill and return it. // Return true, if humidity was sent. bool measure_humidity(void) { bool res = false; uint16_t cnt; switch_schmitt_trigger(true); _delay_ms(10); // make PD5 an input and disable pull-ups DDRD &= ~(1 << 5); PORTD &= ~(1 << 5); // clear counter TCNT1 = 0x00; // configure counter and use external clock source, rising edge TCCR1A = 0x00; TCCR1B |= (1 << CS12) | (1 << CS11) | (1 << CS10); _delay_ms(100); //cnt = (TCNT1H << 8) | TCNT1L; cnt = TCNT1; TCCR1B = 0x00; // turn counter off switch_schmitt_trigger(false); counter_meas += cnt; wupCnt++; UART_PUTF4("Init mode %u, Measurement %u/%u, Counter %u\r\n", init_mode, wupCnt, init_mode ? avgIntInit : avgInt , cnt); if ((init_mode && (wupCnt == avgIntInit)) || (!init_mode && (wupCnt == avgInt))) { uint32_t avg = init_mode ? counter_meas / avgIntInit : counter_meas / avgInt; if (init_mode) { UART_PUTF("Init: Save avg %u as dry threshold.\r\n", avg); dry_thr = avg; counter_min = dry_thr - 1; init_mode = false; init_wakeup(); // to normal value e2p_soilmoisturemeter_set_drythreshold(dry_thr); } else { int32_t result; if (avg < counter_min) { counter_min = avg; UART_PUTF("New min: %lu, ", counter_min); } if (avg > dry_thr) { result = 0; } else { result = (dry_thr - avg) * 1000 / (dry_thr - counter_min); } UART_PUTF("Avg: %u, ", avg); UART_PUTF("Result: %lu permill\r\n", result); // Don't change reported value if it changes within a window of // some percent. if (reported_result == 0) { reported_result = result; } else { if (direction_up) { if (result > reported_result) { reported_result = result; } else if (result < reported_result - smoothing_percentage * 10) { reported_result = result; direction_up = false; } } else // direction down { if (result < reported_result) { reported_result = result; } else if (result > reported_result + smoothing_percentage * 10) { reported_result = result; direction_up = true; } } } prepare_humidity_status((uint16_t)reported_result); //prepare_humidity_status_RAW_DBG((uint16_t)reported_result, (int16_t) MIN((int32_t)avg, 30000)); // for debugging only res = true; } wupCnt = 0; counter_meas = 0; } _delay_ms(10); return res; }
// 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; } }
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); }