Jump to content
  • entries
    21
  • comments
    136
  • views
    2915

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


ARV

755 views

 Share

Нельзя полюбить 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! Но если отладочный вывод в терминал заремарить - рано или поздно все виснет.

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

 Share

0 Comments


Recommended Comments

There are no comments to display.

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Add a comment...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...