wasmapi.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. var printCharBuffers = [null, [], []]
  2. var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined
  3. var HEAP8 = null // Int8Array
  4. var HEAPU8 = null // Uint8Array
  5. var HEAP16 = null // Int16Array
  6. var HEAPU16 = null // Uint16Array
  7. var HEAP32 = null // Int32Array
  8. var HEAPU32 = null // Uint32Array
  9. var HEAPF32 = null // Float32Array
  10. var HEAPF64 = null // Float64Array
  11. //注入函数,打印字符串,C代码中打印字符串需要以\n结束
  12. function printChar(stream, curr) {
  13. var buffer = printCharBuffers[stream];
  14. //assert(buffer);
  15. if (curr === 0 || curr === 10) {
  16. //(stream === 1 ? out : err)(this.UTF8ArrayToString(buffer, 0));
  17. //buffer.length = 0;
  18. let str = UTF8ArrayToString(buffer, 0)
  19. console.log(str)//打印字符串
  20. buffer.length = 0;
  21. } else {
  22. buffer.push(curr);
  23. }
  24. }
  25. //注入函数,将字节数组转成字符数组
  26. function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {
  27. var endIdx = idx + maxBytesToRead;
  28. var endPtr = idx;
  29. // TextDecoder needs to know the byte length in advance, it doesn't stop on
  30. // null terminator by itself. Also, use the length info to avoid running tiny
  31. // strings through TextDecoder, since .subarray() allocates garbage.
  32. // (As a tiny code save trick, compare endPtr against endIdx using a negation,
  33. // so that undefined means Infinity)
  34. while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
  35. if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
  36. return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
  37. }
  38. var str = '';
  39. // If building with TextDecoder, we have already computed the string length
  40. // above, so test loop end condition against that
  41. while (idx < endPtr) {
  42. // For UTF8 byte structure, see:
  43. // http://en.wikipedia.org/wiki/UTF-8#Description
  44. // https://www.ietf.org/rfc/rfc2279.txt
  45. // https://tools.ietf.org/html/rfc3629
  46. var u0 = heapOrArray[idx++];
  47. if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; }
  48. var u1 = heapOrArray[idx++] & 63;
  49. if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; }
  50. var u2 = heapOrArray[idx++] & 63;
  51. if ((u0 & 0xF0) == 0xE0) {
  52. u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
  53. } else {
  54. //if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte ' + ptrToString(u0) + ' encountered when deserializing a UTF-8 string in wasm memory to a JS string!');
  55. u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63);
  56. }
  57. if (u0 < 0x10000) {
  58. str += String.fromCharCode(u0);
  59. } else {
  60. var ch = u0 - 0x10000;
  61. str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
  62. }
  63. }
  64. return str;
  65. }
  66. const wasmapi = {
  67. wasmInstance: null,//wasm实例
  68. wasmFuncs: null,//wasm导出函数
  69. wasmDataPtr: {//wasm模块的数据指针
  70. installBtsDataPtr: 0,//安装基站数据指针
  71. bleBtsDataPtr: 0,//蓝牙基站数据指针
  72. audioDataPtr: 0,//音频数据指针
  73. currentLocationCoordPtr: 0,//定位坐标数据指针
  74. accDataPtr: 0,//加速度指针
  75. softNameAndVersionPtr: 0,//软件名称和版本数据指针
  76. btsSysConfigParamPtr: 0,//基站系统配置参数
  77. sysDebugSwitchPtr: 0,//系统调试开关数据指针
  78. },
  79. data: {
  80. audioDataList: [],//音频数据队列
  81. oneFrameLen: 12000,//一帧音频数据长度
  82. bleBtsMonitorSuccessFlag: false,//蓝牙基站监听成功标识符
  83. bleBtsDataList: [], //蓝牙基站队列
  84. installBtsInjectFlag: false,//安装基站已注入标识符
  85. accDataList: [],//加速度数据队列
  86. },
  87. ////wasm注入函数,将数据从源地址src拷贝长度为num的数据到目的地址dest
  88. _emscripten_memcpy_js(dest, src, num) {
  89. HEAPU8.copyWithin(dest, src, src + num)
  90. },
  91. _emscripten_resize_heap(requestedSize) {
  92. let oldSize = HEAPU8.length
  93. // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
  94. requestedSize >>>= 0
  95. this.abortOnCannotGrowMemory(requestedSize)
  96. },
  97. abortOnCannotGrowMemory(requestedSize) {
  98. abort(`Cannot enlarge memory arrays to size ${requestedSize} bytes (OOM). Either (1) compile with -sINITIAL_MEMORY=X with X higher than the current value ${HEAP8.length}, (2) compile with -sALLOW_MEMORY_GROWTH which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -sABORTING_MALLOC=0`);
  99. },
  100. _fd_write(fd, iov, iovcnt, pnum) {
  101. let num = 0
  102. for (let i = 0; i < iovcnt; i++) {
  103. let ptr = HEAP32[((iov) >> 2)]
  104. let len = HEAP32[(((iov) + (4)) >> 2)]
  105. iov += 8
  106. for (let j = 0; j < len; j++) {
  107. printChar(fd, HEAPU8[ptr + j])
  108. }
  109. num += len
  110. }
  111. HEAP32[((pnum) >> 2)] = num
  112. return 0
  113. },
  114. _fd_close(fd) {
  115. abort('fd_close called without SYSCALLS_REQUIRE_FILESYSTEM');
  116. return 0
  117. },
  118. _fd_seek(fd, offset_low, offset_high, whence, newOffset) {
  119. abort('it should not be possible to operate on streams when !SYSCALLS_REQUIRE_FILESYSTEM')
  120. return 0;
  121. },
  122. _emscripten_date_now() {
  123. return new Date().getTime()
  124. },
  125. // __emscripten_get_now_is_monotonic() {
  126. // return 1
  127. // },
  128. // _emscripten_get_now() {
  129. // return new Date().getTime()
  130. // },
  131. //加载微信wasm模块
  132. loadWxWasm() {
  133. let self = this
  134. //let configParam = { d: this._emscripten_date_now, b: this._emscripten_memcpy_js, a: this._emscripten_resize_heap, c: this._fd_write }
  135. let configParam = {}
  136. configParam.emscripten_memcpy_js = this._emscripten_memcpy_js
  137. configParam.emscripten_resize_heap = this._emscripten_resize_heap
  138. configParam.fd_write = this._fd_write
  139. configParam.fd_close = this._fd_close
  140. configParam.fd_seek = this._fd_seek
  141. configParam.emscripten_date_now = this._emscripten_date_now
  142. // configParam._emscripten_get_now_is_monotonic = this.__emscripten_get_now_is_monotonic
  143. // configParam.emscripten_get_now = this._emscripten_get_now
  144. let importObject = {}
  145. importObject.env = configParam
  146. importObject.wasi_snapshot_preview1 = configParam
  147. //importObject.a = configParam
  148. //返回值res:{instance{}, Module{}}:包含instance和Module对象,instance中也包含Module。
  149. //js使用instance或者Module中Exports对象中的函数(包括用户自定义的函数和系统函数)完成既定功能
  150. //instantiate的第一个参数为绝对路径
  151. WXWebAssembly.instantiate("wasm/aplm8000sdk.wasm", importObject).then((res) => {
  152. self.wasmInstance = res.instance//WASM模块实例
  153. self.wasmFuncs = self.wasmInstance.exports//WASM模块接口
  154. //初始化内存
  155. if (self.wasmInstance.exports['memory']) {
  156. let buf = self.wasmInstance.exports['memory'].buffer
  157. HEAP8 = new Int8Array(buf)
  158. HEAPU8 = new Uint8Array(buf)
  159. HEAP16 = new Int16Array(buf)
  160. HEAPU16 = new Uint16Array(buf)
  161. HEAP32 = new Int32Array(buf)
  162. HEAPU32 = new Uint32Array(buf)
  163. HEAPF32 = new Float32Array(buf)
  164. HEAPF64 = new Float64Array(buf)
  165. }
  166. //wasm模块初始化
  167. self.wasmFuncs.main()
  168. //获得wasm模块路由基站数据指针
  169. self.wasmDataPtr.bleBtsDataPtr = self.wasmFuncs.exchange_js_get_route_bts_save_address()
  170. //获得wasm模块安装基站的数据指针
  171. self.wasmDataPtr.installBtsDataPtr = self.wasmFuncs.exchange_js_get_install_bts_save_address()
  172. //获得wasm模块音频数据指针
  173. self.wasmDataPtr.audioDataPtr = self.wasmFuncs.exchange_js_get_audio_data_save_address()
  174. //获得wasm模块定位坐标数据指针
  175. self.wasmDataPtr.currentLocationCoordPtr = self.wasmFuncs.exchange_js_get_current_location_coord_save_address()
  176. //获得wasm模块加速度数据指针
  177. self.wasmDataPtr.accDataPtr = self.wasmFuncs.exchange_js_get_acc_save_address()
  178. //获得wasm模块软件名称和版本数据指针
  179. self.wasmDataPtr.softNameAndVersionPtr = self.wasmFuncs.exchange_js_get_soft_name_and_version_save_address()
  180. //获得wasm模块基站系统配置参数
  181. self.wasmDataPtr.btsSysConfigParamPtr = self.wasmFuncs.exchange_js_get_sys_config_param_save_address()
  182. self.injectBtsSysConfigParamToWasm()//注入数据并通知wasm模块设置基站系统配置参数
  183. //获得系统调试开关数据指针并配置调试开关
  184. self.wasmDataPtr.sysDebugSwitchPtr = self.wasmFuncs.exchange_js_get_debug_switch_data_address()
  185. self.injectSysDebugSwitchToWasm()//注入调试开关数据
  186. //通知主控模块开始监听蓝牙
  187. worker.postMessage({
  188. message: 'WORKER_MAIN_START_MONITOR_BLE_BTS',
  189. data: ''
  190. })
  191. //TODO打印软件名称与版本
  192. let softNameAndVersionPtr = self.wasmDataPtr.softNameAndVersionPtr
  193. let softName = []
  194. let softVersion = []
  195. for (let i = 0; i < 18; i++) {
  196. if (i < 11) {
  197. softName.push(HEAPU8[softNameAndVersionPtr + i])
  198. } else {
  199. softVersion.push(HEAPU8[softNameAndVersionPtr + i])
  200. }
  201. }
  202. console.log("软件版本:" + softName.map(num => String.fromCharCode(num)).join('') + " " + softVersion.map(num => String.fromCharCode(num)).join(''))
  203. }).catch((err) => {
  204. console.log("加载wasm对象出错", err)
  205. })
  206. },
  207. //保存蓝牙基站数据至本地
  208. saveBleBtsDataToLocal(dataList) {
  209. if (!dataList || dataList.length < 4) {
  210. return
  211. }
  212. //蓝牙基站监听成功,保存数据
  213. this.data.bleBtsMonitorSuccessFlag = true//蓝牙基站监听成功标识符
  214. this.data.bleBtsDataList.splice(0, this.data.bleBtsDataList.length)
  215. this.data.bleBtsDataList = dataList//保存蓝牙基站数据,并覆盖以前的数据
  216. //通知主控模块注入安装基站数据(只注入一次)
  217. if (!this.data.installBtsInjectFlag) {
  218. worker.postMessage({
  219. message: 'WORKER_MAIN_ORGANIZE_INSTALL_BTS_DATA',//通知主线程组织安装基站数据
  220. data: ''
  221. })
  222. }
  223. },
  224. //清除蓝牙基站设备(没有监听到本系统的蓝牙基站)
  225. clearBleBtsData() {
  226. this.data.bleBtsMonitorSuccessFlag = false//蓝牙基站监听失败
  227. this.data.bleBtsDataList.splice(0, this.data.bleBtsDataList.length)
  228. },
  229. //发送蓝牙基站数据至wasm模块
  230. sendBleBtsDataToWasm() {
  231. let dataList = []
  232. //监听蓝牙基站失败
  233. if (!this.data.bleBtsMonitorSuccessFlag) {
  234. return
  235. }
  236. //将数据保存至wasm模块
  237. dataList = this.data.bleBtsDataList
  238. let dataLen = dataList.length
  239. if (this.wasmDataPtr.bleBtsDataPtr > 0) {
  240. let ptr = this.wasmDataPtr.bleBtsDataPtr / 4//蓝牙基站数据在wasm模块按4字节存储
  241. for (let i = 0; i < dataLen; i++) {
  242. HEAP32[ptr + i] = dataList[i]//写入数据
  243. }
  244. } else {
  245. console.log("蓝牙指针尚未初始化")
  246. return
  247. }
  248. //清除本地蓝牙基站数据
  249. this.data.bleBtsDataList.splice(0, this.data.bleBtsDataList.length)
  250. this.data.bleBtsMonitorSuccessFlag = false
  251. // // //TODO,打印一下看看效果,正式版本要去掉
  252. // if (this.wasmFuncs != null) {
  253. // this.wasmFuncs.exchange_js_notice_wasm_show_route_bts();
  254. // }
  255. return
  256. },
  257. //发送安装基站数据至wasm模块
  258. sendInstallBtsDataToWasm(dataList) {
  259. //将数据保存至wasm模块
  260. if (this.wasmDataPtr.installBtsDataPtr > 0 && dataList.length > 0) {
  261. this.data.installBtsInjectFlag = true//注入标识符置1
  262. //向wasm模块注入数据
  263. let ptr = this.wasmDataPtr.installBtsDataPtr / 4//基站数据在wasm模块按4字节存储
  264. for (let i = 0; i < dataList.length; i++) {
  265. HEAP32[ptr + i] = dataList[i]
  266. }
  267. //向主线程发消息开始录音
  268. worker.postMessage({
  269. message: 'WORKER_MAIN_START_REC',
  270. data: ''
  271. })
  272. }
  273. // // TODO,打印一下看看效果,正式版本要去掉
  274. // if (this.wasmFuncs != null) {
  275. // this.wasmFuncs.exchange_js_notice_wasm_show_install_bts()
  276. // }
  277. },
  278. //处理音频数据,实施定位操作
  279. //buffer:录音数据,为二进制单字节(byte)数据数组
  280. processAudioData(buffer) {
  281. //注入蓝牙基站数据
  282. this.sendBleBtsDataToWasm()
  283. ////创建数据视图。
  284. //录音数据是arraryBuffer类型,该类型数据为二进制单字节(byte)数据数组,不能直接读写,需要在buffer上创建数据视图后方可操作数据
  285. const dataView = new DataView(buffer);//创建一个数据视图
  286. //遍历数据视图
  287. let sample = 0
  288. let dataLen = Math.floor(dataView.byteLength / 2) //一个采样点为两个字节
  289. if (dataLen > 0) {
  290. //把数据插入全局队列,以便实施成帧处理
  291. for (let i = 0; i < dataLen; i++) {
  292. sample = dataView.getInt16(2 * i, true)//数据大小端模式,true:小端模式,false:大端模式
  293. this.data.audioDataList.push(sample)
  294. }
  295. //计算全局队列中数据的帧数
  296. let frameCounter = Math.floor(this.data.audioDataList.length / this.data.oneFrameLen)
  297. if (frameCounter) {//至少有一帧数据
  298. //截取音频数据帧(可能是1帧,也可能是多帧。若是多帧,有可能导致处理超时)
  299. const dataList = this.data.audioDataList.splice(0, frameCounter * this.data.oneFrameLen)
  300. //把音频数据逐帧注入wasm模块
  301. let ptr = this.wasmDataPtr.audioDataPtr / 2//音频数据在wasm模块中按2字节存储
  302. for (let i = 0; i < frameCounter; i++) {
  303. // let beginTime = new Date().getTime()//开始计时
  304. //1、把数据注入wasm模块
  305. let baseIndex = i * this.data.oneFrameLen
  306. for (let j = 0; j < this.data.oneFrameLen; j++) {
  307. let item = dataList[baseIndex + j]
  308. HEAP16[ptr + j] = item//把音频数据注入wasm模块
  309. }
  310. //2、注入加速度数据
  311. let oneFrameAccDataList = []
  312. oneFrameAccDataList = this.organizeOneFrameAccData()//组织一秒加速度数据
  313. this.injectAccDataToWasm(oneFrameAccDataList)//注入数据
  314. //3、通知wasm模块处理音频数据
  315. let result = this.wasmFuncs.exchange_js_notice_wasm_start_work()
  316. // let stopTime = new Date().getTime() - beginTime//结束计时
  317. // console.log("耗时:", stopTime)
  318. //4、获取wasm模块处理音频数据的结果
  319. if (result != 1) {
  320. console.log("音频数据处理错误")
  321. } else {
  322. let item = []
  323. //定位坐标数据在wasm模块中按4字节存储
  324. let locationCoordPtr = this.wasmDataPtr.currentLocationCoordPtr / 4
  325. //a、从wasm模块读取音频数据处理结果
  326. for (let i = 0; i < 18; i++) {
  327. item.push(HEAP32[locationCoordPtr + i])
  328. }
  329. //TODO,b、使用定位结果这部分,需要二次开放商根据业务需求,做定制开发
  330. //使用定位结果
  331. if (item[0] === 1 && item[1] === 1) {
  332. let coord = {}
  333. coord.x = item[2]
  334. coord.y = item[3]
  335. //imu移动标识符
  336. const imuMoveFlag = item[17]//0:惯导计算出错,1:惯导计算成功,但手机未移动,50:惯导计算能成功,手机有移动
  337. if (imuMoveFlag == 50) {//手机有移动
  338. //将定位坐标发送至主线程
  339. worker.postMessage({
  340. message: 'WORKER_MAIN_CURRENT_LOCATION_COORD',
  341. data: coord
  342. })
  343. } else {//手机未移动或者出错
  344. console.log("imu move flag:", imuMoveFlag)
  345. }
  346. }
  347. // //向主线程发消息,通知读取音频文件
  348. // worker.postMessage({
  349. // message: 'WORKER_MAIN_NOTICE_READ_AUDIO_FILE',//读取音频文件
  350. // data: ''
  351. // })
  352. }
  353. }
  354. }
  355. }
  356. return
  357. },
  358. //缓存加速度数据
  359. storeAccData(oneAccData) {
  360. let item = {}
  361. item.timestamp = oneAccData.timestamp
  362. item.x = oneAccData.x
  363. item.y = oneAccData.y
  364. item.z = oneAccData.z
  365. this.data.accDataList.push(item)//缓存加速度
  366. },
  367. //组织一帧加速度数据(约250毫秒)
  368. organizeOneFrameAccData() {
  369. let oneFrameAccData = [] //一帧加速度数据
  370. if (this.data.accDataList.length > 0) {
  371. let stopTimestamp = this.data.accDataList[0].timestamp + 260//250毫秒的数据
  372. let accCounter = 0//计数器
  373. for (let k = 0; k < this.data.accDataList.length; k++) {
  374. let oneAcc = {}
  375. oneAcc = this.data.accDataList[k]
  376. if (oneAcc.timestamp <= stopTimestamp) {
  377. oneFrameAccData.push(oneAcc)
  378. accCounter++
  379. } else {
  380. break
  381. }
  382. }
  383. this.data.accDataList = this.data.accDataList.slice(accCounter)//截取加速度队列
  384. }
  385. return oneFrameAccData
  386. },
  387. //注入加速度到wasm模块
  388. injectAccDataToWasm(dataList) {
  389. let ptr = this.wasmDataPtr.accDataPtr / 4//加速度数据在wasm模块中按4字节存储
  390. let wLen = dataList.length;
  391. let item = {}
  392. if (wLen > 0) {
  393. //注入队列长度
  394. HEAPU32[ptr] = wLen //加速度队列长度
  395. ptr++
  396. //注入3轴加速度
  397. for (let i = 0; i < wLen; i++) {
  398. item = dataList[i]
  399. ptr = ptr + i * 3//修改数据指针,去掉时间戳数据
  400. HEAPF32[ptr] = item.x//x轴加速度
  401. HEAPF32[ptr + 1] = item.y//y轴加速度
  402. HEAPF32[ptr + 2] = item.z//z轴加速度
  403. }
  404. //保存数据
  405. this.wasmFuncs.exchange_js_notice_wasm_save_acc()
  406. }
  407. },
  408. //注入基站系统配置参数到wasm模块
  409. injectBtsSysConfigParamToWasm() {
  410. //注入数据
  411. let ptr = this.wasmDataPtr.btsSysConfigParamPtr / 4 //基站系统配置参数在wasm模块中按4字节存储
  412. HEAPU32[ptr] = 350 //基站幅度有效门限,默认值350
  413. HEAPU32[ptr + 1] = 50 // 基站SNR有效门限,默认值50
  414. HEAPU32[ptr + 2] = 1500 // 主站幅度有效门限,默认值1500
  415. HEAPU32[ptr + 3] = 35 // 基站间最大间距,单位米,默认值35
  416. HEAPU32[ptr + 4] = 102 // 三轴陀螺仪加速度门限,默认值102
  417. //通知wasm模块设置基站系统配置参数
  418. this.wasmFuncs.exchange_js_notice_wasm_set_sys_config_param()
  419. },
  420. //注入系统调试开关参数到wasm模块,以决定打印相关调试信息
  421. injectSysDebugSwitchToWasm() {
  422. //注入数据
  423. let ptr = this.wasmDataPtr.sysDebugSwitchPtr / 4 //参数在wasm模块中按4字节存储
  424. HEAPU32[ptr] = 0 //初始化阶段主站信息,0:不打印,1:打印
  425. HEAPU32[ptr + 1] = 1 // 定位基站组,0:不打印,1:打印
  426. HEAPU32[ptr + 2] = 0 // 频率同步信息,0:不打印,1:打印
  427. HEAPU32[ptr + 3] = 0 // 初步有效基站组,0:不打印,1:打印
  428. HEAPU32[ptr + 4] = 0 // 最终有效基站组(暂无效),0:不打印,1:打印
  429. HEAPU32[ptr + 5] = 1 // 路径选择,0:不打印,1:打印
  430. HEAPU32[ptr + 6] = 1 // 维度选择,0:不打印,1:打印
  431. },
  432. //通知wasm模块释放内存
  433. noticeWasmFreeMemory() {
  434. this.wasmFuncs.exchange_js_notice_wasm_free_memory()
  435. }
  436. }
  437. export default wasmapi