From fb807f42c6e05ea7e430112458d17720499b06d0 Mon Sep 17 00:00:00 2001 From: Ben Menking Date: Thu, 7 May 2026 14:41:36 -0400 Subject: [PATCH] making interfaces consistent --- src/CoreParser.php | 4 +- src/CoreProtocol.php | 2 + src/Meshcore.php | 153 ++++++++++++++++++++++++++----------- tests/getStatusRequest.php | 12 ++- tests/getTelemetry.php | 17 +---- 5 files changed, 127 insertions(+), 61 deletions(-) diff --git a/src/CoreParser.php b/src/CoreParser.php index f00203d..24072d5 100644 --- a/src/CoreParser.php +++ b/src/CoreParser.php @@ -44,6 +44,8 @@ class CoreParser { return self::parseBinaryResponse($payload); case CoreProtocol::RESP_CODE_BATT_AND_STORAGE: return self::parseBatteryAndStorage($payload); + case CoreProtocol::RESP_CODE_NO_MORE_MESSAGES: + return (object)['code'=>CoreProtocol::RESP_CODE_NO_MORE_MESSAGES]; default: return $payload; } @@ -170,7 +172,7 @@ class CoreParser { $data->code = ord($payload[0]); $data->snr = ord($payload[1]) / 4; - $data->rssi = ord($payload[2]); + $data->rssi = (ord($payload[2]) >= 128) ? (ord($payload[2]) - 256): ord($payload[2]); $data->log = base64_encode(substr($payload, 3, strlen($payload))); return $data; diff --git a/src/CoreProtocol.php b/src/CoreProtocol.php index e955a78..babb488 100644 --- a/src/CoreProtocol.php +++ b/src/CoreProtocol.php @@ -179,6 +179,8 @@ class CoreProtocol { const RESP_CODE_SELF_INFO = 5; const RESP_CODE_SENT = 6; const RESP_CODE_CURR_TIME = 9; + const RESP_CODE_NO_MORE_MESSAGES = 10; + const RESP_CODE_EXPORT_CONTACT = 11; const RESP_CODE_BATT_AND_STORAGE = 12; const RESP_CODE_DEVICE_INFO = 13; diff --git a/src/Meshcore.php b/src/Meshcore.php index 343cde2..1ab0a21 100644 --- a/src/Meshcore.php +++ b/src/Meshcore.php @@ -2,11 +2,8 @@ namespace Menking\Meshcore; -use Menking\Meshcore\Model\BatteryStorageResponse; -use Menking\Meshcore\Model\BinaryResponse; -use Menking\Meshcore\Model\DeviceInfoResponse; -use Menking\Meshcore\Model\Response; use RuntimeException; +use Menking\Meshcore\Model\BinaryResponse; class Meshcore { private $serial; @@ -22,6 +19,11 @@ class Meshcore { } } + /** + * + * @return Meshcore + * @throws RuntimeException + */ public static function getInstance(): Meshcore { if( self::$instance == null && Environment::getDevice() == null ) { throw new RuntimeException("Please initialize Meshcore by calling Environment::configure()"); @@ -34,11 +36,11 @@ class Meshcore { } /** - * Initialize the connection. Needed for most commands to succeed. * - * @return true|array{code: int, pub_key: string, type: int, flags: int, out_path_len: int, out_path: string, contact_name: string, last_advert_timestamp: string, gps_lat: int|float, gps_lon: int|float, lastmod: string}|array{code: int, sent_flood: int, pending_login: mixed, est_timeout: mixed}|string + * @param string $app_name + * @return mixed */ - public function appStart(string $app_name) { + public function appStart(string $app_name): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_APP_START) . chr(0x00) . " " . $app_name); $response = CoreProtocol::readFrame($this->serial); @@ -47,9 +49,9 @@ class Meshcore { /** * - * @return BatteryStorageResponse + * @return mixed */ - public function getBatteryAndStorage(): BatteryStorageResponse { + public function getBatteryAndStorage(): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_BATT_AND_STORAGE)); $response = CoreProtocol::readFrame($this->serial); @@ -66,9 +68,9 @@ class Meshcore { /** * - * @return DeviceInfoResponse + * @return mixed */ - public function getDeviceInfo(): DeviceInfoResponse { + public function getDeviceInfo(): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_DEVICE_QUERY) . 0x03); $response = CoreProtocol::readFrame($this->serial); @@ -78,25 +80,24 @@ class Meshcore { /** * * @param int $channel_idx - * @return array{response_code: int, channel_idx: int, channel: string[], channel_secret: string} + * @return mixed */ - public function getChannel(int $channel_idx) { + public function getChannel(int $channel_idx): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_CHANNEL) . chr($channel_idx)); $response = CoreProtocol::readFrame($this->serial); return CoreParser::parseResponse($response); } - public function setRadioParams(float $freq, float $bw, int $sf, int $cr) { - /* - $params = [ - 'freq'=>910.525, - 'bw'=>62.5, - 'sf'=>7, - 'cr'=>5, - ]; - */ - + /** + * + * @param float $freq + * @param float $bw + * @param int $sf + * @param int $cr + * @return mixed + */ + public function setRadioParams(float $freq, float $bw, int $sf, int $cr): mixed { $payload = chr(CoreProtocol::CMD_SET_RADIO_PARAMS) . pack('V', $freq * 1000) . pack('V', $bw * 1000) @@ -110,6 +111,10 @@ class Meshcore { return CoreParser::parseResponse($response); } + /** + * + * @return array + */ public function getContacts(): array { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_CONTACTS)); $response = CoreProtocol::readFrame($this->serial); @@ -128,18 +133,35 @@ class Meshcore { return $contacts; } - public function getNextMessage(?string $tag = null) { + /** + * + * @param null|string $tag + * @return mixed + */ + public function getNextMessage(?string $tag = null): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SYNC_NEXT_MESSAGE)); $response = CoreProtocol::readFrame($this->serial); - if( ord($response[0]) == 0x0a ) { - return []; + $data = CoreParser::parseResponse($response); + + if( $data->code == 10 ) { // RESP_CODE_NO_MORE_MESSAGES + return null; } - return CoreParser::parseResponse($response); + if( !is_null($tag) && $data->tag != $tag ) { + return null; + } + + return $data; } - public function sendChannelTxtMessage(string $message, int $channel_idx): bool { + /** + * + * @param string $message + * @param int $channel_idx + * @return mixed + */ + public function sendChannelTxtMessage(string $message, int $channel_idx): mixed { $payload = chr(CoreProtocol::CMD_SEND_CHANNEL_TXT_MSG) . chr(0x00) . chr($channel_idx) . pack('V', time()) . "$message\0"; CoreProtocol::writeFrame($this->serial, $payload); @@ -148,14 +170,22 @@ class Meshcore { return CoreParser::parseResponse($response); } - public function getDeviceTime(){ + /** + * + * @return mixed + */ + public function getDeviceTime(): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_DEVICE_TIME)); $response = CoreProtocol::readFrame($this->serial); return CoreParser::parseResponse($response); } - public function setDeviceTime() { + /** + * + * @return mixed + */ + public function setDeviceTime(): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SET_DEVICE_TIME) . pack('V', time())); $response = CoreProtocol::readFrame($this->serial); @@ -166,9 +196,9 @@ class Meshcore { * * @param string $contact_pk * @param string $password - * @return true|array{code: int, pub_key: string, type: int, flags: int, out_path_len: int, out_path: string, contact_name: string, last_advert_timestamp: string, gps_lat: int|float, gps_lon: int|float, lastmod: string}|array{code: int, sent_flood: int, pending_login: mixed, est_timeout: mixed}|string + * @return mixed */ - public function login(string $contact_pk, string $password) { + public function login(string $contact_pk, string $password): mixed { $payload = chr(CoreProtocol::CMD_LOGIN) . str_pad(base64_decode($contact_pk), CoreProtocol::PUB_KEY_SIZE, "\0") . $password . chr(0x00); CoreProtocol::writeFrame($this->serial, $payload); @@ -186,17 +216,21 @@ class Meshcore { /** * * @param string $contact_pk - * @return true|array{code: int, pub_key: string, type: int, flags: int, out_path_len: int, out_path: string, contact_name: string, last_advert_timestamp: string, gps_lat: int|float, gps_lon: int|float, lastmod: string}|array{code: int, sent_flood: int, pending_login: mixed, est_timeout: mixed}|string + * @return mixed */ - public function disconnect(string $contact_pk) { + public function disconnect(string $contact_pk): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_LOGOUT) . base64_decode($contact_pk) . "\0"); $response = CoreProtocol::readFrame($this->serial); return CoreParser::parseResponse($response); } - - public function statusRequest(string $contact_pk ) { + /** + * + * @param string $contact_pk + * @return mixed + */ + public function statusRequest(string $contact_pk ): mixed { $payload = chr(CoreProtocol::CMD_SEND_STATUS_REQ) . base64_decode($contact_pk); CoreProtocol::writeFrame($this->serial, $payload); @@ -205,6 +239,11 @@ class Meshcore { return CoreParser::parseResponse($response); } + /** + * + * @param string $contact_pk + * @return bool + */ public function connected(string $contact_pk): bool { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_HAS_CONNECTION) . base64_decode($contact_pk) . "\0"); $response = CoreProtocol::readFrame($this->serial); @@ -212,35 +251,63 @@ class Meshcore { return ord($response[0]) != 0x01; } - public function getTelemetryRequest(string $contact_pk) { + /** + * + * @param string $contact_pk + * @return mixed + */ + public function getTelemetryRequest(string $contact_pk): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_TELEMETRY_REQ) . base64_decode($contact_pk)); $response = CoreProtocol::readFrame($this->serial); return CoreParser::parseResponse($response); } - public function sendAnonRequest(string $contact_pk) { + /** + * + * @param string $contact_pk + * @return mixed + */ + public function sendAnonRequest(string $contact_pk): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_ANON_REQ) . base64_decode($contact_pk) . "\0"); $response = CoreProtocol::readFrame($this->serial); return CoreParser::parseResponse($response); } - public function sendBinaryRequest(string $request): BinaryResponse { + /** + * + * @param string $request + * @return mixed + */ + public function sendBinaryRequest(string $request): mixed { CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_SEND_BINARY_REQ) . $request); $response = CoreProtocol::readFrame($this->serial); return CoreParser::parseResponse($response); } - public function poll(int $timeout_ms = 5000): void { + /** + * + * @param string $tag + * @param int $timeout_ms + * @return mixed + */ + public function pollForMessage(string $tag, int $timeout_ms = 5000): mixed { $mark = time(); do { - $response = CoreProtocol::readFrame($this->serial); - echo json_encode(CoreParser::parseResponse($response)); + $msg = self::getNextMessage(); + + if( $msg instanceof BinaryResponse && $msg->tag == $tag ) { + return $msg; + } + + usleep(500000); } - while( (time() - $mark) < $timeout_ms ) ; //ord($response[0]) == 0x01 && ord($response[1]) == 0xff); + while( (time() - $mark) < $timeout_ms ); + + return false; } } \ No newline at end of file diff --git a/tests/getStatusRequest.php b/tests/getStatusRequest.php index be13ab3..247983d 100644 --- a/tests/getStatusRequest.php +++ b/tests/getStatusRequest.php @@ -24,10 +24,14 @@ $contact = $contacts[$choice - 1]; echo "Using {$contact['contact_name']}\n"; -print_r($mc->login($contact['pub_key'], '')); +print_r($mc->login($contact['pub_key'], readline('Please enter the password: '))); -$ts = $mc->statusRequest($contact['pub_key']); +$result = $mc->statusRequest($contact['pub_key']); +print_r($result); +exit; -print_r($ts); +$msg = $mc->pollForMessage($result->tag); -$mc->poll(); +print_r($msg); + +echo "Complete\n"; diff --git a/tests/getTelemetry.php b/tests/getTelemetry.php index fc2e1bf..48dff52 100644 --- a/tests/getTelemetry.php +++ b/tests/getTelemetry.php @@ -36,20 +36,11 @@ if( !$mc->connected($contact['pub_key']) ) { $req = base64_decode($contact['pub_key']) . chr(CoreProtocol::BINREQ_TELEMETRY); $result = $mc->sendBinaryRequest($req); -echo "Tag: {$result['tag']}\n"; -$timeout = 0; +echo "Tag: {$result->tag}\n"; -while($timeout++ < 6) { - echo "timeout: $timeout\n"; - $resp = $mc->getSyncNextMessage(); - if( !empty($resp) ) { - print_r($resp); - if( $resp['code'] == 0x8c) { - exit; - } - } - sleep(1); -} +$msg = $mc->pollForMessage($result->tag); + +print_r($msg); echo "Complete\n";