Перейти к содержанию
  • запись
    21
  • комментариев
    136
  • просмотров
    3 095

Новая любовь - новые тревоги


ARV

799 просмотров

Нельзя полюбить RTOS и избавиться от волнений. Любовь - это штука, волнующая кровь по определению, так что...

Стихли первые эмоции на основе эйфории, появилась тревога. 

Отладка RTOS - та еще песня! Никогда не знаешь точно, что и как происходит не так, если оно не так. Когда одна задача посылает команды по USART в устройство, другая задача принимает от него ответы, а третья занимается управлением, понять, почему третья задача работает не правильно, очень не просто. Непросто потому, что запросы и ответы разделены во времени и в пространстве, и если управляющая задача ждет готовности, надо выснить, из-за неотправленного запроса или же из-за не полученного ответа. А если на все это накладывается еще и не совсем разумное поведение устройства, то вообще все становится загадочно и сташно.

Пытаюсь совместить модуль плейера MP3-файлов с RTOS. Написал две функции-задачи для приема ответов и отправки команд. Вроде бы все правильно, все корректно. 

/**
* задача приема сообщений от других задач и выдачи команд в плейер
* @param p не используется
*/
static void control_task(void *p){
	static int16_t ver;
	static player_msg_t *msg;

	ver = get_current_mbox_version(&player_mailbox);
	while(1){
		wait_for_increment_of(&tick, 10);
		// обработка сообщений
		if((msg = read_mbox_min_version(&player_mailbox, &ver)) != NULL){
			// новое в ящике
			// разбор сообщения
			switch(msg->cmd){
			case PCMD_RESET: // сброс
				status = P_NOT_READY;
				mp3_cmd(MP3_CMD_RESET,0,0);
				break;
			case PCMD_SET_VOL: // громкость
				mp3_cmd(MP3_CMD_SET_VOL, 0, msg->bparam > MP3_MAX_VOL ? MP3_MAX_VOL : msg->bparam);
				break;
			case PCMD_STOP: // остановка воспроизведения
				if(status != P_READY){
					mp3_cmd(MP3_CMD_STOP, 0, 0);
					status = P_READY;
				}
				break;
			case PCMD_S_MSG_QUEUE: // воспроизвести сообщение с ожиданием
				while((status != P_READY)) yield(); //continue;
			case PCMD_S_MSG_NOW: // немедленно воспроизвести сообщение
				// если папка не указана - ищем трек в корне
				if(msg->bparam)
					mp3_cmd(MP3_CMD_PLAY_FOLDER, msg->bparam, msg->wparam);
				else
					mp3_cmd(MP3_CMD_PLAY, msg->wparam >> 8, msg->wparam & 0xFF);
				status = P_PLAY;
				break;
			case PCMD_L_MSG_QUEUE: // воспроизвести трек из "большой" папки с ожиданием
				while(status != P_READY) yield(); //continue;
			case PCMD_L_MSG_NOW: // воспроизвести  из "большой" папки немедленно
				status = P_PLAY;
				mp3_cmd(MP3_CMD_PLAY_3000, ((msg->bparam & 0x0F) << 4) | ((msg->wparam>>8) & 0x0F),msg->wparam & 0xFF);
				break;
			case PCMD_USER: // любая иная команда
				mp3_cmd(msg->bparam, msg->wparam>>8, msg->wparam & 0xFF);
				break;
			}
		}
		release_mbox_read();
		ver++;
	}
}

#include <util/delay.h>

/**
 * Задача приема сообщений от модуля плейера. Осуществляет управление статусом
 * плейера в зависимости от принятых команд.
 * @param p не используется
 */
static void reseive_task(void *p){
	static mp3_buf_t packet;
	static uint8_t old;
	static uint8_t d;

	while(1){
		// обработка ответов модуля
		d = 0;
		// ждем время, достаточное для приема пакета (10 мс)
		wait_for_increment_of(&tick,10);
		// ищем стартовый байт
		if(data_reseived()) d = data_get();
		if(d != MP3_START_BYTE) continue;
		// считываем пакет
		for(uint8_t i=0; i < (MP3_PACKET_SZ-1); i++){
			packet.bytes[i] = d;
			while(!data_reseived()) to_os();
			d = data_get();
		}
		// обрабатываем пакет
		switch(packet.command){
		case MP3_ERROR: // ошибка
			mprintf("\nError %02X st=%d", packet.param_lo, status);
			if(status == P_PLAY) status = P_READY;
			break;
		case MP3_STAY_USB:// конец воспроизведения
		case MP3_STAY_SD:
				// STAY приходит дважды!!!, один раз надо игнорировать
				//dbg_packet(&packet);
				if(old != packet.param_lo)
					status = P_READY;
				old = packet.param_lo;
			break;
		case MP3_DEV_STATUS: // инициализация закончена
			if((status == P_NOT_READY) && (packet.param_lo == DEV_SD))
				status = P_READY;
			break;
		case MP3_PLUG_IN: // подключение источника
			status = P_READY;
			break;
		case MP3_PULL_OUT: // отключение источника
			status = P_NOT_READY;
			break;
		default: // все прочие пакеты
			break;
		}
	}
}

Проверяю функционирование при помощи простой функции, "говорящей время":

void say_time(uint8_t h, uint8_t m){
	player_send_msg(PCMD_S_MSG_QUEUE, FOLDER_MSG, SAY_TIME);
	if(h==0) h=24;
	if(m==0) m=60;
	player_send_msg(PCMD_S_MSG_QUEUE, FOLDER_HOUR, h);
	player_send_msg(PCMD_S_MSG_QUEUE, FOLDER_MIN, m);
}

Вызываю эту функцию каждые 5 секунд, имитируя минуты, в отдельной задаче. В итоге система говорит время некоторое количество раз, после чего состояние модуля становится P_PLAY и не исчезает. Если посмотреть на код функций управления и приема ответов, то можно понять, что такая ситуация возможна, если модуль не ответил о том, что файл проигран до конца. НО ОН ОТВЕЧАЕТ! И отвечает 2 раза на каждый файл, о чем в документации нет ни слова!

Что происходит, как выяснить? Самое удивительное, что если снять ремарку с отладочного вывода содержимого принятого ответа, то все начинает работать! И в терминале я вижу, что на каждый файл приходит подтверждение окончания воспроизведения... И, значит, состояние P_PLAY обязано сбрасываться в P_READY! Но если отладочный вывод в терминал заремарить - рано или поздно все виснет.

А я-то думал, волноваться больше не придется...

0 Комментариев


Рекомендуемые комментарии

Комментариев нет

Присоединяйтесь к обсуждению

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Добавить комментарий...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
×
×
  • Создать...