diff --git a/src/main/java/ru/r2cloud/R2Cloud.java b/src/main/java/ru/r2cloud/R2Cloud.java index 77848437..4a038df0 100644 --- a/src/main/java/ru/r2cloud/R2Cloud.java +++ b/src/main/java/ru/r2cloud/R2Cloud.java @@ -164,7 +164,7 @@ public R2Cloud(Configuration props, Clock clock) { decoders = new Decoders(predict, props, processFactory); decoderService = new DecoderService(props, decoders, resultDao, leoSatDataService, threadFactory, metrics, satelliteDao); priorityService = new PriorityService(props, clock); - houseKeeping = new Housekeeping(props, satelliteDao, threadFactory, new CelestrakClient(props), tleDao, satnogsClient, leoSatDataClient, decoderService, priorityService); + houseKeeping = new Housekeeping(props, satelliteDao, threadFactory, new CelestrakClient(props, clock), tleDao, satnogsClient, leoSatDataClient, decoderService, priorityService); observationFactory = new ObservationFactory(predict); diff --git a/src/main/java/ru/r2cloud/SpectogramService.java b/src/main/java/ru/r2cloud/SpectogramService.java index 95d4265b..006a57d9 100644 --- a/src/main/java/ru/r2cloud/SpectogramService.java +++ b/src/main/java/ru/r2cloud/SpectogramService.java @@ -77,6 +77,10 @@ private File createFromIq(Observation req) { LOG.error("corrupted raw file: {}", req.getRawPath().getAbsolutePath()); return null; } + if (req.getDataFormat() == null) { + LOG.error("data format is missing"); + return null; + } FloatInput source = null; try { InputStream is = new BufferedInputStream(new FileInputStream(req.getRawPath())); diff --git a/src/main/java/ru/r2cloud/device/Device.java b/src/main/java/ru/r2cloud/device/Device.java index 74f35fa0..95f5a86f 100644 --- a/src/main/java/ru/r2cloud/device/Device.java +++ b/src/main/java/ru/r2cloud/device/Device.java @@ -117,11 +117,7 @@ private void schedule(ObservationRequest req, Transmitter transmitter) { public void safeRun() { IQData data; Observation observation = new Observation(req); - observation.setGain(String.valueOf(deviceConfiguration.getGain())); - // write some device-specific parameters - observation.setBiast(deviceConfiguration.isBiast()); - observation.setRtlDeviceId(deviceConfiguration.getRtlDeviceId()); - observation.setPpm(deviceConfiguration.getPpm()); + observation.setDevice(deviceConfiguration); observation.setStatus(ObservationStatus.RECEIVING_DATA); // do not use lock for multiple concurrent observations if (numberOfConcurrentObservations > 1) { diff --git a/src/main/java/ru/r2cloud/model/AntennaConfiguration.java b/src/main/java/ru/r2cloud/model/AntennaConfiguration.java index f26f3f97..1dc5c94a 100644 --- a/src/main/java/ru/r2cloud/model/AntennaConfiguration.java +++ b/src/main/java/ru/r2cloud/model/AntennaConfiguration.java @@ -72,4 +72,15 @@ public JsonObject toJson() { return json; } + public static AntennaConfiguration fromJson(JsonObject meta) { + AntennaConfiguration result = new AntennaConfiguration(); + result.setType(AntennaType.valueOf(meta.getString("antennaType", "OMNIDIRECTIONAL"))); + result.setAzimuth(meta.getDouble("azimuth", 0)); + result.setElevation(meta.getDouble("elevation", 0)); + result.setBeamwidth(meta.getDouble("beamwidth", 0)); + result.setMinElevation(meta.getDouble("minElevation", 0)); + result.setGuaranteedElevation(meta.getDouble("guaranteedElevation", 0)); + return result; + } + } diff --git a/src/main/java/ru/r2cloud/model/DeviceConfiguration.java b/src/main/java/ru/r2cloud/model/DeviceConfiguration.java index ff987b91..513393d9 100644 --- a/src/main/java/ru/r2cloud/model/DeviceConfiguration.java +++ b/src/main/java/ru/r2cloud/model/DeviceConfiguration.java @@ -1,6 +1,7 @@ package ru.r2cloud.model; import com.eclipsesource.json.JsonObject; +import com.eclipsesource.json.JsonValue; public class DeviceConfiguration { @@ -193,7 +194,9 @@ public JsonObject toJson() { if (id != null) { json.add("id", id); } - json.add("name", name); + if (name != null) { + json.add("name", name); + } if (deviceType != null) { json.add("deviceType", deviceType.name()); } @@ -238,4 +241,40 @@ public JsonObject toJson() { } return json; } + + public static DeviceConfiguration fromJson(JsonObject meta) { + DeviceConfiguration result = new DeviceConfiguration(); + result.setId(meta.getString("id", null)); + result.setName(meta.getString("name", null)); + result.setDeviceType(DeviceType.valueOf(meta.getString("deviceType", "RTLSDR"))); + result.setMinimumFrequency(meta.getLong("minimumFrequency", 0)); + result.setMaximumFrequency(meta.getLong("maximumFrequency", 0)); + result.setHost(meta.getString("host", null)); + result.setPort(meta.getInt("port", 0)); + result.setUsername(meta.getString("username", null)); + result.setGain(meta.getFloat("gain", 0)); + result.setRtlDeviceId(meta.getInt("rtlDeviceId", 0)); + result.setBiast(meta.getBoolean("biast", false)); + result.setPpm(meta.getInt("ppm", 0)); + result.setMaximumBatteryVoltage(meta.getDouble("maximumBatteryVoltage", 0)); + result.setMinimumBatteryVoltage(meta.getDouble("minimumBatteryVoltage", 0)); + JsonValue bandwidth = meta.get("bandwidth"); + if (bandwidth != null) { + SdrServerConfiguration sdrConfig = new SdrServerConfiguration(); + sdrConfig.setBandwidth(bandwidth.asLong()); + sdrConfig.setBandwidthCrop(meta.getLong("bandwidthCrop", 0)); + sdrConfig.setBasepath(meta.getString("basepath", null)); + sdrConfig.setUseGzip(meta.getBoolean("usegzip", false)); + result.setSdrServerConfiguration(sdrConfig); + } + JsonValue rotator = meta.get("rotator"); + if (rotator != null) { + result.setRotatorConfiguration(RotatorConfiguration.fromJson(rotator.asObject())); + } + JsonValue antenna = meta.get("antenna"); + if (antenna != null) { + result.setAntennaConfiguration(AntennaConfiguration.fromJson(antenna.asObject())); + } + return result; + } } diff --git a/src/main/java/ru/r2cloud/model/Observation.java b/src/main/java/ru/r2cloud/model/Observation.java index 0f0a66d5..ae79ee60 100644 --- a/src/main/java/ru/r2cloud/model/Observation.java +++ b/src/main/java/ru/r2cloud/model/Observation.java @@ -22,14 +22,9 @@ public class Observation { private GeodeticPoint groundStation; private DataFormat dataFormat; - private SdrType sdrType; private long sampleRate; private long frequency; - private String gain; - private boolean biast; - private long centerBandFrequency; - private int rtlDeviceId; - private int ppm; + private DeviceConfiguration device; // observation status private String channelA; @@ -80,6 +75,14 @@ public ObservationRequest getReq() { return result; } + public DeviceConfiguration getDevice() { + return device; + } + + public void setDevice(DeviceConfiguration device) { + this.device = device; + } + public String getSigmfDataURL() { return sigmfDataURL; } @@ -104,32 +107,6 @@ public void setDataFormat(DataFormat dataFormat) { this.dataFormat = dataFormat; } - public long getCenterBandFrequency() { - return centerBandFrequency; - } - - public void setCenterBandFrequency(long centerBandFrequency) { - this.centerBandFrequency = centerBandFrequency; - } - - @Deprecated - public SdrType getSdrType() { - return sdrType; - } - - @Deprecated - public void setSdrType(SdrType sdrType) { - this.sdrType = sdrType; - } - - public boolean isBiast() { - return biast; - } - - public void setBiast(boolean biast) { - this.biast = biast; - } - public ObservationStatus getStatus() { return status; } @@ -298,30 +275,6 @@ public void setSampleRate(long sampleRate) { this.sampleRate = sampleRate; } - public String getGain() { - return gain; - } - - public void setGain(String gain) { - this.gain = gain; - } - - public int getRtlDeviceId() { - return rtlDeviceId; - } - - public void setRtlDeviceId(int rtlDeviceId) { - this.rtlDeviceId = rtlDeviceId; - } - - public int getPpm() { - return ppm; - } - - public void setPpm(int ppm) { - this.ppm = ppm; - } - public static Observation fromJson(JsonObject meta) { Observation result = new Observation(); result.setId(meta.getString("id", null)); @@ -337,31 +290,8 @@ public static Observation fromJson(JsonObject meta) { if (groundStation != null && groundStation.isObject()) { result.setGroundStation(groundStationFromJson(groundStation.asObject())); } - String sdrTypeStr = meta.getString("sdrType", null); - SdrType sdrType; - if (sdrTypeStr != null) { - sdrType = SdrType.valueOf(sdrTypeStr); - } else { - sdrType = SdrType.RTLSDR; - } - result.setSdrType(sdrType); String dataFormatStr = meta.getString("dataFormat", null); - if (dataFormatStr == null) { - // backward compatible - switch (sdrType) { - case PLUTOSDR: - result.setDataFormat(DataFormat.COMPLEX_SIGNED_SHORT); - break; - case RTLSDR: - result.setDataFormat(DataFormat.COMPLEX_UNSIGNED_BYTE); - break; - case SDRSERVER: - result.setDataFormat(DataFormat.COMPLEX_FLOAT); - break; - default: - result.setDataFormat(DataFormat.UNKNOWN); - } - } else { + if (dataFormatStr != null) { result.setDataFormat(DataFormat.valueOf(dataFormatStr)); } int legacyInputRate = meta.getInt("inputSampleRate", 0); @@ -371,12 +301,6 @@ public static Observation fromJson(JsonObject meta) { result.setSampleRate(meta.getLong("sampleRate", -1)); } result.setFrequency(meta.getLong("actualFrequency", -1)); - result.setGain(meta.getString("gain", null)); - result.setBiast(meta.getBoolean("biast", false)); - result.setCenterBandFrequency(meta.getLong("centerBandFrequency", 0)); - result.setRtlDeviceId(meta.getInt("rtlDeviceId", 0)); - result.setPpm(meta.getInt("ppm", 0)); - result.setChannelA(meta.getString("channelA", null)); result.setChannelB(meta.getString("channelB", null)); JsonValue numberOfDecodedPackets = meta.get("numberOfDecodedPackets"); @@ -389,14 +313,14 @@ public static Observation fromJson(JsonObject meta) { result.setDataURL(meta.getString("data", null)); String statusStr = meta.getString("status", null); if (statusStr != null) { - ObservationStatus status = ObservationStatus.valueOf(statusStr); - if (status.equals(ObservationStatus.NEW)) { - status = ObservationStatus.RECEIVED; - } - result.setStatus(status); + result.setStatus(ObservationStatus.valueOf(statusStr)); } else { result.setStatus(ObservationStatus.UPLOADED); } + JsonValue deviceConfig = meta.get("device"); + if (deviceConfig != null) { + result.setDevice(DeviceConfiguration.fromJson(deviceConfig.asObject())); + } return result; } @@ -413,19 +337,11 @@ public JsonObject toJson(SignedURL signed) { if (getGroundStation() != null) { json.add("groundStation", toJson(getGroundStation())); } - if (sdrType != null) { - json.add("sdrType", sdrType.name()); - } if (dataFormat != null) { json.add("dataFormat", dataFormat.name()); } json.add("sampleRate", getSampleRate()); json.add("actualFrequency", getFrequency()); - json.add("gain", getGain()); - json.add("biast", isBiast()); - json.add("centerBandFrequency", centerBandFrequency); - json.add("rtlDeviceId", getRtlDeviceId()); - json.add("ppm", getPpm()); if (getChannelA() != null) { json.add("channelA", getChannelA()); @@ -448,7 +364,9 @@ public JsonObject toJson(SignedURL signed) { statusToSave = ObservationStatus.UPLOADED; } json.add("status", statusToSave.name()); - + if (device != null) { + json.add("device", device.toJson()); + } return json; } diff --git a/src/main/java/ru/r2cloud/model/ObservationStatus.java b/src/main/java/ru/r2cloud/model/ObservationStatus.java index 256427f4..5f482be3 100644 --- a/src/main/java/ru/r2cloud/model/ObservationStatus.java +++ b/src/main/java/ru/r2cloud/model/ObservationStatus.java @@ -2,9 +2,6 @@ public enum ObservationStatus { - @Deprecated - NEW, - RECEIVING_DATA, RECEIVED, DECODED, UPLOADED, FAILED } diff --git a/src/main/java/ru/r2cloud/model/RotatorConfiguration.java b/src/main/java/ru/r2cloud/model/RotatorConfiguration.java index 04cb19bd..60044eb8 100644 --- a/src/main/java/ru/r2cloud/model/RotatorConfiguration.java +++ b/src/main/java/ru/r2cloud/model/RotatorConfiguration.java @@ -68,4 +68,13 @@ public JsonObject toJson() { return json; } + public static RotatorConfiguration fromJson(JsonObject meta) { + RotatorConfiguration result = new RotatorConfiguration(); + result.setHostname(meta.getString("rotctrldHostname", null)); + result.setPort(meta.getInt("rotctrldPort", 0)); + result.setTolerance(meta.getDouble("rotatorTolerance", 0)); + result.setCycleMillis(meta.getInt("rotatorCycle", 0)); + return result; + } + } diff --git a/src/main/java/ru/r2cloud/model/SdrType.java b/src/main/java/ru/r2cloud/model/SdrType.java deleted file mode 100644 index 289eccd5..00000000 --- a/src/main/java/ru/r2cloud/model/SdrType.java +++ /dev/null @@ -1,13 +0,0 @@ -package ru.r2cloud.model; - -// use separate device types instead -@Deprecated -public enum SdrType { - - RTLSDR, PLUTOSDR, SDRSERVER, - - // be able to load old types from the disk - @Deprecated - R2LORA - -} diff --git a/src/main/java/ru/r2cloud/model/Transmitter.java b/src/main/java/ru/r2cloud/model/Transmitter.java index f2a86ecd..3bd00da8 100644 --- a/src/main/java/ru/r2cloud/model/Transmitter.java +++ b/src/main/java/ru/r2cloud/model/Transmitter.java @@ -529,8 +529,10 @@ public JsonObject toJson() { if (loraLdro != 0) { result.add("loraLdro", loraLdro); } - result.add("loraExplicitHeader", loraExplicitHeader); - result.add("loraCrc", loraCrc); + if (modulation != null && modulation.equals(Modulation.LORA)) { + result.add("loraExplicitHeader", loraExplicitHeader); + result.add("loraCrc", loraCrc); + } if (deviation != 5000) { result.add("deviation", deviation); } diff --git a/src/main/java/ru/r2cloud/tle/CelestrakClient.java b/src/main/java/ru/r2cloud/tle/CelestrakClient.java index 9d4c5e8a..69e57fa3 100644 --- a/src/main/java/ru/r2cloud/tle/CelestrakClient.java +++ b/src/main/java/ru/r2cloud/tle/CelestrakClient.java @@ -13,6 +13,7 @@ import ru.r2cloud.R2Cloud; import ru.r2cloud.model.Tle; +import ru.r2cloud.util.Clock; import ru.r2cloud.util.Configuration; import ru.r2cloud.util.Util; @@ -21,9 +22,11 @@ public class CelestrakClient { private static final Logger LOG = LoggerFactory.getLogger(CelestrakClient.class); private final List urls; + private final Clock clock; private final int timeout; - public CelestrakClient(Configuration props) { + public CelestrakClient(Configuration props, Clock clock) { + this.clock = clock; this.urls = props.getProperties("tle.urls"); this.timeout = props.getInteger("tle.timeout"); } @@ -66,7 +69,7 @@ private Map downloadTle(String location) { } String noradId = line2.substring(2, 2 + 5).trim(); Tle value = new Tle(new String[] { curLine.trim(), line1, line2 }); - value.setLastUpdateTime(System.currentTimeMillis()); + value.setLastUpdateTime(clock.millis()); value.setSource(obj.getHost()); result.put(noradId, value); } diff --git a/src/main/java/ru/r2cloud/web/api/observation/ObservationSigMfMeta.java b/src/main/java/ru/r2cloud/web/api/observation/ObservationSigMfMeta.java index 3b38fc4c..07abcfae 100644 --- a/src/main/java/ru/r2cloud/web/api/observation/ObservationSigMfMeta.java +++ b/src/main/java/ru/r2cloud/web/api/observation/ObservationSigMfMeta.java @@ -14,6 +14,7 @@ import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; +import com.eclipsesource.json.JsonValue; import fi.iki.elonen.NanoHTTPD; import fi.iki.elonen.NanoHTTPD.IHTTPSession; @@ -87,6 +88,11 @@ public ModelAndView doGet(IHTTPSession session) { LOG.info("satellite not found: {} id: {}", satelliteId, id); return new NotFound(); } + Transmitter transmitter = satellite.getById(entity.getTransmitterId()); + if (transmitter == null) { + LOG.info("transmitted not found: {} id: {}", entity.getTransmitterId(), id); + return new NotFound(); + } ModelAndView result = new ModelAndView(); SimpleDateFormat dateFormat = createParser(); @@ -95,7 +101,7 @@ public ModelAndView doGet(IHTTPSession session) { if (ifModifiedSince != null && ifModifiedSince >= entity.getRawPath().lastModified() / 1000) { response = NanoHTTPD.newFixedLengthResponse(fi.iki.elonen.NanoHTTPD.Response.Status.NOT_MODIFIED, "application/octet-stream", null); } else { - response = NanoHTTPD.newFixedLengthResponse(Status.OK, MimeType.JSON.getType(), convertToSigMfMeta(entity, satellite).toString()); + response = NanoHTTPD.newFixedLengthResponse(Status.OK, MimeType.JSON.getType(), convertToSigMfMeta(entity, satellite, transmitter).toString()); // convert to seconds response.addHeader("Cache-Control", "private, max-age=" + ((int) (config.getLong("server.static.signed.validMillis") / 1000))); } @@ -106,7 +112,7 @@ public ModelAndView doGet(IHTTPSession session) { } - private JsonObject convertToSigMfMeta(Observation observation, Satellite satellite) { + private JsonObject convertToSigMfMeta(Observation observation, Satellite satellite, Transmitter transmitter) { JsonObject global = new JsonObject(); global.add("core:author", "r2cloud"); global.add("core:description", "Automatic recording from satellite " + satellite.getName() + " (" + satellite.getId() + ")"); @@ -142,6 +148,30 @@ private JsonObject convertToSigMfMeta(Observation observation, Satellite satelli break; } + JsonObject r2cloudSatellite = new JsonObject(); + r2cloudSatellite.set("noradId", satellite.getId()); + r2cloudSatellite.set("name", satellite.getName()); + JsonObject r2cloudTle = observation.getTle().toJson(); + r2cloudSatellite.set("tle", r2cloudTle); + global.set("r2cloud:satellite", r2cloudSatellite); + JsonObject transmitterJson = transmitter.toJson(); + transmitterJson.remove("status"); + global.set("r2cloud:signal", transmitterJson); + if (observation.getDevice() != null) { + JsonObject deviceConfiguration = observation.getDevice().toJson(); + deviceConfiguration.remove("username"); + deviceConfiguration.remove("password"); + deviceConfiguration.remove("host"); + deviceConfiguration.remove("port"); + JsonValue rotator = deviceConfiguration.get("rotator"); + if (rotator != null) { + JsonObject rotatorObj = rotator.asObject(); + rotatorObj.remove("rotctrldHostname"); + rotatorObj.remove("rotctrldPort"); + } + global.set("r2cloud:device", deviceConfiguration); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); diff --git a/src/test/java/ru/r2cloud/cloud/LeoSatDataClientTest.java b/src/test/java/ru/r2cloud/cloud/LeoSatDataClientTest.java index 9c653f31..a35601f5 100644 --- a/src/test/java/ru/r2cloud/cloud/LeoSatDataClientTest.java +++ b/src/test/java/ru/r2cloud/cloud/LeoSatDataClientTest.java @@ -25,9 +25,10 @@ import ru.r2cloud.MultiHttpResponse; import ru.r2cloud.TestConfiguration; import ru.r2cloud.TestUtil; +import ru.r2cloud.model.DeviceConfiguration; +import ru.r2cloud.model.DeviceType; import ru.r2cloud.model.Observation; import ru.r2cloud.model.Satellite; -import ru.r2cloud.model.SdrType; import ru.r2cloud.model.TransmitterStatus; import ru.r2cloud.util.DefaultClock; @@ -57,14 +58,13 @@ public void testAuthFailure() { server.setObservationMock(new JsonHttpResponse("r2cloudclienttest/auth-failure-response.json", 403)); assertNull(client.saveMeta(createRequest())); } - + @Test(expected = IllegalArgumentException.class) public void testInvalidRequestFailure() { server.setObservationMock(new JsonHttpResponse("r2cloudclienttest/auth-failure-response.json", 400)); client.saveMeta(createRequest()); } - @Test public void testMalformedJsonInResponse() { server.setObservationMock(new JsonHttpResponse("r2cloudclienttest/malformed-response.json", 200)); @@ -139,7 +139,7 @@ public void testLoadSatellites() throws Exception { assertEquals(1, result.size()); assertEquals("53379", result.get(0).getId()); } - + @Test(expected = NotModifiedException.class) public void testLoadSatellitesWithError() throws Exception { config.setProperty("leosatdata.hostname", "http://255.255.255.0"); @@ -148,7 +148,7 @@ public void testLoadSatellitesWithError() throws Exception { client = new LeoSatDataClient(config, new DefaultClock()); client.loadSatellites(0); } - + @Test(expected = NotModifiedException.class) public void testNoUpdateSatellites() throws Exception { server.setSatelliteMock(new JsonHttpResponse("r2cloudclienttest/satellite.json", 304)); @@ -185,7 +185,7 @@ public void testNoUpdateLoadNewLaunch() throws Exception { server.setNewLaunchMock(new JsonHttpResponse("r2cloudclienttest/newlaunch.json", 304)); client.loadNewLaunches(0); } - + @Test(expected = NotModifiedException.class) public void tesLoadNewLaunchWithError() throws Exception { config.setProperty("leosatdata.hostname", "http://255.255.255.0"); @@ -209,7 +209,7 @@ public void testInvalidSatelliteInNewLaunch() throws Exception { List result = client.loadNewLaunches(0); assertEquals(0, result.size()); } - + @Test public void testInvalidSatellite() throws Exception { server.setSatelliteMock(new JsonHttpResponse("r2cloudclienttest/malformed3-response.json", 200)); @@ -285,9 +285,11 @@ private static Observation createRequest() { result.setaURL("1"); result.setDataURL("1"); result.setSpectogramURL("1"); - result.setBiast(true); - result.setSdrType(SdrType.RTLSDR); - result.setGain("12.2"); + DeviceConfiguration device = new DeviceConfiguration(); + device.setGain(12.2f); + device.setBiast(true); + device.setDeviceType(DeviceType.RTLSDR); + result.setDevice(device); return result; } diff --git a/src/test/java/ru/r2cloud/it/ObservationTest.java b/src/test/java/ru/r2cloud/it/ObservationTest.java index 66480d01..33815bbb 100644 --- a/src/test/java/ru/r2cloud/it/ObservationTest.java +++ b/src/test/java/ru/r2cloud/it/ObservationTest.java @@ -2,7 +2,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -15,7 +14,6 @@ import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; -import com.eclipsesource.json.ParseException; import ru.r2cloud.JsonHttpResponse; import ru.r2cloud.LeoSatDataServerMock; @@ -25,8 +23,6 @@ public class ObservationTest extends RegisteredTest { - private final static String METEOR_ID = "40069"; - private RtlSdrDataServer rtlSdrMock; private LeoSatDataServerMock server; @@ -39,20 +35,16 @@ public void testMeteorObservation() throws Exception { server.setSpectogramMock(1L, spectogramHandler); // start observation - List observationIds = client.scheduleStart(METEOR_ID); + String satelliteId = "40069"; + List observationIds = client.scheduleStart(satelliteId); assertEquals(1, observationIds.size()); // get observation and assert - assertObservation(awaitObservation(METEOR_ID, observationIds.get(0), true)); + assertObservation("r2cloudclienttest/40069-1553411549943-request.json", awaitObservation(satelliteId, observationIds.get(0), true)); // wait for r2cloud meta upload and assert metaHandler.awaitRequest(); - JsonObject actual = null; - try { - actual = (JsonObject) Json.parse(metaHandler.getRequest()); - } catch (ParseException e) { - fail("unable to parse request: " + metaHandler.getRequest() + " content-type: " + metaHandler.getRequestContentType() + " " + e.getMessage()); - } - assertObservation(actual); + assertNotNull(metaHandler.getRequest()); + assertObservation("r2cloudclienttest/40069-1553411549943-request.json", Json.parse(metaHandler.getRequest()).asObject()); // wait for spectogram upload and assert spectogramHandler.awaitRequest(); @@ -63,7 +55,6 @@ public void testMeteorObservation() throws Exception { @Test public void testTwoTransmittors() throws Exception { - rtlSdrMock.mockResponse("/data/40069-1553411549943.raw.gz"); JsonHttpResponse metaHandler = new JsonHttpResponse("r2cloudclienttest/save-meta-response.json", 200); server.setObservationMock(metaHandler); JsonHttpResponse spectogramHandler = new JsonHttpResponse("r2cloudclienttest/empty-response.json", 200); @@ -78,19 +69,19 @@ public void testTwoTransmittors() throws Exception { assertEquals(2, observationIds.size()); // get observation and assert - assertObservation(satelliteId, awaitObservation(satelliteId, observationIds.get(0), false)); - assertObservation(satelliteId, awaitObservation(satelliteId, observationIds.get(1), false)); - } - - private static void assertObservation(JsonObject observation) { - assertObservation(METEOR_ID, observation); - assertEquals(288000, observation.getInt("sampleRate", 0)); - assertEquals(137908065, observation.getInt("actualFrequency", 0)); + assertObservation("r2cloudclienttest/46494-0.json", awaitObservation(satelliteId, observationIds.get(0), false)); + assertObservation("r2cloudclienttest/46494-1.json", awaitObservation(satelliteId, observationIds.get(1), false)); } - private static void assertObservation(String satelliteId, JsonObject observation) { + private static void assertObservation(String classPathResource, JsonObject observation) { assertNotNull(observation); - assertEquals(satelliteId, observation.getString("satellite", null)); + observation.remove("start"); + observation.remove("end"); + observation.remove("rawURL"); + observation.remove("sigmfDataURL"); + observation.remove("sigmfMetaURL"); + observation.remove("status"); + TestUtil.assertJson(classPathResource, observation); } static void assertSpectogram(String expectedFilename, byte[] actualBytes) throws IOException { diff --git a/src/test/java/ru/r2cloud/satellite/ObservationDaoTest.java b/src/test/java/ru/r2cloud/satellite/ObservationDaoTest.java index 199df261..89935195 100644 --- a/src/test/java/ru/r2cloud/satellite/ObservationDaoTest.java +++ b/src/test/java/ru/r2cloud/satellite/ObservationDaoTest.java @@ -28,8 +28,13 @@ import ru.r2cloud.ObservationFullComparator; import ru.r2cloud.TestConfiguration; +import ru.r2cloud.model.AntennaConfiguration; +import ru.r2cloud.model.AntennaType; +import ru.r2cloud.model.DeviceConfiguration; import ru.r2cloud.model.Observation; import ru.r2cloud.model.ObservationStatus; +import ru.r2cloud.model.RotatorConfiguration; +import ru.r2cloud.model.SdrServerConfiguration; import ru.r2cloud.model.Tle; public class ObservationDaoTest { @@ -160,6 +165,9 @@ public void testCrud() throws Exception { assertEquals(req.getGroundStation().getLatitude(), actual.getGroundStation().getLatitude(), 0.0); assertEquals(req.getGroundStation().getLongitude(), actual.getGroundStation().getLongitude(), 0.0); assertEquals(ObservationStatus.RECEIVED, actual.getStatus()); + assertEquals(req.getDevice().getGain(), actual.getDevice().getGain(), 0.0f); + assertEquals(req.getDevice().getAntennaConfiguration().getGuaranteedElevation(), actual.getDevice().getAntennaConfiguration().getGuaranteedElevation(), 0.0); + assertEquals(req.getDevice().getRotatorConfiguration().getHostname(), actual.getDevice().getRotatorConfiguration().getHostname()); assertNotNull(dao.saveData(req.getSatelliteId(), req.getId(), createTempFile("data"))); assertNotNull(dao.saveImage(req.getSatelliteId(), req.getId(), createTempFile("image"))); @@ -180,7 +188,6 @@ public void testCrud() throws Exception { full.setChannelB(UUID.randomUUID().toString()); full.setNumberOfDecodedPackets(1L); full.setStatus(ObservationStatus.DECODED); - full.setGain("0.0"); assertTrue(dao.update(full)); actual = dao.find(req.getSatelliteId(), req.getId()); assertEquals(1, actual.getNumberOfDecodedPackets().longValue()); @@ -202,8 +209,7 @@ private static Observation createObservation() { result.setTransmitterId(UUID.randomUUID().toString()); result.setStartTimeMillis(System.currentTimeMillis()); result.setGroundStation(createGroundStation()); - result.setGain("45.0"); - result.setBiast(false); + result.setDevice(createDevice()); return result; } @@ -216,6 +222,50 @@ private static GeodeticPoint createGroundStation() { return result; } + private static DeviceConfiguration createDevice() { + DeviceConfiguration result = new DeviceConfiguration(); + result.setBiast(true); + AntennaConfiguration antenna = new AntennaConfiguration(); + antenna.setType(AntennaType.OMNIDIRECTIONAL); + antenna.setAzimuth(0.0); + antenna.setBeamwidth(0.0); + antenna.setElevation(0.0); + antenna.setGuaranteedElevation(0.0); + antenna.setMinElevation(5.0); + antenna.setGuaranteedElevation(15.0); + result.setAntennaConfiguration(antenna); + result.setCompencateDcOffset(false); + result.setGain(2.0f); + result.setHost("localhost"); + result.setPort(8080); + result.setId(UUID.randomUUID().toString()); + result.setMaximumBatteryVoltage(4.2); + result.setMaximumFrequency(1_700_000_000); + result.setMinimumBatteryVoltage(3.0); + result.setMinimumFrequency(25_000_000); + result.setName(UUID.randomUUID().toString()); + result.setPassword(UUID.randomUUID().toString()); + result.setPpm(2); + RotatorConfiguration rotator = new RotatorConfiguration(); + rotator.setCycleMillis(1000); + rotator.setHostname("localhost"); + rotator.setId(UUID.randomUUID().toString()); + rotator.setPort(8080); + rotator.setTimeout(12000); + rotator.setTolerance(2.0); + result.setRotatorConfiguration(rotator); + result.setRtlDeviceId(1); + SdrServerConfiguration sdrConfig = new SdrServerConfiguration(); + sdrConfig.setBandwidth(1_440_000); + sdrConfig.setBandwidthCrop(48000); + sdrConfig.setBasepath("/tmp"); + sdrConfig.setUseGzip(true); + result.setSdrServerConfiguration(sdrConfig); + result.setTimeout(24000); + result.setUsername(UUID.randomUUID().toString()); + return result; + } + private File createTempFile(String data) throws IOException { File result = new File(tempFolder.getRoot(), UUID.randomUUID().toString() + ".wav"); try (BufferedWriter w = new BufferedWriter(new FileWriter(result))) { diff --git a/src/test/java/ru/r2cloud/satellite/ScheduleTest.java b/src/test/java/ru/r2cloud/satellite/ScheduleTest.java index 0ef05939..0ab076b7 100644 --- a/src/test/java/ru/r2cloud/satellite/ScheduleTest.java +++ b/src/test/java/ru/r2cloud/satellite/ScheduleTest.java @@ -222,12 +222,13 @@ public void start() throws Exception { config.setProperty("satellites.priority.location", new File(tempFolder.getRoot(), "priorities.txt").getAbsolutePath()); config.setProperty("satellites.priority.url", mockServer.getUrl() + "/priorities"); - LeoSatDataClient r2cloudClient = new LeoSatDataClient(config, new FixedClock(current)); - SatnogsClient satnogsClient = new SatnogsClient(config, new FixedClock(current)); + FixedClock clock = new FixedClock(current); + LeoSatDataClient r2cloudClient = new LeoSatDataClient(config, clock); + SatnogsClient satnogsClient = new SatnogsClient(config, clock); satelliteDao = new SatelliteDao(config); TleDao tleDao = new TleDao(config); - PriorityService priorityService = new PriorityService(config, new FixedClock(current)); - houseKeeping = new Housekeeping(config, satelliteDao, new ThreadPoolFactoryImpl(60000), new CelestrakClient(config), tleDao, satnogsClient, r2cloudClient, null, priorityService); + PriorityService priorityService = new PriorityService(config, clock); + houseKeeping = new Housekeeping(config, satelliteDao, new ThreadPoolFactoryImpl(60000), new CelestrakClient(config, clock), tleDao, satnogsClient, r2cloudClient, null, priorityService); PredictOreKit predict = new PredictOreKit(config); factory = new ObservationFactory(predict); schedule = new Schedule(new SequentialTimetable(Device.PARTIAL_TOLERANCE_MILLIS), factory); diff --git a/src/test/java/ru/r2cloud/satellite/UtilizationTest.java b/src/test/java/ru/r2cloud/satellite/UtilizationTest.java index 223986f7..8cf0d46b 100644 --- a/src/test/java/ru/r2cloud/satellite/UtilizationTest.java +++ b/src/test/java/ru/r2cloud/satellite/UtilizationTest.java @@ -51,7 +51,7 @@ public static void main(String[] args) throws Exception { SatelliteDao satelliteDao = new SatelliteDao(config); TleDao tleDao = new TleDao(config); PriorityService priorityService = new PriorityService(config, new DefaultClock()); - Housekeeping houseKeeping = new Housekeeping(config, satelliteDao, new ThreadPoolFactoryImpl(60000), new CelestrakClient(config), tleDao, null, null, null, priorityService); + Housekeeping houseKeeping = new Housekeeping(config, satelliteDao, new ThreadPoolFactoryImpl(60000), new CelestrakClient(config, new DefaultClock()), tleDao, null, null, null, priorityService); houseKeeping.start(); ObservationFactory factory = new ObservationFactory(predict); diff --git a/src/test/java/ru/r2cloud/satellite/decoder/DecoderServiceTest.java b/src/test/java/ru/r2cloud/satellite/decoder/DecoderServiceTest.java index e3d63c78..56573c5a 100644 --- a/src/test/java/ru/r2cloud/satellite/decoder/DecoderServiceTest.java +++ b/src/test/java/ru/r2cloud/satellite/decoder/DecoderServiceTest.java @@ -47,7 +47,6 @@ public void testDeletedBeforeDecodingStarted() throws Exception { TestUtil.copy("data/aausat.raw.gz", wav); Observation observation = TestUtil.loadObservation("data/aausat.raw.gz.json"); observation.setStatus(ObservationStatus.RECEIVED); - observation.setGain("0.0"); dao.insert(observation); wav = dao.update(observation, wav); @@ -65,7 +64,6 @@ public void testScheduleTwice() throws Exception { TestUtil.copy("data/aausat.raw.gz", wav); Observation observation = TestUtil.loadObservation("data/aausat.raw.gz.json"); observation.setStatus(ObservationStatus.RECEIVED); - observation.setGain("0.0"); dao.insert(observation); dao.update(observation, wav); diff --git a/src/test/java/ru/r2cloud/tle/CelestrakClientTest.java b/src/test/java/ru/r2cloud/tle/CelestrakClientTest.java index 52cb9ce2..f018c178 100644 --- a/src/test/java/ru/r2cloud/tle/CelestrakClientTest.java +++ b/src/test/java/ru/r2cloud/tle/CelestrakClientTest.java @@ -15,6 +15,7 @@ import ru.r2cloud.TestConfiguration; import ru.r2cloud.TestUtil; import ru.r2cloud.model.Tle; +import ru.r2cloud.util.DefaultClock; public class CelestrakClientTest { @@ -31,7 +32,7 @@ public void testSuccess() { server.mockResponse(expectedBody); // one slash is important here - CelestrakClient client = new CelestrakClient(config); + CelestrakClient client = new CelestrakClient(config, new DefaultClock()); Map actual = client.downloadTle(); assertEquals(expected.size(), actual.size()); assertEquals(expected, actual); @@ -39,7 +40,7 @@ public void testSuccess() { @Test public void testFailure() { - CelestrakClient client = new CelestrakClient(config); + CelestrakClient client = new CelestrakClient(config, new DefaultClock()); assertEquals(0, client.downloadTle().size()); } diff --git a/src/test/resources/aausat4Observation/1559942730784.json b/src/test/resources/aausat4Observation/1559942730784.json index ce02cfed..d5ddbf90 100644 --- a/src/test/resources/aausat4Observation/1559942730784.json +++ b/src/test/resources/aausat4Observation/1559942730784.json @@ -5,8 +5,7 @@ "sampleRate": 240000, "actualFrequency": 437444309, "satellite": "41460", - "numberOfDecodedPackets": 0, - "sdrType": "RTLSDR", + "numberOfDecodedPackets": 1, "dataFormat": "COMPLEX_UNSIGNED_BYTE", "groundStation": { "lat": 53.72, diff --git a/src/test/resources/aausat4Observation/1559942730784.sigmf-meta.json b/src/test/resources/aausat4Observation/1559942730784.sigmf-meta.json index d3265bc4..f0c7e343 100644 --- a/src/test/resources/aausat4Observation/1559942730784.sigmf-meta.json +++ b/src/test/resources/aausat4Observation/1559942730784.sigmf-meta.json @@ -14,7 +14,28 @@ 0 ] }, - "core:datatype": "cu8" + "core:datatype": "cu8", + "r2cloud:satellite": { + "noradId": "41460", + "name": "AAUSAT 4", + "tle": { + "line1": "AAUSAT 4", + "line2": "1 41460U 16025E 22114.24237288 .00023891 00000+0 95344-3 0 9995", + "line3": "2 41460 98.1778 281.1813 0131168 71.2285 290.3188 15.17490244329716", + "updated": 0 + } + }, + "r2cloud:signal": { + "modulation": "GFSK", + "framing": "CUSTOM", + "beaconClass": "ru.r2cloud.jradio.aausat4.Aausat4Beacon", + "frequency": 437424000, + "bandwidth": 7000, + "baudRates": [ + 2400 + ], + "deviation": 2500 + } }, "captures": [ { diff --git a/src/test/resources/aausat4Observation/expected.json b/src/test/resources/aausat4Observation/expected.json index eadd7786..e87c4158 100644 --- a/src/test/resources/aausat4Observation/expected.json +++ b/src/test/resources/aausat4Observation/expected.json @@ -2,14 +2,23 @@ "id": "1559942730784", "start": 1559942730839, "end": 1559942731040, - "sampleRate": 240000, - "actualFrequency": 437444309, "satellite": "41460", "transmitterId": "41460-0", - "numberOfDecodedPackets": 0, + "tle": { + "line1": "AAUSAT 4", + "line2": "1 41460U 16025E 22114.24237288 .00023891 00000+0 95344-3 0 9995", + "line3": "2 41460 98.1778 281.1813 0131168 71.2285 290.3188 15.17490244329716", + "updated": 0 + }, + "groundStation": { + "lat": 53.72, + "lon": 47.57 + }, + "dataFormat": "COMPLEX_UNSIGNED_BYTE", + "sampleRate": 240000, + "actualFrequency": 437444309, + "numberOfDecodedPackets": 1, "status": "UPLOADED", - "biast": false, - "sdrType": "RTLSDR", "dataEntity": [ { "time": 1562788405439, @@ -63,4 +72,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/test/resources/data b/src/test/resources/data index a209f5f1..5b5a2ba0 160000 --- a/src/test/resources/data +++ b/src/test/resources/data @@ -1 +1 @@ -Subproject commit a209f5f170a431d5785f5e2ff6ca113fd0510f30 +Subproject commit 5b5a2ba0b4d20f68d7a9c86737c1f795039a0e5e diff --git a/src/test/resources/decodertests/LRPTDecoderTest.json b/src/test/resources/decodertests/LRPTDecoderTest.json index 7abb568c..022cb2e8 100644 --- a/src/test/resources/decodertests/LRPTDecoderTest.json +++ b/src/test/resources/decodertests/LRPTDecoderTest.json @@ -6,7 +6,7 @@ "inputSampleRate": 288000, "frequency": 137900000, "actualFrequency": 137898800, - "decoder": "LRPT", + "dataFormat": "COMPLEX_UNSIGNED_BYTE", "satellite": "40069", "bandwidth": 140000, "tle": { diff --git a/src/test/resources/observationSpectrogram/1560007694942.json b/src/test/resources/observationSpectrogram/1560007694942.json index 75e6f6b5..571975da 100644 --- a/src/test/resources/observationSpectrogram/1560007694942.json +++ b/src/test/resources/observationSpectrogram/1560007694942.json @@ -5,5 +5,6 @@ "sampleRate": 288000, "actualFrequency": 137900000, "satellite": "40069", - "numberOfDecodedPackets": 0 + "numberOfDecodedPackets": 0, + "dataFormat" : "COMPLEX_UNSIGNED_BYTE" } diff --git a/src/test/resources/r2cloudclienttest/40069-1553411549943-request.json b/src/test/resources/r2cloudclienttest/40069-1553411549943-request.json new file mode 100644 index 00000000..886a453a --- /dev/null +++ b/src/test/resources/r2cloudclienttest/40069-1553411549943-request.json @@ -0,0 +1,45 @@ +{ + "id": "1559973224691-40069-0", + "satellite": "40069", + "transmitterId": "40069-0", + "tle": { + "line1": "METEOR-M 2", + "line2": "1 40069U 14037A 18286.52491495 -.00000023 00000-0 92613-5 0 9990", + "line3": "2 40069 98.5901 334.4030 0004544 256.4188 103.6490 14.20654800221188", + "updated": 1559942730784, + "source": "localhost" + }, + "groundStation": { + "lat": 56.189, + "lon": 38.174 + }, + "dataFormat": "COMPLEX_UNSIGNED_BYTE", + "sampleRate": 288000, + "actualFrequency": 137908065, + "numberOfDecodedPackets": 0, + "device": { + "id": "rtlsdr.1", + "name": "RTL-SDR 1", + "deviceType": "RTLSDR", + "minimumFrequency": 100000000, + "maximumFrequency": 1700000000, + "gain": 45, + "rtlDeviceId": 1, + "biast": false, + "ppm": 0, + "rotator": { + "rotctrldHostname": "127.0.0.1", + "rotctrldPort": 8004, + "rotatorTolerance": 5, + "rotatorCycle": 1000 + }, + "antenna": { + "antennaType": "DIRECTIONAL", + "azimuth": 0, + "elevation": 0, + "beamwidth": 45, + "minElevation": 8, + "guaranteedElevation": 20 + } + } +} diff --git a/src/test/resources/r2cloudclienttest/46494-0.json b/src/test/resources/r2cloudclienttest/46494-0.json new file mode 100644 index 00000000..ec7fac2f --- /dev/null +++ b/src/test/resources/r2cloudclienttest/46494-0.json @@ -0,0 +1,39 @@ +{ + "id": "1559949406124-46494-0", + "satellite": "46494", + "transmitterId": "46494-0", + "tle": { + "line1": "NORBI", + "line2": "1 46494U 20068J 22099.92133883 .00004000 00000+0 28978-3 0 9992", + "line3": "2 46494 97.7199 41.3905 0017958 151.0787 209.1441 15.04425920 83893", + "updated": 1559942730784, + "source": "localhost" + }, + "groundStation": { + "lat": 56.189, + "lon": 38.174 + }, + "sampleRate": 0, + "actualFrequency": 436703000, + "device": { + "id": "loraatwifi.0", + "name": "LoRa - 127.0.0.1:8005", + "deviceType": "LORAATWIFI", + "minimumFrequency": 144000000, + "maximumFrequency": 500100000, + "host": "127.0.0.1", + "port": 8005, + "gain": 0, + "rtlDeviceId": 0, + "biast": false, + "ppm": 0, + "antenna": { + "antennaType": "OMNIDIRECTIONAL", + "azimuth": 0, + "elevation": 0, + "beamwidth": 45, + "minElevation": 8, + "guaranteedElevation": 20 + } + } +} diff --git a/src/test/resources/r2cloudclienttest/46494-1.json b/src/test/resources/r2cloudclienttest/46494-1.json new file mode 100644 index 00000000..902fa3e3 --- /dev/null +++ b/src/test/resources/r2cloudclienttest/46494-1.json @@ -0,0 +1,39 @@ +{ + "id": "1559949406124-46494-1", + "satellite": "46494", + "transmitterId": "46494-1", + "tle": { + "line1": "NORBI", + "line2": "1 46494U 20068J 22099.92133883 .00004000 00000+0 28978-3 0 9992", + "line3": "2 46494 97.7199 41.3905 0017958 151.0787 209.1441 15.04425920 83893", + "updated": 1559942730784, + "source": "localhost" + }, + "groundStation": { + "lat": 56.189, + "lon": 38.174 + }, + "sampleRate": 0, + "actualFrequency": 436700000, + "device": { + "id": "spyserver.0", + "name": "SpyServer - 127.0.0.1:8008", + "deviceType": "SPYSERVER", + "minimumFrequency": 24000000, + "maximumFrequency": 1700000000, + "host": "127.0.0.1", + "port": 8008, + "gain": 20, + "rtlDeviceId": 0, + "biast": false, + "ppm": 0, + "antenna": { + "antennaType": "OMNIDIRECTIONAL", + "azimuth": 0, + "elevation": 0, + "beamwidth": 45, + "minElevation": 8, + "guaranteedElevation": 20 + } + } +} diff --git a/src/test/resources/r2cloudclienttest/save-meta-request.json b/src/test/resources/r2cloudclienttest/save-meta-request.json index 63a3ae2f..b8c59a97 100644 --- a/src/test/resources/r2cloudclienttest/save-meta-request.json +++ b/src/test/resources/r2cloudclienttest/save-meta-request.json @@ -2,19 +2,22 @@ "id": "1", "start": 1, "end": 1, - "sampleRate": 1, - "actualFrequency": 100, "satellite": "1", "transmitterId": "1", - "gain": "12.2", + "sampleRate": 1, + "actualFrequency": 100, "channelA": "1", "channelB": "1", "numberOfDecodedPackets": 1, "aURL": "1", - "data": "1", "spectogramURL": "1", + "data": "1", "status": "UPLOADED", - "biast": true, - "sdrType": "RTLSDR", - "centerBandFrequency": 0 + "device": { + "deviceType": "RTLSDR", + "gain": 12.2, + "rtlDeviceId": 0, + "biast": true, + "ppm": 0 + } }