Simple
Posts: 121
Joined: Tue Aug 01, 2017 6:51 am
Location: Charleston, SC, USA
Contact: YouTube

Re: Help with gpio-fsm state machine

Thu Jun 03, 2021 2:39 am

Thanks Phil

The time that the amp stays on is normal again, but I noticed something interesting. I was able to hear what sounded like extra clicks from the relays and decided to look deeper into the action. When the amp begins to startup, GPIO22 goes high for just a very short moment, goes low again, then high again, followed by GPIO23 and GPIO24. I was able to observe this using a terminal as well. Actually now it looks easily repeatable. A short burst of audio will actually trigger GPIO22 relay for just a moment and not fully engage the sequence.

Here's a video showing the action..
https://youtu.be/gEwY-H04a0c

Scott

Simple
Posts: 121
Joined: Tue Aug 01, 2017 6:51 am
Location: Charleston, SC, USA
Contact: YouTube

Re: Help with gpio-fsm state machine

Thu Jun 03, 2021 11:08 am

I think it has something to do with the pmdowntime.conf
Apparently, if the timeout is set too low, it runs into trouble
I've removed the timeout entirely for the time being and seems to be functioning normally.

Scott

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 3973
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Help with gpio-fsm state machine

Fri Jun 04, 2021 7:09 am

If you were to add ",fsm_debug" to the dtoverlay line ("dtoverlay=ghost-amp,fsm_debug") it would add diagnostics to the kernel log. To run a test, boot the amp as normal, then at a console shell (probably over ssh in your case) run "sudo dmesg -C" to clean out the normal boot messages. After demonstrating the effect - success or failure - capture the log with, e,g. "dmesg > failure.txt" and either upload the file somewhere or just include the content in a "</>" code section. Alternatively, install pastebinit ("sudo apt install pastebinit") and use "dmesg | pastebinit" to upload the log, after which you only need to post the short URL it outputs.

Simple
Posts: 121
Joined: Tue Aug 01, 2017 6:51 am
Location: Charleston, SC, USA
Contact: YouTube

Re: Help with gpio-fsm state machine

Mon Jun 14, 2021 12:20 pm

Haven't had too much time to play with the fsm, however it appears that if the pmdowntime is set under 1s, it will release under some circumstances. Apparently if it doesn't reach the 1s that we have set for the delay between K1 and K2 activation, it could return to the amp off state.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 3973
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Help with gpio-fsm state machine

Mon Jun 14, 2021 1:17 pm

I think that's behaving how I intended, but perhaps not as you expected.

After the ENABLE signal is received from the codec (what used to be hardware GPIO 22) RELAY1 is enabled. After a 1000ms delay, RELAY2 and RELAYSSR are enabled.

Currently, if ENABLE is deasserted before that 1000ms has elapsed then it is rejected as if it were a glitch, disabling RELAY1 and going back to the amp_off idle state. Would you prefer it to continue to enable RELAY2 when the 1000ms has elapsed but refrain from enabling RELAYSSR, ending up in amp_on_wait for up to 30 minutes? In that way, even a very short audio blip will prime the amp for at least the next 30 minutes.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 3973
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Help with gpio-fsm state machine

Mon Jun 14, 2021 1:46 pm

I've prepared a trial version of the overlay that implements the alternative state transitions I outlined above. You can download it from here: https://drive.google.com/file/d/16DDQkk ... sp=sharing
The trial version is called "new-ghost-amp.dtbo", which you can either rename to "ghost-amp.dtbo" or change your config.txt to say "dtoverlay=new-ghost-amp" while testing it.

The new state machine looks like this:

Code: Select all

				amp_off {
					start_state;
					shutdown_state;

					set = <RELAYSSR 0>,
					      <RELAY2 0>,
					      <RELAY1 0>;
					amp_on_1 = <ENABLE 1>;
					fault = <FAULT 1>;
				};

				amp_on_1 {
					set = <RELAY1 1>;
					amp_on_2 = <GF_DELAY 1000>;
					amp_off = <GF_SHUTDOWN 0>;
					fault = <FAULT 1>;
				};

				amp_on_2 {
					set = <RELAY2 1>;
					amp_on_wait = <ENABLE 0>;
					amp_on = <GF_DELAY 1>;
					fault = <FAULT 1>;
				};

				amp_on {
					set = <RELAYSSR 1>;
					amp_on_wait = <ENABLE 0>;
					fault = <FAULT 1>;
				};

				amp_on_wait {
					set = <RELAYSSR 0>;
					amp_off_1 = <GF_DELAY (30*60*1000)>,
						    <GF_SHUTDOWN 0>;
					amp_on = <ENABLE 1>;
					fault = <FAULT 1>;
				};

				amp_off_1 {
					set = <RELAY2 0>;
					amp_on = <ENABLE 1>;
					amp_off = <GF_DELAY 100>;
					fault = <FAULT 1>;
				};

				// Keep this a distinct state to prevent
				// changes and for the diagnostic output
				fault {
					set = <RELAYSSR 0>,
					      <RELAY2 0>,
					      <RELAY1 0>;
					amp_off = <FAULT 0>;
					shutdown_state;
				};
Notice how the jump to amp_on_2 happens regardless of a change to ENABLE, and on arrival there it will jump to amp_on_wait if it finds ENABLE is low, just like amp_on does.

Simple
Posts: 121
Joined: Tue Aug 01, 2017 6:51 am
Location: Charleston, SC, USA
Contact: YouTube

Re: Help with gpio-fsm state machine

Mon Jun 14, 2021 5:00 pm

Makes sense. I like the 'on' state triggered by any length of sound activity.
For now this should work well. Its really just a nitpicky thing anyways.

Is it a simple edit to change the 'fault' red LED indication from a steady on to a 3Hz blinking indicator?

Thx Phil

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 3973
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Help with gpio-fsm state machine

Mon Jun 14, 2021 7:26 pm

This (completely untested) version of the script should make the LED flash red if the fault condition occurs.

Code: Select all

import time,os,datetime,subprocess,signal,sys,gpiozero,argparse

version=0.3

def debugPrint(s):
    if debug:
        print(time.strftime('%H:%M:%S',time.localtime())+' '+s)

def signal_handler(sig,frame):
    debugPrint('Ctrl+C pressed')
    led.off()
    led.close()
    time.sleep(0.5)
    sys.exit(0)
    
def pingGoogle():
    (s,o)=command(['ping','-c','1','google.com'])
    return s

def checkNetwork(interface):
    (s,o) = command(['grep', '', '/sys/class/net/'+interface+'/carrier'])
    return(o.rstrip() == '1')

def command(command):
    try:
        output = subprocess.check_output(command, stderr=subprocess.STDOUT).decode()
        success = True 
    except subprocess.CalledProcessError as e:
        output = e.output.decode()
        success = False
    return (success,output)

# arguments
ap = argparse.ArgumentParser()
ap.add_argument('-d','--debug',action='store_true',help='Show debug messages')
args = vars(ap.parse_args())
debug = args['debug']
if debug:
    print('Version:',version)
    print('Arguments:',args)

# constants
redGPIO=6
greenGPIO=12
blueGPIO=13
lanSeconds=5
pingSeconds=5
ampStatePath='/sys/class/gpio-fsm/ghost-amp/state'

# setup
led = gpiozero.RGBLED(red=redGPIO, green=greenGPIO, blue=blueGPIO)

signal.signal(signal.SIGINT,signal_handler)
    
nextPing = datetime.datetime.now()
nextLan = datetime.datetime.now()
lanOk = False
internetOk = False

#No network connection (blink LED)
#Network connected (pulse LED)
#Internet access (on LED)

#Then either blue or green based on gpio22 on or off. 

lastInternetOk = None
lastLanOk = None
lastAmpState = None

while True:
    
    # lan
    if datetime.datetime.now() > nextLan:
        lanOk = checkNetwork('eth0') or checkNetwork('wlan0')
        debugPrint('lanOk:'+str(lanOk))
        nextLan = datetime.datetime.now() + datetime.timedelta(seconds=lanSeconds)

    # ping
    if datetime.datetime.now() > nextPing:
        internetOk = pingGoogle()
        debugPrint('internetOk:'+str(internetOk))
        nextPing = datetime.datetime.now() + datetime.timedelta(seconds=pingSeconds)

    fh = open(ampStatePath, 'r')
    if fh:
        ampState = fh.readline().rstrip()
        fh.close()
    else:
        ampState = 'fault'

    if lastAmpState == None or lastAmpState != ampState or lastInternetOk == None or lastInternetOk != internetOk or lastLanOk == None or lastLanOk != lanOk:

        # DAC
        if ampState[:6] == 'amp_on':
            color = (0,1,0) # green
            debugPrint('led green')
        else:
            color = (0,0,1) # blue
            debugPrint('led blue')

        if ampState[:5] == 'fault':
            debugPrint('led red')
            debugPrint('flash')
            led.blink(on_color=(1,0,0), on_time=0.166, off_time=0.166)
        elif internetOk:
            debugPrint('led on')
            led.color = color
        elif lanOk:
            # pulse
            debugPrint('pulse')
            led.pulse(on_color=color)
        else:
            # blink
            debugPrint('blink')
            led.blink(on_color=color)

        lastAmpState = ampState
        lastInternetOk = internetOk
        lastLanOk = lanOk

    time.sleep(0.1)
Note that this will override the pulsing and blinking for network failures.

Simple
Posts: 121
Joined: Tue Aug 01, 2017 6:51 am
Location: Charleston, SC, USA
Contact: YouTube

Re: Help with gpio-fsm state machine

Mon Jun 14, 2021 10:14 pm

Brilliance!

Tested it a few times and works like one would expect.
The nice part about a good quick pulsing LED is that it won't be misunderstood as a hung boot or something other, as the LED comes on steady at boot. With the pulsing, I can now remove the LED that is on the PCB for fault indication.
I've got a friend about to build one of his own using a different PCB design and chassis setup, but everything is now modular and pretty much copy/paste with little edits here and there for the PCB outlines. All of the code for controlling everything will be the same, and the myriad of designs and software to playback will be unlimited. This can even be used without built-in amplifiers and yet control an external amplifier now.

Very happy!
Thanks Phil
Scott

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 3973
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Help with gpio-fsm state machine

Tue Jun 15, 2021 7:31 am

If you are happy with the updated state machine I'll publish the change so it can be incorporated into new kernel builds.

Simple
Posts: 121
Joined: Tue Aug 01, 2017 6:51 am
Location: Charleston, SC, USA
Contact: YouTube

Re: Help with gpio-fsm state machine

Tue Jun 15, 2021 12:24 pm

Working like a charm so far!

Thanks Phil
S

Return to “Device Tree”