Вот мой код для модема. Актуальность - 2024 год, Март.
Выложил основное тело. Всякие очереди и методы СМСок не будут компилироваться.
Мой код отличается от твоего тем, что у меня в конфигурации заданы параметры порта.
Код:
PROGRAM TaskSMS
(* Управление модемом ПМ-01 для приёма и отправки СМСок *)
VAR
(* Внешние переменные для задачи архивации *)
bExtCfgError : BOOL; (* Внешний флаг ошибки *)
bExtCfgErrorCode : WORD; (* Внешний код ошибки *)
(* Конфигурация модема и объекты работы с СМСками *)
fbSMSPort : OpenPort; (* Порт модема *)
fbSMSConfig : FB_SMS_CFG; (* Настройки модема *)
fbSMSObject : FB_SMS_SR; (* Объект приёма и отправки СМСок *)
bCfgOK : BOOL := FALSE; (* Флаг того, что модем успешно настроен и готов к работе *)
bCfgError : BOOL := FALSE; (* Флаг того, что при настройке модема была ошибка *)
wCfgErrCode : WORD := 0; (* Код ошибки модема *)
fbCfgErrorPulse : TP; (* Таймер выдержки ошибки настроек модема *)
fbCfgErrorExt : TOF; (* Таймер выдержки ошибки настроек модема для задачи Архиваии *)
(* Переменные для приёма и отправки СМСок *)
fbSMSInbound : R_TRIG; (* Отслеживание фронта новых СМСок *)
bReadyToSend : BOOL; (* Флаг того, что мы посылаем СМСку *)
bInSendMode : BOOL; (* Флаг того, что мы ждём конца отправки СМСки *)
END_VAR
VAR_TEMP
iPosRcv : WORD := 0; (* Счётчик очереди приёма СМСок *)
iPosSnd : WORD := 0; (* Счётчик очереди отправки СМСок *)
END_VAR
VAR CONSTANT
UNMDevNumber : WORD := 0; (* Номер UNM-устройства (с нуля) для порта модема *)
CFGErrorDelay : TIME := t#60s; (* Время выдержки ошибки настроек модема *)
CFGErrorExtTime : TIME := t#120s; (* Время выдержки ошибки настроек модема для задачи архивации *)
END_VAR
Код:
(***************************************************************************************)
(* Для начала смотрим на то, включено ли питание модема вообще. Если включено - пробуем его настроить. *)
IF (hwCtlPowerPM = TRUE) THEN
fbSMSPort(Enable:= TRUE, DeviceNumber:= UNMDevNumber);
fbSMSConfig(Enable:= (fbSMSPort.OUT AND NOT bCfgError),
Handle:= UNMDevNumber,
PortCfg:= TRUE,
SaveCfg:= FALSE,
ModemART:= FALSE,
PortBaudrate:= '9600',
PortParity:= 0,
PortStopBits:= 1,
PortByteSize:= 8,
PortFlowCtrl:= 0
);
(* Забираем код ошибки и выставляем флаг ошибки или успеха *)
fbCfgErrorPulse(IN:= (fbSMSConfig.ErrCode <> 0), PT:= CFGErrorDelay);
IF (fbCfgErrorPulse.IN) THEN (* Сохраняем код последней ошибки *)
wCfgErrCode := fbSMSConfig.ErrCode;
bExtCfgErrorCode := wCfgErrCode;
END_IF
bCfgError := fbCfgErrorPulse.Q;
bCfgOK := fbSMSConfig.Done AND NOT bCfgError;
(* Передаём значения ошибок на внешнюю задачу Архивации *)
fbCfgErrorExt(IN := bCfgError, PT := CFGErrorExtTime);
bExtCfgError := fbCfgErrorExt.Q;
ELSE
(* Если модем выключен - закрываем порт и выключаем его, сбрасываем ошибки *)
fbSMSPort(Enable:= FALSE, DeviceNumber:= UNMDevNumber);
fbSMSConfig(Enable:= FALSE);
fbCfgErrorPulse(IN := FALSE, PT := t#0ms);
fbCfgErrorExt(IN := FALSE, PT := t#0ms);
bCfgOK := FALSE;
bCfgError := FALSE;
wCfgErrCode := 0;
END_IF
(* Сброс сигналов ошибок, если модем прошёл конфигурацию *)
IF (bCfgOK = TRUE) THEN
bExtCfgError := FALSE;
bExtCfgErrorCode := 0;
END_IF
(***************************************************************************************)
(* РАБОТА С МОДЕМОМ, ЕСЛИ ОН УСПЕШНО НАСТРОЕН *)
fbSMSObject(
Enable := bCfgOK,
Handle := UNMDevNumber,
CsdClose := TRUE, (* Запрет входящих звонков; модем всегда вешает трубку *)
CheckNum := SMSSettingsSequreInbound, (* Проверять номер входящих СМСок по списку разрешённых? *)
CheckNumList := SMSSettingsSequreNumbers, (* Список разрешённых номеров через ; без + и скобок: 71231234567 *)
(* Следующием переменные рапсисаны для наглядности и справки по их назначениям в дальнейшем коде программы *)
Busy => , (* Блок занят и что-то делает *)
ErrCode => , (* Код ошибки *)
SmsSend => , (* СМСка успешно отослана (можно дёргать следующее из очереди) *)
SendSms := , (* Команда запуска отправки СМСки (TRUE) *)
SendSmsText := , (* Текст СМСки, которую надо отсылать *)
SendSmsNum := , (* Номер, куда её надо отсылать *)
NewInSms => , (* Найдено новое входящее СМС - его надо обработать *)
NewInRing => , (* Есть входящий звонок (плевать на него =)) *)
NewInSmsText => , (* Текст новой входящей СМСки *)
NewInSmsTime => , (* Время новой входящей СМСки *)
NewInSmsNum => (* Номер, с которого отправили входящую СМСку *)
);
(***************************************************************************************)
(* Этому блоку нужна обёртка из двух фич:
а) Очередь исходящих СМСок: массив данных (структур), куда мы пихаем новую СМСку и забываем про неё.
Когда блок свободен (.Busy = FALSE) и нет новых входящих СМСок (.NewInSms = FALSE), то мы извлекаем
СМСки из очереди по одной и отсылаем их блоку, ожидая его готовности по .SmsSend.
б) Очередь входящих СМСок: тоже массив данных (можно тех же структур). Работает по тому же принципу:
Как только пришла входящая СМСка, читаенм её из FB и пихаем в эту очередь.
Дальше, если очередь не пуста - извлекаем из неё СМСку и обрабатываем её. *)
(***************************************************************************************)
(* ОБРАБОТКА: Очередь Исходящих СМСок *)
IF (fbSMSObject.Busy = FALSE) THEN (* Работаем только если блок НЕ занят операциями *)
IF (bReadyToSend = FALSE) THEN
fbSMSObject.SendSms := FALSE; (* Скидываем команду отправки СМСки *)
SMSOpDoSend(); (* Подготовка первой СМСки в отправке. Если она готова - выставится флаг bReadyToSend *)
ELSE (* Работа по отправке СМСки и ожиданию успеха в этом *)
(* Здесь логика пизданутая: надо выставить флаг "SendSms" на некоторое время,
а потом дожидаться флага SmsSend, после чего выходить из этого блока.
Прям просится конечный автомат, но так как тут всего два состояния - делаем на IFах. *)
IF (bInSendMode = FALSE) THEN (* Если мы не в режиме отправки СМСки, то входим в него *)
bInSendMode := TRUE; (* Входим в режим отправки СМСок *)
ELSE (* Мы в режиме отправки СМСки. Выставляем флаг отправки и ждём, когда всё будет ОК *)
fbSMSObject.SendSms := TRUE; (* Выставляем флаг отправки СМСки *)
IF (fbSMSObject.SmsSend = TRUE) THEN (* Если СМСка отправлена успешно - выходим из режима отправки *)
fbSMSObject.SendSms := FALSE; (* Скидываем команду отправки СМСки *)
(* Скидываем все флаги отправки СМСок *)
bReadyToSend := FALSE;
bInSendMode := FALSE;
END_IF
END_IF
END_IF
END_IF
(* Дополнительная заглушка: если СМСка отправилась в любом режиме (даже если блок Busy) - выходим из режима отправки *)
IF (fbSMSObject.SmsSend = TRUE) THEN
fbSMSObject.SendSms := FALSE; (* Скидываем команду отправки СМСки *)
(* Скидываем все флаги отправки СМСок *)
bReadyToSend := FALSE;
bInSendMode := FALSE;
END_IF
(***************************************************************************************)
(* ОБРАБОТКА: Очередь Входящих СМСок *)
fbSMSInbound(CLK := fbSMSObject.NewInSms); (* Отслеживаем фронт новой СМСки *)
IF (fbSMSInbound.Q = TRUE) THEN (* Получили СМСку. Пихнём её в очередь *)
SMSOpDoRecieve(); (* Обработка приёма новой СМСки (ставим в очередь) *)
ELSE
SMSProcessInbound(); (* Обрабатываем очередь входящих СМСок *)
END_IF
(* Всё *)