Автоматизация инкремента версий в keil

Опишу небольшой заголовочный файлик, который помогает мне не заботиться о том, что бы у каждой вновь скомпилированный прошивки была новая версия.

Люблю Visual Studio за механизм, позволяющий инкрементировать версию собранного проекта, и также сильно ненавижу Keil за отсутствие таковой возможности .

Для чего это нужно? Представим ситуацию, когда очень много устройств, а ПО всё время дорабатывается, или же прошивкой новой версии занимается другой человек, ... много может быть причин, но не всегда можно отследить в каком устройстве какая версия зашита. Да и не всегда при сборки проекта вспоминаешь что нужно увеличить номер версии.

Стало интересно?

Все мы привыкли к нумерации версий вида 1.2.3456. Я тоде привык к такому виду, но так как программисты существа ленивые и я тому подтверждение решил отказаться от такой нумерации ввиду её сложности при реализации.

Пришлось бы писать небольшую утилитку которая бы при запуске сборки автоматически инкрементировала число в каком-нибудь .hфайле. И я всерьёз об этом задумывался.

Но всё изменилось после того, как я увидел как обозначают версию прошивки производители ЭБУ двигателя на авто. Код версии состоял из непонятной последовательности букв и цифр.

Почему бы и мне не сделать также.

Код до безобразия прост, все его содержимое это просто переработка макросов __DATE__ и __TIME__, поэтому думаю не имеет смысла его объяснять.

/**
  *********************************************************************************************************
  *
  * This file is part of Devprodest Lib.
  * 
  *   Devprodest Lib 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.
  * 
  *   Devprodest Lib 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 Devprodest Lib.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * @file version.c
  * @brief Реализация автоматически изменяемого номера версии в зависимости от времени компиляции
  * @version 1.0
  * @authors Zaikin Denis (ZD)
  * 
  * @copyright GNU General Public License
  *********************************************************************************************************
  */
#pragma once

/**----- Макросы -----------------------------------------------------------------------------------------*/
// __DATE__ "Jan 27 2012"
//           01234567890

// __TIME__ "21:06:19"
//           01234567

#define VERSION_Y0 (__DATE__[ 7] - '0')
#define VERSION_Y1 (__DATE__[ 8] - '0')
#define VERSION_Y2 (__DATE__[ 9] - '0')
#define VERSION_Y3 (__DATE__[10] - '0')

#define VERSION_M_JAN (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n')
#define VERSION_M_FEB (__DATE__[0] == 'F')
#define VERSION_M_MAR (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r')
#define VERSION_M_APR (__DATE__[0] == 'A' && __DATE__[1] == 'p')
#define VERSION_M_MAY (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y')
#define VERSION_M_JUN (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n')
#define VERSION_M_JUL (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l')
#define VERSION_M_AUG (__DATE__[0] == 'A' && __DATE__[1] == 'u')
#define VERSION_M_SEP (__DATE__[0] == 'S')
#define VERSION_M_OCT (__DATE__[0] == 'O')
#define VERSION_M_NOV (__DATE__[0] == 'N')
#define VERSION_M_DEC (__DATE__[0] == 'D')

#define VERSION_M0 ((VERSION_M_OCT || VERSION_M_NOV || VERSION_M_DEC) ? 1 : 0)
#define VERSION_M1 \
    ( \
        (VERSION_M_JAN) ? 1 : \
        (VERSION_M_FEB) ? 2 : \
        (VERSION_M_MAR) ? 3 : \
        (VERSION_M_APR) ? 4 : \
        (VERSION_M_MAY) ? 5 : \
        (VERSION_M_JUN) ? 6 : \
        (VERSION_M_JUL) ? 7 : \
        (VERSION_M_AUG) ? 8 : \
        (VERSION_M_SEP) ? 9 : \
        (VERSION_M_OCT) ? 0 : \
        (VERSION_M_NOV) ? 1 : \
        (VERSION_M_DEC) ? 2 : \
                          0   \
    )

#define VERSION_D0 ((__DATE__[4] >= '0') ? (__DATE__[4] - '0') : 0)
#define VERSION_D1 (__DATE__[ 5] - '0')

#define VERSION_HOUR0 (__TIME__[0] - '0')
#define VERSION_HOUR1 (__TIME__[1] - '0')

#define VERSION_MIN0 (__TIME__[3] - '0')
#define VERSION_MIN1 (__TIME__[4] - '0')

#define VERSION_SEC0 (__TIME__[6] - '0')
#define VERSION_SEC1 (__TIME__[7] - '0')

#define VERSION_DAY       (10U * VERSION_D0 + VERSION_D1)
#define VERSION_MONTH     (10U * VERSION_M0 + VERSION_M1)
#define VERSION_YEAR      (10U * VERSION_Y2 + VERSION_Y3)

#define VERSION_HOUR      (10U * VERSION_HOUR0 + VERSION_HOUR1)
#define VERSION_MIN       (10U * VERSION_MIN0 + VERSION_MIN1)
#define VERSION_SEC       (10U * VERSION_SEC0 + VERSION_SEC1)

#define VERSION_BCD_DAY   (16U * VERSION_D0 + VERSION_D1)
#define VERSION_BCD_MONTH (16U * VERSION_M0 + VERSION_M1)
#define VERSION_BCD_YEAR  (16U * VERSION_Y2 + VERSION_Y3)

#define VERSION_BCD_HOUR  (16U * VERSION_HOUR0 + VERSION_HOUR1)
#define VERSION_BCD_MIN   (16U * VERSION_MIN0 + VERSION_MIN1)
#define VERSION_BCD_SEC   (16U * VERSION_SEC0 + VERSION_SEC1)

/** 
Формат данных 0xDDMYYmmm:
    DD - День = 0x00..0x1F
    M - месяц = 0x0..0xC
    YY - Год = 0x00..0x63
    mmm - минуты = часы * минуты = 000...5A0
*/
#define VERSION_INT     ( VERSION_DAY << 24U | VERSION_MONTH << 20U | VERSION_YEAR << 12U | (VERSION_HOUR * VERSION_MIN) ) 

/**----- Проверка макросов -------------------------------------------------------------------------------*/

/**----- КОНЕЦ ФАЙЛА -------------------------------------------------------------------------------------*/

Частично реализация была взята с StackOwerflow. К сожалению уже не помню откуда, но можно поискать на предмет автоинкремента версий.

Основная фишка это компоновка полученых значений в полноценный код версии - макрос VERSION_INT, из которого получается весьма интересные значения:

  • 27.08.18 11:56 - 0x1B812268;
  • 15.12.18 23:32 - 0x0FC122E0;
  • и тд.

Она имеет несколько преимуществ:

  • всё число имеет размер 4 байта, что для меня было весьма критично;
  • версия при каждой компиляции получается всегда разной за счет произведения значений часов и минут, не думаю что кто-то компилирует проект чаще.

И как всегда - хорошего кодинга.