msqur/msq.php

301 lines
8.5 KiB
PHP

<?php
require "parse.ini.php";
require "msq.format.php";
//TODO Deprecated
define("LARGE_HOT", 0x1);
define("LARGE_COLD", 0x2);
/**
* @brief Given a signature string, finds and parses the respective INI file.
*
* Returns an array of the config file contents.
* @param $signature The signature string which will be modified into a firmware/version array.
*/
function getConfig(&$signature)
{
//sig is 19 bytes + \0
//"MS3 Format 0262.09 "
//"MS3 Format 0435.14P"
//"MS2Extra comms332m2"
//"MS2Extra comms333e2"
//"MS2Extra Serial321 "
//"MS2Extra Serial310 "
//"MSII Rev 3.83000 "
//Get the signature from the MSQ
$sig = explode(' ', $signature); //, 3); limit 3 buckets
$msVersion = $sig[0];
if ($msVersion == "MS2Extra") $fwVersion = $sig[1];
else $fwVersion = $sig[2];
if (DEBUG) echo "<div class=\"debug\">$msVersion/$fwVersion</div>";
//Parse msVersion
switch ($msVersion)
{
case "MS1":
$msDir = "ms1/";
break;
case "MSII":
$msDir = "ms2/";
break;
case "MS2Extra":
$msDir = "ms2extra/";
break;
case "MS3":
$msDir = "ms3/";
break;
}
//Setup firmware version for matching.
//(explode() already trimmed the string of spaces) -- this isn't true a couple inis
//If there's a decimal, remove any trailing zeros.
if (strrpos($fwVersion, '.') !== FALSE)
$fwVersion = rtrim($fwVersion, '0');
//store all our hardwork for use in the calling function
$signature = array($msVersion, $fwVersion);
$iniFile = "ini/" . $msDir . $fwVersion . ".ini";
$msqMap = parse_ms_ini($iniFile, TRUE);
return $msqMap;
}
/**
* @brief Split and format string of Axis values
* @param $el string
* @returns A array of strings
*/
function msqAxis($el)
{
//Why the fuck does this flag bork here on not on the table data?
//And why don't I have to trim the table data either?
return preg_split("/\s+/", trim($el));//, PREG_SPLIT_NO_EMPTY);
}
/**
* @brief Get an HTML table from data, axes, and some other stuff.
* @param $name Friendly name to use for the table
* @param $data 1D array of data
* @param $x X axis data array
* @param $y Y axis data array
* @param $hot For colorizing on the front end, which values are "high"
* @returns A huge string containing a root <table> element
*/
function msqTable($name, $data, $x, $y, $hot)
{
$output = "";
$rows = count($y);
$cols = count($x);
//echo "ROWS: $rows, $cols";
//var_dump($x, "YYYYYYYYY", $y);
if ($rows * $cols != count($data))
{
$output .= '<div class="error">' . $name . ' column/row count mismatched with data count.</div>';
return;
}
//TODO Probably there's a better way to do this (like on the front end)
if (stripos($name, "VE") === FALSE)
{
$output .= '<table class="msq tablesorter" hot="' . $hot . '">';
}
else
{
$output .= '<table class="msq tablesorter ve" hot="' . $hot . '">';
}
$output .= "<caption>$name</caption>";
$output .= "<thead><tr><th></th>";
for ($c = 0; $c < $cols; $c++)
{
//TODO: This is not triggering tablesorter
$output .= '<th class="{sorter: false}">' . $x[$c] . "</th>";
}
$output .= "</tr></thead>";
for ($r = 0; $r < $rows; $r++)
{
$output .= "<tr><th>" . $y[$r] . "</th>";
for ($c = 0; $c < $cols; $c++)
{
//If just a 2D table we ignore the $rows offset.
if ($cols == 1) $output .= "<td>" . $data[$r] . "</td>";
else $output .= "<td>" . $data[$r * $rows + $c] . "</td>";
}
}
$output .= "</tr>";
$output .= "</table>";
return $output;
}
/**
* @brief Format a constant to HTML
* @param $constant The constant name
* @param $value It's value
* @returns String HTML \<div\>
*/
function msqConstant($constant, $value)
{
//var_export($value);
return '<div class="constant">' . $constant . ': ' . $value . '</div>';
}
/**
* @brief Parse MSQ XML into an array of HTML 'groups'.
* @param $xml SimpleXML
* @param $engine
* @param $metadata
* @returns String HTML
*/
function parseMSQ($xml, &$engine, &$metadata)
{
$html = array();
if (DEBUG) echo '<div class="debug">Parsing MSQ...</div>';
$errorCount = 0; //Keep track of how many things go wrong.
$msq = simplexml_load_string($xml);
if ($msq)
{
$htmlHeader = '<div class="info">';
$htmlHeader .= "<div>Format Version: " . $msq->versionInfo['fileFormat'] . "</div>";
$htmlHeader .= "<div>MS Signature: " . $msq->versionInfo['signature'] . "</div>";
$htmlHeader .= "<div>Tuning SW: " . $msq->bibliography['author'] . "</div>";
$htmlHeader .= "<div>Date: " . $msq->bibliography['writeDate'] . "</div>";
$htmlHeader .= '</div>';
$sig = $msq->versionInfo['signature'];
$msqMap = getConfig($sig);
if ($msqMap == null)
{
$htmlHeader .= "<div class=\"error\">Unable to load the corresponding configuration file for that MSQ. Please file a bug requesting: $sig[0]/$sig[1].ini</div>";
}
$html['header'] = $htmlHeader;
//Calling function will update
$metadata['fileFormat'] = $msq->versionInfo['fileFormat'];
$metadata['signature'] = $sig[1];
$metadata['firmware'] = $sig[0];
$metadata['author'] = $msq->bibliography['author'];
$msqMap = $msqMap['Constants'];
$schema = getSchema();
$engineSchema = getEngineSchema();
foreach ($msqMap as $key => $config)
{
if (DEBUG) echo "<div class=\"debug\">Searching for: $key</div>";
$search = $msq->xpath('//constant[@name="' . $key . '"]');
if ($search === FALSE || count($search) == 0) continue;
$constant = $search[0];
if (DEBUG) echo "<div class=\"debug\">Found constant: $search[0]</div>";
if (array_key_exists($key, $schema))
{
$format = $schema[$key];
if (isset($format['group']))
$group = $format['group'];
else
{
if (DEBUG) echo "<div class=\"debug\">No group set for: $key</div>";
$group = "misc";
}
if (!isset($html[$group])) $html[$group] = "";
if (isset($constant['cols'])) //and >= 1?
{//We have a table
if (isset($format['x']) && isset($format['y']))
{//3D Table
$numCols = (int)$constant['cols'];
$numRows = (int)$constant['rows'];
$x = $msq->xpath('//constant[@name="' . $format['x'] . '"]');
$y = $msq->xpath('//constant[@name="' . $format['y'] . '"]');
if (isset($x[0]) || isset($y[0]))
{
$x = msqAxis($x[0]);
$y = msqAxis($y[0]);
if ((count($x) == $numCols) && (count($y) == $numRows))
{
$tableData = preg_split("/\s+/", trim($constant));//, PREG_SPLIT_NO_EMPTY); //, $limit);
$html[$group] .= msqTable($format['name'], $tableData, $x, $y, $format['hot']);
}
else
{
$html[$group] .= '<div class="error">' . $format['name'] . ' axis count mismatched with data count.</div>';
$html[$group] .= '<div class="debug">' . count($x) . ", " . count($y) . " vs $numCols, $numRows</div>";
$errorCount += 1;
}
}
}
else if (isset($format['y']))
{//2D
$numCols = (int)$constant['cols'];
$numRows = (int)$constant['rows'];
$x = array($format['units']);//msqAxis(trim($constant));
$y = $msq->xpath('//constant[@name="' . $format['y'] . '"]');
if (isset($y[0]))
{
$y = msqAxis($y[0]);
if ((count($x) == $numCols) && (count($y) == $numRows))
{
$tableData = preg_split("/\s+/", trim($constant));//, PREG_SPLIT_NO_EMPTY); //, $limit);
$html[$group] .= msqTable($format['name'], $tableData, $x, $y, $format['hot']);
}
else
{
$html[$group] .= '<div class="error">' . $format['name'] . ' configured axis count mismatched with data count.</div>';
$html[$group] .= '<div class="debug">' . count($x) . ", " . count($y) . " vs $numCols, $numRows</div>";
$errorCount += 1;
}
}
}
}
else
{
$html[$group] .= msqConstant($format['name'], $constant);
//TODO $format['units']
}
}
//if (DEBUG) echo "<div class=\"debug\">Trying $key for engine data</div>";
if (array_key_exists($key, $engineSchema))
{
if (DEBUG) echo "<div class=\"debug\">Found engine data: $key ($constant)</div>";
$engine[$key] = trim($constant, '"');
}
}
}
else
{
$html['header'] = '<div class="error">Unable to parse tune.</div>';
}
return $html;
}
function msqError($e)
{
echo '<div class="error">Error parsing MSQ. ';
echo $e->getMessage();
echo '</div>';
}
?>