Arduino Mega Server
Модератор: Alex
-
- Сообщения: 28
- Зарегистрирован: Сб июн 06, 2015 6:04 pm
- Благодарил (а): 9 раз
- Поблагодарили: 3 раза
Re: Arduino Mega Server
Плюс за json, меньше передаваемых данных проще парсить, давненько даже либу встречал для ардуины.
Отправлено с моего P780 через Tapatalk
Отправлено с моего P780 через Tapatalk
- uni
- Сообщения: 191
- Зарегистрирован: Вс июл 26, 2015 9:21 pm
- Откуда: Екатеринбург
- Благодарил (а): 4 раза
- Поблагодарили: 7 раз
- Контактная информация:
Re: Arduino Mega Server
Вот ссылка на сайт проекта jsmn: http://zserge.com/jsmn.html + исходники: https://bitbucket.org/zserge/jsmn/overview
Похоже, что работа над парсером продолжается и мне стоит обновить свой вариант, т.к. я уже не помню когда его правил.
Вот сравнительная статья с тестами различных парсеров: Comparison and microbenchmark of #JSON parsers
Цитата:
Похоже, что работа над парсером продолжается и мне стоит обновить свой вариант, т.к. я уже не помню когда его правил.
Вот сравнительная статья с тестами различных парсеров: Comparison and microbenchmark of #JSON parsers
Цитата:
jsmn
http://zserge.bitbucket.org/jsmn.html (MIT)
Парсер для эмбедщины и других сред с ограниченными ресурсами.
Парсинг использует обычный подход с ручной стейт-машиной. Аллокаций памяти ноль, потому что всё предварительно должно быть зааллоцировано в сплошном куске памяти при вызове парсера. Это для моих целей хорошо. Парсер потоковый, то есть его можно рестартовать, если данных не хватило.
Парсер ожидает, что данные в буфере для парсинга будут ASCIIZ, то есть 0-терминированными. Немного неприятно, но тоже себе идиома.
Почему неприятно? Потому что не всегда ноль доступен (например, как парсить JSONP, даже если известны границы JSON?), а поставить '\0' в данный извне буфер идиоматически можно только с его полной реаллокацией.
Тесты делаются как для хороших данных, так и для плохих, неполных. Fuzz-тестов нет.
Претендент выходит в финал.
UPD: Связался с автором jsmn, и он починил работу с выходным массивом. Теперь по производительности парсинга jsmn минимум в пару раз обгоняет все остальные протестированные проекты.
Россия навсегда!
-
- Сообщения: 110
- Зарегистрирован: Пт авг 14, 2015 11:24 am
- Благодарил (а): 3 раза
- Поблагодарили: 6 раз
Re: Arduino Mega Server
Парсеры json в embedded упираются не в производительность, а в расход памяти. Особенно актуально для больших json файлов. Не видел парсера который может использовать фиксированный размер буфера для любого размера json, т.е. принимать json по частям, а часть может быть сама по себе невалидна (например скобка открылась, а закрывается она только в следующей части).
- uni
- Сообщения: 191
- Зарегистрирован: Вс июл 26, 2015 9:21 pm
- Откуда: Екатеринбург
- Благодарил (а): 4 раза
- Поблагодарили: 7 раз
- Контактная информация:
Re: Arduino Mega Server
Это вот он и есть. Можно посмотреть на тесты: Tests.cpp. Имеющихся у него возможностей достаточно для работы на мк.cg_shura писал(а):Парсеры json в embedded упираются не в производительность, а в расход памяти. Особенно актуально для больших json файлов. Не видел парсера который может использовать фиксированный размер буфера для любого размера json, т.е. принимать json по частям, а часть может быть сама по себе невалидна (например скобка открылась, а закрывается она только в следующей части).
Нужен только фиксированный буфер, достаточный для одного элемента в понимании jsmn. Если этот один элемент помещается в буфер, то его можно распарсить.
Россия навсегда!
-
- Сообщения: 110
- Зарегистрирован: Пт авг 14, 2015 11:24 am
- Благодарил (а): 3 раза
- Поблагодарили: 6 раз
Re: Arduino Mega Server
Да, но в конце части json парсер выдаст JSMN_ERROR_PART и неопонятно, это часть json обрезанная или действительно ошибка. Надо получать следующую часть json, сращивать недопарсенный кусок с предыдущей и т.д. Как-то муторно и ненадежно, или я недопонял как с ним работать при "скользящем" окне.uni писал(а):Нужен только фиксированный буфер, достаточный для одного элемента в понимании jsmn. Если этот один элемент помещается в буфер, то его можно распарсить.
-
- Сообщения: 2357
- Зарегистрирован: Пт апр 20, 2012 12:53 pm
- Благодарил (а): 42 раза
- Поблагодарили: 262 раза
Re: Arduino Mega Server
В связи с оптимизацией количество файлов уменьшилось, но увеличился их размер. И теперь стали заметны огрехи передачи файлов на SD карту по Serial (чем больше файл — тем больше вероятность ошибки передачи).
У кого есть возможность разобраться с проблемой передачи файлов по Serial — было бы здорово.
У кого есть возможность разобраться с проблемой передачи файлов по Serial — было бы здорово.
-
- Сообщения: 110
- Зарегистрирован: Пт авг 14, 2015 11:24 am
- Благодарил (а): 3 раза
- Поблагодарили: 6 раз
Re: Arduino Mega Server
А подробнее? В чем заключаются огрехи? Контрольная сумма файла не сходится? Или она не проверяется?Alex писал(а):стали заметны огрехи передачи файлов на SD карту по Serial (чем больше файл — тем больше вероятность ошибки передачи).
- uni
- Сообщения: 191
- Зарегистрирован: Вс июл 26, 2015 9:21 pm
- Откуда: Екатеринбург
- Благодарил (а): 4 раза
- Поблагодарили: 7 раз
- Контактная информация:
Re: Arduino Mega Server
Но ведь похож на потоковый парсер? Если мегабайты в мк не посылать, то можно и поработать? Я уже точно не помню, но по идее resume должен быть реализован, нужно лишь подвинуть указатель на начало буфера и сбросить ошибку.cg_shura писал(а):Да, но в конце части json парсер выдаст JSMN_ERROR_PART и неопонятно, это часть json обрезанная или действительно ошибка. Надо получать следующую часть json, сращивать недопарсенный кусок с предыдущей и т.д. Как-то муторно и ненадежно, или я недопонял как с ним работать при "скользящем" окне.uni писал(а):Нужен только фиксированный буфер, достаточный для одного элемента в понимании jsmn. Если этот один элемент помещается в буфер, то его можно распарсить.
Я давно его переделывал и не помню есть это или нет.
Россия навсегда!
-
- Сообщения: 2357
- Зарегистрирован: Пт апр 20, 2012 12:53 pm
- Благодарил (а): 42 раза
- Поблагодарили: 262 раза
Re: Arduino Mega Server
Файлы передаются потоковым методом. Processing закачивает файл в бинарном формате в массив и в цикле посылает в сериал. Но есть проблема: просто передать файл мало, нужно ещё в потоке умудриться передать имя файла (работа с директориями пока не поддерживается). Для того, чтобы передать мета-информацию (имя файла) в поток подмешиваются маркеры, которые в потоке выделяются на стороне Ардуины и при их помощи получается имя файла.А подробнее? В чем заключаются огрехи? Контрольная сумма файла не сходится? Или она не проверяется?
На стороне Ардуины потоковый декодер отделяет мета-информацию и записывает поток в файл. Название файла — из выделенных маркеров.
Всё это работает нормально процентов на 95 на небольших файлах и чем больше файл — тем больше вероятность ошибки. Проявляется в появлении мусора, потери части информации или преждевременном завершении передачи.
Я проверял код с обоих сторон и не нашёл ничего, что так может влиять на передачу. Причина дефекта мне не известна.
Замечено, что часто ошибка происходит в начале файла и введён «костыль» (функция errorProtection), который после первой строки принудительно шлёт массив мусора (на этот массив и приходится ошибка) и на стороне Ардуины этот массив отбраковывается и не пишется в файл.
Таким образом нужно установить причину возникновения ошибок передачи и добиться точной байт в байт передачи файлов. Сейчас более-менее нормально передаются только текстовые файлы. Картинку пока передать не получится.
-
- Сообщения: 110
- Зарегистрирован: Пт авг 14, 2015 11:24 am
- Благодарил (а): 3 раза
- Поблагодарили: 6 раз
Re: Arduino Mega Server
Просмотрел arduino_mega_server\upload.ino, это же оно? Не удивительно, что могут быть ошибки. Сложно понять что где. Для начала я бы сделал конечный автомат, типа такого:Alex писал(а):Но есть проблема: просто передать файл мало, нужно ещё в потоке умудриться передать имя файла
enum UploadFileState
{
UFS_IDLE,
UFS_WAIT_FILE_DESC,
UFS_WAIT_FILE_PART,
US_FILE_ARRIVED
}
struct FileDesc
{
char fileName[20];
int fileSize;
int fileCrc32;
}
...
FileDesc _fileDesc;
UploadFileState _state = UFS_WAIT_FILE_DESC;
int _writenFileSize = 0;
File _file;
...
void loop()
{
switch (_state)
{
case UFS_WAIT_FILE_DESC:
{
// Если что-то есть в Serial - значит это заголовок файла. А именно: имя файла, его размер и CRC32.
if (serial.available())
{
serial.readBuffer(&_fileDesc, sizeof(_fileDesc));
_file.create(_fileDesc.fileName);
_state = UFS_WAIT_FILE_PART;
}
break;
}
case UFS_WAIT_FILE_PART:
{
// Если что-то есть в Serial - значит это кусок файла. А именно: имя файла, его размер и CRC32.
if (serial.available())
{
static char buff[128];
int readLen = serial.readBuffer(&buff, sizeof(buff));
_file.writeBuffer(&buff, readLen);
_writtenFileSize += readLen;
if (_writtenFileSize >= _fileDesc.fileSize)
_state = UFS_FILE_ARRIVED;
}
break;
}
case UFS_WAIT_FILE_PART:
{
// Проверяем что СRC32 принятого файла равно _fileDesc.CRC32 и если это не так - удаляем файл
break;
}
...
}
}