+2
Немного поясню почему я решил именно так реализовать чат. Можно было проще, сохранять полученные символы в буффер, а потом просто сравнивать буффер с возможными вариантами ответа. Но я хотел обрабатывать данные на лету, без сохранения ответа в буффер. Поэтому реализовал именно так.

Приведу еще один пример использования – отправка SMS для SIM300D


//---------------------------------------------------------------------------------------------------------------------
error_t _MODEM_SendSMS(const char * PhoneNumber, const char * Message) {
	const char * SmsResponce[] = {"OK", ">", "ERROR", NULL};


	if(!MODEM_Send("AT+CMGS=\"", MODEM_NORMAL_CMD_TIMEOUT)) {
		_DBG("[ERR] MODEM send data timeout\n");
		return ERROR_MODEM_IO_TIMEOUT;
	}

	if(!MODEM_Send(PhoneNumber, MODEM_NORMAL_CMD_TIMEOUT)) {
		_DBG("[ERR] MODEM send data timeout\n");
		return ERROR_MODEM_IO_TIMEOUT;
	}

	int ChatResult = MODEM_Chat("\"\r", SmsResponce, MODEM_NORMAL_CMD_TIMEOUT);
	if(ChatResult != 1) {
		_DBG("[ERR] MODEM invalid SMS mode response\n");
		return ERROR_MODEM_UNEXPECTED_RESPONSE;
	}

	if(!MODEM_Send(Message, MODEM_NORMAL_CMD_TIMEOUT)) {
		_DBG("[ERR] MODEM send data timeout\n");
		return ERROR_MODEM_IO_TIMEOUT;
	}

	ChatResult = MODEM_Chat("\x1A", SmsResponce, MODEM_SEND_SMS_TIMEOUT);
	if(ChatResult != 0)  {
		_DBG("[ERR] MODEM SMS sending error %d\n", ChatResult);
		return ERROR_MODEM_UNEXPECTED_RESPONSE;
	}

	return ERROR_SUCCESS;
}

  • avatar
  • e_mc2
  • 23 сентября 2013, 17:35
+4
Поделюсь своим опытом. Во времена DialUp Интернета для работы с модемом (дозвон и т. д.) в этих ваших Юниксах, часто использовали специальную прогу – chat, которой скармливали специальный скрипт. В скрипте (если очень упростить) было написано, что посылать модему и какие варианты ответа от него ждать (и как на них реагировать). Например, на ATDT в ответ мы ожидаем OK, CONNECT (что хорошо) BUSY, NO CARRIER, NO ANSWER и т. д. (что плохо, ошибка). ИМХО, очень удачный и универсальный получался механизм.

Я написал аналогичную функцию для работы с GSM модемом.

Сама функция


//---------------------------------------------------------------------------------------------------------------------
int MODEM_Chat(const char * SendCommand, const char * WaitResult[], DWORD Timeout) {

	WORD ResultsCount = 0;

#ifdef _DBG_MODEM
	if(SendCommand) {
		//To modem log
		_DBG("To modem send: ");
		for(BYTE j = 0; SendCommand[j]; j++) {
			if(SendCommand[j] >= 32) _DBG("%c", SendCommand[j]); else _DBG("[%02X]", SendCommand[j]);
		}
		_DBG("\n");
	}
#endif


	//From modem log
#ifdef _DBG_MODEM
	_DBG("From modem wait: ");
#endif
	for(BYTE i = 0; WaitResult[i]; i++) {
#ifdef _DBG_MODEM
		_DBG("%d - ", i);
		for(BYTE j = 0; WaitResult[i][j]; j++) {
			if(WaitResult[i][j] >= 32) _DBG("%c", WaitResult[i][j]); else _DBG("[%02X]", WaitResult[i][j]);
		}
		_DBG(" ");
#endif
		ResultsCount++;
	}
#ifdef _DBG_MODEM
	_DBG("\n");
#endif

	WORD Offsets[ResultsCount];

	for(BYTE i = 0; WaitResult[i]; i++) {
		Offsets[i] = 0;
	}

	if(SendCommand && *SendCommand) {
		//Flush modem RX
		BYTE dummy;
		while(MODEM_GetChar(&dummy, MODEM_RX_FLUSH_TIMEOUT)) {
#ifdef _DBG_MODEM
			if(dummy >= 32)_DBG("%c", dummy); else _DBG("[%02X]", dummy);
#endif
		}

		if(!MODEM_Send(SendCommand, Timeout)) return ERROR_MODEM_IO_TIMEOUT;
	}

#ifdef _DBG_MODEM
	_DBG(">>");
#endif

	for(;;) {
		BYTE data;
		if(!MODEM_GetChar(&data, Timeout)) break;

#ifdef _DBG_MODEM
		if(data >= 32)_DBG("%c", data); else _DBG("[%02X]", data);
#endif

		for(int i = 0; WaitResult[i]; i++) {
			if(WaitResult[i][Offsets[i]] != data) Offsets[i] = 0;

			if(WaitResult[i][Offsets[i]] == data) {
				Offsets[i]++;
				if(WaitResult[i][Offsets[i]] == 0) {
#ifdef _DBG_MODEM
					_DBG("\nResult: %s\n", WaitResult[i]);
#endif
					return i;
				}
			}
		}
	}
#ifdef _DBG_MODEM
	_DBG("\n");
#endif
	return ERROR_MODEM_IO_TIMEOUT;
}



Реализация, возможно, выглядит страшно, но использовать ее просто. Например, проверка ввода пин


        const char * PinResponses[] = {"CPIN: READY", "ERROR", "BLABLABLA", NULL};
	error = MODEM_Chat("AT+CPIN?\r\n", PinResponses, MODEM_NORMAL_CMD_TIMEOUT);
	if(error == 0) {
		_DBG("[IFNO] PIN READY\n");
	}
	...


PinResponses – это массив возможных ответов.
MODEM_Chat() в данном случае посылает команду «AT+CPIN?\r\n» и ждет ответ. Возвращаемое значение будет
0 – модем ответил «CPIN: READY»
1 – модем ответил «ERROR»
2 — модем ответил «BLABLABLA»
-1 – тамаут (модем ничего не ответил, либо ответ модема не содержится в массиве ожидаемых значений)

Думаю, идея понятна. Получилось ИМХО, очень удобно.
  • avatar
  • e_mc2
  • 23 сентября 2013, 17:20