//OTHER devices follow a general format: /* connect -> init device and scripts disconnect -> close device connection onconnect -> onconnect callback you can customize ondata -> ondata callback you can customize ondisconnect -> disconnect callback you can customize codec -> optionally used to transform streams e.g. on a separate thread, libraries like muse-js already do it for us so we can just customize ondata to handle output, or use the codec to do some kind of special math on a thread */ import { WebglLinePlotProps } from "webgl-plot-utils"; import { FilterSettings } from "../../util/BiquadFilters"; import {Ganglion} from './dependencies/ganglion-browser' const sps = 250; export const ganglionSettings = { //include muse-js and import {MuseClient} from 'muse-js' for this to work sps, deviceType:'CUSTOM_BLE', deviceName:'ganglion', connect:(settings:any={}) => { return new Promise(async (res,rej) => { let _id = `ganglion${Math.floor(Math.random()*1000000000000000)}`; // //@ts-ignore // if(typeof Ganglion === 'undefined') { document.head.insertAdjacentHTML('beforeend',``) } let client = new Ganglion(); let info = { _id, client, settings:Object.assign(Object.assign({},ganglionSettings),settings) //e.g. customize ondisconnect } await client.connect(); await client.start(); client.stream.subscribe((reading:{ timestamp: number; // milliseconds since epoch data: number[]; // 1 sample per channel, 4 samples total }) => { (reading as any).origin = 'eeg'; info.settings.ondata(reading); }); client.accelData.subscribe((reading:{ data:[number,number,number] //? }) => { (reading as any).origin = 'accelerometer'; info.settings.ondata(reading); }); if(info.settings.onconnect) info.settings.onconnect(info); res(info); }) }, codec:(reading:any) => { //remap outputs to more or less match the rest of our formatting let origin = reading.origin; if(origin === 'eeg') { return { 0:reading.data[0], 1:reading.data[1], 2:reading.data[2], 3:reading.data[3], timestamp: Date.now() } } else if (origin === 'accelerometer') { return { ax:reading.data[0], ay:reading.data[1], az:reading.data[2], timestamp: Date.now() } } }, disconnect:(info) => { info.client.disconnect(); }, onconnect:(info)=>{ console.log('ganglion connected!', info); }, beforedisconnect:(info) => { }, ondisconnect:(info)=>{ console.log('ganglion disconnected!', info); }, ondata:(data:any)=>{ console.log(data); //direct from the device output }, //read:(info:any,command?:any)=>{}, //write:(info:any,command?:any)=>{} } let defaultsetting = { sps, useDCBlock:true, useBandpass:true, bandpassLower:3, bandpassUpper:45 }; export const ganglionFilterSettings:{[key:string]:FilterSettings} = { '0':JSON.parse(JSON.stringify(defaultsetting)), //twos compliment 2^23 '1':JSON.parse(JSON.stringify(defaultsetting)), '2':JSON.parse(JSON.stringify(defaultsetting)), '3':JSON.parse(JSON.stringify(defaultsetting)) } const defaultChartSetting = {nSec:10, sps, units:'mV'}; export const ganglionChartSettings:Partial = { lines:{ '0':JSON.parse(JSON.stringify(defaultChartSetting)), '1':JSON.parse(JSON.stringify(defaultChartSetting)), '2':JSON.parse(JSON.stringify(defaultChartSetting)), '3':JSON.parse(JSON.stringify(defaultChartSetting)), 'ax':{nSec:10, sps, units:'mg'}, 'ay':{nSec:10, sps, units:'mg'}, 'az':{nSec:10, sps, units:'mg'}, }, generateNewLines:true //to add the additional 16 channels };