led-matrix-controllers 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/led-matrix-controllers.browser.mjs +1 -1
- package/dist/led-matrix-controllers.browser.mjs.map +1 -1
- package/package.json +1 -1
- package/src/usb-hid/HIDControllerFactory.js +9 -2
- package/src/usb-hid/firmware/sparkle/SparkleController.js +14 -8
- package/src/usb-serial/SerialControllerFactory.js +9 -9
- package/src/usb-serial/firmware/framework-official/DefaultController.js +33 -27
- package/src/usb-serial/firmware/sigroot/SigrootController.js +29 -23
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const t=9,e=34,r=12972,a=[50,172],i=32,n=[0,32],s=Object.freeze([0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,9,9,9,10,10,10,11,11,11,12,12,12,13,13,14,14,14,15,15,16,16,17,17,17,18,18,19,19,20,20,21,22,22,23,23,24,24,25,26,26,27,27,28,29,29,30,31,32,32,33,34,34,35,36,37,38,38,39,40,41,42,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,66,67,68,69,70,71,73,74,75,76,78,79,80,82,83,84,86,87,88,90,91,93,94,96,97,99,100,102,103,105,106,108,110,111,113,115,116,118,120,121,123,125,127,128,130,132,134,136,138,140,141,143,145,147,149,151,153,155,157,159,161,164,166,168,170,172,174,177,179,181,183,186,188,190,193,195,197,200,202,205,207,210,212,215,217,220,222,225,228,230,233,236,238,241,244,247,249,252,255]),o=[],c=[{vendorId:12972,productId:32}];class l extends Error{constructor(){super("User cancelled device selection."),this.name=this.constructor.name,this.date=new Date}}class d{constructor(t){this.#t=t}async send(t,e){if(e.length<t.bytes)e=function(t,e,r=0){return t.concat(new Array(e-t.length).fill(r))}(e,t.bytes);else if(e.length>t.bytes)throw new Error("Unable to send report: too many bytes");const r=new Uint8Array(e).buffer;t.feature?await this.#t.sendFeatureReport(t.id,r):await this.#t.sendReport(t.buffer)}async receive(t){let e=[];if(!t.feature)throw new Error("Invalid operation");return e=await this.#t.receiveFeatureReport(t.id),e.byteLength!=t.bytes&&console.error(`reply length=${e.byteLength} (exp ${t.bytes})`),e}#t}const h={id:1,bytes:307,feature:!0},w={id:2,bytes:16,feature:!0},u={id:4,bytes:306,feature:!0},p=0,y=1,f=2,m=3,
|
|
1
|
+
const t=9,e=34,r=12972,a=[50,172],i=32,n=[0,32],s=Object.freeze([0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,9,9,9,10,10,10,11,11,11,12,12,12,13,13,14,14,14,15,15,16,16,17,17,17,18,18,19,19,20,20,21,22,22,23,23,24,24,25,26,26,27,27,28,29,29,30,31,32,32,33,34,34,35,36,37,38,38,39,40,41,42,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,66,67,68,69,70,71,73,74,75,76,78,79,80,82,83,84,86,87,88,90,91,93,94,96,97,99,100,102,103,105,106,108,110,111,113,115,116,118,120,121,123,125,127,128,130,132,134,136,138,140,141,143,145,147,149,151,153,155,157,159,161,164,166,168,170,172,174,177,179,181,183,186,188,190,193,195,197,200,202,205,207,210,212,215,217,220,222,225,228,230,233,236,238,241,244,247,249,252,255]),o=[],c=[{vendorId:12972,productId:32}];class l extends Error{constructor(){super("User cancelled device selection."),this.name=this.constructor.name,this.date=new Date}}class d{constructor(t){this.#t=t}async send(t,e){if(e.length<t.bytes)e=function(t,e,r=0){return t.concat(new Array(e-t.length).fill(r))}(e,t.bytes);else if(e.length>t.bytes)throw new Error("Unable to send report: too many bytes");const r=new Uint8Array(e).buffer;t.feature?await this.#t.sendFeatureReport(t.id,r):await this.#t.sendReport(t.buffer)}async receive(t){let e=[];if(!t.feature)throw new Error("Invalid operation");return e=await this.#t.receiveFeatureReport(t.id),e.byteLength!=t.bytes&&console.error(`reply length=${e.byteLength} (exp ${t.bytes})`),e}#t}const h={id:1,bytes:307,feature:!0},w={id:2,bytes:16,feature:!0},u={id:4,bytes:306,feature:!0},p=0,y=1,f=2,m=3,O=5,E=0;class A{constructor(t){this.#e=t}async info(){const t=await this.#e.receive(h);return{sleep_pin:t.getUint8(1),dip1_pin:t.getUint8(2),intb_pin:t.getUint8(3),state_flags:t.getUint8(4),id_reg:t.getUint8(5),config_reg:t.getUint8(6),global_brightness:t.getUint8(7),display_width:t.getUint8(8),display_height:t.getUint8(9),timeout_ms:t.getUint32(10)}}async wake(){await this.#e.send(w,[y,!1])}async sleep(){await this.#e.send(w,[y,!0])}async disableSleep(){await this.#e.send(w,[m,255,255,255,255])}async disableDeepSleep(){await this.#e.send(w,[f,1])}async disableSleepTimer(){await this.#e.send(w,[m,0,0,0,0])}async enableDeepSleep(){await this.#e.send(w,[f,0])}async enableSleepTimer(t){const e=new DataView(new ArrayBuffer(4));e.setInt32(0,t,!1),await this.#e.send(w,[m,e.getUint8(0),e.getUint8(1),e.getUint8(2),e.getUint8(3)])}async reboot(t){await this.#e.send(w,[p,t])}async drawPixel(t,e,r){await this.#e.send(w,[O,e,t,r])}async drawLine({r1:t,c1:e},{r2:r,c2:a},i){await this.#e.send(w,[O,t,e,r,a,i])}async bootloader(){await this.reboot(E)}async draw(t){await this.#e.send(u,t.flat().map(t=>s[Math.floor(255*(t??0))]))}async verifyFirmware(){try{const t=await this.info();return 34==t.display_height&&9==t.display_width}catch{return!1}}async version(){return{major:1,minor:0}}#e}class _{static async make(t){const e=await async function(){if(o&&o.length>0)return o.pop();if(o.push(...await navigator.hid.getDevices()),o&&o.length>0)return o.pop();if(o.push(...await navigator.hid.requestDevice({filters:c})),o&&o.length>0)return o.pop();throw new l}();if(e){if("sparkle"===t)return await _.makeSparkleController(e);if("detect"===t)return await _.makeDetectedController(e);throw new Error(`Unsupported firmware type: ${t}`)}}static async makeSparkleController(t){if(t)return await t.open(),new A(new d(t))}static async makeDetectedController(t){const e=await _.makeSparkleController(t);if(e.verifyFirmware())return e}}class g{constructor(t){this.#r=`port-mutex-${Math.random().toString()}`,this.#a=new Map,this.#i=t}async acquire(t){const e=new Error("created bad cb").stack;await this.#n(async()=>{try{await t(this.#i)}catch(t){console.error("Error occured in anonymous callback."),console.error("Original error:",t),console.error("--- This callback was created at ---\n",e)}})}async acquireIdempotent(t,e){const r=new Error("created bad cb").stack;this.#a.has(t)&&console.info(`"${t}" request coalesced.`),this.#a.set(t,async()=>{try{await e(this.#i)}catch(t){console.error("Error occured in anonymous callback."),console.error("Original error:",t),console.error("--- This callback was created at ---\n",r)}}),await this.#n(()=>this.#s(t))}async#n(t){return navigator.locks.request(this.#r,t)}async#s(t){if(this.#a.has(t)){const e=this.#a.get(t);this.#a.delete(t),await e()}}#r;#a;#i}class b{constructor(t){this.#o=t}async rx(t,e=3e3){if(null===this.#o)throw new Error("attempted RX before port initialization.");if(this.#o.readable.locked)throw new Error("attempted RX while port locked.");const r=[],a=this.#o.readable.getReader(),i=setTimeout(()=>a.cancel(),e);try{for(;r.length<t;){const{value:t,done:e}=await a.read();if(r.push(...t??[]),e||!t)break}}finally{clearTimeout(i),a.releaseLock()}return r}async tx(t){if(null===this.#o)throw new Error("attempted TX before port initialization.");if(this.#o.writable.locked)throw new Error("attempted TX while port locked.");const e=this.#o.writable.getWriter();try{await e.write(new Uint8Array(t))}finally{await e.close()}}#o}class T extends Error{constructor(){super("User cancelled port selection."),this.name=this.constructor.name,this.date=new Date}}class I extends Error{constructor(){super("Selected port already in use."),this.name=this.constructor.name,this.date=new Date}}async function M(t){try{await t.close()}catch(t){if("InvalidStateError"!=t.name&&"Failed to execute 'close' on 'SerialPort': The port is already closed."!=t.message)throw t}}const S=Object.freeze({ANIMATE:4,BRIGHTNESS:0,BOOTLOADER:2,DRAW:6,DRAW_GREY_COL_BUFFER:8,GAME_CTRL:17,GAME_STATUS:18,PANIC:5,PATTERN:1,SLEEP:3,STAGE_GREY_COL:7,START_GAME:16,VERSION:32}),x=Object.freeze({GRAY_8BIT:"8-bit",MONO_1BIT:"1-bit"});class R{constructor(t){this.#c=x.MONO_1BIT,this.#l=t}async bootloader(){await this.#l.acquire(async t=>{await t.tx([...a,S.BOOTLOADER])})}async draw(t){if(this.#c==x.GRAY_8BIT){const e=Array.from({length:9},(e,r)=>new Array({length:34},(e,a)=>GAMMA[Math.floor(255*(t[a][r]??0))]));await this.#l.acquireIdempotent("drawMatrix",async t=>{for(let r=0;r<9;r++)await t.tx([S.STAGE_GREY_COL,r,...e[r]]);await t.tx([S.DRAW_GREY_COL_BUFFER])})}else if(this.#c==x.MONO_1BIT){let e=0,r=new Uint8Array(39).fill(0);for(let a=0;a<34;a++)for(let i=0;i<9;i++)t[a][i]&&(r[e>>3]|=1<<e%8),e++;await this.#l.acquireIdempotent("drawMatrix",async t=>{await t.tx([...a,S.DRAW,...r])})}}async verifyFirmware(){let t=null;await this.#l.acquire(async e=>{await e.tx([...a,S.VERSION]),t=await e.rx(32)});const e=32==t.length,r=t.slice(3).every(t=>0==t);return e&&r}async version(){let t={};return await this.#l.acquire(async e=>{await e.tx([...a,S.VERSION]);const r=await e.rx(32);t.major=r[0],t.minor=r[1]>>4,t.patch=15&r[1],t.preRelease=1==r[2]}),t}#c;#l}const D=Object.freeze({NOOP:0,ANIMATION_DIAMOND:100,ANIMATION_FIRE:98,ANIMATION_FIREPLACE:102,ANIMATION_GEAR:103,ANIMATION_RING:114,ANIMATION_STARTUP:97,ANIMATION_STARTUP_ONCE:65,BOOTLOADER:101,DRAW_PWM:109,DRAW_PWM_BLOCKING:77,DRAW_SCALE:110,DRAW_SCALE_BLOCKING:78,FLUSH_CMD_QUEUE:99,TEST_PATTERN:116,SET_CONST_PWM:119,SET_CONST_SCALE:115,SET_PX_PWM:112,SET_PX_SCALE:113,IDENT:127}),N=/^Sig\sFW\sLED\sMatrix\sFW\sV(\d+)\.(\d+)$/;class k{constructor(t){this.#l=t}async bootloader(){await this.#l.acquire(async t=>{await t.tx([D.BOOTLOADER])})}async draw(t){this.#d||(await this.#l.acquire(async t=>{await t.tx([D.SET_CONST_SCALE,32])}),this.#d=!0);const e=t.flat().map(t=>s[Math.floor(255*(t??0))]);await this.#l.acquireIdempotent("drawMatrix",async t=>{await t.tx([D.DRAW_PWM,...e])})}async verifyFirmware(){let t=null;return await this.#l.acquire(async e=>{await e.tx([D.IDENT]),t=await e.rx(25)}),t=String.fromCharCode(...t),t.match(N)}async version(){let t=null;await this.#l.acquire(async e=>{await e.tx([D.IDENT]),t=await e.rx(25)}),t=String.fromCharCode(...t);const e=t.match(N);return e&&3==e.length?{major:e[1],minor:e[2]}:null}#l;#d}class C{static async make(t){const e=await async function(){try{const t=await navigator.serial.requestPort(),{usbProductId:e,usbVendorId:r}=t;return console.log("Selected port:",t),e&&r&&console.log(`VID:PID ${r}:${e}`),t}catch(t){throw"NotFoundError"==t.name?new T:"InvalidStateError"==t.name?new I:t}}();if(e){if("framework-official"===t)return await C.makeDefaultController(e);if("sigroot"===t)return await C.makeSigrootController(e);if("detect"===t)return await C.makeDetectedController(e);throw new Error(`Unsupported firmware type: ${t}`)}}static async makeDefaultController(t){if(t?.connected)return await M(t),await t.open({baudRate:115200}),new R(new g(new b(t)))}static async makeSigrootController(t){if(t?.connected)return await M(t),await t.open({baudRate:115200}),new k(new g(new b(t)))}static async makeDetectedController(t){const e=await this.makeDefaultController(t);if(await e.verifyFirmware())return e;const r=await this.makeSigrootController(t);return await r.verifyFirmware()?r:void 0}}export{s as GAMMA,e as HEIGHT,_ as HIDControllerFactory,i as PID,n as PID_ARR,C as SerialControllerFactory,r as VID,a as VID_ARR,t as WIDTH};
|
|
2
2
|
//# sourceMappingURL=led-matrix-controllers.browser.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"led-matrix-controllers.browser.mjs","sources":["../src/hardware-constants.js","../src/usb-hid/environments/web/device.js","../src/usb-hid/environments/web/HIDOperations.js","../src/usb-hid/environments/web/util.js","../src/usb-hid/firmware/sparkle/reports.js","../src/usb-hid/firmware/sparkle/SparkleController.js","../src/usb-hid/HIDControllerFactory.js","../src/usb-serial/environments/web/PortMutex.js","../src/usb-serial/environments/web/PortOperations.js","../src/usb-serial/environments/web/port.js","../src/usb-serial/firmware/framework-official/commands.js","../src/usb-serial/firmware/framework-official/DefaultController.js","../src/usb-serial/firmware/sigroot/commands.js","../src/usb-serial/firmware/sigroot/SigrootController.js","../src/usb-serial/SerialControllerFactory.js"],"sourcesContent":["export const WIDTH = 9;\r\nexport const HEIGHT = 34;\r\nexport const VID = 0x32AC;\r\nexport const VID_ARR = [0x32, 0xAC];\r\nexport const PID = 0x0020;\r\nexport const PID_ARR = [0x00, 0x20];\r\n\r\nexport const GAMMA = Object.freeze([\r\n 0, 0, 0, 0, 0, 0, 0, 1, \r\n 1, 1, 1, 1, 1, 1, 1, 1, \r\n 1, 1, 1, 1, 1, 1, 1, 1, \r\n 1, 1, 1, 1, 1, 1, 1, 1, \r\n 1, 1, 1, 2, 2, 2, 2, 2, \r\n 2, 2, 2, 2, 3, 3, 3, 3, \r\n 3, 3, 3, 4, 4, 4, 4, 4, \r\n 4, 5, 5, 5, 5, 6, 6, 6, \r\n 6, 6, 7, 7, 7, 7, 8, 8, \r\n 8, 9, 9, 9, 10, 10, 10, 11, \r\n 11, 11, 12, 12, 12, 13, 13, 14, \r\n 14, 14, 15, 15, 16, 16, 17, 17, \r\n 17, 18, 18, 19, 19, 20, 20, 21, \r\n 22, 22, 23, 23, 24, 24, 25, 26, \r\n 26, 27, 27, 28, 29, 29, 30, 31, \r\n 32, 32, 33, 34, 34, 35, 36, 37, \r\n 38, 38, 39, 40, 41, 42, 42, 43, \r\n 44, 45, 46, 47, 48, 49, 50, 51, \r\n 52, 53, 54, 55, 56, 57, 58, 59, \r\n 60, 61, 62, 63, 64, 66, 67, 68, \r\n 69, 70, 71, 73, 74, 75, 76, 78, \r\n 79, 80, 82, 83, 84, 86, 87, 88, \r\n 90, 91, 93, 94, 96, 97, 99, 100, \r\n 102, 103, 105, 106, 108, 110, 111, 113, \r\n 115, 116, 118, 120, 121, 123, 125, 127, \r\n 128, 130, 132, 134, 136, 138, 140, 141, \r\n 143, 145, 147, 149, 151, 153, 155, 157, \r\n 159, 161, 164, 166, 168, 170, 172, 174, \r\n 177, 179, 181, 183, 186, 188, 190, 193, \r\n 195, 197, 200, 202, 205, 207, 210, 212, \r\n 215, 217, 220, 222, 225, 228, 230, 233, \r\n 236, 238, 241, 244, 247, 249, 252, 255\r\n]);\r\n","import { PID, VID } from '../../../hardware-constants.js';\r\n\r\nconst extraDevices = [];\r\n\r\nconst filters = [\r\n {\r\n vendorId: VID,\r\n productId: PID,\r\n }\r\n]\r\n\r\nexport class DeviceSelectionCancelled extends Error {\r\n constructor() {\r\n super('User cancelled device selection.');\r\n this.name = this.constructor.name;\r\n this.date = new Date();\r\n }\r\n}\r\n\r\nexport async function getDevice() {\r\n if (extraDevices && extraDevices.length > 0) {\r\n return extraDevices.pop();\r\n }\r\n\r\n extraDevices.push(...(await navigator.hid.getDevices()));\r\n if (extraDevices && extraDevices.length > 0) {\r\n return extraDevices.pop();\r\n }\r\n\r\n extraDevices.push(...(await navigator.hid.requestDevice({ filters })));\r\n if (extraDevices && extraDevices.length > 0) {\r\n return extraDevices.pop();\r\n }\r\n\r\n throw new DeviceSelectionCancelled();\r\n}\r\n","import { pad } from './util.js';\r\n\r\nexport class HIDOperations {\r\n constructor(device) {\r\n this.#device = device;\r\n }\r\n\r\n async send(report, data) {\r\n if (data.length < report.bytes) {\r\n data = pad(data, report.bytes);\r\n } else if (data.length > report.bytes) {\r\n throw new Error('Unable to send report: too many bytes');\r\n }\r\n\r\n const buffer = new Uint8Array(data).buffer;\r\n\r\n if (report.feature) {\r\n await this.#device.sendFeatureReport(report.id, buffer);\r\n } else {\r\n await this.#device.sendReport(report.buffer);\r\n }\r\n }\r\n\r\n async receive(report) {\r\n let reply = [];\r\n\r\n if (report.feature) {\r\n reply = await this.#device.receiveFeatureReport(report.id);\r\n } else {\r\n /* \r\n * HID input reports are used for unprompted data.\r\n * An event system must be used.\r\n * See WebHID `HIDInputReportEvent`\r\n */\r\n throw new Error('Invalid operation');\r\n }\r\n\r\n if (reply.byteLength != report.bytes) {\r\n console.error(`reply length=${reply.byteLength} (exp ${report.bytes})`);\r\n }\r\n\r\n return reply;\r\n }\r\n\r\n #device;\r\n}\r\n","export function pad(arr, len, val=0x00) {\r\n return arr.concat(new Array(len - arr.length).fill(val));\r\n}\r\n","export const Reports = {\r\n GLITTER_DEVICE_INFO: {\r\n id: 0x01,\r\n bytes: 307,\r\n feature: true,\r\n },\r\n GLITTER_BASIC_CMD: {\r\n id: 0x02,\r\n bytes: 16,\r\n feature: true,\r\n },\r\n GLITTER_GRID_PWM_CNTL: {\r\n id: 0x03,\r\n bytes: 306,\r\n feature: true,\r\n },\r\n GLITTER_GRID_PWM_CNTL: {\r\n id: 0x04,\r\n bytes: 306,\r\n feature: true,\r\n }\r\n}\r\n\r\nexport const Commands = {\r\n GLITTER_CMD_REBOOT: 0x00,\r\n GLITTER_CMD_SLEEP: 0x01,\r\n GLITTER_CMD_WAKE_ON_COMMAND: 0x02,\r\n GLITTER_CMD_SET_SLEEP_TIMEOUT: 0x03,\r\n GLITTER_CMD_SET_GLOBAL_BRIGHTNESS: 0x04,\r\n GLITTER_CMD_DRAW_PIXEL: 0x05,\r\n GLITTER_CMD_DRAW_LINE: 0x06\r\n}\r\n\r\nexport const BootMode = {\r\n BOOTSEL: 0x00,\r\n NORMAL: 0x01,\r\n}\r\n","import { GAMMA, HEIGHT, WIDTH } from '../../../hardware-constants.js';\r\nimport { Commands, Reports } from './reports.js';\r\n\r\nexport class SparkleController {\r\n constructor(hidOps) {\r\n this.#hidOps = hidOps;\r\n }\r\n\r\n async info() {\r\n const infoRaw = await this.#hidOps.receive(Reports.GLITTER_DEVICE_INFO);\r\n\r\n return {\r\n sleep_pin: infoRaw.getUint8(1),\r\n dip1_pin: infoRaw.getUint8(2),\r\n intb_pin: infoRaw.getUint8(3),\r\n state_flags: infoRaw.getUint8(4),\r\n id_reg: infoRaw.getUint8(5),\r\n config_reg: infoRaw.getUint8(6),\r\n global_brightness: infoRaw.getUint8(7),\r\n display_width: infoRaw.getUint8(8),\r\n display_height: infoRaw.getUint8(9),\r\n timeout_ms: infoRaw.getUint32(10),\r\n };\r\n }\r\n\r\n async wake() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD,\r\n [Commands.GLITTER_CMD_SLEEP, false]\r\n );\r\n }\r\n\r\n async sleep() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD,\r\n [Commands.GLITTER_CMD_SLEEP, true]\r\n );\r\n }\r\n\r\n async disableSleep() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [Commands.GLITTER_CMD_SET_SLEEP_TIMEOUT, 0xff, 0xff, 0xff, 0xff]\r\n );\r\n }\r\n\r\n async disableDeepSleep() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [Commands.GLITTER_CMD_WAKE_ON_COMMAND, 0x01]\r\n );\r\n }\r\n\r\n async disableSleepTimer() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [Commands.GLITTER_CMD_SET_SLEEP_TIMEOUT, 0x00, 0x00, 0x00, 0x00]\r\n );\r\n }\r\n \r\n async enableDeepSleep() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [Commands.GLITTER_CMD_WAKE_ON_COMMAND, 0x00]\r\n );\r\n }\r\n\r\n async enableSleepTimer(milliseconds) {\r\n const view = new DataView(new ArrayBuffer(4));\r\n const littleEndian = false;\r\n view.setInt32(0, milliseconds, littleEndian);\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [\r\n Commands.GLITTER_CMD_SET_SLEEP_TIMEOUT, \r\n view.getUint8(0), \r\n view.getUint8(1), \r\n view.getUint8(2), \r\n view.getUint8(3),\r\n ]\r\n );\r\n }\r\n\r\n async reboot(mode) {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [Commands.GLITTER_CMD_REBOOT, mode]\r\n );\r\n }\r\n\r\n async drawPixel(r, c, brightness) {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD,\r\n [Commands.GLITTER_CMD_DRAW_PIXEL, c, r, brightness]\r\n );\r\n }\r\n\r\n async drawLine({r1, c1}, {r2, c2}, brightness) {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD,\r\n [Commands.GLITTER_CMD_DRAW_PIXEL, r1, c1, r2, c2, brightness]\r\n );\r\n }\r\n\r\n // --- generic methods ---\r\n\r\n async verifyFirmware() {\r\n try {\r\n const info = await this.info();\r\n return (\r\n info.display_height == HEIGHT &&\r\n info.display_width == WIDTH\r\n );\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async version() {\r\n // Not Available\r\n return { major: 1, minor: 0 };\r\n }\r\n\r\n async draw(matrix) {\r\n return await this.#hidOps.send(\r\n Reports.GLITTER_GRID_PWM_CNTL,\r\n matrix.flat().map(v => GAMMA[Math.floor((v ?? 0) * 255)])\r\n );\r\n }\r\n\r\n #hidOps;\r\n}\r\n","import { getDevice } from './environments/web/device.js';\r\nimport { HIDOperations } from './environments/web/HIDOperations.js';\r\nimport { SparkleController } from './firmware/sparkle/SparkleController.js';\r\n\r\nexport class HIDControllerFactory {\r\n static async make(firmware) {\r\n const device = await getDevice();\r\n if (device) {\r\n if (firmware === 'sparkle') {\r\n return await HIDControllerFactory.makeSparkleController(device);\r\n } else {\r\n throw new Error(`Unsupported firmware type: ${firmware}`);\r\n }\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n static async makeSparkleController(device) {\r\n if (device) {\r\n await device.open();\r\n return new SparkleController(\r\n new HIDOperations(device)\r\n );\r\n }\r\n }\r\n}\r\n","export class PortMutex {\r\n constructor(portOperations) {\r\n this.#lockName = `port-mutex-${Math.random().toString()}`;\r\n this.#deduper = new Map();\r\n this.#portOps = portOperations;\r\n }\r\n\r\n async acquire(fn) {\r\n const trace = new Error('created bad cb').stack;\r\n\r\n await this.#enqueue(async () => {\r\n try {\r\n await fn(this.#portOps);\r\n } catch (e) {\r\n console.error('Error occured in anonymous callback.');\r\n console.error('Original error:', e);\r\n console.error('--- This callback was created at ---\\n', trace);\r\n }\r\n });\r\n }\r\n\r\n async acquireIdempotent(key, fn) {\r\n const trace = new Error('created bad cb').stack;\r\n\r\n if (this.#deduper.has(key)) {\r\n console.info(`\"${key}\" request coalesced.`);\r\n }\r\n\r\n this.#deduper.set(key, async () => {\r\n try {\r\n await fn(this.#portOps);\r\n } catch (e) {\r\n console.error('Error occured in anonymous callback.');\r\n console.error('Original error:', e);\r\n console.error('--- This callback was created at ---\\n', trace);\r\n }\r\n });\r\n\r\n await this.#enqueue(() => this.#execDedupedOp(key));\r\n }\r\n\r\n async #enqueue(fn) {\r\n // `navigator.locks` maintains queue and provides mutual exclusion.\r\n return navigator.locks.request(this.#lockName, fn);\r\n }\r\n\r\n async #execDedupedOp(key) {\r\n if (this.#deduper.has(key)) {\r\n const fn = this.#deduper.get(key);\r\n this.#deduper.delete(key);\r\n await fn();\r\n }\r\n }\r\n\r\n #lockName;\r\n #deduper;\r\n #portOps;\r\n}\r\n","export class PortOperations {\r\n constructor(port) {\r\n this.#port = port;\r\n }\r\n\r\n async rx(length, timeout=3000) {\r\n if (this.#port === null) {\r\n throw new Error('attempted RX before port initialization.');\r\n }\r\n\r\n /*\r\n * ReadableStream's built-in locking mechanism cannot be awaited or otherwise\r\n * asynchronously acquired. A PortMutex must be used.\r\n */\r\n if (this.#port.readable.locked) {\r\n throw new Error('attempted RX while port locked.');\r\n }\r\n\r\n const response = [];\r\n const reader = this.#port.readable.getReader();\r\n const timeoutHandle = setTimeout(() => reader.cancel(), timeout);\r\n\r\n try {\r\n // Response may be divided across multiple reads\r\n while (response.length < length) {\r\n const { value, done } = await reader.read();\r\n response.push(...(value ?? []));\r\n if (done || !value) break;\r\n }\r\n } finally {\r\n clearTimeout(timeoutHandle);\r\n reader.releaseLock();\r\n }\r\n\r\n return response;\r\n }\r\n\r\n async tx(buffer) {\r\n if (this.#port === null) {\r\n throw new Error('attempted TX before port initialization.');\r\n }\r\n \r\n /*\r\n * WritableStream's built-in locking mechanism cannot be awaited or otherwise\r\n * asynchronously acquired. A PortMutex must be used.\r\n */\r\n if (this.#port.writable.locked) {\r\n throw new Error('attempted TX while port locked.');\r\n }\r\n\r\n const writer = this.#port.writable.getWriter();\r\n\r\n try {\r\n await writer.write(new Uint8Array(buffer));\r\n } finally {\r\n /* \r\n * The writer must be completely torn down between every single write.\r\n * Many parsers can't handle delayed flushing and write coalescing.\r\n * Command sequences will fail if `releaseLock()` is used here.\r\n */\r\n await writer.close();\r\n }\r\n }\r\n\r\n #port;\r\n}\r\n","export class PortSelectionCancelled extends Error {\r\n constructor() {\r\n super('User cancelled port selection.');\r\n this.name = this.constructor.name;\r\n this.date = new Date();\r\n }\r\n}\r\n\r\nexport class PortUnavailable extends Error {\r\n constructor() {\r\n super('Selected port already in use.');\r\n this.name = this.constructor.name;\r\n this.date = new Date();\r\n }\r\n}\r\n\r\nexport async function getPort() {\r\n try {\r\n const port = await navigator.serial.requestPort();\r\n const { usbProductId, usbVendorId } = port;\r\n console.log('Selected port:', port);\r\n if (usbProductId && usbVendorId) {\r\n console.log(`VID:PID ${usbVendorId}:${usbProductId}`);\r\n }\r\n return port;\r\n } catch (e) {\r\n if (e.name == 'NotFoundError') {\r\n throw new PortSelectionCancelled();\r\n } else if (e.name == 'InvalidStateError') {\r\n throw new PortUnavailable();\r\n } else {\r\n throw e;\r\n }\r\n }\r\n}\r\n\r\nexport async function close(port) {\r\n try {\r\n await port.close();\r\n } catch(e) {\r\n if (e.name != 'InvalidStateError') {\r\n if (e.message != \"Failed to execute 'close' on 'SerialPort': The port is already closed.\") {\r\n throw e;\r\n }\r\n }\r\n }\r\n}\r\n","// All replies to all commands are 32 bytes\r\nexport const RX_PACKET_SZ = 32;\r\n\r\nexport const Command = Object.freeze({\r\n ANIMATE: 0x04,\r\n BRIGHTNESS: 0x00,\r\n BOOTLOADER: 0x02,\r\n DRAW: 0x06,\r\n DRAW_GREY_COL_BUFFER: 0x08,\r\n GAME_CTRL: 0x11,\r\n GAME_STATUS: 0x12,\r\n PANIC: 0x05,\r\n PATTERN: 0x01,\r\n SLEEP: 0x03,\r\n STAGE_GREY_COL: 0x07,\r\n START_GAME: 0x10,\r\n VERSION: 0x20,\r\n});\r\n\r\n// Used with Command.PATTERN\r\nexport const Pattern = Object.freeze({\r\n DISPLAY_LOTUS_HORIZONTAL: 0x03,\r\n DISPLAY_LOTUS_VERTICAL: 0x07,\r\n DISPLAY_PANIC: 0x06,\r\n DOUBLE_GRADIENT: 0x02,\r\n FULL_BRIGHTNESS: 0x05,\r\n GRADIENT: 0x01,\r\n PERCENTAGE: 0x00,\r\n ZIG_ZAG: 0x04,\r\n});\r\n\r\n// DRAW or DRAW_GREY_COL_BUFFER\r\nexport const BitDepth = Object.freeze({\r\n GRAY_8BIT: '8-bit',\r\n MONO_1BIT: '1-bit',\r\n})\r\n","import { HEIGHT, VID_ARR, WIDTH } from '../../../hardware-constants.js';\r\nimport { BitDepth, Command, RX_PACKET_SZ } from './commands.js';\r\n\r\nexport class DefaultController {\r\n constructor(portMutex) {\r\n this.#bitDepth = BitDepth.MONO_1BIT;\r\n this.#portMutex = portMutex;\r\n }\r\n\r\n async verifyFirmware() {\r\n let packet = null;\r\n\r\n await this.#portMutex.acquire(async p => {\r\n await p.tx([...VID_ARR, Command.VERSION]);\r\n packet = await p.rx(RX_PACKET_SZ);\r\n });\r\n\r\n const isPacket = packet.length == RX_PACKET_SZ;\r\n const isPadded = packet.slice(3).every(e => e == 0x00);\r\n\r\n return isPacket && isPadded;\r\n }\r\n\r\n async version() {\r\n let ver = {};\r\n\r\n await this.#portMutex.acquire(async p => {\r\n await p.tx([...VID_ARR, Command.VERSION]);\r\n const response = await p.rx(RX_PACKET_SZ);\r\n\r\n // MMMMMMMM mmmmPPPP 0000000p\r\n ver.major = response[0];\r\n ver.minor = response[1] >> 4;\r\n ver.patch = response[1] & 0x0F;\r\n ver.preRelease = response[2] == 1;\r\n });\r\n\r\n return ver;\r\n }\r\n\r\n async draw(matrix) {\r\n if (this.#bitDepth == BitDepth.GRAY_8BIT) {\r\n // Transpose & Gamma Correction\r\n const payloads = Array.from(\r\n { length: WIDTH }, \r\n (_, c) => new Array(\r\n { length: HEIGHT }, \r\n (_, r) => GAMMA[Math.floor((matrix[r][c] ?? 0) * 255)]\r\n )\r\n );\r\n\r\n // Only execute the most recent call \r\n await this.#portMutex.acquireIdempotent(\r\n 'drawMatrix', \r\n async p => {\r\n for (let i = 0; i < WIDTH; i++) {\r\n await p.tx([Command.STAGE_GREY_COL, i, ...payloads[i]]);\r\n }\r\n await p.tx([Command.DRAW_GREY_COL_BUFFER]);\r\n }\r\n );\r\n }\r\n\r\n else if (this.#bitDepth == BitDepth.MONO_1BIT) {\r\n let index = 0;\r\n let output = new Uint8Array(39).fill(0);\r\n\r\n // Pack cells into bits\r\n for (let r = 0; r < HEIGHT; r++) {\r\n for (let c = 0; c < WIDTH; c++) {\r\n if (matrix[r][c]) {\r\n output[index >> 3] |= 1 << index % 8;\r\n }\r\n index++;\r\n }\r\n }\r\n\r\n await this.#portMutex.acquireIdempotent(\r\n 'drawMatrix', \r\n async p => {\r\n await p.tx([...VID_ARR, Command.DRAW, ...output]);\r\n }\r\n );\r\n }\r\n }\r\n\r\n #bitDepth;\r\n #portMutex;\r\n}\r\n","export const Command = Object.freeze({\r\n /* 000 */ NOOP: 0x00,\r\n /* 'd' */ ANIMATION_DIAMOND: 0x64,\r\n /* 'b' */ ANIMATION_FIRE: 0x62,\r\n /* 'f' */ ANIMATION_FIREPLACE: 0x66,\r\n /* 'g' */ ANIMATION_GEAR: 0x67,\r\n /* 'r' */ ANIMATION_RING: 0x72,\r\n /* 'a' */ ANIMATION_STARTUP: 0x61,\r\n /* 'A' */ ANIMATION_STARTUP_ONCE: 0x41,\r\n /* 'e' */ BOOTLOADER: 0x65,\r\n /* 'm' */ DRAW_PWM: 0x6D,\r\n /* 'M' */ DRAW_PWM_BLOCKING: 0x4D,\r\n /* 'n' */ DRAW_SCALE: 0x6E,\r\n /* 'N' */ DRAW_SCALE_BLOCKING: 0x4E,\r\n /* 'c' */ FLUSH_CMD_QUEUE: 0x63,\r\n /* 't' */ TEST_PATTERN: 0x74,\r\n /* 'w' */ SET_CONST_PWM: 0x77,\r\n /* 's' */ SET_CONST_SCALE: 0x73,\r\n /* 'p' */ SET_PX_PWM: 0x70,\r\n /* 'q' */ SET_PX_SCALE: 0x71,\r\n /* 127 */ IDENT: 0x7F,\r\n});\r\n\r\nexport const IDENT_STR_LEN = 25;\r\n\r\nexport const IDENT_STR_REGEX = /^Sig\\sFW\\sLED\\sMatrix\\sFW\\sV(\\d+)\\.(\\d+)$/;\r\n\r\nexport const IDENT_STR_PREFIX = 'Sig FW LED Matrix FW';\r\n","import { GAMMA } from '../../../hardware-constants.js';\r\nimport { Command, IDENT_STR_LEN, IDENT_STR_REGEX } from './commands.js';\r\n\r\nexport class SigrootController {\r\n constructor(portMutex) {\r\n this.#portMutex = portMutex;\r\n }\r\n\r\n async verifyFirmware() {\r\n let ident = null;\r\n\r\n await this.#portMutex.acquire(async p => {\r\n await p.tx([Command.IDENT]);\r\n ident = await p.rx(IDENT_STR_LEN);\r\n });\r\n\r\n ident = String.fromCharCode(...ident);\r\n\r\n return ident.match(IDENT_STR_REGEX);\r\n }\r\n\r\n async version() {\r\n let ident = null;\r\n\r\n await this.#portMutex.acquire(async p => {\r\n await p.tx([Command.IDENT]);\r\n ident = await p.rx(IDENT_STR_LEN);\r\n });\r\n\r\n ident = String.fromCharCode(...ident);\r\n\r\n const match = ident.match(IDENT_STR_REGEX);\r\n\r\n if (match && match.length == 3) {\r\n return {\r\n major: match[1],\r\n minor: match[2]\r\n }\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n async draw(matrix) {\r\n if (!this.#scaleInitialized) {\r\n await this.#portMutex.acquire(\r\n async p => {\r\n await p.tx([Command.SET_CONST_SCALE, 0x20]);\r\n }\r\n );\r\n this.#scaleInitialized = true;\r\n }\r\n\r\n const bytes = matrix.flat().map(v => \r\n GAMMA[Math.floor((v ?? 0) * 255)]\r\n );\r\n\r\n // Only execute the most recent call \r\n await this.#portMutex.acquireIdempotent(\r\n 'drawMatrix', \r\n async p => {\r\n await p.tx([Command.DRAW_PWM, ...bytes]);\r\n }\r\n );\r\n }\r\n\r\n #portMutex;\r\n #scaleInitialized;\r\n}\r\n","import { PortMutex } from './environments/web/PortMutex.js';\r\nimport { PortOperations } from './environments/web/PortOperations.js';\r\nimport { close, getPort } from './environments/web/port.js';\r\nimport { DefaultController } from './firmware/framework-official/DefaultController.js';\r\nimport { SigrootController } from './firmware/sigroot/SigrootController.js';\r\n\r\nexport class SerialControllerFactory {\r\n static async make(firmware) {\r\n const port = await getPort();\r\n if (port) {\r\n if (firmware === 'framework-official') {\r\n return await SerialControllerFactory.makeDefaultWebController(port);\r\n } else if (firmware === 'sigroot') {\r\n return await SerialControllerFactory.makeSigrootWebController(port);\r\n } else if (firmware === 'auto') {\r\n return await SerialControllerFactory.makeAutoWebController(port);\r\n } else {\r\n throw new Error(`Unsupported firmware type: ${firmware}`);\r\n }\r\n }\r\n }\r\n\r\n static async makeDefaultWebController(port) {\r\n if (port?.connected) {\r\n await close(port);\r\n await port.open({ baudRate: 115200 });\r\n return new DefaultController(\r\n new PortMutex(\r\n new PortOperations(port)\r\n )\r\n );\r\n }\r\n }\r\n\r\n static async makeSigrootWebController(port) {\r\n if (port?.connected) {\r\n await close(port);\r\n await port.open({ baudRate: 115200 });\r\n return new SigrootController(\r\n new PortMutex(\r\n new PortOperations(port)\r\n )\r\n );\r\n }\r\n }\r\n\r\n static async makeAutoWebController(port) {\r\n const ctrl1 = await this.makeDefaultWebController(port);\r\n if (await ctrl1.verifyFirmware()) {\r\n return ctrl1;\r\n }\r\n const ctrl2 = await this.makeSigrootWebController(port);\r\n if (await ctrl2.verifyFirmware()) {\r\n return ctrl2;\r\n }\r\n }\r\n}\r\n"],"names":["WIDTH","HEIGHT","VID","VID_ARR","PID","PID_ARR","GAMMA","Object","freeze","extraDevices","filters","vendorId","productId","DeviceSelectionCancelled","Error","constructor","super","this","name","date","Date","HIDOperations","device","send","report","data","length","bytes","arr","len","val","concat","Array","fill","pad","buffer","Uint8Array","feature","sendFeatureReport","id","sendReport","receive","reply","receiveFeatureReport","byteLength","console","error","Reports","Commands","SparkleController","hidOps","info","infoRaw","sleep_pin","getUint8","dip1_pin","intb_pin","state_flags","id_reg","config_reg","global_brightness","display_width","display_height","timeout_ms","getUint32","wake","sleep","disableSleep","disableDeepSleep","disableSleepTimer","enableDeepSleep","enableSleepTimer","milliseconds","view","DataView","ArrayBuffer","setInt32","reboot","mode","drawPixel","r","c","brightness","drawLine","r1","c1","r2","c2","verifyFirmware","version","major","minor","draw","matrix","flat","map","v","Math","floor","HIDControllerFactory","make","firmware","async","pop","push","navigator","hid","getDevices","requestDevice","getDevice","makeSparkleController","open","PortMutex","portOperations","lockName","random","toString","deduper","Map","portOps","acquire","fn","trace","stack","enqueue","e","acquireIdempotent","key","has","set","execDedupedOp","locks","request","get","delete","PortOperations","port","rx","timeout","readable","locked","response","reader","getReader","timeoutHandle","setTimeout","cancel","value","done","read","clearTimeout","releaseLock","tx","writable","writer","getWriter","write","close","PortSelectionCancelled","PortUnavailable","message","Command","ANIMATE","BRIGHTNESS","BOOTLOADER","DRAW","DRAW_GREY_COL_BUFFER","GAME_CTRL","GAME_STATUS","PANIC","PATTERN","SLEEP","STAGE_GREY_COL","START_GAME","VERSION","BitDepth","GRAY_8BIT","MONO_1BIT","DefaultController","portMutex","bitDepth","packet","p","isPacket","isPadded","slice","every","ver","patch","preRelease","payloads","from","_","i","index","output","NOOP","ANIMATION_DIAMOND","ANIMATION_FIRE","ANIMATION_FIREPLACE","ANIMATION_GEAR","ANIMATION_RING","ANIMATION_STARTUP","ANIMATION_STARTUP_ONCE","DRAW_PWM","DRAW_PWM_BLOCKING","DRAW_SCALE","DRAW_SCALE_BLOCKING","FLUSH_CMD_QUEUE","TEST_PATTERN","SET_CONST_PWM","SET_CONST_SCALE","SET_PX_PWM","SET_PX_SCALE","IDENT","IDENT_STR_REGEX","SigrootController","ident","String","fromCharCode","match","scaleInitialized","SerialControllerFactory","serial","requestPort","usbProductId","usbVendorId","log","getPort","makeDefaultWebController","makeSigrootWebController","makeAutoWebController","connected","baudRate","ctrl1","ctrl2"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"led-matrix-controllers.browser.mjs","sources":["../src/hardware-constants.js","../src/usb-hid/environments/web/device.js","../src/usb-hid/environments/web/HIDOperations.js","../src/usb-hid/environments/web/util.js","../src/usb-hid/firmware/sparkle/reports.js","../src/usb-hid/firmware/sparkle/SparkleController.js","../src/usb-hid/HIDControllerFactory.js","../src/usb-serial/environments/web/PortMutex.js","../src/usb-serial/environments/web/PortOperations.js","../src/usb-serial/environments/web/port.js","../src/usb-serial/firmware/framework-official/commands.js","../src/usb-serial/firmware/framework-official/DefaultController.js","../src/usb-serial/firmware/sigroot/commands.js","../src/usb-serial/firmware/sigroot/SigrootController.js","../src/usb-serial/SerialControllerFactory.js"],"sourcesContent":["export const WIDTH = 9;\r\nexport const HEIGHT = 34;\r\nexport const VID = 0x32AC;\r\nexport const VID_ARR = [0x32, 0xAC];\r\nexport const PID = 0x0020;\r\nexport const PID_ARR = [0x00, 0x20];\r\n\r\nexport const GAMMA = Object.freeze([\r\n 0, 0, 0, 0, 0, 0, 0, 1, \r\n 1, 1, 1, 1, 1, 1, 1, 1, \r\n 1, 1, 1, 1, 1, 1, 1, 1, \r\n 1, 1, 1, 1, 1, 1, 1, 1, \r\n 1, 1, 1, 2, 2, 2, 2, 2, \r\n 2, 2, 2, 2, 3, 3, 3, 3, \r\n 3, 3, 3, 4, 4, 4, 4, 4, \r\n 4, 5, 5, 5, 5, 6, 6, 6, \r\n 6, 6, 7, 7, 7, 7, 8, 8, \r\n 8, 9, 9, 9, 10, 10, 10, 11, \r\n 11, 11, 12, 12, 12, 13, 13, 14, \r\n 14, 14, 15, 15, 16, 16, 17, 17, \r\n 17, 18, 18, 19, 19, 20, 20, 21, \r\n 22, 22, 23, 23, 24, 24, 25, 26, \r\n 26, 27, 27, 28, 29, 29, 30, 31, \r\n 32, 32, 33, 34, 34, 35, 36, 37, \r\n 38, 38, 39, 40, 41, 42, 42, 43, \r\n 44, 45, 46, 47, 48, 49, 50, 51, \r\n 52, 53, 54, 55, 56, 57, 58, 59, \r\n 60, 61, 62, 63, 64, 66, 67, 68, \r\n 69, 70, 71, 73, 74, 75, 76, 78, \r\n 79, 80, 82, 83, 84, 86, 87, 88, \r\n 90, 91, 93, 94, 96, 97, 99, 100, \r\n 102, 103, 105, 106, 108, 110, 111, 113, \r\n 115, 116, 118, 120, 121, 123, 125, 127, \r\n 128, 130, 132, 134, 136, 138, 140, 141, \r\n 143, 145, 147, 149, 151, 153, 155, 157, \r\n 159, 161, 164, 166, 168, 170, 172, 174, \r\n 177, 179, 181, 183, 186, 188, 190, 193, \r\n 195, 197, 200, 202, 205, 207, 210, 212, \r\n 215, 217, 220, 222, 225, 228, 230, 233, \r\n 236, 238, 241, 244, 247, 249, 252, 255\r\n]);\r\n","import { PID, VID } from '../../../hardware-constants.js';\r\n\r\nconst extraDevices = [];\r\n\r\nconst filters = [\r\n {\r\n vendorId: VID,\r\n productId: PID,\r\n }\r\n]\r\n\r\nexport class DeviceSelectionCancelled extends Error {\r\n constructor() {\r\n super('User cancelled device selection.');\r\n this.name = this.constructor.name;\r\n this.date = new Date();\r\n }\r\n}\r\n\r\nexport async function getDevice() {\r\n if (extraDevices && extraDevices.length > 0) {\r\n return extraDevices.pop();\r\n }\r\n\r\n extraDevices.push(...(await navigator.hid.getDevices()));\r\n if (extraDevices && extraDevices.length > 0) {\r\n return extraDevices.pop();\r\n }\r\n\r\n extraDevices.push(...(await navigator.hid.requestDevice({ filters })));\r\n if (extraDevices && extraDevices.length > 0) {\r\n return extraDevices.pop();\r\n }\r\n\r\n throw new DeviceSelectionCancelled();\r\n}\r\n","import { pad } from './util.js';\r\n\r\nexport class HIDOperations {\r\n constructor(device) {\r\n this.#device = device;\r\n }\r\n\r\n async send(report, data) {\r\n if (data.length < report.bytes) {\r\n data = pad(data, report.bytes);\r\n } else if (data.length > report.bytes) {\r\n throw new Error('Unable to send report: too many bytes');\r\n }\r\n\r\n const buffer = new Uint8Array(data).buffer;\r\n\r\n if (report.feature) {\r\n await this.#device.sendFeatureReport(report.id, buffer);\r\n } else {\r\n await this.#device.sendReport(report.buffer);\r\n }\r\n }\r\n\r\n async receive(report) {\r\n let reply = [];\r\n\r\n if (report.feature) {\r\n reply = await this.#device.receiveFeatureReport(report.id);\r\n } else {\r\n /* \r\n * HID input reports are used for unprompted data.\r\n * An event system must be used.\r\n * See WebHID `HIDInputReportEvent`\r\n */\r\n throw new Error('Invalid operation');\r\n }\r\n\r\n if (reply.byteLength != report.bytes) {\r\n console.error(`reply length=${reply.byteLength} (exp ${report.bytes})`);\r\n }\r\n\r\n return reply;\r\n }\r\n\r\n #device;\r\n}\r\n","export function pad(arr, len, val=0x00) {\r\n return arr.concat(new Array(len - arr.length).fill(val));\r\n}\r\n","export const Reports = {\r\n GLITTER_DEVICE_INFO: {\r\n id: 0x01,\r\n bytes: 307,\r\n feature: true,\r\n },\r\n GLITTER_BASIC_CMD: {\r\n id: 0x02,\r\n bytes: 16,\r\n feature: true,\r\n },\r\n GLITTER_GRID_PWM_CNTL: {\r\n id: 0x03,\r\n bytes: 306,\r\n feature: true,\r\n },\r\n GLITTER_GRID_PWM_CNTL: {\r\n id: 0x04,\r\n bytes: 306,\r\n feature: true,\r\n }\r\n}\r\n\r\nexport const Commands = {\r\n GLITTER_CMD_REBOOT: 0x00,\r\n GLITTER_CMD_SLEEP: 0x01,\r\n GLITTER_CMD_WAKE_ON_COMMAND: 0x02,\r\n GLITTER_CMD_SET_SLEEP_TIMEOUT: 0x03,\r\n GLITTER_CMD_SET_GLOBAL_BRIGHTNESS: 0x04,\r\n GLITTER_CMD_DRAW_PIXEL: 0x05,\r\n GLITTER_CMD_DRAW_LINE: 0x06\r\n}\r\n\r\nexport const BootMode = {\r\n BOOTSEL: 0x00,\r\n NORMAL: 0x01,\r\n}\r\n","import { GAMMA, HEIGHT, WIDTH } from '../../../hardware-constants.js';\r\nimport { BootMode, Commands, Reports } from './reports.js';\r\n\r\nexport { BootMode } from './reports.js';\r\n\r\nexport class SparkleController {\r\n constructor(hidOps) {\r\n this.#hidOps = hidOps;\r\n }\r\n\r\n async info() {\r\n const infoRaw = await this.#hidOps.receive(Reports.GLITTER_DEVICE_INFO);\r\n\r\n return {\r\n sleep_pin: infoRaw.getUint8(1),\r\n dip1_pin: infoRaw.getUint8(2),\r\n intb_pin: infoRaw.getUint8(3),\r\n state_flags: infoRaw.getUint8(4),\r\n id_reg: infoRaw.getUint8(5),\r\n config_reg: infoRaw.getUint8(6),\r\n global_brightness: infoRaw.getUint8(7),\r\n display_width: infoRaw.getUint8(8),\r\n display_height: infoRaw.getUint8(9),\r\n timeout_ms: infoRaw.getUint32(10),\r\n };\r\n }\r\n\r\n async wake() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD,\r\n [Commands.GLITTER_CMD_SLEEP, false]\r\n );\r\n }\r\n\r\n async sleep() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD,\r\n [Commands.GLITTER_CMD_SLEEP, true]\r\n );\r\n }\r\n\r\n async disableSleep() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [Commands.GLITTER_CMD_SET_SLEEP_TIMEOUT, 0xff, 0xff, 0xff, 0xff]\r\n );\r\n }\r\n\r\n async disableDeepSleep() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [Commands.GLITTER_CMD_WAKE_ON_COMMAND, 0x01]\r\n );\r\n }\r\n\r\n async disableSleepTimer() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [Commands.GLITTER_CMD_SET_SLEEP_TIMEOUT, 0x00, 0x00, 0x00, 0x00]\r\n );\r\n }\r\n \r\n async enableDeepSleep() {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [Commands.GLITTER_CMD_WAKE_ON_COMMAND, 0x00]\r\n );\r\n }\r\n\r\n async enableSleepTimer(milliseconds) {\r\n const view = new DataView(new ArrayBuffer(4));\r\n const littleEndian = false;\r\n view.setInt32(0, milliseconds, littleEndian);\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [\r\n Commands.GLITTER_CMD_SET_SLEEP_TIMEOUT, \r\n view.getUint8(0), \r\n view.getUint8(1), \r\n view.getUint8(2), \r\n view.getUint8(3),\r\n ]\r\n );\r\n }\r\n\r\n async reboot(mode) {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD, \r\n [Commands.GLITTER_CMD_REBOOT, mode]\r\n );\r\n }\r\n\r\n async drawPixel(r, c, brightness) {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD,\r\n [Commands.GLITTER_CMD_DRAW_PIXEL, c, r, brightness]\r\n );\r\n }\r\n\r\n async drawLine({r1, c1}, {r2, c2}, brightness) {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_BASIC_CMD,\r\n [Commands.GLITTER_CMD_DRAW_PIXEL, r1, c1, r2, c2, brightness]\r\n );\r\n }\r\n\r\n // --- generic methods ---\r\n\r\n async bootloader() {\r\n await this.reboot(BootMode.BOOTSEL);\r\n }\r\n \r\n async draw(matrix) {\r\n await this.#hidOps.send(\r\n Reports.GLITTER_GRID_PWM_CNTL,\r\n matrix.flat().map(v => GAMMA[Math.floor((v ?? 0) * 255)])\r\n );\r\n }\r\n\r\n async verifyFirmware() {\r\n try {\r\n const info = await this.info();\r\n return (\r\n info.display_height == HEIGHT &&\r\n info.display_width == WIDTH\r\n );\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async version() {\r\n // Not Available\r\n return { major: 1, minor: 0 };\r\n }\r\n\r\n #hidOps;\r\n}\r\n","import { getDevice } from './environments/web/device.js';\r\nimport { HIDOperations } from './environments/web/HIDOperations.js';\r\nimport { SparkleController } from './firmware/sparkle/SparkleController.js';\r\n\r\nexport class HIDControllerFactory {\r\n static async make(firmware) {\r\n const device = await getDevice();\r\n if (device) {\r\n if (firmware === 'sparkle') {\r\n return await HIDControllerFactory.makeSparkleController(device);\r\n } else if (firmware === 'detect') {\r\n return await HIDControllerFactory.makeDetectedController(device);\r\n } else {\r\n throw new Error(`Unsupported firmware type: ${firmware}`);\r\n }\r\n }\r\n }\r\n\r\n static async makeSparkleController(device) {\r\n if (device) {\r\n await device.open();\r\n return new SparkleController(\r\n new HIDOperations(device)\r\n );\r\n }\r\n }\r\n\r\n static async makeDetectedController(device) {\r\n const ctrl1 = await HIDControllerFactory.makeSparkleController(device);\r\n if (ctrl1.verifyFirmware()) {\r\n return ctrl1;\r\n }\r\n }\r\n}\r\n","export class PortMutex {\r\n constructor(portOperations) {\r\n this.#lockName = `port-mutex-${Math.random().toString()}`;\r\n this.#deduper = new Map();\r\n this.#portOps = portOperations;\r\n }\r\n\r\n async acquire(fn) {\r\n const trace = new Error('created bad cb').stack;\r\n\r\n await this.#enqueue(async () => {\r\n try {\r\n await fn(this.#portOps);\r\n } catch (e) {\r\n console.error('Error occured in anonymous callback.');\r\n console.error('Original error:', e);\r\n console.error('--- This callback was created at ---\\n', trace);\r\n }\r\n });\r\n }\r\n\r\n async acquireIdempotent(key, fn) {\r\n const trace = new Error('created bad cb').stack;\r\n\r\n if (this.#deduper.has(key)) {\r\n console.info(`\"${key}\" request coalesced.`);\r\n }\r\n\r\n this.#deduper.set(key, async () => {\r\n try {\r\n await fn(this.#portOps);\r\n } catch (e) {\r\n console.error('Error occured in anonymous callback.');\r\n console.error('Original error:', e);\r\n console.error('--- This callback was created at ---\\n', trace);\r\n }\r\n });\r\n\r\n await this.#enqueue(() => this.#execDedupedOp(key));\r\n }\r\n\r\n async #enqueue(fn) {\r\n // `navigator.locks` maintains queue and provides mutual exclusion.\r\n return navigator.locks.request(this.#lockName, fn);\r\n }\r\n\r\n async #execDedupedOp(key) {\r\n if (this.#deduper.has(key)) {\r\n const fn = this.#deduper.get(key);\r\n this.#deduper.delete(key);\r\n await fn();\r\n }\r\n }\r\n\r\n #lockName;\r\n #deduper;\r\n #portOps;\r\n}\r\n","export class PortOperations {\r\n constructor(port) {\r\n this.#port = port;\r\n }\r\n\r\n async rx(length, timeout=3000) {\r\n if (this.#port === null) {\r\n throw new Error('attempted RX before port initialization.');\r\n }\r\n\r\n /*\r\n * ReadableStream's built-in locking mechanism cannot be awaited or otherwise\r\n * asynchronously acquired. A PortMutex must be used.\r\n */\r\n if (this.#port.readable.locked) {\r\n throw new Error('attempted RX while port locked.');\r\n }\r\n\r\n const response = [];\r\n const reader = this.#port.readable.getReader();\r\n const timeoutHandle = setTimeout(() => reader.cancel(), timeout);\r\n\r\n try {\r\n // Response may be divided across multiple reads\r\n while (response.length < length) {\r\n const { value, done } = await reader.read();\r\n response.push(...(value ?? []));\r\n if (done || !value) break;\r\n }\r\n } finally {\r\n clearTimeout(timeoutHandle);\r\n reader.releaseLock();\r\n }\r\n\r\n return response;\r\n }\r\n\r\n async tx(buffer) {\r\n if (this.#port === null) {\r\n throw new Error('attempted TX before port initialization.');\r\n }\r\n \r\n /*\r\n * WritableStream's built-in locking mechanism cannot be awaited or otherwise\r\n * asynchronously acquired. A PortMutex must be used.\r\n */\r\n if (this.#port.writable.locked) {\r\n throw new Error('attempted TX while port locked.');\r\n }\r\n\r\n const writer = this.#port.writable.getWriter();\r\n\r\n try {\r\n await writer.write(new Uint8Array(buffer));\r\n } finally {\r\n /* \r\n * The writer must be completely torn down between every single write.\r\n * Many parsers can't handle delayed flushing and write coalescing.\r\n * Command sequences will fail if `releaseLock()` is used here.\r\n */\r\n await writer.close();\r\n }\r\n }\r\n\r\n #port;\r\n}\r\n","export class PortSelectionCancelled extends Error {\r\n constructor() {\r\n super('User cancelled port selection.');\r\n this.name = this.constructor.name;\r\n this.date = new Date();\r\n }\r\n}\r\n\r\nexport class PortUnavailable extends Error {\r\n constructor() {\r\n super('Selected port already in use.');\r\n this.name = this.constructor.name;\r\n this.date = new Date();\r\n }\r\n}\r\n\r\nexport async function getPort() {\r\n try {\r\n const port = await navigator.serial.requestPort();\r\n const { usbProductId, usbVendorId } = port;\r\n console.log('Selected port:', port);\r\n if (usbProductId && usbVendorId) {\r\n console.log(`VID:PID ${usbVendorId}:${usbProductId}`);\r\n }\r\n return port;\r\n } catch (e) {\r\n if (e.name == 'NotFoundError') {\r\n throw new PortSelectionCancelled();\r\n } else if (e.name == 'InvalidStateError') {\r\n throw new PortUnavailable();\r\n } else {\r\n throw e;\r\n }\r\n }\r\n}\r\n\r\nexport async function close(port) {\r\n try {\r\n await port.close();\r\n } catch(e) {\r\n if (e.name != 'InvalidStateError') {\r\n if (e.message != \"Failed to execute 'close' on 'SerialPort': The port is already closed.\") {\r\n throw e;\r\n }\r\n }\r\n }\r\n}\r\n","// All replies to all commands are 32 bytes\r\nexport const RX_PACKET_SZ = 32;\r\n\r\nexport const Command = Object.freeze({\r\n ANIMATE: 0x04,\r\n BRIGHTNESS: 0x00,\r\n BOOTLOADER: 0x02,\r\n DRAW: 0x06,\r\n DRAW_GREY_COL_BUFFER: 0x08,\r\n GAME_CTRL: 0x11,\r\n GAME_STATUS: 0x12,\r\n PANIC: 0x05,\r\n PATTERN: 0x01,\r\n SLEEP: 0x03,\r\n STAGE_GREY_COL: 0x07,\r\n START_GAME: 0x10,\r\n VERSION: 0x20,\r\n});\r\n\r\n// Used with Command.PATTERN\r\nexport const Pattern = Object.freeze({\r\n DISPLAY_LOTUS_HORIZONTAL: 0x03,\r\n DISPLAY_LOTUS_VERTICAL: 0x07,\r\n DISPLAY_PANIC: 0x06,\r\n DOUBLE_GRADIENT: 0x02,\r\n FULL_BRIGHTNESS: 0x05,\r\n GRADIENT: 0x01,\r\n PERCENTAGE: 0x00,\r\n ZIG_ZAG: 0x04,\r\n});\r\n\r\n// DRAW or DRAW_GREY_COL_BUFFER\r\nexport const BitDepth = Object.freeze({\r\n GRAY_8BIT: '8-bit',\r\n MONO_1BIT: '1-bit',\r\n})\r\n","import { HEIGHT, VID_ARR, WIDTH } from '../../../hardware-constants.js';\r\nimport { BitDepth, Command, RX_PACKET_SZ } from './commands.js';\r\n\r\nexport class DefaultController {\r\n constructor(portMutex) {\r\n this.#bitDepth = BitDepth.MONO_1BIT;\r\n this.#portMutex = portMutex;\r\n }\r\n\r\n async bootloader() {\r\n await this.#portMutex.acquire(async p => {\r\n await p.tx([...VID_ARR, Command.BOOTLOADER]);\r\n });\r\n }\r\n\r\n async draw(matrix) {\r\n if (this.#bitDepth == BitDepth.GRAY_8BIT) {\r\n // Transpose & Gamma Correction\r\n const payloads = Array.from(\r\n { length: WIDTH }, \r\n (_, c) => new Array(\r\n { length: HEIGHT }, \r\n (_, r) => GAMMA[Math.floor((matrix[r][c] ?? 0) * 255)]\r\n )\r\n );\r\n\r\n // Only execute the most recent call \r\n await this.#portMutex.acquireIdempotent(\r\n 'drawMatrix', \r\n async p => {\r\n for (let i = 0; i < WIDTH; i++) {\r\n await p.tx([Command.STAGE_GREY_COL, i, ...payloads[i]]);\r\n }\r\n await p.tx([Command.DRAW_GREY_COL_BUFFER]);\r\n }\r\n );\r\n }\r\n\r\n else if (this.#bitDepth == BitDepth.MONO_1BIT) {\r\n let index = 0;\r\n let output = new Uint8Array(39).fill(0);\r\n\r\n // Pack cells into bits\r\n for (let r = 0; r < HEIGHT; r++) {\r\n for (let c = 0; c < WIDTH; c++) {\r\n if (matrix[r][c]) {\r\n output[index >> 3] |= 1 << index % 8;\r\n }\r\n index++;\r\n }\r\n }\r\n\r\n await this.#portMutex.acquireIdempotent(\r\n 'drawMatrix', \r\n async p => {\r\n await p.tx([...VID_ARR, Command.DRAW, ...output]);\r\n }\r\n );\r\n }\r\n }\r\n\r\n async verifyFirmware() {\r\n let packet = null;\r\n\r\n await this.#portMutex.acquire(async p => {\r\n await p.tx([...VID_ARR, Command.VERSION]);\r\n packet = await p.rx(RX_PACKET_SZ);\r\n });\r\n\r\n const isPacket = packet.length == RX_PACKET_SZ;\r\n const isPadded = packet.slice(3).every(e => e == 0x00);\r\n\r\n return isPacket && isPadded;\r\n }\r\n\r\n async version() {\r\n let ver = {};\r\n\r\n await this.#portMutex.acquire(async p => {\r\n await p.tx([...VID_ARR, Command.VERSION]);\r\n const response = await p.rx(RX_PACKET_SZ);\r\n\r\n // MMMMMMMM mmmmPPPP 0000000p\r\n ver.major = response[0];\r\n ver.minor = response[1] >> 4;\r\n ver.patch = response[1] & 0x0F;\r\n ver.preRelease = response[2] == 1;\r\n });\r\n\r\n return ver;\r\n }\r\n\r\n #bitDepth;\r\n #portMutex;\r\n}\r\n","export const Command = Object.freeze({\r\n /* 000 */ NOOP: 0x00,\r\n /* 'd' */ ANIMATION_DIAMOND: 0x64,\r\n /* 'b' */ ANIMATION_FIRE: 0x62,\r\n /* 'f' */ ANIMATION_FIREPLACE: 0x66,\r\n /* 'g' */ ANIMATION_GEAR: 0x67,\r\n /* 'r' */ ANIMATION_RING: 0x72,\r\n /* 'a' */ ANIMATION_STARTUP: 0x61,\r\n /* 'A' */ ANIMATION_STARTUP_ONCE: 0x41,\r\n /* 'e' */ BOOTLOADER: 0x65,\r\n /* 'm' */ DRAW_PWM: 0x6D,\r\n /* 'M' */ DRAW_PWM_BLOCKING: 0x4D,\r\n /* 'n' */ DRAW_SCALE: 0x6E,\r\n /* 'N' */ DRAW_SCALE_BLOCKING: 0x4E,\r\n /* 'c' */ FLUSH_CMD_QUEUE: 0x63,\r\n /* 't' */ TEST_PATTERN: 0x74,\r\n /* 'w' */ SET_CONST_PWM: 0x77,\r\n /* 's' */ SET_CONST_SCALE: 0x73,\r\n /* 'p' */ SET_PX_PWM: 0x70,\r\n /* 'q' */ SET_PX_SCALE: 0x71,\r\n /* 127 */ IDENT: 0x7F,\r\n});\r\n\r\nexport const IDENT_STR_LEN = 25;\r\n\r\nexport const IDENT_STR_REGEX = /^Sig\\sFW\\sLED\\sMatrix\\sFW\\sV(\\d+)\\.(\\d+)$/;\r\n\r\nexport const IDENT_STR_PREFIX = 'Sig FW LED Matrix FW';\r\n","import { GAMMA } from '../../../hardware-constants.js';\r\nimport { Command, IDENT_STR_LEN, IDENT_STR_REGEX } from './commands.js';\r\n\r\nexport class SigrootController {\r\n constructor(portMutex) {\r\n this.#portMutex = portMutex;\r\n }\r\n\r\n async bootloader() {\r\n await this.#portMutex.acquire(async p => {\r\n await p.tx([Command.BOOTLOADER]);\r\n });\r\n }\r\n\r\n async draw(matrix) {\r\n if (!this.#scaleInitialized) {\r\n await this.#portMutex.acquire(\r\n async p => {\r\n await p.tx([Command.SET_CONST_SCALE, 0x20]);\r\n }\r\n );\r\n this.#scaleInitialized = true;\r\n }\r\n\r\n const bytes = matrix.flat().map(v => \r\n GAMMA[Math.floor((v ?? 0) * 255)]\r\n );\r\n\r\n // Only execute the most recent call \r\n await this.#portMutex.acquireIdempotent(\r\n 'drawMatrix', \r\n async p => {\r\n await p.tx([Command.DRAW_PWM, ...bytes]);\r\n }\r\n );\r\n }\r\n\r\n async verifyFirmware() {\r\n let ident = null;\r\n\r\n await this.#portMutex.acquire(async p => {\r\n await p.tx([Command.IDENT]);\r\n ident = await p.rx(IDENT_STR_LEN);\r\n });\r\n\r\n ident = String.fromCharCode(...ident);\r\n\r\n return ident.match(IDENT_STR_REGEX);\r\n }\r\n\r\n async version() {\r\n let ident = null;\r\n\r\n await this.#portMutex.acquire(async p => {\r\n await p.tx([Command.IDENT]);\r\n ident = await p.rx(IDENT_STR_LEN);\r\n });\r\n\r\n ident = String.fromCharCode(...ident);\r\n\r\n const match = ident.match(IDENT_STR_REGEX);\r\n\r\n if (match && match.length == 3) {\r\n return {\r\n major: match[1],\r\n minor: match[2]\r\n }\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n #portMutex;\r\n #scaleInitialized;\r\n}\r\n","import { PortMutex } from './environments/web/PortMutex.js';\r\nimport { PortOperations } from './environments/web/PortOperations.js';\r\nimport { close, getPort } from './environments/web/port.js';\r\nimport { DefaultController } from './firmware/framework-official/DefaultController.js';\r\nimport { SigrootController } from './firmware/sigroot/SigrootController.js';\r\n\r\nexport class SerialControllerFactory {\r\n static async make(firmware) {\r\n const port = await getPort();\r\n if (port) {\r\n if (firmware === 'framework-official') {\r\n return await SerialControllerFactory.makeDefaultController(port);\r\n } else if (firmware === 'sigroot') {\r\n return await SerialControllerFactory.makeSigrootController(port);\r\n } else if (firmware === 'detect') {\r\n return await SerialControllerFactory.makeDetectedController(port);\r\n } else {\r\n throw new Error(`Unsupported firmware type: ${firmware}`);\r\n }\r\n }\r\n }\r\n\r\n static async makeDefaultController(port) {\r\n if (port?.connected) {\r\n await close(port);\r\n await port.open({ baudRate: 115200 });\r\n return new DefaultController(\r\n new PortMutex(\r\n new PortOperations(port)\r\n )\r\n );\r\n }\r\n }\r\n\r\n static async makeSigrootController(port) {\r\n if (port?.connected) {\r\n await close(port);\r\n await port.open({ baudRate: 115200 });\r\n return new SigrootController(\r\n new PortMutex(\r\n new PortOperations(port)\r\n )\r\n );\r\n }\r\n }\r\n\r\n static async makeDetectedController(port) {\r\n const ctrl1 = await this.makeDefaultController(port);\r\n if (await ctrl1.verifyFirmware()) {\r\n return ctrl1;\r\n }\r\n const ctrl2 = await this.makeSigrootController(port);\r\n if (await ctrl2.verifyFirmware()) {\r\n return ctrl2;\r\n }\r\n }\r\n}\r\n"],"names":["WIDTH","HEIGHT","VID","VID_ARR","PID","PID_ARR","GAMMA","Object","freeze","extraDevices","filters","vendorId","productId","DeviceSelectionCancelled","Error","constructor","super","this","name","date","Date","HIDOperations","device","send","report","data","length","bytes","arr","len","val","concat","Array","fill","pad","buffer","Uint8Array","feature","sendFeatureReport","id","sendReport","receive","reply","receiveFeatureReport","byteLength","console","error","Reports","Commands","BootMode","SparkleController","hidOps","info","infoRaw","sleep_pin","getUint8","dip1_pin","intb_pin","state_flags","id_reg","config_reg","global_brightness","display_width","display_height","timeout_ms","getUint32","wake","sleep","disableSleep","disableDeepSleep","disableSleepTimer","enableDeepSleep","enableSleepTimer","milliseconds","view","DataView","ArrayBuffer","setInt32","reboot","mode","drawPixel","r","c","brightness","drawLine","r1","c1","r2","c2","bootloader","draw","matrix","flat","map","v","Math","floor","verifyFirmware","version","major","minor","HIDControllerFactory","make","firmware","async","pop","push","navigator","hid","getDevices","requestDevice","getDevice","makeSparkleController","makeDetectedController","open","ctrl1","PortMutex","portOperations","lockName","random","toString","deduper","Map","portOps","acquire","fn","trace","stack","enqueue","e","acquireIdempotent","key","has","set","execDedupedOp","locks","request","get","delete","PortOperations","port","rx","timeout","readable","locked","response","reader","getReader","timeoutHandle","setTimeout","cancel","value","done","read","clearTimeout","releaseLock","tx","writable","writer","getWriter","write","close","PortSelectionCancelled","PortUnavailable","message","Command","ANIMATE","BRIGHTNESS","BOOTLOADER","DRAW","DRAW_GREY_COL_BUFFER","GAME_CTRL","GAME_STATUS","PANIC","PATTERN","SLEEP","STAGE_GREY_COL","START_GAME","VERSION","BitDepth","GRAY_8BIT","MONO_1BIT","DefaultController","portMutex","bitDepth","p","payloads","from","_","i","index","output","packet","isPacket","isPadded","slice","every","ver","patch","preRelease","NOOP","ANIMATION_DIAMOND","ANIMATION_FIRE","ANIMATION_FIREPLACE","ANIMATION_GEAR","ANIMATION_RING","ANIMATION_STARTUP","ANIMATION_STARTUP_ONCE","DRAW_PWM","DRAW_PWM_BLOCKING","DRAW_SCALE","DRAW_SCALE_BLOCKING","FLUSH_CMD_QUEUE","TEST_PATTERN","SET_CONST_PWM","SET_CONST_SCALE","SET_PX_PWM","SET_PX_SCALE","IDENT","IDENT_STR_REGEX","SigrootController","scaleInitialized","ident","String","fromCharCode","match","SerialControllerFactory","serial","requestPort","usbProductId","usbVendorId","log","getPort","makeDefaultController","makeSigrootController","connected","baudRate","ctrl2"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -8,11 +8,11 @@ export class HIDControllerFactory {
|
|
|
8
8
|
if (device) {
|
|
9
9
|
if (firmware === 'sparkle') {
|
|
10
10
|
return await HIDControllerFactory.makeSparkleController(device);
|
|
11
|
+
} else if (firmware === 'detect') {
|
|
12
|
+
return await HIDControllerFactory.makeDetectedController(device);
|
|
11
13
|
} else {
|
|
12
14
|
throw new Error(`Unsupported firmware type: ${firmware}`);
|
|
13
15
|
}
|
|
14
|
-
} else {
|
|
15
|
-
return null;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -24,4 +24,11 @@ export class HIDControllerFactory {
|
|
|
24
24
|
);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
static async makeDetectedController(device) {
|
|
29
|
+
const ctrl1 = await HIDControllerFactory.makeSparkleController(device);
|
|
30
|
+
if (ctrl1.verifyFirmware()) {
|
|
31
|
+
return ctrl1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
27
34
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { GAMMA, HEIGHT, WIDTH } from '../../../hardware-constants.js';
|
|
2
|
-
import { Commands, Reports } from './reports.js';
|
|
2
|
+
import { BootMode, Commands, Reports } from './reports.js';
|
|
3
|
+
|
|
4
|
+
export { BootMode } from './reports.js';
|
|
3
5
|
|
|
4
6
|
export class SparkleController {
|
|
5
7
|
constructor(hidOps) {
|
|
@@ -104,6 +106,17 @@ export class SparkleController {
|
|
|
104
106
|
|
|
105
107
|
// --- generic methods ---
|
|
106
108
|
|
|
109
|
+
async bootloader() {
|
|
110
|
+
await this.reboot(BootMode.BOOTSEL);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async draw(matrix) {
|
|
114
|
+
await this.#hidOps.send(
|
|
115
|
+
Reports.GLITTER_GRID_PWM_CNTL,
|
|
116
|
+
matrix.flat().map(v => GAMMA[Math.floor((v ?? 0) * 255)])
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
107
120
|
async verifyFirmware() {
|
|
108
121
|
try {
|
|
109
122
|
const info = await this.info();
|
|
@@ -121,12 +134,5 @@ export class SparkleController {
|
|
|
121
134
|
return { major: 1, minor: 0 };
|
|
122
135
|
}
|
|
123
136
|
|
|
124
|
-
async draw(matrix) {
|
|
125
|
-
return await this.#hidOps.send(
|
|
126
|
-
Reports.GLITTER_GRID_PWM_CNTL,
|
|
127
|
-
matrix.flat().map(v => GAMMA[Math.floor((v ?? 0) * 255)])
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
137
|
#hidOps;
|
|
132
138
|
}
|
|
@@ -9,18 +9,18 @@ export class SerialControllerFactory {
|
|
|
9
9
|
const port = await getPort();
|
|
10
10
|
if (port) {
|
|
11
11
|
if (firmware === 'framework-official') {
|
|
12
|
-
return await SerialControllerFactory.
|
|
12
|
+
return await SerialControllerFactory.makeDefaultController(port);
|
|
13
13
|
} else if (firmware === 'sigroot') {
|
|
14
|
-
return await SerialControllerFactory.
|
|
15
|
-
} else if (firmware === '
|
|
16
|
-
return await SerialControllerFactory.
|
|
14
|
+
return await SerialControllerFactory.makeSigrootController(port);
|
|
15
|
+
} else if (firmware === 'detect') {
|
|
16
|
+
return await SerialControllerFactory.makeDetectedController(port);
|
|
17
17
|
} else {
|
|
18
18
|
throw new Error(`Unsupported firmware type: ${firmware}`);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
static async
|
|
23
|
+
static async makeDefaultController(port) {
|
|
24
24
|
if (port?.connected) {
|
|
25
25
|
await close(port);
|
|
26
26
|
await port.open({ baudRate: 115200 });
|
|
@@ -32,7 +32,7 @@ export class SerialControllerFactory {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
static async
|
|
35
|
+
static async makeSigrootController(port) {
|
|
36
36
|
if (port?.connected) {
|
|
37
37
|
await close(port);
|
|
38
38
|
await port.open({ baudRate: 115200 });
|
|
@@ -44,12 +44,12 @@ export class SerialControllerFactory {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
static async
|
|
48
|
-
const ctrl1 = await this.
|
|
47
|
+
static async makeDetectedController(port) {
|
|
48
|
+
const ctrl1 = await this.makeDefaultController(port);
|
|
49
49
|
if (await ctrl1.verifyFirmware()) {
|
|
50
50
|
return ctrl1;
|
|
51
51
|
}
|
|
52
|
-
const ctrl2 = await this.
|
|
52
|
+
const ctrl2 = await this.makeSigrootController(port);
|
|
53
53
|
if (await ctrl2.verifyFirmware()) {
|
|
54
54
|
return ctrl2;
|
|
55
55
|
}
|
|
@@ -7,35 +7,10 @@ export class DefaultController {
|
|
|
7
7
|
this.#portMutex = portMutex;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
async
|
|
11
|
-
let packet = null;
|
|
12
|
-
|
|
10
|
+
async bootloader() {
|
|
13
11
|
await this.#portMutex.acquire(async p => {
|
|
14
|
-
await p.tx([...VID_ARR, Command.
|
|
15
|
-
packet = await p.rx(RX_PACKET_SZ);
|
|
12
|
+
await p.tx([...VID_ARR, Command.BOOTLOADER]);
|
|
16
13
|
});
|
|
17
|
-
|
|
18
|
-
const isPacket = packet.length == RX_PACKET_SZ;
|
|
19
|
-
const isPadded = packet.slice(3).every(e => e == 0x00);
|
|
20
|
-
|
|
21
|
-
return isPacket && isPadded;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async version() {
|
|
25
|
-
let ver = {};
|
|
26
|
-
|
|
27
|
-
await this.#portMutex.acquire(async p => {
|
|
28
|
-
await p.tx([...VID_ARR, Command.VERSION]);
|
|
29
|
-
const response = await p.rx(RX_PACKET_SZ);
|
|
30
|
-
|
|
31
|
-
// MMMMMMMM mmmmPPPP 0000000p
|
|
32
|
-
ver.major = response[0];
|
|
33
|
-
ver.minor = response[1] >> 4;
|
|
34
|
-
ver.patch = response[1] & 0x0F;
|
|
35
|
-
ver.preRelease = response[2] == 1;
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return ver;
|
|
39
14
|
}
|
|
40
15
|
|
|
41
16
|
async draw(matrix) {
|
|
@@ -84,6 +59,37 @@ export class DefaultController {
|
|
|
84
59
|
}
|
|
85
60
|
}
|
|
86
61
|
|
|
62
|
+
async verifyFirmware() {
|
|
63
|
+
let packet = null;
|
|
64
|
+
|
|
65
|
+
await this.#portMutex.acquire(async p => {
|
|
66
|
+
await p.tx([...VID_ARR, Command.VERSION]);
|
|
67
|
+
packet = await p.rx(RX_PACKET_SZ);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const isPacket = packet.length == RX_PACKET_SZ;
|
|
71
|
+
const isPadded = packet.slice(3).every(e => e == 0x00);
|
|
72
|
+
|
|
73
|
+
return isPacket && isPadded;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async version() {
|
|
77
|
+
let ver = {};
|
|
78
|
+
|
|
79
|
+
await this.#portMutex.acquire(async p => {
|
|
80
|
+
await p.tx([...VID_ARR, Command.VERSION]);
|
|
81
|
+
const response = await p.rx(RX_PACKET_SZ);
|
|
82
|
+
|
|
83
|
+
// MMMMMMMM mmmmPPPP 0000000p
|
|
84
|
+
ver.major = response[0];
|
|
85
|
+
ver.minor = response[1] >> 4;
|
|
86
|
+
ver.patch = response[1] & 0x0F;
|
|
87
|
+
ver.preRelease = response[2] == 1;
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return ver;
|
|
91
|
+
}
|
|
92
|
+
|
|
87
93
|
#bitDepth;
|
|
88
94
|
#portMutex;
|
|
89
95
|
}
|
|
@@ -6,6 +6,35 @@ export class SigrootController {
|
|
|
6
6
|
this.#portMutex = portMutex;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
async bootloader() {
|
|
10
|
+
await this.#portMutex.acquire(async p => {
|
|
11
|
+
await p.tx([Command.BOOTLOADER]);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async draw(matrix) {
|
|
16
|
+
if (!this.#scaleInitialized) {
|
|
17
|
+
await this.#portMutex.acquire(
|
|
18
|
+
async p => {
|
|
19
|
+
await p.tx([Command.SET_CONST_SCALE, 0x20]);
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
this.#scaleInitialized = true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const bytes = matrix.flat().map(v =>
|
|
26
|
+
GAMMA[Math.floor((v ?? 0) * 255)]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// Only execute the most recent call
|
|
30
|
+
await this.#portMutex.acquireIdempotent(
|
|
31
|
+
'drawMatrix',
|
|
32
|
+
async p => {
|
|
33
|
+
await p.tx([Command.DRAW_PWM, ...bytes]);
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
9
38
|
async verifyFirmware() {
|
|
10
39
|
let ident = null;
|
|
11
40
|
|
|
@@ -41,29 +70,6 @@ export class SigrootController {
|
|
|
41
70
|
}
|
|
42
71
|
}
|
|
43
72
|
|
|
44
|
-
async draw(matrix) {
|
|
45
|
-
if (!this.#scaleInitialized) {
|
|
46
|
-
await this.#portMutex.acquire(
|
|
47
|
-
async p => {
|
|
48
|
-
await p.tx([Command.SET_CONST_SCALE, 0x20]);
|
|
49
|
-
}
|
|
50
|
-
);
|
|
51
|
-
this.#scaleInitialized = true;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const bytes = matrix.flat().map(v =>
|
|
55
|
-
GAMMA[Math.floor((v ?? 0) * 255)]
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
// Only execute the most recent call
|
|
59
|
-
await this.#portMutex.acquireIdempotent(
|
|
60
|
-
'drawMatrix',
|
|
61
|
-
async p => {
|
|
62
|
-
await p.tx([Command.DRAW_PWM, ...bytes]);
|
|
63
|
-
}
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
73
|
#portMutex;
|
|
68
74
|
#scaleInitialized;
|
|
69
75
|
}
|