Извините, но я снова про немцев. Оказывается, 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).