/* Demo Hidprobe Script Applications bl_fsm, version 0.4, 29 November 2008, FSM (Finite State Machine) version for event handlers Customisable bootloader script for embedded devices using Hidprobe, http://www.zgus.com/hid. Code uploaded may be secure firmware. This script does not need to know. Rename file from bl_fsm_js.txt to bl_fsm.js for ease of editing and ease of loading to Hidprobe. For the file to be passed through to an embedded device, all lines must be in multiples of 16 characters Please see zgus_hidprobe_manual.pdf for general usage of scripting with Hidprobe (http://www.zgus.com/hid) Author: John Heenan, Auscyber Pty Ltd Copyright 2008 Auscyber Pty Ltd. All rights reserved. ZGUS is a trading name of Auscyber Pty Ltd No Warranty: No warranty of any kind, such as no warranty of fitness for any purpose, including no warranty of fitness for merchantability. No Liability: Auscyber Pty Ltd shall not be liable for any damage or harm the software may cause by its use, whether from faults or not, - including direct, indirect, incidental, consequential, loss of business profits or special damages Should you have any questions regarding your right to use this Software, contact Auscyber Pty Ltd T/A ZGUS at www.zgus.com. */ var file_log="bl_log.txt"; var file_secure="zgus_fw_secure.txt"; var TIMEOUT_INFINITE =-1; var HIDSCRIPT_EVENT_SHUTDOWN =0x00; var HIDSCRIPT_EVENT_TIMEOUT =0x01; var HIDSCRIPT_EVENT_TIMER =0x02; var HIDSCRIPT_EVENT_GETREPORT =0x03; var HIDSCRIPT_EVENT_SIGNAL =0x04; var HIDSCRIPT_EVENT_TIMEOUT_OUTOFRANGE =0x0800; var HIDSCRIPT_EVENT_WAITING =0x0801; //only applicable if a script makes a multithreaded call var HIDSCRIPT_EVENT_ERROR =0x0802; var priorBAUD=0; var fso, tf_log, tf_secure; var er=null; var continue_event_loop=true; if(host_is_hidprobe()) { if(null!=connection.match(/No connection/i)) { alert("No connection: please open a connection then click on Load/Run again"); } else { try { fsm_open(); try { event_loop(TIMEOUT_INFINITE);//for bootloader. For simplicity there are no calls or callbacks as a result of events log("Returned from event_loop()"); } catch(e) { log("event loop error"); throw e; } } catch(e) { alert("error: " + e.description); er=e; }//finally only appears to work with a rethrow if a javascript throw that was used to generate the error in the first place, not a windows runtime error?? try { fsm_close(); } catch(e) { } if(er!=null) throw er; } } function host_is_hidprobe() { var host_ok; try { WScript.Echo("Must be run hosted by Hidprobe http//www.zgus.com/hid"); host_ok=false; } catch(e) { try { if(null!=Version.match(/Hidprobe/i)) host_ok=true; else host_ok=false; } catch(e) { host_ok=false; } } return host_ok; } function _sleep(timeMs) { var resSleep; switch(resSleep=Sleep(timeMs)) { case HIDSCRIPT_EVENT_TIMEOUT: //OK return; case HIDSCRIPT_EVENT_TIMEOUT_OUTOFRANGE: //out of range (10 to 1000 000 000 milliseconds is the accepted range throw new Error("Sleep value '"+timerM+"' out of ms range"); default: //error or shutdown throw new Error("Sleep received error or shutdown response: "+resSleep); } } function log2file(msg) { tf_log.WriteLine(msg); } function log(msg) { log2file(msg); alert(msg); } function event_loop(timeout) {//GetNextEvent() SENDS THREAD TO SLEEP IF THERE IS NO EVENT NOTIFICATION WAITING TO BE COLLECTED! while(1) { if(!continue_event_loop) return; var event=GetNextEvent(timeout);//THREAD GOES TO SLEEP IF THERE IS NO EVENT NOTIFICATION WAITING TO BE COLLECTED! switch(event) { case HIDSCRIPT_EVENT_SHUTDOWN: event_Shutdown(); return;//NOT A BREAK! case HIDSCRIPT_EVENT_TIMEOUT: event_Timeout(); break; case HIDSCRIPT_EVENT_TIMER: event_Timer(); break; case HIDSCRIPT_EVENT_GETREPORT: event_GetReport(); break; case HIDSCRIPT_EVENT_SIGNAL: event_Signal(); default: event_Unexpected(event);//throws an Error! break; } } } function event_Shutdown() { alert("Shutdown event received"); } function event_Timeout() { alert("timeout event received"); } function event_Timer() { alert("timer event received"); } function event_Signal() { alert("Signal '" + GetSignal() + "' received"); } function event_Unexpected(event) { coninue_event_loop=false; throw new Error("unexpected event: " + event + " in event_loop"); } //finite state machine variable var fs; var str_hex; var str_received, char_last; var chars_to_send; var chars_sent; function fsm_open() { var signal=GetSignal(); alert("version is '"+Version+"'"); alert("signal is '"+signal+"'"); alert("connection is '"+Connection+"'"); fs=1; str_received=""; str_reply=""; chars_sent=0; fso = new ActiveXObject("Scripting.FileSystemObject"); tf_log = fso.CreateTextFile(file_log, true); try { tf_secure = fso.OpenTextFile(file_secure, 1, false); } catch(e) { throw new Error(0,"file_secure not found: '" + file_secure + "'"); } if(BAUD!=2400) { priorBAUD=BAUD; BAUD=2400;//the default start speed, can be changed later log("baud temporarily changed to 2400 baud for start up"); } } function fsm_close() { if(priorBAUD) { BAUD=priorBAUD; log("prior BAUD restored"); } tf_secure.Close(); tf_log.Close(); } function event_GetReport() { str_received+=GetReport(); switch(fs) {//Finite State Machine case 1: char_last=str_received.charAt(str_received.length-1); if(char_last=='\n') { if(str_received=="ZGBL\r\n")//hidprobe inserts an extra \r { fs=2; str_received=""; SetReport("ZGBL S5\n");//change baud to 38400 _sleep(100);//this is a lot easier than inclsuding addiitonal states within current fsm BAUD=38400; log("speed changed to 38400") } } break; case 2: char_last=str_received.charAt(str_received.length-1); if(char_last=='\n') { if(str_received=="ZGBL S5\r\n")//hidprobe inserts an extra \r { fs=3; str_received=""; SetReport("ZGBL L\n")//start thr bootloader } else { continue_event_loop=false; throw new Error("Error: ZGBL S5\\n expected to confirm baud change"); } } break; case 3: if(tf_secure.AtEndOfStream) { _sleep(200); log("Bootloader finished"); continue_event_loop=false; return; } str_hex=tf_secure.ReadLine();//read in the first line, end of stream not checked for here log2file("Read in Line: " + str_hex + " of length " + str_hex.length); chars_to_send=str_hex.length; if(chars_to_send%16) throw new Error("Error: chars_to_send must be a multiple of 16"); fs=4; //NO BREAK HERE: allow to fall through case 4: if(str_received!="C")//should only be character at a time throw new Error("Unexpected response '" + str_received + "'"); str_received=""; SetReport(str_hex.substring(chars_sent, chars_sent+16));//currently ONLY 100 characters allowed to be sent at a time!!!!! chars_sent+=16; if(chars_to_send==chars_sent)//also caters for a blank line being read in with zero characters { chars_sent=0; fs=3; } break; } }