For those of you with ROACH boards, here is a little utility for querying the onboard Actel Fusion housekeeping/monitoring chip.

It's simply a python script that lets you view and control some of the housekeeping functions over the network (through the Xport). If you've never used the Xport before, ROACH boards ship with a default IP address of 192.168.4.20.

There are no dependancies for the script, and it works across platforms (tested Linux, OS-X and Windows: cygwin's python). Just execute it as you would any other script: ./roach_monitor.py

You'll get a menu as follows:

=====================================
        ROACH MONITOR CONTROL
=====================================

  1) Retrieve details
  2) Reset crashlog counter
  3) Power-up ROACH
  4) Reset ROACH, but not Actel
  5) Toggle safety-shutdown defeat
  6) Power down ROACH
  7) Toggle PPC EEPROM boot (config H)
  other) Exit



SAMPLE PRINTOUT of option 1:
=============================

Serial number: 020115.
ID: 48879, revision 6.5.1429
Board time: 210784105591360 seconds

Power state: 3 (Powered on)
Reason for last shutdown: 3 (User shutdown)

Unacknowledged crashes: 0
Unacknowledged watchdog overflows: 0
Watchdog timeout: 0.00 seconds.

PPC bootstrap option H (boot from I2C EEPROM) is currently  ENABLED.
Automatic safety shutdowns are currently  ENABLED.

Power good from onboard voltage regulators:
3v3aux:  1
MGT_AVCCPLL:  1
MGT_AVTTX:  1
MGT_AVCC:  1
ATX_PWR:  1
ADC values are averaged 32 times.

Current values:
          Channel          Current        Shutdown        Shutdown
           Name            value           below           above
=====================================================================
         1v5aux:            1.55           1.40            1.60
   Virtex5 temp:           23.00        -278.00          458.00
        12V ATX:           11.93           9.98           13.95
       PPC temp:           31.75        -278.00          410.00
         5V ATX:            5.14           4.38            5.60
        3v3 ATX:            3.39           2.99            3.62
          1V PS:            0.99           0.90            1.05
         1V5 PS:            1.51           1.40            1.55
         1V8 PS:            1.81           1.70            1.90
         2V5 PS:            2.50           2.45            2.54
      Actl temp:           27.25        -278.00          410.00
          Fan 1:         4800 rpm
          Fan 2:            0 rpm
          Fan 3:            0 rpm




If there was a crash detected (auto power down), it will print out the timestamp and cause of the error too.

There is a fancy GUI-based version being developed at KAT which includes plotting of temperatures and green/red status lights etc. It will be LabView-based.

Jason
#!/usr/bin/env python

import socket,struct,sys

def write(addr,value):
    'Writes a 16bit value to the Fusion part through the Xport.'
    request=struct.pack('<5B',0x02,addr&0xff,(addr&0xff00)>>8,value&0xff,(value&0xff00)>>8)
    xport.send(request)
    raw=xport.recv(10)
    if len(raw) != 1:
        print 'Received an invalid response. Received %i bytes:'%len(raw),raw_unpacked
        xport.close()
        sys.exit(1)

def read(addr):
    'Reads a 16bit value from the Fusion part through the Xport.'
    request=struct.pack('<3B',0x01,addr&0xff,(addr&0xff00)>>8)
    xport.send(request)
    raw=xport.recv(10)
    if len(raw) == 3:
        raw_unpacked=struct.unpack('<%iB'%len(raw),raw)
        #print 'Received: ',raw_unpacked
        value=(raw_unpacked[2]<<8) + raw_unpacked[1]
        #print 'Received value: ',value
        return value
    else:
        print 'Received an invalid response. Received %i bytes:'%len(raw),raw_unpacked
        xport.close()
        sys.exit(1)

def print_details():
    print '\nSerial number: %c%c%c%c%c%c.'%(chr(read(0xB8)),chr(read(0xB9)),chr(read(0xBA)),chr(read(0xBB)),chr(read(0xBC)),chr(read(0xBD)))
    print 'ID: %i, revision %i.%i.%i'%(read(0),read(1),read(2),read(3))
    print 'Board time: %i seconds'%((read(0x06)<<32)+(read(0x07)<<16)+(read(0x08)))

    pwr_state_raw=read(0x280)
    pwr_state=pwr_state_raw&7
    shutdown_reason=(pwr_state_raw&0x300)>>8
    print '\nPower state: %i (%s)'%(pwr_state,pwr_state_decode[pwr_state])
    print 'Reason for last shutdown: %i (%s)'%(shutdown_reason,shutdown_reason_decode[shutdown_reason])

    crashes=read(0x283)
    print '\nUnacknowledged crashes: %i'%crashes
    watchdog_overflows=read(0x284)
    print 'Unacknowledged watchdog overflows: %i'%watchdog_overflows
    print 'Watchdog timeout: %4.2f seconds.'%(read(0x285)*53.7)
    if crashes>0:
        #print 'Hard violation src %i val %i.'%(read(0x204),read(0x205))
        id=read(0x400)
        if id != 0xdead:
            print 'Crash ID fail: %x instead of 0xdead'%id
        else:
            time=((read(0x401)<<32)+(read(0x402)<<16)+(read(0x403)))
            src=read(0x404)
            val=read(0x405)
            print 'Flash crashlog: Crash at %is system time caused by channel %i (%s) with value %2.2f'%(time,src,channels[src],val/channel_scale[src])

    sys_config=read(0xffff)
    print '\nPPC bootstrap option H (boot from I2C EEPROM) is currently ',
    if (sys_config&0x02): print 'ENABLED.'
    else: print 'DISABLED.'

    print 'Automatic safety shutdowns are currently ',
    if (sys_config&0x80): print 'DISABLED.'
    else: print 'ENABLED.'

    print '\nPower good from onboard voltage regulators:'
    ps_powergds=read(0x288)
    print '3v3aux: ',(ps_powergds&0x01)>>0
    print 'MGT_AVCCPLL: ',(ps_powergds&0x02)>>1
    print 'MGT_AVTTX: ',(ps_powergds&0x04)>>2
    print 'MGT_AVCC: ',(ps_powergds&0x08)>>3
    print 'ATX_PWR: ',(ps_powergds&0x10)>>4

    print 'ADC values are averaged %i times.'%(2**(read(0x145)))

    print '\nCurrent values:'
    print '%s \t%s \t%s \t%s'%('Channel'.rjust(17),'Current'.rjust(10), 'Shutdown'.rjust(10), 'Shutdown'.rjust(10))
    print '%s \t%s \t%s \t%s'%('Name'.rjust(15),'value'.rjust(8), 'below'.rjust(8), 'above'.rjust(8))
    print '====================================================================='
    for chan in valid_channels:
        sample_addr=0x240+chan
        hard_thresh_min_addr=0x1c0+(chan*2)
        hard_thresh_max_addr=0x1c0+(chan*2)+1
        
        sample=read(sample_addr)/channel_scale[chan] + channel_offset[chan]
        hard_thresh_min=read(hard_thresh_min_addr)/channel_scale[chan] + channel_offset[chan]
        hard_thresh_max=read(hard_thresh_max_addr)/channel_scale[chan] + channel_offset[chan]
        print '%s:\t %7.2f \t%7.2f \t%7.2f'%(channels[chan].rjust(15),sample,hard_thresh_min,hard_thresh_max)
    print '%s: \t%5i rpm'%('Fan 1'.rjust(15),read(0x300)*60)
    print '%s: \t%5i rpm'%('Fan 2'.rjust(15),read(0x301)*60)
    print '%s: \t%5i rpm'%('Fan 3'.rjust(15),read(0x302)*60)

def power_up():
    write(0x281,0xffff)

def warm_rst():
    write(0x282,0x0)

def power_down():
    write(0x282,0xffff)

def clear_crashlog():
    write(0x283,0xffff)

def toggle_config_h():
    print 'Retrieval of PPC bootstrap options from EEPROM (boot configuration H) is currently',
    sys_config=read(0xffff)
    if (sys_config&0x02):
        print 'enabled. DISABLING...',
        write(0xffff,sys_config-0x02)
        read(0x1000)
        if not read(0xffff)&0x2: 
            print 'done.'
            print 'PPC will now boot into configuration C (533MHz CPU, 66MHz bus) if all CONFIG_DIP switches are in OFF position.',
        else: print 'error saving.'
    else:
        print 'enabled. ENABLING...',
        write(0xffff,sys_config+0x02)
        read(0x1000)
        if read(0xffff)&0x2: 
            print 'done.'
            print 'PPC will now retrieve bootstrap options from EEPROM (bootstrap config H) if all CONFIG_DIP switches are in OFF position.',
        else: print 'error saving.'
        

def disable_hard_threshold():
    #SYSCTRL register value is retrieved from flash at 0xffff.
    #Commit writes to flash by following each write by a read to a different addr.
    
    #SYSCTRL bitmask:   bit0:
    #                   bit1: Enable EEPROM booting
    #                   bit2:
    #                   bit3:
    #                   bit4:
    #                   bit5:
    #                   bit6:
    #                   bit7: Disable crashes (auto-shutdown in the event of bad power / over temp).
    #                   bit8:
    #                   bit9:
    #                   bit10:

    sys_config=read(0xffff)
    print '\nAutomatic safety shutdowns are currently',
    if (sys_config&0x80):
        print 'DISABLED. Enabling...',
        write(0xffff,sys_config-0x80)
        read(0x1000)
        if not read(0xffff)&0x80: print 'done.'
        else: print 'error saving.'
    else:
        print 'ENABLED. Disabling...',
        write(0xffff,sys_config+0x80)
        read(0x1000)
        if (read(0xffff)&0x80): 
            print 'done.\n\n'
            print '============================================================================'
            print '||  WARNING: Defeating the safety shutdowns could cause permanent damage  ||'
            print '||           to your board in the event of a fault.                       ||'
            print '============================================================================\n\n'
        else: print 'error saving.'
        
xport_ip='192.168.4.20'
exit=False
channels={7: '12V ATX',10:'5V ATX',13:'3v3 ATX',16:'1V PS',22:'1V5 PS',25:'1V8 PS',28:'2V5 PS',0:'1v5aux',3:'Virtex5 temp',9:'PPC temp',31:'Actl temp'}
channel_scale={0: 1600.0, 7:250.0, 10:500.0, 13:1000.0, 16:1600.0, 22:1600.0, 25:1600.0, 28:1600.0, 3:4.0, 9:4.0, 31:4.0}
#the fusion measures temperature in Kelvin, with a positive 5 degree offset.
channel_offset={0: 0, 7:0, 10:0, 13:0, 16:0, 22:0, 25:0, 28:0, 3:-278, 9:-278, 31:-278}
pwr_state_decode={4: 'Powered off', 3: 'Powered on', 2: 'Sequencing power up',1: 'Sequencing power up',0: 'Sequencing power up'}

shutdown_reason_decode={0:'Cold start or hard reset', 1: 'Crash', 2:'watchdog overflow', 3: 'User shutdown'}
valid_channels=channels.keys()


try: 
    if sys.argv[1] == '-h' or sys.argv[1] == '?' or sys.argv[1] == '--help': 
        print '\n Connect to a ROACH Xport, monitor and control the Actel Fusion. \nUsage: ./roach_monitor.py [XPORT IP ADDRESS] \n\nJason Manley 2009' 
        exit=True
    else: xport_ip=sys.argv[1]
except: 
    print 'No Xport address specified, defaulting to 192.168.4.20.'

if not exit:
    # CONNECT TO XPORT
    #=================
    xport=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    xport.connect((xport_ip,10001))
    print 'Connecting to 192.168.4.20 on port 10001...',

    # FLUSH RECEIVE BUFFER
    #======================
    xport.setblocking(False)
    try: raw=xport.recv(10)
    except: print ''
    xport.setblocking(True)

    # CHECK THAT WE"RE TALKING TO FUSION
    # ==================================
    ping=struct.pack('<1B',0x08)
    xport.send(ping)
    raw=xport.recv(10)
    if len(raw) == 1:
        raw_unpacked=struct.unpack('<%iB'%len(raw),raw)[0]
        if raw_unpacked != 0x08: 
            print 'Ping error. Received %i bytes:'%len(raw),raw_unpacked
            xport.close()
            sys.exit()

    # PRINT HEADER
    # =============
    print '\nSerial number: %c%c%c%c%c%c.'%(chr(read(0xB8)),chr(read(0xB9)),chr(read(0xBA)),chr(read(0xBB)),chr(read(0xBC)),chr(read(0xBD)))
    print 'ID: %i, revision %i.%i.%i'%(read(0),read(1),read(2),read(3))
    print 'Board time: %i seconds'%((read(0x06)<<32)+(read(0x07)<<16)+(read(0x08)))

    pwr_state_raw=read(0x280)
    pwr_state=pwr_state_raw&7
    shutdown_reason=(pwr_state_raw&0x300)>>8
    print '\nPower state: %i (%s)'%(pwr_state,pwr_state_decode[pwr_state])
    print 'Reason for last shutdown: %i (%s)'%(shutdown_reason,shutdown_reason_decode[shutdown_reason])


while not exit:
    print '====================================='
    print '        ROACH MONITOR CONTROL    '
    print '====================================='
    print ''
    print '  1) Retrieve details'
    print '  2) Reset crashlog counter '
    print '  3) Power-up ROACH '
    print '  4) Reset ROACH, but not Actel '
    print '  5) Toggle safety-shutdown defeat'
    print '  6) Power down ROACH '
    print '  7) Toggle PPC EEPROM boot (config H)'
    print '  other) Exit'

    selection=raw_input('=>')
    
    if selection == '1': print_details()
    elif selection == '2': clear_crashlog()
    elif selection == '3': power_up()
    elif selection == '4': warm_rst()
    elif selection == '5': disable_hard_threshold()
    elif selection == '6': power_down()
    elif selection == '7': toggle_config_h()
    else: exit=True

xport.close()

Reply via email to