Страниц: 1 2 3 [4] 5
  Печать  
Автор Тема: Работа через USB с FlirOne Gen 2  (Прочитано 4957 раз)
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #45 : Июля 10, 2017, 12:38:45 pm »

Цитировать
Почему метод написан так, что сам код не объясняет решение/подход?

Но этот вопрос сродни вопросу, как имея формулу расчета, понять, как она была выведена? За каждой функцией лежит некий алгоритм. Вот в приведённой функции, например, даже прочитав описание идеи (я эту идею взял из книжки Хонича 1996 года “Как самому написать трёхмерную игру”, описывающую DooM изнутри) не сразу понимаешь, как это работает – придётся посидеть с карандашом и понять идею изменения столбцов экрана при проецировании сегмента на экран.

Цитировать
начиная от того что нет нужды разделять объявления локальных переменных и их инициализацию, 

Ну, это вопрос эстетики. На мой вкус так смотрится лучше. Smiley Также не люблю в одну строчку объявлять кучу переменных – каждой своя строка – ну не нравится чисто визуально.

Цитировать
до того - что циклы с отрисовкой - явные кандидаты на сервис-методы

Да ну, зачем ещё ради 10 строчек отдельную функцию плодить…

Цитировать
Читаемость кода - в приоритете даже над его производительностью!

Это верно. Однако, тут тоже на всех не угодишь.

Цитировать
Вот, все - мне нечего возразить человеку который регулярно игнорирует инициализацию выражением и на следующей строчке присваивает переменной вычисляемое значение.

Это непривычный для меня вариант. Smiley Может быть, потом понравится. Smiley

Цитировать
Ну и так, между прочем - он вернет константную ссылку. Между прочим, метод может быть констэкспр - вычисленный на этапе компиляции. Метод может быть заинлайненый.

В случае с классом - да, все эти методы будут inline (если я их не вынесу в cpp-файл). В других случаях с заданным явно inline - как повезёт. В целом, да, использование класса снимет эту проблему. Хотя, возможно, стоит всё же посмотреть IDA что конкретно сделает компилятор и на что будет похож такой код в сравнении с обычным макросом.
Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #46 : Июля 10, 2017, 02:10:21 pm »

Но этот вопрос сродни вопросу....
Я вдруг понял - Вам не нужны объяснения). Странно правда, что Вы исренне удивляетесь при этом замечаниям сторонних людей)

Цитировать
стоит всё же посмотреть IDA что конкретно сделает компилятор и на что будет похож такой код в сравнении с обычным макросом.

О! Эта великая экономия на спичках! Вот они преимущества макросов ))
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #47 : Июля 10, 2017, 02:28:31 pm »

Цитировать
Я вдруг понял - Вам не нужны объяснения). Странно правда, что Вы исренне удивляетесь при этом замечаниям сторонних людей)

Да нет, нужны. Smiley Просто я их так же анализирую, оцениваю и сравниваю в разных ситуациях. Вот, скажем, сейчас я применил RAII-подход, который вы советовали, для работы с базой данных (класс CRecordset из MFC). Этот класс действительно удобно так обернуть - экономия кучи проверок при подключении к записи базы данных. Но просто так я эти замечания не использую. Почему? Потому что за десятилетия у меня выработалась своя база приёмов и подходов и чтобы её менять нужно очень тщательно разобраться с плюсами и минусами. А следовать слепо приёмам любого автора - это настоящий фанатизм. Smiley Чего смешного на том же хабре в этих замечаниях? То, что если разбирается код того же Кармака, то находятся 1001 объяснение того, почему он сделал именно так, причём, от тех же людей, что только что ругали то же самое у других.  При этом на каждого критикующего автора найдётся такой же с противоположным мнением. Вот именно поэтому слепо следовать советам тоже не дело. А вот собирать их - отличная идея. Smiley

Цитировать
О! Эта великая экономия на спичках! Вот они преимущества макросов ))

Так в разных ситуациях по-разному. Есть циклы, которые крайне критичны, и стоит их чуть изменить, как быстродействие упадёт колоссально (или вырастет Smiley ). И да, я часто работаю с довольно низкоскоростными устройствами и часто вижу, что быстродействия катастрофически не хватает.
« Последнее редактирование: Июля 10, 2017, 02:48:16 pm от da-nie » Записан

И день и ночь в пути
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #48 : Сентября 05, 2017, 09:22:02 pm »

А не знает ли кто, как может сложиться следующая ситуация: я подключил этот тепловизор к stm32f4 Discovery к USB-Host. Проект я создал в CubeMX. То есть, вся обвязка USB там точно верная. Проблема в том, что тепловизор в дескрипторе конечной точки передаёт wMaxPacketSize=0x40. И это не управляющие точки. Однако, операционным системам тепловизор по usb -vvv и lsusb -vvv сообщает о конечных точках вот что:


Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    240
      bInterfaceProtocol      1
      iInterface              6 com.flir.rosebud.fileio
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
       wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x04  EP 4 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               1

То есть, операционным системам тепловизор рапортует о 512 байтах. А микроконтроллеру о 64. Это вообще как так может быть? Я обыскал всю библиотеку USB для STM32 и не нашёл ничего такого, что могло бы так повлиять на решение тепловизора выдавать такие параметры. Там обычная энумерация с получение дескрипторов конфигураций и устройства и задание адреса устройства. Но что-то же заставило тепловизор выдать 64, а не 512 байт? Использую я режим USB Full Speed, 12 МБ/c. Кстати, а никто не знает, запрос SET_DESCRIPTOR позволит изменить параметры конечной точки (и вообще, для чего он применяется? В инете его что-то не используют). Я бы оставил бы это всё без внимания, но на 64 байтах я не успеваю принять все данные, хотя у контроллера аж 168 МГц частота и он вроде бы должен успевать (хотя тут и PC пропускал кадры с радостью под Linux). А конечная точка в 512 байт, думаю, позволила бы пропускать кадры гораздо реже.
« Последнее редактирование: Сентября 05, 2017, 09:24:49 pm от da-nie » Записан

И день и ночь в пути
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #49 : Сентября 06, 2017, 03:10:17 pm »

Понятно, в чём дело. 64 - максимальный размер пакета для LowSpeed и FullSpeed. А для HeighSpeed максимальны размер 512.
Записан

И день и ночь в пути
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #50 : Октября 06, 2017, 10:45:12 pm »

Экспериментальная альфа-версия прошивки микроконтроллера STM32F407 платы STM32F4Discovery для работы с тепловизором Flir One Gen 2 через USB: ссылка на репозиторий

Из особенностей:
1) Проект создан в Cube MX для Keil 5 - без Cube MX запустить USB с уровня HAL или CMSIS было бы ооочень непросто.
2) Весь объём кода от Cube MX для поддержки процессора в комплекте. Здравствуйте мегабайтные *.h-файлы CMSIS и такого же размера библиотеки HAL в *.c-файлах для работы с периферией.
3) Если три секунды нет картинки, процессор перезагружается, и процесс энумерации начинается заново.

Подключён дисплей 320x240 на контроллере HX8347D.
Через FSMC запуск не удался (возможно, мешают устройства на плате),поэтому контакты дисплея были заново подключены так:
D0-D7 - PE4-PE11
CS - PE12
RD - PE13
RW - PE14
RS - PE15
RST - PE2

А вот так работает: https://youtu.be/-elBzHRjZxo
« Последнее редактирование: Октября 15, 2017, 09:51:23 pm от da-nie » Записан

И день и ночь в пути
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #51 : Октября 13, 2017, 07:41:36 pm »

А вот интересно, я сделал отдельный класс для констант CConsts:

Код:
class CConsts
{
 protected:
 public:  
  //конструктор
  CConsts(void) {};
  //деструктор
  ~CConsts() {};
 public:
  //количество точек сигнала оптических датчиков
  const unsigned long GetSignalPointAmount(void) {static const unsigned long ret=128; return(ret);}
  //время паузы в циклах ожидания данных, нc
  const unsigned long GetPauseTimeNSec(void) {static const unsigned long ret=1000; return(ret);}
  //время добавления точек диаграммы, секунды
  const unsigned long GetDiagramTimeSec(void) {static const unsigned long ret=600; return(ret);}
  //максимальное количество точек диаграммы  
  const unsigned long GetDiagramMaxPointsAmount(void) {static const unsigned long ret=1000; return(ret);}
  //начальное максимальное время записи диаграммы
  const unsigned long GetDiagramInitMaxTimeSec(void) {static const unsigned long ret=10*60*60; return(ret);}
  //рабочая частота  
  const unsigned long GetWorkingFrequencyHZ(void) {static const unsigned long ret=32; return(ret);}
  //количество гироблоков
  const unsigned long GetUnitAmount(void) {static const unsigned long ret=3; return(ret);}
  //сколько тактов допустимо пропустить устройству, чтобы считать его ещё работающим
  const unsigned long GetUnitEnabledCounterMaxValue(void) {static const unsigned long ret=3*GetWorkingFrequencyHZ(); return(ret);}
  //сколько тактов допустимо пропустить АКУ, чтобы считать его ещё работающим
  const unsigned long GetACUEnabledCounterMaxValue(void) {static const unsigned long ret=3*GetWorkingFrequencyHZ(); return(ret);}
  //сколько тактов допустимо пропустить акселерометру, чтобы считать его ещё работающим
  const unsigned long GetAcsEnabledCounterMaxValue(void) {static const unsigned long ret=3*GetWorkingFrequencyHZ(); return(ret);}
  //сколько тактов допустимо пропустить БВФКП, чтобы считать его ещё работающим
  const unsigned long GetBWFKPEnabledCounterMaxValue(void) {static const unsigned long ret=3*GetWorkingFrequencyHZ(); return(ret);}
  //время аварийного торможения в тактах
  const unsigned long GetAlarmCounterMaxValue(void) {static const unsigned long ret=4*60*GetWorkingFrequencyHZ(); return(ret);}
  //сколько тактов отсутствут электропитание, чтобы считать это за аварию
  const unsigned long GetPowerOffCounterMaxValue(void) {static const unsigned long ret=60*GetWorkingFrequencyHZ(); return(ret);}
  //максимальное значение счётчика для принудительного сохранения данных (1 такт - 10 мс)
  const unsigned long GetSaveChacheCounterMaxValue(void) {static const unsigned long ret=100*60; return(ret);}
  //количество точек в графиках сигналов
  const unsigned long GetTrendSignalsPointsAmount(void) {static const unsigned long ret=350; return(ret);}
  //количество точек в графиках углов
  const unsigned long GetTrendAnglesPointsAmount(void) {static const unsigned long ret=350; return(ret);}
  //количество точек в графиках углов в неподвижном основании
  const unsigned long GetTrendStillAnglesPointsAmount(void) {static const unsigned long ret=295; return(ret);}
  //какой такт добавлять в график углов в неподвижном основании
  const unsigned long GetTrendStillVoidCycle(void) {static const unsigned long ret=12; return(ret);}
  //бесконечно малое
  const double GetZeroEPS(void) {static const double ret=0.00000000001; return(ret);}
  //точность задания углов ПАК, угловые секунды
  const float GetPAKAngleSecEPS(void) {static const float ret=10; return(ret);}
};

И использовал этот класс для задания структуры с вложенной структурой внутри, вида
struct SSettings
{
 long Port;//порт сервера
 struct SUnit
 {
  //....что-то тут
 } sUnit[cConst.GetUnitAmount()];// !!!!!Вот в чём проблема!!!!!
 bool EnabledPowerMonitor;//разрешение контроля питания
};

И вот компилятор IDE Momentics теперь ругается - он позволяет задавать Port (sSettings.Port=...), но не позволяет задавать EnabledPowerMonitor. Пишет, что структура переменного размера. Э... Ну, логично - размер ведь задан в другом модуле, а про него компилятор ничего не знает. Только вот как это обойти?  Roll Eyes
« Последнее редактирование: Октября 13, 2017, 07:46:46 pm от da-nie » Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #52 : Октября 16, 2017, 03:00:14 pm »

Цитировать
А вот интересно, я сделал отдельный класс для констант CConsts:
На первый взгляд вам вообще класс не нужен, и объект создавать этого класса вроде бы нет такой необходимости. Достаточно было все эти методы объявить свободными и в
едином неймспейсе. Разумеется, если речь о модульности (хедеры и сипипишники в том же числе), то так же странно - почему реализация методов в "хедере".

С таким классом как ваш (который не содержит данные, а обеспечивает доступ к константам через методы) - достаточно в каждом модуле объявить свой объект cConst.
И лучше это сделать непосредственно в момент вызова (так как создание объекта по сути ничего не стоит - он пустой).
Но опять же, вы из всех путей нашли самый извращенный )) Вы почему-то решили для возвращения конкретного значения создавать статический объект. Возвращаете его по значению (при этом возвращаете как константный объект, а сам метод не константный - но это все дело десятое и к вашему вопросу сейчас мало относится, просто рано или поздно вернетесь к интерфейсу и все равно сделаете правильно)
Так вот, возвращая по значению - вы тем самым уже гарантируете что внутренне значение снаружи изменено быть не может. А значит вполне можно было сделать и так:
Код:
unsigned long CConsts::GetPowerOffCounterMaxValue() const
{
  return 60*GetWorkingFrequencyHZ();
}

Цитировать
И использовал этот класс для задания структуры с вложенной структурой внутри, вида
struct SSettings
{
 long Port;//порт сервера
 struct SUnit
 {
  //....что-то тут
 } sUnit[cConst.GetUnitAmount()];// !!!!!Вот в чём проблема!!!!!
 bool EnabledPowerMonitor;//разрешение контроля питания
};

Конкретно с вашей проблемой - вам необходимо знать размер вашего массива на момент компиляции. Классом который оперирует и вычисляет/возвращает свои значения в рантайме - воспользоватся не получится. Для этого вами придется использовать constexpr методы/значения - они вычисляться на этапе компиляции.
Но я так же бы рекомендовал второй подход. Начните программировать в стиле C++. Все структуры как и классы можно (в большинстве случаев - даже нужно) инициализировать с помощью механизмов конструкторов.
Если тип SSettings может быть инициализирован каким-либо объектом/размером - инициализируйте этим объектом/размером непосредственно в конструкторе, например:
Код:
struct SSettings
{
 long Port;//порт сервера
 struct SUnit
 {
  //....что-то тут
 };
 using SUnitList_t = std::vector<SUnit>;
 SUnitList_t sUnits;  // и никаких проблем

 bool EnabledPowerMonitor;//разрешение контроля питания

//////

 SSettings()
   : SSettings(CConsts {})
 {
 }

 explicit SSettings(const CConsts& initObj)
   : Port (0)
   , sUnits(initObj.GetUnitAmount())  // перенесли инициализацию в рантайм
   , EnabledPowerMonitor(false)
 {
 }
};
« Последнее редактирование: Октября 16, 2017, 04:16:01 pm от lastcross » Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #53 : Октября 16, 2017, 06:40:35 pm »

Спасибо за ответ. Smiley Я и не сомневался, кто из присутствующих тут напишет. Smiley

Цитировать
На первый взгляд вам вообще класс не нужен, и объект создавать этого класса вроде бы нет такой необходимости. Достаточно было все эти методы объявить свободными и в
едином неймспейсе. Разумеется, если речь о модульности (хедеры и сипипишники в том же числе), то так же странно - почему реализация методов в "хедере".

Просто приятно, когда всё собрано в обном месте - в данном случае, в классе. Я, может быть, потом часть констант из констант переведу в загружаемые из файла параметры. С классом удобно. Почему в заголовочном файле - по двум причинам: и лень было реализацию писать отдельно, и наглядно - все описания рядышком, и всё как встраиваемые функции соберётся.

Цитировать
С таким классом как ваш (который не содержит данные, а обеспечивает доступ к константам через методы) - достаточно в каждом модуле объявить свой объект cConst.

Можно, конечно. Только в чём же будет выгода, всесто extern сделать статический объект для каждого модуля?

Цитировать
И лучше это сделать непосредственно в момент вызова (так как создание объекта по сути ничего не стоит - он пустой).

Вы имеете в виду, использовать как временный объект при получении каждой константы? Конечно, можно и так. Просто, а... зачем?  Shocked

Цитировать
Но опять же, вы из всех путей нашли самый извращенный ))

О, таких путей Си++ предлагает просто множество. Smiley Грех не воспользоваться. А как приятно видеть в IDE Momentics после автоматической замены во всех файлах макроса на такой объект ( с ошибочной заменой в ряде мест - заменяемая фраза оказалась частью большей) "неизвестная ошибка компилятора номер..." и ссылку на сайт для скидывания информации о том, как мне удалось эту ошибку сделать. Grin Я долго не мог понять, а что произошло-то, пока не обнаружил неверную замену.

Цитировать
при этом возвращаете как константный объект, а сам метод не константный

Да просто с вероятностью 100% не буду я никогда этот объект cConst никуда как константный передавать (он глобальный - у меня всё-таки есть пара глобальных объектов на всю программу). Да и вообще, я просто от нечего делать решил небольшой рефакторинг сделать. Ну и так, из интереса, заменить ряд структур на классы, да и макросы на классы тоже. Всё-таки программу три года я не улучшал, и накопились неудачные на текущий момент решения, мешающие её развивать дальше.

Цитировать
Классом который оперирует и вычисляет/возвращает свои значения в рантайме - воспользоватся не получится. Для этого вами придется использовать constexpr методы/значения - они вычисляться на этапе компиляции.

Увы, это достаточно новый оператор и IDE Momentics с её компилятором его вряд знает.

Цитировать
Так вот, возвращая по значению - вы тем самым уже гарантируете что внутренне значение снаружи изменено быть не может. А значит вполне можно было сделать и так:

Ну да, ну да. Можно было, конечно. Я ещё не решил, что мне нравится больше (да, есть фразы комментариев и текст, который просто вызывает какое-то отторжение, а есть наоборот). Smiley

Цитировать
Начните программировать в стиле C++. Все структуры как и классы можно (в большинстве случаев - даже нужно) инициализировать с помощью механизмов конструкторов.

Проблема в том, что SSettings не единственный, кому требуются эти самые константы. Его-то можно так инициализировать и вектор ему поставить. А вот есть структуры протоколов обмена - они целиком по сети пойдут один-в-один. А часть кода вообще кусок на чистом Си - эта часть вставляется потом в микроконтроллер один-в-один. А кстати, надо глянуть, не попадёт ли туда часть констант из этого класса.
« Последнее редактирование: Октября 16, 2017, 06:45:35 pm от da-nie » Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #54 : Октября 16, 2017, 08:04:33 pm »

Цитировать
и всё как встраиваемые функции соберётся.
Кстати вообще нет никакой прямой связи что будет собираться встраиваемо а что нет. Метод может быть и встраиваемым даже если его реализация внутри cpp-модуля (яркий пример лямбды)

Цитировать
Можно, конечно. Только в чём же будет выгода, вместо extern сделать статический объект для каждого модуля?
Речь шла скорее о том чтобы создавать переменные CConsts налету, прям перед вызовом. По сути они не должны занимать сколько-либо памяти. С другой стороны - преимущество сгруппированных в пространстве имен методов по сравнению с такими вот классом в том - что для пространства имен не требуется создавать объекты (описывать это явно).
Но да, если вы хотите использовать свой класс как объект который что-либо загружает, хранит состояние - то со свободными функциями все будет посложнее.

Цитировать
Вы имеете в виду, использовать как временный объект при получении каждой константы? Конечно, можно и так. Просто, а... зачем?  Shocked
Зачем Вам - я не знаю) Но могу предположить, что в упрощенном варианте ваш объект может хранить/ссылаться на разные наборы "констант" (загруженных из файла/полученных по сети). Либо объекты эти могут быть инициализированы частично и иметь возможность объединятся или разделятся (компоноваться в единую всеобъемлющую настройку).
Один словом - состояния набора "констант" может зависеть от условий вызова. Вот тогда такой объект удобно будет формировать непосредственно перед вызовом анализируя некие условия

Цитировать
О, таких путей Си++ предлагает просто множество. Smiley Грех не воспользоваться. А как приятно видеть в IDE Momentic ...
Проблемы среды разработки - это только проблема среды разработки, а не языка. Имхо - я бы для упрощенного случая сделал бы пространство имен с константами, сделал бы отдельно класс настроек который может быть кем-то заполнен (из файла/сети или другого ввода), а по умолчанию инициализировался бы значениями вызываемых методов (методы бы возвращали по значению неименнованные константы/литералы)

Цитировать
Да просто с вероятностью 100% не буду я никогда этот объект cConst никуда как константный передавать
Я просто отметил - что константность к возвращаемому значению это многословность, которая для читающего Ваш код человека немного вводит в некое заблуждение (не понятно что вы этим хотели сказать - не хотите чтобы возвращаемое значение изменялось, но оно же возвращается по значению, а значит с конст или без - оно никогда не поменяет внутренне состояние объекта. Если же вы хотели обеспечить контракт вызова - то следовало вероятно сделать конст-метод, но вы этого не сделали. Это когда const в конце объявления метода)

Цитировать
Увы, это достаточно новый оператор и IDE Momentics с её компилятором его вряд знает.
Это конечно жаль


Цитировать
А вот есть структуры протоколов обмена - они целиком по сети пойдут один-в-один. А часть кода вообще кусок на чистом Си - эта часть вставляется потом в микроконтроллер один-в-один. А кстати, надо глянуть, не попадёт ли туда часть констант из этого класса.
Ну вы же в курсе что вектор от вашего массива отличатся будет незначительно. У вектора можно запросить указатель на данные которые будут представлены в точь точь как если бы данные хранились в вашем массиве. Вас смущает тот момент что сейчас вы просто берете адрес объекта настроек SSettings и передаете его в сеть, а вот с вектором внутри вам придется помучатся. Но это же правильный подход! По-тому что, в ++ нет гарантий к размеру всех типов (единственные гарантии - это тип char, насколько помню). Кроме того - создав отдельный метод сереализации/десереализации - всегда можно контролировать правильный порядок байт (иногда есть большая разница как данные должны хранится оптимально и как передаваться/сохранятся по протоколу)
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #55 : Октября 16, 2017, 08:43:02 pm »

Цитировать
Кстати вообще нет никакой прямой связи что будет собираться встраиваемо а что нет. Метод может быть и встраиваемым даже если его реализация внутри cpp-модуля (яркий пример лямбды)

В смысле? Насколько я помню, все методы, реализованные в самом объявлении класса являются inline всегда (и, полагаю, даже если там функция в 1000 строк будет, она всё равно будет встраиваемой). А вот отдельная вынесенная реализация уже будет как удобно компилятору (если указать inline для такой функции, конечно).

Цитировать
Но могу предположить, что в упрощенном варианте ваш объект может хранить/ссылаться на разные наборы "констант"

Нет, это, к счастью, не потребуется. Smiley

Цитировать
Проблемы среды разработки - это только проблема среды разработки, а не языка.

Не спорю. Но забавно видеть, когда компилятор падает от написанного. Smiley

Цитировать
Если же вы хотели обеспечить контракт вызова - то следовало вероятно сделать конст-метод. Это когда const в конце объявления метода

Я знаю, как это делается. Smiley А зачем я возвращаю как const? Да просто это больше информация для компилятора  - так, на всякий случай.

Цитировать
Ну вы же в курсе что вектор от вашего массива отличатся будет незначительно. У вектора можно запросить указатель на данные которые будут представлены в точь точь как если бы данные хранились в вашем массиве.

Касаемо вектора - я где-то прочёл, что это не всегда так (я имею в виду, предложенный вами мне когда-то вариант с &vect[0]). В ранних стандартах порядок хранения в контейнерах не регламентирован. Это только сейчас так. Я понятия не имею, что умеет в QNX 6.3 компилятор и стандартные библиотеки.
А в структуре, которая передаётся как поток байтов, вектора внутри быть не должно - требуется ведь передать его содержимое, а не внутреннюю структуру вектора.
Я имею в виду:
Код:
struct SData
{
 unsigned long Size;
 struct SUnit
 {
  unsigned char Data[128];
 }
 vector<SUnit> vector_SUnit;
} sData;

Translate(&sData,sizeof(SData));

Translate(&sData,sizeof(SData)); - будет передан ведь вовсе не SUnit[заданное количество] внутри.

Цитировать
По-тому что, в ++ нет гарантий к размеру всех типов

По-моему, только int и long double могут иметь машинозависимую длину. Char имеет компиляторозависимый знак. Float мог быть произвольный - в старых компиляторах не по стандарту IEEE. Порядок же кодирования big или little-endian может меняться, это да. Остальные стандартные типы заданы жёстко (ну, может, double ещё схож с float). Про допкод не уверен, но, думаю, что он гарантируется.
Вообще, тут уже действует соглашение на протокол обмена по устройствам, где порядок данных описан как little-endian, допкод для переменных. Все устройства у которых это не так должны сами перекодировать данные.
Исключение составили разработчики из ЛОМО - они у нас отличились и вляпали свои числа в... прямом коде. Говорят, вояки всегда с ним работают. Заставить переделать не удалось. Ну и ладно - хоть один урод в списке аппаратуры комплекса непременно должен быть. Smiley

Цитировать
Кроме того - создав отдельный метод сереализации/десереализации - всегда можно контролировать правильный порядок байт (иногда есть большая разница как данные должны хранится оптимально и как передаваться/сохранятся по протоколу)

Это будет редкий *дец. Smiley Структура состояния устройств с подструктурами по типам принятых данных это около 500 строк. Их передача/приём с разложением на байты породит большущий код. Но... зачем?
« Последнее редактирование: Октября 17, 2017, 06:30:48 am от da-nie » Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #56 : Октября 17, 2017, 05:04:43 pm »

Цитировать
В смысле? Насколько я помню, все методы, реализованные в самом объявлении класса являются inline всегда
Вероятно я не точно выразился написав "нет никакой прямой связи"..
В том то и дело что НЕ ВСЕГДА. У каждого компилятора существуют свои ограничения и он на свое усмотрение мог взять и не встроить вашу функцию, даже если она реализована в хедере. Просто потому, что она вызывает внутри себя что-то виртуальное, содержит какие-то сложные циклы/условия.
Да, в целом существует требование на встраиваемость функций/методов если такое поведение ожидается получить между разными единицами трансляций - тело методов должно быть в хедерах. Но будет ли метод встроеным - решит компилятор в конечном счете, а не Вы. Вот и получается - что ожидание от inline всегда немного преувеличены.

Цитировать
В ранних стандартах порядок хранения в контейнерах не регламентирован. Это только сейчас так. Я понятия не имею, что умеет в QNX 6.3 компилятор и стандартные библиотеки.
Все то время в течении которого я программирую на с++ - все это время std::vector был последовательным контейнером который предоставлял доступ к единому/цельному куску памяти (аля массив).
Другое дело, что у вектора не всегда был метод data(), но вот с &vect[0] - всегда решал поставленную задачу.

Цитировать
А в структуре, которая передаётся как поток байтов, вектора внутри быть не должно - требуется ведь передать его содержимое, а не внутреннюю структуру вектора.
О том и речь, что ваша структура не только хранит/представляет данные, но она то по сути знает как данные должны передаваться.
Я понимаю что так проще и привычнее. Но до тех пор, когда протокол имеет фиксированную структуру/пакеты, пока нет версионности и пока не окажется что в разных протоколах нужны разные порядки сохранения/чтения данных.
Относительно вашего случая - вы уверены что на этапе компиляции размер настроек известен. А это значит, что пользователь не может ни увеличить ни уменьшить их количество со временем и под конкретную конфигурацию. Вы передаете настройки "на другую сторону", а значит на принимающей стороне работает программа собранная в соответствии и согласованная по размеру этой структуре настроек. Все это до тех пор, пока у вас есть доступ к синхронному обновлению бинарника программ для передатчика и приемника.
Мое замечание относится к тому, что не составляет труда определить методы внутри хотя бы того-же:
Код:
size_t SData::save(char *to);
size_t SData::load(char *from);
Упрощенно, но .. Внутри которых, как хотите так и читаете. И можете дописать/прочитать данные которые в структуре не хранятся явно, а можете предварительно проверить пред- и пост-условия (чтобы понять насколько пришедшие данные вообще cответствуют ожидаемым)

Цитировать
По-моему, только int и long double могут иметь машинозависимую длину.
Вся гарантия размеров типов в С++ сводится к этому
Код:
1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long).
Про это можете почитать тут

Цитировать
Это будет редкий *дец. Smiley Структура состояния ...
...
Но... зачем?
Объяснение дано было выше - представление структуры в памяти программы вообще может не совпадать с представлением данных при передаче. Хотя бы по тому что для передачи данных - нужны протоколы, а протоколы должны быть более устойчивы к изменениям (модификациям программ). Как правило - новые программы должны работать/взаимодействовать со старыми данными (версиями программ). Так принято. Люди не любят терять наработанные данные только потому-что вам вздумалось изменить структуру представления внутри программы
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #57 : Октября 17, 2017, 07:29:17 pm »

Цитировать
В том то и дело что НЕ ВСЕГДА.

Это я не верно интерпретировал, что у Подбельского написано. Там написано, что они все inline, но фраза несколько неудачно построена, и я решил что ограничения на обычные inline-функции на эти функции не действуют (за исключением рекурсии, конечно).

Цитировать
Я понимаю что так проще и привычнее. Но до тех пор, когда протокол имеет фиксированную структуру/пакеты, пока нет версионности и пока не окажется что в разных протоколах нужны разные порядки сохранения/чтения данных.

Всё вы верно говорите, но случаи бывают разные. В данном случае такое делать просто нецелесообразно. Протокол после отладки больше не меняется никогда. Он жёстко зашивается в устройство и всё.

Цитировать
А это значит, что пользователь не может ни увеличить ни уменьшить их количество со временем и под конкретную конфигурацию.

Нет-нет, я настройки не передаю. Передаётся другое. Просто в этих настройках нужны константы и в другом тоже они же нужны.

Цитировать
Вся гарантия размеров типов в С++ сводится к этому

Отвратительно. Для языка тесно связанного с низкоуровневым программированием (я имею в виду Си) иметь гарантии в стиле "не меньше" просто идиотизм. Жаль. В книжках, вроде как, чётко пишут разрядность чисел, упоминая вот то, что я перечислил. А оказывается, гарантии в стиле "не меньше".

Цитировать
нужны протоколы, а протоколы должны быть более устойчивы к изменениям

Не всегда это нужно. Протоколы работы с оборудованием низкоуровневые и версионности не имеют практически никогда - она бесполезна. Как пример, протокол обмена по USB вот этого вот тепловизора. Всё жёстко задано и для тепловизора следующего поколения протокол другой.
Записан

И день и ночь в пути
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #58 : Октября 18, 2017, 12:51:11 am »

Цитировать
Отвратительно. Для языка тесно связанного с низкоуровневым программированием (я имею в виду Си) иметь гарантии в стиле "не меньше" просто идиотизм. Жаль. В книжках, вроде как, чётко пишут разрядность чисел, упоминая вот то, что я перечислил. А оказывается, гарантии в стиле "не меньше".
Ну, с 11-го стандарта у языка все стало проще

Цитировать
Не всегда это нужно. Протоколы работы с оборудованием низкоуровневые и версионности не имеют практически никогда..

Вот с этим не согласен, но в вашем случае вам же решать.
Записан
da-nie
Full Member
***
Offline Offline

Сообщений: 167



Просмотр профиля
« Ответ #59 : Октября 18, 2017, 12:14:47 pm »

Цитировать
Ну, с 11-го стандарта у языка все стало проще

Ну, inttype.h уже давно в Си компиляторах типа Keil и IAR лежат. Нет только с плавающей точкой и bool.

Цитировать
Вот с этим не согласен, но в вашем случае вам же решать.

Когда работа идёт с оборудованием, этот протокол чем-то напоминает внутрипрограммный обмен - вы же почти никогда ("почти" - потому что есть случаи, когда передаёте - например, Win32API такое практикует именно по причине разных версий Windows и одних и тех же программ) не передаёте в функцию версию передаваемой структуры/объекта и её размер?

Кстати, спрошу ещё кое-что. Что бывают unit-тесты я давным-давно знаю. Но вот как их делать - без понятия. В статьях, обычно, они как-то как сами собой разумеющиеся идут (моки и стабы там всякие и т.п.). Я, обычно, такими вещами не занимаюсь и делаю всегда интеграционное тестирование (потому что почти 100% ошибки не в конкретных функциях и классах, а в их взаимодействии между собой - скажем, не в том порядке захвачены мюьтексы в разных объектах и произошла взаимоблокировка. Ну или просто не предусмотрена некая ситуация в программе в принципе, а она случилась.). Отсюда вопросы:
1) Unit-тест - это отдельная программа или они встраиваются в основное приложение (что странно, на мой взгляд)?
2) Если это отдельная программа, то делают на каждый тест одну программу или всё тестирует одна программа?
3) Вот есть у меня класс кодирования/декодирования принятых/отправленных данных. Чтобы его протестировать, нужно написать тест, который будет размером в пять таких классов (ведь то же самое кодирование/декодирование потребуется реализовать в программе теста). И нет никакой гарантии, что в тесте не будет ошибки. Да и как, например, убедиться, что все состояния покрыты тестом? Передаваться-то может просто тьма самых различных данных.
4) Ряд вещей вообще непонятно как проверять - например, передачу через сокеты/CAN/USB - там всё завязано на функции ОС и работы с аппаратурой напрямую.
5) Не получится ли тест программы сложнее и объёмнее самой программы раз в 5? По моим прикидкам, так и получится. Smiley
Записан

И день и ночь в пути
Страниц: 1 2 3 [4] 5
  Печать  
 
Перейти в: