И вот такой у нас Industrial IoT

Извините, но я снова про немцев. Оказывается, Dr. Ing. Michael Schoeffler на гитхабе пишет про себя так:

I’m a research engineer working in the field of Industrial IoT.

Парочка примеров кода от инженера-исследователя, работающего в индустриальном IoT:


void loop() {
  if (Serial.available() > 0) {
    byte incomingByte = 0;
    incomingByte = Serial.read(); // read the incoming byte:
    if (incomingByte != -1) { // -1 means no data is available
      lcd.setCursor(0, 0); // set cursor to first row
      lcd.print("I received: "); // print out to LCD
      lcd.setCursor(0, 1); // set cursor to secon row
      lcd.print(incomingByte); // print out the retrieved value to the second row
    }
  }
}

О существовании буквы “я”, конечно, в индустриальном IoT можно не задумываться.


long hexstr_to_value(char *str, unsigned int length) { // converts a hexadecimal value (encoded as ASCII string) to a numeric value
  char* copy = malloc((sizeof(char) * length) + 1);
  memcpy(copy, str, sizeof(char) * length);
  copy[length] = '\0';
  // the variable "copy" is a copy of the parameter "str". "copy" has an additional '\0' element to make sure that "str" is null-terminated.
  long value = strtol(copy, NULL, 16);  // strtol converts a null-terminated string to a long value
  free(copy); // clean up
  return value;
}

malloc() на микроконтроллере – это, несомненно, очень индустриально.


accelerometer_x = Wire.read()<<8 | Wire.read(); // reading registers: 0x3B (ACCEL_XOUT_H) and 0x3C (ACCEL_XOUT_L)

Я бы еще вписал где-нибудь в этой программе i++ + ++i.

А вы говорите Bosch, настоящее немецкое качество и все такое.

20 комментариев

  1. Dmitry пишет:

    Первый пример просто шикарен! Сразу два неявных приведения! Не смог удержаться и проверить приведения:

    #include
    #include

    int main() {
    int16_t a = 0xFFFF;
    uint8_t b = a;
    printf(”a = %d, b = %d\n”, a, b);
    printf(”a == -1: %d\n”, a == -1);
    printf(”b == -1: %d\n”, b == -1);
    }

    gcc c.c -o c -Werror ## Никаких ошибок!

    ./c
    a = -1, b = 255
    a == -1: 1
    b == -1: 0

  2. kettle пишет:

    Шыкаааарно. Человек, который год не может прикрутить защиту от спамеров, но при этом учит других как им быдлокодить надо. :)

    что не так, кстати, с буквой йа?
    $ echo Я | hexdump
    0000000 afd0 000a
    по-моему все ништяк. тем более что 0xFF это не -1. И вообще, 0377 это Ъ. Не понимаю ваших страданий в узких рамках одной отдельно взятой кодировки.
    Тем более что -1 это очень даже нормальный EOF.
    $ grep EOF /usr/include/stdio.h
    #define EOF (-1)

    Нагляднее, конечно, было бы написать if (incomingByte != EOF ).

    Тем более, вы ухватившись за -1 напрочь не увидели, что байт, как вам выше правильно заметили, банально unsigned. И уже за это надо гнать ссаными тряпками.
    Потому что по жизни всегда так было что getchar “возвращает unsigned char преобразованный в int, или EOF”.

    Но возвращаясь к вашим страданиям по йа, допуская что где-то рукожопо byte переопределен как char (с целью дополнительного батхерта). А вы не думали, что по UART размер символа не тождественен 8 битам? Что там, например, где-то выше выставлено 7N1? :)

    И, кстати, чем вам не так маллок? Ну кроме того, что не проверяется что память выделилась, что в реальной жизни приводит к увлекательному поиску че же оно глючит-то?

    И еще вдогонку: этот пример тем не менее будет работать без ошибок. Догадаетесь почему?

    • Какой год? Как бы уже не все десять!

      Дык писать int /* а не char */ c = getchar() учат на второй лабе по Си. Кстати, стандарт Си не определяет, является ли char знаковым или беззнаковым :)

      Что касается символов в UART – да похуй. На работу Serial.byte() это вообще не влияет.

      С malloc все хорошо – за исключением двух вещей: во-первых, нормальный полнофункциональный malloc “весит” 1-2 килобайта (и в любой нормальной стандартной библиотеке для МК по этой самой причине есть какие-нибудь варианты no-free malloc и прочая чертовщина), во-вторых, его время работы совершенно непредсказуемо.

      Все эти примеры будут работать без ошибок – пока кто-то не захочет внести мааааленькое какое-нибудь изменение. Мне вот пример с дальномером у мужика еще понравился – но там долго объяснять.

      • kettle пишет:

        в данном случае “который” относится не к человеку, а к году. :)
        Это я просто криво написал и запятую не там поставил.

        в принципе, в целочисленной арифметике двоичных ЭВМ отрицательные числа это в некотором роде условность. Хотя, емнип, char машиннозависимый (и даже не всегда 8 бит), а на PDP, откуда пошло он знаковый.

        это влияет на возможность передать Йа.
        Вы, видимо, никогда не видели иНЖАЛИД ДЕЖИЦЕ :)
        А в электронной почте не сталкивались с серверам, которые обрабатывали в 7-битной кодировке. :)

        Если вам нужно время от времени какие-то буферы, вы либо будете каждый раз заранее выделять под него место, надеясь что оперативки хватит, либо в любом случае будете колхозить свой маллок. Если он использовался на старых PDP, то почему не может использовать на, скажем, blue pill с stm32f103, у которого 64К пзу и 20К озу? Это дэцл больше 56К которые были у ДВК. А если вам важно время, то берите асм и считайте такты.

        А работать будет просто потому, что read никогда не вернет -1.

        • > blue pill с stm32f103, у которого 64К пзу и 20К озу?

          У мужика вообще-то Arduino, где стоит AtMega328 – 32 кБ ПЗУ и 2 кБ ОЗУ.

          Ну а если мы говорим про ARM – то вот раскладка по одному из моих проектов – FreeRTOS “весит” 6 кБ, столько же – FATFS, около 14 кБ – довольно развесистая “пользовательская” программа – и на фоне этого полнофункциональный (к сожалению, его за собой тащит TI Simplelink – хотя надо попробовать избавиться) malloc из IAR EWARM “стоимостью” те же 6 кБ выглядит уже не так хорошо.

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

          Вот так обычно и делают. Ну или если без malloc не обойтись – то стараются использовать его в варианте no-free malloc, он существенно проще. И только на самых жирных МК, хотя бы со 128 кБ оперативки, полноценный маллок может быть хоть как-то оправдан.

          Ну и в заключение – обсуждать необходимость malloc для работы с буферами размером 9 или 3 байта в целом не имеет смысла. Равно как нет необходимости и в вызове strtol для того, чтобы перевести в long строку известной длины, соответствующая функция пишется за пять минут.

          • kettle пишет:

            я, конечно, подозреваю что у него классическая ардуина, но синяя пилюля, насколько я понимаю, программно с ней совместима. но тем не менее вы слишком много кушать, в смысле – зажрались, если вам 32к мало.
            А динамическое распределение памяти оправдано везде, где ее не хватает, что бы раздать всем статически. переменные на стеке вас не смущают?
            За 5 минут пишется все, но в сумме они дают часы и дни помноженные на ошибки, поскольку юнит-тесты вы врядли пишете. А зачем это надо, когда концепция: хуяк, хуяк и в продакшн! Что вы возьмете готовую strtol, что вы ее сами напишете, какой профит?
            я давеча printf писал, так функциональность сильно обрезанная под мои нужды, но сдается что у меня тот еще быдлокод вышел. :)
            char console_printf_digit[] = “0123456789ABCDEF”;
            char out[10];
            void console_outint( uint32_t usart , uint32_t value , uint8_t base )
            {
            char *c = out;
            do
            {
            *c++ = console_printf_digit[value%base];
            value /= base;
            } while( value );

            do
            {
            console_putc( usart , *–c );
            } while( c != out );
            }

            хотя это надо только для отладки, в финальной версии этого не будет.

            • Отводить из 32к добрую четверть под маллок (ну или хз сколько, мне вот в лом сейчас выяснять, сколько он занимает в avr-gcc с его стандартной библиотекой) – это и есть “зажрались”.

              Переменные на стеке, в отличие от маллок, не тащат за собой кучу ненужного кода.

              Ну как минимум в приведенном быдлокоде предсказуемо потребление стека и время работы, в отличие от того, что родил немецкий Dr. Ing.

              • kettle пишет:

                А у вас что, борьба за каждый байт и каждый такт?
                переменные на стеке жрут стек.
                и я не зря сказал про быдлокод, потому что
                while ((USART_ISR(usart) & USART_ISR_TXE) == 0);
                USART_TDR(usart) = *p++;

                что особенно зачотно выглядит внутри обработчика прерывания. И хрен тут, кстати, руками раздашь память, потому что не понятно какой код в какое время будет выполняться, а соответственно какая когда использоваться.

    • savant пишет:

      > И, кстати, чем вам не так маллок?

      У malloc в общем случае есть один поганый нюанс, о котором иногда забывают – память фрагментируется при неаккуратном использовании. А потом вроде ты даже все аллокации освобождаешь как надо, а хуяк, ENOMEM(условно). Да, с этим можно бороться, если либо брать аллокатор который за этим следит, либо понимать как используется heap по итогу. Так что не зря в MISRA C malloc запрещён, не зря.

      То что он работает непредсказуемое время – можно взять TLSF который за константное время работает и даёт даже не особо конский оверхед, но зачем? Если есть ответ на этот вопрос, то кто ж не даёт – используй.

      • Ну в этом конкретном случае фрагментация вряд ли грозит, как захватили память, так через три строчки и освободили. Но граблей полно, и в большинстве книжек по Си про них не рассказывают.

      • kettle пишет:

        IoT не авионика. Получили ENOMEM, ну дерните reset и начните с чистого листа.

        • Вышеприведенный код дергает reset, когда из malloc прилетает NULL?

        • savant пишет:

          За такой подход в приличном обществе канделябром ебут. Особенно там где эта железка может управлять чем-то тяжёлым, IIoT он как раз про Industrial. Плюс с reset не всегда можно корректно вернуться в текущий процесс, либо надо это обрабатывать, что ведёт у увеличению времни старта.

          Делали железку давно, прощёлкали то что по даташиту ноги у проца в + подтянуты, ну и нам потом задали вопрос: “ребят, всё почти норм, но на сбросе на выходе импульс в десяток микросекунд, он нам мешает, можно убрать?” и мы такие “ЫЫЫЫЫ”.

          • Где-то слышал такое “определение” Industrial IoT – это дешевые средства контроля разного рода показателей, которые не включены в общий “контур управления”, но могут быть полезны для диагностики. Ну вот, например, SCADA-система, которая рулит конвейерной линией какой-нибудь – это “обычная” промавтоматика, а вот если повесить там рядышком какой-нибудь, скажем, беспроводной датчик вибрации на электродвигатель – то это IIoT. Соответственно, отказы там менее критичны и заниматься этим всем могут вот такие Dr. Ing. и всякого рода индусы.

          • kettle пишет:

            Ну какой индастриал? Вам не надоело натягивать сову на глобус. Такое ощущение, что у вас в автомобиле четырехточечные ремни и шлемак, цепляющийся к подголовнику.
            Эй, Шура, у вас-то в раллийной волге хотя бы каркас силовой установлен?

            • Такое впечатление, что это я про себя написал “I’m a research engineer working in the field of Industrial IoT.”

              Вот та хуита, которая написана у герра инженера – это не четырехточечные ремни безопасности, это что-то из разряда заглушек для ремня.

              • kettle пишет:

                Ну и вы пишите. Кто вам мешает?
                Или вы реально верите что это кусок кода из индустриального продакшена?

                И таки да, это заглушки для ремня, но вы требуете что бы везде был каркас. И система пожаротушения. И отключение АКБ из салона.

                • Когда человек всерьез пишет вот такое:

                  accelerometer_x = Wire.read()<<8 | Wire.read();

                  то возникают обоснованные предположения, что такую же херь он пишет и в “индустриальном продакшене” (или же производит слово “индустриальный” от слов “индус” и trial).

Ответить

Или воспользуйтесь входом по OpenID: