Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > инкапсуляция данных в пакет Xmodem |
Автор: daemonaz 8.1.2012, 13:44 |
Я новичок в Qt, у меня цель написать код, который бы отправлял прошивку флеш микроконтроллера, подключенный к COM-порту, по протоколу Xmodem, я создал отдельный класс Xmodem, но не знаю как правильно было бы реализовать инкапсуляцию данных из файла в пакет xmodem, есть ли у кого нибудь готовая реализация? Буду благодарен если кто-нибудь посоветует куда посмотреть.. Вопрос вот в чем, я использую в качестве пакета QByteArray, куда инкапсулирую данные прочитанные из файла, но получилось у меня довольно громоздко из трех массивов: один -для данных, которые я извлек из файла, второй - для служебной информации пакета (SOH, num, ~num), затем слиянием двух массивов делаю третий и отправляю в COM-порт. Как сделать более компактно и быстро? Есть вариант с использованием сериализации DataStream, но не знаю как его использовать в данном случае |
Автор: daemonaz 8.1.2012, 23:26 | ||
borisbn, спасибо! Вот что получилось
Покритикуйте плиз код, это мой первый скажем так проект в QT, и заодно вопрос, хочу вывести на экран содержимое буфера побайтово, а выводится почему то в 32-хразрядном виде 0xffffffA5, как сделать чтобы массив выводился именно побайтово в виде 0xA5? Спасибо |
Автор: bsa 9.1.2012, 11:52 | ||||
мне только непонятно, а почему ты не отправляешь заголовок напрямую модему, а пихаешь во временный буфер? Так, думаю, было бы значительно более эффективно. Аналогично и с данными, т.е. ты читаешь их непосредственно перед отправкой. В этом случае будет значительно проще выполнить повтор передачи при возникновении ошибки (достаточно будет в очередь пакетов добавить номер повторяемого). QT = QuickTime. Не путай с Qt. По возможности не используй sprintf, а используй arg().
В твоем случае код подготовки к выводу можно переписать так:
|
Автор: daemonaz 11.1.2012, 15:38 |
bsa, спасибо! ![]() |
Автор: daemonaz 12.1.2012, 20:40 |
Мне нужно отправить через COM-порт заготовленный пакет, но с ожиданием подтверждения, по протоколу xmodem, и чтобы не висеть в бесконечном цикле ожидания подтверждения по таймауту я хотел бы реализовать это через поток, но не знаю как это можно сделать, буду благодарен если будет примерчик такого способа реализации.. Планируется использовать при передаче файла QProgressDialog, где-то читал что можно реализовать через поток. Буду благодарен за любую помошь. |
Автор: kuzulis 12.1.2012, 23:08 | ||
Да не нужен тебе поток в этом случае, тем более, если не еще знаешь что это такое и как им пользоваться. Используй сигналы/слоты для этого + QTimer для ожидания ответа. Также рекомендуется использовать готовые библиотеки для I/O через Serial порты, т.к. не понятно как ты там реализуешь у себя I/O и т.п. -- Также вместо crc16_ccitt() можно использовать Qt-шные функции (они вроде тоже могут считать CRC по разным там полиномам). |
Автор: daemonaz 13.1.2012, 08:52 | ||
Я использую библиотеку QextSerialPort, я обратил внимание на сигнал void QIODevice::readyRead () , он реализован в waitForReadyRead(), не это имели ввиду? Только хотелось бы понять механизм работы этой функции, или там сидим пока не придет сигнал, или же можем выполнять другую работу пока сигнал приема не придет? под Qt-шной функцией имеете ввиду qChecksum()? А где инициализируется полином? |
Автор: bsa 13.1.2012, 10:03 | ||
мне тоже интересно... |
Автор: daemonaz 13.1.2012, 10:41 | ||||
Я так понимаю это имеет смысль если реализованы отправка пакета и ожидание приема по отдельности, а если они в одной функции
А вообще сушествует ли готовый класс для работы с протоколом X-modem, Ymodem? |
Автор: kuzulis 13.1.2012, 12:39 | ||||||||
Лучше эту https://gitorious.org/qserialdevice/qserialdevice/archive-tarball/2.0
Нене, так делать не нужно, т.к. твой цикл while(1), затормозит/приостановит Qt-шный Event loop и у тебя будут тормоза GUI во время твоей транзакции.
В Qt их точно нету. Да и что ты подразумеваешь под готовым классом? Что он должен делать? ;)
Упс... Я думал что это запилили, судя по "утвердительным" высказываниям на форумах: http://developer.qt.nokia.com/forums/viewthread/13128 http://developer.qt.nokia.com/doc/note_revisions/136/229/view Значит я ошибся :( Это плохо, если нет такой возможности. Нужно запилить!!! ![]() |
Автор: daemonaz 13.1.2012, 16:42 | ||
я как раз пытаю Вашу библиотеку, если Вы действительно его автор, а как надо правильно подкиньте идею.. |
Автор: bsa 13.1.2012, 17:23 |
daemonaz, открываешь порт (объект serial типа SerialPort). Открываешь файл (объект file типа QFile). Подключаешь сигнал readyRead к слоту readData (или как ты его назвал) твоего класса. Этот слот читает данные из порта при вызове. Теперь тебе необходимо отправить признак начала передачи и проинициализировать переменную - номер текущего блока. Внутри readData ты читаешь данные из порта, на их основании принимаешь решение о дальнейших действиях. Если все нормально, ты посылаешь текущий блок, предварительно считав его в буфер. Или еще что-нибудь. Все. функция завершилась. Но когда придут очередные данные она снова будет вызвана. |
Автор: kuzulis 13.1.2012, 17:24 | ||||||
вот идея:
т.е как то так:
Идея думаю ясна ![]() А вообще, такого рода задачи необходимо делать через State Machine, оно тогда будет нагляднее и меньше ошибок сделаешь, ИМХО |
Автор: daemonaz 13.1.2012, 19:33 |
Спасибо, kuzulis, супер! ![]() |
Автор: daemonaz 14.1.2012, 12:48 | ||
А вот это уже интересно, я правда имел дело с микроконтроллером, там да, понятно, а в Qt есть вроде QstateMachine, не это имели ввиду? |
Автор: kuzulis 14.1.2012, 13:13 |
Ну да. Сначала рисуешь на бумажке, какие должны быть состояния, переходы, что должно выполняться в каждом состоянии и т.п. а потом реализуеш на QStateMachine, сигналах/слотах. Вот, раз пошла такая пьянка, советую еще это почитать: http://www.eventhelix.com/realtimemantra/patterncatalog/protocol_layer.htm Может поможет в осмыслении глубины глубин. ![]() |
Автор: daemonaz 25.1.2012, 08:36 | ||
Вопрос к kuzulis по поводу библиотеки, я хочу вывести принятые данные на QPlainTextEdit, делаю с помошью сигнала readyRead() Почему то выводится не все содержимое, а кусками, кстати с QExtSerial у меня такого не было. Хотелось бы понять где ошибка? Может не успевает обрабатывать, нужен поток?
|
Автор: kuzulis 25.1.2012, 10:21 |
Сигнал readyRead() сигнализирует о том, что имеется некоторое количество входящих данных, доступных для чтения. Минимальное количество от 1 байта и больше. Внутри, в классе SerialPort, при приходе данных, автоматически вызывается нативная (платформо-зависимая) функция чтения данных, которая читает доступые в текущий момент данные в буфере UART и помещает их в кольцевой буфер класса. При открытии порта, его дескриптор настраивается таким образом, чтобы все функции чтения возвращались немедленно, т.е. читают то, что есть (или то чего нет) и сразу возвращают управление, не ожидая пока придут следующие данные. Таким образом, если передаешь, скажем, 100 байт, то оно будет читать это порциями, по N байт (где N - кол-во байт, успевших придти в UART). Из этого всего следует, что метод readAll() вернет всё, что есть в внутреннем буфере класса!!! т.е. это не значит, что вызвав readAll() ты получишь весь пакет данных целиком! Это не ошибка, так и должно быть, всё успевает обработать, и поток не нужен (хотя, по хорошему нужен, т.к. в текущей реализации при интенсивном обмене данными будет фризить GUI под виндой - да есть такой косячок). Как сделать так, чтобы принимался весь пакет - тебе было дано решение выше, на первых страницах твоей темы. |
Автор: daemonaz 25.1.2012, 14:56 |
kuzulis, спасибо! на прием данных наконец-то вынес в поток, но проблема оставалась до сих пор, пока вместо readAll не взял read(count), все заработало.. Специфичная такая функция.. ![]() |
Автор: kuzulis 25.1.2012, 15:40 | ||
Да и read(count) аналогично работает: если запрашиваешь кол-во данных, превышающее их реальное текущее значение в буфере - то сразу вернет только то что в буфере, а не count, также не будет ждать пока набегут все count. В принципе, readAll() и read(<стопицотмильеновбайт>) эквивалентны, за исключением того, что в readAll() происходит некий оверхед и она чуть медленнее работает. |
Автор: tzirechnoy 25.1.2012, 19:13 |
А есть ли смысл писать свой xmodem, а не использовать бинарник sx из lrzsz? |
Автор: daemonaz 30.1.2012, 13:51 |
tzirechnoy, я рад бы использовать их, сам пишу под Линух, но юзеры хотят на windows only.. |
Автор: tzirechnoy 30.1.2012, 15:13 |
Вы так говорите, будто lrzsz под windows мало. |