x393sata_eyesis4pi_control.py 6.75 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
#!/usr/bin/env python

from __future__ import print_function
from __future__ import division
import x393sata
import x393_mem

import subprocess
import sys
import time
import os
12
import re
13 14 15 16 17 18 19

from time import sleep

LOGFILE = "/var/log/x393sata_eyesis4pi.log"
STATEFILE = "/var/state/ssd"

# constants
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
20
RESET_LIMIT = 3
21 22
DRIVER_RELOAD_LIMIT = 5
DRIVER_WAIT_TIME = 10
23
DRIVER_UNLOAD_TRIES = 30
24

25
#global
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
26
DEVICE_CONNECTED = False
27

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
def colorize(string, color, bold):
    color=color.upper()
    attr = []
    if color == 'RED':
        attr.append('31')
    elif color == 'GREEN':    
        attr.append('32')
    elif color == 'YELLOW':    
        attr.append('33')
    elif color == 'BLUE':    
        attr.append('34')
    elif color == 'MAGENTA':    
        attr.append('35')
    elif color == 'CYAN':    
        attr.append('36')
    elif color == 'GRAY':    
        attr.append('37')
    else:
        pass
        # red
    if bold:
        attr.append('1')
    return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)


def log_msg(msg, mode=0):
    bold = False
    color = ""
    if mode == 2: #bold red - error
        color = "RED"
        bold = True
    elif mode == 3: # just bold
        bold = True
    elif mode == 4: # just bold
        bold = True
        color = "YELLOW" #warning
            
    with open ('/proc/uptime') as f: 
        t=float(f.read().split()[0])
    with open(LOGFILE,'a') as msg_file:
        print("[%8.2f]  %s"%(t,msg),file=msg_file)
    if bold or color:
        msg = colorize(msg,color,bold)    
71
    print (colorize("[%8.2f] %s: "%(t, sys.argv[0].split('/')[-1].split('.')[0]),'GREEN',0)+msg)
72 73 74 75 76 77 78 79


def shout(cmd):
  #subprocess.call prints to console
  subprocess.call(cmd,shell=True)


def connection_errors():
80
  
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
81
  global DEVICE_CONNECTED
82
  
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
  result = True
  skip0 = True
  MAXI1_ADDR = 0x80000000
  group_range = "HBA_PORT__PxSERR"
  cached_addr = None
  cached_data = None
  first_line = True
  
  range_defines = sata.register_defines[group_range]
  
  for fld in range_defines:  
    byte_addr = 4 * fld['dword_address'] + MAXI1_ADDR
    if byte_addr != cached_addr:
        cached_addr = byte_addr
        cached_data = mem.read_mem(cached_addr)
    data = cached_data
    fld_value = (data >> fld['start_bit']) & ((1 << fld['num_bits']) - 1)
    if first_line:
        log_msg("%s: 0x%08x [%08x]"%(group_range, data, byte_addr))
102
        if data!=0:
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
103
          DEVICE_CONNECTED = True
104 105 106 107 108 109 110 111 112 113 114
        first_line = False
    if fld_value or not skip0:
        log_msg("%8x : %s (%s)"%(fld_value, fld['name'], fld['description'] ))
        # the device is there but fails to establish a correct link
        if fld['name']=="DIAG.B" or fld['name']=="DIAG.S" or fld['name']=="ERR.E":
          result = False
        
  return result


def reset_device():
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
115 116 117
  
  global DEVICE_CONNECTED
  
118 119
  result = False
  
120 121
  sleep(0.5)
  
122 123
  for i in range(RESET_LIMIT):
    if not connection_errors():
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
124 125 126
      if i==0:
        DEVICE_CONNECTED = False
        
127 128 129 130 131 132 133 134 135 136
      log_msg("connection error ("+str(i)+"), resetting device",4)
      sata.reset_ie()
      sata.reset_device()
      sleep(0.5)
    else:
      if i!=0: 
        log_msg("resetting device: success")
      result = True
      break
  
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
137 138
  # load driver in any case
  load_driver()
139 140
  return result

141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
def load_ahci_elphel_driver():
  
  shout("modprobe ahci_elphel &")
  shout("sleep 2")
  shout("echo 1 > /sys/devices/soc0/amba@0/80000000.elphel-ahci/load_module")
  log_msg("AHCI driver loaded")
  

def unload_ahci_elphel_driver():
  
  for i in range(DRIVER_UNLOAD_TRIES):
    unmount_partitions()
    try:
      output = subprocess.check_output(["rmmod","ahci_elphel"],stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as e:
      output = [x.strip() for x in e.output.split(":")]
      if output[-1]=="Resource temporarily unavailable":
        log_msg("Tried to unload driver "+str(i)+": "+output[-1])
        if i==(DRIVER_UNLOAD_TRIES-1):
          log_msg("AHCI driver unloading timeout")
        sleep(2)
      else:
163
        log_msg("AHCI driver is not loaded")
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
        break
    else:
      log_msg("AHCI driver unloaded")
      break

def unmount_partitions():
  
  with open("/proc/mounts") as f:
    content = f.readlines()
  
  content = [x.strip() for x in content]
  content = [x.split(" ")[0] for x in content]
  
  for mounted_device in content:
    m = re.search(r"\/dev\/sd[a-z][0-9]",mounted_device)
    if m:
      log_msg("Unmounting "+m.group(0))
      shout("umount "+m.group(0))
182 183 184 185 186

def load_driver():

  for i in range(DRIVER_RELOAD_LIMIT):
    log_msg("Loading SATA driver ("+str(i)+")")
187
    result = reload_driver()
188 189 190 191
    if result:
      break
    
  if not result:
192
    log_msg("SATA failed, SSD was not detected: reconnect SSD",2)
193 194
    shout("echo 0 > "+STATEFILE)
  else:
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
195
    if not DEVICE_CONNECTED:
196 197 198
      log_msg("SSD was not detected, ahci_elphel driver is loaded",4)
    else:
      log_msg("SATA ok, SSD detected after "+str(i)+" tries")
199 200 201
    shout("echo 1 > "+STATEFILE)
  

202 203 204
def check_device():
  with open("/proc/partitions") as f:
    content = f.readlines()
205
  
206 207
  content = [x.strip() for x in content]
  content = [x.split(" ")[-1] for x in content]
208
  
209
  result = False
210
  
211 212 213 214 215 216 217 218
  for device in content:
    m = re.search(r"sd[a-z]",device)
    if m:
      result = True
      break
  
  return result

219
def reload_driver():
220 221 222 223 224 225 226 227 228

  unload_ahci_elphel_driver()
  # check once
  sata.reset_ie()
  #sata.reset_device()
  sleep(0.1)
  connection_errors()
  
  load_ahci_elphel_driver()
229
  
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
230 231 232 233 234 235 236 237 238 239
  if DEVICE_CONNECTED:
    sleep(DRIVER_WAIT_TIME)
    result = check_device()
    
    # one more try
    if not result:
      log_msg(colorize("SSD was not detected: waiting for another "+str(DRIVER_WAIT_TIME)+" seconds",'YELLOW',True))
      sleep(DRIVER_WAIT_TIME)  
      result = check_device()
  else:
240 241
    result = True
  
242
  return result
243 244 245 246 247

def unmount_unload_disconnect():
  unload_ahci_elphel_driver()
  sata.vsc3304.disconnect_all()  

248 249 250 251 252 253 254 255 256 257
mem = x393_mem.X393Mem(0,0,1)
sata = x393sata.x393sata() # 1,0,"10389B")

if len(sys.argv) > 1:
  cmd = sys.argv[1]
else:
  cmd = "donothing"


if   cmd == "set_zynq_ssd":
258
  unmount_unload_disconnect()
259 260 261
  sata.set_zynq_ssd()
  reset_device()
elif cmd == "set_zynq_esata":
262
  unmount_unload_disconnect()
263 264 265
  sata.set_zynq_esata()
  reset_device()
elif cmd == "set_zynq_ssata":
266
  unmount_unload_disconnect()
267 268 269
  sata.set_zynq_ssata()
  reset_device()
elif cmd == "set_esata_ssd":
270
  unmount_unload_disconnect()
271 272 273 274 275 276 277 278
  sata.set_esata_ssd()
  reset_device()
else:
  print("Usage:")
  print("    * camera <-> internal SSD  :            x393sata_eyesis4pi_control.py set_zynq_ssd")
  print("    * camera <-> external disk :            x393sata_eyesis4pi_control.py set_zynq_esata")
  print("    * camera <-> external disk (crossover): x393sata_eyesis4pi_control.py set_zynq_ssata")
  print("    * PC <-> internal SSD)     :            x393sata_eyesis4pi_control.py set_esata_ssd")