Говнокод по пятницам. Эпизод 3. «Serial.println vs. Imperial Starfleet»

Мужики, во попёрло!

Давеча тут Дарт Вейдер звонил, говорит, что затеяли они писать новую прошивку для истребителя TIE Fighter, но выяснилось, что компания-производитель (Sienar Fleet Systems), своими идиотскими мерами по экономии фонда оплаты труда, разогнала всех программистов и новую версию прошивки писать некому! Решили нанять меня! Обещали целый мешок вупиупи или полмешка имперских кредитов на мой выбор!

Ну, чё, посмотрел я ТЗ, начал писать. Там типа при включении питания можно заранее нажать кнопку, чтобы система включилась нормальном рабочем режиме (а если не зажимать, то включается в сервисном режиме). Стало быть, сразу после включения нужно проверять нажатость кнопки и начинать работать в выбранном режиме.

В нормальном режиме она должна приветствовать пилота фразой “Да прибудет с тобою Сила!”, а в сервисном – вывести температуру обоих ионных двигателей (датчик внешний, всё делает сам, нам надо только вывести считанные “попугаи”).

Ну, с этого решил и начать. Написал

вот такой код
////////////////////////////////////////////////////////
//
//	TIE fighter's electronic control unit 2.0
//	
//	Заказчик: Sienar Fleet Systems, Галактическая Империя
//	Контактное лицо: Darth Vader
//
////////////////////////////////////////////////////////
//
//	Назначение пинов
//
static constexpr uint8_t pinModeButton = 4;
static constexpr uint8_t pinEngine1Temp = A0;
static constexpr uint8_t pinEngine2Temp = A1;

//
//	Стартовое сообщение (в зависимости от режима работы)
//	Cообщение о сервисном режиме должно быть НЕ ДЛИННЕЕ стандартного!
//
char * welcomeMessage = (char *) "TIE Fighter ECU standard mode!\r\n";
char * serviceMessage = (char *) "TIE Fighter ECU service mode\r\n";

//
//	Функция проверяет в каком режиме запущен ECU
//	Если кнопка на pinModeButton НЕ нажата, то это сервисный режим (возвращается false)
//	Если кнопка на pinModeButton нажата, то это стандартный режим (возвращается true)
//	Также, в случае сервисного режима, заменяет приветсвенное сообщение
//		welcomeMessage на serviceMessage. Последнее короче (не длиннее), 
//		так что выхода за границы не будет.
//
static inline bool defineOperationalMode(void) {
	pinMode(pinModeButton, INPUT_PULLUP);
	const bool result = digitalRead(pinModeButton) == LOW; // true, если нажата (стандартный режим)
	if (! result) strcpy(welcomeMessage, serviceMessage);
	return result;
}

void setup (void) {
	Serial.begin(9600);

	const bool isModeStandard = defineOperationalMode(); // если false, то сервисный режим

	Serial.println(welcomeMessage);

	if (isModeStandard) { // Основной режим
		Serial.println("TIE fighter is ready, sir!");
		Serial.println("May the Force be with you!");
	} else {	// Сервисный режим
		Serial.println("On-board sensor readings:");
		Serial.print("Ion engine #1 temperature: ");
		Serial.print(analogRead(pinEngine1Temp) + 32.0);
		Serial.println("F");
		Serial.print("Ion engine #2 temperature: ");
		Serial.print(analogRead(pinEngine2Temp) + 32.0);
		Serial.println("F");
	}
}

void loop(void) {}

Запускаю с нажатой кнопкой (в обычном режиме). Смотрю.

вроде, всё красиво
TIE Fighter ECU standard mode!

TIE fighter is ready, sir!
May the Force be with you!

Запускаю с отпущенной кнопкой (в сервисном режиме)

и вижу такую хрень
TIE Fighter ECU service mode
On-board sensor readings:Ion engine #1 temperature: 479.00FIon engine #2 temperature: 430.00F

Не понял! Этошоза…? У меня же в коде при выводе буквы F явно прописано Serial.println (строки №52 и №55)! Да и в строке №49 – тоже должна новая строчка при печати начаться! С каких это, простите, пор println перестал переводить строки? И как его заставить это делать?

В общем и так я и эдак, уже и дополнительные Serial.println(); ставил и даже по нескольку штук – не работает – слипаются все строки в одну и хучь ты сдохни.

В общем, правильно мне говорили – не связывайся с этим лживым, грязным IDE, пиши на чистом и кошерном (а ещё лучше на волшебном асме, где само всё правильно пишется!), так нет же … :frowning:

Выручайте, а не то – плакали мои вупиупи.

P.S.
Примеры запускались на IDE 2.2.1 и 2.3.2. Работать, в принципе, будет на любой версии GCC, но на какой-то может потребоваться дополнительное смещение или перестановка местами строк.

3 лайка


чет я не так делаю)))

а так подвох, как мне кажется, в строке №34.

если так, ломается

выкинул все “лишнее”
изучайте))

Спойлер
char * welcomeMessage = "++\r\n";
char * serviceMessage = "\r\n";

void setup (void) {
  Serial.begin(9600);

  strcpy(welcomeMessage, serviceMessage);

  Serial.println("Дальше println идет по бороде - ");
  Serial.println("#1 temperature: ");
  Serial.println(32.0);
  Serial.println("F");
  Serial.println("#2 temperature: ");
  Serial.println(64.0);
  Serial.println("F");
}

void loop(void) {}
1 лайк

Реально, не слабо вас так

Рецептиком не поделитесь? ))

1 лайк

100500 Live Sinus прикупил, ну не мотал жеж )))

1 лайк

Я вот чего не понял…
А зачем у функции bool defineOperationalMode(void) в определении указаны static и inline?

В мониторах Arduino IDE и VS Code все нормально

Снимок экрана в 2024-09-20 08-54-02

В Putty и терминале - расколбас ))

Тут дело таки в том, как эти мониторы обрабатывают конец строки

Да, если убрать эту строку и выводить сообщения непосредственно, то проблем нет.

Так же нет проблем, если заменить строку 34 на

if(!result) welcomeMessage = serviceMessage;

Но сдается мне, Петрович неспроста этот пример выложил, есть у него что-то в загашнике ))

Ну, ошибка сильно зависит от версии компилятора. У меня IDE 2.2.1 из коробки и всё работает как я показал (дописал в стартовый пост).

Но, как Вы поняли, она (ошибка) реально всегда есть, просто иногда чуть в другом месте проявляется – стоило @xDriver один символ сместить и у него “получилось” в его версии :slight_smile:

Ну, а …

К ошибке не имеет отношения, уберите – ничего не изменится. Просто я всегда ставлю inline у коротких, единожны (или мало) используемых функций и всегда ставлю static, если не нужна видимость из других файлов. Если увидите, что не поставил, просто случайность.

println() только /r мечет в порт. Что-то, помнится мне такое.

У меня 2.3.2

У меня проблема не в переводе строки - он-то как раз имеет место быть. А вот возврат каретки теряется ))

С чего? Откройте IDE’шный файл Print.cpp и увидите:

size_t Print::println(void)
{
  return write("\r\n");
}

Ну, я могу обновиться и “починить”, но Вы и сами можете. Подвигайте строки, как это сделал @xDriver и всё получится.

Впрочем, сейчас обновлюсь и поправлю.

Откуда-то же у меня всплывает такое воспоминание. Или в стародавних версиях такое было или пора принимать таблетки ))

Ну да, добавил пробел во второй строке, и проблема ушла

Может я понимаю неправильно, но в исходном варианте после strcpy(welcomeMessage, serviceMessage) в конце welcomeMessage образовывался лишний \n

Ну, а если удалите (как @xDriver сделал), то наоборот, вылезет в полный рост.

Нет, конечно, но, даже если бы это и было так, каким же боком он повлиял на println в коде ниже, где печатаются другие вещи. Там ведь все println ломаются.

так полнолуние, коридор затмений, то ли ещё что вылезет )))

Надо было наоборот. Вот так у меня отлично работает на 2.3.2. Сейчас поправлю в стартовом посте.

Поправил в стартовом посте.
Теперь должна работать если не во всех, то почти во всех версиях IDE

Ну, а чё я сделаю, если он звонит? Не блокировать же его!

@ЕвгенийП
А итоги подводить будете?
Вроде уже нашли где ошибка