Added DataView class

This commit is contained in:
Gordon Williams 2017-02-28 11:54:22 +00:00
parent 15ffa96f1b
commit b383ec74b5
7 changed files with 411 additions and 11 deletions

View File

@ -15,6 +15,7 @@
nRF52: Add BluetoothRemoteGATTCharacteristic.startNotifications (fix #959)
nRF52: Added BluetoothDevice.gattserverdisconnected event
nRF5x: Report back reason codes for BLE disconnect
Added DataView class
1v91 : Fix recent regression if no Boot Code defined at startup
Fix handling of return of rejected promise within a promise

View File

@ -807,6 +807,7 @@ TARGETSOURCES =
WRAPPERSOURCES = \
src/jswrap_array.c \
src/jswrap_arraybuffer.c \
src/jswrap_dataview.c \
src/jswrap_date.c \
src/jswrap_error.c \
src/jswrap_espruino.c \

View File

@ -103,6 +103,7 @@ typedef enum {
ARRAYBUFFERVIEW_FLOAT = 32,
ARRAYBUFFERVIEW_CLAMPED = 64, // As in Uint8ClampedArray - clamp to the acceptable bounds
ARRAYBUFFERVIEW_ARRAYBUFFER = 1 | 128, ///< Basic ArrayBuffer type
ARRAYBUFFERVIEW_BIG_ENDIAN = 256, ///< access as big endian (normally little)
ARRAYBUFFERVIEW_UINT8 = 1,
ARRAYBUFFERVIEW_INT8 = 1 | ARRAYBUFFERVIEW_SIGNED,

View File

@ -316,10 +316,17 @@ ALWAYS_INLINE JsvArrayBufferIterator jsvArrayBufferIteratorClone(JsvArrayBufferI
static void jsvArrayBufferIteratorGetValueData(JsvArrayBufferIterator *it, char *data) {
if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return;
assert(!it->hasAccessedElement); // we just haven't implemented this case yet
unsigned int i,dataLen = JSV_ARRAYBUFFER_GET_SIZE(it->type);
for (i=0;i<dataLen;i++) {
data[i] = jsvStringIteratorGetChar(&it->it);
if (dataLen!=1) jsvStringIteratorNext(&it->it);
int i,dataLen = (int)JSV_ARRAYBUFFER_GET_SIZE(it->type);
if (it->type & ARRAYBUFFERVIEW_BIG_ENDIAN) {
for (i=dataLen-1;i>=0;i--) {
data[i] = jsvStringIteratorGetChar(&it->it);
if (dataLen!=1) jsvStringIteratorNext(&it->it);
}
} else {
for (i=0;i<dataLen;i++) {
data[i] = jsvStringIteratorGetChar(&it->it);
if (dataLen!=1) jsvStringIteratorNext(&it->it);
}
}
if (dataLen!=1) it->hasAccessedElement = true;
}
@ -430,21 +437,28 @@ void jsvArrayBufferIteratorSetIntegerValue(JsvArrayBufferIterator *it, JsVarInt
if (dataLen!=1) it->hasAccessedElement = true;
}
void jsvArrayBufferIteratorSetValue(JsvArrayBufferIterator *it, JsVar *value) {
void jsvArrayBufferIteratorSetValue(JsvArrayBufferIterator *it, JsVar *value) {
if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return;
assert(!it->hasAccessedElement); // we just haven't implemented this case yet
char data[8];
unsigned int i,dataLen = JSV_ARRAYBUFFER_GET_SIZE(it->type);
int i,dataLen = (int)JSV_ARRAYBUFFER_GET_SIZE(it->type);
if (JSV_ARRAYBUFFER_IS_FLOAT(it->type)) {
jsvArrayBufferIteratorFloatToData(data, dataLen, it->type, jsvGetFloat(value));
jsvArrayBufferIteratorFloatToData(data, (unsigned)dataLen, it->type, jsvGetFloat(value));
} else {
jsvArrayBufferIteratorIntToData(data, dataLen, it->type, jsvGetInteger(value));
jsvArrayBufferIteratorIntToData(data, (unsigned)dataLen, it->type, jsvGetInteger(value));
}
for (i=0;i<dataLen;i++) {
jsvStringIteratorSetChar(&it->it, data[i]);
if (dataLen!=1) jsvStringIteratorNext(&it->it);
if (it->type & ARRAYBUFFERVIEW_BIG_ENDIAN) {
for (i=dataLen-1;i>=0;i--) {
jsvStringIteratorSetChar(&it->it, data[i]);
if (dataLen!=1) jsvStringIteratorNext(&it->it);
}
} else {
for (i=0;i<dataLen;i++) {
jsvStringIteratorSetChar(&it->it, data[i]);
if (dataLen!=1) jsvStringIteratorNext(&it->it);
}
}
if (dataLen!=1) it->hasAccessedElement = true;
}

317
src/jswrap_dataview.c Normal file
View File

@ -0,0 +1,317 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* JavaScript DataView implementation
* ----------------------------------------------------------------------------
*/
#include "jswrap_dataview.h"
#include "jsvar.h"
#include "jsvariterator.h"
#include "jsparse.h"
#include "jswrap_arraybuffer.h"
/*JSON{
"type" : "class",
"class" : "DataView",
"ifndef" : "SAVE_ON_FLASH"
}
This class helps
*/
/*JSON{
"type" : "constructor",
"class" : "DataView",
"name" : "DataView",
"generate" : "jswrap_dataview_constructor",
"params" : [
["buffer","JsVar","The ArrauBuffer to base this on"],
["byteOffset","int","(optional) The offset of this view in bytes"],
["byteLength","int","(optional) The length in bytes"]
],
"return" : ["JsVar","A DataView object"],
"return_object" : "DataView",
"ifndef" : "SAVE_ON_FLASH"
}
Create a DataView object
*/
JsVar *jswrap_dataview_constructor(JsVar *buffer, int byteOffset, int byteLength) {
if (!jsvIsArrayBuffer(buffer) ||
buffer->varData.arraybuffer.type!=ARRAYBUFFERVIEW_ARRAYBUFFER) {
jsExceptionHere(JSET_TYPEERROR, "Expecting ArrayBuffer, got %t", buffer);
return 0;
}
JsVar *dataview = jspNewObject(0,"DataView");
if (dataview) {
jsvObjectSetChild(dataview, "buffer", buffer);
if (byteOffset)
jsvObjectSetChildAndUnLock(dataview, "byteOffset", jsvNewFromInteger(byteOffset));
if (byteLength)
jsvObjectSetChildAndUnLock(dataview, "byteLength", jsvNewFromInteger(byteLength));
}
return dataview;
}
JsVar *jswrap_dataview_get(JsVar *dataview, JsVarDataArrayBufferViewType type, int byteOffset, bool littleEndian) {
JsVar *buffer = jsvObjectGetChild(dataview, "buffer", 0);
if (!jsvIsArrayBuffer(buffer)) {
jsvUnLock(buffer);
return 0;
}
byteOffset += jsvGetIntegerAndUnLock(jsvObjectGetChild(dataview, "byteOffset", 0));
JsVarInt length = JSV_ARRAYBUFFER_GET_SIZE(type);
// TODO: range error based on byteLength?
if (!littleEndian) type |= ARRAYBUFFERVIEW_BIG_ENDIAN;
JsVar *arr = jswrap_typedarray_constructor(type, buffer, byteOffset, length);
jsvUnLock(buffer);
if (!arr) return 0;
JsvArrayBufferIterator it;
jsvArrayBufferIteratorNew(&it, arr, 0);
JsVar *value = jsvArrayBufferIteratorGetValue(&it);
jsvArrayBufferIteratorFree(&it);
jsvUnLock(arr);
return value;
}
void jswrap_dataview_set(JsVar *dataview, JsVarDataArrayBufferViewType type, int byteOffset, JsVar *value, bool littleEndian) {
JsVar *buffer = jsvObjectGetChild(dataview, "buffer", 0);
if (!jsvIsArrayBuffer(buffer)) {
jsvUnLock(buffer);
return;
}
byteOffset += jsvGetIntegerAndUnLock(jsvObjectGetChild(dataview, "byteOffset", 0));
JsVarInt length = JSV_ARRAYBUFFER_GET_SIZE(type);
// TODO: range error based on byteLength?
if (!littleEndian) type |= ARRAYBUFFERVIEW_BIG_ENDIAN;
JsVar *arr = jswrap_typedarray_constructor(type, buffer, byteOffset, length);
jsvUnLock(buffer);
if (!arr) return;
JsvArrayBufferIterator it;
jsvArrayBufferIteratorNew(&it, arr, 0);
jsvArrayBufferIteratorSetValue(&it, value);
jsvArrayBufferIteratorFree(&it);
jsvUnLock(arr);
}
// ============================================================================= GET
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "getFloat32",
"generate_full" : "jswrap_dataview_get(parent, ARRAYBUFFERVIEW_FLOAT32, byteOffset, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"return" : ["JsVar","the index of the value in the array, or -1"],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "getFloat64",
"generate_full" : "jswrap_dataview_get(parent, ARRAYBUFFERVIEW_FLOAT64, byteOffset, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"return" : ["JsVar","the index of the value in the array, or -1"],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "getInt8",
"generate_full" : "jswrap_dataview_get(parent, ARRAYBUFFERVIEW_INT8, byteOffset, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"return" : ["JsVar","the index of the value in the array, or -1"],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "getInt16",
"generate_full" : "jswrap_dataview_get(parent, ARRAYBUFFERVIEW_INT16, byteOffset, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"return" : ["JsVar","the index of the value in the array, or -1"],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "getInt32",
"generate_full" : "jswrap_dataview_get(parent, ARRAYBUFFERVIEW_INT32, byteOffset, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"return" : ["JsVar","the index of the value in the array, or -1"],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "getUint8",
"generate_full" : "jswrap_dataview_get(parent, ARRAYBUFFERVIEW_UINT8, byteOffset, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"return" : ["JsVar","the index of the value in the array, or -1"],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "getUint16",
"generate_full" : "jswrap_dataview_get(parent, ARRAYBUFFERVIEW_UINT16, byteOffset, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"return" : ["JsVar","the index of the value in the array, or -1"],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "getUint32",
"generate_full" : "jswrap_dataview_get(parent, ARRAYBUFFERVIEW_UINT32, byteOffset, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"return" : ["JsVar","the index of the value in the array, or -1"],
"ifndef" : "SAVE_ON_FLASH"
}
*/
// ============================================================================= SET
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "setFloat32",
"generate_full" : "jswrap_dataview_set(parent, ARRAYBUFFERVIEW_FLOAT32, byteOffset, value, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["value","JsVar","The value to write"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "setFloat64",
"generate_full" : "jswrap_dataview_set(parent, ARRAYBUFFERVIEW_FLOAT64, byteOffset, value, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["value","JsVar","The value to write"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "setInt8",
"generate_full" : "jswrap_dataview_set(parent, ARRAYBUFFERVIEW_INT8, byteOffset, value, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["value","JsVar","The value to write"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "setInt16",
"generate_full" : "jswrap_dataview_set(parent, ARRAYBUFFERVIEW_INT16, byteOffset, value, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["value","JsVar","The value to write"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "setInt32",
"generate_full" : "jswrap_dataview_set(parent, ARRAYBUFFERVIEW_INT32, byteOffset, value, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["value","JsVar","The value to write"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "setUint8",
"generate_full" : "jswrap_dataview_set(parent, ARRAYBUFFERVIEW_UINT8, byteOffset, value, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["value","JsVar","The value to write"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "setUint16",
"generate_full" : "jswrap_dataview_set(parent, ARRAYBUFFERVIEW_UINT16, byteOffset, value, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["value","JsVar","The value to write"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"ifndef" : "SAVE_ON_FLASH"
}
*/
/*JSON{
"type" : "method",
"class" : "DataView",
"name" : "setUint32",
"generate_full" : "jswrap_dataview_set(parent, ARRAYBUFFERVIEW_UINT32, byteOffset, value, littleEndian)",
"params" : [
["byteOffset","int","The offset in bytes to read from"],
["value","JsVar","The value to write"],
["littleEndian","bool","(optional) Whether to read in little endian - if false or undefined data is read as big endian"]
],
"ifndef" : "SAVE_ON_FLASH"
}
*/

18
src/jswrap_dataview.h Normal file
View File

@ -0,0 +1,18 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* JavaScript DataView Implementation
* ----------------------------------------------------------------------------
*/
#include "jsvar.h"
JsVar *jswrap_dataview_constructor(JsVar *buffer, int byteOffset, int byteLength);
JsVar *jswrap_dataview_get(JsVar *dataview, JsVarDataArrayBufferViewType type, int byteOffset, bool littleEndian);
void jswrap_dataview_set(JsVar *dataview, JsVarDataArrayBufferViewType type, int byteOffset, JsVar *value, bool littleEndian);

48
tests/test_dataview.js Normal file
View File

@ -0,0 +1,48 @@
var testsPass = 0;
var testsRun = 0;
function test(a,b) {
testsRun++;
var r = eval(a);
if (r!=eval(b)) {
console.log(a+" == "+r+" expected "+b);
} else {
testsPass++;
}
}
var ua = new Uint8Array([1,2,3,4,5,6,7,8]);
var ab = ua.buffer;
var d = new DataView(ab);
console.log(ab);
test("d.getInt8(0)", "0x01");
test("d.getInt8(1)", "0x02");
test("d.getInt8(2)", "0x03");
test("d.getInt16()", "0x0102");
test("d.getInt32()", "0x01020304");
test("d.getUint8()", "0x01");
test("d.getUint16()", "0x0102");
test("d.getUint32()", "0x01020304");
test("d.getInt8(0,true)", "0x01");
test("d.getInt16(0,true)", "0x0201");
test("d.getInt32(0,true)", "0x04030201");
test("d.getUint8(0,true)", "0x01");
test("d.getUint16(0,true)", "0x0201");
test("d.getUint32(0,true)", "0x04030201");
d.setFloat32(0,42,true)
test("d.getFloat32(0,true)", "42");
test("d.getUint32()", "10306");
d.setFloat64(0,42.42)
test("d.getFloat64(0)", "42.42");
d.setUint32(0,0x12345678,true)
test("d.getUint32(0,true)", "0x12345678");
d.setUint32(0,0x12345678)
test("d.getUint32(0)", "0x12345678");
result = testsRun==testsPass;