/* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /** STM32F1 Maxim DS2432 (1k-Bit Protected 1-Wire EEPROM with SHA-1 Engine) implementation * @file application.c * @author King Kévin * @date 2016-2017 */ /* standard libraries */ #include // standard integer types #include // standard utilities #include // string utilities #include // date/time utilities /* STM32 (including CM3) libraries */ #include // Cortex M3 utilities #include // vector table definition #include // interrupt utilities #include // general purpose input output library #include // real-time control clock library #include // external interrupt utilities #include // real time clock utilities #include // independent watchdog utilities #include // debug utilities #include // flash utilities /* own libraries */ #include "global.h" // board definitions #include "print.h" // printing utilities #include "usart.h" // USART utilities #include "usb_cdcacm.h" // USB CDC ACM utilities #include "onewire_slave.h" // 1-Wire utilities #define WATCHDOG_PERIOD 10000 /**< watchdog period in ms */ /** @defgroup main_flags flag set in interrupts to be processed in main task * @{ */ volatile bool rtc_internal_tick_flag = false; /**< flag set when internal RTC ticked */ /** @} */ time_t time_rtc = 0; /**< time (seconds since Unix Epoch) */ struct tm* time_tm; /**< time in tm format (time zones are not handled for non-POSIX environments) */ size_t putc(char c) { size_t length = 0; // number of characters printed static char newline = 0; // to remember on which character we sent the newline if (0==c) { length = 0; // don't print string termination character } else if ('\r' == c || '\n' == c) { // send CR+LF newline for most carriage return and line feed combination if (0==newline || c==newline) { // send newline only if not already send (and only once on \r\n or \n\r) usart_putchar_nonblocking('\r'); // send CR over USART usb_cdcacm_putchar('\r'); // send CR over USB usart_putchar_nonblocking('\n'); // send LF over USART usb_cdcacm_putchar('\n'); // send LF over USB length += 2; // remember we printed 2 characters newline = c; // remember on which character we sent the newline } else { length = 0; // the \r or \n of \n\r or \r\n has already been printed } } else { usart_putchar_nonblocking(c); // send byte over USART usb_cdcacm_putchar(c); // send byte over USB newline = 0; // clear new line length++; // remember we printed 1 character } return length; // return number of characters printed } /** user input command */ static char command[32] = {0}; /** user input command index */ uint8_t command_i = 0; /** process user command * @param[in] str user command string (\0 ended) */ static void process_command(char* str) { // split command const char* delimiter = " "; char* word = strtok(str,delimiter); if (!word) { goto error; } // parse command if (0==strcmp(word,"h") || 0==strcmp(word,"help") || 0==strcmp(word,"?")) { printf("available commands:\n"); printf("led [on|off|toggle]\n"); } else if (0==strcmp(word,"l") || 0==strcmp(word,"led")) { word = strtok(NULL,delimiter); if (!word) { printf("LED is "); if (gpio_get(GPIO(LED_PORT), GPIO(LED_PIN))) { printf("on\n"); } else { printf("off\n"); } } else if (0==strcmp(word,"on")) { led_on(); // switch LED on printf("LED switched on\n"); // notify user } else if (0==strcmp(word,"off")) { led_off(); // switch LED off printf("LED switched off\n"); // notify user } else if (0==strcmp(word,"toggle")) { led_toggle(); // toggle LED printf("LED toggled\n"); // notify user } else { goto error; } } else if (0==strcmp(word,"time")) { word = strtok(NULL,delimiter); if (!word) { time_rtc = rtc_get_counter_val(); // get time from internal RTC time_tm = localtime(&time_rtc); // convert time printf("time: %02d:%02d:%02d\n", time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec); } else if (strlen(word)!=8 || word[0]<'0' || word[0]>'2' || word[1]<'0' || word[1]>'9' || word[3]<'0' || word[3]>'5' || word[4]<'0' || word[4]>'9' || word[6]<'0' || word[6]>'5' || word[7]<'0' || word[7]>'9') { // time format is incorrect goto error; } else { time_rtc = rtc_get_counter_val(); // get time from internal RTC time_tm = localtime(&time_rtc); // convert time time_tm->tm_hour = (word[0]-'0')*10+(word[1]-'0')*1; // set hours time_tm->tm_min = (word[3]-'0')*10+(word[4]-'0')*1; // set minutes time_tm->tm_sec = (word[6]-'0')*10+(word[7]-'0')*1; // set seconds time_rtc = mktime(time_tm); // get back seconds rtc_set_counter_val(time_rtc); // save time to internal RTC printf("time set\n"); } } else if (0==strcmp(word,"date")) { word = strtok(NULL,delimiter); if (!word) { time_rtc = rtc_get_counter_val(); // get time from internal RTC time_tm = localtime(&time_rtc); // convert time printf("date: %d-%02d-%02d\n", 1900+time_tm->tm_year, time_tm->tm_mon+1, time_tm->tm_mday); } else if (strlen(word)!=10 || word[0]!='2' || word[1]!='0' || word[2]<'0' || word[2]>'9' || word[3]<'0' || word[3]>'9' || word[5]<'0' || word[5]>'1' || word[6]<'0' || word[6]>'9' || word[8]<'0' || word[8]>'3' || word[9]<'0' || word[9]>'9') { goto error; } else { time_rtc = rtc_get_counter_val(); // get time from internal RTC time_tm = localtime(&time_rtc); // convert time time_tm->tm_year = ((word[0]-'0')*1000+(word[1]-'0')*100+(word[2]-'0')*10+(word[3]-'0')*1)-1900; // set year time_tm->tm_mon = (word[5]-'0')*10+(word[6]-'0')*1-1; // set month time_tm->tm_mday = (word[8]-'0')*10+(word[9]-'0')*1; // set day time_rtc = mktime(time_tm); // get back seconds rtc_set_counter_val(time_rtc); // save time to internal RTC printf("date set\n"); } } else { goto error; } return; // command successfully processed error: printf("command not recognized. enter help to list commands\n"); return; } /** static table used for the table_driven implementation * Generated by pycrc v0.9, https://pycrc.org * using the configuration: * Width = 16 * Poly = 0x8005 * Xor_In = 0x0000 * ReflectIn = True * Xor_Out = 0xffff * ReflectOut = True * Algorithm = table-driven */ static const uint16_t crc_table[256] = { 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 }; /** update the crc value with new data. * @param crc The current crc value. * @param data Pointer to a buffer of @a data_len bytes. * @param data_len Number of bytes in the @a data buffer. * @return The updated crc value. */ static uint16_t crc16_update(uint16_t crc, const uint8_t *data, size_t data_len) { const unsigned char *d = (const unsigned char *)data; unsigned int tbl_idx; while (data_len--) { tbl_idx = (crc ^ *d) & 0xff; crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffff; d++; } return crc & 0xffff; } /** SHA-1 input data to calculate MAC for 'Read Authenticated Page' function command */ static uint32_t m[16] = {0}; /** intermediate calculation */ uint32_t wt[80] = {0}; /** DS2432 SHA-1 S function, rotating to the left * @param[in] x value to rotate by @a n to the left * @param[in] n rotate @a x by n to the left * @return @a x rotated ny @a n to the left */ static uint32_t s_left(uint32_t x, uint8_t n) { return (((x)<<(n)) | ((x)>>(32-(n)))); } /** DS2432 SHA-1 F function * @param[in] t time/round * @param[in] b B value * @param[in] c C value * @param[in] d D value * @return result of the F function */ static uint32_t f(uint8_t t, uint32_t b, uint32_t c, uint32_t d) { if (t<20) { return (b&c)|((~b)&d); } else if (t<40) { return b^c^d; } else if (t<60) { return (b&c)|(b&d)|(c&d); } else if (t<80) { return b^c^d; } else { // this should not happen return 0; } } /** DS2432 SHA-1 K function * @param[in] t time/round * @return result of the K function */ static uint32_t k(uint8_t t) { if (t<20) { return 0x5A827999; } else if (t<40) { return 0x6ED9EBA1; } else if (t<60) { return 0x8F1BBCDC; } else if (t<80) { return 0xCA62C1D6; } else { // this should not happen return 0; } } /** DS2432 SHA-1 W function * @param[in] t time/round * @note uses @a m or previously calculated @a wt values * @return result of the W function */ static uint32_t w(uint8_t t) { if (t<16) { return m[t]; } else { return s_left(wt[t-3]^wt[t-8]^wt[t-14]^wt[t-16], 1); } } /** program entry point * this is the firmware function started by the micro-controller */ void main(void); void main(void) { rcc_clock_setup_in_hse_8mhz_out_72mhz(); // use 8 MHz high speed external clock to generate 72 MHz internal clock #if DEBUG // enable functionalities for easier debug DBGMCU_CR |= DBGMCU_CR_IWDG_STOP; // stop independent watchdog counter when code is halted DBGMCU_CR |= DBGMCU_CR_WWDG_STOP; // stop window watchdog counter when code is halted DBGMCU_CR |= DBGMCU_CR_STANDBY; // allow debug also in standby mode (keep digital part and clock powered) DBGMCU_CR |= DBGMCU_CR_STOP; // allow debug also in stop mode (keep clock powered) DBGMCU_CR |= DBGMCU_CR_SLEEP; // allow debug also in sleep mode (keep clock powered) #else // setup watchdog to reset in case we get stuck (i.e. when an error occurred) iwdg_set_period_ms(WATCHDOG_PERIOD); // set independent watchdog period iwdg_start(); // start independent watchdog #endif board_setup(); // setup board usart_setup(); // setup USART (for printing) usb_cdcacm_setup(); // setup USB CDC ACM (for printing) printf("welcome to the CuVoodoo STM32F1 DS2432 implementation (1k-Bit Protected 1-Wire EEPROM with SHA-1 Engine)\n"); // print welcome message #if !(DEBUG) // show watchdog information printf("watchdog set to (%.2fs)\n",WATCHDOG_PERIOD/1000.0); if (FLASH_OBR&FLASH_OBR_OPTERR) { printf("option bytes not set in flash: software wachtdog used (not started at reset)\n"); } else if (FLASH_OBR&FLASH_OBR_WDG_SW) { printf("software wachtdog used (not started at reset)\n"); } else { printf("hardware wachtdog used (started at reset)\n"); } #endif // setup RTC printf("setup internal RTC: "); rtc_auto_awake(RCC_LSE, 32768-1); // ensure internal RTC is on, uses the 32.678 kHz LSE, and the prescale is set to our tick speed, else update backup registers accordingly (power off the micro-controller for the change to take effect) rtc_interrupt_enable(RTC_SEC); // enable RTC interrupt on "seconds" nvic_enable_irq(NVIC_RTC_IRQ); // allow the RTC to interrupt printf("OK\n"); time_rtc= rtc_get_counter_val(); // get time from internal RTC time_tm = localtime(&time_rtc); // convert time printf("date: %d-%02d-%02d %02d:%02d:%02d\n", 1900+time_tm->tm_year, time_tm->tm_mon+1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec); uint8_t ds2432_eeprom[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97}; /**< EEPROM content (including secret) */ uint8_t ds2432_scratchpad[8]; /**< scratchpad data */ uint8_t ds2432_address[2+1] = {0, 0, 0x5f}; /**< address registers: target address and E/S */ uint8_t ds2432_buffer[2+1+8+2]; /**< buffer to save command code target address, data status, scratchpad, and CRC */ const uint8_t ds2432_padding = 0xff; /**< padding byte used in Read Authenticated Page command */ uint16_t ds2432_crc = 0; // CRC-16 used in 1-Wire DS2432 communication uint8_t ds2432_mac[20] = {0}; // buffer for the MAC enum { DS2432_STATE_IDLE, DS2432_STATE_WRITE_SCRATCHPAD_DATA, DS2432_STATE_WRITE_SCRATCHPAD_CRC, DS2432_STATE_READ_SCRATCHPAD_ADDRESS, DS2432_STATE_READ_SCRATCHPAD_DATA, DS2432_STATE_READ_SCRATCHPAD_CRC, DS2432_STATE_READ_AUTHENTICATED_PAGE_ADDRESS, DS2432_STATE_READ_AUTHENTICATED_PAGE_DATA, DS2432_STATE_READ_AUTHENTICATED_PAGE_PADDING, DS2432_STATE_READ_AUTHENTICATED_PAGE_CRC, DS2432_STATE_READ_AUTHENTICATED_PAGE_MAC, DS2432_STATE_READ_AUTHENTICATED_PAGE_MACCRC, DS2432_STATE_READ_MEMORY_ADDRESS, DS2432_STATE_READ_MEMORY_DATA, } ds2432_state = DS2432_STATE_IDLE; /**< current state */ printf("setup 1-Wire bus: "); onewire_slave_setup(ds2432_eeprom[0x90], ((uint64_t)ds2432_eeprom[0x91]<<0)+((uint64_t)ds2432_eeprom[0x91]<<0)+((uint64_t)ds2432_eeprom[0x92]<<8)+((uint64_t)ds2432_eeprom[0x93]<<16)+((uint64_t)ds2432_eeprom[0x94]<<24)+((uint64_t)ds2432_eeprom[0x95]<<32)+((uint64_t)ds2432_eeprom[0x96]<<40)); // setup 1-Wire peripheral to act as slave printf("OK\n"); // main loop printf("command input: ready\n"); bool action = false; // if an action has been performed don't go to sleep button_flag = false; // reset button flag char ch = '\0'; // to store received character bool char_flag = false; // a new character has been received while (true) { // infinite loop iwdg_reset(); // kick the dog while (usart_received) { // data received over UART action = true; // action has been performed led_toggle(); // toggle LED ch = usart_getchar(); // store receive character char_flag = true; // notify character has been received } while (usb_cdcacm_received) { // data received over USB action = true; // action has been performed led_toggle(); // toggle LED ch = usb_cdcacm_getchar(); // store receive character char_flag = true; // notify character has been received } while (char_flag) { // user data received char_flag = false; // reset flag action = true; // action has been performed printf("%c",ch); // echo receive character if (ch=='\r' || ch=='\n') { // end of command received if (command_i>0) { // there is a command to process command[command_i] = 0; // end string command_i = 0; // prepare for next command process_command(command); // process user command } } else { // user command input command[command_i] = ch; // save command input if (command_itm_sec) { // new minute printf("time: %02d:%02d:%02d\n", time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec); } } while (onewire_slave_function_code_received) { // we received a function command code over the 1-Wire bus onewire_slave_function_code_received = false; // reset flag action = true; // action has been performed switch (onewire_slave_function_code) { case 0x0f: // Write Scratchpad onewire_slave_function_read(ds2432_buffer, 2+8); // read target address and scratchpad ds2432_state = DS2432_STATE_WRITE_SCRATCHPAD_DATA; // update state break; case 0xaa: // Read Scratchpad onewire_slave_function_write(ds2432_address, LENGTH(ds2432_address)); // send address registers ds2432_state = DS2432_STATE_READ_SCRATCHPAD_ADDRESS; // update state break; case 0xa5: // Read Authenticated Page onewire_slave_function_read(ds2432_buffer, 2); // read target address ds2432_state = DS2432_STATE_READ_AUTHENTICATED_PAGE_ADDRESS; // update state break; case 0xf0: // Read Memory onewire_slave_function_read(ds2432_buffer, 2); // read target address ds2432_state = DS2432_STATE_READ_MEMORY_ADDRESS; // update state break; default: // unknown function command code ds2432_state = DS2432_STATE_IDLE; // return to idle state break; } printf("1-Wire function command received: 0x%02x\n", onewire_slave_function_code); } while (onewire_slave_transfer_complete) { // the current data transfer completed onewire_slave_transfer_complete = false; // reset flag action = true; // action has been performed switch (ds2432_state) { case DS2432_STATE_WRITE_SCRATCHPAD_DATA: ds2432_crc = crc16_update(0, (const uint8_t *)&onewire_slave_function_code, 1); // initialize CRC with function code ds2432_crc = crc16_update(ds2432_crc, ds2432_buffer, (2+8)); // calculate CRC ds2432_crc ^= 0xffff; // invert CRC ds2432_buffer[2+1+8+0] = ds2432_crc>>0; // save CRC (LSB first) ds2432_buffer[2+1+8+1] = ds2432_crc>>8; // save CRC (MSB last) onewire_slave_function_write(&ds2432_buffer[2+1+8+0], 2); // write CRC ds2432_state = DS2432_STATE_WRITE_SCRATCHPAD_CRC; // update state ds2432_address[0] = ds2432_buffer[0]&0xf8; // save target address ds2432_address[1] = ds2432_buffer[1]; // save target address ds2432_address[2] = 0x5f; // reset state for (uint8_t i=0; i>0; // save CRC (LSB first) ds2432_buffer[2+1+8+1] = ds2432_crc>>8; // save CRC (MSB last) break; case DS2432_STATE_READ_SCRATCHPAD_DATA: // scratchpad data transfer complete, send CRC onewire_slave_function_write(&ds2432_buffer[2+1+8+0], 2); // send CRC ds2432_state = DS2432_STATE_WRITE_SCRATCHPAD_CRC; // update state break; case DS2432_STATE_READ_AUTHENTICATED_PAGE_ADDRESS: // target address transfer completed, send data if (0==ds2432_buffer[1] && ds2432_buffer[0]<0x80) { // target address matches to memory page onewire_slave_function_write(&ds2432_eeprom[ds2432_buffer[0]], 0x20-(ds2432_buffer[0]&0x1f)); // send memory data until end of page ds2432_state = DS2432_STATE_READ_AUTHENTICATED_PAGE_DATA; // update state } else { // target address is out of range ds2432_state = DS2432_STATE_IDLE; // return to idle state } break; case DS2432_STATE_READ_AUTHENTICATED_PAGE_DATA: // memory page data transfer completed, send padding byte onewire_slave_function_write((uint8_t *)&ds2432_padding, 1); // send padding byte ds2432_state = DS2432_STATE_READ_AUTHENTICATED_PAGE_PADDING; // update state ds2432_crc = crc16_update(0, (const uint8_t *)&onewire_slave_function_code, 1); // initialize CRC with function code ds2432_crc = crc16_update(ds2432_crc, ds2432_buffer, 2); // update CRC with target address ds2432_crc = crc16_update(ds2432_crc, &ds2432_eeprom[ds2432_buffer[0]], 0x20-(ds2432_buffer[0]&0x1f)); // update CRC with data ds2432_crc = crc16_update(ds2432_crc, &ds2432_padding, 1); // update CRC with padding ds2432_crc ^= 0xffff; // invert CRC ds2432_buffer[2+1+8+0] = ds2432_crc>>0; // save CRC (LSB first) ds2432_buffer[2+1+8+1] = ds2432_crc>>8; // save CRC (MSB last) break; case DS2432_STATE_READ_AUTHENTICATED_PAGE_PADDING: // padding byte transfer complete, send CRC onewire_slave_function_write(&ds2432_buffer[2+1+8+0], 2); // send CRC ds2432_state = DS2432_STATE_READ_AUTHENTICATED_PAGE_CRC; // update state // calculate MAC { ds2432_buffer[0] &= 0xe0; // set target address to start of page // initialize SHA-1 input data (see table 4) m[0] = (ds2432_eeprom[0x80+0]<<24)+(ds2432_eeprom[0x80+1]<<16)+(ds2432_eeprom[0x80+2]<<8)+(ds2432_eeprom[0x80+3]<<0); // copy secret for (uint8_t i=0; i<8; i++) { // copy page m[1+i] = (ds2432_eeprom[ds2432_buffer[0]+i*4+0]<<24)+(ds2432_eeprom[ds2432_buffer[0]+i*4+1]<<16)+(ds2432_eeprom[ds2432_buffer[0]+i*4+2]<<8)+(ds2432_eeprom[ds2432_buffer[0]+i*4+3]<<0); } m[9] = (0xff<<24)+(0xff<<16)+(0xff<<8)+(0xff<<0); // filling bytes m[10] = ((0x40+(ds2432_buffer[0]>>5))<<24)+(ds2432_eeprom[0x90+0]<<16)+(ds2432_eeprom[0x90+1]<<8)+(ds2432_eeprom[0x90+2]<<0); // copy target and ROM code m[11] = (ds2432_eeprom[0x90+3]<<24)+(ds2432_eeprom[0x90+4]<<16)+(ds2432_eeprom[0x90+5]<<8)+(ds2432_eeprom[0x90+6]<<0); // copy ROM code m[12] = (ds2432_eeprom[0x80+4]<<24)+(ds2432_eeprom[0x80+5]<<16)+(ds2432_eeprom[0x80+6]<<8)+(ds2432_eeprom[0x80+7]<<0); // copy rest of secret m[13] = (ds2432_scratchpad[4]<<24)+(ds2432_scratchpad[5]<<16)+(ds2432_scratchpad[6]<<8)+(0x80<<0); // copy challenge m[14] = (0x00<<24)+(0x00<<16)+(0x00<<8)+(0x00<<0); m[15] = (0x00<<24)+(0x00<<16)+(0x01<<8)+(0xb8<<0); // initialize variables uint32_t a = 0x67452301; uint32_t b = 0xEFCDAB89; uint32_t c = 0x98BADCFE; uint32_t d = 0x10325476; uint32_t e = 0xC3D2E1F0; // loop through computation for (uint8_t t=0; t<80; t++) { wt[t] = w(t); uint32_t tmp = s_left(a, 5)+f(t,b,c,d)+wt[t]+k(t)+e; e = d; d = c; c = s_left(b, 30); b = a; a = tmp; } // copy result ds2432_mac[0] = e>>0; ds2432_mac[1] = e>>8; ds2432_mac[2] = e>>16; ds2432_mac[3] = e>>24; ds2432_mac[4] = d>>0; ds2432_mac[5] = d>>8; ds2432_mac[6] = d>>16; ds2432_mac[7] = d>>24; ds2432_mac[8] = c>>0; ds2432_mac[9] = c>>8; ds2432_mac[10] = c>>16; ds2432_mac[11] = c>>24; ds2432_mac[12] = b>>0; ds2432_mac[13] = b>>8; ds2432_mac[14] = b>>16; ds2432_mac[15] = b>>24; ds2432_mac[16] = a>>0; ds2432_mac[17] = a>>8; ds2432_mac[18] = a>>16; ds2432_mac[19] = a>>24; } break; case DS2432_STATE_READ_AUTHENTICATED_PAGE_CRC: // CRC transfer completed, send MAC onewire_slave_function_write(ds2432_mac, LENGTH(ds2432_mac)); // send CRC ds2432_state = DS2432_STATE_READ_AUTHENTICATED_PAGE_MAC; // update state ds2432_crc = crc16_update(0, ds2432_mac, LENGTH(ds2432_mac)); // calculate CRC for MAC ds2432_crc ^= 0xffff; // invert CRC ds2432_buffer[2+1+8+0] = ds2432_crc>>0; // save CRC (LSB first) ds2432_buffer[2+1+8+1] = ds2432_crc>>8; // save CRC (MSB last) break; case DS2432_STATE_READ_AUTHENTICATED_PAGE_MAC: // padding byte transfer complete, send CRC onewire_slave_function_write(&ds2432_buffer[2+1+8+0], 2); // send CRC ds2432_state = DS2432_STATE_READ_AUTHENTICATED_PAGE_MACCRC; // update state break; case DS2432_STATE_READ_MEMORY_ADDRESS: if (0==ds2432_buffer[1] && ds2432_buffer[0]<0x97) { // target address is in EEPROM range onewire_slave_function_write(&ds2432_eeprom[ds2432_buffer[0]], LENGTH(ds2432_eeprom)-ds2432_buffer[0]); // send memory data until end of page ds2432_state = DS2432_STATE_READ_MEMORY_DATA; // update state } else { // target address is out of range ds2432_state = DS2432_STATE_IDLE; // return to idle state } break; default: // unknown or end state ds2432_state = DS2432_STATE_IDLE; // return to idle state break; } printf("1-Wire transfer complete\n"); } if (action) { // go to sleep if nothing had to be done, else recheck for activity action = false; } else { __WFI(); // go to sleep } } // main loop } /** @brief interrupt service routine called when tick passed on RTC */ void rtc_isr(void) { rtc_clear_flag(RTC_SEC); // clear flag rtc_internal_tick_flag = true; // notify to show new time }