И вот такой у нас 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, настоящее немецкое качество и все такое.
Первый пример просто шикарен! Сразу два неявных приведения! Не смог удержаться и проверить приведения:
#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
А byte в ардуине – это uint8_t? Тогда еще лучше :)
Шыкаааарно. Человек, который год не может прикрутить защиту от спамеров, но при этом учит других как им быдлокодить надо. :)
что не так, кстати, с буквой йа?
$ 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 и прочая чертовщина), во-вторых, его время работы совершенно непредсказуемо.
Все эти примеры будут работать без ошибок – пока кто-то не захочет внести мааааленькое какое-нибудь изменение. Мне вот пример с дальномером у мужика еще понравился – но там долго объяснять.
в данном случае “который” относится не к человеку, а к году. :)
Это я просто криво написал и запятую не там поставил.
в принципе, в целочисленной арифметике двоичных ЭВМ отрицательные числа это в некотором роде условность. Хотя, емнип, 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 строку известной длины, соответствующая функция пишется за пять минут.
я, конечно, подозреваю что у него классическая ардуина, но синяя пилюля, насколько я понимаю, программно с ней совместима. но тем не менее вы слишком много кушать, в смысле – зажрались, если вам 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.
А у вас что, борьба за каждый байт и каждый такт?
переменные на стеке жрут стек.
и я не зря сказал про быдлокод, потому что
while ((USART_ISR(usart) & USART_ISR_TXE) == 0);
USART_TDR(usart) = *p++;
что особенно зачотно выглядит внутри обработчика прерывания. И хрен тут, кстати, руками раздашь память, потому что не понятно какой код в какое время будет выполняться, а соответственно какая когда использоваться.
> И, кстати, чем вам не так маллок?
У malloc в общем случае есть один поганый нюанс, о котором иногда забывают – память фрагментируется при неаккуратном использовании. А потом вроде ты даже все аллокации освобождаешь как надо, а хуяк, ENOMEM(условно). Да, с этим можно бороться, если либо брать аллокатор который за этим следит, либо понимать как используется heap по итогу. Так что не зря в MISRA C malloc запрещён, не зря.
То что он работает непредсказуемое время – можно взять TLSF который за константное время работает и даёт даже не особо конский оверхед, но зачем? Если есть ответ на этот вопрос, то кто ж не даёт – используй.
Ну в этом конкретном случае фрагментация вряд ли грозит, как захватили память, так через три строчки и освободили. Но граблей полно, и в большинстве книжек по Си про них не рассказывают.
IoT не авионика. Получили ENOMEM, ну дерните reset и начните с чистого листа.
Вышеприведенный код дергает reset, когда из malloc прилетает NULL?
“Ну кроме того, что не проверяется что память выделилась”
За такой подход в приличном обществе канделябром ебут. Особенно там где эта железка может управлять чем-то тяжёлым, IIoT он как раз про Industrial. Плюс с reset не всегда можно корректно вернуться в текущий процесс, либо надо это обрабатывать, что ведёт у увеличению времни старта.
Делали железку давно, прощёлкали то что по даташиту ноги у проца в + подтянуты, ну и нам потом задали вопрос: “ребят, всё почти норм, но на сбросе на выходе импульс в десяток микросекунд, он нам мешает, можно убрать?” и мы такие “ЫЫЫЫЫ”.
Где-то слышал такое “определение” Industrial IoT – это дешевые средства контроля разного рода показателей, которые не включены в общий “контур управления”, но могут быть полезны для диагностики. Ну вот, например, SCADA-система, которая рулит конвейерной линией какой-нибудь – это “обычная” промавтоматика, а вот если повесить там рядышком какой-нибудь, скажем, беспроводной датчик вибрации на электродвигатель – то это IIoT. Соответственно, отказы там менее критичны и заниматься этим всем могут вот такие Dr. Ing. и всякого рода индусы.
Ну какой индастриал? Вам не надоело натягивать сову на глобус. Такое ощущение, что у вас в автомобиле четырехточечные ремни и шлемак, цепляющийся к подголовнику.
Эй, Шура, у вас-то в раллийной волге хотя бы каркас силовой установлен?
Такое впечатление, что это я про себя написал “I’m a research engineer working in the field of Industrial IoT.”
Вот та хуита, которая написана у герра инженера – это не четырехточечные ремни безопасности, это что-то из разряда заглушек для ремня.
Ну и вы пишите. Кто вам мешает?
Или вы реально верите что это кусок кода из индустриального продакшена?
И таки да, это заглушки для ремня, но вы требуете что бы везде был каркас. И система пожаротушения. И отключение АКБ из салона.
Когда человек всерьез пишет вот такое:
accelerometer_x = Wire.read()<<8 | Wire.read();
то возникают обоснованные предположения, что такую же херь он пишет и в “индустриальном продакшене” (или же производит слово “индустриальный” от слов “индус” и trial).