diff --git a/flashloaders/stm32f0.s b/flashloaders/stm32f0.s index 23f1c43fe..76bfd9b95 100644 --- a/flashloaders/stm32f0.s +++ b/flashloaders/stm32f0.s @@ -30,15 +30,9 @@ copy: # add r3 to flash_base for support dual bank (see flash_loader.c) ldr r7, flash_base add r7, r7, r3 - ldr r6, flash_off_cr - add r6, r6, r7 ldr r5, flash_off_sr add r5, r5, r7 - # FLASH_CR = 0x01 (set PG) - ldr r4, =0x1 - str r4, [r6] - loop: # copy 2 bytes ldrh r4, [r0] @@ -68,18 +62,10 @@ wait: bgt loop exit: - # FLASH_CR &= ~1 - ldr r7, =0x1 - ldr r4, [r6] - bics r4, r4, r7 - str r4, [r6] - bkpt .align 2 flash_base: .word 0x40022000 -flash_off_cr: - .word 0x10 flash_off_sr: .word 0x0c diff --git a/src/common.c b/src/common.c index 4541aa31c..7ddd37032 100644 --- a/src/common.c +++ b/src/common.c @@ -87,9 +87,11 @@ #define FLASH_CR_PER 1 #define FLASH_CR_MER 2 #define FLASH_CR_OPTPG 4 +#define FLASH_CR_OPTER 5 #define FLASH_CR_STRT 6 #define FLASH_CR_LOCK 7 #define FLASH_CR_OPTWRE 9 +#define FLASH_CR_OBL_LAUNCH 13 #define STM32L_FLASH_REGS_ADDR ((uint32_t)0x40023c00) #define STM32L_FLASH_ACR (STM32L_FLASH_REGS_ADDR + 0x00) @@ -3137,17 +3139,6 @@ int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t *base, } int stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) { - - // According to DDI0419C, Table C1-7 firstly force halt - stlink_write_debug32(sl, STLINK_REG_DHCSR, - STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | - STLINK_REG_DHCSR_C_HALT); - // and only then disable interrupts - stlink_write_debug32(sl, STLINK_REG_DHCSR, - STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | - STLINK_REG_DHCSR_C_HALT | - STLINK_REG_DHCSR_C_MASKINTS); - // disable DMA set_dma_state(sl, fl, 0); @@ -3257,6 +3248,15 @@ int stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) { ELOG("stlink_flash_loader_init() == -1\n"); return (-1); } + + // unlock flash + unlock_flash_if(sl); + + // set programming mode + set_flash_cr_pg(sl, BANK_1); + if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) { + set_flash_cr_pg(sl, BANK_2); + } } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) { ILOG("Starting Flash write for H7\n"); @@ -3437,7 +3437,9 @@ int stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl, int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) { uint32_t dhcsr; - if ((sl->flash_type == STLINK_FLASH_TYPE_F4) || + if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || + (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) || + (sl->flash_type == STLINK_FLASH_TYPE_F4) || (sl->flash_type == STLINK_FLASH_TYPE_F7) || (sl->flash_type == STLINK_FLASH_TYPE_L4) || (sl->flash_type == STLINK_FLASH_TYPE_WB) || @@ -3446,8 +3448,9 @@ int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) { (sl->flash_type == STLINK_FLASH_TYPE_H7)) { clear_flash_cr_pg(sl, BANK_1); - if (sl->flash_type == STLINK_FLASH_TYPE_H7 && - sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { + if ((sl->flash_type == STLINK_FLASH_TYPE_H7 && + sl->chip_flags & CHIP_F_HAS_DUAL_BANK) || + sl->flash_type == STLINK_FLASH_TYPE_F1_XL) { clear_flash_cr_pg(sl, BANK_2); } lock_flash(sl); @@ -3840,6 +3843,64 @@ int stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr) { return (err); } +/** + * Write option bytes + * @param sl + * @param base option bytes to write + * @param addr of the memory mapped option bytes + * @param len of options bytes to write + * @return 0 on success, -ve on failure. + */ +static int stlink_write_option_bytes_f0( + stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) { + int ret = 0; + + if (len < 12 || addr != STM32_F0_OPTION_BYTES_BASE) { + WLOG("Only full write of option bytes area is supported\n"); + return -1; + } + + clear_flash_error(sl); + + WLOG("Erasing option bytes\n"); + + /* erase option bytes */ + stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_OPTWRE)); + ret = stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_STRT) | (1 << FLASH_CR_OPTWRE)); + if (ret) { + return ret; + } + + wait_flash_busy(sl); + + ret = check_flash_error(sl); + if (ret) { + return ret; + } + + WLOG("Writing option bytes to %#10x\n", addr); + + /* Set the Option PG bit to enable programming */ + stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTPG) | (1 << FLASH_CR_OPTWRE)); + + /* Use flash loader for write OP + * because flash memory writable by half word */ + flash_loader_t fl; + ret = stlink_flash_loader_init(sl, &fl); + if (ret) { + return ret; + } + ret = stlink_flash_loader_run(sl, &fl, addr, base, len); + if (ret) { + return ret; + } + + /* Reload option bytes */ + stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OBL_LAUNCH)); + + return check_flash_error(sl); +} + /** * Write option bytes * @param sl @@ -4192,6 +4253,18 @@ int stlink_read_option_control_register_f7(stlink_t *sl, return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte); } +/** + * Read option bytes + * @param sl + * @param option_byte value to read + * @return 0 on success, -ve on failure. + */ +int stlink_read_option_control_register_f0(stlink_t *sl, + uint32_t *option_byte) { + DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_OBR); + return stlink_read_debug32(sl, FLASH_OBR, option_byte); +} + /** * Read option bytes * @param sl @@ -4335,8 +4408,8 @@ int stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) { return -1; } - switch (sl->chip_id) { - case STLINK_CHIPID_STM32_F7XXXX: + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F7: return stlink_read_option_bytes_boot_add_f7(sl, option_byte); default: return -1; @@ -4356,12 +4429,14 @@ int stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) { return -1; } - switch (sl->chip_id) { - case STLINK_CHIPID_STM32_F7XXXX: + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F0: + case STLINK_FLASH_TYPE_F1_XL: + return stlink_read_option_control_register_f0(sl, option_byte); + case STLINK_FLASH_TYPE_F7: return stlink_read_option_control_register_f7(sl, option_byte); default: return -1; - // return stlink_read_option_control_register_generic(sl, option_byte); } } @@ -4378,8 +4453,8 @@ int stlink_read_option_control_register1_32(stlink_t *sl, return -1; } - switch (sl->chip_id) { - case STLINK_CHIPID_STM32_F7XXXX: + switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F7: return stlink_read_option_control_register1_f7(sl, option_byte); default: return -1; @@ -4441,6 +4516,10 @@ int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base, } switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F0: + case STLINK_FLASH_TYPE_F1_XL: + ret = stlink_write_option_bytes_f0(sl, base, addr, len); + break; case STLINK_FLASH_TYPE_F4: ret = stlink_write_option_bytes_f4(sl, base, addr, len); break; @@ -4511,6 +4590,95 @@ stlink_write_option_control_register_f7(stlink_t *sl, return ret; } + +/** + * Write option bytes + * @param sl + * @param option_byte value to write + * @return 0 on success, -ve on failure. + */ +static int +stlink_write_option_control_register_f0(stlink_t *sl, + uint32_t option_control_register) { + int ret = 0; + uint16_t opt_val[8]; + unsigned protection, optiondata; + uint16_t user_options, user_data, rdp; + unsigned option_offset, user_data_offset; + + ILOG("Asked to write option control register %#10x to %#010x.\n", + option_control_register, FLASH_OBR); + + /* Clear errors */ + clear_flash_error(sl); + + /* Retrieve current values */ + ret = stlink_read_debug32(sl, FLASH_OBR, &optiondata); + if (ret) { + return ret; + } + ret = stlink_read_debug32(sl, FLASH_WRPR, &protection); + if (ret) { + return ret; + } + + /* Translate OBR value to flash store structure + * F0: RM0091, Option byte description, pp. 75-78 + * F1: PM0075, Option byte description, pp. 19-22 + * F3: RM0316, Option byte description, pp. 85-87 */ + switch(sl->chip_id) + { + case 0x422: /* STM32F30x */ + case 0x432: /* STM32F37x */ + case 0x438: /* STM32F303x6/8 and STM32F328 */ + case 0x446: /* STM32F303xD/E and STM32F398xE */ + case 0x439: /* stm32f302x6/8 */ + case 0x440: /* stm32f05x */ + case 0x444: /* stm32f03x */ + case 0x445: /* stm32f04x */ + case 0x448: /* stm32f07x */ + case 0x442: /* stm32f09x */ + option_offset = 6; + user_data_offset = 16; + rdp = 0x55AA; + break; + default: + option_offset = 0; + user_data_offset = 10; + rdp = 0x5AA5; + break; + } + + user_options = (option_control_register >> option_offset >> 2) & 0xFFFF; + user_data = (option_control_register >> user_data_offset) & 0xFFFF; + +#define VAL_WITH_COMPLEMENT(v) (uint16_t)(((v)&0xFF) | (((~(v))<<8)&0xFF00)) + + opt_val[0] = (option_control_register & (1 << 1/*OPT_READOUT*/)) ? 0xFFFF : rdp; + opt_val[1] = VAL_WITH_COMPLEMENT(user_options); + opt_val[2] = VAL_WITH_COMPLEMENT(user_data); + opt_val[3] = VAL_WITH_COMPLEMENT(user_data >> 8); + opt_val[4] = VAL_WITH_COMPLEMENT(protection); + opt_val[5] = VAL_WITH_COMPLEMENT(protection >> 8); + opt_val[6] = VAL_WITH_COMPLEMENT(protection >> 16); + opt_val[7] = VAL_WITH_COMPLEMENT(protection >> 24); + +#undef VAL_WITH_COMPLEMENT + + /* Write bytes and check errors */ + ret = stlink_write_option_bytes_f0(sl, (uint8_t*)opt_val, STM32_F0_OPTION_BYTES_BASE, sizeof(opt_val)); + if (ret) + return ret; + + ret = check_flash_error(sl); + if (!ret) { + ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register, + FLASH_OBR); + } + + return ret; +} + /** * Write option bytes * @param sl @@ -4631,6 +4799,10 @@ int stlink_write_option_control_register32(stlink_t *sl, } switch (sl->flash_type) { + case STLINK_FLASH_TYPE_F0: + case STLINK_FLASH_TYPE_F1_XL: + ret = stlink_write_option_control_register_f0(sl, option_control_register); + break; case STLINK_FLASH_TYPE_F7: ret = stlink_write_option_control_register_f7(sl, option_control_register); break; diff --git a/src/stlink-lib/chipid.c b/src/stlink-lib/chipid.c index 187a6d957..3d4339526 100644 --- a/src/stlink-lib/chipid.c +++ b/src/stlink-lib/chipid.c @@ -57,6 +57,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0x5000, .bootrom_base = 0x1ffff000, .bootrom_size = 0x800, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { @@ -83,6 +85,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0x2800, .bootrom_base = 0x1ffff000, .bootrom_size = 0x800, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { @@ -162,6 +166,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0x10000, .bootrom_base = 0x1ffff000, .bootrom_size = 0x800, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { @@ -232,6 +238,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0x10000, .bootrom_base = 0x1fffb000, .bootrom_size = 0x4800, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { @@ -244,6 +252,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0x2000, // 0x1000 for low density devices .bootrom_base = 0x1ffff000, .bootrom_size = 0x800, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { @@ -283,6 +293,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0xa000, .bootrom_base = 0x1ffff000, .bootrom_size = 0x800, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { @@ -296,6 +308,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0xa000, .bootrom_base = 0x1ffff000, .bootrom_size = 0x800, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { @@ -307,6 +321,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0x8000, .bootrom_base = 0x1ffff000, .bootrom_size = 0x800, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { @@ -332,12 +348,14 @@ static const struct stlink_chipid_params devices[] = { .bootrom_base = 0x1fffC800, // "System memory" starting address from Table 2 .bootrom_size = 0x3000, // "System memory" byte size in hex from Table 2 + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, }, { // Use this as an example for mapping future chips: // RM0091 document was used to find these paramaters .chip_id = STLINK_CHIPID_STM32_F0, - .description = "F0xx", + .description = "F05x", .flash_type = STLINK_FLASH_TYPE_F0, .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735) .flash_pagesize = 0x400, // Page sizes listed in Table 4 @@ -345,6 +363,8 @@ static const struct stlink_chipid_params devices[] = { .bootrom_base = 0x1fffec00, // "System memory" starting address from Table 2 .bootrom_size = 0xC00, // "System memory" byte size in hex from Table 2 + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, }, { // RM0402 document was used to find these parameters @@ -387,6 +407,8 @@ static const struct stlink_chipid_params devices[] = { .bootrom_base = 0x1fffd800, // "System memory" starting address from Table 2 .bootrom_size = 0x2000, // "System memory" byte size in hex from Table 2 + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, }, { // Use this as an example for mapping future chips: @@ -400,12 +422,14 @@ static const struct stlink_chipid_params devices[] = { .bootrom_base = 0x1fffec00, // "System memory" starting address from Table 2 .bootrom_size = 0xC00, // "System memory" byte size in hex from Table 2 + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, }, { // Use this as an example for mapping future chips: // RM0091 document was used to find these paramaters .chip_id = STLINK_CHIPID_STM32_F0_SMALL, - .description = "F0xx small", + .description = "F03x", .flash_type = STLINK_FLASH_TYPE_F0, .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735) .flash_pagesize = 0x400, // Page sizes listed in Table 4 @@ -413,6 +437,8 @@ static const struct stlink_chipid_params devices[] = { .bootrom_base = 0x1fffec00, // "System memory" starting address from Table 2 .bootrom_size = 0xC00, // "System memory" byte size in hex from Table 2 + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, }, { // STM32F30x @@ -424,6 +450,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0xa000, .bootrom_base = 0x1fffd800, .bootrom_size = 0x2000, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { @@ -479,6 +507,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0x3000, .bootrom_base = 0x1fffd800, .bootrom_size = 0x2000, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { @@ -492,6 +522,8 @@ static const struct stlink_chipid_params devices[] = { .sram_size = 0x10000, // 3.3 Embedded SRAM .bootrom_base = 0x1fffd800, // 3.3.2 / Table 4 System Memory .bootrom_size = 0x2000, + .option_base = STM32_F0_OPTION_BYTES_BASE, + .option_size = 16, .flags = CHIP_F_HAS_SWO_TRACING, }, { diff --git a/src/stlink-lib/flash_loader.c b/src/stlink-lib/flash_loader.c index ba5efdb8e..4ec91258b 100644 --- a/src/stlink-lib/flash_loader.c +++ b/src/stlink-lib/flash_loader.c @@ -19,44 +19,33 @@ /* flashloaders/stm32f0.s -- compiled with thumb2 */ static const uint8_t loader_code_stm32vl[] = { 0x00, 0xbf, 0x00, 0xbf, - 0x0e, 0x4f, 0x1f, 0x44, - 0x0e, 0x4e, 0x3e, 0x44, - 0x0e, 0x4d, 0x3d, 0x44, - 0x4f, 0xf0, 0x01, 0x04, - 0x34, 0x60, 0x04, 0x88, - 0x0c, 0x80, 0x02, 0x30, - 0x02, 0x31, 0x4f, 0xf0, - 0x01, 0x07, 0x2c, 0x68, - 0x3c, 0x42, 0xfc, 0xd1, - 0x4f, 0xf0, 0x14, 0x07, - 0x3c, 0x42, 0x01, 0xd1, - 0x02, 0x3a, 0xf0, 0xdc, + 0x09, 0x4f, 0x1f, 0x44, + 0x09, 0x4d, 0x3d, 0x44, + 0x04, 0x88, 0x0c, 0x80, + 0x02, 0x30, 0x02, 0x31, 0x4f, 0xf0, 0x01, 0x07, - 0x34, 0x68, 0xbc, 0x43, - 0x34, 0x60, 0x00, 0xbe, + 0x2c, 0x68, 0x3c, 0x42, + 0xfc, 0xd1, 0x4f, 0xf0, + 0x14, 0x07, 0x3c, 0x42, + 0x01, 0xd1, 0x02, 0x3a, + 0xf0, 0xdc, 0x00, 0xbe, 0x00, 0x20, 0x02, 0x40, - 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 }; /* flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored */ static const uint8_t loader_code_stm32f0[] = { 0xc0, 0x46, 0xc0, 0x46, - 0x0c, 0x4f, 0x1f, 0x44, - 0x0c, 0x4e, 0x3e, 0x44, - 0x0c, 0x4d, 0x3d, 0x44, - 0x0c, 0x4c, 0x34, 0x60, + 0x08, 0x4f, 0x1f, 0x44, + 0x08, 0x4d, 0x3d, 0x44, 0x04, 0x88, 0x0c, 0x80, 0x02, 0x30, 0x02, 0x31, - 0x09, 0x4f, 0x2c, 0x68, + 0x06, 0x4f, 0x2c, 0x68, 0x3c, 0x42, 0xfc, 0xd1, - 0x08, 0x4f, 0x3c, 0x42, + 0x05, 0x4f, 0x3c, 0x42, 0x01, 0xd1, 0x02, 0x3a, - 0xf2, 0xdc, 0x05, 0x4f, - 0x34, 0x68, 0xbc, 0x43, - 0x34, 0x60, 0x00, 0xbe, + 0xf2, 0xdc, 0x00, 0xbe, 0x00, 0x20, 0x02, 0x40, - 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 @@ -159,6 +148,17 @@ int stlink_flash_loader_init(stlink_t *sl, flash_loader_t *fl) { size_t size = 0; uint32_t dfsr, cfsr, hfsr; + /* Interrupt masking. + * According to DDI0419C, Table C1-7 firstly force halt */ + stlink_write_debug32(sl, STLINK_REG_DHCSR, + STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | + STLINK_REG_DHCSR_C_HALT); + /* and only then disable interrupts */ + stlink_write_debug32(sl, STLINK_REG_DHCSR, + STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | + STLINK_REG_DHCSR_C_HALT | + STLINK_REG_DHCSR_C_MASKINTS); + // allocate the loader in SRAM if (stlink_flash_loader_write_to_sram(sl, &fl->loader_addr, &size) == -1) { WLOG("Failed to write flash loader to sram!\n"); diff --git a/src/stlink-lib/logging.c b/src/stlink-lib/logging.c index 87978230d..817f3d68e 100644 --- a/src/stlink-lib/logging.c +++ b/src/stlink-lib/logging.c @@ -8,6 +8,7 @@ #include #include #include +#define __STDC_WANT_LIB_EXT1__ 1 #include #include "logging.h" @@ -29,10 +30,22 @@ int ugly_log(int level, const char *tag, const char *format, ...) { va_list args; va_start(args, format); time_t mytt = time(NULL); - struct tm *tt; - tt = localtime(&mytt); - fprintf(stderr, "%d-%02d-%02dT%02d:%02d:%02d ", tt->tm_year + 1900, - tt->tm_mon + 1, tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec); + + struct tm *ptt; +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) // C11 + struct tm tt; + ptt = &tt; +# if defined (_WIN32) || defined(__STDC_LIB_EXT1__) + localtime_s(&tt, &mytt); +# else + localtime_r(&mytt, &tt); +# endif +#else + ptt = localtime(&mytt); +#endif + + fprintf(stderr, "%d-%02d-%02dT%02d:%02d:%02d ", ptt->tm_year + 1900, + ptt->tm_mon + 1, ptt->tm_mday, ptt->tm_hour, ptt->tm_min, ptt->tm_sec); switch (level) { case UDEBUG: