diff --git a/README.md b/README.md new file mode 100644 index 0000000..60f3a47 --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +## Command Implementation Status + +| Command | Status | +| ------- | ------ +| CMD_APP_START | Implemented | +| CMD_SEND_TXT_MSG | | +| CMD_SEND_CHANNEL_TXT_MSG | | +| CMD_GET_CONTACTS | Implemented | +| CMD_GET_DEVICE_TIME | Implemented | +| CMD_SET_DEVICE_TIME | Implemented | +| CMD_SEND_SELF_ADVERT | | +| CMD_SET_ADVERT_NAME | | +| CMD_ADD_UPDATE_CONTACT | | +| CMD_SYNC_NEXT_MESSAGE | Implemented | +| CMD_SET_RADIO_PARAMS | Implemented | +| CMD_SET_RADIO_TX_POWER | | +| CMD_RESET_PATH | | +| CMD_SET_ADVERT_LATLON | | +| CMD_REMOVE_CONTACT | | +| CMD_SHARE_CONTACT | | +| CMD_EXPORT_CONTACT | | +| CMD_IMPORT_CONTACT | | +| CMD_REBOOT | Implemented | +| CMD_GET_BATT_AND_STORAGE | Implemented | +| CMD_SET_TUNING_PARAMS | | +| CMD_DEVICE_QEURY | Implemented | +| CMD_EXPORT_PRIVATE_KEY | | +| CMD_IMPORT_PRIVATE_KEY | | +| CMD_SEND_RAW_DATA | | +| CMD_SEND_LOGIN | Implemented | +| CMD_SEND_STATUS_REQ | Implemented | +| CMD_HAS_CONNECTION | Implemented | +| CMD_LOGOUT | Implemented | +| CMD_GET_CONTACT_BY_KEY | | +| CMD_GET_CHANNEL | Implemented | +| CMD_SET_CHANNEL | | +| CMD_SIGN_START | | +| CMD_SIGN_DATA | | +| CMD_SIGN_FINISH | | +| CMD_SEND_TRACE_PATH | | +| CMD_SET_DEVICE_PIN | | +| CMD_SET_OTHER_PARAMS | | +| CMD_SEND_TELEMETRY_REQ | Implemented | +| CMD_GET_CUSTOM_VARS | | +| CMD_SET_CUSTOM_VAR | | +| CMD_GET_ADVERT_PATH | Implemented | +| CMD_GET_TUNING_PARAMS | | +| CMD_SEND_BINARY_REQ | Implemented | +| CMD_FACTORY_RESET | | +| CMD_SEND_PATH_DISCOVERY_REQ | | +| CMD_SET_FLOOD_SCOPE_KEY | | +| CMD_SEND_CONTROL_DATA | | +| CMD_GET_STATS | Implemented | +| CMD_SEND_ANON_REQ | Implemented | +| CMD_SET_AUTOADD_CONFIG | | +| CMD_GET_AUTOADD_CONFIG | | +| CMD_GET_ALLOWED_REPEAT_FREQ | | +| CMD_SET_PATH_HASH_MODE | | +| CMD_SEND_CHANNEL_DATA | | +| CMD_SET_DEFAULT_FLOOD_SCOPE | | +| CMD_GET_DEFAULT_FLOOD_SCOPE | | \ No newline at end of file diff --git a/src/CoreParser.php b/src/CoreParser.php index 24072d5..1ef67d7 100644 --- a/src/CoreParser.php +++ b/src/CoreParser.php @@ -46,7 +46,14 @@ class CoreParser { return self::parseBatteryAndStorage($payload); case CoreProtocol::RESP_CODE_NO_MORE_MESSAGES: return (object)['code'=>CoreProtocol::RESP_CODE_NO_MORE_MESSAGES]; + case CoreProtocol::RESP_CODE_ADVERT_PATH: + return self::parseAdvertPathResponse($payload); + case CoreProtocol::RESP_CODE_STATS: + return self::parseCodeStatusResponse($payload); + case CoreProtocol::RESP_CODE_DEVICE_INFO: + return self::parseDeviceInfoResponse($payload); default: + echo "Unparsed response: " . \Menking\Meshcore\Util\Debug::hexDump($payload) . "\n"; return $payload; } } @@ -284,6 +291,68 @@ class CoreParser { return $info; } + public static function parseAdvertPathResponse(string $payload) { + $info = [ + 'code'=>ord($payload[0]), + 'received_timestamp'=>unpack('V', substr($payload, 1, 4))[1], + 'path_len'=>ord($payload[5]), + 'path'=>substr($payload, 6, ord($payload[5])) + ]; + + return $info; + } + + public static function parseCodeStatusResponse(string $payload) { + $info = [ + 'code'=>ord($payload[0]), + 'type'=>ord($payload[1]), + ]; + + switch($info['type']) { + case CoreProtocol::STATS_TYPE_CORE: + $info['battery_mv'] = unpack('v', substr($payload, 2, 2))[1]; + $info['uptime_secs'] = unpack('V', substr($payload, 4, 4))[1]; + $info['err_flags'] = unpack('v', substr($payload, 8, 2))[1]; + $info['queue_len'] = ord($payload[10]); + break; + case CoreProtocol::STATS_TYPE_RADIO: + $info['noise_floor'] = unpack('v', substr($payload, 2, 2))[1]; + $info['last_rssi'] = (ord($payload[4]) >= 128) ? (ord($payload[4]) - 256): ord($payload[4]); + $info['last_snr'] = ord($payload[5]); + $info['tx_air_secs'] = unpack('V', substr($payload, 6, 4))[1]; + $info['rx_air_secs'] = unpack('V', substr($payload, 10, 4))[1]; + break; + case CoreProtocol::STATS_TYPE_PACKETS: + $info['recv'] = unpack('V', substr($payload, 2, 4))[1]; + $info['sent'] = unpack('V', substr($payload, 6, 4))[1]; + $info['n_sent_flood'] = unpack('V', substr($payload, 10, 4))[1]; + $info['n_sent_direct'] = unpack('V', substr($payload, 14, 4))[1]; + $info['n_recv_flood'] = unpack('V', substr($payload, 18, 4))[1]; + $info['n_recv_direct'] = unpack('V', substr($payload, 22, 4))[1]; + $info['n_rec_errors'] = unpack('V', substr($payload, 26, 4))[1]; + break; + } + + return $info; + } + + public static function parseDeviceInfoResponse(string $payload) { + $info = [ + 'code'=>ord($payload[0]), + 'fw_ver_code'=>ord($payload[1]), + 'max_contacts'=>ord($payload[2]) * 2, + 'max_group_channels'=>ord($payload[3]), + 'ble_pin'=>unpack('V', substr($payload, 4, 4))[1], + 'fw_build_date'=>trim(substr($payload, 8, 12)), + 'manufacturer_name'=>trim(substr($payload, 20, 40)), + 'fw_version'=>trim(substr($payload, 60, 20)), + 'client_repeat'=>ord($payload[80]), + 'path_hash_mode'=>ord($payload[81]) + ]; + + return $info; + } + public static function parseMessage(string $payload) { $data = [ 'code'=>ord($payload[0]), diff --git a/src/CoreProtocol.php b/src/CoreProtocol.php index babb488..c7ea84e 100644 --- a/src/CoreProtocol.php +++ b/src/CoreProtocol.php @@ -157,32 +157,87 @@ class CoreProtocol { const CMD_GET_CONTACTS = 4; const CMD_GET_DEVICE_TIME = 5; const CMD_SET_DEVICE_TIME = 6; + const CMD_SEND_SELF_ADVERT = 7; + const CMD_SET_ADVERT_NAME = 8; + const CMD_ADD_UPDATE_CONTACT = 9; const CMD_SYNC_NEXT_MESSAGE = 10; const CMD_SET_RADIO_PARAMS = 11; + const CMD_SET_RADIO_TX_POWER = 12; + const CMD_RESET_PATH = 13; + const CMD_SET_ADVERT_LATLON = 14; + const CMD_REMOVE_CONTACT = 15; + const CMD_SHARE_CONTACT = 16; + const CMD_EXPORT_CONTACT = 17; + const CMD_IMPORT_CONTACT = 18; const CMD_REBOOT = 19; - const CMD_GET_BATT_AND_STORAGE = 20; + const CMD_GET_BATT_AND_STORAGE = 20; // was CMD_GET_BATTERY_VOLTAGE + const CMD_SET_TUNING_PARAMS = 21; const CMD_DEVICE_QUERY = 22; - const CMD_LOGIN = 26; + const CMD_EXPORT_PRIVATE_KEY = 23; + const CMD_IMPORT_PRIVATE_KEY = 24; + const CMD_SEND_RAW_DATA = 25; + const CMD_SEND_LOGIN = 26; const CMD_SEND_STATUS_REQ = 27; const CMD_HAS_CONNECTION = 28; - const CMD_LOGOUT = 29; + const CMD_LOGOUT = 29; // 'Disconnect' + const CMD_GET_CONTACT_BY_KEY = 30; const CMD_GET_CHANNEL = 31; - const CMD_SEND_TELEMETRY_REQ = 39; - const CMD_SEND_BINARY_REQ = 50; // 0x32 - const CMD_SEND_ANON_REQ = 57; + const CMD_SET_CHANNEL = 32; + const CMD_SIGN_START = 33; + const CMD_SIGN_DATA = 34; + const CMD_SIGN_FINISH = 35; + const CMD_SEND_TRACE_PATH = 36; + const CMD_SET_DEVICE_PIN = 37; + const CMD_SET_OTHER_PARAMS = 38; + const CMD_SEND_TELEMETRY_REQ = 39; // can deprecate this + const CMD_GET_CUSTOM_VARS = 40; + const CMD_SET_CUSTOM_VAR = 41; + const CMD_GET_ADVERT_PATH = 42; + const CMD_GET_TUNING_PARAMS = 43; + const CMD_SEND_BINARY_REQ = 50; + const CMD_FACTORY_RESET = 51; + const CMD_SEND_PATH_DISCOVERY_REQ = 52; + const CMD_SET_FLOOD_SCOPE_KEY = 54; // v8+ + const CMD_SEND_CONTROL_DATA = 55; // v8+ + const CMD_GET_STATS = 56; // v8+, second byte is stats type + const CMD_SEND_ANON_REQ = 57; + const CMD_SET_AUTOADD_CONFIG = 58; + const CMD_GET_AUTOADD_CONFIG = 59; + const CMD_GET_ALLOWED_REPEAT_FREQ = 60; + const CMD_SET_PATH_HASH_MODE = 61; + const CMD_SEND_CHANNEL_DATA = 62; + const CMD_SET_DEFAULT_FLOOD_SCOPE = 63; + const CMD_GET_DEFAULT_FLOOD_SCOPE = 64; const RESP_CODE_OK = 0; const RESP_CODE_ERR = 1; - const RESP_CODE_CONTACTS_START = 2; - const RESP_CODE_CONTACT = 3; - const RESP_CODE_END_OF_CONTACTS = 4; - 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_CONTACTS_START = 2; // first reply to CMD_GET_CONTACTS + const RESP_CODE_CONTACT = 3; // multiple of these (after CMD_GET_CONTACTS) + const RESP_CODE_END_OF_CONTACTS = 4; // last reply to CMD_GET_CONTACTS + const RESP_CODE_SELF_INFO = 5; // reply to CMD_APP_START + const RESP_CODE_SENT = 6; // reply to CMD_SEND_TXT_MSG + const RESP_CODE_CONTACT_MSG_RECV = 7; // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) + const RESP_CODE_CHANNEL_MSG_RECV = 8; // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) + const RESP_CODE_CURR_TIME = 9; // a reply to CMD_GET_DEVICE_TIME + const RESP_CODE_NO_MORE_MESSAGES = 10; // a reply to CMD_SYNC_NEXT_MESSAGE const RESP_CODE_EXPORT_CONTACT = 11; - const RESP_CODE_BATT_AND_STORAGE = 12; - const RESP_CODE_DEVICE_INFO = 13; + const RESP_CODE_BATT_AND_STORAGE = 12; // a reply to a CMD_GET_BATT_AND_STORAGE + const RESP_CODE_DEVICE_INFO = 13; // a reply to CMD_DEVICE_QEURY + const RESP_CODE_PRIVATE_KEY = 14; // a reply to CMD_EXPORT_PRIVATE_KEY + const RESP_CODE_DISABLED = 15; + const RESP_CODE_CONTACT_MSG_RECV_V3 = 16; // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) + const RESP_CODE_CHANNEL_MSG_RECV_V3 = 17; // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) + const RESP_CODE_CHANNEL_INFO = 18; // a reply to CMD_GET_CHANNEL + const RESP_CODE_SIGN_START = 19; + const RESP_CODE_SIGNATURE = 20; + const RESP_CODE_CUSTOM_VARS = 21; + const RESP_CODE_ADVERT_PATH = 22; + const RESP_CODE_TUNING_PARAMS = 23; + const RESP_CODE_STATS = 24; // v8+, second byte is stats type + const RESP_CODE_AUTOADD_CONFIG = 25; + const RESP_ALLOWED_REPEAT_FREQ = 26; + const RESP_CODE_CHANNEL_DATA_RECV = 27; + const RESP_CODE_DEFAULT_FLOOD_SCOPE = 28; const ERR_CODE_UNSUPPORTED_CMD = 1; const ERR_CODE_NOT_FOUND = 2; @@ -231,4 +286,7 @@ class CoreProtocol { const LPP_GYRO = 0x86; const LPP_GPS = 0x88; + const STATS_TYPE_CORE = 0; + const STATS_TYPE_RADIO = 1; + const STATS_TYPE_PACKETS = 2; } diff --git a/src/Meshcore.php b/src/Meshcore.php index 45f6faa..401ea17 100644 --- a/src/Meshcore.php +++ b/src/Meshcore.php @@ -296,6 +296,30 @@ class Meshcore { return CoreParser::parseResponse($response); } + /** + * + * @param string $contact_pk + * @return mixed + */ + public function getAdvertPath(string $contact_pk): mixed { + 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); + } + + /** + * + * @param int $type + * @return mixed + */ + public function getStats(int $type): mixed { + CoreProtocol::writeFrame($this->serial, chr(CoreProtocol::CMD_GET_STATS) . chr($type)); + $response = CoreProtocol::readFrame($this->serial); + + return CoreParser::parseResponse($response); + } + public function readFrame(): mixed { return CoreProtocol::readFrame($this->serial); } diff --git a/tests/getAdvertPath.php b/tests/getAdvertPath.php new file mode 100644 index 0000000..d4eedc9 --- /dev/null +++ b/tests/getAdvertPath.php @@ -0,0 +1,31 @@ +\n"); + +Environment::configure($argv[1]); + +$mc = Meshcore::getInstance(); + +$mc->appStart("send message"); + +$contacts = $mc->getContacts(); + +echo "Found " . count($contacts) . " contacts\n"; + + +$idx = 1; +foreach($contacts as $contact) { + echo "(" . $idx++ . ") {$contact['contact_name']} [" . substr($contact['pub_key'], 0, 6) . "]\n"; +} + +$choice = readline("\nPlease select contact to attempt remote login: "); +$contact = $contacts[$choice - 1]; + +$resp = $mc->getAdvertPath($contact['pub_key']); +print_r($resp); + diff --git a/tests/getStats.php b/tests/getStats.php new file mode 100644 index 0000000..39da062 --- /dev/null +++ b/tests/getStats.php @@ -0,0 +1,26 @@ +\n"); + +Environment::configure($argv[1]); + +$mc = Meshcore::getInstance(); + +$resp = $mc->appStart("battery storage"); + +$resp = $mc->getStats(CoreProtocol::STATS_TYPE_CORE); +print_r($resp); +usleep(250000); + +$resp = $mc->getStats(CoreProtocol::STATS_TYPE_RADIO); +print_r($resp); +usleep(250000); + +$resp = $mc->getStats(CoreProtocol::STATS_TYPE_PACKETS); +print_r($resp); diff --git a/tests/sendMessage.php b/tests/sendMessage.php index 46b2aad..745d8c6 100644 --- a/tests/sendMessage.php +++ b/tests/sendMessage.php @@ -6,12 +6,18 @@ use Menking\Meshcore\Util\Debug; require(__DIR__ . '/../vendor/autoload.php'); -Environment::configure('/dev/ttyUSB0'); +if( !isset($argv[1]) ) die("{$argv[0]} \n"); + +Environment::configure($argv[1]); $mc = Meshcore::getInstance(); $mc->appStart("send message"); $resp = $mc->sendChannelTxtMessage("Ping", 0); // default channel Public on 0 -echo Debug::hexDump($resp); -exit; +echo "Send Channel Txt Message result: " . print_r($resp, true) . "\n"; + +$msgs = $mc->pollForMessage(''); + +print_r($msgs); +