better handling of responses
This commit is contained in:
+17
-8
@@ -15,14 +15,13 @@ use Menking\Meshcore\Model\ErrorResponse;
|
|||||||
use Menking\Meshcore\Model\LoginResponse;
|
use Menking\Meshcore\Model\LoginResponse;
|
||||||
use Menking\Meshcore\Model\LogReceiveResponse;
|
use Menking\Meshcore\Model\LogReceiveResponse;
|
||||||
use Menking\Meshcore\Model\BatteryStorageResponse;
|
use Menking\Meshcore\Model\BatteryStorageResponse;
|
||||||
use Menking\Meshcore\Model\CodeStatusTypeCoreResponse;
|
use Menking\Meshcore\Model\CodeStatusResponse;
|
||||||
use Menking\Meshcore\Model\CodeStatusTypePacketResponse;
|
|
||||||
use Menking\Meshcore\Model\CodeStatusTypeRadioResponse;
|
|
||||||
use Menking\Meshcore\Model\ContactResponse;
|
use Menking\Meshcore\Model\ContactResponse;
|
||||||
use Menking\Meshcore\Model\ContactsFullResponse;
|
use Menking\Meshcore\Model\ContactsFullResponse;
|
||||||
use Menking\Meshcore\Model\MessageResponse;
|
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;
|
||||||
|
|
||||||
class CoreParser {
|
class CoreParser {
|
||||||
/**
|
/**
|
||||||
@@ -33,7 +32,7 @@ class CoreParser {
|
|||||||
public static function parseResponse(string $payload): mixed {
|
public static function parseResponse(string $payload): mixed {
|
||||||
switch(ord($payload[0])) {
|
switch(ord($payload[0])) {
|
||||||
case CoreProtocol::RESP_CODE_OK:
|
case CoreProtocol::RESP_CODE_OK:
|
||||||
return true;
|
return self::parseOk($payload);
|
||||||
case CoreProtocol::RESP_CODE_ERR:
|
case CoreProtocol::RESP_CODE_ERR:
|
||||||
//throw new \Exception("Protocol error: " . CoreProtocol::getErrorText(ord($payload[1])));
|
//throw new \Exception("Protocol error: " . CoreProtocol::getErrorText(ord($payload[1])));
|
||||||
return self::parseError($payload);
|
return self::parseError($payload);
|
||||||
@@ -82,6 +81,13 @@ class CoreParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static function parseOk(string $payload): OkResponse {
|
||||||
|
$m = new OkResponse();
|
||||||
|
$m->code = ord($payload[0]);
|
||||||
|
|
||||||
|
return $m;
|
||||||
|
}
|
||||||
|
|
||||||
protected static function parseMsg(string $payload): mixed {
|
protected static function parseMsg(string $payload): mixed {
|
||||||
$m = new MessageResponse();
|
$m = new MessageResponse();
|
||||||
|
|
||||||
@@ -384,21 +390,23 @@ class CoreParser {
|
|||||||
* @param string $payload
|
* @param string $payload
|
||||||
* @return CodeStatusTypeCoreResponse|CodeStatusTypeRadioResponse|CodeStatusTypePacketResponse
|
* @return CodeStatusTypeCoreResponse|CodeStatusTypeRadioResponse|CodeStatusTypePacketResponse
|
||||||
*/
|
*/
|
||||||
protected static function parseCodeStatusResponse(string $payload): CodeStatusTypeCoreResponse|CodeStatusTypeRadioResponse|CodeStatusTypePacketResponse {
|
protected static function parseCodeStatusResponse(string $payload): CodeStatusResponse {
|
||||||
$m = null;
|
$m = null;
|
||||||
|
|
||||||
switch(ord($payload[1])) {
|
switch(ord($payload[1])) {
|
||||||
case CoreProtocol::STATS_TYPE_CORE:
|
case CoreProtocol::STATS_TYPE_CORE:
|
||||||
$m = new CodeStatusTypeCoreResponse();
|
$m = new CodeStatusResponse();
|
||||||
$m->code = ord($payload[0]);
|
$m->code = ord($payload[0]);
|
||||||
|
$m->type = CodeStatusResponse::RESP_CORE;
|
||||||
$m->battery_mv = unpack('v', substr($payload, 2, 2))[1];
|
$m->battery_mv = unpack('v', substr($payload, 2, 2))[1];
|
||||||
$m->uptime_secs = unpack('V', substr($payload, 4, 4))[1];
|
$m->uptime_secs = unpack('V', substr($payload, 4, 4))[1];
|
||||||
$m->err_flags = unpack('v', substr($payload, 8, 2))[1];
|
$m->err_flags = unpack('v', substr($payload, 8, 2))[1];
|
||||||
$m->queue_len = ord($payload[10]);
|
$m->queue_len = ord($payload[10]);
|
||||||
break;
|
break;
|
||||||
case CoreProtocol::STATS_TYPE_RADIO:
|
case CoreProtocol::STATS_TYPE_RADIO:
|
||||||
$m = new CodeStatusTypeRadioResponse();
|
$m = new CodeStatusResponse();
|
||||||
$m->code = ord($payload[0]);
|
$m->code = ord($payload[0]);
|
||||||
|
$m->type = CodeStatusResponse::RESP_RADIO;
|
||||||
$m->noise_floor = unpack('v', substr($payload, 2, 2))[1];
|
$m->noise_floor = unpack('v', substr($payload, 2, 2))[1];
|
||||||
$m->last_rssi = (ord($payload[4]) >= 128) ? (ord($payload[4]) - 256): ord($payload[4]);
|
$m->last_rssi = (ord($payload[4]) >= 128) ? (ord($payload[4]) - 256): ord($payload[4]);
|
||||||
$m->last_snr = ord($payload[5]);;
|
$m->last_snr = ord($payload[5]);;
|
||||||
@@ -406,8 +414,9 @@ class CoreParser {
|
|||||||
$m->rx_air_secs = unpack('V', substr($payload, 10, 4))[1];
|
$m->rx_air_secs = unpack('V', substr($payload, 10, 4))[1];
|
||||||
break;
|
break;
|
||||||
case CoreProtocol::STATS_TYPE_PACKETS:
|
case CoreProtocol::STATS_TYPE_PACKETS:
|
||||||
$m = new CodeStatusTypePacketResponse();
|
$m = new CodeStatusResponse();
|
||||||
$m->code = ord($payload[0]);
|
$m->code = ord($payload[0]);
|
||||||
|
$m->type = CodeStatusResponse::RESP_PACKET;
|
||||||
$m->recv = unpack('V', substr($payload, 2, 4))[1];
|
$m->recv = unpack('V', substr($payload, 2, 4))[1];
|
||||||
$m->sent = unpack('V', substr($payload, 6, 4))[1];
|
$m->sent = unpack('V', substr($payload, 6, 4))[1];
|
||||||
$m->n_sent_flood = unpack('V', substr($payload, 10, 4))[1];
|
$m->n_sent_flood = unpack('V', substr($payload, 10, 4))[1];
|
||||||
|
|||||||
+132
-135
@@ -2,24 +2,28 @@
|
|||||||
|
|
||||||
namespace Menking\Meshcore;
|
namespace Menking\Meshcore;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Menking\Meshcore\Model\AdvertPathResponse;
|
||||||
|
use Menking\Meshcore\Model\AppStartResponse;
|
||||||
|
use Menking\Meshcore\Model\BatteryStorageResponse;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Menking\Meshcore\Model\BinaryResponse;
|
use Menking\Meshcore\Model\BinaryResponse;
|
||||||
|
use Menking\Meshcore\Model\ChannelResponse;
|
||||||
|
use Menking\Meshcore\Model\CodeSentResponse;
|
||||||
|
use Menking\Meshcore\Model\CodeStatusResponse;
|
||||||
|
use Menking\Meshcore\Model\CodeStatusTypeCoreResponse;
|
||||||
|
use Menking\Meshcore\Model\CodeStatusTypePacketResponse;
|
||||||
|
use Menking\Meshcore\Model\CodeStatusTypeRadioResponse;
|
||||||
|
use Menking\Meshcore\Model\CurrentTimeResponse;
|
||||||
|
use Menking\Meshcore\Model\DeviceInfoResponse;
|
||||||
|
use Menking\Meshcore\Model\MessageResponse;
|
||||||
|
use Menking\Meshcore\Model\OkResponse;
|
||||||
|
|
||||||
class Meshcore {
|
class Meshcore {
|
||||||
private $serial;
|
private $serial;
|
||||||
static private ?Meshcore $instance = null;
|
static private ?Meshcore $instance = null;
|
||||||
private $msg_queue = [];
|
private $msg_queue = [];
|
||||||
|
|
||||||
private function __construct() {
|
|
||||||
CoreProtocol::configureTty(Environment::getDevice());
|
|
||||||
|
|
||||||
$this->serial = fopen(Environment::getDevice(), 'r+b');
|
|
||||||
|
|
||||||
if( !$this->serial ) {
|
|
||||||
throw new RuntimeException("Could not open " . Environment::getDevice());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return Meshcore
|
* @return Meshcore
|
||||||
@@ -35,28 +39,26 @@ class Meshcore {
|
|||||||
|
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $app_name
|
* @param string $app_name
|
||||||
* @return mixed
|
* @return null|AppStartResponse
|
||||||
*/
|
*/
|
||||||
public function appStart(string $app_name): mixed {
|
public function appStart(string $app_name): ?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);
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
return $this->waitForResponse(AppStartResponse::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return null|BatteryStorageResponse
|
||||||
*/
|
*/
|
||||||
public function getBatteryAndStorage(): mixed {
|
public function getBatteryAndStorage(): ?BatteryStorageResponse {
|
||||||
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_BATT_AND_STORAGE));
|
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_BATT_AND_STORAGE));
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
return $this->waitForResponse(BatteryStorageResponse::class);
|
||||||
return CoreParser::parseResponse($response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,36 +71,34 @@ class Meshcore {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return null|DeviceInfoResponse
|
||||||
*/
|
*/
|
||||||
public function getDeviceInfo(): mixed {
|
public function getDeviceInfo(): ?DeviceInfoResponse {
|
||||||
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_DEVICE_QUERY) . 0x03);
|
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_DEVICE_QUERY) . 0x03);
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
return $this->waitForResponse(DeviceInfoResponse::class);
|
||||||
return CoreParser::parseResponse($response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param int $channel_idx
|
* @param int $channel_idx
|
||||||
* @return mixed
|
* @return null|ChannelResponse
|
||||||
*/
|
*/
|
||||||
public function getChannel(int $channel_idx): mixed {
|
public function getChannel(int $channel_idx): ?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));
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
return $this->waitForResponse(ChannelResponse::class);
|
||||||
return CoreParser::parseResponse($response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param float $freq
|
* @param float $freq Frequency of radio.
|
||||||
* @param float $bw
|
* @param float $bw
|
||||||
* @param int $sf
|
* @param int $sf
|
||||||
* @param int $cr
|
* @param int $cr
|
||||||
* @return mixed
|
* @return null|OkResponse
|
||||||
*/
|
*/
|
||||||
public function setRadioParams(float $freq, float $bw, int $sf, int $cr): mixed {
|
public function setRadioParams(float $freq, float $bw, int $sf, int $cr): ?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)
|
||||||
@@ -107,9 +107,8 @@ class Meshcore {
|
|||||||
;
|
;
|
||||||
|
|
||||||
CoreProtocol::writeFrame($this->serial, $payload);
|
CoreProtocol::writeFrame($this->serial, $payload);
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
return $this->waitForResponse(OkResponse::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,181 +135,152 @@ class Meshcore {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return null|MessageResponse
|
||||||
*/
|
*/
|
||||||
public function getNextMessage(): mixed {
|
public function getNextMessage(): ?MessageResponse {
|
||||||
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SYNC_NEXT_MESSAGE));
|
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SYNC_NEXT_MESSAGE));
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
return $this->waitForResponse(MessageResponse::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $message
|
* @param string $message
|
||||||
* @param int $channel_idx
|
* @param int $channel_idx
|
||||||
* @return mixed
|
* @return null|CodeSentResponse
|
||||||
*/
|
*/
|
||||||
public function sendChannelTxtMessage(string $message, int $channel_idx): mixed {
|
public function sendChannelTxtMessage(string $message, int $channel_idx): ?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);
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
return $this->waitForResponse(CodeSentResponse::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return null|CurrentTimeResponse
|
||||||
*/
|
*/
|
||||||
public function getDeviceTime(): mixed {
|
public function getDeviceTime(): ?CurrentTimeResponse {
|
||||||
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_DEVICE_TIME));
|
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_DEVICE_TIME));
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
return $this->waitForResponse(CurrentTimeResponse::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return null|OkResponse
|
||||||
*/
|
*/
|
||||||
public function setDeviceTime(): mixed {
|
public function setDeviceTime(): ?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()));
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
return $this->waitForResponse(OkResponse::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $contact_pk
|
* @param string $contact_pk
|
||||||
* @param string $password
|
* @param string $password
|
||||||
* @return mixed
|
* @return null|CodeSentResponse
|
||||||
*/
|
*/
|
||||||
public function login(string $contact_pk, string $password): mixed {
|
public function login(string $contact_pk, string $password): ?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);
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
do {
|
return $this->waitForResponse(CodeSentResponse::class);
|
||||||
usleep(250000);
|
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
}
|
|
||||||
while(ord($response[0]) != 0x85 && ord($response[0]) != 0x86 && ord($response[0]) != 0x01);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $contact_pk
|
* @param string $contact_pk
|
||||||
* @return mixed
|
* @return null|OkResponse
|
||||||
*/
|
*/
|
||||||
public function disconnect(string $contact_pk): mixed {
|
public function disconnect(string $contact_pk): ?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");
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
return $this->waitForResponse(OkResponse::class);
|
||||||
return CoreParser::parseResponse($response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $contact_pk
|
* @param string $contact_pk
|
||||||
* @return mixed
|
* @return null|CodeSentResponse
|
||||||
*/
|
*/
|
||||||
public function statusRequest(string $contact_pk ): mixed {
|
public function statusRequest(string $contact_pk ): ?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);
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
return $this->waitForResponse(CodeSentResponse::class);
|
||||||
return CoreParser::parseResponse($response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $contact_pk
|
* @param string $contact_pk
|
||||||
* @return bool
|
* @return null|OkResponse
|
||||||
*/
|
*/
|
||||||
public function connected(string $contact_pk): bool {
|
public function connected(string $contact_pk): ?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");
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
return $this->waitForResponse(OkResponse::class);
|
||||||
return ord($response[0]) != 0x01;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $contact_pk
|
* @param string $contact_pk
|
||||||
* @return mixed
|
* @return null|OkResponse
|
||||||
*/
|
*/
|
||||||
public function getTelemetryRequest(string $contact_pk): mixed {
|
public function getTelemetryRequest(string $contact_pk): ?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));
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
return $this->waitForResponse(OkResponse::class);
|
||||||
return CoreParser::parseResponse($response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $contact_pk
|
* @param string $contact_pk
|
||||||
* @return mixed
|
* @return null|OkResponse
|
||||||
*/
|
*/
|
||||||
public function sendAnonRequest(string $contact_pk): mixed {
|
public function sendAnonRequest(string $contact_pk): ?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");
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
return $this->waitForResponse(OkResponse::class);
|
||||||
return CoreParser::parseResponse($response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $request
|
* @param string $request
|
||||||
* @return mixed
|
* @return null|CodeSentResponse
|
||||||
*/
|
*/
|
||||||
public function sendBinaryRequest(string $request): mixed {
|
public function sendBinaryRequest(string $request): ?CodeSentResponse {
|
||||||
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_BINARY_REQ) . $request);
|
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_BINARY_REQ) . $request);
|
||||||
|
|
||||||
do {
|
return $this->waitForResponse(CodeSentResponse::class);
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
}
|
|
||||||
while(
|
|
||||||
ord($response) != CoreProtocol::RESP_CODE_SENT &&
|
|
||||||
ord($response) != CoreProtocol::ERR_CODE_NOT_FOUND &&
|
|
||||||
ord($response) != CoreProtocol::ERR_CODE_NOT_FOUND
|
|
||||||
);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $contact_pk
|
* @param string $contact_pk
|
||||||
* @return mixed
|
* @return null|AdvertPathResponse
|
||||||
*/
|
*/
|
||||||
public function getAdvertPath(string $contact_pk): mixed {
|
public function getAdvertPath(string $contact_pk): ?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));
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
return $this->waitForResponse(AdvertPathResponse::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param int $type
|
* @param int $type
|
||||||
* @return mixed
|
* @return null|CodeStatusResponse
|
||||||
*/
|
*/
|
||||||
public function getStats(int $type): mixed {
|
public function getStats(int $type): ?CodeStatusResponse {
|
||||||
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_STATS) . chr($type));
|
CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_STATS) . chr($type));
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
return $this->waitForResponse(CodeStatusResponse::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setChannel(int $idx, string $name, string $secret): mixed {
|
public function setChannel(int $idx, string $name, string $secret): ?OkResponse {
|
||||||
echo "secret length: " . strlen($secret) . "\n";
|
echo "secret length: " . strlen($secret) . "\n";
|
||||||
$payload = chr(CoreProtocol::CMD_SET_CHANNEL)
|
$payload = chr(CoreProtocol::CMD_SET_CHANNEL)
|
||||||
. chr($idx)
|
. chr($idx)
|
||||||
@@ -321,45 +291,72 @@ class Meshcore {
|
|||||||
echo \Menking\Meshcore\Util\Debug::hexDump($payload) . "\n";
|
echo \Menking\Meshcore\Util\Debug::hexDump($payload) . "\n";
|
||||||
|
|
||||||
CoreProtocol::writeFrame($this->serial, $payload);
|
CoreProtocol::writeFrame($this->serial, $payload);
|
||||||
$response = CoreProtocol::readFrame($this->serial);
|
|
||||||
|
|
||||||
return CoreParser::parseResponse($response);
|
return $this->waitForResponse(OkResponse::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasQueuedMessages(): bool {
|
||||||
|
return count($this->msg_queue) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function popMessage(): mixed {
|
||||||
|
return array_pop($this->msg_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
public function readFrame(): mixed {
|
public function readFrame(): mixed {
|
||||||
return CoreProtocol::readFrame($this->serial);
|
return CoreProtocol::readFrame($this->serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Poll for messages, returning after timeout or if a message with <tag> is received. This function can
|
|
||||||
* return zero to many results in an array. Not all messages may match <tag>.
|
|
||||||
*
|
*
|
||||||
* @param string $tag
|
* @return void
|
||||||
* @param int $timeout_ms defaults to 5 seconds
|
* @throws RuntimeException
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function pollForMessage(string $tag, int $timeout_ms = 5000): array {
|
private function __construct() {
|
||||||
$mark = time();
|
CoreProtocol::configureTty(Environment::getDevice());
|
||||||
$messages = [];
|
|
||||||
|
|
||||||
do {
|
$this->serial = fopen(Environment::getDevice(), 'r+b');
|
||||||
$msg = self::getNextMessage();
|
|
||||||
|
|
||||||
if( $msg->code != 10) {
|
if( !$this->serial ) {
|
||||||
$messages[] = $msg;
|
throw new RuntimeException("Could not open " . Environment::getDevice());
|
||||||
|
|
||||||
if( $msg instanceof BinaryResponse && $msg->tag == $tag ) {
|
|
||||||
return $messages;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
usleep(250000);
|
|
||||||
|
|
||||||
$response = $this->readFrame();
|
|
||||||
}
|
}
|
||||||
while( ((time() - $mark) * 1000) < $timeout_ms );
|
|
||||||
|
|
||||||
return $messages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param string $class_expected
|
||||||
|
* @return mixed
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
private function waitForResponse(string $class_expected): mixed {
|
||||||
|
if( !class_exists($class_expected) ) {
|
||||||
|
throw new InvalidArgumentException("Class $class_expected does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
$mark = time();
|
||||||
|
|
||||||
|
do {
|
||||||
|
$response = CoreProtocol::readFrame($this->serial);
|
||||||
|
$obj = CoreParser::parseResponse($response);
|
||||||
|
|
||||||
|
if( !is_a($obj, $class_expected) ) {
|
||||||
|
array_push($this->msg_queue, $obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while((time() - $mark) < 5000 || is_a($obj, $class_expected));
|
||||||
|
|
||||||
|
return (is_a($obj, $class_expected))?$obj:null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Menking\Meshcore\Model;
|
||||||
|
|
||||||
|
class CodeStatusResponse extends Response {
|
||||||
|
public int $code;
|
||||||
|
public int $type;
|
||||||
|
|
||||||
|
// for Core
|
||||||
|
public int $battery_mv;
|
||||||
|
public int $uptime_secs;
|
||||||
|
public int $err_flags;
|
||||||
|
public int $queue_len;
|
||||||
|
|
||||||
|
// for Radio
|
||||||
|
public int $noise_floor;
|
||||||
|
public int $last_rssi;
|
||||||
|
public int $last_snr;
|
||||||
|
public int $tx_air_secs;
|
||||||
|
public int $rx_air_secs;
|
||||||
|
|
||||||
|
// for Packets
|
||||||
|
public int $recv;
|
||||||
|
public int $sent;
|
||||||
|
public int $n_sent_flood;
|
||||||
|
public int $n_sent_direct;
|
||||||
|
public int $n_recv_flood;
|
||||||
|
public int $n_recv_direct;
|
||||||
|
public int $n_recv_errors;
|
||||||
|
|
||||||
|
const RESP_CORE = 1;
|
||||||
|
const RESP_PACKET = 2;
|
||||||
|
const RESP_RADIO = 3;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Menking\Meshcore\Model;
|
|
||||||
|
|
||||||
class CodeStatusTypeCoreResponse extends Response {
|
|
||||||
public int $code;
|
|
||||||
public int $battery_mv;
|
|
||||||
public int $uptime_secs;
|
|
||||||
public int $err_flags;
|
|
||||||
public int $queue_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Menking\Meshcore\Model;
|
|
||||||
|
|
||||||
class CodeStatusTypePacketResponse extends Response {
|
|
||||||
public int $code;
|
|
||||||
public int $recv;
|
|
||||||
public int $sent;
|
|
||||||
public int $n_sent_flood;
|
|
||||||
public int $n_sent_direct;
|
|
||||||
public int $n_recv_flood;
|
|
||||||
public int $n_recv_direct;
|
|
||||||
public int $n_recv_errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Menking\Meshcore\Model;
|
|
||||||
|
|
||||||
class CodeStatusTypeRadioResponse extends Response {
|
|
||||||
public int $code;
|
|
||||||
public int $noise_floor;
|
|
||||||
public int $last_rssi;
|
|
||||||
public int $last_snr;
|
|
||||||
public int $tx_air_secs;
|
|
||||||
public int $rx_air_secs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Menking\Meshcore\Model;
|
||||||
|
|
||||||
|
class OkResponse extends Response {
|
||||||
|
public int $code;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user