|
|
  |
Своя программная обёртка USB stm32, Создание своего драйвера USB для STM32 |
|
|
|
Aug 4 2017, 06:59
|
Группа: Участник
Сообщений: 12
Регистрация: 15-05-17
Пользователь №: 97 085

|
Работаю над собственным драйвером для USB в STM32 , что-то мало материала. 99 % как скомпилировать готовый пример. Кто занимался аналогичной задачей? В принципе значительная часть уже сделана.
|
|
|
|
|
Aug 4 2017, 10:17
|
Частый гость
 
Группа: Участник
Сообщений: 180
Регистрация: 5-04-09
Пользователь №: 47 205

|
QUOTE (linuxbergi @ Aug 4 2017, 09:59)  Работаю над собственным драйвером для USB в STM32 , что-то мало материала. 99 % как скомпилировать готовый пример. Кто занимался аналогичной задачей? В принципе значительная часть уже сделана. Чем не устраивает кейловский пример?
|
|
|
|
|
Aug 4 2017, 10:41
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(linuxbergi @ Aug 4 2017, 12:59)  Работаю над собственным драйвером для USB в STM32 , что-то мало материала. 99 % как скомпилировать готовый пример. Кто занимался аналогичной задачей? В принципе значительная часть уже сделана. Я занимался. Достаточно долгое время. В итоге есть платформонезависимая библиотека. К ней подключаются файлы драйверов для различных МК. Один файл - один модуль и один заголовок. Сейчас есть драйверы для AVR XMEGA, AT91, STM32 USB, STM32 OTG. STM32 OTG дался труднее всех. Есть некоторые отличительные нюансы, к примеру, для F107, F407 и L4xx в плане инициализации Device Core. Это те, с которыми работал.
--------------------
|
|
|
|
|
Aug 4 2017, 12:12
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(prottoss @ Aug 4 2017, 15:00)  Под стеком, исторически, подразумевается оболочка и API к ней, которая знать не знает, на каком МК она выполняется. Все что ниже - драйвер. Не, драйвер эта такая штука которая управляется менеджером драйверов и может быть динамически привязана и отвязана от процесса. Т.е. физически набор функций со строго единообразным верхним интерфейсом для любой периферии. У Keil-а отродясь такого не было. Не все RTOS такое имеют. Потому как в embedded это излишне, там нет нужды динамически менять и управлять драйверами. А потому автор должен был написать по простому какой набор функций он хочет реализовать, а не туманить насчет драйвера. Эти функции там на пальцах пересчитать можно.
|
|
|
|
|
Aug 4 2017, 18:35
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(prottoss @ Aug 4 2017, 15:30)  lwIP что по Вашему? Или FatFS? FatFS, насколько знаю, даже с NAND не умеет работать. А lwIP не умеет с СDC-ECM. Это просто наборы функций которые кое-как с помощью косвенной адресации могут перенаправлять свои потоки данных. Но всей подготовкой к перенаправлению юзер должен заниматься вручную. Или мы сейчас все что взаимодействует через косвенную адресацию будем называть драйверами? Я даже скажу, что использования термина "драйвер" крайне вредно для TC. Вместо того чтобы написать всего две специализированные функции read_x и write_x и остальное разрулить прямым доступом к периферии без всякой унификации, он будет сочинять API, которое сам забудет через месяц.
|
|
|
|
|
Aug 5 2017, 06:34
|

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

|
QUOTE (Эдди @ Aug 5 2017, 00:39)  Где драйвера-то? Может, здесь?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Aug 5 2017, 06:41
|
Знающий
   
Группа: Участник
Сообщений: 825
Регистрация: 16-04-15
Из: КЧР, Нижний Архыз
Пользователь №: 86 250

|
Цитата(ViKo @ Aug 5 2017, 09:01)  Эдди, вы когда-нибудь ставили Виндовс на голый комп? Тьфу-тьфу, с этим говном дела не имею! Цитата(Сергей Борщ @ Aug 5 2017, 09:34)  Просто какой-то осел модуль ядра драйвером назвал. Бывает. До сих пор встречаются ослы, которые директории/каталоги/справочники называют "папками". А мамок им не завезли случайно?
Сообщение отредактировал Эдди - Aug 5 2017, 06:42
|
|
|
|
|
Aug 5 2017, 06:46
|
Гуру
     
Группа: Участник
Сообщений: 2 219
Регистрация: 16-08-12
Из: Киров
Пользователь №: 73 143

|
Цитата(ViKo @ Aug 5 2017, 09:01)  Эдди, вы когда-нибудь ставили Виндовс на голый комп? Это ортодоксальный фанатик, какая винда? О чем вы... Спросите еще, как диск С отформатировать  Драйвер - всегда была программа, являющаяся мостом между аппаратным устр-вом уровня ядра и программой уровня пользователя. В МК таких уровней, как правило, нет, поэтому название "драйвер", как-то не совсем корректно.
Сообщение отредактировал mantech - Aug 5 2017, 06:52
|
|
|
|
|
Aug 5 2017, 13:01
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(Шаманъ @ Aug 5 2017, 14:05)  Если под драйвером понимать то, что в МК обеспечивает работу USB интерфейса, то у меня написано свое под STM32 (назовем USB стек+некая HAL прослойка, хотя с платформонезависимостью я особо не заморачивался). А в чем собственно вопрос? Ну так автор наверно хочет узнать что же входит или должно входить в состав "своего" Расскажите что у вас там "своё". Хост или дивайс вы сделали, или может OTG? Покажите список вызовов вашего API между аппаратурой и фреймворком. Это ж не секретно? А также между фреймворком и классами. Или если нет у вас такого деления на уровни, то расскажите почему. Покажите список классов которые вы реализовали. Покажите как сделан адаптер к RTOS, как реентерабельность обеспечена и т.д. и т.п.
|
|
|
|
|
Aug 6 2017, 09:21
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(AlexandrY @ Aug 5 2017, 16:01)  Ну так автор наверно хочет узнать что же входит или должно входить в состав "своего" Расскажите что у вас там "своё". Хост или дивайс вы сделали, или может OTG? У меня свое все  , включая RTOS, графику, математику и т.д. Касательно USB реализован USB device, host/OTG мне не интересен, потому не реализовывался. Цитата Покажите список вызовов вашего API между аппаратурой и фреймворком. Это ж не секретно? А также между фреймворком и классами. Или если нет у вас такого деления на уровни, то расскажите почему. Покажите список классов которые вы реализовали. Реализованы CDC и аудио устройство, может быть сделаю еще Mass Storage. Деление на уровни есть - нижний уровень общается непосредственно с аппаратурой, ядро реализует обработку базовых запросов и обеспечивает обработку запросов классами, классы взаимодействуют с первыми двумя уровнями, полная изоляция не делалась. Ставилась задача сделать не универсального монстра (таких хватает), а маленький модуль под конкретные задачи. В итоге три VCP и аудио устройство (стерео in/out) у меня занимают: - базовый модуль (HAL+ядро) 5.2кбайт флеша - CDC класс (виртуальный ком порт) - 1119байт - Аудио класс - 456байт флеша API между классами и стеком несколько нетрадиционен по части стандартных запросов, они реализованы через "карты" обработчиков (по типу того, как сделана обработка событий в MFC/ATL/WTL). Поэтому у меня нет аццких switchей  Также все дескрипторы сделаны через макросы, так что нет необходимости подсчитывать их длины, порядок байт и прочую ерунду. Например строковые дескрипторы: Код STRINGS_TABLE(Strings) { LANGUAGES(0x409), STRING(u"Oleg xxxxxxxxx"), /* 1 = MANUFACTURER */ STRING(u"xxxxt"), /* 2 = PRODUCT */ STRING(u"0001"), /* 3 = SERIAL */ STRING(u"xxxx RX A CAT Port"), /* 4 = INTERFACE_0*/ STRING(u"xxxx RX B CAT Port"), /* 5 = INTERFACE_2*/ STRING(u"xxxx OTRSP Port"), /* 6 = INTERFACE_4*/ STRING(u"xxxx Audio"), /* 7 = */ STRING(u"xxxx RX Audio"), /* 8 = RX Audio Terminal */ STRING(u"xxxx TX Audio") /* 9 = TX Audio Terminal */ }; И их обработка: Код //Standard Request Map BEGIN_REQUEST_MAP(StandardRequestMap) ................. ON_GET_STRING_DESCRIPTOR(Strings) ................. END_REQUEST_MAP() Разные языки поддерживаются в таком же стиле  Также и с другими запросами (типа выбора интерфейса, параметров CDC, параметров аудиодевайса и т.д., а также стандартные запросы дискрипторов устройства, конфига и т.п.). Цитата Покажите как сделан адаптер к RTOS, как реентерабельность обеспечена и т.д. и т.п. Стек изначально рассчитан работу с моей RTOS, потому никаких никаких адаптеров не делалось. Реентабельность обеспечена обычными средствами RTOS - критическими секциями, семафорами и т.д. Без RTOS он не работает, почему так я уже объяснил выше. P.S. Странный у Вас стиль общения - хотя бы слово волшебное добавили  , а то "покажите"... а Вы заплатите, а я покажу  . Если есть конкретный вопрос, ну что-то там не едет или что-то конкретное интересует, то спрашивайте - чем смогу - помогу, а просто так время тратить желания нет.
Сообщение отредактировал Шаманъ - Aug 6 2017, 09:57
|
|
|
|
|
Aug 7 2017, 08:03
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Шаманъ @ Aug 6 2017, 12:21)  У меня свое все  , включая RTOS, графику, математику и т.д. Касательно USB реализован USB device, host/OTG мне не интересен, потому не реализовывался. У меня тоже - почти всё своё  Кроме RTOS разве что. Хотя и к ней тоже порт - свой, ну ещё кой-какие её корректировки. А так и USB-device (когда нужен) - свой, и TCP-стек - свой, и графические библиотеки - тоже свои, о математике и прочих фильтрах и не говорю... Цитата(Шаманъ @ Aug 6 2017, 12:21)  API между классами и стеком несколько нетрадиционен по части стандартных запросов, они реализованы через "карты" обработчиков (по типу того, как сделана обработка событий в MFC/ATL/WTL). Это как я понимаю - массивы указателей на обработчики? Они у Вас во флешь или интерактивно в runtime-е в ОЗУ создаются? Цитата(Шаманъ @ Aug 6 2017, 12:21)  Поэтому у меня нет аццких switchей  "Аццкие" switch-и если они действительно аццкие, компилятор как правило превращает в эти же самые массивы указателей. Если возможно. Цитата(Шаманъ @ Aug 6 2017, 12:21)  Также все дескрипторы сделаны через макросы, так что нет необходимости подсчитывать их длины, порядок байт и прочую ерунду. Например строковые дескрипторы: У меня тоже так же сделано. Только имена макросов другие Цитата(Шаманъ @ Aug 6 2017, 12:21)  Реентабельность обеспечена обычными средствами RTOS - критическими секциями, семафорами и т.д. Без RTOS он не работает, почему так я уже объяснил выше. Я иногда делаю на callback-ах такое взаимодействие. Например: в TCP-стеке так сделан вызов обработчиков протоколов, обработчиков событий для сокетов и т.п. Поэтому оно никак не привязано к ОС (или к её отсутствию вовсе).
|
|
|
|
|
Aug 7 2017, 10:11
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(Шаманъ @ Aug 6 2017, 12:21)  У меня свое все  , включая RTOS, графику, математику и т.д. Касательно USB реализован USB device, host/OTG мне не интересен, потому не реализовывался. P.S. Странный у Вас стиль общения - хотя бы слово волшебное добавили  , а то "покажите"... а Вы заплатите, а я покажу  . Видите, вы даже толком не можете описать "своё" Потому что документацию на него не делали, а API ваше фрагментарное и архаичное. Небось и полного тестирования не делали, и даже профайлинга. Такого недокументированного всеми забытого добра на гитхабе тоннами лежит. Я бы TC предложил не делать "своё", а отрефакторить в пределах разумного какой-либо хорошо документированный USB фреймворк. Вот допустим в MQX есть отличная документация и полные исходники USB стека для Device, Host(EHCI, KHCI), OTG. Имеет реализации всех востребованных классов HID, CDC, MSD, Audio, Video, Composite, RNDIS Десятки примеров законченных приложений. Полная интеграция в RTOS, файловую систему, TCP стек и т.д. А все что "полностью своё" это будет как правило очень примитивно с урезанной функциональностью, не документировано и непереносимо даже на уровне компиляторов.
|
|
|
|
|
Aug 7 2017, 15:50
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(jcxz @ Aug 7 2017, 11:03)  У меня тоже - почти всё своё  Кроме RTOS разве что. Хотя и к ней тоже порт - свой, ну ещё кой-какие её корректировки. А так и USB-device (когда нужен) - свой, и TCP-стек - свой, и графические библиотеки - тоже свои, о математике и прочих фильтрах и не говорю...  Ну и правильно  Цитата Это как я понимаю - массивы указателей на обработчики? Они у Вас во флешь или интерактивно в runtime-е в ОЗУ создаются? Нет, макросы разворачиваются прямо в код из цепочки if/else и выховы функций без использования указателей. Цитата У меня тоже так же сделано. Только имена макросов другие   Цитата(AlexandrY @ Aug 7 2017, 13:11)  Видите, вы даже толком не можете описать "своё" Потому что документацию на него не делали, а API ваше фрагментарное и архаичное. Небось и полного тестирования не делали, и даже профайлинга. Такого недокументированного всеми забытого добра на гитхабе тоннами лежит. Ну вот еще один пуп вселенной, которому все должны - проходите мимо, я Вас не задерживаю. И да продолжайте хамить - сразу видно, что на другое не способны...
|
|
|
|
|
Aug 7 2017, 16:26
|
Знающий
   
Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842

|
Цитата(AlexandrY @ Aug 7 2017, 18:45)  У них форум есть с обсуждением комьюнити версии MQX. Они там ее модифицируют как хотят. Как они это делают не делясь исходниками? То что они не собираются наказывать своё комюнити, в тех случаях когда они считают нарушения незначительными это одно. А вы, к примеру, выкладывая что-то завязанное на MQX на тот же гитхаб - нарушаете лицензию, это другое. Поймите нет второго сорта лицензионной чистоты, когда вы почти "соблюдаете" лицензию. Либо ваш продукт белый в плане лицензий, либо он их нарушает и вы находитесь из-за этого в зоне риска. Это как с электриками которые нарушают ТБ - не все сталкиваются с последствиями своих нарушений, но это не значит что так поступать правильно. Цитата(AlexandrY @ Aug 7 2017, 18:45)  А привязка к узкому семейству чипов это даже хорошо, не будет ненужных веток и фрагментации. Ммм, давайте не будем называть недостатки достоинствами?
|
|
|
|
|
Aug 7 2017, 16:48
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(Kabdim @ Aug 7 2017, 19:26)  Это как с электриками ... Ммм, давайте не будем называть недостатки достоинствами?  При чем тут электрики если вы плохо поняли лицензию. Вот у меня выложен стек USB. Абсолютно лицензионно чисто. А недостатком привязка возможно была до того как объявили о i.MX RT. А теперь это только достоинство.  Цитата(Шаманъ @ Aug 7 2017, 18:50)  Ну вот еще один пуп вселенной, которому все должны - проходите мимо, я Вас не задерживаю. И да продолжайте хамить - сразу видно, что на другое не способны... Уважаемый, если вы тут хотите продавать, то что лежит бесплатно на каждом углу, то имейте совесть. И не флудите в форуме.
|
|
|
|
|
Aug 7 2017, 17:51
|
Группа: Участник
Сообщений: 12
Регистрация: 15-05-17
Пользователь №: 97 085

|
Цитата(prottoss @ Aug 5 2017, 14:18)  Нате, глумитесь. Премного благодарен! Многая лета. В книге 'Making Embedded systems' описывается шаблон программирования МК под названием 'драйвер', ну это так. Залез в USB-FS-Device_Lib_V4 и ужаснулся, мрачное нагромождение файлов и не понятно по какому принципу. Меня интересовало как можно подойти к проблеме. Общая схема, два конечных автомата, один автомат отвечает за переходы между состояниями USB устройства, а второй за сборку управляющих запросов из отдельных транзакций. После сборки сообщения , передаётся первому автомату и служит событием, которое может изменить его состояние. Когда смоделировать поведение устройства оказывается затруднительным одним автоматом, то оказывается просто смоделировать несколькими конечными автоматами, взаимодействующими друг с другом передачей сообщений.  Но при ближайшем рассмотрении выяснилось, что обработку управляющих запросов от хоста невозможно представить одним конечным автоматом. Схема сложней. После выполнения транзакции SETUP нужно раскодировать конфигурационный пакет. По результатам расшифровки выбирается один из некоторого множества конечных автоматов, отражающий запрос. Ниже граф переходов для запроса GET_DESCRIPTOR c несколькими стадиями данных. Транзакции выполняются аппаратурой автоматически, по результатам выполнения выставляют флаги. Хост инициирует тр. setup, из сост. I переходит в S, готовит буфер USB для следующей транзакции от хоста и т.д.
Эскизы прикрепленных изображений
|
|
|
|
|
Aug 7 2017, 18:34
|
Знающий
   
Группа: Участник
Сообщений: 758
Регистрация: 27-08-08
Пользователь №: 39 839

|
Цитата(AlexandrY @ Aug 7 2017, 19:48)  Уважаемый, если вы тут хотите продавать, то что лежит бесплатно на каждом углу, то имейте совесть. И не флудите в форуме. Уважаемый, тут нет покупателей, чтобы что-то продавать Да и кому продавать у меня есть, как пример, на применение моей RTOS были куплены эксклюзивные права вместе с поддержкой-сопровождением одной не нашей конторой, которая с ней выпускает девайсы тиражем несколько десятков тысяч в год (видимо на каждом углу у них не получилось найти  ), так что вопрос продаж меня совсем не волнует, уж поверьте...
Сообщение отредактировал Шаманъ - Aug 7 2017, 18:36
|
|
|
|
|
Aug 8 2017, 04:00
|
Группа: Участник
Сообщений: 12
Регистрация: 15-05-17
Пользователь №: 97 085

|
И ещё вопрос для специалистов. Могут ли быть вложенными управляющие передачи? Например, началась передача setup и не завершая её хост начинает новую? Из разных источников разные ответы, по-моему полная ерунда. То что хост может внезапно закончить начатаю передачу, это знаю. А вот вложенные передачи? Тогда нужно складывать контекст. Да и какой максимальный уровень вложенности? В "USB complete" написано что вроде как могут быть вложенные.
|
|
|
|
|
Aug 8 2017, 14:02
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(AlexandrY @ Aug 7 2017, 22:48)  При чем тут... Я попрошу Вас, как модератора, не флудить в ветке! Вы не одного поста по теме не написали... Как обычно, в прочем. Цитата(linuxbergi @ Aug 7 2017, 23:51)  Но при ближайшем рассмотрении выяснилось, что обработку управляющих запросов от хоста невозможно представить одним конечным автоматом. Схема сложней... Заблуждаетесь. Совершенно один конечный автомат. У меня описан вот так: Код /* Control transfer states */ typedef enum __USBD_CTRL_STATE { USBD_CTRL_STAGE_SETUP, /* SETUP packet */ USBD_CTRL_STAGE_DATA_OUT, /* OUT data packet */ USBD_CTRL_STAGE_DATA_IN, /* IN data packet */ USBD_CTRL_HANDSHAKE_ZLP_IN, /* The handshake IN ZLP packet was sent */ USBD_CTRL_WAIT_HANDSHAKE_ZLP_OUT, /* Wait a OUT ZLP packet */ USBD_CTRL_STALL_REQ, /* STALL enabled on IN & OUT packet */ } USBD_CTRL_STATE, *P_USBD_CTRL_STATE; Цитата(linuxbergi @ Aug 8 2017, 10:00)  И ещё вопрос для специалистов. Могут ли быть вложенными управляющие передачи? Например, началась передача setup и не завершая её хост начинает новую? Из разных источников разные ответы, по-моему полная ерунда. То что хост может внезапно закончить начатаю передачу, это знаю. А вот вложенные передачи? Тогда нужно складывать контекст. Да и какой максимальный уровень вложенности? В "USB complete" написано что вроде как могут быть вложенные. На чем я учился - во вложении. Вложенных передач нет. Есть стэйт машина, любой шаг влево-вправо - сброс.
--------------------
|
|
|
|
|
Aug 9 2017, 10:05
|
Группа: Участник
Сообщений: 12
Регистрация: 15-05-17
Пользователь №: 97 085

|
В своё время интересовался USB , даже опубликовал результат своих изысканий https://yadi.sk/i/kQfoeUJ8iicDiЧем плохи доки по стандартам? Они объективно очень громоздки в силу их специфики, там предусматриваются все варианты событий, какие только возможны. Например если смотреть стандарт по HID, то умопомрачительно, а кто знает, что такое custom hid (наиболее используемый на практике), тот рассмеётся. На практике можно многое отбросить, скостить углы. Основу моего проекта составляют идеи предоставленные здесь: http://mcu.goodboard.ru/viewtopic.php?id=40Может модератор не удалит сей ценный материал?
|
|
|
|
|
Aug 9 2017, 13:29
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(linuxbergi @ Aug 9 2017, 13:05)  В своё время интересовался USB , даже опубликовал результат своих изысканий Вы идете совершенно неэффективным путем. Если нужен эталон как правильно писать под USB в embedded то всегда смотрят у Micrium-а. Он делает исходники специально так чтобы начинающие могли легче понять как все внутри устроено. И только у Micrium-а документация действительно объясняет как работает их софт.
Диаграмма выше как бы намекает, что вам до своего "драйвера USB" как до луны.
А эта диаграмма показывает слои. У Micrium-а драйверы действительно являются драйверами. И как видно драйвер у них это даже не половина дела. Справок где берут Micrium USB, документацию на него и какая у него лицензия не даю.
|
|
|
|
|
Aug 10 2017, 06:36
|
Группа: Участник
Сообщений: 12
Регистрация: 15-05-17
Пользователь №: 97 085

|
За информацию и отклики благодарен всем, рискну выложить схему реализации, может кто-нибудь ещё подкинет идей.  В цикле мониторятся флаги событий. GLOBAL_SM - мониторит RESET, SUSPEND и пр. Группа TRN_SM собирает из отдельных транзакций запросы управления, мониторит флаги транзакций передач управления. После транзакции setup, выполняется парсинг пакета конфигурации (выделено голубым), остальные секции не реагируют, состояние автомата фиксируется в глобальных переменных. По транзакции IN выполняется соответственная секция кода, состояние фиксируется в гл. переменных. Транзакция setup общая для всех передач управления, а дальнейшая реализация зависит от парсинга конфигурационного пакета из этой самой транзакции setup. В секции setup устанавливается указатель на функцию реализующую конкретный запрос и далее эта функция вызывается каждый раз при выполнении последующих транзакций пока запрос не закончится выполняться. Думаю схема ясна. Обработчик транзакций передачи данных прост, по сравнению с управляющими, поэтому пока не рассматривается
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|