реклама на сайте
подробности

 
 
> Возможность использования OS::channel в прерываниях
abutorin
сообщение Jan 13 2013, 19:25
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Добрый вечер.
Пробую сделать передачу по USART с использование буфера. Для межпроцессорного удобства очень нравится использовать OS::channel. Возможно ли его использовать и в прерываниях? Точнее интересует процедура получения элемента из канала?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
AHTOXA
сообщение Jan 13 2013, 20:45
Сообщение #2


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Использовать канал в прерывании можно. Учтите только, что если вы в него что-то заталкиваете, а он полон, то будет сделана попытка усыпить прерванный процесс и дождаться освобождения (или при доставании из пустого канала). Вероятно, это не то поведение, которое ожидается в прерыванииsm.gif
Поэтому проверяйте наличие свободного места при запихивании чего-то в канал, и наличие данных при доставании из канала.
Примерно вот так:
Код
void uart_t::irq_handler(){
    uint16_t status = USARTx->SR;
    if (status & USART_SR_RXNE){
        uint8_t ch = USARTx->DR;
        if (RxChannel.get_free_size())
            RxChannel.push(ch);
    }
            
    if (status & USART_SR_TXE){
        if (TxChannel.get_count()){
            char ch = 0;
            TxChannel.pop(ch);
            USARTx->DR = ch;
        }
        else
            disable_tx_interrupt();
    }
}


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 15 2013, 19:16
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Цитата(AHTOXA @ Jan 14 2013, 00:45) *
Использовать канал в прерывании можно. Учтите только, что если вы в него что-то заталкиваете, а он полон, то будет сделана попытка усыпить прерванный процесс и дождаться освобождения (или при доставании из пустого канала). Вероятно, это не то поведение, которое ожидается в прерыванииsm.gif
Поэтому проверяйте наличие свободного места при запихивании чего-то в канал, и наличие данных при доставании из канала.


Примерно так и делал.
Код
    
class usart_t
{
public:
    OS::channel<uint8_t,4> Rxbuf;
    OS::channel<uint8_t,4> Txbuf;
    USART_TypeDef * PORT;

INLINE void it_handler ()
    {

        if (USART_GetITStatus(this->PORT,USART_IT_TXE) != RESET)
        {
            {
                if(this->Txbuf.get_count())
                {
                    uint8_t data;
                    this->Txbuf.pop(data);
                    USART_SendData(this->PORT,data);
                }
                else
                {
                    USART_ITConfig(this->PORT, USART_IT_TXE, DISABLE);
                }

            }

            USART_ClearITPendingBit(this->PORT,USART_IT_TXE);
        }

    }

    void send(const uint8_t & data)
    {
        this->Txbuf.push(data);
        USART_ITConfig(this->PORT, USART_IT_TXE, ENABLE);

    }


Размер буфера 4 элемента. заполняю его в одном из потоков:
Код
        
      for(i=0;i<8;i++)
        {
            usart.send(i+0x30);
        }

        OS::sleep(1000);

Задача проверить работоспособность при заполнении буфера до отказа. В результата камень зависает в прерывании. Причем смотрю терминалом на компьютере, нормально отправляется только 2 байта.

Поэкспериментировал немного с размером буфера и размером отправляемых данных, если размер буфера поставить 5 и отправлять 8 байт то все работает нормально, размер буфера 14 количество отправляемых данных 16 тоже нормально. На лицо правило размер буфера = количество отправляемых данных - 2.

Сообщение отредактировал abutorin - Jan 15 2013, 19:03
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Jan 15 2013, 19:26
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Не знаю почему зависает, наверное что-то неправильно ...
Не пойму, в чём сермяга посать всюду this->?
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 15 2013, 19:31
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Цитата(_Артём_ @ Jan 15 2013, 23:26) *
Не знаю почему зависает, наверное что-то неправильно ...
Не пойму, в чём сермяга посать всюду this->?

Объектный подход, да можно былобы статичным класом обойтись, думаю это не критично.

Посмотрел поглубже, помоему нашел в чем проблема:
Код
template<typename T, uint16_t Size, typename S>
void OS::channel<T, Size, S>::push(const T& item)
{
    TCritSect cs;

    while(!pool.get_free_size())
    {
        // channel is full, suspend current process until data removed
        suspend(ProducersProcessMap);
    }

    pool.push_back(item);
    resume_all(ConsumersProcessMap);
}

Судя по коду, push выполняется с запретом прерывания. Как я понимаю работу TCritSect, запрет снимается в деструкторе, так вот деструктор не вызовется, т.к. потребитель канала находится в прерывании.
Получается что канал использовать с прерываниями не получится.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 15 2013, 22:46
Сообщение #6


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (abutorin @ Jan 15 2013, 21:31) *
Судя по коду, push выполняется с запретом прерывания. Как я понимаю работу TCritSect, запрет снимается в деструкторе, так вот деструктор не вызовется, т.к. потребитель канала находится в прерывании.
Прерывания будут разрешены во время suspend() при передаче управления другому процессу. Что касается вашей проблемы - мне кажется причина в том, что вы делаете USART_ClearITPendingBit(this->PORT,USART_IT_TXE); даже если данных не было и ничего не было передано. И когда данные в канале появляются - у процессора нет причин вызвать прерывание и отправить их. Хотя я не очень хорошо помню, как этот механизм (pending) работает в кортексах. Также полагаю, что объект типа OS::TCritSect вы в начале обработчика прерывания создаете. Если нет - это тоже может быть причиной.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 16 2013, 03:29
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Цитата(Сергей Борщ @ Jan 16 2013, 02:46) *
Прерывания будут разрешены во время suspend() при передаче управления другому процессу. Что касается вашей проблемы - мне кажется причина в том, что вы делаете USART_ClearITPendingBit(this->PORT,USART_IT_TXE); даже если данных не было и ничего не было передано. И когда данные в канале появляются - у процессора нет причин вызвать прерывание и отправить их. Хотя я не очень хорошо помню, как этот механизм (pending) работает в кортексах. Также полагаю, что объект типа OS::TCritSect вы в начале обработчика прерывания создаете. Если нет - это тоже может быть причиной.

USART_ClearITPendingBit(this->PORT,USART_IT_TXE); Это очистка признака возникновения прерывания, в у STM32 большинство битов (признаков) прерывания необходимо очищать вручную. Прерывание по USART_IT_TXE выключается командой USART_ITConfig(this->PORT, USART_IT_TXE, DISABLE); только в случае если канал пустой. А в процедуре которая заполняет канал send это прерывание всегда включаетсся.
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);

Посмотрел еще раз
Код
   void OS::TService::suspend(TProcessMap volatile & waiters_map)
    {
        TProcessMap PrioTag = cur_proc_prio_tag();
    
        set_prio_tag(waiters_map, PrioTag);                   // put current process to wait map
        clr_prio_tag(ready_process_map(), PrioTag);           // remove current process from ready map
    
    #if scmRTOS_DEBUG_ENABLE == 1
        cur_proc_waiting_for() = this;                        // catch current service address to process debug data
    #endif

    #if scmRTOS_PROCESS_RESTART_ENABLE == 1
        cur_proc_waiting_map() = &waiters_map;
    #endif
        
        reschedule();
        
    #if scmRTOS_DEBUG_ENABLE == 1
        cur_proc_waiting_for() = 0;                           // remove current service address from process debug data
    #endif
        
    #if scmRTOS_PROCESS_RESTART_ENABLE == 1
        cur_proc_waiting_map() = 0;
    #endif
        
    }

void OS::channel<T, Size, S>::push(const T& item)
{
    TCritSect cs;

    while(!pool.get_free_size())
    {
        // channel is full, suspend current process until data removed
        suspend(ProducersProcessMap);
    }

    pool.push_back(item);
    resume_all(ConsumersProcessMap);
}

А в какой момент происходи включение прерываний? в suspend я не нашел включение прерываний.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 16 2013, 08:54
Сообщение #8


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (abutorin @ Jan 16 2013, 05:29) *
USART_ClearITPendingBit(this->PORT,USART_IT_TXE); Это очистка признака возникновения прерывания, в у STM32 большинство битов (признаков) прерывания необходимо очищать вручную.
К сожалению я использую для передачи DMA, поэтому у меня нет примера для UART c каналом. Без ОС рабочий код у меня выглядит так:
CODE
INLINE void uart::handler()
{
    uint32_t Status = pUART->SR;
    Status &= pUART->CR1;   // mask disabled ints

    if(Status & USART_SR_RXNE)
    {
        uint8_t Data = pUART->DR;
        if(Rx_buffer.has_place())
            Rx_buffer.put(Data);
    }
    if(Status & USART_SR_TXE)
    {
        pUART->DR = Tx_buffer.get();
        if(!Tx_buffer.has_data())
            pUART->CR1 &= ~USART_CR1_TXEIE;
    }
}
Как видите, никаких ручных очисток.


QUOTE (abutorin @ Jan 16 2013, 05:29) *
А в какой момент происходи включение прерываний? в suspend я не нашел включение прерываний.
Из suspend() вызывается TKernelAgent::reschelule(), который в свою очередь вызывет TKernel::shed(), в котором есть такой код:
CODE
        do
        {
            enable_context_switch();
            DUMMY_INSTR();
            disable_context_switch();
        }
        while(CurProcPriority != SchedProcPriority); // until context switch done
Вот тут произойдет переключение на другой процесс, а уже этот процесс (если нет активных - то процесс Idle) выполняется с разрешенными прерываниями, т.е. при восстановлении его контекста прерывания будут разрешены.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 16 2013, 11:33
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Цитата(Сергей Борщ @ Jan 16 2013, 12:54) *
К сожалению я использую для передачи DMA, поэтому у меня нет примера для UART c каналом.

У меня логика построена на том, что я с уартом работаю как с потоком байт, я не знаю сколько байт отправляюи сколько получу. Если даже с таким подходом это можно реализовать через DMA то был бы очень признателен за пример.
Если с прерываниями стало ясно.то опять возникает вопрос в чем же тогда проблема?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 17 2013, 10:15
Сообщение #10


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (abutorin @ Jan 16 2013, 13:33) *
Если с прерываниями стало ясно.то опять возникает вопрос в чем же тогда проблема?
Вы заводите в начале обработчика объект типа OS::TISRW (я в предыдущем сообщении описался, указав его как OS::TCritSect)? Без него прерывание не сможет при необходимости вызвать перепланирование.

QUOTE (abutorin @ Jan 16 2013, 13:33) *
У меня логика построена на том, что я с уартом работаю как с потоком байт, я не знаю сколько байт отправляюи сколько получу. Если даже с таким подходом это можно реализовать через DMA то был бы очень признателен за пример.
Как-то так, хотя мне самому этот код не очень нравится:
CODE

//**** uart.h: *****
#ifndef UART_H__
#define UART_H__
#include <stdint.h>
#include <stm32f10x.h>
#include <scmRTOS.h>
#include <string.h>

#include <stdarg.h>
#include <stdio.h>

class uart
{
public:
uart(USART_TypeDef * usart, uint32_t dma_channel)
: Tx_ready(OS::TEventFlag::efOn)
, pUART(usart)
, DMA_channel_no(dma_channel - 1)
, DMA_channel((DMA_Channel_TypeDef *)(DMA1_Channel1_BASE + (dma_channel - 1) * 0x14))
{}

void send(const uint8_t &byte);
void send(char const * string);
void send(char * string, OS::TMutex * pLock);
void send_HEX(uint8_t data);
void send_HEX(uint16_t data);
void new_line();
void vprintf(char const * format, va_list args);
void printf(char const * format, ...);
bool is_transmitting() {return !(pUART->SR & USART_SR_TXE);}

bool hasinput() {return Rx_buffer.get_count();}
bool receive(uint8_t & data, timeout_t timeout);
bool receive(char & data, timeout_t timeout);
uint8_t receive() { uint8_t Data; Rx_buffer.pop(Data); return Data;}

void speed_setup(uint_fast32_t baudrate) { pUART->BRR = (PCLK1_FREQ + baudrate / 2) / baudrate; }
void tx_dma_handler();
void rx_handler();
protected:
static size_t const RX_BUFF_SIZE = 16;

OS::TEventFlag Tx_ready;
uint8_t Tx_byte_buffer;
OS::TMutex Tx_byte_buffer_lock;

OS::TMutex Tx_buffer_lock;
char Tx_buffer[80];

OS::TMutex * pDMA_buffer_lock;
void setup_tx_dma(uint8_t const * pSrc, size_t size, OS::TMutex *pLock = 0);

OS::channel<uint8_t volatile, RX_BUFF_SIZE> Rx_buffer;
private:
USART_TypeDef * pUART;
uint_fast32_t DMA_channel_no;
DMA_Channel_TypeDef * DMA_channel;
};
// =========== receiving ==============
INLINE void uart::rx_handler()
{
uint8_t Data = pUART->DR;
if(Rx_buffer.get_free_size())
Rx_buffer.push(Data);
}

inline bool uart::receive(uint8_t & symbol, timeout_t timeout)
{
if(timeout <= 0 || !Rx_buffer.pop(symbol, timeout))
return false;
return true;
}

inline bool uart::receive(char & symbol, timeout_t timeout)
{
uint8_t data;
if(timeout <= 0 || !Rx_buffer.pop(data, timeout))
return false;
symbol = char(data);
return true;
}

// ========== transmitting ===========

INLINE void uart::tx_dma_handler()
{
DMA1->IFCR = DMA_IFCR_CTCIF1 << (4 * DMA_channel_no);
DMA_channel->CCR = 0
;
Tx_ready.signal_isr();
if(pDMA_buffer_lock)
pDMA_buffer_lock->unlock_isr();
}

#endif //UART_H__


//**** uart.cpp ******
#include "uart.h"
#include <string.h>

void uart::setup_tx_dma(uint8_t const * pSrc, size_t size, OS::TMutex * pLock)
{
Tx_ready.wait();
pDMA_buffer_lock = pLock;
// --------- DMA setup -----------
DMA_channel->CPAR = uintptr_t(&pUART->DR);
DMA_channel->CMAR = uintptr_t(pSrc);
DMA_channel->CNDTR = size;
DMA_channel->CCR = 0
| 1 * DMA_CCR1_EN // Channel enable
| 1 * DMA_CCR1_TCIE // Transfer complete interrupt enable
| 0 * DMA_CCR1_HTIE // Half Transfer interrupt enable
| 0 * DMA_CCR1_TEIE // Transfer error interrupt enable
| 1 * DMA_CCR1_DIR // Data transfer direction: Memory->Peripheral
| 0 * DMA_CCR1_CIRC // Circular mode
| 0 * DMA_CCR1_PINC // Peripheral increment mode
| 1 * DMA_CCR1_MINC // Memory increment mode
| 0 * DMA_CCR1_PSIZE_0 // Peripheral size: 8 bits
| 0 * DMA_CCR1_MSIZE_0 // Memory size: 8 bits
| 1 * DMA_CCR1_PL_0 // Channel Priority level: higher than lowest, conversion frequency is low enough
| 0 * DMA_CCR1_MEM2MEM // Memory to memory mode disabled
;

}

void uart::send(uint8_t const &byte)
{
Tx_byte_buffer_lock.lock();
Tx_byte_buffer = byte;
setup_tx_dma(&Tx_byte_buffer, 1, &Tx_byte_buffer_lock);
}

void uart::send(char const * pString)
{
setup_tx_dma((uint8_t const *)pString, strlen(pString));
}

void uart::send(char * pString, OS::TMutex * pLock)
{
setup_tx_dma((uint8_t const *)pString, strlen(pString), pLock);
}

void uart::vprintf(char const * format, va_list args)
{

Tx_buffer_lock.lock();
vsprintf (Tx_buffer, format, args);
send(Tx_buffer, &Tx_buffer_lock);
}

void uart::printf(char const * format, ...)
{
va_list args;
va_start (args, format);
uart::vprintf (format, args);
va_end (args);
}


uart Serial(USART2, 7);
uart & Console = Serial;


extern "C" void DMA1_Channel7_IRQHandler(void)
{
OS::TISRW ISR_wrapper;
Console.tx_dma_handler();
}

extern "C" void USART2_IRQHandler(void)
{
OS::TISRW ISR_wrapper;
Console.rx_handler();
}

Тут готовность DMA передается через флаг Tx_ready, а буфер передачи (если он используется для данной посылки) защищен мутексом Tx_byte_buffer_lock. Если же передается готовая строка из флеша или ОЗУ - буфер не используется.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 17 2013, 12:25
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Цитата(Сергей Борщ @ Jan 17 2013, 14:15) *
Как-то так, хотя мне самому этот код не очень нравится:


Да, я понял. Но мои вопросы этот метод нерешит т.к. посылка делается по одному байту (как поток), тут изначально нельзя знать какой объем займет посылка. Плохо что DMA не умеет работать как кольцевой буфер. Тогда хотябы можно было накапливать данные и отсылать по таймауту в случае отсутствия новых.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- abutorin   Возможность использования OS::channel в прерываниях   Jan 13 2013, 19:25
|- - abutorin   Спасибо, проверку заполнености, проверку пустоты я...   Jan 14 2013, 02:40
|- - _Артём_   Цитата(abutorin @ Jan 15 2013, 21:31) Объ...   Jan 15 2013, 20:10
|- - _Артём_   Цитата(abutorin @ Jan 16 2013, 05:29) А в...   Jan 16 2013, 04:45
||- - AHTOXA   TXE очищается записью в DR. Вручную его чистить не...   Jan 16 2013, 05:05
|- - AHTOXA   Цитата(Сергей Борщ @ Jan 16 2013, 14:54) ...   Jan 16 2013, 10:18
||- - Сергей Борщ   QUOTE (AHTOXA @ Jan 16 2013, 12:18) А это...   Jan 16 2013, 11:27
||- - AHTOXA   Цитата(Сергей Борщ @ Jan 16 2013, 17:27) ...   Jan 16 2013, 13:52
|- - Сергей Борщ   QUOTE (abutorin @ Jan 17 2013, 14:25) Пло...   Jan 17 2013, 13:12
|- - abutorin   Цитата(Сергей Борщ @ Jan 17 2013, 17:12) ...   Jan 17 2013, 13:20
|- - AHTOXA   Насчёт работы с UART по DMA вот вам три темы: раз...   Jan 17 2013, 18:31
|- - abutorin   Цитата(AHTOXA @ Jan 17 2013, 22:31) Насчё...   Jan 18 2013, 05:37
|- - Сергей Борщ   QUOTE (abutorin @ Jan 18 2013, 07:37) Спа...   Jan 18 2013, 07:41
|- - abutorin   Цитата(Сергей Борщ @ Jan 18 2013, 11:41) ...   Jan 18 2013, 09:14
- - Vasya777   Мне кажется для обмена по интерфейсам связи лучше ...   Jan 15 2013, 15:07
- - abutorin   Проблему решил использовав События: Кодclass usart...   Jan 15 2013, 20:14
|- - _Артём_   Цитата(abutorin @ Jan 15 2013, 22:14) есл...   Jan 15 2013, 20:20
|- - abutorin   Цитата(_Артём_ @ Jan 16 2013, 00:20) На ч...   Jan 15 2013, 20:24
|- - _Артём_   Цитата(abutorin @ Jan 15 2013, 22:24) Вто...   Jan 15 2013, 20:52
- - abutorin   Как обещал ранее выкладываю код который у меня раб...   Jan 18 2013, 18:52
|- - AHTOXA   USART_ClearITPendingBit(this->PORT,USART_IT_TXE...   Jan 19 2013, 04:43
|- - abutorin   Цитата(AHTOXA @ Jan 19 2013, 08:43) USART...   Jan 19 2013, 17:19
|- - AHTOXA   Цитата(abutorin @ Jan 19 2013, 23:19) В к...   Jan 19 2013, 17:42
|- - abutorin   Цитата(AHTOXA @ Jan 19 2013, 21:42) Код ...   Jan 19 2013, 17:56
||- - _Артём_   Цитата(abutorin @ Jan 19 2013, 19:56) В с...   Jan 19 2013, 18:13
|- - abutorin   Цитата(AHTOXA @ Jan 19 2013, 21:42) Код ...   Jan 19 2013, 18:42
|- - AHTOXA   Цитата(abutorin @ Jan 20 2013, 00:42) С т...   Jan 19 2013, 19:12
|- - abutorin   Цитата(AHTOXA @ Jan 19 2013, 23:12) У мен...   Jan 19 2013, 19:19
|- - AHTOXA   Насчёт компактности - думаю, что случайно так вышл...   Jan 19 2013, 19:36
|- - abutorin   Цитата(AHTOXA @ Jan 19 2013, 23:36) А по ...   Jan 19 2013, 20:01
|- - AHTOXA   Цитата(abutorin @ Jan 20 2013, 02:01) Есл...   Jan 19 2013, 20:21
|- - abutorin   Цитата(AHTOXA @ Jan 20 2013, 00:21) А уве...   Jan 19 2013, 20:42
|- - AHTOXA   Ну, с тех пор что-то же поменялось. Так что это бы...   Jan 20 2013, 05:31
|- - abutorin   Цитата(AHTOXA @ Jan 20 2013, 09:31) В общ...   Jan 20 2013, 05:57
- - сарматъ   я так и не понял, а функции типа push_isr() не нуж...   Sep 4 2013, 20:26
|- - _Артём_   Цитата(сарматъ @ Sep 4 2013, 23:26) я так...   Sep 4 2013, 21:41
|- - сарматъ   там могло бы быть что либо такого плана CODEtempl...   Sep 5 2013, 05:39
|- - Сергей Борщ   QUOTE (сарматъ @ Sep 5 2013, 07:39) там м...   Sep 5 2013, 06:10
- - сарматъ   да я уже подумал над этим правда придется не насле...   Sep 5 2013, 06:24
|- - dxp   QUOTE (сарматъ @ Sep 5 2013, 13:24) да я ...   Sep 5 2013, 07:21
|- - сарматъ   потому что нужен вот такой вот пул и если я его до...   Sep 5 2013, 07:37
|- - Сергей Борщ   QUOTE (сарматъ @ Sep 5 2013, 09:37) потом...   Sep 5 2013, 08:25
- - сарматъ   да, класс канала отличный класс, плюс ко всем его ...   Sep 5 2013, 08:33
|- - Сергей Борщ   QUOTE (сарматъ @ Sep 5 2013, 10:33) сдела...   Sep 6 2013, 08:29
- - сарматъ   ок, так и сделаю и потом выложу сюда что получилос...   Sep 6 2013, 08:44


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd June 2025 - 08:20
Рейтинг@Mail.ru


Страница сгенерированна за 0.01621 секунд с 7
ELECTRONIX ©2004-2016