Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2017:envi-logger

Rozdíly

Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.

Odkaz na výstup diff

Obě strany předchozí revize Předchozí verze
Následující verze
Předchozí verze
2017:envi-logger [2018/01/22 05:09]
Miroslav Waldecker [Konfigurácia hodín]
2017:envi-logger [2018/01/22 06:23] (aktuální)
Miroslav Waldecker [Záver]
Řádek 32: Řádek 32:
   - Konfigurácia pinov   - Konfigurácia pinov
   - Konfigurácia hodinových domén   - Konfigurácia hodinových domén
-  - Kofigurácia periférií a komunikácia ​s obvodmi k nim pripojenými+  - Kofigurácia periférií a komunikácia
   - Správa displeja   - Správa displeja
   - Ukladanie údajov   - Ukladanie údajov
Řádek 190: Řádek 190:
 Zdrojom hodín pre RTC časovač a prevodník snímača tlaku je použitý oscilátor s kryštálom 32,768kHz. Ten funguje aj po vypnutá napájania. Výstup z neho je smerovaný na výstupný pin procesora CLKOUT. ​ Zdrojom hodín pre RTC časovač a prevodník snímača tlaku je použitý oscilátor s kryštálom 32,768kHz. Ten funguje aj po vypnutá napájania. Výstup z neho je smerovaný na výstupný pin procesora CLKOUT. ​
  
-===== Kofigurácia periférií a komunikácia s obvodmi k nim pripojenými ​=====+===== Kofigurácia periférií a komunikácia ​===== 
 +==== TGS4161 a ADC ==== 
 + 
 +Pre zber údajov zo senzoru koncentrácie j epoužitý interný prevodník ADC v single ended móde a internou referenciou. Funkcia pre nastavenie periférií:​ 
 + 
 +<code c> 
 +void Init_CO(void) { 
 +//Set GPIO for heater control 
 + gpio_pin_config_t heater = { kGPIO_DigitalOutput,​ 0, }; 
 + GPIO_PinInit(GPIOB,​ 20U, &​heater);​ 
 +//Get ADC default config 
 + ADC16_GetDefaultConfig(&​adc16ConfigStruct);​ 
 + 
 + adc16ConfigStruct.resolution = kADC16_ResolutionSE16Bit;​ 
 + ADC16_Init(DEMO_ADC16_BASE,​ &​adc16ConfigStruct);​ 
 + ADC16_EnableHardwareTrigger(DEMO_ADC16_BASE,​ false); 
 + if (kStatus_Success == ADC16_DoAutoCalibration(DEMO_ADC16_BASE)) { 
 + PRINTF("​ADC16_DoAutoCalibration() Done.\r\n"​);​ 
 + } else { 
 + PRINTF("​ADC16_DoAutoCalibration() Failed.\r\n"​);​ 
 +
 + 
 + adc16ChannelConfigStruct.channelNumber = DEMO_ADC16_USER_CHANNEL;​ 
 + adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false; 
 +
 +//Set heater on 
 +void Start_sensor(void) { 
 + GPIO_SetPinsOutput(GPIOB,​ 1U << 20U); 
 +
 +//Reset heater 
 +void Stop_sensor(void) { 
 + GPIO_ClearPinsOutput(GPIOB,​ 1U << 20U); 
 +
 + 
 +</​code>​ 
 +Funkcia pre čitanie vzorky vzčítanej prevodníkom - ADC0 kanál 0 single ended: 
 +<code c> 
 +int32_t get_adc(void) { 
 + 
 + ADC16_SetChannelConfig(DEMO_ADC16_BASE,​ DEMO_ADC16_CHANNEL_GROUP,​ 
 + &​adc16ChannelConfigStruct);​ 
 + while (0U 
 + == (kADC16_ChannelConversionDoneFlag 
 + & ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE,​ 
 + DEMO_ADC16_CHANNEL_GROUP))) 
 +
 + return (ADC16_GetChannelConversionValue(DEMO_ADC16_BASE,​ 
 + DEMO_ADC16_CHANNEL_GROUP));​ 
 +
 +</​code>​ 
 + 
 +Prepočet hodnoty zmeranej AD prevodníkom na koncentráciu ppm CO2: 
 +<code c> 
 +int32_t get_concentration(void){ 
 + float adc_mv; 
 + float sens_mv; 
 + float adc_mv_min;​ 
 + float sens_mv_min;​ 
 + float delta_emf;​ 
 + int32_t co2ppm; 
 + 
 +//Prepocet na rozsah + kalibracia 
 + adc_mv_min = 5.03321924e-5 * (float)adc_val_min;​ 
 + adc_mv = 5.03321924e-5 * (float)get_adc();​ 
 +//Prepocet prevodová charakteristika 
 + sens_mv_min = (0.39 - 0.2*adc_mv_min)*1000.0;​ 
 + sens_mv = (0.39 - 0.2*adc_mv)*1000.0;​ 
 +//Prepocet na ppm zo semilox charakteristiky v datasheet-e 
 + delta_emf = sens_mv_min - sens_mv; 
 + sens_mv = powf(10.0,​(0.0161*delta_emf + 2.5441)); 
 + 
 + co2ppm = (int32_t)sens_mv;​ 
 + return(co2ppm);​ 
 + 
 +
 +</​code>​ 
 + 
 +==== SHT21, HP03M a ADC ==== 
 + 
 +Nastavenie IIC periférie a GPIO pre ovládanie XCLR - reset signálu pre HP03M. 
 +<code c> 
 +void Init_iic(void) { 
 + BOARD_I2C_ConfigurePins();​ 
 + gpio_pin_config_t xclr = { kGPIO_DigitalOutput,​ 0, }; 
 + GPIO_PinInit(GPIOB,​ 10U, &​xclr);​ 
 + 
 + I2C_MasterGetDefaultConfig(&​masterConfig);​ 
 + masterConfig.baudRate_Bps = I2C_BAUDRATE;​ 
 + 
 + sourceClock = I2C_MASTER_CLK_FREQ;​ 
 + 
 + I2C_MasterInit(I2C0,​ &​masterConfig,​ sourceClock);​ 
 + 
 +
 +</​code>​ 
 + 
 +Komunikácia ​SHT21. Funkcie pre čítanie teploty a vlhkosti a ich prepočet na °C a %RH: 
 +<code c> 
 +float read_temp() { 
 + 
 + uint8_t data[5]; 
 + uint16_t itemp; 
 + float ftemp; 
 + 
 + data[0] ​(uint8_t) SHT21_TRIG_TEMP_HM;​ 
 + while (kStatus_Success 
 + !I2C_MasterStart(I2C0,​ SHT21_I2C_ADDRESS,​ kI2C_Write)) 
 +
 + 
 + while (kStatus_Success 
 + !I2C_MasterWriteBlocking(I2C0,​ data, 1, kI2C_TransferNoStopFlag)) 
 +
 + 
 + while (kStatus_Success 
 + !I2C_MasterRepeatedStart(I2C0,​ SHT21_I2C_ADDRESS,​ kI2C_Read)) 
 +
 + 
 + while (kStatus_Success 
 + !I2C_MasterReadBlocking(I2C0,​ data, 3, kI2C_TransferCompleteFlag)) 
 +
 + itemp = data[0]; 
 + itemp = itemp << 8; 
 + itemp |= data[1]; 
 + itemp &= 0xFFFC; 
 + ftemp = -48.85 + (175.72 * ((float) itemp)) / 65536.0; 
 + 
 + return (ftemp); 
 +
 + 
 +float read_hum() { 
 + 
 + uint8_t data[5]; 
 + uint16_t ihum; 
 + float fhum; 
 + 
 + data[0] = (uint8_t) SHT21_TRIG_HUMIDITY_HM;​ 
 + while (kStatus_Success 
 + != I2C_MasterStart(I2C0,​ SHT21_I2C_ADDRESS,​ kI2C_Write)) 
 +
 + while (kStatus_Success 
 + != I2C_MasterWriteBlocking(I2C0,​ data, 1, kI2C_TransferNoStopFlag)) 
 +
 + while (kStatus_Success 
 + != I2C_MasterRepeatedStart(I2C0,​ SHT21_I2C_ADDRESS,​ kI2C_Read)) 
 +
 +  
 + while (kStatus_Success 
 + != I2C_MasterReadBlocking(I2C0,​ data, 3, kI2C_TransferCompleteFlag)) 
 +
 + ihum = data[0]; 
 + ihum = ihum << 8; 
 + ihum |= data[1]; 
 + ihum &= 0xFFFC; 
 + fhum = -6.0 + 125.0 * ((float) ihum) / 65536.0; 
 + return (fhum); 
 +
 +</​code>​ 
 + 
 +Komunikácia s HP03M a výpočet barometrického tlaku, je zaujímavé,​ že tento senzor obsahuje 2 obvody, v jednom sú kalibračné a kompenzačné údaje, druhý je AD prevodník s meraním teploty pre kompenzáciu a tlaku. Každý z týchto obvodov má inú adresu a iný spôsob ich čítania:​ 
 + 
 +<code c> 
 +float read_pressure() { 
 + 
 + uint8_t eeprom_data[18];​ 
 + uint16_t iPressure;​ 
 + uint16_t iTemperature;​ 
 + uint8_t data_index;​ 
 + uint16_t C[7]; 
 + uint8_t coef_A; 
 + uint8_t coef_B; 
 + uint8_t coef_C; 
 + uint8_t coef_D; 
 + float fTemp; 
 + float fPressure;​ 
 + float dut; 
 + float offset; 
 + float sensitivity;​ 
 + float xpress; 
 + 
 + GPIO_PinWrite(GPIOB,​ 10U, 1); 
 + 
 +  
 + eeprom_data[0] = 0x10; 
 +  
 + while (kStatus_Success != I2C_MasterStop(I2C0)) 
 +
 + 
 +  
 + while (kStatus_Success 
 + != I2C_MasterStart(I2C0,​ HP03_I2C_EEPROM_ADDRESS,​ kI2C_Write)) 
 +
 +  
 + while (kStatus_Success 
 + != I2C_MasterWriteBlocking(I2C0,​ eeprom_data,​ 1, 
 + kI2C_TransferNoStopFlag)) 
 +
 +  
 + while (kStatus_Success 
 + != I2C_MasterRepeatedStart(I2C0,​ HP03_I2C_EEPROM_ADDRESS,​ kI2C_Read)) 
 +
 +  
 + while (kStatus_Success 
 + != I2C_MasterReadBlocking(I2C0,​ eeprom_data,​ 18, 
 + kI2C_TransferCompleteFlag)) 
 +
 + 
 + for (data_index = 0; data_index <= 6; data_index++) { 
 + C[data_index] = eeprom_data[data_index * 2]; 
 + C[data_index] = C[data_index] << 8; 
 + C[data_index] |= eeprom_data[(data_index * 2) + 1]; 
 +
 + 
 + coef_A = eeprom_data[14];​ 
 + coef_B = eeprom_data[15];​ 
 + coef_C = eeprom_data[16];​ 
 + coef_D = eeprom_data[17];​ 
 + 
 +  
 + while (kStatus_Success 
 + != I2C_MasterStart(I2C0,​ HP03_I2C_AD_ADDRESS,​ kI2C_Write)) 
 +
 + 
 + eeprom_data[0] = 0xFF; 
 + eeprom_data[1] = 0xF0; 
 +  
 + while (kStatus_Success 
 + != I2C_MasterWriteBlocking(I2C0,​ eeprom_data,​ 2, 
 + kI2C_TransferCompleteFlag)) 
 +
 +  
 +  
 + while (kStatus_Success 
 + != I2C_MasterStart(I2C0,​ HP03_I2C_AD_ADDRESS,​ kI2C_Write)) 
 +
 + eeprom_data[0] = 0xFD; 
 +  
 + while (kStatus_Success 
 + != I2C_MasterWriteBlocking(I2C0,​ eeprom_data,​ 1, 
 + kI2C_TransferNoStopFlag)) 
 +
 +  
 + while (kStatus_Success 
 + != I2C_MasterRepeatedStart(I2C0,​ HP03_I2C_AD_ADDRESS,​ kI2C_Read)) 
 +
 +  
 + while (kStatus_Success 
 + != I2C_MasterReadBlocking(I2C0,​ eeprom_data,​ 2, 
 + kI2C_TransferCompleteFlag)) 
 +
 + 
 + iPressure = eeprom_data[0];​ 
 + iPressure = iPressure << 8; 
 + iPressure |= eeprom_data[1];​ 
 + 
 +  
 + while (kStatus_Success 
 + != I2C_MasterStart(I2C0,​ HP03_I2C_AD_ADDRESS,​ kI2C_Write)) 
 +
 + 
 + eeprom_data[0] = 0xFF; 
 + eeprom_data[1] = 0xE8; 
 +  
 + while (kStatus_Success 
 + != I2C_MasterWriteBlocking(I2C0,​ eeprom_data,​ 2, 
 + kI2C_TransferCompleteFlag)) 
 +
 +  
 +  
 + while (kStatus_Success 
 + != I2C_MasterStart(I2C0,​ HP03_I2C_AD_ADDRESS,​ kI2C_Write)) 
 +
 + eeprom_data[0] = 0xFD; 
 +  
 + while (kStatus_Success 
 + != I2C_MasterWriteBlocking(I2C0,​ eeprom_data,​ 1, 
 + kI2C_TransferNoStopFlag)) 
 +
 +  
 + while (kStatus_Success 
 + != I2C_MasterRepeatedStart(I2C0,​ HP03_I2C_AD_ADDRESS,​ kI2C_Read)) 
 +
 +  
 + while (kStatus_Success 
 + != I2C_MasterReadBlocking(I2C0,​ eeprom_data,​ 2, 
 + kI2C_TransferCompleteFlag)) 
 +
 + 
 + iTemperature = eeprom_data[0];​ 
 + iTemperature = iTemperature << 8; 
 + iTemperature |= eeprom_data[1];​ 
 + GPIO_PinWrite(GPIOB,​ 10U, 0); 
 + 
 + fTemp = (float)iTemperature;​ 
 + 
 + if(iTemperature >= C[4]){ 
 + dut = fTemp - (float)C[4] - ((fTemp-(float)C[4])/​128.0) * ((fTemp-(float)C[4])/​128.0) * (float)coef_A / (float)(2^coef_C);​ 
 + }else{ 
 + dut = fTemp - (float)C[4] - ((fTemp-(float)C[4])/​128.0) * ((fTemp-(float)C[4])/​128.0) * (float)coef_B / (float)(2^coef_C);​ 
 +
 + 
 + offset = ((float)C[1]+((float)C[3]-1024.0)*dut/​16384.0)*4.0;​ 
 + sensitivity = (float)C[0]+ (float)C[2]*dut/​1024.0;​ 
 + xpress = sensitivity * ((float)iPressure-7168.0)/​16384.0 - offset; 
 + fPressure = xpress*10.0/​32.0+(float)C[6] + 253.0; 
 + return (fPressure/​10.0);​ 
 +
 +</​code>​ 
 + 
 +==== TFT display a FlexBus ==== 
 + 
 +Pre riadenie TFT display-u som využil hotovú knižnicu:​ 
 +https://​www.element14.com/​community/​groups/​development-tools/​blog/​2012/​05/​26/​stm32f4-discovery-hy32d-tft-lcd Tú som však musel naportovať pre K64 procesor a zbernicu FluxBus: 
 +Inicializácia:​ 
 +<code c> 
 +void Init_FlexBus(void){ 
 + flexbus_config_t flexbusUserConfig;​ 
 + 
 + FLEXBUS_GetDefaultConfig(&​flexbusUserConfig);​ 
 + 
 + flexbusUserConfig.waitStates = 2U; 
 + flexbusUserConfig.portSize = kFLEXBUS_2Bytes;​ 
 + flexbusUserConfig.chipBaseAddress = (uint32_t)TFT_DC_ADDRESS;​ 
 + flexbusUserConfig.chipBaseAddressMask = 1U; 
 + flexbusUserConfig.byteLaneShift = kFLEXBUS_Shifted;​ 
 + flexbusUserConfig.autoAcknowledge = true; 
 + 
 + FLEXBUS_Init(FB,​ &​flexbusUserConfig);​ 
 + } 
 +</​code>​ 
 +Zápis dát do pamäte a do registrov:​ 
 +<code c> 
 +void vfnSendDataWord(unsigned short value) 
 +  { 
 +    *((unsigned short*)TFT_BASE_ADDRESS) = value; 
 +  } 
 + 
 +void vfnSendCmdWord(unsigned short cmd) 
 +  { 
 +    *((unsigned short*)TFT_DC_ADDRESS) = cmd; 
 +  } 
 +</​code>​ 
 + 
 +==== RTC ==== 
 + 
 +Inicializácia a nastavenie hodín reálneho času: 
 +<code c> 
 +void Init_rtc(void){ 
 + 
 + rtc_config_t rtcConfig;​ 
 + 
 + RTC_GetDefaultConfig(&​rtcConfig);​ 
 + RTC_Init(RTC,​ &​rtcConfig);​ 
 +     /* Select RTC clock source */ 
 + RTC_SetClockSource(RTC);​ 
 +
 + 
 +void rtc_settime(rtc_datetime_t date){ 
 + 
 +   RTC_StopTimer(RTC);​ 
 +   RTC_SetDatetime(RTC,​ &​date);​ 
 +   RTC_StartTimer(RTC);​ 
 +
 + 
 +rtc_datetime_t rtc_gettime(void){ 
 + 
 + rtc_datetime_t date; 
 + 
 + RTC_GetDatetime(RTC,​ &​date);​ 
 + return(date);​ 
 +
 +</​code>​ 
 + 
 +==== Hlavná slučka a Fat FS ==== 
 +Kinetis software development kit obsahuje okrem štandardných ovládačov periférií aj middleware pre prácu s USB a SD kartami s podporou Fat FS, ktorý som použil. Tým, že zapisujem namerané údaje v textovom formáte, tieto sú po pripojeni SD karty do počítača bezproblémov spracovateľné. ​ V hlavnej slučke sa periodicky vyčítavajú údaje, ktoré sa okamžite zobrazujú na display-i a každých 10s sa otvorí súbor pre zápis a udaje sa zapíšu vo formáte dátum, čas, koncentrácia CO2, teplota, vlhkosť a tlak. Po zápise sa súbor okamžite uzavrie. 
 +<code c> 
 +while (1) { 
 + 
 + date = rtc_gettime();​ 
 + sprintf(str,​ "​%02hd-%02hd-%04hd %02hd:​%02hd:​%02hd ​    ",​ date.day, 
 + date.month,​ date.year, date.hour, date.minute,​ date.second);​ 
 + 
 + LCD_SetTextColor(ASSEMBLE_RGB(0,​ 0, 0)); 
 + LCD_CharSize(16);​ 
 + LCD_StringLine(1,​ 1, (uint8_t*) str); 
 + co_value = get_concentration();​ 
 + sprintf(str,​ "​CO2:​%d ppm", co_value);​ 
 + LCD_SetTextColor(ASSEMBLE_RGB(0,​ 0, 0xFF)); 
 + LCD_CharSize(24);​ 
 + LCD_StringLine(1,​ 16, (uint8_t*) str); 
 + 
 + temperature = read_temp();​ 
 + humidity = read_hum();​ 
 + LCD_SetTextColor(ASSEMBLE_RGB(0xFF,​ 0, 0)); 
 + sprintf(str,​ "​T: ​  %2.2f C", temperature);​ 
 + LCD_StringLine(1,​ 40, (uint8_t*) str); 
 + LCD_SetTextColor(ASSEMBLE_RGB(0,​ 0, 0xFF)); 
 + sprintf(str,​ "​RH: ​ %2.2f %%", humidity);​ 
 + LCD_StringLine(1,​ 64, (uint8_t*) str); 
 + LCD_SetTextColor(ASSEMBLE_RGB(0xFF,​ 0, 0)); 
 + pressure = read_pressure();​ 
 + sprintf(str,​ "​P:​%6.2fhPa",​ pressure);​ 
 + LCD_StringLine(1,​ 88, (uint8_t*) str); 
 + Delay(10);​ 
 + 
 + if(card_ok && prev_second != date.second && !(date.second % 10)){ 
 + sprintf(g_bufferWrite,​ "​%02hd-%02hd-%04hd %02hd:​%02hd:​%02hd %d %2.2f %2.2f %6.2f \r\n", date.day, 
 + date.month,​ date.year, date.hour, date.minute,​ date.second,​ co_value, temperature,​ humidity, pressure);​ 
 + f_open(&​g_fileObject,​ _T("/​data.dat"​),​ (FA_WRITE | FA_READ | FA_OPEN_APPEND));​ 
 + 
 + error = f_write(&​g_fileObject,​ g_bufferWrite,​ strlen(g_bufferWrite),​ &​bytesWritten);​ 
 + f_close(&​g_fileObject);​ 
 + prev_second = date.second;​ 
 +
 +
 +</​code>​ 
 +===== Video datalogger ===== 
 +{{youtube>​R_bAfAzXU1A?​medium}} 
 + 
 +===== Výpis dát ===== 
 +V tomto bolku je príklad zmeraných dát, potom ako som začal vetrať. Je vidieť, ako klesá koncentrácia CO2, ale zároveň aj s teplotou... 
 + 
 +<​file>​ 
 +14-01-2018 17:20:10 1052 21.98 27.91 1017.92  
 +14-01-2018 17:20:20 1021 21.99 27.36 1017.80  
 +14-01-2018 17:20:30 971 21.93 26.92 1017.80  
 +14-01-2018 17:20:40 955 21.92 26.60 1017.67  
 +14-01-2018 17:20:50 939 21.87 25.60 1017.90  
 +14-01-2018 17:21:00 920 21.83 24.97 1017.95  
 +14-01-2018 17:21:10 909 21.79 24.63 1017.90  
 +14-01-2018 17:21:20 884 21.73 24.27 1017.90  
 +14-01-2018 17:21:30 898 21.64 24.33 1017.95  
 +14-01-2018 17:21:40 883 21.58 23.90 1017.99  
 +14-01-2018 17:21:50 917 21.50 24.53 1017.89  
 +14-01-2018 17:22:00 905 21.41 24.16 1018.08  
 +14-01-2018 17:22:10 872 21.35 23.40 1017.94  
 +14-01-2018 17:22:20 862 21.24 23.51 1017.98  
 +14-01-2018 17:22:30 909 21.13 23.87 1017.94  
 +14-01-2018 17:22:40 861 21.13 22.79 1017.95  
 +14-01-2018 17:22:50 833 21.12 22.56 1017.95  
 +14-01-2018 17:23:00 841 21.11 22.62 1018.04  
 +14-01-2018 17:23:10 821 21.02 22.26 1017.94  
 +14-01-2018 17:23:20 814 20.96 22.06 1018.06  
 +14-01-2018 17:23:30 803 20.91 21.89 1018.05  
 +14-01-2018 17:23:40 819 20.86 21.93 1017.82  
 +14-01-2018 17:23:50 864 20.76 23.28 1018.07  
 +14-01-2018 17:24:00 841 20.71 22.27 1017.97  
 +14-01-2018 17:24:10 799 20.64 21.51 1018.00  
 +14-01-2018 17:24:20 794 20.58 21.94 1018.07  
 +</​file>​ 
 + 
 + 
 +==== Záver ==== 
 + 
 +Tento projekt je prototyp, na ktorom som si overil rôzne senzory, vyskúšal som prostredie MCUXpresso firmy NXP a ich software-ové knižnice pre prácu s ARM procesormi Kinetis KSDK verzie 2.3. K tomu, aby to bol plnohodnotný projekt je nutné prerobiť a dorobiť niekoľko vecí. Najmä radiče pre komunikáciu prerobiť z blokovacieho na neblokovací režim, veľa času stráca procesor tým, že čaká, kým periféria zmeria a odpovie. Ďalej je nutné prerobiť HW vývojovej dosky na zálohovanie z batérie pre kalibračné dáta a hodiny reálneho času. Takisto ovládanie z konzoly a prekopírovávanie uložených dát. Z užívateľského rozhrania je vhodné dorobiť grafické zobrazenie údajov v čase. Debug sériový port, ktorý je teraz použitý previesť na USB com port, a tento sériový port priviesť na malý WiFi modul so serverom, na ktorom budú prístupné namerané údaje z lokálnej siete. Za úvahu stojí aj zmena senzora koncentrácie CO2, keďže je to už pomerne obsolete senzor, ktorý je náchylný na všetky parametre ako napájacie napätie, ktoré v tomto prípade nie je vôbec stabilné, nepresnosť,​ stále je nutné ho kalibrovať a náročný prepočet.  
 + 
 +Zdroje:{{ :​2017:​xwalde01:​envilogger.rar | Zdrojové súbory}} 
 + 
2017/envi-logger.1516594177.txt.gz · Poslední úprava: 2018/01/22 05:09 autor: Miroslav Waldecker