Commit 0c223c5e authored by Jake Read's avatar Jake Read

low level controller

parent 9b629821
...@@ -20,7 +20,6 @@ no warranty is provided, and users accept all liability. ...@@ -20,7 +20,6 @@ no warranty is provided, and users accept all liability.
#include "syserror.h" #include "syserror.h"
#include "./drivers/indicators.h" #include "./drivers/indicators.h"
#define VPUSB_NUM_SPACES 8
#define VPUSB_SPACE_SIZE 1028 #define VPUSB_SPACE_SIZE 1028
class COBSSerial { class COBSSerial {
......
...@@ -20,12 +20,9 @@ boolean writeLenBytes(unsigned char* dest, uint16_t* dptr, uint16_t len){ ...@@ -20,12 +20,9 @@ boolean writeLenBytes(unsigned char* dest, uint16_t* dptr, uint16_t len){
*/ */
// config-your-own-ll-escape-hatch // config-your-own-ll-escape-hatch
void sysError(String msg){ void debugmsg(String msg){
return;
// whatever you want,
//ERRLIGHT_ON;
uint32_t len = msg.length(); uint32_t len = msg.length();
errBuf[0] = PK_LLERR; // the ll-errmsg-key errBuf[0] = DEXKEY_DEBUGMSG; // the ll-errmsg-key
errBuf[1] = len & 255; errBuf[1] = len & 255;
errBuf[2] = (len >> 8) & 255; errBuf[2] = (len >> 8) & 255;
errBuf[3] = (len >> 16) & 255; errBuf[3] = (len >> 16) & 255;
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include "cobs.h" #include "cobs.h"
#include "ts.h" #include "ts.h"
void sysError(String msg); #define DEXKEY_DEBUGMSG 11
void debugmsg(String msg);
#endif #endif
...@@ -39,6 +39,35 @@ void ts_writeUint32(uint32_t val, unsigned char *buf, uint16_t *ptr){ ...@@ -39,6 +39,35 @@ void ts_writeUint32(uint32_t val, unsigned char *buf, uint16_t *ptr){
buf[(*ptr) ++] = (val >> 24) & 255; buf[(*ptr) ++] = (val >> 24) & 255;
} }
// pls recall the union,
union chunk_float32 {
uint8_t bytes[4];
float f;
};
/*
chunk_float32 dur_chunk = { .bytes = { bPck[ptr ++], bPck[ptr ++], bPck[ptr ++], bPck[ptr ++] } } ;
float duration = dur_chunk.f;
*/
union chunk_int32 {
uint8_t bytes[4];
int32_t num;
};
void ts_readInt32(int32_t *val, unsigned char *buf, uint16_t *ptr){
chunk_int32 wc = { .bytes = { buf[(*ptr) ++], buf[(*ptr) ++], buf[(*ptr) ++], buf[(*ptr) ++] }};
*val = wc.num;
}
void ts_writeInt32(int32_t val, unsigned char *buf, uint16_t *ptr){
chunk_int32 wc = { .num = val };
buf[(*ptr) ++] = wc.bytes[0];
buf[(*ptr) ++] = wc.bytes[1];
buf[(*ptr) ++] = wc.bytes[2];
buf[(*ptr) ++] = wc.bytes[3];
}
void ts_writeString(String val, unsigned char *buf, uint16_t *ptr){ void ts_writeString(String val, unsigned char *buf, uint16_t *ptr){
uint32_t len = val.length(); uint32_t len = val.length();
buf[(*ptr) ++] = len & 255; buf[(*ptr) ++] = len & 255;
......
...@@ -14,77 +14,16 @@ no warranty is provided, and users accept all liability. ...@@ -14,77 +14,16 @@ no warranty is provided, and users accept all liability.
#include <arduino.h> #include <arduino.h>
// -------------------------------------------------------- Routing (Packet) Keys
#define PK_PPACK 77
#define PK_PTR 88
#define PK_DEST 99
#define PK_LLERR 44
#define PK_PORTF_KEY 11
#define PK_PORTF_INC 3
#define PK_BUSF_KEY 12
#define PK_BUSF_INC 5
#define PK_BUSB_KEY 14
#define PK_BUSB_INC 5
// -------------------------------------------------------- Destination Keys (arrival layer)
#define DK_APP 100 // application codes, go to -> main
#define DK_PINGREQ 101 // ping request
#define DK_PINGRES 102 // ping reply
#define DK_RREQ 111 // read request
#define DK_RRES 112 // read response
#define DK_WREQ 113 // write request
#define DK_WRES 114 // write response
// -------------------------------------------------------- Application Keys
#define AK_MOCODE 101
// -------------------------------------------------------- MVC Endpoints
#define EP_ERRKEY 150
#define EP_ERRKEY_QUERYDOWN 151
#define EP_ERRKEY_EMPTY 153
#define EP_ERRKEY_UNCLEAR 154
#define EP_NAME 171
#define EP_DESCRIPTION 172
#define EP_NUMVPORTS 181
#define EP_VPORT 182
#define EP_PORTTYPEKEY 183
#define EP_MAXSEGLENGTH 184
#define EP_PORTSTATUS 185
#define EP_PORTBUFSPACE 186
#define EP_PORTBUFSIZE 187
#define EP_NUMVMODULES 201
#define EP_VMODULE 202
#define EP_NUMINPUTS 211
#define EP_INPUT 212
#define EP_NUMOUTPUTS 221
#define EP_OUTPUT 222
#define EP_TYPE 231
#define EP_VALUE 232
#define EP_STATUS 233
#define EP_NUMROUES 243
#define EP_ROUTE 235
// ... etc, later
// -------------------------------------------------------- Reading and Writing // -------------------------------------------------------- Reading and Writing
void ts_writeBoolean(boolean val, unsigned char *buf, uint16_t *ptr); void ts_writeBoolean(boolean val, unsigned char *buf, uint16_t *ptr);
void ts_readUint16(uint16_t *val, uint8_t *buf, uint16_t *ptr); void ts_readUint16(uint16_t *val, uint8_t *buf, uint16_t *ptr);
void ts_writeUint16(uint16_t val, unsigned char *buf, uint16_t *ptr); void ts_writeUint16(uint16_t val, unsigned char *buf, uint16_t *ptr);
void ts_writeUint32(uint32_t val, unsigned char *buf, uint16_t *ptr); void ts_writeUint32(uint32_t val, unsigned char *buf, uint16_t *ptr);
void ts_readInt32(int32_t *val, unsigned char *buf, uint16_t *ptr);
void ts_writeInt32(int32_t val, unsigned char *buf, uint16_t *ptr);
void ts_writeString(String val, unsigned char *buf, uint16_t *ptr); void ts_writeString(String val, unsigned char *buf, uint16_t *ptr);
...@@ -5,13 +5,12 @@ ...@@ -5,13 +5,12 @@
#include "comm/cobs.h" #include "comm/cobs.h"
#include "comm/cobsserial.h" #include "comm/cobsserial.h"
/*
// loadcell / stepper // loadcell / stepper
#include "lib/HX711.h" #include "lib/HX711.h"
#include "lib/AccelStepper.h" #include "lib/AccelStepper.h"
#define LOADCELL_DOUT_PIN 5 #define LOADCELL_DOUT_PIN 12
#define LOADCELL_SCK_PIN 6 #define LOADCELL_SCK_PIN 11
#define LOADCELL_OFFSET 50682624 #define LOADCELL_OFFSET 50682624
#define LOADCELL_DIVIDER 5895655 #define LOADCELL_DIVIDER 5895655
...@@ -22,6 +21,11 @@ ...@@ -22,6 +21,11 @@
HX711 loadcell; HX711 loadcell;
AccelStepper stepper(AccelStepper::DRIVER, 9, 10); AccelStepper stepper(AccelStepper::DRIVER, 9, 10);
// using A4988 step driver,
// want to limit to 1A current for thermal safety,
// vref = 8 * I_max * 0.050 // is 8 * 1A * 50mOhm
// so, target vref at 0.4v
void enableStepDriver(void){ void enableStepDriver(void){
digitalWrite(STEPPER_ENABLE_PIN, LOW); digitalWrite(STEPPER_ENABLE_PIN, LOW);
} }
...@@ -30,8 +34,6 @@ void disableStepDriver(void){ ...@@ -30,8 +34,6 @@ void disableStepDriver(void){
digitalWrite(STEPPER_ENABLE_PIN, HIGH); digitalWrite(STEPPER_ENABLE_PIN, HIGH);
} }
*/
COBSSerial* cobsSerial = new COBSSerial(); COBSSerial* cobsSerial = new COBSSerial();
void setup() { void setup() {
...@@ -39,31 +41,86 @@ void setup() { ...@@ -39,31 +41,86 @@ void setup() {
ERRLIGHT_SETUP; ERRLIGHT_SETUP;
CLKLIGHT_SETUP; CLKLIGHT_SETUP;
cobsSerial->init(); cobsSerial->init();
/*
// do application setup, // do application setup,
// EN pin on step driver // EN pin on step driver
pinMode(5, OUTPUT); pinMode(5, OUTPUT);
disableStepDriver(); disableStepDriver();
// stepper basics hello // stepper basics hello
stepper.setMaxSpeed(100); stepper.setMaxSpeed(2500);
stepper.setAcceleration(20); stepper.setAcceleration(5000);
// loacell // loacell
loadcell.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN); loadcell.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
loadcell.set_scale(LOADCELL_DIVIDER); loadcell.set_scale(LOADCELL_DIVIDER);
loadcell.set_offset(LOADCELL_OFFSET); loadcell.set_offset(LOADCELL_OFFSET);
loadcell.tare(); loadcell.tare();
*/
} }
uint8_t* pck; uint8_t* pck;
uint16_t pl = 0; uint16_t pl = 0;
uint8_t res[1024];
uint16_t rl = 0;
#define DEXKEY_LOADCELLREADING 12
#define DEXKEY_LOADCELLTARE 14
#define DEXKEY_STEPS 15
#define DEXKEY_MOTORENABLE 16
uint16_t one = 1;
int32_t stepsToTake = 0;
int32_t position = 0;
void loop() { void loop() {
stepper.run();
cobsSerial->loop(); cobsSerial->loop();
if(cobsSerial->hasPacket()){ if(cobsSerial->hasPacket()){
CLKLIGHT_TOGGLE; CLKLIGHT_TOGGLE;
cobsSerial->getPacket(&pck, &pl); cobsSerial->getPacket(&pck, &pl);
cobsSerial->sendPacket(pck, pl); switch(pck[0]){
case DEXKEY_LOADCELLREADING:
if(loadcell.is_ready()){
int32_t reading = loadcell.get_value(10);
rl = 0;
res[rl ++] = DEXKEY_LOADCELLREADING;
ts_writeInt32(reading, res, &rl);
debugmsg("reads: " + String(reading));
} else {
debugmsg("loadcell not ready");
}
break;
case DEXKEY_LOADCELLTARE:
loadcell.tare();
rl = 0;
res[rl ++] = DEXKEY_LOADCELLTARE;
break;
case DEXKEY_STEPS:
stepsToTake = 0;
one = 1;
ts_readInt32(&stepsToTake, pck, &one);
debugmsg("to take steps: " + String(stepsToTake));
stepper.runToNewPosition(position + stepsToTake);
position += stepsToTake;
rl = 0;
res[rl ++] = DEXKEY_STEPS;
ts_writeInt32(stepsToTake, res, &rl);
break;
case DEXKEY_MOTORENABLE:
rl = 0;
res[rl ++] = DEXKEY_MOTORENABLE;
if(pck[1] > 0){
enableStepDriver();
res[rl ++] = 1;
} else {
disableStepDriver();
res[rl ++] = 0;
}
default:
// no-op
break;
}
if(rl > 0){
cobsSerial->sendPacket(res, rl);
}
cobsSerial->clearPacket(); cobsSerial->clearPacket();
} }
} // end loop } // end loop
...@@ -16,7 +16,7 @@ no warranty is provided, and users accept all liability. ...@@ -16,7 +16,7 @@ no warranty is provided, and users accept all liability.
import GRIDSQUID from './drawing/gridsquid.js' import GRIDSQUID from './drawing/gridsquid.js'
import { TS, PK, DK, AK, EP } from '../core/ts.js' import { TS } from '../core/ts.js'
import * as dat from './libs/dat.gui.module.js' import * as dat from './libs/dat.gui.module.js'
...@@ -27,7 +27,7 @@ console.log("hello-dex-tools") ...@@ -27,7 +27,7 @@ console.log("hello-dex-tools")
document.addEventListener('keydown', (evt) => { document.addEventListener('keydown', (evt) => {
console.log(`keycode ${evt.keyCode}`) console.log(`keycode ${evt.keyCode}`)
switch (evt.keyCode) { switch (evt.keyCode) {
case 69: // 'e' case 80: // 'p'
if(wscPort.send){ if(wscPort.send){
console.log('pinging...') console.log('pinging...')
wscPort.send(Uint8Array.from([0,1,2])) wscPort.send(Uint8Array.from([0,1,2]))
...@@ -36,20 +36,164 @@ document.addEventListener('keydown', (evt) => { ...@@ -36,20 +36,164 @@ document.addEventListener('keydown', (evt) => {
} }
break; break;
case 82: // 'r' case 82: // 'r'
// read loadcell,
console.log('reading cell...')
dex.readLoadcell().then((count) => {
console.log('resolves count', count)
}).catch((err) => {
console.error(err)
})
break; break;
case 80: // 'p' case 69: // 'e'
dex.setMotorEnable(true).then((val) => {
console.log('motor is ', val)
}).catch((err) => {
console.error(err)
})
break;
case 68: // 'd'
dex.setMotorEnable(false).then((val) => {
console.log('motor is ', val)
}).catch((err) => {
console.error(err)
})
break; break;
case 83: // 's' case 83: // 's'
dex.step(-10000).then((increment) => {
console.log('motor stepped', increment)
}).catch((err) => {
console.error(err)
})
break; break;
} }
}) })
// -------------------------------------------------------- DEX Virtual Machine
let TIMEOUT_MS = 5000
let DEXKEY_DEBUGMSG = 11
let DEXKEY_LOADCELLREADING = 12
let DEXKEY_LOADCELLTARE = 14
let DEXKEY_STEPS = 15
let DEXKEY_MOTORENABLE = 16
let dex = {}
dex.readLoadcell = () => {
return new Promise((resolve, reject) => {
if(!wscPort.send){
reject('port to dex is closed')
return
}
wscPort.send((Uint8Array.from([DEXKEY_LOADCELLREADING])))
let rejected = false
dex.recv = (data) => {
if(rejected) return // if already timed out... don't get confused
if(data[0] != DEXKEY_LOADCELLREADING){
reject('oddball key after loadcell request')
} else {
let counts = TS.read('int32', data, 1, true)
resolve(counts)
}
}
setTimeout(() => {
rejected = true
reject('timeout')
}, TIMEOUT_MS)
})
}
dex.tareLoadcell = () => {
return new Promise((resolve, reject) => {
if(!wscPort.send){
reject('port to dex is closed')
return
}
wscPort.send(Uint8Array.from([DEXKEY_LOADCELLTARE]))
let rejected = false
dex.recv = (data) => {
if(rejected) return
if(data[0] != DEXKEY_LOADCELLTARE){
reject('oddball key after loadcell tare request')
} else {
resolve()
}
}
setTimeout(() => {
rejected = true
reject('timeout')
}, TIMEOUT_MS)
})
}
dex.setMotorEnable = (val) => {
return new Promise((resolve, reject) => {
if(!wscPort.send){
reject('port to dex is closed')
return
}
let ob = 0
if(val) ob = 1
wscPort.send(Uint8Array.from([DEXKEY_MOTORENABLE, ob]))
let rejected = false
dex.recv = (data) => {
if(rejected) return
if(data[0] != DEXKEY_MOTORENABLE){
reject('oddball key after motor enable request')
} else {
if(data[1] > 0){
resolve('enabled')
} else {
resolve('disabled')
}
}
} // end recv
setTimeout(() => {
rejected = true
reject('timeout')
}, TIMEOUT_MS)
})
}
dex.step = (count) => {
return new Promise((resolve, reject) => {
if(!wscPort.send){
reject('port to dex is closed')
return
}
let req = new Uint8Array(5)
req[0] = DEXKEY_STEPS
TS.write('int32', count, req, 1, true)
wscPort.send(req)
let rejected = false
dex.recv = (data) => {
if(rejected) return
if(data[0] != DEXKEY_STEPS){
reject('oddball key after step request')
} else {
let increment = TS.read('int32', data, 1, true)
resolve(increment)
}
} // end recv
setTimeout(() => {
rejected = true
reject('timeout')
}, TIMEOUT_MS)
})
}
// -------------------------------------------------------- SPAWNING TEST SUBS // -------------------------------------------------------- SPAWNING TEST SUBS
let wscPort = {} let wscPort = {}
wscPort.send = null wscPort.send = null
wscPort.onReceive = (data) => { wscPort.onReceive = (data) => {
console.warn('recv', data) // put ll-msg catch flag here,
if(data[0] == DEXKEY_DEBUGMSG){
let msg = TS.read('string', data, 1, true)
console.warn('DEX DEBUGMSG: ', msg.value)
} else {
dex.recv(data)
}
} }
let LOGPHY = false let LOGPHY = false
......
/* /*
ts.js // typeset ts.js // typeset
serialization, keys for OSAP serialization, keys for DEX
Jake Read at the Center for Bits and Atoms Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2020 (c) Massachusetts Institute of Technology 2020
...@@ -12,157 +12,12 @@ Copyright is retained and must be preserved. The work is provided as is; ...@@ -12,157 +12,12 @@ Copyright is retained and must be preserved. The work is provided as is;
no warranty is provided, and users accept all liability. no warranty is provided, and users accept all liability.
*/ */
// 13: \r
// 10: \n
// these should be clearly delimited as L1 / L2 possible keys...
// packet keys, for l0 of packets,
// PKEYS all need to be on the same byte order, since they're
// walked
// TRANSPORT LAYER
let PK = {
PPACK: 77, // this and following two bytes are rcrxb size
PTR: 88, // packet pointer (next byte is instruction)
DEST: 99, // have arrived, (next bytes are 16b checksum)
LLERR: 44,
PORTF: {
KEY: 11, // actual instruction key,
INC: 3 // number of bytes in instruction argument + 1 for the key
},
BUSF: {
KEY: 12,
INC: 5
},
BUSB: {
KEY: 14,
INC: 5,
}
}
// ARRIVAL LAYER (what do to once received packet / passed checksum)
// destination keys
let DK = {
APP: 100, // next bytes are for your application,
PINGREQ: 101, // next byte is ping-id | eop
PINGRES: 102, // next byte is ping-id | eop
RREQ: 111, // read request, next byte is request-id, then ENDPOINTS,
RRES: 112, // response, next byte is request-id, then ENDPOINTS
WREQ: 113, // write request,
WRES: 114, // write response,
}
// application keys
let AK = {
MOCODE: 101
}
// could do like
// ITEMS.key / .serialize / .deserialize
// the mess is down here
// the idea is that any unique endpoint has one routine to
// serialize / deserialze. these are for the mvc layer,
// typed objects will get a similar set
// perhaps, i.e, some of these should be like 'numinputs'
// or 'numports', etc ... unclear to me how to query down-tree
let EP = {
ERR: {
KEY: 150,
KEYS: {
QUERYDOWN: 151, // selected chunk too large for single segment, go finer grain
MSG: 152, // generic error message
EMPTY: 153, // resource queried for not here
UNCLEAR: 154, // bad request / query
NOREAD: 155, // no reading supported for this,
NOWRITE: 156, // rejected write request: writing not available here
WRITEREJECT: 157, // writing OK here, but not with this value ?
}
},
// anything can include:
NAME: {
KEY: 171,
},
DESCRIPTION: {
KEY: 172,
},
// number of vPorts, at node,