mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-04-11 21:49:02 +02:00
HIDScript JS callbacks to go are now reacting to Otto's IRQ channel
This commit is contained in:
parent
5a7a0b352d
commit
1c7389f77f
5
ToDo.txt
5
ToDo.txt
@ -18,9 +18,8 @@ HID
|
||||
- DONE: avoid memory leak on reinit of HIDController
|
||||
- DONE: implement job management
|
||||
- DONE: implement context for cancellation and cancellation propagation
|
||||
- blocking JavaScript to go callbacks (waitLED, delay, waitLEDRepeated) have to be job-context aware to allow
|
||||
interruption (the Interrupt channel of Otto only triggers after a blocking callback is evaluated, thus this callbacks have
|
||||
to be interrupted themselves)
|
||||
- DONE: blocking JavaScript to go callbacks (waitLED, delay, waitLEDRepeated) have to consume the otto.Otto.Interrupt channel
|
||||
to be able to be aborted when Otto is interrupted
|
||||
|
||||
WIFI
|
||||
- implement connection to OPEN-AUTH network as STA
|
||||
|
@ -58,9 +58,6 @@ func (job *AsyncOttoJob) ResultJsonString() (string, error) {
|
||||
|
||||
type AsyncOttoVM struct {
|
||||
vm *otto.Otto
|
||||
ResultErr *error
|
||||
ResultValue otto.Value
|
||||
Finished chan bool
|
||||
isWorking bool
|
||||
sync.Mutex
|
||||
Id int
|
||||
@ -70,8 +67,6 @@ func NewAsyncOttoVM(vm *otto.Otto) *AsyncOttoVM {
|
||||
vm.Interrupt = make(chan func(), 1) //set Interrupt channel
|
||||
res := &AsyncOttoVM{
|
||||
isWorking: false,
|
||||
ResultValue: otto.Value{},
|
||||
Finished: make(chan bool,1), //buffer of 1 as we don't want to block on setting the finished signal
|
||||
vm: vm,
|
||||
Id: vmNum,
|
||||
}
|
||||
@ -125,7 +120,7 @@ func (avm *AsyncOttoVM) RunAsync(ctx context.Context, src interface{}) (job *Asy
|
||||
if job.executingVM != nil {
|
||||
job.executingVM.vm.Interrupt <- func() {
|
||||
log.Printf("VM %d EXECUTED INTERRUPT FUNCTION\n", avm.Id)
|
||||
panic(halt)
|
||||
panic(haltirq)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -136,14 +131,14 @@ func (avm *AsyncOttoVM) RunAsync(ctx context.Context, src interface{}) (job *Asy
|
||||
defer avm.SetWorking(false)
|
||||
if caught := recover(); caught != nil {
|
||||
fmt.Printf("VM %d CAUGHT INTERRUPT, ENDING JOB %d\n", avm.Id, job.Id)
|
||||
if caught == halt {
|
||||
if caught == haltirq {
|
||||
job.ResultErr = errors.New(fmt.Sprintf("Execution of job %d on VM %d interrupted\n", job.Id, avm.Id))
|
||||
|
||||
// signal Job finished
|
||||
job.SetFinished()
|
||||
return
|
||||
}
|
||||
panic(caught) //re-raise panic, as it isn't `halt`
|
||||
panic(caught) //re-raise panic, as it isn't `haltirq`
|
||||
}
|
||||
return
|
||||
}()
|
||||
|
@ -23,8 +23,9 @@ var (
|
||||
|
||||
hidControllerReuse *HIDController
|
||||
|
||||
halt = errors.New("Stahp")
|
||||
ErrAbort = errors.New("Event listening aborted")
|
||||
haltirq = errors.New("Stahp")
|
||||
ErrAbort = errors.New("Event listening aborted")
|
||||
ErrIrq = errors.New("Aborted due to interrupt request")
|
||||
ErrNotAllowed = errors.New("Calling not allowed (currently disabled)")
|
||||
)
|
||||
|
||||
@ -276,7 +277,6 @@ func (ctl *HIDController) jsTypingSpeed(call otto.FunctionCall) (res otto.Value)
|
||||
}
|
||||
|
||||
func (ctl *HIDController) jsDelay(call otto.FunctionCall) (res otto.Value) {
|
||||
|
||||
arg0 := call.Argument(0)
|
||||
//fmt.Printf("JS delay() called with: `%s` (%s)\n", arg0, arg0)
|
||||
|
||||
@ -292,8 +292,14 @@ func (ctl *HIDController) jsDelay(call otto.FunctionCall) (res otto.Value) {
|
||||
}
|
||||
delay := int(fDelay)
|
||||
log.Printf("HIDScript delay: Sleeping `%v` milliseconds\n", delay)
|
||||
time.Sleep(time.Millisecond * time.Duration(int(delay)))
|
||||
//time.Sleep(time.Millisecond * time.Duration(int(delay)))
|
||||
|
||||
select {
|
||||
case <- time.After(time.Millisecond * time.Duration(int(delay))):
|
||||
return
|
||||
case irq := <-call.Otto.Interrupt:
|
||||
irq()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -357,8 +363,19 @@ func (ctl *HIDController) jsWaitLED(call otto.FunctionCall) (res otto.Value) {
|
||||
return
|
||||
}
|
||||
|
||||
changed,err := ctl.Keyboard.WaitLEDStateChange(mask, timeout)
|
||||
//fmt.Printf("Changed %+v\n", changed)
|
||||
irqCtx, cancel := context.WithCancel(context.Background())
|
||||
go func(cancel context.CancelFunc, vm *otto.Otto) {
|
||||
select {
|
||||
case /*irq :=*/ <- vm.Interrupt:
|
||||
cancel() //cancel context used by LED state change
|
||||
//irq() // call irq handler
|
||||
}
|
||||
}(cancel,call.Otto)
|
||||
|
||||
changed,err := ctl.Keyboard.WaitLEDStateChange(irqCtx, mask, timeout)
|
||||
if err == ErrIrq {
|
||||
panic(haltirq)
|
||||
}
|
||||
|
||||
errStr := ""
|
||||
if err != nil {errStr = fmt.Sprintf("%v",err)}
|
||||
@ -459,9 +476,21 @@ func (ctl *HIDController) jsWaitLEDRepeat(call otto.FunctionCall) (res otto.Valu
|
||||
return
|
||||
}
|
||||
|
||||
irqCtx, cancel := context.WithCancel(context.Background())
|
||||
go func(cancel context.CancelFunc, vm *otto.Otto) {
|
||||
select {
|
||||
case /*irq :=*/ <- vm.Interrupt:
|
||||
cancel() //cancel context used by LED state change
|
||||
//irq() // call irq handler
|
||||
}
|
||||
}(cancel,call.Otto)
|
||||
|
||||
|
||||
log.Printf("HIDScript: Waiting for repeated LED change. Mask for considered LEDs: %v, Minimum repeat count: %v, Maximum repeat delay: %v, Timeout: %v\n", mask, repeatCount, maxInterval, timeout)
|
||||
changed,err := ctl.Keyboard.WaitLEDStateChangeRepeated(mask, repeatCount, maxInterval, timeout)
|
||||
//fmt.Printf("Changed %+v\n", changed)
|
||||
changed,err := ctl.Keyboard.WaitLEDStateChangeRepeated(irqCtx, mask, repeatCount, maxInterval, timeout)
|
||||
if err == ErrIrq {
|
||||
panic(haltirq)
|
||||
}
|
||||
|
||||
errStr := ""
|
||||
if err != nil {errStr = fmt.Sprintf("%v",err)}
|
||||
|
@ -308,7 +308,7 @@ Waits for single LED state change
|
||||
intendedChange: Mask values combined with logical or, to indicate which LEDs are allowed to trigger MaskNu
|
||||
return value changed: Mask values combined with logical or, indicating which LED actually changed in order to stop waiting
|
||||
*/
|
||||
func (kbd *HIDKeyboard) WaitLEDStateChange(intendedChange byte, timeout time.Duration) (changed *HIDLEDState,err error) {
|
||||
func (kbd *HIDKeyboard) WaitLEDStateChange(ctxIrq context.Context, intendedChange byte, timeout time.Duration) (changed *HIDLEDState,err error) {
|
||||
//register state change listener
|
||||
l,err := kbd.LEDWatcher.RetrieveNewListener()
|
||||
if err!= nil { return nil,err }
|
||||
@ -345,13 +345,15 @@ func (kbd *HIDKeyboard) WaitLEDStateChange(intendedChange byte, timeout time.Dur
|
||||
//If here, there was a LED state change, but not one we want to use for triggering (continue outer loop, consuming channel data)
|
||||
case <-l.ledWatcher.ctx.Done():
|
||||
return nil, ErrAbort
|
||||
case <-ctxIrq.Done():
|
||||
return nil, ErrIrq
|
||||
case <- time.After(remaining):
|
||||
return nil, ErrTimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (kbd *HIDKeyboard) WaitLEDStateChangeRepeated(intendedChange byte, repeatCount int, minRepeatDelay time.Duration, timeout time.Duration) (changed *HIDLEDState,err error) {
|
||||
func (kbd *HIDKeyboard) WaitLEDStateChangeRepeated(ctxIrq context.Context, intendedChange byte, repeatCount int, minRepeatDelay time.Duration, timeout time.Duration) (changed *HIDLEDState,err error) {
|
||||
//register state change listener
|
||||
l,err := kbd.LEDWatcher.RetrieveNewListener()
|
||||
if err!= nil { return nil,err }
|
||||
@ -454,6 +456,8 @@ func (kbd *HIDKeyboard) WaitLEDStateChangeRepeated(intendedChange byte, repeatCo
|
||||
//If here, there was a LED state change, but not one we want to use for triggering (continue outer loop, consuming channel data)
|
||||
case <-l.ledWatcher.ctx.Done():
|
||||
return nil, ErrAbort
|
||||
case <-ctxIrq.Done():
|
||||
return nil, ErrIrq
|
||||
case <- time.After(remaining):
|
||||
return nil, ErrTimeout
|
||||
}
|
||||
|
13
testhid.go
13
testhid.go
@ -70,7 +70,7 @@ func TestLEDTriggers(hidCtl *hid.HIDController) {
|
||||
|
||||
//Test repeat trigger on any LED
|
||||
fmt.Println("Waiting for any repeated LED state change (5 times frequently), wait timeout after 20 seconds...")
|
||||
trigger, err := hidCtl.Keyboard.WaitLEDStateChangeRepeated(hid.MaskAny, 5, time.Millisecond*500, 20*time.Second)
|
||||
trigger, err := hidCtl.Keyboard.WaitLEDStateChangeRepeated(context.Background(), hid.MaskAny, 5, time.Millisecond*500, 20*time.Second)
|
||||
if err != nil {
|
||||
fmt.Printf("Waiting aborted with error: %v\n", err)
|
||||
} else {
|
||||
@ -79,7 +79,7 @@ func TestLEDTriggers(hidCtl *hid.HIDController) {
|
||||
|
||||
//Test single trigger on any LED
|
||||
fmt.Println("Waiting for any LED single state change, timeout after 15 seconds")
|
||||
trigger, err = hidCtl.Keyboard.WaitLEDStateChange(hid.MaskAny, 15*time.Second)
|
||||
trigger, err = hidCtl.Keyboard.WaitLEDStateChange(context.Background(),hid.MaskAny, 15*time.Second)
|
||||
if err != nil {
|
||||
fmt.Printf("Waiting aborted with error: %v\n", err)
|
||||
} else {
|
||||
@ -91,7 +91,7 @@ func TestLEDTriggers(hidCtl *hid.HIDController) {
|
||||
|
||||
//Test single trigger on NUMLOCK LED (ignore CAPSLOCK, SCROLLLOCK etc.)
|
||||
fmt.Println("Waiting for NUMLOCK LED state change, timeout after 15 seconds")
|
||||
trigger, err = hidCtl.Keyboard.WaitLEDStateChange(hid.MaskNumLock, 15*time.Second)
|
||||
trigger, err = hidCtl.Keyboard.WaitLEDStateChange(context.Background(),hid.MaskNumLock, 15*time.Second)
|
||||
if err != nil {
|
||||
fmt.Printf("Waiting aborted with error: %v\n", err)
|
||||
} else {
|
||||
@ -100,7 +100,7 @@ func TestLEDTriggers(hidCtl *hid.HIDController) {
|
||||
|
||||
//Test single trigger on NUMLOCK LED (ignore CAPSLOCK, SCROLLLOCK etc.)
|
||||
fmt.Println("Waiting for CAPSLOCK LED state change for 15 seconds")
|
||||
trigger, err = hidCtl.Keyboard.WaitLEDStateChange(hid.MaskCapsLock, 15*time.Second)
|
||||
trigger, err = hidCtl.Keyboard.WaitLEDStateChange(context.Background(), hid.MaskCapsLock, 15*time.Second)
|
||||
if err != nil {
|
||||
fmt.Printf("Waiting aborted with error: %v\n", err)
|
||||
} else {
|
||||
@ -111,7 +111,7 @@ func TestLEDTriggers(hidCtl *hid.HIDController) {
|
||||
func TestMultiLEDTrigges(hidCtl *hid.HIDController, triggerMask byte) {
|
||||
//Test repeat trigger on given LED
|
||||
fmt.Printf("Waiting for repeated LED state change (5 times frequently) of mask %v, wait timeout after 20 seconds...\n", triggerMask)
|
||||
trigger, err := hidCtl.Keyboard.WaitLEDStateChangeRepeated(triggerMask, 5, time.Millisecond*500, 20*time.Second)
|
||||
trigger, err := hidCtl.Keyboard.WaitLEDStateChangeRepeated(context.Background(),triggerMask, 5, time.Millisecond*500, 20*time.Second)
|
||||
if err != nil {
|
||||
fmt.Printf("Waiting aborted with error: %v\n", err)
|
||||
} else {
|
||||
@ -332,7 +332,8 @@ func main() {
|
||||
jobList := make([]int,0)
|
||||
fmt.Println("Adding sleeping jobs with 5 seconds timeout context")
|
||||
ctxT,_ := context.WithTimeout(context.Background(), time.Second * 2)
|
||||
script := "console.log('START ' + JID + ' on VM ' + VMID);delay(5000);console.log(JID + ' returned from 5s blocking delay');"
|
||||
//script := "console.log('START ' + JID + ' on VM ' + VMID);delay(5000);console.log(JID + ' returned from 5s blocking delay');"
|
||||
script := "console.log('START ' + JID + ' on VM ' + VMID);waitLEDRepeat(ANY,5000);console.log(JID + ' returned from 5s blocking delay');"
|
||||
startTime := time.Now()
|
||||
for i:=1; i<4; i++ {
|
||||
job,err := hidCtl.StartScriptAsBackgroundJob(ctxT,script)
|
||||
|
Loading…
x
Reference in New Issue
Block a user