Skocz do zawartości

ArduinoISP - wykrycie portu pod Linuksem


ethanak

Pomocna odpowiedź

Taki mały trick...

Zrobiłem sobie programator z Arduino Pro Mini i przejściówki USB/UART na kabelku. Działa bardzo dobrze (bo niby czemu nie?), ma tylko jedną wadę: przynajmniej na Linuksie w zależności od różnych czynników (historii włączeń wtyczek, podłączonych innych urządzeń oraz prawdopodobnie pogody na Marsie) zgłasza się na różnych portach ttyUSB. Przy korzystaniu z Arduino IDE nie jest to specjalnie dużym problemem (tyle, że trzeba sobie kliknąć na którym porcie siedzi programator), o tyle przy używaniu make wymagałoby to edycji Makefile za każdym razem, kiedy zmieni się port.


Postanowiłem uprościć sobie życie i napisać kawałek skryptu, który sprawdzi na jakim porcie siedzi programator i przekaże tę informację do avrdude.
Zasada jest bardzo prosta: przede wszystkim program sprawdza do których portów podpięty jest PL2303 (bo mogę mieć podłączone kilka różnych urządzeń), a następnie po kolei wysyła sekwencję jedynka-spacja na port. Jeśli odpowiedział programator - mamy już nazwę portu.

Program jest na tyle krótki, że zamieszczam kod w całości:

#!/usr/bin/env python
#coding: utf-8

import serial
from serial.tools.list_ports import comports

def detect_avrisp(port):
    try:
        if '067B:2303' not in port[2]:
            return
    except:
        return
    try:
        ser = serial.Serial(port[0], 19200, timeout=1)
    except:
        return
    ser.write('1 ')
    a=ser.read(9)
    if a == '\x14AVR ISP\x10':
        return port[0]
    ser.close()
    return None

  
ports = comports()
avr = []
for port in ports:
    a = detect_avrisp(port)
    if a:
        avr.append(a)
import sys
if len(avr) == 1:
    sys.stdout.write(avr[0])
    exit(0)
elif len(avr) == 0:
    sys.stderr.write("No port\n")
else:
    sys.stderr.write("Too many ports\n")
exit(1)

W przypadku, gdy mamy inny konwerter niż PL2303, należy w miejsce stringu '067B:2303' podać jego Vendor ID i Product ID. W tym celu wydajemy polecenie lsusb, wynik powinien wyglądać jakoś tak:

Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 006 Device 044: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port
Bus 006 Device 041: ID 1ea7:0064  
Bus 006 Device 040: ID 05e3:0606 Genesys Logic, Inc. USB 2.0 Hub / D-Link DUB-H4 USB 2.0 Hub

Po odnalezieniu ID naszego konwertera wstawiamy go we właściwe miejsce w skrypcie.

Możemy teraz sprawdzić czy działa - jeśli programator będzie podłączony, skrypt powinien w odpowiedzi podać jego adres:

ethanak@moiraine: echo `python ~/bin/ispport.py`
/dev/ttyUSB0

(użyłem tu echo, ponieważ skrypt nie wypisuje nowej linii i jego wynik jest dla człowieka niespecjalnie czytelny).

Jeśli skrypt nazwiemy "ispport" i umieścimy np. w /usr/local/bin, odpowiedni fragment Makefile może wyglądać mniej więcej tak:

flash: $(PROGRAM).hex
    avrdude -P $(shell /usr/local/bin/ispport) -b 19200 -c arduino -p t85 -U flash:w:$(PROGRAM).hex

Mała rzecz a cieszy :)

PS. Nie wiem, czy ktoś takie rzeczy już robił, pewnie tak - ale nigdzie czegoś podobnego nie znalazłem.

  • Lubię! 2
Link do komentarza
Share on other sites

Bardzo ładnie. Pozwoliłem sobie trochę poprawić i przeformatować, żeby się lepiej czytało:

#!/usr/bin/env python
#coding: utf-8

import serial
from serial.tools.list_ports import comports


found = None
for name, desc, hardware in comports():
    kind, vidpid, location = hardware.split(None, 2)
    vidpid_label, vidpid_value = vidpid.split(':', 1)
    if vidpid_value != '067B:2303':
        continue
    try:
        with serial.serial(name, 19200, timeout=1) as port:
            port.write('1 ')
            if port.read(9) != '\x14AVR ISP\x10':
                continue
    except Exception:
        continue
    if found:
        raise SystemExit("Too many ports")
    found = name
if not found:
    raise SystemExit("No port")
print name,

Trochę boli mnie jeszcze to "except Exception" — nie lubię pokemon programming — ale nie chce mi się sprawdzać jaki wyjątek tam rzeczywiście lata.

Edytowano przez deshipu
Link do komentarza
Share on other sites

Może być jakiś "busy" albo coś w tym rodzaju. Ogólnie założenie było takie, że jaki by wyjątek nie wyskoczył to to coś co jest do portu podpięte to nie programator 🙂

BTW Twój program chyba nie zadziała - print(name) wywali znak nowej linii na końcu, a tak nie można (avrdude zgłupieje, próbowałem wcześniej, stąd stdout.write()).

  • Lubię! 1
Link do komentarza
Share on other sites

18 minut temu, ethanak napisał:

Może być jakiś "busy" albo coś w tym rodzaju. Ogólnie założenie było takie, że jaki by wyjątek nie wyskoczył to to coś co jest do portu podpięte to nie programator 🙂

 

Jasne, ale jednak jak jest to KeyboardInterrupt albo MemoryError, to chciałbys chyba, żeby program się mimo wszystko przewrócił. Dlatego  łapiemy tylko te wyjątki, których się spodziewamy, inaczej jest bardzo trudno debugować nieoczekiwane błędy.

20 minut temu, ethanak napisał:

BTW Twój program chyba nie zadziała - print(name) wywali znak nowej linii na końcu, a tak nie można (avrdude zgłupieje, próbowałem wcześniej, stąd stdout.write()).

A to przepraszam, poprawiłem (zakładając python 2).

  • Lubię! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Ech... jak by tu powiedzieć żeby nie obrazić...

$ python dupa.py
Traceback (most recent call last):
  File "dupa.py", line 10, in <module>
    kind, vidpid, location = hardware.split(None, 2)
ValueError: need more than 1 value to unpack

Poza tym linijka:

print name, 

robi dokładnie to samo co

print name

a zupełnie coś innego niż

sys.stdout.write(name)

Twój kod jest śliczny i profesjonalny. Mój na odmianę działa.

 

 

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.