Модуль «Календарь»

C++
void Calendar()
{
    // CYear Входящие данные: год для расчета
    // CMonth Входящие данные: месяц для расчета
    // CDay Входящие данные: день для расчета
    // int change_data[43] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // Массив для изменения текущей даты touch screen
    byte dwin_day[] = {0x5A, 0xA5, 0x05, 0x82, 0X57, 0x00, 0x00, 0x00};   // Расчетное значение день месяца
    byte dwin_month[] = {0x5A, 0xA5, 0x05, 0x82, 0X58, 0x00, 0x00, 0x00}; // Расчетное значение номера месяца
    byte dwin_year[] = {0x5A, 0xA5, 0x05, 0x82, 0X59, 0x00, 0x00, 0x00};  // Расчетное значение год
    int dwin_year_v;
    int dwin_month_v;
    rtc.DSread();      // Чтение модуля RTC
    int era_year = 1;   // Переменная указывает на то, является ли искомый год годом нашей эры (era_year=1), либо годом до н.э. (era_year=0). Вычисляется из положительного, либо отрицательного CYear
    int month_first_day = 0; // Переменная для хранения дня недели первого числа искомого месяца (Month First Day)
    int type_1_leap = 0;     // Количество накопившихся до искомой даты исключений из следования високосных лет Григорианского календаря. Год кратный 100, но не кратный 400 - не високосный. Первый тип исключений
    int type_2_leap = 0;     // Количество накопившихся до искомой даты исключений из следования високосных лет Григорианского календаря. Год кратный 400 - високосный. Второй тип исключений
    //int start_week_day = 7;  // Порядковый номер дня недели даты отсчета, то есть 01.01.0001 года, то есть суббота (6). Это точка отсчета для определения 1-го января искомого года ENG-7 RUS-6
    int array_grid[42];      // Массив календаря. С 0-го до 41-го значения, то есть всего 42 значения для 6-и рядов из 7-и столбцов (сетка календаря)
    int array_grid_10_1582[] = {1, 2, 3, 4, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};        // Календарь октября 1582 - исключение;
    int array_grid_11_1582[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0};    // Календарь ноября 1582 - исключение;
    int array_grid_12_1582[] = {29, 30, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 1, 2, 0, 0, 0, 0, 0, 0, 0}; // Календарь декабря 1582 - исключение;
    int end_day_month[]{31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};                                                                                                                // Количество дней в месяцах года. Ряд массива смещен для удобства расчетов end_day_month[0]=31 - условный "январь" предыдущего года
    char str_hex[10]; // Служебные переменные для перевода из HEX в DEC
    unsigned char A[] = {0x5A, 0xA5, 0x05, 0x82, 0x00, 0x00, 0x00, 0x00}; // Передаваемый в порт массив
    int Registr_ID = 6000 - 10; // Начальное значение регистра адресов, куда будут вписываться числа месяца
    int Registr = 0;  // Вычисляемое значение регистра (переменной), в который будет записано значение даты
    float FirstDay;   // Переменная дня недели 01 января искомого года
    int CEnd = 0;    // Переменная определяет, когда перестать печатать дни предстоящего месяца (загасить лишнюю строку)
    double xxx;
    // Serial.println("debug4");

    if (CYear == 1582 && (CMonth == 10 || CMonth == 11 || CMonth == 12))
        goto Iskl; // Пропускаем расчет, если октябрь-декабрь 1582 года, то есть исключения
    // ### Вычисление эры ###
    if (CYear < 0)
    {
        CYear = abs(CYear);
        era_year = 0;
    }
    // ### Вычисление дня недели первого числа искомого месяца ###
    for (int i = cal_lang; i <= CMonth; i++) // было RUS i=2 ENG i=5
    {
        // Serial.println(i);
        month_first_day += end_day_month[i - 1]; // Накапливаем смещение дня недели по каждому из прошедших в году месяцев
    }
    if ((int(CYear) > 1582 && ((int(CYear) % 4 == 0 && int(CYear) % 100 != 0) || int(CYear) % 400 == 0)) && era_year == 1)
    {
        end_day_month[2] = 29; // Прибавляем 29 февраля в високосных годах Григорианского календаря и смещаем один день с марта
        if (CMonth > 2)
            month_first_day++;
    }
    if ((int(CYear) < 1583 && int(CYear) % 4 == 0) && era_year == 1)
    {
        end_day_month[2] = 29; // Прибавляем 29 февраля в високосных годах Юлианского календаря н.э. и смещаем один день с марта
        if (CMonth > 2)
            month_first_day++;
    }
    if (((int(CYear - 1) % 4 == 0) && era_year == 0) || (CYear == 1 && era_year == 0))
    {
        end_day_month[2] = 29; // Прибавляем 29 февраля в високосных годах Юлианского календаря до н.э. и смещаем один день с марта
        if (CMonth > 2)
            month_first_day++;
    }
    if (CYear > 1582 && era_year == 1)
    {
        start_week_day = 10; // Изменение параметров для лет, после введения Григорианского календаря в октябре 1582 года. Меняется start_week_day и из расчета накопленных високосных лет уходят два типа исключений (type_1_leap и type_2_leap)
        type_1_leap = (CYear - 1582) / 100;
        type_2_leap = (CYear - 1582) / 400;
    }

    // ### Главный расчет ###
    if (era_year == 1)
    { // Блок вычислений для определения дня недели 01 января лет н.э.
        // FirstDay = round(modf(((CYear - 1 + (ceil(CYear / 4) - 1 - (type_1_leap - type_2_leap))) + month_first_day) / 7, &xxx) * 7) + start_week_day; // Расчет дня недели 1-го января искомого года. ПН-1, ВТ-2, и т.д.
        FirstDay = round(modf(((CYear - 1 + (ceil(CYear / 4) - 1 - (type_1_leap - type_2_leap))) + month_first_day) / 7, &xxx) * 7) + start_week_day;
        if (FirstDay > 7)
            FirstDay = roundf(modf(float(FirstDay / 7), &xxx) * 7);
        if (FirstDay == 0)
            FirstDay = 7; // Корректировка значения если число вышло за 7, возвращение его в диапазон 1-7
    }
    if (era_year == 0 && CYear < 5)
    {
        FirstDay = round((modf(float((5 - CYear + month_first_day) / 7), &xxx)) * 7); // день недели искомого месяца первых 4-х лет до нашей эры
        if (FirstDay == 0)
            FirstDay = 7;
    }
    if (era_year == 0 && CYear >= 5)
    {
        FirstDay = (7 - abs(round(modf((4 - floor((CYear - 1) / 4) - CYear + 1) / 7, &xxx) * 7))) + round(modf(float(month_first_day) / 7, &xxx) * 7); // день недели искомого месяца с 5-го года до нашей эры и далее
        if (FirstDay > 7)
            FirstDay = round(modf(float(FirstDay / 7), &xxx) * 7);
    }
    // ### Публикация ###
    for (int i = 1; i < FirstDay; i++)
    {
        array_grid[i - 1] = end_day_month[CMonth - 1] - (FirstDay - 1) + i; // Цикл заполнения календаря предыдущего месяца
    }
    for (int i = 0; i < 43; i++)
        change_data[i] = 0;
    for (int i = 1; i <= end_day_month[CMonth]; i++)
    {
        array_grid[i - 1 + int(FirstDay) - 1] = i;     // Цикл заполнения календаря текущего месяца
        change_data[int(FirstDay) + i - 1] = i; // Заполнение глобального массива для изменения текущего числа
    }

    // for (int d = 0; d < 43; d++) Serial.println(change_data[d]);  // Печать массива, который для изменения даты в модуле часов

    for (int i = end_day_month[CMonth] + FirstDay - 1; i <= 41; i++)
    {
        if (CEnd != 1)
            array_grid[i] = i - (end_day_month[CMonth] - 1) - (FirstDay - 1); // Цикл заполнения календаря предстоящего месяца
        else
            array_grid[i] = 0;
        if (i == 28 || i == 35)
        {
            array_grid[i] = 0;
            CEnd = 1;
        }
    }
// ### Исключения 1582 года ###
Iskl: // Метка, куда переходит выполнение программы если 10, 11, 12 месяц 1582 года
    if (CYear == 1582 && CMonth == 10)
    { // Если октябрь 1982
        for (int i = 0; i <= 41; i++)
            array_grid[i] = array_grid_10_1582[i]; // Перезаполняем массив исходя из массива исключений
        end_day_month[10] = 21;                  // Дней тогда было всего 21
        FirstDay = 1;                // Начинался с понедельника
    }
    if (CYear == 1582 && CMonth == 11)
    { // Если ноябрь 1982
        for (int i = 0; i <= 41; i++)
            array_grid[i] = array_grid_11_1582[i]; // Перезаполняем массив исходя из массива исключений
        FirstDay = 1;                // Начинался с понедельника
    }
    if (CYear == 1582 && CMonth == 12)
    { // Если декабрь 1982
        for (int i = 0; i <= 41; i++)
            array_grid[i] = array_grid_12_1582[i]; // Перезаполняем массив исходя из массива исключений
        FirstDay = 3;                // Начинался со среды
    }

    // for (int i=0; i<=41; i++) {Serial.print(array_grid[i]);Serial.print("#");} //Печать для проверки правильности расчетов HEX
    // Serial.println();Serial.print("01.");Serial.print(CMonth);Serial.print(".");Serial.print(CYear, 0);Serial.print(" = ");Serial.print(int(FirstDay));Serial.print(" era_year=");Serial.println(era_year); // Печать дня недели первого января искомого года для контроля
    //  ### Цикл печати ###
    for (int i = 1; i <= 42; i++)
    {
        itoa(Registr_ID + i * 10, str_hex, 10);   // Преобразуем int в строку в DEC. Будем считать, что это HEX
        Registr = (int)strtol(str_hex, NULL, 16); // Получаем из HEX-строки новое число. Присваиваем переведенное из HEX в DEC число
        A[4] = highByte(Registr);                 // Меняем значение регистра и числа в массиве
        A[5] = lowByte(Registr);
        /* Выбор блока иконок
          1-й блок картинок 01-31: обычные дни ПН-ПТ - по умолчанию
          2-й блок картинок 32-62: обычные СБ-ВС
          3-й блок картинок 63-93: ПН-ПТ - сегодня
          4-й блок картинок 94-124: СБ-ВС - сегодня
          5-й блок картинок 125-156: дни других месяцев (хвосты) */
        int Blok = 0; // Переменная, которая определяет первый файл типа иконки числа, соответствующих определенному дню месяца календаря
        if (i % 7 == 0 || (i + 1) % 7 == cal_block_lang) // RUS (i + 1) % 7 == 0) ENG (i + 1) % 7 == 2)
        {
            Blok = 31; // 2-й блок иконок: обычные Сб и Вс
            if ((array_grid[i - 1] == CDay) && (CMonth == (rtc.month) && CYear == float(rtc.year) + 2000))
                Blok = 93; // 4-й блок: Сб и Вс - текущая дата
        }
        else if ((array_grid[i - 1] == CDay) && (CMonth == (rtc.month) && CYear == float(rtc.year) + 2000))
        {
            Blok = 62; // 3-й блок иконок: ПН-ПТ - текущая дата
        }
        if (i < FirstDay || i > FirstDay - 1 + end_day_month[CMonth])
            Blok = 124; // 5-й блок. Даты соседних месяцев
        if (array_grid[i - 1] == 0)
            Blok = 0;
        A[7] = array_grid[i-1] + Blok; // Значение + выбор блока картинок
        SerialDwin.write(A, 8); // Выгружаем в порт
        // Serial.print(Registr);Serial.print(":");Serial.print(A[7]);Serial.println("#"); //Печать для проверки правильности расчетов HEX
    }
    // Serial.print("№№№№№№№№№№");
    dwin_year_v = (CYear);
    dwin_year[6] = highByte(dwin_year_v);
    dwin_year[7] = lowByte(dwin_year_v);
    SerialDwin.write(dwin_year, 8);
    // SerialDwin.flush();
    dwin_month_v = (CMonth);
    dwin_month[6] = highByte(dwin_month_v);
    dwin_month[7] = lowByte(dwin_month_v);
    SerialDwin.write(dwin_month, 8);
}