Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Jake Read
displacementexercise
Commits
0c223c5e
Commit
0c223c5e
authored
Jul 06, 2020
by
Jake Read
Browse files
low level controller
parent
9b629821
Changes
9
Hide whitespace changes
Inline
Side-by-side
controller/embedded/src/comm/cobsserial.h
View file @
0c223c5e
...
...
@@ -20,7 +20,6 @@ no warranty is provided, and users accept all liability.
#include
"syserror.h"
#include
"./drivers/indicators.h"
#define VPUSB_NUM_SPACES 8
#define VPUSB_SPACE_SIZE 1028
class
COBSSerial
{
...
...
controller/embedded/src/comm/syserror.cpp
View file @
0c223c5e
...
...
@@ -20,12 +20,9 @@ boolean writeLenBytes(unsigned char* dest, uint16_t* dptr, uint16_t len){
*/
// config-your-own-ll-escape-hatch
void
sysError
(
String
msg
){
return
;
// whatever you want,
//ERRLIGHT_ON;
void
debugmsg
(
String
msg
){
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
[
2
]
=
(
len
>>
8
)
&
255
;
errBuf
[
3
]
=
(
len
>>
16
)
&
255
;
...
...
controller/embedded/src/comm/syserror.h
View file @
0c223c5e
...
...
@@ -6,6 +6,8 @@
#include
"cobs.h"
#include
"ts.h"
void
sysError
(
String
msg
);
#define DEXKEY_DEBUGMSG 11
void
debugmsg
(
String
msg
);
#endif
controller/embedded/src/comm/ts.cpp
View file @
0c223c5e
...
...
@@ -39,6 +39,35 @@ void ts_writeUint32(uint32_t val, unsigned char *buf, uint16_t *ptr){
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
){
uint32_t
len
=
val
.
length
();
buf
[(
*
ptr
)
++
]
=
len
&
255
;
...
...
controller/embedded/src/comm/ts.h
View file @
0c223c5e
...
...
@@ -14,77 +14,16 @@ no warranty is provided, and users accept all liability.
#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
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_writeUint16
(
uint16_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
);
controller/embedded/src/main.cpp
View file @
0c223c5e
...
...
@@ -5,13 +5,12 @@
#include
"comm/cobs.h"
#include
"comm/cobsserial.h"
/*
// loadcell / stepper
#include
"lib/HX711.h"
#include
"lib/AccelStepper.h"
#define LOADCELL_DOUT_PIN
5
#define LOADCELL_SCK_PIN
6
#define LOADCELL_DOUT_PIN
12
#define LOADCELL_SCK_PIN
11
#define LOADCELL_OFFSET 50682624
#define LOADCELL_DIVIDER 5895655
...
...
@@ -22,6 +21,11 @@
HX711
loadcell
;
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
){
digitalWrite
(
STEPPER_ENABLE_PIN
,
LOW
);
}
...
...
@@ -30,8 +34,6 @@ void disableStepDriver(void){
digitalWrite
(
STEPPER_ENABLE_PIN
,
HIGH
);
}
*/
COBSSerial
*
cobsSerial
=
new
COBSSerial
();
void
setup
()
{
...
...
@@ -39,31 +41,86 @@ void setup() {
ERRLIGHT_SETUP
;
CLKLIGHT_SETUP
;
cobsSerial
->
init
();
/*
// do application setup,
// EN pin on step driver
pinMode
(
5
,
OUTPUT
);
disableStepDriver
();
// stepper basics hello
stepper.setMaxSpeed(
1
00);
stepper.setAcceleration(
2
0);
stepper
.
setMaxSpeed
(
25
00
);
stepper
.
setAcceleration
(
500
0
);
// loacell
loadcell
.
begin
(
LOADCELL_DOUT_PIN
,
LOADCELL_SCK_PIN
);
loadcell
.
set_scale
(
LOADCELL_DIVIDER
);
loadcell
.
set_offset
(
LOADCELL_OFFSET
);
loadcell
.
tare
();
*/
}
uint8_t
*
pck
;
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
()
{
stepper
.
run
();
cobsSerial
->
loop
();
if
(
cobsSerial
->
hasPacket
()){
CLKLIGHT_TOGGLE
;
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
();
}
}
// end loop
controller/js/client/dex-client.js
View file @
0c223c5e
...
...
@@ -16,7 +16,7 @@ no warranty is provided, and users accept all liability.
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
'
...
...
@@ -27,7 +27,7 @@ console.log("hello-dex-tools")
document
.
addEventListener
(
'
keydown
'
,
(
evt
)
=>
{
console
.
log
(
`keycode
${
evt
.
keyCode
}
`
)
switch
(
evt
.
keyCode
)
{
case
69
:
// '
e
'
case
80
:
// '
p
'
if
(
wscPort
.
send
){
console
.
log
(
'
pinging...
'
)
wscPort
.
send
(
Uint8Array
.
from
([
0
,
1
,
2
]))
...
...
@@ -36,20 +36,164 @@ document.addEventListener('keydown', (evt) => {
}
break
;
case
82
:
// 'r'
// read loadcell,
console
.
log
(
'
reading cell...
'
)
dex
.
readLoadcell
().
then
((
count
)
=>
{
console
.
log
(
'
resolves count
'
,
count
)
}).
catch
((
err
)
=>
{
console
.
error
(
err
)
})
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
;
case
83
:
// 's'
dex
.
step
(
-
10000
).
then
((
increment
)
=>
{
console
.
log
(
'
motor stepped
'
,
increment
)
}).
catch
((
err
)
=>
{
console
.
error
(
err
)
})
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
let
wscPort
=
{}
wscPort
.
send
=
null
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
...
...
controller/js/core/ts.js
View file @
0c223c5e
/*
ts.js // typeset
serialization, keys for
OSAP
serialization, keys for
DEX
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2020
...
...
@@ -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.
*/
// 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,
NUMVPORTS
:
{
KEY
:
181
,
// count of vPorts at node
},
// this vPort (always succeeded by indice)
VPORT
:
{
KEY
:
182
,
ISDIVE
:
true
,
},
// vPort-unique keys,
PORTTYPEKEY
:{
KEY
:
183
,
},
MAXSEGLENGTH
:
{
KEY
:
184
,
// uint32 num-bytes-per-fwded-pck allowed on this phy
},
PORTSTATUS
:
{
KEY
:
185
,
CLOSED
:
0
,
OPEN
:
1
,
CLOSING
:
2
,
OPENING
:
3
},
PORTBUFSPACE
:
{
KEY
:
186
,
// num empty frames in port
},
PORTBUFSIZE
:
{
KEY
:
187
,
},
// I currently have *no idea* how will handle bus drops:
// perhaps they are mostly like outputs, in the vPort... typed, have value, ok
// number of vModules, at node,
NUMVMODULES
:{
KEY
:
201
,
},
// this vmodule, (always succeeded by indice)
VMODULE
:
{
KEY
:
202
,
ISDIVE
:
true
,
},
// vPorts, vModules can both have inputs, outputs,
NUMINPUTS
:
{
KEY
:
211
,
},
INPUT
:
{
// this input (always succeeded by indice)
KEY
:
212
,
ISDIVE
:
true
,
},
NUMOUTPUTS
:
{
KEY
:
221
,
},
OUTPUT
:
{
// this output (always succeeded by indice)
KEY
:
222
,
ISDIVE
:
true
,
},
// inputs / outputs can have: (in addnt to name, description)
TYPE
:
{
// not the same as port-type, key or key(s) for compound types
KEY
:
231
,
},
VALUE
:
{
// data bytes currently occupying the output / input
KEY
:
232
,
},
STATUS
:
{
KEY
:
233
,
// boolean open / closed, occupied / unoccupied, etc
},
// outputs have:
NUMROUTES
:
{
KEY
:
234
,