2022-07-18 17:17:40 +00:00
|
|
|
package com.radio.codec2talkie.protocol.aprs;
|
|
|
|
|
|
|
|
import com.radio.codec2talkie.protocol.message.TextMessage;
|
|
|
|
import com.radio.codec2talkie.protocol.position.Position;
|
|
|
|
|
2022-07-18 19:24:48 +00:00
|
|
|
import java.nio.ByteBuffer;
|
2022-09-06 15:55:52 +00:00
|
|
|
import java.nio.charset.StandardCharsets;
|
2023-07-15 13:25:48 +00:00
|
|
|
import java.util.Locale;
|
2022-09-12 15:35:35 +00:00
|
|
|
import java.util.regex.Matcher;
|
|
|
|
import java.util.regex.Pattern;
|
2022-07-18 19:24:48 +00:00
|
|
|
|
2022-07-18 17:17:40 +00:00
|
|
|
public class AprsDataTextMessage implements AprsData {
|
|
|
|
|
2022-07-23 10:00:20 +00:00
|
|
|
public String srcCallsign;
|
2022-07-18 17:17:40 +00:00
|
|
|
public String dstCallsign;
|
2022-08-20 12:52:10 +00:00
|
|
|
public String digipath;
|
2022-07-18 17:17:40 +00:00
|
|
|
public String textMessage;
|
2023-07-15 13:25:48 +00:00
|
|
|
public Integer ackId;
|
2022-07-18 17:17:40 +00:00
|
|
|
|
|
|
|
private boolean _isValid;
|
|
|
|
|
2023-07-02 08:10:45 +00:00
|
|
|
@Override
|
|
|
|
public boolean isPositionReport() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isTextMessage() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-07-18 17:17:40 +00:00
|
|
|
@Override
|
|
|
|
public void fromPosition(Position position) {
|
|
|
|
_isValid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void fromTextMessage(TextMessage textMessage) {
|
|
|
|
this.dstCallsign = textMessage.dst;
|
|
|
|
this.textMessage = textMessage.text;
|
2022-08-20 12:52:10 +00:00
|
|
|
this.digipath = textMessage.digipath;
|
2023-07-15 13:25:48 +00:00
|
|
|
this.ackId = textMessage.ackId;
|
2022-07-18 17:17:40 +00:00
|
|
|
_isValid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Position toPosition() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public TextMessage toTextMessage() {
|
|
|
|
TextMessage textMessage = new TextMessage();
|
2022-07-23 10:00:20 +00:00
|
|
|
textMessage.src = this.srcCallsign;
|
2022-07-18 17:17:40 +00:00
|
|
|
textMessage.dst = this.dstCallsign;
|
2022-08-20 12:52:10 +00:00
|
|
|
textMessage.digipath = this.digipath;
|
2022-07-18 17:17:40 +00:00
|
|
|
textMessage.text = this.textMessage;
|
2023-07-15 13:25:48 +00:00
|
|
|
textMessage.ackId = this.ackId;
|
2022-07-18 17:17:40 +00:00
|
|
|
return textMessage;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-08-20 12:52:10 +00:00
|
|
|
public void fromBinary(String srcCallsign, String dstCallsign, String digipath, byte[] infoData) {
|
2022-07-18 17:17:40 +00:00
|
|
|
_isValid = false;
|
2022-07-18 19:24:48 +00:00
|
|
|
if (infoData.length < 10) return;
|
2022-08-20 12:52:10 +00:00
|
|
|
this.digipath = digipath;
|
2022-07-23 10:00:20 +00:00
|
|
|
this.srcCallsign = srcCallsign;
|
2022-07-18 19:24:48 +00:00
|
|
|
ByteBuffer buffer = ByteBuffer.wrap(infoData);
|
2023-07-15 13:25:48 +00:00
|
|
|
|
2022-07-18 19:24:48 +00:00
|
|
|
// callsign, trim ending spaces
|
|
|
|
byte[] callsign = new byte[9];
|
|
|
|
buffer.get(callsign);
|
2022-07-23 10:00:20 +00:00
|
|
|
this.dstCallsign = new String(callsign).replaceAll("\\s+$", "");
|
2023-07-15 13:25:48 +00:00
|
|
|
|
2022-07-18 19:24:48 +00:00
|
|
|
// ':' separator
|
|
|
|
byte b = buffer.get();
|
|
|
|
if (b != ':') return;
|
2023-07-15 13:25:48 +00:00
|
|
|
|
2022-07-18 19:24:48 +00:00
|
|
|
// message
|
|
|
|
byte[] message = new byte[buffer.remaining()];
|
|
|
|
buffer.get(message);
|
2023-07-15 13:25:48 +00:00
|
|
|
String stringMessage = new String(message, StandardCharsets.UTF_8);
|
|
|
|
|
|
|
|
// ack/rej message
|
|
|
|
this.ackId = 0;
|
|
|
|
Pattern p = Pattern.compile("^(ack|rej)(\n+){1,5}$", Pattern.DOTALL);
|
|
|
|
Matcher m = p.matcher(stringMessage);
|
|
|
|
if (m.find()) {
|
|
|
|
String type = m.group(1);
|
|
|
|
if (type != null) {
|
|
|
|
String ackIdStr = m.group(2);
|
|
|
|
if (ackIdStr != null)
|
|
|
|
this.ackId = Integer.parseInt(ackIdStr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// message requires acknowledge {xxxxx (for auto ack)
|
2023-12-07 12:26:07 +00:00
|
|
|
p = Pattern.compile("^.+[{](\\d+){1,5}$", Pattern.DOTALL);
|
2023-07-15 13:25:48 +00:00
|
|
|
m = p.matcher(stringMessage);
|
|
|
|
if (m.find()) {
|
|
|
|
this.textMessage = m.group(1);
|
|
|
|
String ackNumStr = m.group(2);
|
|
|
|
if (ackNumStr != null)
|
|
|
|
this.ackId = Integer.parseInt(ackNumStr);
|
2023-12-07 12:26:07 +00:00
|
|
|
} else {
|
2023-07-15 13:25:48 +00:00
|
|
|
this.textMessage = stringMessage;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-12 15:35:35 +00:00
|
|
|
// TODO, telemetry, make subclass from message, extend and extract values
|
2023-07-15 13:25:48 +00:00
|
|
|
if (this.textMessage != null)
|
|
|
|
_isValid = !isTelemetry(this.textMessage);
|
2022-07-18 17:17:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public byte[] toBinary() {
|
2023-07-15 13:25:48 +00:00
|
|
|
return (ackId > 0)
|
|
|
|
? String.format(Locale.US, ":%-9s:%s{%d", dstCallsign, textMessage, ackId).getBytes()
|
|
|
|
: String.format(":%-9s:%s", dstCallsign, textMessage).getBytes();
|
2022-07-18 17:17:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isValid() {
|
|
|
|
return _isValid;
|
|
|
|
}
|
2022-09-12 15:35:35 +00:00
|
|
|
|
|
|
|
private boolean isTelemetry(String textMessage) {
|
2022-09-12 15:44:28 +00:00
|
|
|
Pattern p = Pattern.compile("^(EQNS|PARM|UNIT|BITS)[.].+$", Pattern.DOTALL);
|
2022-09-12 15:35:35 +00:00
|
|
|
Matcher m = p.matcher(textMessage);
|
|
|
|
return m.matches();
|
|
|
|
}
|
2022-07-18 17:17:40 +00:00
|
|
|
}
|