From afd63f92ad8c8e5dd1dfe687b16cf93d0cffb7b6 Mon Sep 17 00:00:00 2001 From: Kilian Hofmann Date: Wed, 28 Sep 2022 00:38:15 +0200 Subject: [PATCH] Primary Logbook PHP --- TODO.md | 2 + file/include/logbook/logbookEntry.hpp | 2 +- file/php/Logbook.php | 153 ++++++++++++++++++++++++++ file/php/Recording.php | 94 ++++++++-------- file/php/testLogbook.php | 7 ++ file/php/testRecording.php | 5 +- 6 files changed, 217 insertions(+), 46 deletions(-) create mode 100644 file/php/Logbook.php create mode 100644 file/php/testLogbook.php diff --git a/TODO.md b/TODO.md index 92f190c..a4388ae 100644 --- a/TODO.md +++ b/TODO.md @@ -1 +1,3 @@ - Implement Logbook PHP + - Implement aggregates + - Test JSON exports diff --git a/file/include/logbook/logbookEntry.hpp b/file/include/logbook/logbookEntry.hpp index 20d7122..9c5e925 100644 --- a/file/include/logbook/logbookEntry.hpp +++ b/file/include/logbook/logbookEntry.hpp @@ -51,7 +51,7 @@ namespace file * STRLEN | STRING * Times (24) - * CHAR[5] | CHAR[5] | CHAR[5] | CHAR[4] | FLOAT + * CHAR[5] | CHAR[5] | CHAR[5] | CHAR[5] | FLOAT * ----------+---------------+--------------+---------------+------ * OFF BLOCK | TAKEOFF (OUT) | LANDING (ON) | ON BLOCK (IN) | TOTAL diff --git a/file/php/Logbook.php b/file/php/Logbook.php new file mode 100644 index 0000000..164e9e5 --- /dev/null +++ b/file/php/Logbook.php @@ -0,0 +1,153 @@ +directory_name = $directory; + + $this->read(); + } + + /** + * Generates a json representation + * + * @return array json representation + */ + public function to_json(): array + { + $retVal = []; + foreach ($this->flights as $flight) { + try { + $rec = new \germanairlinesva\file\recording\Recording($this->directory_name . + Logbook::recordings_directory . $flight["recordingFilename"] . ".rec"); + $flight["recording"] = $rec->to_json(); + } catch (\InvalidArgumentException) { + } + array_push($retVal, $flight); + } + + return $retVal; + } + + /** + * Generates a string json representation + * + * @return string json string representation + */ + public function to_json_string(): string + { + return json_encode($this->to_json()); + } + + /** + * Reads logbook + */ + private function read() + { + $file = fopen($this->directory_name . Logbook::file_name, "rb"); + flock($file, LOCK_SH); + + $version = $this->read_header($file); + + if ($version == 1) { + while ($this->read_flight_1($file) != false); + } + + flock($file, LOCK_UN); + fclose($file); + } + + /** + * Reads one flight entry + * + * @param resource $file File handle + * + * @return true if not EOF + * @return false if EOF + * + * @throws InvalidArgumentException If file is not a resource + */ + private function read_flight_1($file): bool + { + if (false === is_resource($file)) { + throw new \InvalidArgumentException(sprintf('Argument must be a valid resource type. %s given.', gettype($file))); + } + + $retVal = []; + $data = fread($file, 25); + if ($data) { + $retVal = array_merge($retVal, unpack(Logbook::flight_start_unpack, $data)); + + $size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"]; + $retVal["departureAirport"] = fread($file, $size); + $size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"]; + $retVal["departureGate"] = fread($file, $size); + $size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"]; + $retVal["departureRunway"] = fread($file, $size); + $size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"]; + $retVal["arrivalAirport"] = fread($file, $size); + $size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"]; + $retVal["arrivalGate"] = fread($file, $size); + $size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"]; + $retVal["arrivalRunway"] = fread($file, $size); + + $retVal = array_merge($retVal, unpack(Logbook::flight_middle_unpack, fread($file, 65))); + + $size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"]; + $retVal["recordingFilename"] = fread($file, $size); + + $retVal = array_merge($retVal, unpack(Logbook::flight_end_unpack, fread($file, 5))); + + array_push($this->flights, $retVal); + + return true; + } + return false; + } + + /** + * Reads the file header + * + * @param resource $file File handle + * + * @return string File version + * + * @throws InvalidArgumentException If file is not a resource + * @throws UnexpectedValueException If ident mismatches + */ + private function read_header($file): string + { + if (false === is_resource($file)) { + throw new \InvalidArgumentException(sprintf('Argument must be a valid resource type. %s given.', gettype($file))); + } + + $header = unpack(Logbook::header_unpack, fread($file, 5)); + + if ($header["ident"] !== Logbook::ident) { + throw + new \UnexpectedValueException(sprintf("Ident mismatch. Got %s, expected %s", $header["ident"], Logbook::ident)); + } + + return $header["version"]; + } +} diff --git a/file/php/Recording.php b/file/php/Recording.php index 3b95f44..a25a61b 100644 --- a/file/php/Recording.php +++ b/file/php/Recording.php @@ -1,6 +1,6 @@ file_name = $file; + $this->file_path = $path; + + $this->read(); } /** - * Generates a geoJSON representation + * Generates a json representation * - * @return string geoJSON representation of path + * @return array json representation with path as geoJSON and profile as array */ - public function geoJSON(): string + public function to_json(): array { - $geoJSON = [ + $path = [ "type" => "FeatureCollection", "features" => [ 0 => [ @@ -39,43 +43,51 @@ class Recording ] ] ]; - $segments = $this->read(); - $geoJSON["features"][0]["geometry"]["coordinates"] = array_map(function ($segment) { + $path["features"][0]["geometry"]["coordinates"] = array_map(function ($segment) { return array($segment["longitude"], $segment["latitude"]); - }, $segments); + }, $this->segments); - return json_encode($geoJSON); + $profile = array_map(function ($segment) { + return array("altitude" => $segment["altitude"], "groundspeed" => $segment["groundspeed"]); + }, $this->segments); + + return ["path" => $path, "profile" => $profile]; + } + + /** + * Generates a string json representation + * + * @return string json string representation with path as geoJSON and profile as array + */ + public function to_json_string(): string + { + return json_encode($this->to_json()); } /** * Reads recording - * - * @return array Fields: - * int Segment time (number) as time, - * int Altitude as altitude, - * int Ground speed as groundspeed, - * double Latitude as latitude, - * double Longitude as longitude */ - public function read(): array + private function read() { - $file = fopen($this->file_name, "rb"); - flock($file, LOCK_SH); - - $segments = []; - - $version = $this->read_header($file); - - if ($version == 1) { - while (($segment = $this->read_segment_1($file)) != false) { - array_push($segments, $segment); - } + if (!file_exists($this->file_path)) { + throw new \InvalidArgumentException("File not found"); } - flock($file, LOCK_UN); - fclose($file); + $file = fopen($this->file_path, "rb"); + if ($file) { + flock($file, LOCK_SH); - return $segments; + $version = $this->read_header($file); + + if ($version == 1) { + while ($this->read_segment_1($file) != false); + } + + flock($file, LOCK_UN); + fclose($file); + } else { + throw new \Exception("fopen Error"); + } } /** @@ -83,25 +95,21 @@ class Recording * * @param resource $file File handle * - * @return array if not EOF with fields: - * int Segment time (number) as time, - * int Altitude as altitude, - * int Ground speed as groundspeed, - * double Latitude as latitude, - * double Longitude as longitude - * + * @return true if not EOF * @return false if EOF * * @throws InvalidArgumentException If file is not a resource */ - private function read_segment_1($file): array | false + private function read_segment_1($file): bool { if (false === is_resource($file)) { throw new \InvalidArgumentException(sprintf('Argument must be a valid resource type. %s given.', gettype($file))); } $data = fread($file, 24); if ($data) { - return unpack(Recording::segment_unpack, $data); + array_push($this->segments, unpack(Recording::segment_unpack, $data)); + + return true; } return false; } diff --git a/file/php/testLogbook.php b/file/php/testLogbook.php new file mode 100644 index 0000000..0f16bc5 --- /dev/null +++ b/file/php/testLogbook.php @@ -0,0 +1,7 @@ +to_json_string()); diff --git a/file/php/testRecording.php b/file/php/testRecording.php index 13b0e9d..f644e4c 100644 --- a/file/php/testRecording.php +++ b/file/php/testRecording.php @@ -2,5 +2,6 @@ require "Recording.php"; -$r = new germanairlinesva_recording\Recording("/mnt/f/X-Plane 11/Resources/plugins/GAConnector/recordings/flight.rec"); -print_r($r->geoJSON()); +$r = new \germanairlinesva\file\recording\Recording("/mnt/f/X-Plane 11/Resources/plugins/GAConnector/recordings/flight.rec"); +print_r($r); +print_r($r->to_json_string());