Primary Logbook PHP
This commit is contained in:
parent
174c20bd8f
commit
afd63f92ad
2
TODO.md
2
TODO.md
@ -1 +1,3 @@
|
|||||||
- Implement Logbook PHP
|
- Implement Logbook PHP
|
||||||
|
- Implement aggregates
|
||||||
|
- Test JSON exports
|
||||||
|
|||||||
@ -51,7 +51,7 @@ namespace file
|
|||||||
* STRLEN | STRING
|
* STRLEN | STRING
|
||||||
|
|
||||||
* Times (24)
|
* 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
|
* OFF BLOCK | TAKEOFF (OUT) | LANDING (ON) | ON BLOCK (IN) | TOTAL
|
||||||
|
|
||||||
|
|||||||
153
file/php/Logbook.php
Normal file
153
file/php/Logbook.php
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace germanairlinesva\file\logbook;
|
||||||
|
|
||||||
|
require_once "Recording.php";
|
||||||
|
|
||||||
|
class Logbook
|
||||||
|
{
|
||||||
|
private const file_name = "/logbook.bin";
|
||||||
|
private const recordings_directory = "/recordings/";
|
||||||
|
private const ident = "VGAL";
|
||||||
|
private const header_unpack = "a4ident/Cversion";
|
||||||
|
private const variable_string_size_unpack = "Clength";
|
||||||
|
private const flight_start_unpack = "a10date/a1flightType/a4flightNumber/a4aircraftType/a6aircraftRegistration";
|
||||||
|
private const flight_middle_unpack = "a5offBlockTime/a5outTime/a5inTime/a5onBlockTime/gtotalFlightTime/" .
|
||||||
|
"gtaxiOutFuel/ginFlightFuel/gtaxiInFuel/gtotalFuel/gtaxiOutDistance/ginFlightDistance/gtaxiInDistance/" .
|
||||||
|
"gtotalDistance/gmaxLandingRate/Ctouchdowns/gmaxLandingGees";
|
||||||
|
private const flight_end_unpack = "gpoints/Cflags";
|
||||||
|
|
||||||
|
private string $directory_name = "";
|
||||||
|
|
||||||
|
private array $flights = [];
|
||||||
|
|
||||||
|
public function __construct(string $directory)
|
||||||
|
{
|
||||||
|
$this->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"];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace germanairlinesva_recording;
|
namespace germanairlinesva\file\recording;
|
||||||
|
|
||||||
class Recording
|
class Recording
|
||||||
{
|
{
|
||||||
@ -8,21 +8,25 @@ class Recording
|
|||||||
private const header_unpack = "a4ident/Cversion";
|
private const header_unpack = "a4ident/Cversion";
|
||||||
private const segment_unpack = "Vtime/Saltitude/Sgroundspeed/elatitude/elongitude";
|
private const segment_unpack = "Vtime/Saltitude/Sgroundspeed/elatitude/elongitude";
|
||||||
|
|
||||||
private string $file_name;
|
private string $file_path = "";
|
||||||
|
|
||||||
public function __construct(string $file)
|
private array $segments = [];
|
||||||
|
|
||||||
|
public function __construct(string $path)
|
||||||
{
|
{
|
||||||
$this->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",
|
"type" => "FeatureCollection",
|
||||||
"features" => [
|
"features" => [
|
||||||
0 => [
|
0 => [
|
||||||
@ -39,43 +43,51 @@ class Recording
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
$segments = $this->read();
|
$path["features"][0]["geometry"]["coordinates"] = array_map(function ($segment) {
|
||||||
$geoJSON["features"][0]["geometry"]["coordinates"] = array_map(function ($segment) {
|
|
||||||
return array($segment["longitude"], $segment["latitude"]);
|
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
|
* 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");
|
if (!file_exists($this->file_path)) {
|
||||||
flock($file, LOCK_SH);
|
throw new \InvalidArgumentException("File not found");
|
||||||
|
}
|
||||||
|
|
||||||
$segments = [];
|
$file = fopen($this->file_path, "rb");
|
||||||
|
if ($file) {
|
||||||
|
flock($file, LOCK_SH);
|
||||||
|
|
||||||
$version = $this->read_header($file);
|
$version = $this->read_header($file);
|
||||||
|
|
||||||
if ($version == 1) {
|
if ($version == 1) {
|
||||||
while (($segment = $this->read_segment_1($file)) != false) {
|
while ($this->read_segment_1($file) != false);
|
||||||
array_push($segments, $segment);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
flock($file, LOCK_UN);
|
flock($file, LOCK_UN);
|
||||||
fclose($file);
|
fclose($file);
|
||||||
|
} else {
|
||||||
return $segments;
|
throw new \Exception("fopen Error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,25 +95,21 @@ class Recording
|
|||||||
*
|
*
|
||||||
* @param resource $file File handle
|
* @param resource $file File handle
|
||||||
*
|
*
|
||||||
* @return array if not EOF with fields:
|
* @return true if not EOF
|
||||||
* int Segment time (number) as time,
|
|
||||||
* int Altitude as altitude,
|
|
||||||
* int Ground speed as groundspeed,
|
|
||||||
* double Latitude as latitude,
|
|
||||||
* double Longitude as longitude
|
|
||||||
*
|
|
||||||
* @return false if EOF
|
* @return false if EOF
|
||||||
*
|
*
|
||||||
* @throws InvalidArgumentException If file is not a resource
|
* @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)) {
|
if (false === is_resource($file)) {
|
||||||
throw new \InvalidArgumentException(sprintf('Argument must be a valid resource type. %s given.', gettype($file)));
|
throw new \InvalidArgumentException(sprintf('Argument must be a valid resource type. %s given.', gettype($file)));
|
||||||
}
|
}
|
||||||
$data = fread($file, 24);
|
$data = fread($file, 24);
|
||||||
if ($data) {
|
if ($data) {
|
||||||
return unpack(Recording::segment_unpack, $data);
|
array_push($this->segments, unpack(Recording::segment_unpack, $data));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
7
file/php/testLogbook.php
Normal file
7
file/php/testLogbook.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require "Logbook.php";
|
||||||
|
|
||||||
|
$r = new \germanairlinesva\file\logbook\Logbook("/mnt/f/X-Plane 11/Resources/plugins/GAConnector/");
|
||||||
|
print_r($r);
|
||||||
|
print_r($r->to_json_string());
|
||||||
@ -2,5 +2,6 @@
|
|||||||
|
|
||||||
require "Recording.php";
|
require "Recording.php";
|
||||||
|
|
||||||
$r = new germanairlinesva_recording\Recording("/mnt/f/X-Plane 11/Resources/plugins/GAConnector/recordings/flight.rec");
|
$r = new \germanairlinesva\file\recording\Recording("/mnt/f/X-Plane 11/Resources/plugins/GAConnector/recordings/flight.rec");
|
||||||
print_r($r->geoJSON());
|
print_r($r);
|
||||||
|
print_r($r->to_json_string());
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user