Merge remote-tracking branch 'asm/asm_16.2.1' into master_16.2.1
Former-commit-id: 70338bff91bc02d5b0e2b2286164073afd85ed3c
This commit is contained in:
commit
44c2a22f93
6 changed files with 504 additions and 288 deletions
|
@ -21,61 +21,84 @@ package com.raytheon.rcm.message;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Represents the contents of an ORPG General Status Message.
|
||||
*
|
||||
* <pre>
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 2009 dfriedman Initial version
|
||||
* 2016-04-22 DR 18909 dfriedman Read fields of expanded GSM.
|
||||
* </pre>
|
||||
*/
|
||||
public class GSM extends Message {
|
||||
public static final int OP_MODE_MAINTENANCE = 0;
|
||||
public static final int OP_MODE_CLEAR_AIR = 1;
|
||||
public static final int OP_MODE_STORM = 2;
|
||||
|
||||
public int opMode;
|
||||
public int rdaOpStatus;
|
||||
public int vcp;
|
||||
public int[] cuts; // in tenths of degrees
|
||||
public int rdaStatus;
|
||||
public int rdaAlarms;
|
||||
public int dataAvailability; // "DTE"
|
||||
public int rpgOpStatus;
|
||||
public int rpgAlarms;
|
||||
public int rpgStatus;
|
||||
public int rpgNarrowbandStatus;
|
||||
public int rcc;
|
||||
public int productAvailability;
|
||||
public int superResCuts;
|
||||
public int rdaVersion;
|
||||
public int rdaChannel;
|
||||
public int rpgVersion;
|
||||
|
||||
public static GSM decode(byte[] msg) {
|
||||
return (GSM) MD.decode(msg);
|
||||
}
|
||||
public static final int OP_MODE_MAINTENANCE = 0;
|
||||
public static final int OP_MODE_CLEAR_AIR = 1;
|
||||
public static final int OP_MODE_STORM = 2;
|
||||
|
||||
protected void decodeBlock(int index, ByteBuffer buf) {
|
||||
if (index != 1)
|
||||
return;
|
||||
opMode = buf.getShort();
|
||||
rdaOpStatus = buf.getShort();
|
||||
vcp = buf.getShort();
|
||||
int nCuts = buf.getShort();
|
||||
cuts = new int[nCuts];
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
if (i < cuts.length)
|
||||
cuts[i] = buf.getShort();
|
||||
else
|
||||
buf.getShort();
|
||||
}
|
||||
rdaStatus = buf.getShort();
|
||||
rdaAlarms = buf.getShort();
|
||||
dataAvailability = buf.getShort();
|
||||
rpgOpStatus = buf.getShort();
|
||||
rpgAlarms = buf.getShort();
|
||||
rpgStatus = buf.getShort();
|
||||
rpgNarrowbandStatus = buf.getShort();
|
||||
rcc = buf.getShort();
|
||||
productAvailability = buf.getShort();
|
||||
superResCuts = buf.getShort();
|
||||
buf.position(buf.position() + 4);
|
||||
rdaVersion = buf.getShort();
|
||||
rdaChannel = buf.getShort();
|
||||
buf.position(buf.position() + 4);
|
||||
rpgVersion = buf.getShort();
|
||||
}
|
||||
public int opMode;
|
||||
public int rdaOpStatus;
|
||||
public int vcp;
|
||||
public int[] cuts; // in tenths of degrees
|
||||
public int rdaStatus;
|
||||
public int rdaAlarms;
|
||||
public int dataAvailability; // "DTE"
|
||||
public int rpgOpStatus;
|
||||
public int rpgAlarms;
|
||||
public int rpgStatus;
|
||||
public int rpgNarrowbandStatus;
|
||||
public int rcc;
|
||||
public int productAvailability;
|
||||
public int superResCuts;
|
||||
public int rdaVersion;
|
||||
public int rdaChannel;
|
||||
public int rpgVersion;
|
||||
public int vcpSupplemental;
|
||||
|
||||
public static GSM decode(byte[] msg) {
|
||||
return (GSM) MD.decode(msg);
|
||||
}
|
||||
|
||||
protected void decodeBlock(int index, ByteBuffer buf) {
|
||||
if (index != 1)
|
||||
return;
|
||||
opMode = buf.getShort();
|
||||
rdaOpStatus = buf.getShort();
|
||||
vcp = buf.getShort();
|
||||
int nCuts = buf.getShort();
|
||||
cuts = new int[nCuts];
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
short cut = buf.getShort();
|
||||
if (i < cuts.length) {
|
||||
cuts[i] = cut;
|
||||
}
|
||||
}
|
||||
rdaStatus = buf.getShort();
|
||||
rdaAlarms = buf.getShort();
|
||||
dataAvailability = buf.getShort();
|
||||
rpgOpStatus = buf.getShort();
|
||||
rpgAlarms = buf.getShort();
|
||||
rpgStatus = buf.getShort();
|
||||
rpgNarrowbandStatus = buf.getShort();
|
||||
rcc = buf.getShort();
|
||||
productAvailability = buf.getShort();
|
||||
superResCuts = buf.getShort();
|
||||
buf.position(buf.position() + 4);
|
||||
rdaVersion = buf.getShort();
|
||||
rdaChannel = buf.getShort();
|
||||
buf.position(buf.position() + 4);
|
||||
rpgVersion = buf.getShort();
|
||||
if (buf.remaining() < 12) {
|
||||
return;
|
||||
}
|
||||
for (int i = 20; i < 25; ++i) {
|
||||
short cut = buf.getShort();
|
||||
if (i < cuts.length) {
|
||||
cuts[i] = cut;
|
||||
}
|
||||
}
|
||||
vcpSupplemental = buf.getShort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,12 @@ package com.raytheon.rcm.otrmgr;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.raytheon.rcm.config.RadarConfig;
|
||||
import com.raytheon.rcm.config.RadarType;
|
||||
import com.raytheon.rcm.config.RcmUtil;
|
||||
import com.raytheon.rcm.event.OtrEvent;
|
||||
import com.raytheon.rcm.event.RadarEvent;
|
||||
|
@ -39,6 +41,7 @@ import com.raytheon.rcm.message.MessageFormatException;
|
|||
import com.raytheon.rcm.message.MessageInfo;
|
||||
import com.raytheon.rcm.message.ProductRequest;
|
||||
import com.raytheon.rcm.message.RequestResponse;
|
||||
import com.raytheon.rcm.products.ElevationInfo;
|
||||
import com.raytheon.rcm.request.Filter;
|
||||
import com.raytheon.rcm.request.Request;
|
||||
import com.raytheon.rcm.request.Sequence;
|
||||
|
@ -55,9 +58,18 @@ import com.raytheon.rcm.server.RadarServer;
|
|||
/**
|
||||
* Manages One Time Requests for the RPGs.
|
||||
* <p>
|
||||
* Does not actually do much except provide a place to queue up requests while
|
||||
* waiting to connect to the RPG. Does do some coalescing of duplicate
|
||||
* requests.
|
||||
* Implements a queue for pending requests to the RPGs. Performs some coalescing
|
||||
* of duplicate requests.
|
||||
*
|
||||
* <pre>
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 2009 dfriedman Initial version
|
||||
* 2016-04-22 DR 18909 dfriedman Accurately calculate the number of expected
|
||||
* responses for multiple-elevation requests.
|
||||
* </pre>
|
||||
*/
|
||||
public class OTRManager extends RadarEventAdapter {
|
||||
|
||||
|
@ -69,7 +81,7 @@ public class OTRManager extends RadarEventAdapter {
|
|||
*/
|
||||
protected boolean isReady;
|
||||
|
||||
protected List<Req> requests = new ArrayList<Req>();
|
||||
protected List<Req> requests = new ArrayList<>();
|
||||
|
||||
protected GSM lastGSM;
|
||||
|
||||
|
@ -226,7 +238,7 @@ public class OTRManager extends RadarEventAdapter {
|
|||
|
||||
private void trySendingRequests() {
|
||||
if (isReady()) {
|
||||
ArrayList<Request> requestsToSend = new ArrayList<Request>();
|
||||
ArrayList<Request> requestsToSend = new ArrayList<>();
|
||||
long now = System.currentTimeMillis();
|
||||
synchronized (this.requests) {
|
||||
for (Req r : requests) {
|
||||
|
@ -319,31 +331,55 @@ public class OTRManager extends RadarEventAdapter {
|
|||
&& request.getElevationSelection() != Request.SPECIFIC_ELEVATION) {
|
||||
if (lastGSM != null) {
|
||||
if (request.getElevationSelection() == Request.ALL_ELEVATIONS) {
|
||||
/*
|
||||
* We do not get information about duplicate
|
||||
* elevations. Could put in TDWR-specific knowledge.
|
||||
* If vcp==80 && is-low-elevation...
|
||||
*
|
||||
* But probably needs something like.
|
||||
* nExpectedUnknown = true and (if nExpectedUnknown
|
||||
* then connMgr.idleDisconnectRadar(...)
|
||||
*/
|
||||
// if is tdwr and vcp80...
|
||||
exactCountUnknown = true;
|
||||
RadarType radarType = RcmUtil.getRadarType(getRadarConfig());
|
||||
int[] completeElevationList;
|
||||
|
||||
nElevations = request.getElevationAngle() == 0 ? lastGSM.cuts.length
|
||||
: 1;
|
||||
if (radarType == RadarType.WSR
|
||||
|| (radarType == RadarType.TDWR && lastGSM.rpgVersion >= 80)) {
|
||||
/*
|
||||
* When MESO-SAILS was added to WSR-88D, the
|
||||
* expanded GSM was already available and it
|
||||
* contained the complete list of elevations
|
||||
* including extra SAILS elevations. Therefore,
|
||||
* we can always rely on a WSR-88D's GSM for the
|
||||
* list of elevation angles.
|
||||
*
|
||||
* Later version of the SPG contain the complete
|
||||
* list of angles in an expected GSM.
|
||||
*/
|
||||
completeElevationList = lastGSM.cuts;
|
||||
} else if (radarType == RadarType.TDWR && lastGSM.rpgVersion < 80) {
|
||||
/*
|
||||
* Earlier versions of the SPG do not list the
|
||||
* extra low angle elevations scans. We can use
|
||||
* the static elevation list instead.
|
||||
*/
|
||||
completeElevationList = ElevationInfo
|
||||
.getInstance().getScanElevations(
|
||||
radarID, lastGSM.vcp);
|
||||
} else {
|
||||
/*
|
||||
* No choice but to guess based on the list of
|
||||
* elevations from the GSM.
|
||||
*/
|
||||
completeElevationList = lastGSM.cuts;
|
||||
exactCountUnknown = true;
|
||||
}
|
||||
int elevationAngle = request.getElevationAngle();
|
||||
nElevations = elevationAngle == 0 ? uniqueCount(completeElevationList)
|
||||
: matchCount(elevationAngle, completeElevationList);
|
||||
} else if (request.getElevationSelection() == Request.N_ELEVATIONS) {
|
||||
nElevations = Math.min(lastGSM.cuts.length,
|
||||
nElevations = Math.min(uniqueCount(lastGSM.cuts),
|
||||
request.getElevationAngle());
|
||||
} else if (request.getElevationSelection() == Request.LOWER_ELEVATIONS) {
|
||||
HashSet<Integer> seenAngles = new HashSet<>();
|
||||
nElevations = 0;
|
||||
int reqEA = request.getElevationAngle();
|
||||
for (int ea : lastGSM.cuts) {
|
||||
if (ea <= reqEA)
|
||||
if (ea <= reqEA && !seenAngles.contains(ea)) {
|
||||
++nElevations;
|
||||
else
|
||||
break;
|
||||
seenAngles.add(ea);
|
||||
}
|
||||
}
|
||||
} else
|
||||
exactCountUnknown = true;
|
||||
|
@ -356,9 +392,41 @@ public class OTRManager extends RadarEventAdapter {
|
|||
nExpected = request.count * nElevations;
|
||||
}
|
||||
|
||||
private int uniqueCount(int[] angles) {
|
||||
HashSet<Integer> uniqueAngles = new HashSet<>();
|
||||
for (int a : angles) {
|
||||
uniqueAngles.add(a);
|
||||
}
|
||||
return uniqueAngles.size();
|
||||
}
|
||||
|
||||
private int matchCount(int angle, int[] angles) {
|
||||
int matchedAngle = findClosestAngle(angle, angles);
|
||||
int count = 0;
|
||||
for (int a : angles) {
|
||||
if (a == matchedAngle) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private int findClosestAngle(int angle, int[] angles) {
|
||||
int result = Integer.MIN_VALUE;
|
||||
int bestDiff = Integer.MAX_VALUE;
|
||||
for (int a : angles) {
|
||||
int diff = Math.abs(a - angle);
|
||||
if (result == -1 || diff < bestDiff) {
|
||||
result = a;
|
||||
bestDiff = diff;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addHandler(OTRHandler handler) {
|
||||
if (handlers == null)
|
||||
handlers = new ArrayList<OTRHandler>();
|
||||
handlers = new ArrayList<>();
|
||||
handlers.add(handler);
|
||||
}
|
||||
|
||||
|
@ -387,7 +455,7 @@ public class OTRManager extends RadarEventAdapter {
|
|||
RadarServer radarServer;
|
||||
|
||||
// ArrayList<Req> requests = new ArrayList<Req>();
|
||||
HashMap<String, RadarStatus> state = new HashMap<String, RadarStatus>();
|
||||
HashMap<String, RadarStatus> state = new HashMap<>();
|
||||
|
||||
public OTRManager(RadarServer radarServer) {
|
||||
this.radarServer = radarServer;
|
||||
|
|
|
@ -31,184 +31,198 @@ import com.raytheon.rcm.message.GraphicProduct.PDB;
|
|||
|
||||
/**
|
||||
* A radar server component that logs various radar events.
|
||||
*
|
||||
* <pre>
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 2009 dfriedma Initial version
|
||||
* 2016-04-22 DR 18909 dfriedma Log fields of expanded GSM.
|
||||
* </pre>
|
||||
*/
|
||||
public class EventLogger extends RadarEventAdapter {
|
||||
|
||||
public EventLogger() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRadarEvent(RadarEvent event) {
|
||||
switch (event.getType()) {
|
||||
case RadarEvent.CONNECTION_UP:
|
||||
Log.eventf("%s: connected", event.getRadarID());
|
||||
break;
|
||||
case RadarEvent.CONNECTION_DOWN:
|
||||
Log.eventf("%s: disconnected", event.getRadarID());
|
||||
break;
|
||||
case RadarEvent.MESSAGE_RECEIVED:
|
||||
{
|
||||
StringBuilder s = new StringBuilder();
|
||||
byte[] msg = event.getMessageData();
|
||||
int messageCode = Message.messageCodeOf(msg);
|
||||
s.append("code=" + messageCode);
|
||||
s.append(" size=" + msg.length);
|
||||
if (messageCode == Message.GSM) {
|
||||
s.append(' ');
|
||||
GSM gsm = null;
|
||||
try {
|
||||
gsm = GSM.decode(msg);
|
||||
} catch (Exception e) {
|
||||
s.append("(Message decoding failed)");
|
||||
}
|
||||
if (gsm != null)
|
||||
s.append(formatGSM(gsm));
|
||||
} else if (messageCode == Message.REQUEST_RESPONSE) {
|
||||
s.append(' ');
|
||||
RequestResponse rr = null;
|
||||
try {
|
||||
rr = RequestResponse.decode(msg);
|
||||
} catch (Exception e) {
|
||||
s.append("(Message decoding failed)");
|
||||
}
|
||||
if (rr != null)
|
||||
s.append(formatPRR(rr));
|
||||
} else if (messageCode >= 16) {
|
||||
PDB pdb = null;
|
||||
|
||||
s.append(' ');
|
||||
try {
|
||||
pdb = GraphicProduct.pdbOfMessage(msg);
|
||||
} catch (Exception e) {
|
||||
s.append("(Message decoding failed)");
|
||||
}
|
||||
if (pdb != null)
|
||||
s.append(String.format("elev=%.1f sequence=%d"+
|
||||
" vs=%3$tY-%3$tm-%3$td %3$tH:%3$tM:%3$tS #%4$d",
|
||||
pdb.getElevationAngle() / 10.0, pdb.sequence,
|
||||
pdb.volumeScanTime, pdb.volumeScan));
|
||||
}
|
||||
|
||||
Log.eventf("%s: message %s", event.getRadarID(), s.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
public EventLogger() {
|
||||
|
||||
protected final String[] rdaOpStatusStr = {
|
||||
"auto-calib-disab", "online", "maint-req", "maint-mand", "cmd-shutdown",
|
||||
"inoperable", null, "wideband-disconn"
|
||||
};
|
||||
protected final String[] rdaStatusStr = {
|
||||
null, "startup", "standby", "restart", "operate", null, "offline-op"
|
||||
};
|
||||
protected final String[] rdaAlarmStr = {
|
||||
"indeterminate", "tower", "pedestal", "transmitter", "receiver", "control", "comms"
|
||||
};
|
||||
protected final String[] dteStr = {
|
||||
null, "none", "refl", "vel", "sw", "dual-pol"
|
||||
};
|
||||
protected final String[] rpgOpStr = {
|
||||
"load-shed", "online", "maint-req", "maint-mand", "cmd-shutdown"
|
||||
};
|
||||
protected final String[] rpgAlarmStr = {
|
||||
"none", "node-conn", null, "ctl-task-fail", "db-fail", null, "input-load-shed",
|
||||
null, "store-load-shed", null, null, null, "link-fail", "redundant-channel-error",
|
||||
"task-fail", "media-fail"
|
||||
};
|
||||
protected final String[] rpgStatusStr = {
|
||||
"restart", "operate", "standby", null, "test-mode"
|
||||
};
|
||||
protected final String[] productAvailStr = {
|
||||
"avail", "degraded", "not-avail"
|
||||
};
|
||||
protected final String[] prrStr = {
|
||||
"no-such-msg", "no-such-prod", "not-gen", "proc-fault",
|
||||
"narrowband-loadshed", "illegal-req", "mem-loadshed", "cpu-loadshed",
|
||||
"slot-unavail", "task-failed", "task-unavail", "avail-next-scan",
|
||||
"moment-disabled", "invalid-password", null, "aborted-scan",
|
||||
"inval-prod-param", "data-seq-error", "task-term"
|
||||
};
|
||||
|
||||
protected String formatBits(short bits, String[] strings) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((bits & (1 << i)) != 0) {
|
||||
if (result.length() > 0)
|
||||
result.append(',');
|
||||
String s = null;
|
||||
if (i < strings.length)
|
||||
s = strings[i];
|
||||
if (s == null)
|
||||
s = "unk" + Integer.toString(15 - i);
|
||||
result.append(s);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
protected String formatPrrBits(int bits, String[] strings) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < 32; i++) {
|
||||
// PRR bits are defined from the MSB on down, so
|
||||
// note the (31-i)
|
||||
if ((bits & (1 << (31-i))) != 0) {
|
||||
if (result.length() > 0)
|
||||
result.append(',');
|
||||
String s = null;
|
||||
if (i < strings.length)
|
||||
s = strings[i];
|
||||
if (s == null)
|
||||
s = "unk" + Integer.toString(31 - i);
|
||||
result.append(s);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
protected String formatGSM(GSM gsm) {
|
||||
StringBuilder o = new StringBuilder();
|
||||
String s;
|
||||
}
|
||||
|
||||
switch (gsm.opMode) {
|
||||
case GSM.OP_MODE_CLEAR_AIR: s = "clear-air"; break;
|
||||
case GSM.OP_MODE_STORM: s = "storm"; break;
|
||||
case GSM.OP_MODE_MAINTENANCE: s = "maintenance"; break;
|
||||
default: s = "(" +Integer.toString(gsm.opMode) + ")";
|
||||
}
|
||||
o.append("opMode=" + s);
|
||||
|
||||
o.append(" vcp=" + gsm.vcp);
|
||||
o.append(" cuts=" + Arrays.toString(gsm.cuts));
|
||||
|
||||
o.append(String.format(" rdaOp=%s rdaStat=%s rdaAlarm=%s dte=%s rpgOp=%s rpgStat=%s rpgAlarm=%s",
|
||||
formatBits((short) gsm.rdaOpStatus, rdaOpStatusStr),
|
||||
formatBits((short) gsm.rdaStatus, rdaStatusStr),
|
||||
formatBits((short) gsm.rdaAlarms, rdaAlarmStr),
|
||||
formatBits((short) gsm.dataAvailability, dteStr),
|
||||
formatBits((short) gsm.rpgOpStatus, rpgOpStr),
|
||||
formatBits((short) gsm.rpgStatus, rpgStatusStr),
|
||||
formatBits((short) gsm.rpgAlarms, rpgAlarmStr)));
|
||||
|
||||
o.append(String.format(" avail=%s",
|
||||
formatBits((short) gsm.productAvailability, productAvailStr)));
|
||||
|
||||
o.append(String.format(" rdaVer=%.1f rpgVer=%.1f", gsm.rdaVersion/10.0, gsm.rpgVersion/10.));
|
||||
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
protected String formatPRR(RequestResponse rr) {
|
||||
StringBuilder o = new StringBuilder();
|
||||
|
||||
o.append(String.format("productCode=%d sequence=%d elev=%d flags=%s",
|
||||
rr.productCode,
|
||||
rr.sequence,
|
||||
rr.elevationAngle,
|
||||
formatPrrBits(rr.errorCode, prrStr)));
|
||||
|
||||
return o.toString();
|
||||
}
|
||||
@Override
|
||||
public void handleRadarEvent(RadarEvent event) {
|
||||
switch (event.getType()) {
|
||||
case RadarEvent.CONNECTION_UP:
|
||||
Log.eventf("%s: connected", event.getRadarID());
|
||||
break;
|
||||
case RadarEvent.CONNECTION_DOWN:
|
||||
Log.eventf("%s: disconnected", event.getRadarID());
|
||||
break;
|
||||
case RadarEvent.MESSAGE_RECEIVED:
|
||||
{
|
||||
StringBuilder s = new StringBuilder();
|
||||
byte[] msg = event.getMessageData();
|
||||
int messageCode = Message.messageCodeOf(msg);
|
||||
s.append("code=" + messageCode);
|
||||
s.append(" size=" + msg.length);
|
||||
if (messageCode == Message.GSM) {
|
||||
s.append(' ');
|
||||
GSM gsm = null;
|
||||
try {
|
||||
gsm = GSM.decode(msg);
|
||||
} catch (Exception e) {
|
||||
s.append("(Message decoding failed)");
|
||||
}
|
||||
if (gsm != null)
|
||||
s.append(formatGSM(gsm));
|
||||
} else if (messageCode == Message.REQUEST_RESPONSE) {
|
||||
s.append(' ');
|
||||
RequestResponse rr = null;
|
||||
try {
|
||||
rr = RequestResponse.decode(msg);
|
||||
} catch (Exception e) {
|
||||
s.append("(Message decoding failed)");
|
||||
}
|
||||
if (rr != null)
|
||||
s.append(formatPRR(rr));
|
||||
} else if (messageCode >= 16) {
|
||||
PDB pdb = null;
|
||||
|
||||
s.append(' ');
|
||||
try {
|
||||
pdb = GraphicProduct.pdbOfMessage(msg);
|
||||
} catch (Exception e) {
|
||||
s.append("(Message decoding failed)");
|
||||
}
|
||||
if (pdb != null)
|
||||
s.append(String.format("elev=%.1f sequence=%d"+
|
||||
" vs=%3$tY-%3$tm-%3$td %3$tH:%3$tM:%3$tS #%4$d",
|
||||
pdb.getElevationAngle() / 10.0, pdb.sequence,
|
||||
pdb.volumeScanTime, pdb.volumeScan));
|
||||
}
|
||||
|
||||
Log.eventf("%s: message %s", event.getRadarID(), s.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final String[] rdaOpStatusStr = {
|
||||
"auto-calib-disab", "online", "maint-req", "maint-mand", "cmd-shutdown",
|
||||
"inoperable", null, "wideband-disconn"
|
||||
};
|
||||
protected final String[] rdaStatusStr = {
|
||||
null, "startup", "standby", "restart", "operate", null, "offline-op"
|
||||
};
|
||||
protected final String[] rdaAlarmStr = {
|
||||
"indeterminate", "tower", "pedestal", "transmitter", "receiver", "control", "comms"
|
||||
};
|
||||
protected final String[] dteStr = {
|
||||
null, "none", "refl", "vel", "sw", "dual-pol"
|
||||
};
|
||||
protected final String[] rpgOpStr = {
|
||||
"load-shed", "online", "maint-req", "maint-mand", "cmd-shutdown"
|
||||
};
|
||||
protected final String[] rpgAlarmStr = {
|
||||
"none", "node-conn", null, "ctl-task-fail", "db-fail", null, "input-load-shed",
|
||||
null, "store-load-shed", null, null, null, "link-fail", "redundant-channel-error",
|
||||
"task-fail", "media-fail"
|
||||
};
|
||||
protected final String[] rpgStatusStr = {
|
||||
"restart", "operate", "standby", null, "test-mode"
|
||||
};
|
||||
protected final String[] productAvailStr = {
|
||||
"avail", "degraded", "not-avail"
|
||||
};
|
||||
protected final String[] prrStr = {
|
||||
"no-such-msg", "no-such-prod", "not-gen", "proc-fault",
|
||||
"narrowband-loadshed", "illegal-req", "mem-loadshed", "cpu-loadshed",
|
||||
"slot-unavail", "task-failed", "task-unavail", "avail-next-scan",
|
||||
"moment-disabled", "invalid-password", null, "aborted-scan",
|
||||
"inval-prod-param", "data-seq-error", "task-term"
|
||||
};
|
||||
protected final String[] vcpSupplementalStr = {
|
||||
"AVSET", "SAILS", "site-specific-vcp", "RxRN", "CBT"
|
||||
};
|
||||
|
||||
protected String formatBits(short bits, String[] strings) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((bits & (1 << i)) != 0) {
|
||||
if (result.length() > 0)
|
||||
result.append(',');
|
||||
String s = null;
|
||||
if (i < strings.length)
|
||||
s = strings[i];
|
||||
if (s == null)
|
||||
s = "unk" + Integer.toString(15 - i);
|
||||
result.append(s);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
protected String formatPrrBits(int bits, String[] strings) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < 32; i++) {
|
||||
// PRR bits are defined from the MSB on down, so
|
||||
// note the (31-i)
|
||||
if ((bits & (1 << (31-i))) != 0) {
|
||||
if (result.length() > 0)
|
||||
result.append(',');
|
||||
String s = null;
|
||||
if (i < strings.length)
|
||||
s = strings[i];
|
||||
if (s == null)
|
||||
s = "unk" + Integer.toString(31 - i);
|
||||
result.append(s);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
protected String formatGSM(GSM gsm) {
|
||||
StringBuilder o = new StringBuilder();
|
||||
String s;
|
||||
|
||||
switch (gsm.opMode) {
|
||||
case GSM.OP_MODE_CLEAR_AIR: s = "clear-air"; break;
|
||||
case GSM.OP_MODE_STORM: s = "storm"; break;
|
||||
case GSM.OP_MODE_MAINTENANCE: s = "maintenance"; break;
|
||||
default: s = "(" +Integer.toString(gsm.opMode) + ")";
|
||||
}
|
||||
o.append("opMode=" + s);
|
||||
|
||||
o.append(" vcp=" + gsm.vcp);
|
||||
o.append(" cuts=" + Arrays.toString(gsm.cuts));
|
||||
|
||||
o.append(String.format(" rdaOp=%s rdaStat=%s rdaAlarm=%s dte=%s rpgOp=%s rpgStat=%s rpgAlarm=%s",
|
||||
formatBits((short) gsm.rdaOpStatus, rdaOpStatusStr),
|
||||
formatBits((short) gsm.rdaStatus, rdaStatusStr),
|
||||
formatBits((short) gsm.rdaAlarms, rdaAlarmStr),
|
||||
formatBits((short) gsm.dataAvailability, dteStr),
|
||||
formatBits((short) gsm.rpgOpStatus, rpgOpStr),
|
||||
formatBits((short) gsm.rpgStatus, rpgStatusStr),
|
||||
formatBits((short) gsm.rpgAlarms, rpgAlarmStr)));
|
||||
|
||||
o.append(String.format(" avail=%s",
|
||||
formatBits((short) gsm.productAvailability, productAvailStr)));
|
||||
|
||||
o.append(String.format(" suppl=%s",
|
||||
formatBits((short) gsm.vcpSupplemental, vcpSupplementalStr)));
|
||||
|
||||
o.append(String.format(" rdaVer=%.1f rpgVer=%.1f", gsm.rdaVersion/10.0, gsm.rpgVersion/10.));
|
||||
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
protected String formatPRR(RequestResponse rr) {
|
||||
StringBuilder o = new StringBuilder();
|
||||
|
||||
o.append(String.format("productCode=%d sequence=%d elev=%d flags=%s",
|
||||
rr.productCode,
|
||||
rr.sequence,
|
||||
rr.elevationAngle,
|
||||
formatPrrBits(rr.errorCode, prrStr)));
|
||||
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -369,6 +369,7 @@ import com.raytheon.viz.ui.simulatedtime.SimulatedTimeOperations;
|
|||
* 06Jan2016 5225 randerso Fix problem with mixed case not getting converted to upper case
|
||||
* when multiple text editors are open on the same product.
|
||||
* Mar 17, 2016 RM 18727 D. Friedman Fix use of verification listener when entering and exiting editor.
|
||||
* Apr 15, 2016 RM 18870 D. Friedman Replace commas with ellipses only at start of edit and then word-wrap.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -4254,20 +4255,19 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
// section
|
||||
setCurrentHeaderAndBody();
|
||||
|
||||
// if product is a WarnGen product and is not enabled for mixed case
|
||||
// transmission, replace all commas with ellipses
|
||||
if ((product != null) && warngenPils.contains(product.getNnnid())
|
||||
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
|
||||
textEditor.setText(textEditor.getText()
|
||||
.replaceAll(", {0,1}", "..."));
|
||||
}
|
||||
|
||||
// Mark the uneditable warning text
|
||||
if (markUneditableText(textEditor)) {
|
||||
// Enable listener to monitor attempt to edit locked text
|
||||
verifyUndeditableText = true;
|
||||
}
|
||||
|
||||
// if product is a WarnGen product and is not enabled for mixed case
|
||||
// transmission, replace all commas with ellipses
|
||||
if ((product != null) && warngenPils.contains(product.getNnnid())
|
||||
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
|
||||
replaceCommasWithEllipses(product);
|
||||
}
|
||||
|
||||
// Set the menu buttons to reflect the edit mode.
|
||||
editorButtonMenuStates(inEditMode);
|
||||
|
||||
|
@ -4295,6 +4295,60 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
editHeader("warning", true);
|
||||
}
|
||||
|
||||
private void replaceCommasWithEllipses(StdTextProduct product) {
|
||||
boolean wasVerifying = verifyUndeditableText;
|
||||
try {
|
||||
verifyUndeditableText = false;
|
||||
/*
|
||||
* Performing wrapping as few times as possible to reduce the
|
||||
* chances of breaking the product format. Also, the location list
|
||||
* does not wrap properly unless all commas in the paragraph have
|
||||
* been changed to ellipses.
|
||||
*/
|
||||
Pattern p = Pattern.compile(", {0,1}");
|
||||
int pendingParagraphLineStart = -1;
|
||||
while (true) {
|
||||
String text = textEditor.getText();
|
||||
Matcher m = p.matcher(text);
|
||||
if (! m.find())
|
||||
break;
|
||||
int line = textEditor.getLineAtOffset(m.start());
|
||||
int paragraphLineStart = findParagraphStart(line);
|
||||
String lineText = textEditor.getLine(line);
|
||||
boolean lineNeedsWrap = lineText.length()
|
||||
- (m.end() - m.start()) + 3 > charWrapCol;
|
||||
if (pendingParagraphLineStart >= 0
|
||||
&& paragraphLineStart != pendingParagraphLineStart
|
||||
&& lineNeedsWrap) {
|
||||
wrapWholeParagraphAtLine(pendingParagraphLineStart);
|
||||
pendingParagraphLineStart = -1;
|
||||
// Line numbers may have changed so restart.
|
||||
continue;
|
||||
}
|
||||
textEditor.replaceTextRange(m.start(), m.end() - m.start(), "...");
|
||||
if (lineNeedsWrap) {
|
||||
pendingParagraphLineStart = paragraphLineStart;
|
||||
}
|
||||
}
|
||||
if (pendingParagraphLineStart >= 0) {
|
||||
wrapWholeParagraphAtLine(pendingParagraphLineStart);
|
||||
}
|
||||
} finally {
|
||||
verifyUndeditableText = wasVerifying;
|
||||
}
|
||||
}
|
||||
|
||||
void wrapWholeParagraphAtLine(int paragraphLineStart) {
|
||||
String line = textEditor.getLine(paragraphLineStart);
|
||||
// Avoid rewrapInternal early bailout check.
|
||||
if (line.length() < charWrapCol
|
||||
&& line.indexOf("...") == line.lastIndexOf("...")) {
|
||||
paragraphLineStart++;
|
||||
}
|
||||
int offset = textEditor.getOffsetAtLine(paragraphLineStart);
|
||||
rewrap(offset, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the editor mode.
|
||||
*
|
||||
|
@ -4402,16 +4456,6 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
textEditor.setText(originalText);
|
||||
}
|
||||
|
||||
// if product is a WarnGen product and is not enabled for mixed case
|
||||
// transmission, replace all commas with ellipses
|
||||
StdTextProduct product = TextDisplayModel.getInstance()
|
||||
.getStdTextProduct(token);
|
||||
if ((product != null) && warngenPils.contains(product.getNnnid())
|
||||
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
|
||||
textEditor.setText(textEditor.getText()
|
||||
.replaceAll(", {0,1}", "..."));
|
||||
}
|
||||
|
||||
markUneditableText(textEditor);
|
||||
|
||||
// Disable the lockable text listener since the application is no
|
||||
|
@ -7109,14 +7153,6 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
|
||||
textEditor.append(textProduct);
|
||||
|
||||
// if product is a WarnGen product and is not enabled for mixed case
|
||||
// transmission, replace all commas with ellipses
|
||||
if (warngenPils.contains(product.getNnnid())
|
||||
&& !MixedCaseProductSupport.isMixedCase(product.getNnnid())) {
|
||||
textEditor.setText(textEditor.getText()
|
||||
.replaceAll(", {0,1}", "..."));
|
||||
}
|
||||
|
||||
markUneditableText(textEditor);
|
||||
|
||||
// Update text display model with the product that was
|
||||
|
@ -8038,7 +8074,10 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
|
||||
paragraphStart = paragraphStart.toUpperCase();
|
||||
// is this the locations paragraph?
|
||||
if (paragraphStart.startsWith("* LOCATIONS")) {
|
||||
if (paragraphStart.startsWith("* LOCATIONS")
|
||||
|| paragraphStart.startsWith(("* SOME LOCATIONS"))
|
||||
|| paragraphStart.startsWith(("LOCATIONS IMPACTED"))
|
||||
|| paragraphStart.startsWith(("SOME LOCATIONS THAT"))) {
|
||||
inLocations = true;
|
||||
}
|
||||
|
||||
|
@ -8079,7 +8118,7 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
}
|
||||
|
||||
if (line.length() <= charWrapCol) {
|
||||
extendShortLine(lineNumber, padding);
|
||||
extendShortLine(lineNumber, padding, inLocations);
|
||||
if (textEditor.getLine(lineNumber).length() <= charWrapCol) {
|
||||
// extended line is still short enough do not wrap
|
||||
if (lineNumber < endWrapLine) {
|
||||
|
@ -8110,8 +8149,9 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
*
|
||||
* @param lineNumber
|
||||
* @param padding
|
||||
* @param inLocations
|
||||
*/
|
||||
private void extendShortLine(int lineNumber, final String padding) {
|
||||
private void extendShortLine(int lineNumber, final String padding, boolean inLocations) {
|
||||
// if the line is too short move the next line up
|
||||
// if there is a next line
|
||||
String line = textEditor.getLine(lineNumber);
|
||||
|
@ -8190,10 +8230,12 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
String wordSpace = "";
|
||||
if (noSeparatorPattern.matcher(endLine).matches()
|
||||
&& noSeparatorPattern.matcher(startNextLine)
|
||||
.matches()) {
|
||||
.matches()
|
||||
&& (!inLocations || !line.endsWith("..."))) {
|
||||
// Put a space between words when merging the lines.
|
||||
wordSpace = " ";
|
||||
}
|
||||
|
||||
textEditor.replaceTextRange(newlinePosition, deleteLen,
|
||||
wordSpace);
|
||||
String afterReplace = textEditor.getText();
|
||||
|
@ -8207,7 +8249,7 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
|
||||
// is this line still too short?
|
||||
if (textEditor.getLine(lineNumber).length() <= charWrapCol) {
|
||||
extendShortLine(lineNumber, padding);
|
||||
extendShortLine(lineNumber, padding, inLocations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8460,7 +8502,7 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
private void recompileRegex() {
|
||||
this.standardWrapRegex = Pattern.compile("( |..).{1,"
|
||||
+ (charWrapCol - 3) + "}(\\s|-)");
|
||||
this.locationsFirstRegex = Pattern.compile("^\\* LOCATIONS [^\\.]{1,"
|
||||
this.locationsFirstRegex = Pattern.compile("^(?:\\* (?:SOME )?LOCATIONS|LOCATIONS IMPACTED|SOME LOCATIONS THAT) [^\\.]{1,"
|
||||
+ (charWrapCol - 13) + "}\\s");
|
||||
this.locationsBodyRegex = Pattern.compile("(( |..).{1,"
|
||||
+ (charWrapCol - 5) + "}\\.\\.\\.)|(( |..).{1,"
|
||||
|
|
|
@ -1,19 +1,39 @@
|
|||
package com.raytheon.viz.warnings.rsc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
|
||||
import com.raytheon.uf.common.dataplugin.PluginDataObject;
|
||||
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
|
||||
import com.raytheon.uf.common.dataquery.requests.DbQueryRequest;
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
|
||||
import com.raytheon.uf.common.dataquery.responses.DbQueryResponse;
|
||||
import com.raytheon.uf.viz.core.RecordFactory;
|
||||
import com.raytheon.uf.viz.core.alerts.AbstractAlertMessageParser;
|
||||
import com.raytheon.uf.viz.core.alerts.AlertMessage;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.requests.ThriftClient;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractRequestableResourceData;
|
||||
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||
|
||||
/**
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Apr 21, 2016 DR 18905 Qinglu Lin Added code to handle no SPS auto-update issue.
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
public class CWASPSResourceData extends WWAResourceData {
|
||||
|
||||
private static AlertMessageToPDOParserSPS alertParser = new AlertMessageToPDOParserSPS();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
@ -34,4 +54,42 @@ public class CWASPSResourceData extends WWAResourceData {
|
|||
|
||||
return new CWASPSResource(this, loadProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAlertMessageParser getAlertParser() {
|
||||
return alertParser;
|
||||
}
|
||||
|
||||
private static class AlertMessageToPDOParserSPS extends AbstractAlertMessageParser {
|
||||
|
||||
@Override
|
||||
public Object parseAlertMessage(AlertMessage message,
|
||||
AbstractRequestableResourceData reqResourceData) throws VizException {
|
||||
Object objectToSend = null;
|
||||
Map<String, Object> attribs = new HashMap<>(message.decodedAlert);
|
||||
|
||||
if (reqResourceData.isUpdatingOnMetadataOnly()) {
|
||||
PluginDataObject record = RecordFactory.getInstance()
|
||||
.loadRecordFromMap(attribs);
|
||||
objectToSend = record;
|
||||
} else {
|
||||
/*
|
||||
* TODO avoid requesting data that will not be used, for example
|
||||
* when time matching won't allow the frame to be displayed.
|
||||
*/
|
||||
attribs.remove(PluginDataObject.DATAURI_ID);
|
||||
DbQueryRequest request = new DbQueryRequest(
|
||||
RequestConstraint.toConstraintMappingExcludeNull(attribs));
|
||||
request.setLimit(1);
|
||||
DbQueryResponse response = (DbQueryResponse) ThriftClient
|
||||
.sendRequest(request);
|
||||
PluginDataObject[] pdos = response
|
||||
.getEntityObjects(PluginDataObject.class);
|
||||
if (pdos.length > 0) {
|
||||
objectToSend = pdos[0];
|
||||
}
|
||||
}
|
||||
return objectToSend;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ import com.raytheon.uf.common.wmo.WMOTimeParser;
|
|||
* Jun 19, 2014 3226 bclement added validator callback
|
||||
* Jul 07, 2015 4581 skorolev Corrected decodeStrikes to avoid BufferUnderflowException.
|
||||
* Apr 07, 2016 DR18763 mgamazaychikov Switched to using LightningWMOHeader.
|
||||
* Apr 21, 2016 DR18849 mgamazaychikov Decrypt all data in decrypt method.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -200,9 +201,19 @@ public class TotalLightningDecoder {
|
|||
*/
|
||||
private PluginDataObject[] decodeInternal(LightningWMOHeader wmoHdr,
|
||||
String fileName, byte[] pdata) throws DecoderException {
|
||||
if (!validFlashPacket(pdata, COMBINATION_PACKET_HEADER_SIZE)) {
|
||||
/* assume data is encrypted if we can't understand it */
|
||||
pdata = decrypt(wmoHdr, fileName, pdata);
|
||||
byte[] pdataPreDecrypt = pdata;
|
||||
// determine if the data is encrypted or not based on comparing
|
||||
// checksums for flash packet
|
||||
pdata = decrypt(wmoHdr, fileName, pdata);
|
||||
boolean isDecryptedValid = validFlashPacket(pdata,
|
||||
COMBINATION_PACKET_HEADER_SIZE);
|
||||
boolean isPreDecryptedValid = validFlashPacket(pdataPreDecrypt,
|
||||
COMBINATION_PACKET_HEADER_SIZE);
|
||||
// assume that all data is encrypted, so decrypt it
|
||||
if (!isDecryptedValid && isPreDecryptedValid) {
|
||||
// this means that data is not encrypted, proceed without
|
||||
// decryption
|
||||
pdata = pdataPreDecrypt;
|
||||
}
|
||||
List<LightningStrikePoint> strikes = decodeStrikes(fileName, pdata);
|
||||
if (!strikes.isEmpty()) {
|
||||
|
|
Loading…
Add table
Reference in a new issue