diff --git a/PHP/psat2tlm.php b/PHP/psat2tlm.php
new file mode 100644
index 0000000..0e09668
--- /dev/null
+++ b/PHP/psat2tlm.php
@@ -0,0 +1,187 @@
+
+
+PSAT-2 TLM decoder
+
+
+
+
+
+
+
+= ord('a') && $hi5 <= ord('z')) $value += $hi5 - ord('a');
+ else if ($hi5 >= ord('A') && $hi5 <= ord('F')) $value += $hi5 - ord('A') + 26;
+ $value <<= 5;
+
+ if ($lo5 >= ord('a') && $lo5 <= ord('z')) $value += $lo5 - ord('a');
+ else if ($lo5 >= ord('A') && $lo5 <= ord('F')) $value += $lo5 - ord('A') + 26;
+ return $value;
+}
+
+function parse_tlm_psk($tlm)
+{
+ // PSAT-2 C apng eFaaijtkpokoaB aaaa A aokF eEadjluappjxay
+ echo "---- Current frame ----\n\n";
+
+ $tok = strtok($tlm, " ");
+ echo "Mode: " . $tok . "\n";
+ echo "\n";
+
+ $tok = strtok(" ");
+ $val = (getval(substr($tok, 0, 2)) << 10) + getval(substr($tok, 2, 2));
+ echo "ClockTimer = " . $val . " ticks = " . floor($val*20/3600) . gmdate(":i:s", $val*20) . "\n";
+ echo "\n";
+
+ $tok = strtok(" ");
+ echo "RebootCnt = " . getval(substr($tok, 0, 2)) . " times\n";
+ echo "val_PSK = " . getval(substr($tok, 2, 2)) . " %\n";
+ echo "val_AGC = " . getval(substr($tok, 4, 2)) . "\n";
+ echo "val_Vbat = " . getval(substr($tok, 6, 2)) . " = " . round(getval(substr($tok, 6, 2)) * 3300 * 147 / 47 / 1024 / 1000, 3) . " V\n";
+ echo "val_5V = " . getval(substr($tok, 8, 2)) . " = " . round(getval(substr($tok, 8, 2)) * 2500 * 409 / 100 / 1024 / 1000, 3) . " V\n";
+ echo "val_Ic = " . getval(substr($tok, 10, 2)) . " mA\n";
+ echo "val_T_RX = " . getval(substr($tok, 12, 2)) . " deg C\n";
+ echo "\n";
+
+ $tok = strtok(" ");
+ $val = getval(substr($tok, 0, 2));
+ echo "status.PeriodNr = " . (($val >> 5) & 0x1F) . "\n";
+ echo "status.PeriodsSSTV_RX = " . (($val >> 0) & 0x1F) . "\n";
+ $val = getval(substr($tok, 0, 2));
+ echo "status.PeriodsRX = " . (($val >> 5) & 0x1F) . "\n";
+ echo "status.PeriodsTX = " . (($val >> 0) & 0x1F) . "\n";
+
+ echo "\n\n";
+ echo "---- History frame ----\n\n";
+
+ $tok = strtok(" ");
+ echo "Mode: " . $tok . "\n";
+ echo "\n";
+
+ $tok = strtok(" ");
+ $val = (getval(substr($tok, 0, 2)) << 10) + getval(substr($tok, 2, 2));
+ echo "ClockTimer = " . $val . " ticks = " . floor($val*20/3600) . gmdate(":i:s", $val*20) . "\n";
+ echo "\n";
+
+ $tok = strtok(" ");
+ echo "RebootCnt = " . getval(substr($tok, 0, 2)) . " times\n";
+ echo "val_PSK = " . getval(substr($tok, 2, 2)) . " %\n";
+ echo "val_AGC = " . getval(substr($tok, 4, 2)) . "\n";
+ echo "val_Vbat = " . getval(substr($tok, 6, 2)) . " = " . round(getval(substr($tok, 6, 2)) * 3300 * 147 / 47 / 1024 / 1000, 3) . " V\n";
+ echo "val_5V = " . getval(substr($tok, 8, 2)) . " = " . round(getval(substr($tok, 8, 2)) * 2500 * 409 / 100 / 1024 / 1000, 3) . " V\n";
+ echo "val_Ic = " . getval(substr($tok, 10, 2)) . " mA\n";
+ echo "val_T_RX = " . getval(substr($tok, 12, 2)) . " deg C\n";
+ echo "\n";
+}
+
+
+function legend_psk()
+{
+?>
+
+PSK footnotes
+
+ClockTimer - frame counter, incremented every 20sec, persistent on reboot
+
+
+
+SSTV footnotes
+
+Tick - tick counter, i.e. number of seconds elapsed from reboot, not persistent on reboot
+Plan_Auth - authorization time counter; counts down the number of seconds, for which is the authorization valid (zero if not authorized)
+Plan_*_Count - number of planned events (sum of sstv_live, sstv_save, psk and cw)
+cnt_Boot - count of BOOT
+cnt_*_Error - sum of HARDFAULT, FLASH_INIT_ERROR, FLASH_TIMEOUT, CAM_I2C_ERROR, CAM_DCMI_ERROR, CAM_SIZE_ERROR, JPEG_ERROR and PSK_TIMEOUT
+cnt_AudioStart - count of AUDIO_START (start of SSTV/PSK/CW transmission)
+cnt_CamSnapshot - count of CAM_SNAPSHOT (frame transferred via DCMI)
+cnt_CmdHandled - sum of CMD_HANDLED and PSK_UPLINK (accepted command from APRS or CW)
+cnt_CmdIgnored - count of CMD_IGNORED (rejected data from APRS)
+cnt_AuthError - count of AUTH_ERROR (access to restricted command without autorization)
+
+PSK TLM\n";
+ echo "\n";
+ parse_tlm_psk($tlm2);
+ echo "
";
+ legend_psk();
+ }
+ else if ($tlm2[0] == 'S') {
+ echo "SSTV TLM
\n";
+ echo "\n";
+ parse_tlm_sstv($tlm2);
+ echo "
";
+ legend_sstv();
+ }
+ else {
+ echo "Unknown TLM type";
+ }
+ }
+}
+
+?>
+
+
diff --git a/STM32/Src/comm.c b/STM32/Src/comm.c
index 83693a6..9f4d14a 100644
--- a/STM32/Src/comm.c
+++ b/STM32/Src/comm.c
@@ -164,6 +164,7 @@ void printf_debug(const char *format, ...)
}
+/* FIXME: This is not always called - bug in HAL? Better to test DMAR every time => call comm_init() periodically */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
/* restart DMA ring buffer RX after any error */