linux-list.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.linuxList = linuxList;
  4. const child_process_1 = require("child_process");
  5. const parser_readline_1 = require("@serialport/parser-readline");
  6. // get only serial port names
  7. function checkPathOfDevice(path) {
  8. return /(tty(S|WCH|ACM|USB|AMA|MFD|O|XRUSB)|rfcomm)/.test(path) && path;
  9. }
  10. function propName(name) {
  11. return {
  12. DEVNAME: 'path',
  13. ID_VENDOR_ENC: 'manufacturer',
  14. ID_SERIAL_SHORT: 'serialNumber',
  15. ID_VENDOR_ID: 'vendorId',
  16. ID_MODEL_ID: 'productId',
  17. DEVLINKS: 'pnpId',
  18. /**
  19. * Workaround for systemd defect
  20. * see https://github.com/serialport/bindings-cpp/issues/115
  21. */
  22. ID_USB_VENDOR_ENC: 'manufacturer',
  23. ID_USB_SERIAL_SHORT: 'serialNumber',
  24. ID_USB_VENDOR_ID: 'vendorId',
  25. ID_USB_MODEL_ID: 'productId',
  26. // End of workaround
  27. }[name.toUpperCase()];
  28. }
  29. function decodeHexEscape(str) {
  30. return str.replace(/\\x([a-fA-F0-9]{2})/g, (a, b) => {
  31. return String.fromCharCode(parseInt(b, 16));
  32. });
  33. }
  34. function propVal(name, val) {
  35. if (name === 'pnpId') {
  36. const match = val.match(/\/by-id\/([^\s]+)/);
  37. return (match === null || match === void 0 ? void 0 : match[1]) || undefined;
  38. }
  39. if (name === 'manufacturer') {
  40. return decodeHexEscape(val);
  41. }
  42. if (/^0x/.test(val)) {
  43. return val.substr(2);
  44. }
  45. return val;
  46. }
  47. function linuxList(spawnCmd = child_process_1.spawn) {
  48. const ports = [];
  49. const udevadm = spawnCmd('udevadm', ['info', '-e']);
  50. const lines = udevadm.stdout.pipe(new parser_readline_1.ReadlineParser());
  51. let skipPort = false;
  52. let port = {
  53. path: '',
  54. manufacturer: undefined,
  55. serialNumber: undefined,
  56. pnpId: undefined,
  57. locationId: undefined,
  58. vendorId: undefined,
  59. productId: undefined,
  60. };
  61. lines.on('data', (line) => {
  62. const lineType = line.slice(0, 1);
  63. const data = line.slice(3);
  64. // new port entry
  65. if (lineType === 'P') {
  66. port = {
  67. path: '',
  68. manufacturer: undefined,
  69. serialNumber: undefined,
  70. pnpId: undefined,
  71. locationId: undefined,
  72. vendorId: undefined,
  73. productId: undefined,
  74. };
  75. skipPort = false;
  76. return;
  77. }
  78. if (skipPort) {
  79. return;
  80. }
  81. // Check dev name and save port if it matches flag to skip the rest of the data if not
  82. if (lineType === 'N') {
  83. if (checkPathOfDevice(data)) {
  84. ports.push(port);
  85. }
  86. else {
  87. skipPort = true;
  88. }
  89. return;
  90. }
  91. // parse data about each port
  92. if (lineType === 'E') {
  93. const keyValue = data.match(/^(.+)=(.*)/);
  94. if (!keyValue) {
  95. return;
  96. }
  97. const key = propName(keyValue[1]);
  98. if (!key) {
  99. return;
  100. }
  101. port[key] = propVal(key, keyValue[2]);
  102. }
  103. });
  104. return new Promise((resolve, reject) => {
  105. udevadm.on('close', (code) => {
  106. if (code) {
  107. reject(new Error(`Error listing ports udevadm exited with error code: ${code}`));
  108. }
  109. });
  110. udevadm.on('error', reject);
  111. lines.on('error', reject);
  112. lines.on('finish', () => resolve(ports));
  113. });
  114. }