unparsed response handling; async for most calls

This commit is contained in:
Ben Menking
2026-06-23 17:20:50 -04:00
parent 985e76c938
commit c5ac643299
3 changed files with 86 additions and 47 deletions
+10 -3
View File
@@ -22,6 +22,7 @@ use Menking\Meshcore\Model\MessageResponse;
use Menking\Meshcore\Model\MessagesWaitingResponse; use Menking\Meshcore\Model\MessagesWaitingResponse;
use Menking\Meshcore\Model\NoMoreMessagesResponse; use Menking\Meshcore\Model\NoMoreMessagesResponse;
use Menking\Meshcore\Model\OkResponse; use Menking\Meshcore\Model\OkResponse;
use Menking\Meshcore\Model\UnparsedResponse;
class CoreParser { class CoreParser {
/** /**
@@ -34,7 +35,6 @@ class CoreParser {
case CoreProtocol::RESP_CODE_OK: case CoreProtocol::RESP_CODE_OK:
return self::parseOk($payload); return self::parseOk($payload);
case CoreProtocol::RESP_CODE_ERR: case CoreProtocol::RESP_CODE_ERR:
//throw new \Exception("Protocol error: " . CoreProtocol::getErrorText(ord($payload[1])));
return self::parseError($payload); return self::parseError($payload);
case CoreProtocol::RESP_CODE_CONTACT: case CoreProtocol::RESP_CODE_CONTACT:
return self::getContact($payload); return self::getContact($payload);
@@ -76,11 +76,18 @@ class CoreParser {
case CoreProtocol::PUSH_CODE_CONTACTS_FULL: case CoreProtocol::PUSH_CODE_CONTACTS_FULL:
return new ContactsFullResponse(); return new ContactsFullResponse();
default: default:
echo "Unparsed response: " . \Menking\Meshcore\Util\Debug::hexDump($payload) . "\n"; return self::unparsed($payload);
return $payload;
} }
} }
protected static function unparsed(string $payload): UnparsedResponse {
$m = new UnparsedResponse();
$m->code = ord($payload[0]);
$m->payload = $payload;
return $m;
}
protected static function parseOk(string $payload): OkResponse { protected static function parseOk(string $payload): OkResponse {
$m = new OkResponse(); $m = new OkResponse();
$m->code = ord($payload[0]); $m->code = ord($payload[0]);
+67 -44
View File
@@ -40,22 +40,24 @@ class Meshcore {
/** /**
* *
* @param string $app_name * @param string $app_name
* @param bool $async
* @return null|AppStartResponse * @return null|AppStartResponse
*/ */
public function appStart(string $app_name): ?AppStartResponse { public function appStart(string $app_name, bool $async = false): ?AppStartResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_APP_START) . chr(0x00) . " " . $app_name); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_APP_START) . chr(0x00) . " " . $app_name);
return $this->waitForResponse([AppStartResponse::class]); return $this->waitForResponse([AppStartResponse::class], $async);
} }
/** /**
* *
* @param bool $async
* @return null|BatteryStorageResponse * @return null|BatteryStorageResponse
*/ */
public function getBatteryAndStorage(): ?BatteryStorageResponse { public function getBatteryAndStorage(bool $async = false): ?BatteryStorageResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_BATT_AND_STORAGE)); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_BATT_AND_STORAGE));
return $this->waitForResponse([BatteryStorageResponse::class]); return $this->waitForResponse([BatteryStorageResponse::class], $async);
} }
/** /**
@@ -68,23 +70,25 @@ class Meshcore {
/** /**
* *
* @param bool $async
* @return null|DeviceInfoResponse * @return null|DeviceInfoResponse
*/ */
public function getDeviceInfo(): ?DeviceInfoResponse { public function getDeviceInfo(bool $async = false): ?DeviceInfoResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_DEVICE_QUERY) . 0x03); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_DEVICE_QUERY) . 0x03);
return $this->waitForResponse([DeviceInfoResponse::class]); return $this->waitForResponse([DeviceInfoResponse::class], $async);
} }
/** /**
* *
* @param int $channel_idx * @param int $channel_idx
* @param bool $async
* @return null|ChannelResponse * @return null|ChannelResponse
*/ */
public function getChannel(int $channel_idx): ?ChannelResponse { public function getChannel(int $channel_idx, bool $async = false): ?ChannelResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_CHANNEL) . chr($channel_idx)); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_CHANNEL) . chr($channel_idx));
return $this->waitForResponse([ChannelResponse::class]); return $this->waitForResponse([ChannelResponse::class], $async);
} }
/** /**
@@ -93,9 +97,10 @@ class Meshcore {
* @param float $bw * @param float $bw
* @param int $sf * @param int $sf
* @param int $cr * @param int $cr
* @param bool $async
* @return null|OkResponse * @return null|OkResponse
*/ */
public function setRadioParams(float $freq, float $bw, int $sf, int $cr): ?OkResponse { public function setRadioParams(float $freq, float $bw, int $sf, int $cr, bool $async = false): ?OkResponse {
$payload = chr(CoreProtocol::CMD_SET_RADIO_PARAMS) $payload = chr(CoreProtocol::CMD_SET_RADIO_PARAMS)
. pack('V', $freq * 1000) . pack('V', $freq * 1000)
. pack('V', $bw * 1000) . pack('V', $bw * 1000)
@@ -105,7 +110,7 @@ class Meshcore {
CoreProtocol::writeFrame($this->serial, $payload); CoreProtocol::writeFrame($this->serial, $payload);
return $this->waitForResponse([OkResponse::class]); return $this->waitForResponse([OkResponse::class], $async);
} }
/** /**
@@ -132,164 +137,182 @@ class Meshcore {
/** /**
* *
* @param bool $async
* @return null|MessageResponse * @return null|MessageResponse
*/ */
public function getNextMessage(): ?MessageResponse { public function getNextMessage(bool $async = false): ?MessageResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SYNC_NEXT_MESSAGE)); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SYNC_NEXT_MESSAGE));
return $this->waitForResponse([MessageResponse::class, NoMoreMessagesResponse::class]); return $this->waitForResponse([MessageResponse::class, NoMoreMessagesResponse::class], $async);
} }
/** /**
* *
* @param string $message * @param string $message
* @param int $channel_idx * @param int $channel_idx
* @param bool $async
* @return null|CodeSentResponse * @return null|CodeSentResponse
*/ */
public function sendChannelTxtMessage(string $message, int $channel_idx): ?CodeSentResponse { public function sendChannelTxtMessage(string $message, int $channel_idx, bool $async = false): ?CodeSentResponse {
$payload = chr(CoreProtocol::CMD_SEND_CHANNEL_TXT_MSG) . chr(0x00) . chr($channel_idx) . pack('V', time()) . "$message\0"; $payload = chr(CoreProtocol::CMD_SEND_CHANNEL_TXT_MSG) . chr(0x00) . chr($channel_idx) . pack('V', time()) . "$message\0";
CoreProtocol::writeFrame($this->serial, $payload); CoreProtocol::writeFrame($this->serial, $payload);
return $this->waitForResponse([CodeSentResponse::class]); return $this->waitForResponse([CodeSentResponse::class], $async);
} }
/** /**
* *
* @param bool $async
* @return null|CurrentTimeResponse * @return null|CurrentTimeResponse
*/ */
public function getDeviceTime(): ?CurrentTimeResponse { public function getDeviceTime(bool $async = false): ?CurrentTimeResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_DEVICE_TIME)); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_DEVICE_TIME));
return $this->waitForResponse([CurrentTimeResponse::class]); return $this->waitForResponse([CurrentTimeResponse::class], $async);
} }
/** /**
* Sets the time on the device to the current system time.
* *
* @param bool $async
* @return null|OkResponse * @return null|OkResponse
*/ */
public function setDeviceTime(): ?OkResponse { public function setDeviceTime(bool $async = false): ?OkResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SET_DEVICE_TIME) . pack('V', time())); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SET_DEVICE_TIME) . pack('V', time()));
return $this->waitForResponse([OkResponse::class]); return $this->waitForResponse([OkResponse::class], $async);
} }
/** /**
* *
* @param string $contact_pk * @param string $contact_pk
* @param string $password * @param string $password
* @param bool $async
* @return null|CodeSentResponse * @return null|CodeSentResponse
*/ */
public function login(string $contact_pk, string $password): ?CodeSentResponse { public function login(string $contact_pk, string $password, bool $async = false): ?CodeSentResponse {
$payload = chr(CoreProtocol::CMD_SEND_LOGIN) . str_pad(base64_decode($contact_pk), CoreProtocol::PUB_KEY_SIZE, "\0") . $password . chr(0x00); $payload = chr(CoreProtocol::CMD_SEND_LOGIN) . str_pad(base64_decode($contact_pk), CoreProtocol::PUB_KEY_SIZE, "\0") . $password . chr(0x00);
CoreProtocol::writeFrame($this->serial, $payload); CoreProtocol::writeFrame($this->serial, $payload);
return $this->waitForResponse([CodeSentResponse::class]); return $this->waitForResponse([CodeSentResponse::class], $async);
} }
/** /**
* *
* @param string $contact_pk * @param string $contact_pk
* @param bool $async
* @return null|OkResponse * @return null|OkResponse
*/ */
public function disconnect(string $contact_pk): ?OkResponse { public function disconnect(string $contact_pk, bool $async = false): ?OkResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_LOGOUT) . base64_decode($contact_pk) . "\0"); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_LOGOUT) . base64_decode($contact_pk) . "\0");
return $this->waitForResponse([OkResponse::class]); return $this->waitForResponse([OkResponse::class], $async);
} }
/** /**
* *
* @param string $contact_pk * @param string $contact_pk
* @param bool $async
* @return null|CodeSentResponse * @return null|CodeSentResponse
*/ */
public function statusRequest(string $contact_pk ): ?CodeSentResponse { public function statusRequest(string $contact_pk, bool $async = false): ?CodeSentResponse {
$payload = chr(CoreProtocol::CMD_SEND_STATUS_REQ) . base64_decode($contact_pk); $payload = chr(CoreProtocol::CMD_SEND_STATUS_REQ) . base64_decode($contact_pk);
CoreProtocol::writeFrame($this->serial, $payload); CoreProtocol::writeFrame($this->serial, $payload);
return $this->waitForResponse([CodeSentResponse::class]); return $this->waitForResponse([CodeSentResponse::class], $async);
} }
/** /**
* *
* @param string $contact_pk * @param string $contact_pk
* @param bool $async
* @return null|OkResponse * @return null|OkResponse
*/ */
public function connected(string $contact_pk): ?OkResponse { public function connected(string $contact_pk, bool $async = false): ?OkResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_HAS_CONNECTION) . base64_decode($contact_pk) . "\0"); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_HAS_CONNECTION) . base64_decode($contact_pk) . "\0");
return $this->waitForResponse([OkResponse::class]); return $this->waitForResponse([OkResponse::class], $async);
} }
/** /**
* *
* @param string $contact_pk * @param string $contact_pk
* @param bool $async
* @return null|OkResponse * @return null|OkResponse
*/ */
public function getTelemetryRequest(string $contact_pk): ?OkResponse { public function getTelemetryRequest(string $contact_pk, bool $async = false): ?OkResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_TELEMETRY_REQ) . base64_decode($contact_pk)); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_TELEMETRY_REQ) . base64_decode($contact_pk));
return $this->waitForResponse([OkResponse::class]); return $this->waitForResponse([OkResponse::class], $async);
} }
/** /**
* *
* @param string $contact_pk * @param string $contact_pk
* @param bool $async
* @return null|OkResponse * @return null|OkResponse
*/ */
public function sendAnonRequest(string $contact_pk): ?OkResponse { public function sendAnonRequest(string $contact_pk, bool $async = false): ?OkResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_ANON_REQ) . base64_decode($contact_pk) . "\0"); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_ANON_REQ) . base64_decode($contact_pk) . "\0");
return $this->waitForResponse([OkResponse::class]); return $this->waitForResponse([OkResponse::class], $async);
} }
/** /**
* *
* @param string $request * @param string $request
* @param bool $async
* @return null|CodeSentResponse * @return null|CodeSentResponse
*/ */
public function sendBinaryRequest(string $request): ?CodeSentResponse { public function sendBinaryRequest(string $request, bool $async = false): ?CodeSentResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_BINARY_REQ) . $request); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_BINARY_REQ) . $request);
return $this->waitForResponse([CodeSentResponse::class]); return $this->waitForResponse([CodeSentResponse::class], $async);
} }
/** /**
* *
* @param string $contact_pk * @param string $contact_pk
* @param bool $async
* @return null|AdvertPathResponse * @return null|AdvertPathResponse
*/ */
public function getAdvertPath(string $contact_pk): ?AdvertPathResponse { public function getAdvertPath(string $contact_pk, bool $async = false): ?AdvertPathResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_ADVERT_PATH) . chr(0x00) . base64_decode($contact_pk)); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_ADVERT_PATH) . chr(0x00) . base64_decode($contact_pk));
return $this->waitForResponse([AdvertPathResponse::class]); return $this->waitForResponse([AdvertPathResponse::class], $async);
} }
/** /**
* *
* @param int $type * @param int $type
* @param bool $async
* @return null|CodeStatusResponse * @return null|CodeStatusResponse
*/ */
public function getStats(int $type): ?CodeStatusResponse { public function getStats(int $type, bool $async = false): ?CodeStatusResponse {
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_STATS) . chr($type)); CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_STATS) . chr($type));
return $this->waitForResponse([CodeStatusResponse::class]); return $this->waitForResponse([CodeStatusResponse::class], $async);
} }
public function setChannel(int $idx, string $name, string $secret): ?OkResponse { /**
echo "secret length: " . strlen($secret) . "\n"; *
* @param int $idx
* @param string $name
* @param string $secret
* @param bool $async
* @return null|OkResponse
*/
public function setChannel(int $idx, string $name, string $secret, bool $async = false): ?OkResponse {
$payload = chr(CoreProtocol::CMD_SET_CHANNEL) $payload = chr(CoreProtocol::CMD_SET_CHANNEL)
. chr($idx) . chr($idx)
. str_pad($name, 32, "\0") . str_pad($name, 32, "\0")
. $secret; . $secret;
echo "payload length: " . strlen($payload) . "\n";
echo \Menking\Meshcore\Util\Debug::hexDump($payload) . "\n";
CoreProtocol::writeFrame($this->serial, $payload); CoreProtocol::writeFrame($this->serial, $payload);
return $this->waitForResponse([OkResponse::class]); return $this->waitForResponse([OkResponse::class], $async);
} }
/** /**
@@ -337,7 +360,7 @@ class Meshcore {
* @return mixed * @return mixed
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
private function waitForResponse(array $classes_expected): mixed { private function waitForResponse(array $classes_expected, bool $async = false): mixed {
foreach($classes_expected as $class) { foreach($classes_expected as $class) {
if( !class_exists($class) ) { if( !class_exists($class) ) {
throw new \InvalidArgumentException("Class $class does not exist"); throw new \InvalidArgumentException("Class $class does not exist");
@@ -354,7 +377,7 @@ class Meshcore {
array_push($this->msg_queue, $obj); array_push($this->msg_queue, $obj);
} }
} }
while((time() - $mark) < 5 && !in_array(get_class($obj), $classes_expected)); while(!$async && (time() - $mark) < 5 && !in_array(get_class($obj), $classes_expected));
return in_array(get_class($obj), $classes_expected)?$obj:null; return in_array(get_class($obj), $classes_expected)?$obj:null;
} }
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace Menking\Meshcore\Model;
class UnparsedResponse extends Response {
public int $code;
public string $payload;
}