//-U lfuse:w:0xa2:m -U hfuse:w:0xd9:m // avrdude -p m8 -c avrispv2 -P /dev/ttyACM0 -U lfuse:w:0xa2:m -U hfuse:w:0xd9:m #define VERSION_STR "D KeySafe Version: 3.2.5\n" /* History * --------------------------- * 2021-04-25 - 3.2.0 -> INIT Initial Status Open changed on aktive Code. * 2021-05-12 - 3.2.1 -> BFIX Prevent duplicate acceptence of Lock Codes. * 2021-05-20 - 3.2.2 -> BFIX Prevent Timeupdate after Timeout. Fix not running Timer. * 2021-09-27 - 3.2.3 -> DBG Debug Version zur Fehlersuche mit Ausgabe der Übertragungswerte. -NOT INCLUDED- * 2021-11-01 - 3.2.4 -> DBG Debug Version eingrenzen auf btea error. -NOT INCLUDED- * 2021-11-08 - 3.2.5 -> ENHT Memory Safing spritnf() removed + Text constans + better Send Methods * 2022-01-31 - 3.2.6 -> --- Handling of ATMEGA8 and ATMEGA88V + Auto Baud Calc via ATMEL LIB * * INIT = Intial Version * BFIX = Bugfix non breaking Changes * BBUG = Breaking Bugfix - Changes in more then 1 Component * ENHT = Enhancement Erweiterung */ #define BAUD 9600UL // Baudrate #include #include #include #include #include #include #include #include #include #include // ATMEGA8 -> ATMEGA88 Migration Guide http://ww1.microchip.com/downloads/en/AppNotes/doc2553.pdf --> AT8-88 Migration.pdf #ifdef __AVR_ATmega88__ #if F_CPU == 1000000UL #pragma message ( "Using ATMEGA88V at 1Mhz!" ) #define F_CPU 1000000UL #define __U2X U2X0 #define __UDR UDR0 #define __UCSRB UCSR0B #define __UCSRC UCSR0C #define __RXEN RXEN0 #define __TXEN TXEN0 #define __UCSRC UCSR0C #define __URSEL UMSEL01 #define __UCSZ0 UCSZ00 #define __UCSZ1 UCSZ01 #define __UBRRL UBRR0L #define __UBRRH UBRR0H #define __UCSRA UCSR0A #define __RXC RXC0 #define __UDRE UDRE0 #define __GICR EIMSK #define __TCCR2 TCCR2B #define __TIMSK TIMSK2 #define __TCR2UB TCR2AUB #define __TIFR TIFR2 #define __OCR2 OCR2A #define __OCR2UB OCR2AUB //Interrupt #define __MCUCR EICRA #else #error ATMEGA88V but wrong F_CPU Speed #endif #endif #ifdef __AVR_ATmega8__ #if F_CPU == 2000000UL #pragma message ( "Using ATMEGA8A-AU at 2Mhz!" ) #define F_CPU 2000000UL #define __U2X U2X #define __UDR UDR #define __UCSRB UCSRB #define __UCSRC UCSRC #define __RXEN RXEN #define __TXEN TXEN #define __UCSRC UCSRC #define __URSEL URSEL #define __UCSZ0 UCSZ0 #define __UCSZ1 UCSZ1 #define __UBRRL UBRRL #define __UBRRH UBRRH #define __UCSRA UCSRA #define __RXC RXC #define __UDRE UDRE #define __GICR GICR #define __TCCR2 TCCR2 #define __TIMSK TIMSK #define __TCR2UB TCR2UB #define __TIFR TIFR #define __OCR2 OCR2 #define __OCR2UB OCR2UB #define __MCUCR MCUCR #else #error ATMEGA8 but wrong F_CPU Speed #endif #endif #define EEPROM_DEF 0xFF #define BTDEBUG 0 // Original KeySave Meiner #define BT_EN_REGISTER DDRC #define BT_EN_PORT PORTC #define BT_EN_PIN PC5 #define BT_RTX_PORT PORTD #define BT_TRX_REG DDRD #define BT_RX_PIN PD0 #define BT_TX_PIN PD1 #define LED_REGISTER DDRC #define LED_PORT PORTC #define LED_RED_PIN PC0 #define LED_GREEN_PIN PC1 #define LED_BLUE_PIN PC2 // Board /* #define BT_EN_REGISTER DDRC #define BT_EN_PORT PORTC #define BT_EN_PIN PC0 #define BT_RTX_PORT PORTD #define BT_TRX_REG DDRD #define BT_RX_PIN PD0 #define BT_TX_PIN PD1 #define LED_REGISTER DDRC #define LED_PORT PORTC #define LED_RED_PIN PC5 #define LED_GREEN_PIN PC4 #define LED_BLUE_PIN PC3 */ #define STAT_NO_BYTES_READ 0 #define STAT_START_FOUND 1 #define STAT_UPD_MASTERCODE 2 #define STAT_SET_LOCKCODE 3 #define STAT_READY 4 #define STAT_ERROR 5 #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) //#define BAUD_PRESCALE (((F_CPU / (BAUDRATE * 16UL))) - 1) /* Define prescale value for BT Module */ #define BT_INPUT_BUFFER 50 //Largest command is 49 including \0 !U10,10,10,10,$\n\0 #define TXT__D_DebugOut "D Debug Out: " #define TXT__I_MasterCodeUpdate "I MasterCodeUpdate - " #define TXT__I_LockCodeUpdate "I LockCodeUpdate - " #define TXT____vorbereiten "vorbereiten\n" #define TXT____erledigt "erledigt\n" #define TXT__E_Datenfehler "E Datenfehler (bufidx,status,ichar,char,errCode): " #define TXT__E_LockCodeUpdate "E LockCodeUpdate - " uint32_t gEi_MasterKeyU32[4] EEMEM; // EEPORM uint16_t gEi_Req_Counter EEMEM; uint32_t gul__MasterKeyU32[4]; uint16_t gu_Req_Counter =0; uint32_t gul_lockInfo[] = {0,0}; //Element 1 = Time; Element 2 = (1Bit)ShowRemainingToSub (30Bit) Scrambled VerificationCode volatile uint8_t gi_wakeup_pressed = 0; volatile uint8_t gi_intrusion_detected = 1; // Will be set to 0 on Activation /** *@desc This Function initalizes Bluetooth Module with Baud *@param BAUDRATE The Baud Rate for the Module */ void USART_init(void){ //Flag for Baud Rate Calculated with util/setbaud.h __UBRRH = UBRRH_VALUE; /* Load UBRRL with lower 8 bit of prescale value */ __UBRRL = UBRRL_VALUE; /* Load UBRRH with upper 8 bit of prescale value */ // Ganz wichtig der Double Speed Modus fuer 1Mhz bekommen wir sonst keine Baud hin. // https://cache.amobbs.com/bbs_upload782111/files_22/ourdev_508497.html --> AVR Baud Rate Tables.pdf // https://alexandria.atmel.com/pr/GUID-ED37252C-1496-4275-BAEF-5152050ED2C2-en-US-2/index.html?GUID-65A53416-8DE2-468E-99CF-09F480AEF734 --> AVR306_ Using the AVR USART on tinyAVR and megaAVR devices.pdf #if USE_2X /* U2X-Modus erforderlich */ __UCSRA |= (1 << __U2X); #else /* U2X-Modus nicht erforderlich */ __UCSRA &= ~(1 << __U2X); #endif __UCSRB |= (1 << __RXEN) | (1 << __TXEN); /* Enable USART transmitter and receiver */ __UCSRC |= (1 << __URSEL)| (1 << __UCSZ0) | (1 << __UCSZ1); /* Write USCRC for 8 bit data and 1 stop bit */ } void USART_deinit(void){ BT_RTX_PORT |= (1< intrusion_detection ISR(INT0_vect){ gi_intrusion_detected = 1; LED_PORT |= (1< Trigger Show remaining_time ISR(INT1_vect){ gi_wakeup_pressed = 1; LED_PORT |= (1< 8){ gul_lockInfo[0] = gul_lockInfo[0] - 8; }else{ gul_lockInfo[0] = 0; } } //TinyEncryptionAlgorythem void btea(uint32_t *v, int n, uint32_t key[4]) { uint32_t y, z, sum; unsigned p, rounds, e; if (n > 1) { /* Coding Part */ rounds = 6 + 52/n; sum = 0; z = v[n-1]; do { sum += DELTA; e = (sum >> 2) & 3; for (p=0; p> 2) & 3; for (p=n-1; p>0; p--) { z = v[p-1]; y = v[p] -= MX; } z = v[n-1]; y = v[0] -= MX; sum -= DELTA; } while (--rounds); } } void getStatus(void){ uint32_t cryptblocks[2]; cryptblocks[0] = gul_lockInfo[0]; cryptblocks[1] = gul_lockInfo[1]; if (gi_intrusion_detected == 0){ cryptblocks[1] &= ~(1UL << 31); // Clear Bit i }else{ cryptblocks[1] |= 1UL << 31; // Set Bit i } for (int8_t i=15; i >= 0; i--){ // Integriere die 16 Bit vom Request Counter in den CodeBlock an die letzten 16 Bit if ( (gu_Req_Counter >> i) & 1U ){ // Check bit from Refcounter cryptblocks[1] |= 1UL << i; // Set Bit i }else{ cryptblocks[1] &= ~(1UL << i); // Clear Bit i } } btea(cryptblocks,2, gul__MasterKeyU32); USART_sendStr("!R"); USART_sendUint16t(getCurrentVoltage()); USART_sendChar(','); USART_sendUint8t(gi_intrusion_detected); USART_sendChar(','); // Bit31 nicht gesetzt (ShowSubRemainingTime) && Lock Zeit != 0 && Nicht geoeffnet if ( (! (gul_lockInfo[1] >> 31) & 1U ) && (gul_lockInfo[0] != 0) && (gi_intrusion_detected == 0) ){ USART_sendChar('N'); }else{ USART_sendUint32t(gul_lockInfo[0]); } USART_sendChar(','); USART_sendUint32t(cryptblocks[0]); USART_sendChar(','); USART_sendUint32t(cryptblocks[1]); USART_sendStr(",$\n"); } void updateMasterCode(void){ USART_sendStr(TXT__I_MasterCodeUpdate); USART_sendStr(TXT____vorbereiten); gu_Req_Counter=0; eeprom_write_word(&gEi_Req_Counter, gu_Req_Counter); eeprom_write_dword(&gEi_MasterKeyU32[0], gul__MasterKeyU32[0]); eeprom_write_dword(&gEi_MasterKeyU32[1], gul__MasterKeyU32[1]); eeprom_write_dword(&gEi_MasterKeyU32[2], gul__MasterKeyU32[2]); eeprom_write_dword(&gEi_MasterKeyU32[3], gul__MasterKeyU32[3]); USART_sendStr(TXT__I_MasterCodeUpdate); USART_sendStr(TXT____erledigt); gi_intrusion_detected = 0; getStatus(); gi_intrusion_detected = 1; } /* Command List: ============== !U....,...,...,$ = Update Master Code !L....,...,...,$ = Set Lock Code !G = Get Status */ void get_BTData(uint8_t timeout_active){ for (uint8_t i=0; i < 4; i++){ // Blink LED while Init gives BT time to bootup LED_PORT ^= (1 << LED_BLUE_PIN); _delay_ms(200); } _delay_ms(2000); BT_EN_PORT |= (1< (15500000UL)){ //ca 1 Minute 15 4294967295 (MAX) status=STAT_ERROR; break; } } if (status == STAT_ERROR){ break; } } c = __UDR; if (c == '!'){ //Start of my Data status = STAT_START_FOUND; bufidx = 0; continue; }else if (c == '$'){ //End of my Data if (bufidx > 0){ buffer[bufidx] = '$'; bufidx++; buffer[bufidx] = '\0'; break; } status = STAT_NO_BYTES_READ; bufidx=0; }else if (c == '\n'){ continue; } if ((status == STAT_START_FOUND) && (bufidx < (BT_INPUT_BUFFER-2))){ //Keep space for $ and \0 buffer[bufidx] = c; bufidx++; }else{ //ERROR USART_sendStr(TXT__E_Datenfehler); USART_sendUint8t(bufidx); USART_sendUint8t(status); USART_sendUint8t((unsigned int)c);USART_sendChar(c);USART_sendStr(",E1\n"); LED_PORT |= (1< Ignore LED_PORT |= (1< Parse out Long Values if ((status == STAT_UPD_MASTERCODE) || (status == STAT_SET_LOCKCODE)){ char uint_str_buffer[11]; // 11 = size of value of unit32_t (10 chars) uint8_t str_buf_idx = 0; uint8_t sub_idx = 0; uint32_t lul_lockInfo[] = {0,0}; for (uint8_t i=1; i < bufidx; i++){ if ((str_buf_idx < 11) && ((buffer[i] == '0') || (buffer[i] == '1') || (buffer[i] == '2') || (buffer[i] == '3') || (buffer[i] == '4') || (buffer[i] == '5') || (buffer[i] == '6') || (buffer[i] == '7') || (buffer[i] == '8') || (buffer[i] == '9') )){ uint_str_buffer[str_buf_idx] = buffer[i]; str_buf_idx++; uint_str_buffer[str_buf_idx] = '\0'; continue; }else if (buffer[i] == ','){ //End of Block if ((status == STAT_UPD_MASTERCODE)&&(sub_idx < 5)){ uint_str_buffer[str_buf_idx] = '\0'; gul__MasterKeyU32[sub_idx] = strtoul(uint_str_buffer, NULL,0); sub_idx++; str_buf_idx=0; }else if ((status==STAT_SET_LOCKCODE) && (sub_idx <2)){ uint_str_buffer[str_buf_idx] = '\0'; lul_lockInfo[sub_idx] = strtoul(uint_str_buffer, NULL,0); #if defined BTDEBUG && BTDEBUG == 1 USART_sendStr(TXT__D_DebugOut); USART_sendStr(uint_str_buffer); USART_sendChar('\n'); #endif sub_idx++; str_buf_idx=0; }else{ //To much Elements LED_PORT |= (1< Lockcode update abgebrochen\n"); sub_idx = 0; bufidx = 0; str_buf_idx=0; lul_lockInfo[0] = 0; lul_lockInfo[1] = 0; status = STAT_NO_BYTES_READ; break; } USART_sendStr(TXT__I_LockCodeUpdate); USART_sendStr("aktivieren\n"); gu_Req_Counter++; eeprom_write_word(&gEi_Req_Counter, gu_Req_Counter); if ((timeout_active != 0) && (gi_intrusion_detected != 0)){ USART_sendStr(TXT__E_LockCodeUpdate); USART_sendStr("KeySafe war offen\n"); sub_idx = 0; bufidx = 0; str_buf_idx=0; lul_lockInfo[0] = 0; lul_lockInfo[1] = 0; status = STAT_NO_BYTES_READ; getStatus(); break; }else if ((timeout_active != 0) && (gul_lockInfo[0] < 60)){ USART_sendStr(TXT__E_LockCodeUpdate); USART_sendStr("Restzeit zu kurz < 60 Sec.\n"); sub_idx = 0; bufidx = 0; str_buf_idx=0; lul_lockInfo[0] = 0; lul_lockInfo[1] = 0; status = STAT_NO_BYTES_READ; getStatus(); break; }else{ USART_sendStr("I KeySafe ist in 5 Sekunden aktiv.\n"); gul_lockInfo[0] = lul_lockInfo[0]; gul_lockInfo[1] = lul_lockInfo[1]; gi_intrusion_detected = 0; // Nur bei Initial } getStatus(); status = STAT_READY; break; }else{ LED_PORT |= (1< 2s Überlaufperiode __TCCR2 |= (1 << CS22) | (1 << CS21) | (1 << CS20); // Prescaler 1024 -> 8s Überlaufperiode while((ASSR & (1<< __TCR2UB))); // Warte auf das Ende des Zugriffs __TIFR = (1< 0) && (gi_intrusion_detected==0)){ if_wakup_key_pressed(); __GICR |= (1 << INT1); //enable interrupt 1 //WAKEUP cli(); sei(); ADCSRA = 0; // WICHTIG! // Wenn der Timer2 im asynchronen Modus periodisch zum Wecken aus dem Sleep Mode genutzt wird, dann muss vor dem Wiedereintritt mindestens // 1 Oszillatortakt des Timers abgewartet werden (~30us), um die Interruptlogik wieder zu aktivieren, anderenfalls wacht der AVR nicht mehr auf. // Die folgenden zwei Zeilen tun dies. Nur wenn sichergestellt ist, dass der Interrupt + Hauptschleife länger als 30µs dauern, kann man den Test weglassen __OCR2 = 0; // Dummyzugriff while((ASSR & (1<< __OCR2UB))); // Warte auf das Ende des Zugriffs // Go to sleep set_sleep_mode(SLEEP_MODE_PWR_SAVE); sleep_mode(); // in den Schlafmodus wechseln // hier wachen wir wieder auf //__GICR &= ~(1 << INT0); // externen Interrupt sperren WICHTIG! falls der externe LOW Puls an INT0 sehr lange dauert __GICR &= ~(1 << INT1); // externen Interrupt sperren WICHTIG! falls der externe LOW Puls an INT1 sehr lange dauert cli(); sei(); } //Finished __GICR &= ~(1<