Skip to content

Commit

Permalink
release
Browse files Browse the repository at this point in the history
  • Loading branch information
cfry committed Jul 7, 2019
1 parent 2636509 commit 364272d
Show file tree
Hide file tree
Showing 27 changed files with 723 additions and 259 deletions.
5 changes: 3 additions & 2 deletions core/instruction.js
Original file line number Diff line number Diff line change
Expand Up @@ -2391,9 +2391,10 @@ Instruction.start_job = class start_job extends Instruction{
if(job_name === undefined){
dde_error("start_job was not passed a <b>job_name</b> which is required.")
}
if(typeof(job_name) != "string"){
if((typeof(job_name) != "string") && !(job_name instanceof Job)){
dde_error("start_job was passed an invalid <b>job_name</b> of: " + job_name + "<br/>" +
"It must be a Job instance or the string of a Job name.")
"It must be a Job instance,<br/>the string of a Job name<br/>" +
"or the string of a file containing a Job definition.")
}
this.job_name = job_name
this.start_options = start_options
Expand Down
65 changes: 57 additions & 8 deletions core/job.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,15 @@ class Job{
if (!Job.is_plausible_when_stopped_value(when_stopped)) {
dde_error("new Job passed: " + when_stopped + " but that isn't a valid value.")
}
this.orig_args = {do_list: do_list, robot: robot,
keep_history: keep_history, show_instructions: show_instructions,
inter_do_item_dur: inter_do_item_dur, user_data: user_data,
this.orig_args = {do_list: do_list,
robot: robot,
keep_history: keep_history,
show_instructions: show_instructions,
inter_do_item_dur: inter_do_item_dur,
user_data: user_data,
default_workspace_pose: default_workspace_pose,
program_counter: program_counter, ending_program_counter: ending_program_counter,
program_counter: program_counter,
ending_program_counter: ending_program_counter,
initial_instruction: initial_instruction,
data_array_transformer: data_array_transformer,
start_if_robot_busy: start_if_robot_busy,
Expand All @@ -80,7 +84,7 @@ class Job{
//setup name
Job.job_id_base += 1
this.job_id = Job.job_id_base
if ((name == null) || (name == "")){ this.name = "job_" + this.job_id }
if ((name == null) || (name == "")){ this.name = Job.generate_default_name() }//"job_" + this.job_id }
else { this.name = name }
//setup robot
if (!(robot instanceof Robot)){
Expand Down Expand Up @@ -113,6 +117,14 @@ class Job{
}
} //end constructor

static generate_default_name(){
for(let i = 2; i < 1000000; i++){
let candidate = "job" + i
if (!Job[candidate]) { return candidate }
}
dde_error("Job.generate_default_name has found a million job names in use. Seems unlikely.")
}

static class_init(){ //inits the Job class as a whole. called by ready
this.job_default_params =
{name: null, robot: Robot.dexter0, do_list: [],
Expand Down Expand Up @@ -279,6 +291,12 @@ class Job{
}
}

//a job that, when passed to start_and_monitor_dexter_job, will start the job
//in "path" (on Dexter). The job specified by the path will be run on Dexter
generate_run_dexter_job(path){

}

//Called by user to start the job and "reinitialize" a stopped job
start(options={}){ //sent_from_job = null
if(this.wait_until_this_prop_is_false) { this.wait_until_this_prop_is_false = false } //just in case previous running errored before it could set this to false, used by start_objects
Expand Down Expand Up @@ -991,9 +1009,10 @@ Job.remember_job_name = function(job_name){
if (!Job.all_names.includes(job_name)){
Job.all_names.push(job_name)
if(window["job_or_robot_to_simulate_id"]){
let a_option = document.createElement("option");
a_option.innerText = "Job." + job_name
job_or_robot_to_simulate_id.prepend(a_option)
refresh_job_or_robot_to_simulate_id()
//let a_option = document.createElement("option");
//a_option.innerText = "Job." + job_name
//job_or_robot_to_simulate_id.prepend(a_option)
}
}
}
Expand Down Expand Up @@ -1157,13 +1176,43 @@ Job.prototype.status = function (){
}
}


//if the job errored, the robot is a dexter, and the error code is in the 600's,
//and we're not simulating, then try to show the user the Dexter's errors.log file
//in the output pane.
Job.prototype.show_error_log_maybe = function(){
let rob = this.robot
if(rob instanceof Dexter){
const sim_actual = Robot.get_simulate_actual(rob.simulate)
if ((sim_actual === false) || (sim_actual === "both")) {
if((this.status_code == "errored") &&
(rob.rs.error_code() >= 600) &&
(rob.rs.error_code() < 700)){
let path = rob.name + ":" + "../errors.log"
read_file_async(path,
undefined,
function(err, content){
if(err) {
warning("Could not get " + path + "<br/>Error: " + err)
}
else {
content = replace_substrings(content, "\n", "<br/>")
out("<b>" + rob_name + ":/srv/samba/share/errors.log</b> content:<br/>" + content)
}
})
}
}
}
}

Job.prototype.finish_job = function(perform_when_stopped=true){ //regardless of more to_do items or waiting for instruction, its over.
if ((this.when_stopped == "stop") || !perform_when_stopped){
this.robot.finish_job()
if(this.robot instanceof Dexter) { this.robot.remove_from_busy_job_array(this)} //sometimes a job might be busy and the user clicks its stop button. Let's clean up after that!
this.color_job_button()
this.show_progress_maybe()
out("Done with job: " + this.name + " for reason: " + this.stop_reason)
this.show_error_log_maybe()
}
else{ //we don't have "stop" and we are performming the when_stopped action
let job_instance = this //for closure
Expand Down
40 changes: 31 additions & 9 deletions core/robot.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ var Robot = class Robot {
else { return rob_class.all_names.length > 0 }
}

static default_robot_name(){
/*never called July 6, 2019 static default_robot_name(){
if (Robot.all_names.length > 0){
return Robot.all_names[Robot.all_names.length - 1]
}
else {
return "r1"
}
}
}*/
//put the new item on the end, even if ypu have to remove it from the middle,
//because we want the latest on the end for default_robot_name
static set_robot_name(name, robot_instance){
Expand All @@ -52,7 +52,9 @@ var Robot = class Robot {
job_or_robot_to_simulate_id.prepend(a_option)
}
//for Make Instance dialog
if (i == -1){ MakeInstruction.add_robot_to_job_wrapper_robot_menu_maybe(robot_instance) }
if ((i == -1) && window["add_robot_to_default_menu"]) {
add_robot_to_default_menu(robot_instance)
}
}
static get_simulate_actual(simulate_val){
if (simulate_val === true) { return true }
Expand Down Expand Up @@ -855,29 +857,38 @@ Serial.prototype.string_instruction = function(instruction_string){
//the pose matrix includes info on position and orientation
* */
Dexter = class Dexter extends Robot {
constructor({name = "dex1",
constructor({name = null,
simulate = null,
ip_address = null,
port = null,
pose = Vector.identity_matrix(4),
enable_heartbeat=true,
is_calibrated=null, //means calibration status is unknown.
instruction_callback = Job.prototype.set_up_next_do}={}){
for(let key in arguments[0]){
if(!["name", "simulate", "ip_address", "port", "pose", "enable_heartbeat", "instruction_callback"].includes(key)){
dde_error("Attempt to create a Dexter with an invalid argument of: " + key +
"<br/>Click on 'Dexter' to see its valid argument names.")
}
}
if(!name) {
name = Dexter.generate_default_name()
}
if((name.length == 1) && (name >= "A") && (name <= "Z")){
dde_error("While construction a Dexter robot named: " + name +
"<br/>Sorry, you can't name a Dexter with a single upper case letter.")
}
if(!ip_address) { ip_address = persistent_get("default_dexter_ip_address") }
if(!port) { port = persistent_get("default_dexter_port") }

let keyword_args = {name: name, simulate: simulate, ip_address: ip_address, port: port,
let keyword_args = {name: name,
simulate: simulate,
ip_address: ip_address,
port: port,
pose: pose,
enable_heartbeat: enable_heartbeat, instruction_callback: instruction_callback }
enable_heartbeat: enable_heartbeat,
is_calibrated: is_calibrated,
instruction_callback: instruction_callback }
let old_same_named_robot = Robot[name]
if (old_same_named_robot){
if ((old_same_named_robot.ip_address === ip_address) &&
Expand Down Expand Up @@ -928,6 +939,16 @@ Dexter = class Dexter extends Robot {
}
}

static generate_default_name(){
for(let i = 1; i < 1000000; i++) {
let candidate_name = "dexter" + i
if(!Dexter[candidate_name]) {
return candidate_name
}
}
dde_error("When making an instance of Dexter,<br/>the first million default names are used.<br/> Probably something wrong.")
}

static class_init(){ //inits Dexter class as a whole. called by ready
this.dexter_default_params =
{name: "dex1",
Expand Down Expand Up @@ -955,7 +976,7 @@ Dexter = class Dexter extends Robot {
}

make_new_robot(keyword_args){
this.is_calibrated = null //null means calibration status is unknown.
this.is_calibrated = keyword_args.is_calibrated //null means calibration status is unknown.
this.name = keyword_args.name
this.ip_address = keyword_args.ip_address
this.port = keyword_args.port
Expand Down Expand Up @@ -1115,8 +1136,8 @@ Dexter = class Dexter extends Robot {
//returns undefined. Only if is_calibrate is not null (hasn't been set),
//and robut is not simulate only and we have a robot_status do we set is_calibrated on the dexter instance
set_is_calibrated(){
if(this.is_calibrated !== null) {} //means it is already set to true or false.
else if (Robot.get_simulate_actual(this.simulate) == true) {} //since we aren't sending in structions to the Dextr5er, we can't set the value
//if(this.is_calibrated !== null) {} //means it is already set to true or false.
if (Robot.get_simulate_actual(this.simulate) == true) {} //since we aren't sending in structions to the Dexter, we can't set the value
else {
let rs_line = last(this.robot_status)
for(let measured_angle of this.joint_angles()) {
Expand All @@ -1125,6 +1146,7 @@ Dexter = class Dexter extends Robot {
return
}
}
//all 5 meansured angles are 0
this.is_calibrated = false
}
}
Expand Down
2 changes: 2 additions & 0 deletions core/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ var Socket = class Socket{
//let elt = oplet_array_or_string[i] + suffix
let elt = oplet_array_or_string[i]
if (Number.isNaN(elt)) { elt = "NaN" } //usually only for "a" instructions and only for elts > 4
//looks like this is never used now because I convert from NaN to the prev val
//in the the higher level code so only numbers get passed to DexRun.
elt = elt + suffix
str += elt
}
Expand Down
8 changes: 7 additions & 1 deletion core/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,13 @@ function adjust_path_to_os(path){
//this will do nothing. So on a windows machine, that's ok,
//but on a mac or linux, that's bad. But this is unlikely to
//happen on a mac or linus, esp since dde standard is slash.
const result = path.replace(/\//g, folder_separator())
let result = path.replace(/\//g, folder_separator())
//we might have a path like \C:\foo.txt in which case, take off the initial backslash
if(result.startsWith("\\") &&
(result.length == 3) &&
(result[2] == ":")) {
result = result.substring(1)
}
return result
}
}
Expand Down
12 changes: 7 additions & 5 deletions core/to_source_code.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
function to_source_code({value, indent="", function_names=false, newObject_paths=false,
job_names=false, robot_names=false,
depth_limit=Infinity, depth=0, job_orig_args=false} = {}){
depth_limit=Infinity, depth=0, job_orig_args=false,
one_line_per_array_elt=false, array_elt_max_chars=60} = {}){
//console.log("top of to_source_code with value: " + value + " arguments: " + arguments)
//console.log("Object.isNewObject: " + Object.isNewObject)
if (!((typeof(arguments[0]) == "object") && arguments[0].hasOwnProperty("value"))){
Expand Down Expand Up @@ -57,22 +58,23 @@ function to_source_code_array(args){
let chars_added_since_last_newline = 0
let result = "["
let len = value.length
let max_chars = (args.array_elt_max_chars ? args.array_elt_max_chars : 60)
for (let i = 0; i < len; i++){ //don't use "for ... in here as it gets some wrong stuff
let prefix = ""
let val = value[i]
let val_str = to_source_code({value: val})
let val_str = to_source_code({value: val, array_elt_max_chars: max_chars})
let comma_maybe = ((i < (len - 1)) ? "," : "")
let newline_or_space_suffix = ((i == (len - 1))? "" : " ")
let str_and_suffix_len = val_str.length
if (args.one_line_per_array_elt) { newline_or_space_suffix = "\n" }
else if (chars_added_since_last_newline > 60) {
else if (chars_added_since_last_newline > max_chars) {
prefix = "\n"
chars_added_since_last_newline = str_and_suffix_len
}
else if ((chars_added_since_last_newline == 0) && (val_str.length > 60)) {
else if ((chars_added_since_last_newline == 0) && (val_str.length > max_chars)) {
chars_added_since_last_newline = str_and_suffix_len //add it in the usual way
}
else if ((chars_added_since_last_newline + str_and_suffix_len) > 60) {
else if ((chars_added_since_last_newline + str_and_suffix_len) > args.array_elt_max_chars) {
prefix = "\n"
chars_added_since_last_newline = str_and_suffix_len
}
Expand Down
31 changes: 25 additions & 6 deletions core/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,19 @@ function flatten(arr, result=[]){
}
module.exports.flatten = flatten

function is_array_of_numbers(a_array){
if(!Array.isArray(a_array)) { return false }
else {
for(let num of a_array){
if(typeof(num) != "number") {
return false
}
}
return true
}
}
module.exports.is_array_of_numbers = is_array_of_numbers

//used by inspector for printing 2D arrays
function is_array_of_same_lengthed_arrays(array){
if (array.length === 0) { return false }
Expand Down Expand Up @@ -1075,35 +1088,41 @@ function params_string_to_param_names_and_defaults(params_full_string){
//and get back the names of the args in their proper order.
function function_param_names_and_defaults_lit_obj(fn){
let params_full_string = function_params(fn, false)
let params_string = params_full_string
//let params_string = params_full_string
if (params_full_string.startsWith("{")){
if (params_full_string.endsWith("= {}") ||
params_full_string.endsWith("={}")){
let closing_equal = params_full_string.lastIndexOf("=")
params_string = params_full_string.substring(0, closing_equal).trim()
params_full_string = params_full_string.substring(0, closing_equal).trim()
}
params_string = replace_substrings(params_string, "\\n", " ")
//cut off both open and close brace
if(params_full_string.endsWith("}")) { params_full_string = params_full_string.substring(0, params_full_string.length - 1) }
params_full_string = params_full_string.substring(1)
}
/* params_string = replace_substrings(params_string, "\\n", " ")
var inner_params_and_defaults = params_string.substring(1, params_string.length -1) //cut off { and }
var inner_params_and_defaults_array = inner_params_and_defaults.split(",")
var param_names = []
for(let inner_param_and_default of inner_params_and_defaults_array){
inner_param_and_default = inner_param_and_default.trim()
let the_param_default_array = inner_param_and_default.split("=")
the_param_default_array[0] = the_param_default_array[0].trim()
the_param_default_array[1] = the_param_default_array[1].trim()
if(typeof(the_param_default_array[1]) == "string") { //ie there is a default
the_param_default_array[1] = the_param_default_array[1].trim()
}
param_names.push(the_param_default_array)
//obj[the_param_default_array[0]] = the_param_default_array[1]
}
return [param_names, "{}"]
}
else {
else {*/
let array_of_arrays = params_string_to_param_names_and_defaults(params_full_string)
let result = {}
for (let name_val of array_of_arrays) {
result[name_val[0]] = name_val[1]
}
return result
}
//}
}

module.exports.function_param_names_and_defaults_lit_obj = function_param_names_and_defaults_lit_obj
Expand Down
10 changes: 9 additions & 1 deletion doc/guide.html
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,15 @@ <h5>Step 3</h5>
<ol><li><b>Create</b> an instruction by choosing it from <button>Instruction&#9660;</button></li>
<li><b>Edit</b> both the instruction name and the argument type-in fields.
If you edit the instruction name and hit the ENTER key, it
will recompute the arguments for the new instruction name.</li>
will recompute the arguments for the new instruction name.
<p></p>
Values for instruction properties can be JS source code.
For example, a distance that is normally in meters can
be entered in as inches via: <code> 6 * _in </code> &nbsp;
This source will appear when you insert the instruction in the editor
buffer. You can also select property values and click the <button>Eval</button>
button to see the result.
</li>
<li><b>Debug</b> those values by clicking <button>Eval Instr</button>.
This evaluates each argument and highlights the first one that errors.
This will catch syntactic bugs and a few others.
Expand Down
Loading

0 comments on commit 364272d

Please sign in to comment.