Skip to content

Instantly share code, notes, and snippets.

@Oldes
Created March 6, 2024 20:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Oldes/f3c78cc3438e448223dc40eac03d00c4 to your computer and use it in GitHub Desktop.
Save Oldes/f3c78cc3438e448223dc40eac03d00c4 to your computer and use it in GitHub Desktop.
Cross-platform DMX port usage example
Rebol [
Purpose: "Cross-platform DMX port usage example"
Needs: 3.11.0 ;= https://github.com/Oldes/Rebol3/releases/tag/3.11.0
]
;------------- DMX ------------------------
dmx-ctx: context [
ser: none
bin: make binary! 513 insert/dup bin 0 513
;- Channel 10A
DIMM: 2 ;; 0 = no light, 255 = max light
RED: 3
GREEN: 4
BLUE: 5
WHITE: 6
AMBER: 7
UV: 8
STROBE: 9
MACRO: 10
SPEED: 11
;- Light 2
;; RED: 44
;; GREEN: 45
;; BLUE: 46
;; WHITE: 47
;; AMBER: 48
;; UV: 49
bin/:DIMM: 255
bin/:UV: 255
;bin/:MACRO: 225
;bin/:SPEED: 255
either system/platform = 'Windows [
;; Windows...
ser: make port! [scheme: 'serial path: %COM7 speed: 250000 stop-bits: 2]
send-data: func[p][
;; initiate and then clear a break condition
modify p 'BRK true
modify p 'BRK false
write p bin
]
ser/awake: func [event /local p][
false
]
try/with [
open ser
;modify ser 'RTS false
] :print
][
;; Linux...
try/with [
ser: open %/dev/dmx0
send-data: func[p][write p bin]
] :print
]
set 'dmx-port ser
set 'update-dmx func[][ if all [dmx-port open? dmx-port] [send-data dmx-port] ]
]
;; then in regular interval modify the `dmx-ctx/bin` series and call `update-dmx`
@Oldes
Copy link
Author

Oldes commented Mar 6, 2024

Above code is just a fragment.. in real scenario I used Rebol webserver as a core.. GUI was made as a webpage which communicated with the server over WebSocket. The server was also responsible to play sounds and control electric plugs over GPIO.

It was possible to record all commands and re-play them later... the main loop was like:

process-commands: func[ctx msg /local out val new pos vol time][
    if all [ctx not series? ctx/out/content] [ctx/out/content: clear ""]
    try/with [
        parse msg [any [
            (out: none)
            [
                  'volume [
                    set val: integer! (audio/volume: val / 100.0)
                    | set val: percent! (audio/volume: val)
                  ]
                | 'delay-wet   set val: [percent! | decimal!] (delay/wet:   val)
                | 'delay-dry   set val: [percent! | decimal!] (delay/dry:   val)
                | 'delay-decay set val: [percent! | decimal!] (delay/decay:   val)
                | 'sw1 set val: word! ( out: switch-pin 'sw1 :val)
                | 'sw2 set val: word! ( out: switch-pin 'sw2 :val)
                | 'sw3 set val: word! ( out: switch-pin 'sw3 :val)
                | 'sw4 set val: word! ( out: switch-pin 'sw4 :val)
                | 'sw5 set val: word! ( out: switch-pin 'sw5 :val)
                | 'sw6 set val: word! ( out: switch-pin 'sw6 :val)
                | 'sw7 set val: word! ( out: switch-pin 'sw7 :val)
                | 'sw8 set val: word! ( out: switch-pin 'sw8 :val)
                | 'dot set id: integer! set val: pair! (
                    current-sound-source: id
                    new: pick state/sound-sources id
                    either new [
                        new/1/position: val
                    ][
                        new: new-sound-source
                        new/position: val
                        probe sound-ends: now + (new/duration - 0:0:15)
                        print ["Vrana:" new/source "id:" id "position:" val "ends:" sound-ends]
                        repend/only state/sound-sources [new sound-ends]
                        ma/start/fade/seek new 0:0:10 0
                    ]
                    ;state/position: val
                    ;try/with [vrana/position: val] :print
                    out: ajoin ["set dot" id SP val LF]
                )
                | 'RGB set val: tuple! (
                    change/part next dmx-ctx/bin to binary! val length? val
                )
                | 'RGB2 set val: tuple! (
                    change/part skip dmx-ctx/bin 43 to binary! val length? val
                )
                | 'strobo set val: integer! (
                    dmx-ctx/bin/9: val
                )
                | 'svitani set val: opt [time!] (
                    dmx-ctx/bin/2: 0
                    svitani: object [
                        start: now
                        time:  any [val 0:4:0]
                        end:   now + time
                    ]
                )
                | 'akce-sound set val: file! set vol: opt[decimal! | percent!] set pos: opt [pair!] set time: opt [time!] (
                    if new: akce-sounds/:val [
                        if pos [new/position: pos]
                        if vol [new/volume: vol]
                        print ["Akce sound:" new/source]
                        ma/start/fade/seek new any [time 0:1:10] 0
                    ]
                )
                | 'akce-sound-stop set val: file! set time: opt [time!] (
                    if new: akce-sounds/:val [
                        print ["Akce sound stop:" new/source]
                        ma/stop/fade new any [time 0:0:10]
                    ]
                )
            ] ;; end of recordable action
            (   
                if all [ctx out][
                    append ctx/out/content ajoin [out LF]
                ]
                log-action msg
            )
            |
            [
                'sync (
                    out: to-json state
                )
                | 'record-start (
                    log-start: now/precise
                    log-file: open/new/write %log.txt
                )
                | 'record-stop (
                    try [close log-file]
                    log-file: none
                )
                | 'replay (
                    play-start: now/precise + 0:0:5
                    play-rules: transcode read %log.txt
                    timeout: 0.01
                    ? play-rules
                )
                | 'change-sound (
                    if all [
                        current-sound-source
                        snd: pick state/sound-sources current-sound-source
                    ][
                        change-sound snd current-sound-source
                    ]
                    out: reform ["Changed sound:" snd/1/source]
                )
            ]
            (
                if all [ctx out][
                    append ctx/out/content ajoin [out LF]
                ]
                print as-red msg
            )
        ]]
    ] :print
]

timeout: either dmx-port [0.01][5]
forever [
    p: wait [server server/extra/subport timeout]
    t: now/precise

    if dmx-port [
        update-dmx
        if svitani [
            either t <= svitani/end [
                dmx-ctx/bin/2: ea/tween 14 255 1.0 - ((difference svitani/end t) / svitani/time) 'out-expo
            ][
                print "Svitani END"
                svitani: none
            ]
        ]
    ]
    while [not empty? play-rules][
        either t >= (play-start + play-rules/1) [
            process-commands none probe play-rules/2
            play-rules: skip play-rules 2
            if empty? play-rules [
                print as-green "Playback ended"
            ]
        ][  break ]
    ]
    update-sounds
]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment