CKWARE ASM MODULE FOR KIOSK (copyright 1991)

This portion of software is copyright 1991 Roberto Gaspari, CKWARE Ceo. The author change this code copyright to public-domain in 2006.
If you want to utilize it or simply recompile or publish the project, please mention the author and related header copyright.


    ;******************************************************************************
    ; INT60 per Videobank VSX500
    ; Author Roberto Gaspari, RVM Genova / Ciakware
    ; 
    ; Rel 1.128: 22 Jan 1991 
    ; Rel 1.129: 28 Jan 1991 
    ; Rel 1.130: 06 Feb 1991 
    ; Rel 1.131: 11 Mar 1991 
    ; Rel 1.132: 25 Mar 1991 
    ; Rel 1.133: 17 Dec 1992 
    ; Rel 1.134: 05 Apr 1993 
    ; Rel 1.135: 06 Apr 1993 
    ; Rel 1.136: 14 Sep 1994  (copia per GAMMA srl, Abano) 
    ; Rel 1.137: 16 Oct 1998  (copia per Buster24 per adeguare il nuovo robot Buster) 
    ;
    ; (c)1991-1998 Roberto Gaspari 
    ; porzioni di codice rielaborate da un progetto originale di Ing. Pietro Rotoloni (Videobank 500)
    ;
    ; TASM
    ;
    ;******************************************************************************
    _CODE           SEGMENT
    ASSUME  cs:_CODE,ds:_CODE,es:_CODE
    ORG     100h

    start:          jmp     installa

    SNSPNC          EQU     0 ; tipo sensore pinza (1=switch,0=prossimetro)
    DOORBCKGRD      EQU     1 ; chiusura porta in background (1=abilitata,0=disabilitata)
    BARGP           EQU     0 ; barriere gruppo pinza (1=presenti,0=assenti)
    VERPNZ          EQU     1 ; verifica apertura pinza (1=abilitata,0=disabilitata)
    INT8            EQU     1 ; timer (1=tramite int 8,0=tramite int 1c)

    sign            DB      13,10,'VIDEOBANK VSX500    ',13,10,'$'

    filler          DB      128 DUP(?)

    ;******************************************************************************
    ;
    ;    gestione delle porte di output mappate fra 300h e 31fh
    ;
    ; input: dx = indirizzo
    ;     al = maschera
    ;
    ;******************************************************************************

    port            DB      32 DUP (0)      ; copia dei valori delle porte

    resetbit        PROC    NEAR        ; resetta il bit
    not    al
    mov    bx,dx
    and    [port+bx-300h],al
    mov    al,[port+bx-300h]
    out    dx,al
    ret
    ENDP

    setbit        PROC    NEAR        ; setta il bit
    mov    bx,dx
    or    [port+bx-300h],al
    mov    al,[port+bx-300h]
    out    dx,al
    ret
    ENDP

    reversebit    PROC    NEAR        ; inverte il bit
    mov    bx,dx
    xor    [port+bx-300h],al
    mov    al,[port+bx-300h]
    out    dx,al
    ret
    ENDP

    ;******************************************************************************
    ;
    ;    gestione degli elettromagneti
    ;
    ; input: ds:si = puntatore ai parametri del magnete
    ;
    ; output: zero-flag = stato del sensore
    ;
    ;******************************************************************************
    ; parametri magnete
    MGN        EQU    [si]        ; indirizzo magnete
    MGN_BIT        EQU    [si+2]        ; bit magnete
    MSNS        EQU    [si+3]        ; indirizzo sensore
    MSNS_BIT    EQU    [si+5]        ; bit sensore

    WAIT_MGN    EQU    3        ; tempo attesa lettura sensore

    magneteoff    PROC    NEAR        ; disattiva il magnete
    mov    dx,MGN
    mov    al,MGN_BIT
    call    setbit
    jmp    SHORT magnete

    magneteon:    mov    dx,MGN        ; attiva il magnete
    mov    al,MGN_BIT
    call    resetbit

    magnete:    mov    bx,WAIT_MGN    ; attende
    mgn1:        xor    cx,cx
    loop    $
    dec    bx
    jnz    mgn1
    mov    dx,MSNS        ; legge sensore
    in    al,dx
    test    al,MSNS_BIT
    ret
    ENDP

    ;******************************************************************************
    ;
    ;    gestione dei motori passo-passo
    ;
    ; input: ds:di = puntatore ai parametri fissi del motore
    ;
    ;******************************************************************************
    ; segnali motore
    EN              EQU    [di]        ; indirizzo abilitazione
    EN_BIT        EQU    [di+2]        ; bit abilitazione
    DIR        EQU     [di+3]        ; indirizzo direzione
    DIR_BIT        EQU     [di+5]        ; bit direzione
    CK        EQU     [di+6]        ; indirizzo clock
    CK_BIT        EQU    [di+8]        ; bit clock
    ; parametri rampa velocit…
    START_VEL    EQU    [di+9]        ; velocit… di partenza
    STEPS_ACC    EQU    [di+11]        ; passi per accelerazione
    ACC        EQU    [di+13]        ; accelerazione
    STEPS_DECC    EQU    [di+15]        ; passi per deccelerazione
    DECC        EQU    [di+17]        ; deccelerazione
    ; parametri traiettoria
    SNS        EQU    [si]        ; indirizzo sensore
    SNS_BIT        EQU    [si+2]          ; bit sensore
    SNS_STAT    EQU    [si+3]        ; stato sensore per arresto
    MAX_STEPS    EQU    [si+4]        ; passi massimi prima del sensore
    STEPS_SNS    EQU    [si+6]        ; passi dopo il sensore

    WAIT_SNS    EQU    2000        ; tempo attesa verifica sensore

    steps        DW    ?        ; contatore passi
    vel        DW      ?               ; velocit… attuale

    motoreoff    PROC    NEAR        ; disattiva il motore
    mov    dx,EN
    mov    al,EN_BIT
    call    setbit
    ret
    ENDP

    motoreon    PROC    NEAR        ; attiva il motore: questa non funziona quasi mai a "freddo"
    mov    dx,EN               ; al limite ci butto un loop
    mov    al,EN_BIT
    call    resetbit
    ret
    ENDP

    ;     muove il motore fino al sensore nella direzione specificata
    ;
    ; input: ds:si = puntatore ai parametri della traiettoria
    ;
    ; output: carry-flag = reset se tutto ha funzionato a dovere
    ;      carry-flag = set   se non Š stato raggiunto il sensore

    step        PROC    NEAR        ; muove il motore di un passo
    mov    dx,CK        ; tick
    mov    al,CK_BIT
    call    reversebit
    mov    cx,vel        ; velocit…
    loop    $
    ret
    ENDP

    motore0        PROC    NEAR        ; direzione 0
    mov    dx,DIR
    mov    al,DIR_BIT
    call    resetbit
    jmp    SHORT motorego

    motore1:    mov    dx,DIR        ; direzione 1
    mov    al,DIR_BIT
    call    setbit

    motorego:    call    motoreon    ; abilita il motore

    mov    ax,START_VEL    ; velocit… di partenza
    mov    vel,ax

    mov    ax,STEPS_ACC    ; passi per accelerazione
    mov    steps,ax
    mt1:        call    step
    mov    ax,ACC        ; accellera
    sub    vel,ax
    dec    steps
    jnz    mt1

    mtt1:           mov     ax,MAX_STEPS    ; passi massimi prima del sensore
    mov    steps,ax
    mt2:        call    step
    mov    dx,SNS        ; controlla sensore
    in    al,dx
    and    al,SNS_BIT
    xor    al,SNS_STAT
    jnz    mt3        ; sensore non raggiunto
    mov    cx,WAIT_SNS    ; attende stabilit… segnale
    loop    $
    in    al,dx           ; verifica sensore
    and    al,SNS_BIT
    xor    al,SNS_STAT
    jz    mt4        ; sensore raggiunto
    mt3:            dec    steps
    jnz    mt2        ; continua
    stc            ; TROPPI PASSI !!!
    ret

    mt4:        mov    ax,STEPS_SNS    ; passi dopo il sensore
    mov    steps,ax
    mt5:        call    step
    dec    steps
    jnz    mt5

    mov     dx,SNS          ; verifica stato fine-corsa
    in    al,dx
    and    al,SNS_BIT
    xor    al,SNS_STAT
    jnz     mtt1            ; sensore non raggiunto

    mov    ax,STEPS_DECC    ; passi per deccelerazione
    mov    steps,ax
    mt6:        call    step
    mov    ax,DECC        ; deccellera
    add    vel,ax
    dec    steps
    jnz    mt6

    clc            ; tutto ok
    ret
    ENDP

    ;******************************************************************************
    ;
    ;    gestione del tappeto del posto operatore
    ;
    ;******************************************************************************

    ESC_KEY        EQU    011bh
    F9_KEY          EQU    4300h

    TEN        EQU    0310h          ; segnali motore
    TEN_BIT        EQU    00001000b
    TDIR        EQU    031ch
    TDIR_BIT        EQU     10000000b       ; 0 -> verso l'esterno
    TCK        EQU    0312h
    TCK_BIT        EQU    00100000b
    SNS_EST        EQU    0318h        ; sensore esterno
    SNS_EST_BIT     EQU     00000001b
    SNS_CNT         EQU     0318h           ; sensore centrale
    SNS_CNT_BIT     EQU     00000010b
    SNS_INT        EQU    0318h        ; sensore interno
    SNS_INT_BIT     EQU     00000100b
    MGN_TAPP        EQU     0318h           ; magnete blocco cassetta e micro relativo
    MGN_TAPP_BIT    EQU     00000100b
    MSNS_TAPP       EQU     0318h
    MSNS_TAPP_BIT   EQU     10000000b
    PBOX            EQU     0318h           ; sensore presenza box
    PBOX_BIT        EQU     00001000b
    PBOK            EQU     0310h           ; sensore presenza box ok
    PBOK_BIT        EQU     00000010b

    MAX_STEPS_CNT0  EQU     10000           ; passi massimi prima del sensore cnt.
    MAX_STEPS_CNT1  EQU     7000            ; passi massimi durante il sensore cnt.
    MAX_STEPS_EST   EQU     10000           ; passi massimi espulsione cassetta
    STEPS_EST       EQU     400             ; passi extra espulsione cassetta

    VEL_REG         DW      1300            ; velocita' tappeto a regime
    STEPS_INT       DW      200             ; passi extra dopo sensore centrale

    ex              DW      0

    ;     riporta lo stato attuale del tappeto dedotto dalla lettura dei sensori
    ;
    ; output: ah = 00000XXXb
    ;                   ³³³
    ;                   ³³ÀÄÄÄ = stato sensore esterno
    ;                   ³ÀÄÄÄÄ = stato sensore centrale
    ;                   ÀÄÄÄÄÄ = stato sensore interno

    tappstatus    PROC    NEAR
    xor    ah,ah

    mov     dx,SNS_EST      ; controlla sensore esterno
    in    al,dx
    test    al,SNS_EST_BIT
    jz      ts1             ; sensore a 0
    or      ah,00000001b    ; sensore ad 1

    ts1:            mov     dx,SNS_CNT      ; controlla sensore centrale
    in    al,dx
    test    al,SNS_CNT_BIT
    jz      ts2             ; sensore a 0
    or      ah,00000010b    ; sensore ad 1

    ts2:            mov     dx,SNS_INT      ; controlla sensore interno
    in    al,dx
    test    al,SNS_INT_BIT
    jz      ts3             ; sensore a 0
    or    ah,00000100b    ; sensore ad 1

    ts3:            ret
    ENDP

    ;    muove di un passo il motore del tappeto

    tstep        PROC    NEAR
    mov    dx,TCK        ; tick
    mov    al,TCK_BIT
    call    reversebit
    mov     cx,vel          ; pausa
    loop    $
    ret
    ENDP

    ;       porta la cassetta davanti il tappeto
    ;
    ; output: param = '0' se tutto ha funzionato a dovere
    ;         param = 'P' se ancora prima di aver raggiunto il sensore centrale,
    ;               si Š eccitato un sensore della pinza
    ;         param = '1' se ancora prima di aver raggiunto il sensore centrale,
    ;               e' stato premuto il tasto Esc
    ;         param = '2' se ancora prima di aver raggiunto il sensore centrale
    ;               e' stato premuto il tasto F9
    ;         param = 'A' se non Š mai stato raggiunto il sensore centrale
    ;         param = 'p' se dopo aver raggiunto il sensore centrale, si Š eccitato
    ;               un sensore della pinza
    ;         param = 'B' se non Š mai stato superato il sensore centrale
    ;         param = 'Q' se dopo aver superato il sensore centrale, questo si Š
    ;               eccitato di nuovo
    ;         param = 'q' se dopo aver superato il sensore centrale, si Š eccitato
    ;               un sensore della pinza

    __vbtapp        PROC    NEAR
    mov    dx,TDIR            ; fissa direzione 1
    mov    al,TDIR_BIT
    call    setbit

    mov    dx,TEN            ; attiva motore
    mov    al,TEN_BIT
    call    resetbit

    mov     ax,VEL_REG             ; velocit… di regime
    mov     vel,ax

    mov     dx,SNS_INT              ; controlla sensore interno
    in      al,dx
    test    al,SNS_INT_BIT
    jz      tapp4                   ; sensore eccitato

    ; cassetta davanti sensore centrale

    mov     steps,MAX_STEPS_CNT0    ; massima attesa cassetta

    tapp1:          call    tstep                   ; un passo

    mov     dx,SNS_CNT              ; controlla sensore centrale
    in    al,dx
    test    al,SNS_CNT_BIT
    jnz    tapp2            ; sensore non eccitato
    mov    cx,WAIT_SNS        ; attende stabilit… segnale
    loop    $
    in    al,dx            ; verifica sensore
    test    al,SNS_CNT_BIT
    jz    tapp4            ; sensore eccitato

    tapp2:          mov     dx,BAR_ANT              ; controlla sensori pinza
    in    al,dx
    test    al,BAR_ANT_BIT
    jnz     lp                      ; sensori non eccitati
    mov    cx,WAIT_SNS        ; attende stabilit… segnale
    loop    $
    in      al,dx                   ; verifica sensori
    test    al,BAR_ANT_BIT
    jnz     lp                      ; sensori non eccitati
    mov     al,'P'
    jmp     tappret                 ; sensori eccitati

    lp:             mov     ah,01h                  ; lettura tastiera al volo
    int    16h
    jz    tapp3            ; nessun tasto
    xor    ah,ah            ; scarica il buffer
    int    16h
    cmp     ax,ESC_KEY
    jne     tapp31
    mov    al,'1'
    jmp     tappret                 ; ESC
    tapp31:         cmp     ax,F9_KEY
    jne     tapp3
    mov    al,'2'
    jmp     tappret                 ; F9

    tapp3:          dec     steps                   ; controlla passi totali
    jnz     tapp1                   ; pochi: continua
    mov    al,'A'            ; time-out
    jmp    tappret

    ; cassetta dopo sensore centrale

    tapp4:          mov     steps,MAX_STEPS_CNT1    ; massima attesa cassetta

    tapp5:          call    tstep                   ; un passo

    mov     dx,SNS_CNT              ; controlla sensore centrale
    in    al,dx
    test    al,SNS_CNT_BIT
    jz    tapp6            ; sensore eccitato
    mov    cx,WAIT_SNS        ; attende stabilit… segnale
    loop    $
    in    al,dx            ; verifica sensore
    test    al,SNS_CNT_BIT
    jz      tapp6                   ; sensore eccitato
    mov     dx,SNS_INT              ; controlla barriera interna
    in      al,dx
    test    al,SNS_INT_BIT
    jz      tapp7                   ; barriera interrotta

    tapp6:          mov     dx,BAR_ANT              ; controlla sensori pinza
    in    al,dx
    test    al,BAR_ANT_BIT
    jnz     lp1                     ; sensori non eccitati
    mov    cx,WAIT_SNS        ; attende stabilit… segnale
    loop    $
    in      al,dx                   ; verifica sensori
    test    al,BAR_ANT_BIT
    jnz     lp1                     ; sensori non eccitati
    mov     al,'p'
    jmp     tappret                 ; sensori eccitati

    lp1:            mov     dx,SNS_EST              ; controlla barriera esterna
    in      al,dx
    test    al,SNS_EST_BIT
    jnz     lp11                    ; barriera non interrotta
    mov     dx,SNS_INT              ; controlla barriera interna
    in      al,dx
    test    al,SNS_INT_BIT
    jnz     lp11                    ; barriera non interrotta
    mov     al,'Q'
    jmp     tappret                 ; 3 barriere interrotte

    lp11:           dec     steps                   ; controlla passi totali
    jnz     tapp5                   ; pochi: continua
    mov    al,'B'            ; time-out
    jmp    tappret

    ; passi extra

    tapp7:          mov     ax,STEPS_INT            ; passi dopo sensore
    mov     steps,ax

    tapp8:          call    tstep                   ; un passo

    mov     dx,SNS_CNT              ; controlla sensore centrale
    in    al,dx
    test    al,SNS_CNT_BIT
    jnz     lp2                     ; sensore non eccitato
    mov     cx,WAIT_SNS             ; attesa stabilta' segnale
    loop    $
    in      al,dx                   ; verifica sensore
    test    al,SNS_CNT_BIT
    jnz     lp2                     ; sensore non eccitato
    mov    al,'Q'
    jmp     tappret                 ; sensore eccitato

    lp2:            mov     dx,BAR_ANT              ; controlla sensori pinza
    in    al,dx
    test    al,BAR_ANT_BIT
    jnz     lp3                     ; sensori non eccitati
    mov     cx,WAIT_SNS             ; attesa stabilita' segnale
    loop    $
    in      al,dx                   ; verifica sensori
    test    al,BAR_ANT_BIT
    jnz     lp3                     ; sensori non eccitati
    mov    al,'q'
    jmp     tappret                 ; sensori eccitati

    lp3:            dec     steps                   ; controlla passi fatti
    jnz     tapp8                   ; pochi: continua

    mov    al,'0'            ; tutto ok

    tappret:    push    ax            ; salva esito
    mov    dx,TEN            ; disattiva motore
    mov    al,TEN_BIT
    call    setbit
    pop    ax            ; ripristina esito
    ret
    ENDP

    ;       espelle la cassetta
    ;
    ; output: param = '0' se tutto ha funzionato a dovere
    ;         param = 'B' se time-out

    esp_stat        DB      ?                       ; stato da raggiungere
    esp_max         DW      ?                       ; passi massimi
    esp_ex          DW      ?                       ; passi extra

    ___vbesp        PROC    NEAR
    mov    dx,TDIR            ; fissa direzione 0
    mov    al,TDIR_BIT
    call    resetbit

    mov    dx,TEN            ; attiva motore
    mov    al,TEN_BIT
    call    resetbit

    mov     ax,VEL_REG             ; velocit… di regime
    mov     vel,ax

    mov     steps,0                 ; passi totali

    esp1:           mov     ex,0                    ; passi extra

    esp2:           call    tstep                   ; un passo
    inc     steps

    call    tappstatus              ; controlla sensori
    cmp     ah,esp_stat
    jne     esp3                    ; sensori non ok
    inc     ex                      ; controlla passi extra
    mov     ax,ex
    cmp     ax,esp_ex
    jb      esp2                    ; continua
    mov     al,'0'                  ; tutto ok
    jmp     espret

    esp3:           mov     ax,steps
    cmp     ax,esp_max              ; controlla passi totali
    jb      esp1                    ; pochi: continua
    mov     al,'B'                  ; time-out

    espret:        push    ax            ; salva esito
    mov    dx,TEN            ; disattiva motore
    mov    al,TEN_BIT
    call    setbit
    pop    ax            ; ripristina esito
    ret
    ENDP

    __vbesp         PROC    NEAR                    ; espulsione totale
    mov     esp_stat,111b
    mov     esp_max,MAX_STEPS_EST
    mov     esp_ex,STEPS_EST
    jmp     ___vbesp
    ENDP

    __vbespp        PROC    NEAR                    ; espulsione parziale, utente batman
    mov     esp_stat,100b
    mov     esp_max,MAX_STEPS_EST
    mov     esp_ex,30
    jmp     ___vbesp
    ENDP

    COMMENT ~

    ;       porta la cassetta davanti il tappeto

    __vbtapp        PROC    NEAR
    mov     dx,TEN          ; abilitazione
    mov     al,TEN_BIT
    call    resetbit

    mov     dx,TDIR         ; direzione
    mov     al,TDIR_BIT
    call    setbit

    __tapp1:        mov     dx,TCK          ; clock
    mov     al,TCK_BIT
    call    reversebit

    mov     cx,VEL_REG      ; velocita'
    loop    $

    mov     dx,SNS_CNT      ; controlla barriera centrale
    in      al,dx
    test    al,SNS_CNT_BIT
    jnz     __tapp1         ; barriera non interrotta

    __tapp2:        mov     dx,TCK          ; clock
    mov     al,TCK_BIT
    call    reversebit

    mov     cx,VEL_REG      ; velocita'
    loop    $

    mov     dx,SNS_CNT      ; controlla barriera interna
    in      al,dx
    test    al,SNS_CNT_BIT
    jz      __tapp2         ; barriera interrotta

    mov     dx,TEN          ; disabilitazione
    mov     al,TEN_BIT
    call    setbit

    mov     al,'0'          ; ok
    ret
    ENDP

    ;       espelle la cassetta

    __vbespp        LABEL   NEAR
    __vbesp         PROC    NEAR
    mov     dx,TEN          ; abilitazione
    mov     al,TEN_BIT
    call    resetbit

    mov     dx,TDIR         ; direzione
    mov     al,TDIR_BIT
    call    resetbit

    __esp1:         mov     dx,TCK          ; clock
    mov     al,TCK_BIT
    call    reversebit

    mov     cx,VEL_REG      ; velocita'
    loop    $

    mov     dx,SNS_EST      ; controlla barriera esterna
    in      al,dx
    test    al,SNS_EST_BIT
    jnz     __esp1          ; barriera non interrotta

    mov     dx,TEN          ; disabilitazione
    mov     al,TEN_BIT
    call    setbit

    mov     al,'0'          ; ok
    ret
    ENDP

    ~
    ;******************************************************************************
    ;
    ;    gestione della porta del posto operatore
    ;
    ;******************************************************************************

    APERTA          EQU     00000010b       ; porta aperta
    CHIUSA          EQU     00000001b       ; porta chiusa

    pen        DW    0310h          ; segnali motore
    pen_bit        DB    00000100b
    pdir        DW    031ch
    pdir_bit        DB      01000000b       ; 0 -> verso chiusura
    pck        DW    0312h
    pck_bit        DB    00010000b

    pstart_vel      DW      1200            ; parametri rampa velocit…
    psteps_acc    DW    1
    pacc        DW    0
    psteps_decc    DW    1
    pdecc        DW    0

    sns_inf        DW    0318h        ; dati per chiusura porta
    sns_inf_bit    DB    00100000b
    sns_inf_stat    DB    00000000b
    max_steps_down    DW    6000
    steps_sns_down  DW      20

    sns_sup        DW    0318h        ; dati per apertura porta
    sns_sup_bit    DB    00010000b
    sns_sup_stat    DB    00000000b
    max_steps_up    DW    6000
    steps_sns_up    DW      40

    mgn_blc        DW    0318h        ; magnete blocco porta
    mgn_blc_bit    DB    00001000b
    msns_blc        DW      0318h
    msns_blc_bit    DB      01000000b

    status          DB      0               ; stato teorico porta (0=aperta, 1=chiusa, 2=incastrata in chiusura)
    time1           DW      ?               ; istante chiusura completata se plexiglas e finecorsa sani

    ;    riporta lo stato attuale della porta dedotto dalla lettura dei sensori
    ;
    ; output: ah = 000000XXb
    ;                    ³ÀÄÄÄ = stato sensore superiore
    ;                    ÀÄÄÄÄ = stato sensore inferiore

    portastatus    PROC    NEAR
    xor    ah,ah

    mov    dx,sns_inf    ; controlla sensore inferiore
    in    al,dx
    test    al,sns_inf_bit
    jz    ps1             ; sensore a 0
    or      ah,00000010b    ; sensore ad 1

    ps1:        mov    dx,sns_sup    ; controlla sensore superiore
    in    al,dx
    test    al,sns_sup_bit
    jz    ps2        ; sensore a 0
    or      ah,00000001b    ; sensore ad 1

    ps2:            ret
    ENDP

    ;     chiude la porta
    ;
    ; output: param = '0' se tutto ha funzionato a dovere
    ;      param = 'B' se la porta non si Š chiusa nel tempo stabilito
    ;      param = 'D' se dopo la chiusura la porta non risultava chiusa

    __vbdown        PROC    NEAR
    mov     status,0                ; imposta porta aperta

    mov     di,OFFSET pen           ; chiude
    mov    si,OFFSET sns_inf
    call    motore0
    mov    al,'B'
    jc    downret            ; CHIUSURA NON AVVENUTA !!!

    IF INT8 EQ 0                    ; se non c'e' chiusura in background
    call    motoreoff               ; resetta motore (in background)
    ENDIF

    call    portastatus             ; controlla stato porta
    cmp    ah,CHIUSA
    mov    al,'D'
    jne    downret            ; PORTA NON CHIUSA !!!

    mov    al,'0'            ; tutto ok

    cli
    mov     status,1                ; imposta porta chiusa
    mov     time1,0                 ; registra istante attuale
    sti
    ret

    downret:        push    ax                      ; salva esito
    call    motoreoff               ; disabilita motore
    pop     ax                      ; recupera esito
    mov     status,2                ; imposta porta incastrata
    ret
    ENDP

    ;    apre la porta
    ;
    ; output: param = '0' se tutto ha funzionato a dovere
    ;      param = 'C' se la porta non si Š aperta nel tempo stabilito
    ;      param = 'D' se dopo l'apertura la porta non risultava aperta

    __vbup          PROC    NEAR
    mov     status,0                ; imposta porta aperta

    mov     di,OFFSET pen           ; apre
    mov    si,OFFSET sns_sup
    call    motore1
    mov    al,'C'
    jc    upret            ; APERTURA NON AVVENUTA !!!

    call    portastatus             ; controlla stato porta
    cmp    ah,APERTA
    mov    al,'D'
    jne    upret            ; PORTA NON APERTA !!!

    mov    al,'0'            ; tutto ok

    upret:          ret
    ENDP

    ;******************************************************************************
    ;
    ;    gestione del gruppo pinza
    ;
    ;******************************************************************************

    MT0             EQU          ; direzione 0
    MT1        EQU        ; direzione 1
    MAG             EQU          ; pinza davanti magazzino
    RIP             EQU         ; pinza a riposo
    RIP_MCR      EQU         
    RIP_MCR_BIT  EQU         
    RIP_MCR_STAT EQU         
    RIP_MAX      EQU         
    RIP_EX       EQU         
    TIN             EQU         ; cassetta dentro tappeto
    TOUT            EQU         ; cassetta su bordo tappeto
    FBR             EQU         ; indirizzo fibra
    FBR_BIT         EQU         ; maschera fibra
    BAR             EQU         ; indirizzo barriera
    BAR_BIT         EQU         ; maschera barriera
    MGN             EQU         ; magnete pinza
    VICINO          EQU         ; passi vicino magazzino
    OTHER           EQU         ; puntatore all'altro magazzino

    TNT_PNZ         EQU     3
    TNT_PMAG        EQU     15
    TNT_INS        EQU    10
    TNT_OUT        EQU    10
    EX_FIBRA        EQU     100

    MCR_ANT         EQU     0310h
    MCR_ANT_BIT     EQU     00010000b
    MCR_POS         EQU     0316h
    MCR_POS_BIT     EQU     00000001b
    MCR_CNT         EQU     0310h
    MCR_CNT_BIT     EQU     00100000b
    IF BARGP EQ 1                                   ; se ci sono le barriere
    BAR_ANT         EQU     0316h               ; le associo ai loro indirizzi
    BAR_ANT_BIT     EQU     00100000b
    BAR_POS         EQU     0316h
    BAR_POS_BIT     EQU     01000000b
    ELSE                                            ; se non ci sono le barriere
    BAR_ANT         EQU     FBR_ANT             ; le associo alle fibre
    BAR_ANT_BIT     EQU     FBR_ANT_BIT
    BAR_POS         EQU     FBR_POS
    BAR_POS_BIT     EQU     FBR_POS_BIT
    ENDIF
    FBR_ANT         EQU     031ah
    FBR_ANT_BIT     EQU     01000000b
    FBR_POS         EQU     031ah
    FBR_POS_BIT     EQU     10000000b
    MMCR_ANT        EQU     0316h
    MMCR_ANT_BIT    EQU     00001000b
    MMCR_POS        EQU     0316h
    MMCR_POS_BIT    EQU     00010000b

    ppvel           DW      1400
    ttvel           DW      1400

    ; motore trasporto pinza
    ppen        DW    0310h        ; segnali motore
    ppen_bit    DB    00100000b
    ppdir        DW    0314h
    ppdir_bit       DB      00001000b       ; 0 -> verso anteriore
    ppck        DW    0312h
    ppck_bit    DB    10000000b

    ppstart_vel     DW      1400            ; parametri rampa velocit…
    ppsteps_acc    DW    1
    ppacc        DW    0
    ppsteps_decc    DW    1
    ppdecc        DW    0
    ; motore tappeto pinza
    tten            DW      0310h           ; segnali motore
    tten_bit    DB    00010000b
    ttdir        DW    0314h
    ttdir_bit       DB      00000100b       ; 0 -> verso posteriore
    ttck        DW    0312h
    ttck_bit    DB    01000000b

    ttstart_vel     DW      1400            ; parametri rampa velocit…
    ttsteps_acc    DW    1
    ttacc        DW    0
    ttsteps_decc    DW    1
    ttdecc        DW    0

    ; parametri per azioni su magazzino anteriore

    mt0_ant        DW    OFFSET motore1  ; direzione motori
    mt1_ant        DW    OFFSET motore0

    mcr_cnta        DW      MCR_CNT         ; dati per trasporto pinza davanti
    mcr_cnta_bit    DB      MCR_CNT_BIT     ; magazzino da posizione di riposo
    mcr_cnta_stat   DB      MCR_CNT_BIT
    max_steps_ravt    DW    1000
    steps_sns_ravt  DW      10

    mcr_ant         DW      MCR_POS         ; dati per trasporto pinza in posizione
    mcr_ant_bit     DB      MCR_POS_BIT     ; di riposo da magazzino
    mcr_ant_stat    DB      MCR_POS_BIT
    max_steps_ind    DW    1000
    steps_sns_ind   DW      10

    IF BARGP EQ 1
    bar_pos0        DW      BAR_POS         ; dati per trasporto cassetta in
    bar_pos0_bit    DB      BAR_POS_BIT     ; centro tappeto da bordo esterno
    bar_pos0_stat   DB      00000000b
    ELSE
    bar_pos0        DW      FBR_ANT         ; idem in caso di assenza barriere
    bar_pos0_bit    DB      FBR_ANT_BIT
    bar_pos0_stat   DB      FBR_ANT_BIT
    ENDIF
    max_steps_aind  DW      3000
    steps_sns_aind  DW      10

    bar_ant1        DW      BAR_ANT                 ; dati per trasporto cassetta
    bar_ant1_bit    DB      BAR_ANT_BIT+BAR_POS_BIT ; da centro tappeto a bordo
    bar_ant1_stat   DB      BAR_ANT_BIT+BAR_POS_BIT ; esterno
    max_steps_cavt  DW      3000
    steps_sns_cavt  DW      10

    fbr_ant         DW      FBR_ANT         ; fibra
    fbr_ant_bit     DB      FBR_ANT_BIT

    bar_ant         DW      BAR_ANT         ; barriera
    bar_ant_bit     DB      BAR_ANT_BIT

    mgn_ant         DW      0318h           ; magnete pinza
    mgn_ant_bit     DB      00100000b
    mmcr_ant        DW      MMCR_ANT
    mmcr_ant_bit    DB      MMCR_ANT_BIT

    vicino_ant      DW      100             ; passi vicino magazzino

    othera          DW      OFFSET mt0_pos

    ; parametri per azioni su magazzino posteriore

    mt0_pos        DW    OFFSET motore0  ; direzione motori
    mt1_pos        DW    OFFSET motore1

    mcr_cntp        DW      MCR_CNT         ; dati per trasporto pinza davanti
    mcr_cntp_bit    DB      MCR_CNT_BIT     ; magazzino da posizione di riposo
    mcr_cntp_stat   DB      MCR_CNT_BIT
    max_steps_rind    DW    1000
    steps_sns_rind  DW      10

    mcr_pos         DW      MCR_ANT         ; dati per trasporto pinza in posizione
    mcr_pos_bit     DB      MCR_ANT_BIT     ; di riposo da magazzino
    mcr_pos_stat    DB      MCR_ANT_BIT
    max_steps_avt    DW    1000
    steps_sns_avt   DW      10

    IF BARGP EQ 1
    bar_ant0        DW      BAR_ANT         ; dati per trasporto cassetta in
    bar_ant0_bit    DB      BAR_ANT_BIT     ; centro tappeto da bordo esterno
    bar_ant0_stat   DB      00000000b
    ELSE
    bar_ant0        DW      FBR_POS         ; idem in caso di assenza barriere
    bar_ant0_bit    DB      FBR_POS_BIT
    bar_ant0_stat   DB      FBR_POS_BIT
    ENDIF
    max_steps_pavt  DW      3000
    steps_sns_pavt  DW      10

    bar_pos1        DW      BAR_POS                 ; dati per trasporto cassetta
    bar_pos1_bit    DB      BAR_POS_BIT+BAR_ANT_BIT ; da centro tappeto a bordo
    bar_pos1_stat   DB      BAR_POS_BIT+BAR_ANT_BIT ; esterno
    max_steps_cind  DW      3000
    steps_sns_cind  DW      10

    fbr_pos         DW      FBR_POS         ; fibra
    fbr_pos_bit     DB      FBR_POS_BIT

    bar_pos         DW      BAR_POS         ; barriera
    bar_pos_bit     DB      BAR_POS_BIT

    mgn_pos         DW      0318h           ; magnete pinza
    mgn_pos_bit     DB      00010000b
    mmcr_pos        DW      MMCR_POS
    mmcr_pos_bit    DB      MMCR_POS_BIT

    vicino_pos      DW      100             ; passi vicino magazzino

    otherp          DW      OFFSET mt0_ant

    IF BARGP EQ 0                           ; se non ci sono le barriere
    tout0           DW        ?         ; in trasporto cassetta da centro
    tout0_bit       DB        ?         ; a bordo tappeto e' necessario prima
    tout0_stat      DB        00000000b ; eccitare una fibra
    tout0_max       DW        1000
    tout0_ex        DW        50
    ENDIF

    t               DW      ?

    ;       riporta in AX la variazione di velocita' del trasporto pinza

    ppvelvar        PROC    NEAR
    mov     ax,ppvel
    shr     ax,1
    ret
    ENDP

    ;       abbassa la velocita' del trasporto

    ppslow          PROC    NEAR
    call    ppvelvar
    add     ppstart_vel,ax
    ret
    ENDP

    ;       aumenta la velocita' del trasporto

    ppfast          PROC    NEAR
    call    ppvelvar
    sub     ppstart_vel,ax
    ret
    ENDP

    ;       riporta in AX la variazione di velocita' del tappeto pinza

    ttvelvar        PROC    NEAR
    mov     ax,ttvel
    shr     ax,1
    ret
    ENDP

    ;       abbassa la velocita' del tappeto

    ttslow          PROC    NEAR
    call    ttvelvar
    add     ttstart_vel,ax
    ret
    ENDP

    ;       aumenta la velocita' del tappeto

    ttfast          PROC    NEAR
    call    ttvelvar
    sub     ttstart_vel,ax
    ret
    ENDP

    ;       riporta in AH lo stato delle barriere
    ;
    ; out: bit0 = stato barriera anteriore
    ;      bit1 = stato barriera posteriore

    barstat         PROC    NEAR
    xor     ah,ah           ; inizializza stato

    mov     dx,BAR_ANT      ; controlla barriera anteriore
    in      al,dx
    test    al,BAR_ANT_BIT
    jz      brs1            ; barriera interrotta
    or      ah,01b          ; barriera non interrotta

    brs1:           mov     dx,BAR_POS      ; controlla barriera posteriore
    in      al,dx
    test    al,BAR_POS_BIT
    jz      brs2            ; barriera interrotta
    or      ah,10b          ; barriera non interrotta

    brs2:           ret                     ; fine
    ENDP

    ;       riporta in AH lo stato dei micro
    ;
    ; out: bit0 = stato micro anteriore
    ;      bit1 = stato micro centrale
    ;      bit2 = stato micro posteriore

    mcrstat         PROC    NEAR
    xor     ah,ah           ; inizializza stato

    mov     dx,MCR_ANT      ; controlla micro anteriore
    in      al,dx
    test    al,MCR_ANT_BIT
    jz      mrs1            ; micro premuto
    or      ah,001b         ; micro rilasciato

    mrs1:           mov     dx,MCR_CNT      ; controlla micro centrale
    in      al,dx
    test    al,MCR_CNT_BIT
    jz      mrs2            ; micro premuto
    or      ah,010b         ; micro rilasciato

    mrs2:           mov     dx,MCR_POS      ; controlla micro posteriore
    in      al,dx
    test    al,MCR_POS_BIT
    jz      mrs3            ; micro premuto
    or      ah,100b         ; micro rilasciato

    mrs3:           ret                     ; fine
    ENDP

    ;       cerca di portare il tappeto in posizione di riposo
    ;
    ; out: cf = esito (set = negativo, reset = positivo)

    taprip          PROC    NEAR
    mov     di,OFFSET tten  ; tappeto pinza

    call    ttslow          ; bassa velocita'

    call    barstat         ; legge stato barriere
    cmp     ah,10b
    je      tprpa           ; cassetta verso anteriore
    cmp     ah,01b
    je      tprpp           ; cassetta verso posteriore

    tprpok:         call    ttfast          ; alta velocita'
    clc                     ; ok
    ret

    tprpa:          mov     si,OFFSET bar_pos0      ; cassetta in centro da ant.
    call    motore0

    call    barstat                 ; legge stato barriere
    IF BARGP EQ 1
    cmp     ah,00b
    ELSE
    cmp     ah,11b
    ENDIF
    je      tprpok                  ; cassetta in centro
    cmp     ah,01b
    je      tprpok                  ; cassetta verso posteriore
    jmp     tprperr                 ; ERRORE !!!

    tprpp:          mov     si,OFFSET bar_ant0      ; cassetta in centro da pos.
    call    motore1

    call    barstat                 ; legge stato barriere
    IF BARGP EQ 1
    cmp     ah,00b
    ELSE
    cmp     ah,11b
    ENDIF
    je      tprpok                  ; cassetta in centro
    cmp     ah,10b
    je      tprpok                  ; cassetta verso anteriore

    tprperr:        call    ttfast          ; alta velocita'
    stc                     ; ERRORE !!!
    ret
    ENDP

    ;       cerca di portare la pinza in posizione di riposo
    ;
    ; out: cf = esito (set = negativo, reset = positivo)

    pnzrip          PROC    NEAR
    mov     di,OFFSET ppen  ; trasporto pinza

    call    ppslow          ; bassa velocita'

    call    mcrstat         ; legge stato micro
    cmp     ah,100b
    je      pzrpp           ; pinza un po' indietro
    cmp     ah,110b
    je      pzrpp           ; pinza tutta indietro
    cmp     ah,001b
    je      pzrpa           ; pinza un po' avanti
    cmp     ah,011b
    je      pzrpa           ; pinza tutta avanti
    cmp     ah,101b
    je      pzrpok          ; pinza a riposo

    pzrperr:        call    ppfast          ; alta velocita'
    stc                     ; ERRORE !!!
    ret

    pzrpp:          mov     si,OFFSET mcr_pos       ; pinza a riposo da pos.
    call    motore0

    call    mcrstat                 ; legge stato micro
    cmp     ah,001b
    je      pzrpok                  ; pinza un po' avanti
    cmp     ah,101b
    je      pzrpok                  ; pinza a riposo
    jmp     pzrperr                 ; ERRORE !!!

    pzrpa:          mov     si,OFFSET mcr_ant       ; pinza a riposo da ant.
    call    motore1

    call    mcrstat                 ; legge stato micro
    cmp     ah,100b
    je      pzrpok                  ; pinza un po' indietro
    cmp     ah,101b
    je      pzrpok                  ; pinza a riposo
    jmp     pzrperr                 ; ERRORE !!!

    pzrpok:         call    ppfast          ; alta velocita'
    clc                     ; ok
    ret
    ENDP

    ;       cerca di portare la pinza in uno stato stabile e ne riporta l'esito
    ;
    ; output: cf = esito (set = negativo, reset = positivo)
    ;         zf = stato in caso di presenza barriere
    ;                (set = con cassetta, reset = senza cassetta)

    statopinza      PROC    NEAR
    call    pnzrip          ; pinza a riposo
    jc      statoret        ; ERRORE !!!

    call    taprip          ; tappeto a riposo
    jc      statoret        ; ERRORE !!!

    IF BARGP EQ 1                   ; se ci sono le barriere
    call    barstat         ; controlla presenza cassetta
    test    ah,01b
    jz      statook         ; cassetta presente
    test    ah,10b
    ENDIF

    statook:        clc                     ; ok

    statoret:       ret
    ENDP

    ;       chiusura pinza

    pnz_on          PROC    NEAR
    lea     si,MGN          ; magnete pinza
    mov     cx,TNT_PNZ      ; # tentativi
    jmp     SHORT po2
    po1:            push    cx
    call    magneteoff    ; apre
    pop    cx
    po2:            push    cx
    call    magneteon    ; chiude
    pop    cx
    IF SNSPNC EQ 1                ; se i magneti hanno i micro
    jnz     po3             ; pinza chiusa
    ELSE                          ; altrimenti ci sono i prossimetri
    jz      po3             ; pinza chiusa
    ENDIF
    loop    po1
    po3:            ret
    ENDP

    ;       apertura pinza

    ver_pnz         DB      ?               ; flag di verifica apertura pinza
    ; (1=pinza aperta,0=pinza chiusa)

    pnz_off         PROC    NEAR
    lea     si,MGN          ; magnete pinza
    call    magneteoff      ; apre
    mov     ver_pnz,1       ; imposta apertura avvenuta
    IF SNSPNC EQ 1                  ; se i magneti hanno i micro
    jz      pnzor           ; pinza aperta
    ELSE                            ; altrimenti ci sono i prossimetri
    jnz     pnzor           ; pinza aperta
    ENDIF
    mov     ver_pnz,0       ; imposta apertura fallita
    pnzor:          ret
    ENDP

    ;       pinzata da magazzino
    ;
    ; output: zf = stato della barriera

    pinzata_mag     PROC    NEAR
    mov     di,OFFSET ppen  ; pinza davanti magazzino
    lea     si,MAG
    call    MT1

    call    pnz_on          ; chiusura pinza

    mov     dx,ttdir        ; dir. tapp. (verso mag. opposto)
    mov    al,ttdir_bit
    call    setbit          ; verso anteriore
    cmp     word ptr MT1,OFFSET motore1
    je      pm1
    mov     dx,ttdir
    mov     al,ttdir_bit
    call    resetbit    ; verso posteriore

    pm1:            mov     al,ttck_bit     ; pinza a riposo con rotazione tappeto
    or    ppck_bit,al
    lea     si,RIP
    call    MT0
    mov    al,ttck_bit
    not    al
    and    ppck_bit,al

    call    pnz_off         ; apertura pinza

    mov     dx,BAR          ; controllo barriera
    in      al,dx
    test    al,BAR_BIT
    ret
    ENDP

    ;       pinzata da tappeto
    ;
    ; output: zf = esito (set -> ok, reset -> si richiede ulteriore pinzata)

    fibra           DW      ?
    totrip          DW      ?
    exrip           DW      ?

    ind             DB      ? ; flag di indietreggiamento:
    ; 0 -> non indietreggiare, 1 -> indietreggiare

    STEPSIND        DW      30      ; passi indietro dopo apertura pinza e prima
    ; di controllare la fibra su magazzino

    pinzata_tap     PROC    NEAR
    call    pnz_on          ; chiusura pinza

    mov     dx,ttdir        ; dir. tapp. (verso mag.)
    mov    al,ttdir_bit
    call    setbit          ; verso anteriore
    cmp     word ptr MT0,OFFSET motore1
    je      _pt1
    mov     dx,ttdir
    mov     al,ttdir_bit
    call    resetbit    ; verso posteriore

    _pt1:           mov     al,ttck_bit     ; pinza su mag. con rotazione tappeto
    or    ppck_bit,al
    mov    di,OFFSET ppen
    lea     si,MAG
    call    MT1
    mov    al,ttck_bit
    not    al
    and    ppck_bit,al

    cmp     ind,5           ; controlla indietreggiamento
    jb      no_ind          ; indietreggiamento non attivo

    mov     ax,2            ; attende un po'
    __pt1:          xor     cx,cx
    loop    $
    dec     ax
    jnz     __pt1

    call    pnz_off         ; apertura pinza

    ; pinza un po' indietro lentamente
    mov     dx,ppdir        ;   inverte direzione
    mov     al,ppdir_bit
    call    reversebit
    call    ppslow          ;   bassa velocita'
    mov     cx,STEPSIND     ;   passi da fare
    call    stepss          ;   muove
    call    ppfast          ;   alta velocita'

    mov     ax,2            ; attende un po'
    ___pt1:         xor     cx,cx
    loop    $
    dec     ax
    jnz     ___pt1

    mov     fibra,0         ; imposta fibra diseccitata
    mov     dx,FBR          ; controlla fibra
    in      al,dx
    test    al,FBR_BIT
    jnz     _pt2            ; fibra diseccitata
    mov     fibra,1         ; imposta fibra eccitata
    jmp     _pt2

    no_ind:         mov     fibra,0         ; imposta fibra diseccitata
    mov     dx,FBR          ; controlla fibra
    in      al,dx
    test    al,FBR_BIT
    jnz     __pt2           ; fibra diseccitata
    mov     fibra,1         ; imposta fibra eccitata

    __pt2:          call    pnz_off         ; apertura pinza

    mov     dx,ppdir        ; inverte direzione trasporto pinza
    mov     al,ppdir_bit
    call    reversebit

    ; riporta la pinza in posizione di riposo

    _pt2:           mov     totrip,0        ; passi totali
    mov     exrip,0         ; passi extra

    _pt3:           mov     dx,ppck         ; un passo
    mov     al,ppck_bit
    call    reversebit
    mov     cx,ppstart_vel
    loop    $
    inc     totrip

    mov     dx,RIP_MCR      ; controlla stato di riposo
    in      al,dx
    and     al,RIP_MCR_BIT
    xor     al,RIP_MCR_STAT
    jnz     _pt4            ; stato non raggiunto

    inc     exrip           ; controlla passi extra
    mov     ax,exrip
    cmp     ax,RIP_EX
    jbe     _pt5            ; pochi: continua

    mov     cx,WAIT_SNS     ; attende stabilita' segnale
    loop    $

    in      al,dx           ; verifica stato di riposo
    and     al,RIP_MCR_BIT
    xor     al,RIP_MCR_STAT
    jz      _ptret          ; stato raggiunto

    _pt4:           mov     exrip,0
    mov     ax,totrip       ; controlla passi totali
    cmp     ax,RIP_MAX
    jae     _ptret          ; troppi: time-out !!!

    _pt5:           mov     dx,FBR          ; controlla fibra
    in      al,dx
    test    al,FBR_BIT
    jnz     _pt6            ; fibra non eccitata

    mov     fibra,1         ; imposta fibra eccitata
    jmp     _pt3            ; continua

    _pt6:           cmp     fibra,0         ; controlla storico fibra
    je      _pt3            ; fibra non eccitata: continua

    inc     fibra           ; fibra diseccitata
    cmp     fibra,EX_FIBRA  ; da quanto ?
    jb      _pt3            ; da poco: continua

    _ptret:         cmp     fibra,0         ; imposta valore di ritorno
    ret
    ENDP

    ;       verifica la presenza della cassetta in magazzino
    ;
    ; out: cf = esito (set -> negativo, reset -> positivo)

    STEPSVER        EQU     150
    STEPSVER1       EQU     300

    verifica        PROC    NEAR
    mov     di,OFFSET ppen  ; pinza davanti magazzino
    lea     si,MAG
    call    MT1

    call    pnz_on          ; chiusura pinza

    ; pinza un po' indietro
    mov     dx,ppdir        ;   inverte direzione
    mov     al,ppdir_bit
    call    reversebit
    mov     cx,STEPSVER     ;   passi da fare
    call    stepss          ;   muove

    call    pnz_off         ; apertura pinza

    mov     di,OFFSET ppen  ; pinza davanti magazzino
    lea     si,MAG
    call    MT1

    and     fibra,110b      ; imposta fibra eccitata
    mov     dx,FBR          ; controlla fibra
    in      al,dx
    test    al,FBR_BIT
    jz      ver0            ; fibra eccitata
    or      fibra,001b      ; imposta fibra non eccitata

    ver0:           and     fibra,011b      ; azzera tentativi

    ; riporta la pinza un po' indietro
    ver1:           mov     dx,ppdir        ;   inverte direzione
    mov     al,ppdir_bit
    call    reversebit
    mov     cx,STEPSVER1    ;   passi da fare
    call    stepss          ;   muove

    call    pnz_on          ; chiusura pinza

    mov     di,OFFSET ppen  ; pinza davanti magazzino
    lea     si,MAG
    call    MT1

    and     fibra,101b      ; imposta fibra diseccitata
    mov     dx,FBR          ; controlla fibra
    in      al,dx
    test    al,FBR_BIT
    jnz     ver2            ; fibra non eccitata
    or      fibra,010b      ; imposta fibra eccitata
    xor     fibra,100b      ; incrementa tentativi

    ver2:           call    pnz_off         ; apertura pinza

    test    fibra,010b      ; testa stato fibra
    jz      ver3            ; fibra non eccitata
    test    fibra,100b      ; controlla tentativi fatti
    jnz     ver1            ; pochi: riprova
    stc                     ; ERRORE: FIBRA ECCITATA !!!
    jmp     verret

    ver3:           test    fibra,001b      ; testa stato fibra precedente
    stc
    jnz     verret          ; ERRORE: FIBRA NON ECCITATA !!!
    clc                     ; ok

    verret:         pushf                   ; salva esito
    mov     di,OFFSET ppen  ; pinza a riposo
    lea     si,RIP
    call    MT0
    popf                    ; recupera esito
    ret
    ENDP

    ;       prelievo cassetta da bordo tappeto
    ;
    ; output: cf = esito (set = negativo, reset = positivo)

    inside          PROC    NEAR
    mov     cx,TNT_INS      ; # tentativi
    jmp     SHORT in2
    in1:            push    cx              ; pinzata da magazzino
    call    pinzata_mag
    pop     cx
    in2:            push    cx              ; cassetta in centro tappeto
    mov    di,OFFSET tten
    lea     si,TIN
    call    MT1
    pop    cx
    jnc    insret        ; cassetta in centro
    loop    in1             ; riprova
    stc                     ; time-out
    insret:        ret
    ENDP

    ;       deposito cassetta da bordo tappeto
    ;
    ; output: cf = esito (set = time-out, reset = ok)

    outside        PROC    NEAR
    mov     cx,TNT_OUT      ; contatore tentativi
    mov     ind,0           ; disattiva indietreggiamento

    _out00:         inc     ind             ; imposta riprova per fibra eccitata

    _out0:          push    cx              ; salva contatore
    call    pinzata_tap     ; pinzata da tappeto
    pop     cx              ; recupera contatote

    mov     ah,0            ; imposta esito pinzata positivo
    jz      _out1           ; esito positivo
    or      ah,00000001b    ; imposta esito pinzata negativo

    _out1:          mov     dx,BAR_ANT      ; controlla barriera anteriore
    in      al,dx
    test    al,BAR_ANT_BIT
    jnz     _out2           ; barriera non interrotta
    or      ah,00000010b    ; barriera interrotta

    _out2:          mov     dx,BAR_POS      ; controlla barriera posteriore
    in      al,dx
    test    al,BAR_POS_BIT
    jnz     _out3           ; barriera non interrotta
    or      ah,00000010b    ; barriera interrotta

    _out3:          or      ah,ah           ; controlla esito generale
    jz      _outok
    dec     cx              ; controlla tentativi
    stc
    jz      _outret         ; troppi: time-out !!!

    test    ah,00000010b    ; controlla stato barriere
    jz      _out00          ; non interrotte: continua
    push    cx              ; salva contatore
    mov     di,OFFSET tten  ; motore tappeto

    IF BARGP EQ 0                      ; se non ci sono le barriere,
    mov     ax,FBR             ; prima eccita una fibra
    mov     tout0,ax
    mov     al,FBR_BIT
    mov     tout0_bit,al
    mov     si,OFFSET tout0
    call    MT0
    ENDIF

    lea     si,TOUT         ; tappeto verso esterno
    call    MT0
    pop     cx              ; recupera contatore
    jmp     _out0           ; continua

    _outok:
    IF VERPNZ EQ 1
    cmp     ver_pnz,1       ; controlla pinza aperta
    clc
    je      _outret         ; tutto ok
    call    verifica        ; verifica pinza in magazzino
    ELSE
    clc                     ; tutto ok
    ENDIF

    _outret:        ret
    ENDP

    ;    preleva la cassetta dal magazzino
    ;
    ; output: AL = '0' = tutto ok
    ;              'G' = cassetta assente o presa fallita
    ;              'F' = stato errato dopo constatazione cassetta assente
    ;              'J' = prelievo e deposito falliti
    ;              'K' = prelievo fallito ma deposito riuscito
    ;              'I' = stato errato dopo prelievo o deposito riusciti

    pop        PROC    NEAR
    call    pinzata_mag     ; avvicina la cassetta

    mov     cx,TNT_PMAG     ; numero tentativi
    pop1:           push    cx
    call    pinzata_mag     ; pinza la cassetta
    pop    cx
    jz      pop3            ; barriera eccitata
    loop    pop1        ; riprova

    call    statopinza      ; controlla stato gruppo pinza
    mov     al,'F'
    jc      pop2            ; STATO ERRATO !!!
    IF BARGP EQ 1
    jz      pop2            ; STATO ERRATO !!!
    ENDIF
    mov    al,'G'        ; CASSETTA ASSENTE !!!
    pop2:           ret

    pop3:           call    inside          ; porta la cassetta al centro
    jnc     pop5            ; ok

    call    outside        ; deposita la cassetta
    mov     al,'J'
    jc      pop4            ; DEPOSITO E PRELIEVO FALLITI !!!
    call    statopinza      ; controlla stato pinza
    mov     al,'I'
    jc      pop4            ; STATO ERRATO !!!
    IF BARGP EQ 1
    jz      pop4            ; STATO ERRATO !!!
    ENDIF
    mov     al,'K'          ; prelievo fallito ma deposito ok
    pop4:           ret

    pop5:           call    statopinza      ; controlla stato pinza
    mov     al,'I'
    jc      pop6            ; STATO ERRATO !!!
    IF BARGP EQ 1
    jnz     pop6            ; STATO ERRATO !!!
    ENDIF
    mov    al,'0'        ; tutto ok
    pop6:           ret
    ENDP

    ;       deposita la cassetta in magazzino
    ;
    ; output: AL = '0' = tutto ok
    ;              'S' = stato errato dopo deposito o prelievo riuscito
    ;              'V' = deposito e prelievo falliti
    ;              'U' = deposito fallito ma prelievo riuscito

    push            PROC    NEAR
    mov     di,OFFSET tten  ; motore tappeto

    IF BARGP EQ 0                      ; se non ci sono le barriere,
    mov     ax,FBR             ; prima eccita una fibra
    mov     tout0,ax
    mov     al,FBR_BIT
    mov     tout0_bit,al
    mov     si,OFFSET tout0
    call    MT0
    ENDIF

    lea     si,TOUT         ; cassetta su bordo tappeto
    call    MT0

    call    outside         ; tenta deposito
    jc      push2           ; deposito non riuscito

    call    statopinza      ; controlla stato gruppo pinza
    mov     al,'S'
    jc      push1           ; STATO ERRATO !!!
    IF BARGP EQ 1
    jz      push1           ; STATO ERRATO !!!
    ENDIF
    mov    al,'0'        ; tutto ok
    push1:          ret

    push2:          mov     cx,TNT_PMAG
    push22:         mov     dx,BAR          ; controlla barriera
    in      al,dx
    test    al,BAR_BIT
    jz      push222         ; barriera eccitata
    dec     cx              ; controlla tentativi
    mov     al,'V'
    jz      push3           ; troppi: DEPOSITO E PRELIEVO FALLITI
    push    cx              ; salva contatore
    call    pinzata_mag     ; pinzata da magazzino
    pop     cx              ; recupera contatore
    jmp     push22          ; ricontrolla

    push222:        call    inside          ; tenta prelievo
    mov     al,'V'
    jc      push3           ; DEPOSITO E PRELIEVO FALLITI !!!
    call    statopinza      ; controlla stato pinza
    mov     al,'S'
    jc      push3           ; STATO ERRATO !!!
    IF BARGP EQ 1
    jnz     push3           ; STATO ERRATO !!!
    ENDIF
    mov     al,'U'          ; deposito fallito ma prelievo ok
    push3:          ret
    ENDP

    ;    preleva/restituisce la cassetta dal/nel magazzino specificato
    ;
    ; input: param = 'A' se prelievo/restituzione dal/nel magazzino anteriore
    ;     param = 'P' se prelievo/restituzione dal/nel magazzino posteriore
    ;
    ; output: param = codice di errore

    __vbpick        PROC    NEAR
    mov     bx,OFFSET pop
    jmp     SHORT prgo

    __vbplace       LABEL    NEAR
    mov     bx,OFFSET push

    prgo:           push    bp

    mov    bp,OFFSET mt0_ant    ; dal/nel magazzino anteriore
    cmp    al,'A'
    je      prg1
    mov     bp,OFFSET mt0_pos       ; dal/nel magazzino posteriore

    prg1:           push    bx
    mov     di,OFFSET tten          ; abilita motori
    call    motoreon
    mov     di,OFFSET ppen
    call    motoreon
    pop    bx

    call    bx                      ; preleva/restituisce
    xor     cx,cx                   ; attesa
    loop    $

    push    ax            ; salva esito
    mov    di,OFFSET ppen        ; disattiva motori
    call    motoreoff
    mov    di,OFFSET tten
    call    motoreoff
    pop    ax            ; recupera esito

    pop    bp
    ret
    ENDP

    STEPS_ANT       DW     200     ; passi in deposito su tappeto
    STEPST          DW     70      ; passi pinza da riposo a tappeto
    STEPSP          DW     70      ; passi pinza da riposo a posteriore

    MAX_TNT         EQU     10     ; tentativi pinzate su tappeto

    tttstep        PROC    NEAR        ; muove di un passo i tappeti
    mov    dx,ttck            ; tick
    mov    al,01100000b
    call    reversebit
    mov    cx,vel            ; velocit…
    loop    $
    ret
    ENDP

    dir0            PROC    NEAR            ; direzione verso tappeto
    mov     dx,ppdir
    mov     al,ppdir_bit
    call    resetbit
    ret
    ENDP

    dir1            PROC    NEAR            ; direzione verso posteriore
    mov     dx,ppdir
    mov     al,ppdir_bit
    call    setbit
    ret
    ENDP

    cktton          PROC    NEAR            ; abilita rotazione tappeti con pinza
    mov     al,TCK_BIT
    or      al,ttck_bit
    or      ppck_bit,al
    ret
    ENDP

    ckttoff         PROC    NEAR            ; disabilita tappeti con pinza
    mov     al,TCK_BIT
    or      al,ttck_bit
    not     al
    and     ppck_bit,al
    ret
    ENDP

    stepss          PROC    NEAR            ; cx passi su trasporto
    mov     dx,ppck         ; tick
    mov     al,ppck_bit
    call    reversebit
    push    cx              ; delay
    mov     cx,ppstart_vel
    loop    $
    pop     cx
    loop    stepss          ; prossimo
    ret
    ENDP

    pnzon           PROC    NEAR            ; chiusura pinza anteriore
    push    bp
    mov     bp,OFFSET mt0_ant
    call    pnz_on
    pop     bp
    ret
    ENDP

    pnzoff          PROC    NEAR            ; apertura pinza anteriore
    push    bp
    mov     bp,OFFSET mt0_ant
    call    pnz_off
    pop     bp
    ret
    ENDP

    pick            PROC    NEAR            ; presa cassetta
    call    dir0            ; direzione verso tappeto

    mov     cx,STEPST       ; pinza su tappeto
    call    stepss

    call    pnzon           ; chiusura pinza

    call    dir1            ; direzione verso posteriore

    call    cktton          ; associa tappeti

    mov     cx,STEPST       ; pinza su posteriore
    add     cx,STEPSP
    call    stepss

    call    ckttoff         ; dissocia tappeti

    call    pnzoff          ; apertura pinza

    mov     di,OFFSET ppen          ; pinza a riposo
    mov     si,OFFSET mcr_pos
    call    motore0

    ret
    ENDP

    place           PROC    NEAR            ; deposito cassetta
    call    dir1            ; direzione verso posteriore

    mov     cx,STEPSP       ; pinza su posteriore
    call    stepss

    call    pnzon           ; chiusura pinza

    call    dir0            ; direzione verso tappeto

    call    cktton          ; associa tappeti

    mov     cx,STEPSP       ; pinza su tappeto
    add     cx,STEPST
    call    stepss

    call    ckttoff         ; dissocia tappeti

    call    pnzoff          ; apertura pinza

    mov     di,OFFSET ppen          ; pinza a riposo
    mov     si,OFFSET mcr_ant
    call    motore1

    ret
    ENDP

    ;    preleva la cassetta dal tappeto (casella 0)
    ;
    ; output: AL = '0' -> tutto ok
    ;              'B' -> time-out
    ;              'I' -> barriera centrale interrotta prima di quella anteriore
    ;              'i' -> barriera cnt. int. assieme a quella anteriore

    IF BARGP EQ 0
    fbr_stat    DB      ?
    ENDIF

    __vbpicktp      PROC    NEAR
    mov     di,OFFSET ppen          ; abilita tappeti e pinza
    call    motoreon
    mov     dx,TEN
    mov    al,TEN_BIT
    call    resetbit
    mov    di,OFFSET tten
    call    motoreon

    mov    dx,TDIR            ; direzione 1 per tappeto p.o.
    mov    al,TDIR_BIT
    call    setbit
    mov    dx,ttdir        ; direzione 0 per tappeto pinza
    mov    al,ttdir_bit
    call    resetbit

    mov     ax,VEL_REG              ; velocit… di regime
    mov     vel,ax

    mov     t,0                     ; # tentativi

    IF BARGP EQ 0
    mov     fbr_stat,0              ; attende fibra eccitata
    ENDIF

    pt1:            mov     steps,0                 ; passi totali

    pt2:            mov     ex,0                    ; passi extra

    pt3:            call    tttstep                 ; un passo
    inc     steps

    mov     dx,SNS_CNT              ; controllo barriera centrale
    in      al,dx
    test    al,SNS_CNT_BIT
    jnz     pt4                     ; barriera non interrotta
    mov     dx,SNS_EST              ; controllo barriera esterna
    in      al,dx
    test    al,SNS_EST_BIT
    jnz     pt4                     ; barriera non interrotta

    mov     cx,WAIT_SNS             ; attende stabilita'
    loop    $

    mov     dx,SNS_CNT              ; verifica barriera centrale
    in      al,dx
    test    al,SNS_CNT_BIT
    jnz     pt4                     ; barriera non interrotta
    mov     dx,SNS_EST              ; verifica barriera esterna
    in      al,dx
    test    al,SNS_EST_BIT
    jnz     pt4                     ; barriera non interrotta

    mov     dx,BAR_ANT              ; controllo barriera anteriore
    in      al,dx
    test    al,BAR_ANT_BIT
    mov     al,'I'                  ; non interrotta
    jnz     ptret
    mov     al,'i'                  ; interrotta
    jmp     ptret

    pt4:
    IF BARGP EQ 1
    mov     dx,BAR_POS              ; controllo barriera posteriore
    in      al,dx
    test    al,BAR_POS_BIT
    jnz     pt5                     ; barriera non eccitata
    ;      mov     dx,BAR_ANT              ; controlla barriera anteriore
    ;      in      al,dx
    ;      test    al,BAR_ANT_BIT
    ;      jnz     pt5                     ; barriera non eccitata
    ELSE
    mov     dx,FBR_ANT              ; controlla barriera interna
    in      al,dx
    and     al,FBR_ANT_BIT
    xor     al,fbr_stat
    jnz     pt5                     ; barriera non raggiunta
    ENDIF

    inc     ex                      ; controllo passi extra
    mov     ax,ex
    cmp     ax,steps_sns_aind
    jb      pt3                     ; continua

    mov     cx,WAIT_SNS             ; attende stabilita'
    loop    $

    IF BARGP EQ 1
    mov     dx,BAR_POS              ; verifica barriera posteriore
    in      al,dx
    test    al,BAR_POS_BIT
    jnz     pt5                     ; barriera non eccitata
    ;      mov     dx,BAR_ANT              ; verifica barriera anteriore
    ;      in      al,dx
    ;      test    al,BAR_ANT_BIT
    ;      jnz     pt5                     ; barriera non eccitata
    ELSE
    mov     dx,FBR_ANT              ; verifica barriera interna
    in      al,dx
    and     al,FBR_ANT_BIT
    xor     al,fbr_stat
    jnz     pt5                     ; barriera non raggiunta
    xor     fbr_stat,FBR_ANT_BIT    ; inverte stato da raggiungere
    jnz     pt1                     ; continua
    ENDIF

    mov     al,'0'                  ; tutto ok
    jmp     ptret

    pt5:            mov     ax,steps
    cmp     ax,max_steps_aind       ; controllo passi totali
    jb      pt2                     ; continua
    cmp     t,MAX_TNT               ; controlla tentativi
    mov     al,'B'
    jae     ptret                   ; time-out
    call    pick                    ; pinzata
    inc     t
    jmp     pt1                     ; riprova

    ptret:        push    ax            ; salva esito
    mov     dx,ppen                 ; disabilita tappeti e pinza
    mov     al,ppen_bit
    call    setbit
    mov     dx,TEN
    mov    al,TEN_BIT
    call    setbit
    mov    di,OFFSET tten
    call    motoreoff
    pop    ax            ; recupera esito
    ret
    ENDP

    ;    pone la cassetta sul tappeto (casella 0)
    ;
    ; output: AL = '0' -> tutto ok
    ;              'A' -> time-out
    ;              'B' -> cassetta in tappeto ma ancora visibile da pinza
    ;              'C' -> cassetta non vista da pinza e neanche in tappeto

    presente        DB      ? ; flag di rilevazione passaggio cassetta
    stato           DB      ? ; stato attuale barriere
    ex_pnz          DW      ? ; passi extra barriere pinza diseccitate
    ex_cnt          DW      ? ; passi extra barriera centrale eccitata

    __vbpltp        PROC    NEAR
    mov     di,OFFSET ppen  ; abilita tappeti e pinza
    call    motoreon
    mov     dx,TEN
    mov    al,TEN_BIT
    call    resetbit
    mov    di,OFFSET tten
    call    motoreon

    mov     dx,TDIR         ; direzione 0 per tappeto p.o.
    mov    al,TDIR_BIT
    call    resetbit
    mov     dx,ttdir        ; direzione 1 per tappeto pinza
    mov    al,ttdir_bit
    call    setbit

    mov     ax,VEL_REG      ; velocit… di regime
    mov     vel,ax

    mov     t,0             ; # tentativi

    mov     presente,000b   ; imposta cassetta non vista

    pl1:            mov     steps,0         ; passi totali

    mov     ex_pnz,0        ; passi extra
    mov     ex_cnt,0

    pl3:            call    tttstep         ; un passo
    inc     steps           ; incrementa contatore passi totali

    ;       mov     dx,BAR_POS      ; controlla barriera posteriore
    ;       in      al,dx
    ;       test    al,BAR_POS_BIT
    ;       jz      pl4             ; barriera interrotta
    mov     dx,BAR_ANT      ; controlla barriera anteriore
    in      al,dx
    test    al,BAR_ANT_BIT
    jz      pl4             ; barriera interrotta

    or      stato,001b      ; impone: barriere pinza = non interr.
    inc     ex_pnz          ; incrementa contatore passi extra ...
    cmp     ex_pnz,500      ; ... limitando l'overflow
    jbe     pl5
    dec     ex_pnz
    jmp     pl5

    pl4:            or      presente,001b   ; impone: cassetta vista da barr. pnz.
    and     stato,110b      ; impone: barriere pinza = interr.
    mov     ex_pnz,0        ; azzera contatore passi extra

    pl5:            mov     dx,SNS_INT      ; controlla barriera interna
    in      al,dx
    test    al,SNS_INT_BIT
    jz      pl6             ; barriera interrotta

    or      stato,010b      ; impone: barriera interna = non int.
    jmp     pl7

    pl6:            or      presente,010b   ; impone: cassetta vista da barr. int.
    and     stato,101b      ; impone: barriera interna interrotta

    pl7:            mov     dx,SNS_CNT      ; controlla barriera centrale
    in      al,dx
    test    al,SNS_CNT_BIT
    jz      pl8             ; barriera interrotta

    or      stato,100b      ; impone: barriera centrale = non int.
    mov     ex_cnt,0        ; azzera contatore passi extra
    jmp     pl9

    pl8:            or      presente,100b   ; impone: cassetta vista da barr. cnt.
    and     stato,011b      ; impone: barriera centrale = int.
    inc     ex_cnt          ; incrementa contatore passi extra ...
    cmp     ex_cnt,20       ; ... evitando l'overflow
    jbe     pl9
    dec     ex_cnt

    pl9:            test    stato,001b      ; ceck barriere pinza
    jnz     pl12            ; barriere non interrotte

    test    stato,010b      ; ceck barriera interna
    jz      pl10            ; barriera interrotta

    test    presente,010b   ; cassetta vista su barr. interna ?
    jz      pl10            ; no: continua

    test    stato,100b      ; ceck barriere centrale
    jnz     pl10            ; barriera non interrotta

    mov     al,'B'          ; CASSETTA VISIBILE DA TAPP. E PNZ. !!
    jmp     plret

    pl10:           cmp     steps,2000      ; controlla passi totali
    jae     pl33            ; troppi
    jmp     pl3             ; pochi: continua

    pl33:           cmp     t,MAX_TNT       ; controlla tentativi pinzata
    jb      pl11            ; pochi: continua

    mov     al,'A'          ; TIME-OUT !!!
    jmp     plret

    pl11:           call    place           ; pinzata
    inc     t
    jmp     pl1             ; riprova

    pl12:           cmp     ex_pnz,500      ; da quanto bar. pnz. non interr. ?
    jae     pl333           ; da molto
    jmp     pl3             ; da poco: continua

    pl333:          test    stato,010b      ; ceck barriera interna
    jnz     pl13            ; barriera non interrotta

    test    stato,100b      ; ceck barriera centrale
    jnz     pl10            ; barriera non interrotta

    cmp     ex_cnt,20       ; da quanto bar. cnt. interrotta ?
    jae     pl13            ; da molto
    jmp     pl3             ; da poco: coninua

    pl13:   IF BARGP EQ 0                   ; verifica deposito avvenuto

    test    presente,001b   ; cassetta vista su barriere pinza ?
    jz      pl14            ; no: verifica

    jmp     plok            ; si: fine

    pl14:           call    dir1            ; pinza su mag. post.
    mov     cx,STEPSP
    call    stepss

    mov     ax,3            ; piccola attesa
    llll1:          xor     cx,cx
    loop    $
    dec     ax
    jnz     llll1

    mov     dx,FBR_ANT      ; controlla fibra anteriore
    in      al,dx
    test    al,FBR_ANT_BIT
    jnz     __pl1           ; fibra non eccitata

    cmp     t,MAX_TNT       ; controlla tentativi
    jb      __pl0           ; pochi

    mov     di,OFFSET ppen  ; pinza a riposo
    mov     si,OFFSET mcr_pos
    call    motore0

    mov     al,'A'          ; time-out !!!
    jmp     plret

    __pl0:          call    pnzon           ; chiusura pinza

    call    dir0            ; direzione verso tappeto

    call    cktton          ; associa tappeti

    mov     cx,STEPSP       ; pinza su tappeto
    add     cx,STEPST
    call    stepss

    call    ckttoff         ; dissocia tappeti

    call    pnzoff          ; apertura pinza

    mov     di,OFFSET ppen  ; pinza a riposo
    mov     si,OFFSET mcr_ant
    call    motore1

    inc     t

    jmp     pl1             ; riprova

    __pl1:          call    dir0            ; pinza su tappeto p.o.
    mov     cx,STEPSP
    add     cx,STEPST
    call    stepss

    mov     ax,3            ; piccola attesa
    llll2:          xor     cx,cx
    loop    $
    dec     ax
    jnz     llll2

    mov     dx,FBR_POS      ; controlla fibra posteriore
    in      al,dx
    test    al,FBR_POS_BIT
    jnz     __pl2           ; fibra non eccitata

    cmp     t,MAX_TNT       ; controlla tentativi
    jb      __pl00          ; pochi

    mov     di,OFFSET ppen  ; pinza a riposo
    mov     si,OFFSET mcr_ant
    call    motore1

    mov     al,'A'          ; time-out !!!
    jmp     plret

    __pl00:         mov     di,OFFSET ppen  ; pinza a riposo
    mov     si,OFFSET mcr_ant
    call    motore1

    call    place           ; pinzata
    inc     t

    jmp     pl1             ; riprova

    __pl2:          mov     di,OFFSET ppen  ; pinza a riposo
    mov     si,OFFSET mcr_ant
    call    motore1

    test    presente,010b   ; cassetta vista su barriera interna ?
    jnz     plok            ; si: ok

    cmp     t,5             ; controlla tentativi pinzata
    jb      __pl3

    mov     al,'C'          ; CASSETTA ASSENTE O MAI VISTA !!!
    jmp     plret

    __pl3:          call    place           ; pinzata
    inc     t
    jmp     pl1             ; riprova

    ENDIF

    plok:           mov     al,'0'                  ; tutto ok

    plret:          push    ax                      ; salva esito
    mov     dx,ppen                 ; disabilita tappeti e pinza
    mov     al,ppen_bit
    call    setbit
    mov     dx,TEN
    mov    al,TEN_BIT
    call    setbit
    mov    di,OFFSET tten
    call    motoreoff
    pop    ax            ; recupera esito
    ret
    ENDP

    COMMENT ~

    ;    pone la cassetta sul tappeto (casella 0)
    ;
    ; output: AL = '0' -> tutto ok
    ;              'A' -> time-out

    __vbpltp        PROC    NEAR
    mov     di,OFFSET ppen          ; abilita tappeti e pinza
    call    motoreon
    mov     dx,TEN
    mov    al,TEN_BIT
    call    resetbit
    mov    di,OFFSET tten
    call    motoreon

    mov     dx,TDIR                 ; direzione 0 per tappeto p.o.
    mov    al,TDIR_BIT
    call    resetbit
    mov     dx,ttdir                ; direzione 1 per tappeto pinza
    mov    al,ttdir_bit
    call    setbit

    mov     ax,VEL_REG              ; velocit… di regime
    mov     vel,ax

    mov     t,0                     ; # tentativi

    IF BARGP EQ 0
    mov     fbr_stat,0              ; attesa fibra eccitata

    mov     dx,SNS_INT              ; controlla barriera interna
    in      al,dx
    test    al,SNS_INT_BIT
    jnz     pl1                     ; barriera non interrotta
    mov     fbr_stat,FBR_ANT_BIT    ; barriera interrotta -> attesa fibra diseccitata
    ENDIF

    pl1:            mov     steps,0                 ; passi totali

    pl2:            mov     ex,0                    ; passi extra

    pl3:            call    tttstep                 ; un passo
    inc     steps

    IF BARGP EQ 1
    mov     dx,BAR_POS              ; controllo bar. pos.
    in      al,dx
    test    al,BAR_POS_BIT
    jz      pl4                     ; bar. interrotta
    mov     dx,BAR_ANT              ; controllo bar. ant.
    in      al,dx
    test    al,BAR_ANT_BIT
    jz      pl4                     ; bar. interrotta
    ELSE
    mov     dx,FBR_ANT              ; controlla fibra anteriore
    in      al,dx
    and     al,FBR_ANT_BIT
    xor     al,fbr_stat
    jnz     pl4                     ; fibra non raggiunta
    cmp     fbr_stat,FBR_ANT_BIT    ; che stato ? ...
    je      pl44                    ; ... fibra diseccitata
    mov     fbr_stat,FBR_ANT_BIT    ; attesa fibra diseccitata
    jmp     pl1                     ; continua
    ENDIF

    pl44:           mov     dx,SNS_INT              ; controlla barriera interna
    in      al,dx
    test    al,SNS_INT_BIT
    jnz     pl4                     ; barriera non interrotta
    mov     dx,SNS_CNT              ; controlla barriera centrale
    in      al,dx
    test    al,SNS_CNT_BIT
    jnz     pl4                     ; barriera non interrotta

    inc     ex                      ; controllo passi extra
    mov     ax,ex
    cmp     ax,20
    ;       cmp     ax,STEPS_ANT
    jb      pl3                     ; continua

    mov     al,'0'                  ; tutto ok
    jmp     plret

    pl4:            mov     ax,steps
    cmp     ax,max_steps_cavt       ; controllo passi totali
    jb      pl2                     ; continua
    cmp     t,MAX_TNT               ; controlla tentativi
    mov     al,'A'
    jae     plret                   ; time-out
    call    place                   ; pinzata
    inc     t
    jmp     pl1                     ; riprova

    plret:          push    ax                      ; salva esito
    mov     dx,ppen                 ; disabilita tappeti e pinza
    mov     al,ppen_bit
    call    setbit
    mov     dx,TEN
    mov    al,TEN_BIT
    call    setbit
    mov    di,OFFSET tten
    call    motoreoff
    pop    ax            ; recupera esito
    ret
    ENDP

    ~
    ;******************************************************************************
    ;
    ;    gestione degli LM628
    ;
    ; input: dx = command-port
    ;
    ;******************************************************************************
    ; LM628 user command set
    RESET        EQU    00h        ; reset LM628
    PORT8        EQU    05h         ; select 8-bit output
    PORT12        EQU    06h        ; select 12-bit output
    DFH        EQU    02h        ; define home
    SIP        EQU    03h         ; set index position
    LPEI        EQU    1bh        ; interrupt on error
    LPES        EQU    1ah        ; stop on eror
    SBPA        EQU    20h        ; set breakpoint, absolute
    SBPR        EQU    21h        ; set breakpoint, relative
    MSKI        EQU    1ch        ; mask interrupts
    RSTI        EQU    1dh        ; reset interrupts
    LFIL        EQU    1eh        ; load filter parameters
    UDF        EQU    04h        ; update filter
    LTRJ        EQU    1fh        ; load trajectory
    STT        EQU    01h        ; start motion
    RDSIGS        EQU    0ch        ; read signals register
    RDIP        EQU    09h        ; read index position
    RDDP        EQU    08h        ; read desired position
    RDRP        EQU    0ah        ; read real position
    RDDV        EQU    07h        ; read desired velocity
    RDRV        EQU    0bh        ; read real velocity
    RDSUM        EQU    0dh        ; read integration sum

    ALL_INT        EQU    0000000001111110b    ; mask for all interrupts

    LALL_FIL    EQU    00001111b    ; loading kp,ki,kd and il data
    ; trajectory control word bit allocation
    FWRD        EQU    0001000000000000b    ; forward direction
    VMODE        EQU    0000100000000000b    ; velocity mode
    STOP        EQU    0000010000000000b    ; stop smoothly
    BREAK        EQU    0000001000000000b    ; stop abruptly
    OFF        EQU    0000000100000000b    ; turn off motor
    LACC        EQU    0000000000100000b    ; loading acceleration data
    LVEL        EQU    0000000000001000b    ; loading velocity data
    LPOS        EQU    0000000000000010b    ; loading position data
    ; status byte bit allocation
    MT_OFF        EQU    10000000b    ; motor off
    BREAKPOINT    EQU    01000000b    ; breakpoint reached [interrupt]
    EX_POS_ERR      EQU     00100000b       ; excessive position error [interrupt]
    WRAPAROUND    EQU    00010000b    ; wraparound occurred [interrupt]
    INDEX_PULSE    EQU    00001000b    ; index pulse observed [interrupt]
    TRJ_COMP    EQU    00000100b    ; trajectory complete [interrupt]
    CMD_ERROR    EQU    00000010b    ; command error [interrupt]
    BUSY_BIT    EQU    00000001b    ; busy bit

    ;     invia un comando all'LM628
    ;
    ; input: al = comando

    wrcmd        PROC    NEAR
    push    ax
    busy1:        in    al,dx        ; attende che l'LM628 sia disponible
    test    al,BUSY_BIT
    jnz    busy1
    inc    dx           ; prima uno zero sulla data-port
    xor    al,al
    out    dx,al
    dec    dx              ; e poi il comando sulla command-port
    pop    ax
    out    dx,al
    ret
    ENDP

    ;    invia una word all'LM628
    ;
    ; input: ax = valore

    wrword        PROC    NEAR
    push    ax
    busy2:        in    al,dx        ; attende che l'LM628 sia disponibile
    test    al,BUSY_BIT
    jnz    busy2
    inc    dx        ; data-port
    pop    ax        ; prima il byte pi— significativo
    xchg    al,ah
    out    dx,al
    xchg    al,ah           ; e poi quello meno significativo
    out    dx,al
    dec    dx           ; command-port
    ret
    ENDP

    ;    legge una word dall'LM628
    ;
    ; output: ax = valore

    rdword        PROC    NEAR
    in    al,dx        ; attende che l'LM628 sia disponibile
    test    al,BUSY_BIT
    jnz    rdword
    inc    dx        ; data-port
    in    al,dx        ; prima il byte pi— significativo
    mov    ah,al
    in    al,dx           ; e poi quello meno significativo
    dec    dx              ; command-port
    ret
    ENDP

    ;    resetta tutte le interruzzioni

    rsti        PROC    NEAR
    mov    al,RSTI        ; prima il comando di reset
    call    wrcmd
    mov    ax,NOT ALL_INT    ; e poi la parola di controllo
    call    wrword
    ret
    ENDP

    ;    inizializza l'LM628
    ;
    ; input: ds:di+13 = puntatore ai parametri del filtro

    DSI        EQU    [di+14]        ; derivative sampling interval
    KP        EQU    [di+15]        ; proportional term
    KI        EQU    [di+17]        ; integration term
    KD        EQU    [di+19]        ; derivative term
    IL        EQU    [di+21]        ; integration limit

    WAIT_RESET    EQU    0        ; tempo attesa reset
    MAX_PEI        EQU    7fffh        ; max. errore di posizione senza stop

    init628        PROC    NEAR
    ; resetta l'LM628
    xor    ax,ax        ; prima due zeri sulla data-port
    call    wrword
    mov    al,RESET    ; poi il comando di reset
    call    wrcmd
    mov    cx,WAIT_RESET   ; e quindi attesa
    loop    $

    mov    al,PORT12    ; seleziona l'output a 12 bits
    call    wrcmd
    ; massimizza il massimo errore senza stop
    mov    al,LPEI        ; prima il comando di caricamento
    call    wrcmd
    mov    ax,MAX_PEI    ; e poi il valore effettivo
    call    wrword
    ; inizializza i parametri del filtro
    mov    al,LFIL        ; prima il comando di caricamento
    call    wrcmd
    mov    ah,DSI        ; poi la parola di controllo con dsi
    mov    al,LALL_FIL
    call    wrword
    mov    ax,KP        ; quindi il dato per kp
    call    wrword
    mov    ax,KI        ; quello per ki
    call    wrword
    mov    ax,KD        ; quello per kd
    call    wrword
    mov    ax,IL        ; e quello per il
    call    wrword
    mov    al,UDF        ; ed infine il comando
    call    wrcmd        ; di aggiornamento effettivo
    ; azzera i parametri della traiettoria
    mov    al,LTRJ        ; prima il comando di caricamento
    call    wrcmd
    mov    ax,LACC OR LVEL OR LPOS    ; poi la parola di controllo
    call    wrword
    mov    cx,6        ; quindi i dati per acc=vel=pos=0
    xor    ax,ax
    ini1:        call    wrword
    loop    ini1
    mov    al,DFH        ; poi il comando per fissare l'origine
    call    wrcmd
    mov    al,STT          ; ed infine il comando
    call    wrcmd        ; di aggiornamento effettivo
    ; disabilita tutte le interruzzioni
    mov    al,MSKI         ; prima il comando di mascheramento
    call    wrcmd
    mov    ax,NOT ALL_INT    ; e poi la parola di controllo
    call    wrword

    call    rsti        ; resetta tutte le interruzzini

    ret
    ENDP

    ;******************************************************************************
    ;
    ;    gestione degli assi
    ;
    ; input: ds:di = puntatore ai parametri dell'asse
    ;
    ;******************************************************************************

    CMD_PORT        EQU     [di+0]          ; command-port
    ENABLE        EQU    [di+2]        ; abilitazione asse
    ENABLE_BIT    EQU    [di+4]
    VER_AB          EQU     [di+5]          ; verifica abilitazione
    VER_AB_BIT      EQU     [di+7]
    SNS_1        EQU    [di+8]        ; sensore 1
    SNS_1_BIT    EQU    [di+10]
    SNS_2        EQU    [di+11]        ; sensore 2
    SNS_2_BIT    EQU    [di+13]

    FILTER        EQU    [di+14]        ; parametri filtro
    ACC_LOW        EQU    [di+23]        ; accelerazione
    ACC_HIGH    EQU    [di+25]
    SSLOW_LOW       EQU     [di+27]         ; velocit… bassissima
    SSLOW_HIGH      EQU     [di+29]
    SLOW_LOW        EQU     [di+31]         ; bassa velocit…
    SLOW_HIGH       EQU     [di+33]
    FAST_LOW        EQU     [di+35]         ; alta velocit…
    FAST_HIGH       EQU     [di+37]
    POS_LOW         EQU     [di+39]         ; posizione
    POS_HIGH        EQU     [di+41]
    WAIT_1          EQU     [di+43]         ; attesa raggiunta 1 per origine

    WAIT_ARR    EQU    12        ; tempo attesa arresto effettivo asse

    ; parametri asse x
    xport        DW    0300h        ; command-port
    xenable        DW    0310h        ; abilitazione
    xenable_bit    DB    10000000b
    xab             DW      0316h           ; verifica abilitazione
    xab_bit         DB      00000010b
    xsns_1          DW      031Ah           ; sensore 1
    xsns_1_bit      DB      00100000b
    xsns_2          DW      031Ah           ; sensore 2
    xsns_2_bit      DB      00010000b

    xdsi        DB    0          ; parametri filtro
    xkp             DW    8
    xki             DW    5
    xkd             DW    20
    xil             DW    0

    xacc        DD    700        ; accelerazione
    xsslow        DD      1000        ; bassissima velocit…
    xslow        DD    20000        ; bassa velocit…
    xfast           DD      150000          ; alta velocit…
    xpos        DW    0,0        ; posizione
    xwait_1         DW      546             ; attesa raggiunta 1 per origine

    ; parametri asse z
    zport        DW    0304h        ; command-port
    zenable        DW    0310h        ; abilitazione
    zenable_bit     DB      01000000b
    zab             DW      0316h           ; verifica abilitazione
    zab_bit         DB      00000100b
    zsns_1          DW      031Ah           ; sensore 1
    zsns_1_bit      DB      00000100b
    zsns_2          DW      031Ah           ; sensore 2
    zsns_2_bit      DB      00000010b

    zdsi        DB    0          ; parametri filtro
    zkp             DW    8
    zki             DW    5
    zkd             DW    20
    zil             DW    0

    zacc        DD    120        ; accelerazione
    zsslow        DD      3000        ; bassissima velocit…
    zslow        DD    90000        ; bassa velocit…
    zfast        DD    2750000        ; alta velocit…
    zpos        DW    0,0        ; posizione
    zwait_1         DW      728             ; attesa raggiunta 1 per origine

    ;    riporta lo stato dell'asse dedotto dalla lettura dei sensori
    ;
    ; output: ah = 00000XX0b
    ;                   ³³
    ;                   ³ÀÄÄÄ not stato sensore 1
    ;                   ÀÄÄÄÄ not stato sensore 2

    assestatus         PROC    NEAR
    xor    ah,ah

    mov     dx,SNS_1        ; controlla sensore 1
    in    al,dx
    test    al,SNS_1_BIT
    jnz     as1             ; sensore rilasciato
    or    ah,00000010b    ; SENSORE PREMUTO !!!

    as1:            mov     dx,SNS_2        ; controlla sensore 2
    in    al,dx
    test    al,SNS_2_BIT
    jnz     as2             ; sensore rilasciato
    or    ah,00000100b    ; SENSORE PREMUTO !!!

    as2:            ret
    ENDP

    ;    sposta l'asse in modo posizione

    position    PROC    NEAR
    mov    dx,CMD_PORT    ; command-port
    mov    al,LTRJ        ; carica la traiettoria
    call    wrcmd
    mov    ax,LVEL OR LPOS
    call    wrword
    mov    ax,FAST_HIGH        ; velocit…
    call    wrword
    mov    ax,FAST_LOW
    call    wrword
    mov    ax,POS_HIGH        ; posizione
    call    wrword
    mov    ax,POS_LOW
    call    wrword
    call    rsti        ; resetta le interruzzioni
    mov    al,STT        ; inizia lo spostamento
    call    wrcmd
    ret
    ENDP

    ;    sposta l'asse in modo velocit…

    forward        PROC    NEAR        ; direzione indietro/basso
    mov    ah,(VMODE OR FWRD) SHR 8
    jmp    SHORT velocity

    backward:    mov    ah,VMODE SHR 8    ; direzione avanti/alto

    velocity:       mov    dx,CMD_PORT    ; command-port
    mov    al,LTRJ        ; carica la traiettoria
    call    wrcmd
    mov    al,LVEL
    call    wrword
    mov    ax,SLOW_HIGH
    call    wrword
    mov    ax,SLOW_LOW
    call    wrword
    call    rsti        ; resetta le interruzzioni
    mov    al,STT          ; inizia lo spostamento
    call    wrcmd
    ret
    ENDP

    ;     attende l'arresto effettivo dell'asse

    waitarr        PROC    NEAR
    mov    bx,WAIT_ARR    ; attesa arresto
    wa1:        xor    cx,cx
    loop    $
    dec    bx
    jnz    wa1
    ret
    ENDP

    ;    arresta l'asse

    stop        PROC    NEAR        ; deccelerazione programmata
    mov    ah,STOP SHR 8
    jmp    SHORT arresto

    break:          mov    ah,BREAK SHR 8    ; massima deccelerazione
    jmp    SHORT arresto

    off:        mov    ah,OFF SHR 8    ; blocco immediato

    arresto:        mov    dx,CMD_PORT    ; command-port
    mov    al,LTRJ        ; carica la traiettoria
    call    wrcmd
    xor    al,al
    call    wrword
    call    rsti        ; resetta le interruzzioni
    mov    al,STT        ; inizia arresto
    call    wrcmd
    arr1:        in    al,dx         ; attende arresto
    test    al,TRJ_COMP
    jz    arr1
    call    waitarr        ; attende arresto effettivo
    ret
    ENDP

    ;       resetta l'asse

    reset           PROC    NEAR
    in      al,61h          ; beep
    mov     cx,500
    ll11:           xor     al,00000010b
    out     61h,al
    push    cx
    mov     cx,200
    loop    $
    pop     cx
    loop    ll11

    mov    dx,CMD_PORT    ; command-port
    call    init628        ; inizializza l'LM628
    mov    al,LTRJ        ; fissa l'accelerazione
    call    wrcmd
    mov    ax,LACC
    call    wrword
    mov    ax,ACC_HIGH
    call    wrword
    mov    ax,ACC_LOW
    call    wrword
    mov     ax,STT
    call    wrcmd
    call    waitarr        ; attende arresto asse
    call    waitarr
    call    waitarr
    ret
    ENDP

    ;    sposta l'asse dai sensori 1 e 2
    ;
    ; output: carry-flag = reset se tutto ha funzionato a dovere
    ;      carry-flag = set   se l'asse Š bloccato o si Š verificato un errore

    ttt             DW      ?
    tnt_nosns       DW      ?

    nosns        PROC    NEAR
    call    assestatus      ; legge stato micro

    ; controlla micro 1

    test    ah,00000010b    ; controlla micro 1
    jz      ns4             ; micro 1 rilasciato

    ; sposta l'asse dal micro 1

    mov     tnt_nosns,0     ; # tentativi fatti

    ns1:            call    forward         ; inizia spostamento
    mov     ax,time         ; registra istante attuale
    mov     ttt,ax

    ns2:            call    assestatus      ; legge stato micro

    test    ah,00000100b    ; controlla micro 2
    jnz     nsoff           ; MICRO 2 PREMUTO !!!

    mov     ax,time         ; controlla tempo trascorso
    sub     ax,ttt
    jnc     ns3
    neg     ax              ; evita l'overflow del timer
    ns3:            cmp     ax,54
    jb      ns2             ; tempo inferiore a 3 sec.

    call    stop            ; arresta l'asse

    call    assestatus      ; legge stato micro

    test    ah,00000100b    ; controlla micro 2
    jnz     nsoff           ; MICRO 2 PREMUTO !!!

    test    ah,00000010b    ; controlla micro 1
    jz      nsok            ; micro 1 rilasciato

    inc     tnt_nosns       ; controlla tentativi
    cmp     tnt_nosns,3
    jae     nsoff           ; troppi: ERRORE !!!

    call    reset           ; resetta l'asse
    jmp     ns1             ; riprova

    ; controlla micro 2

    ns4:            test    ah,00000100b    ; controlla micro 2
    jz      nsok            ; micro 2 rilasciato

    ; sposta l'asse dal micro 2

    mov     tnt_nosns,0     ; # tentativi fatti

    ns5:            call    backward        ; inizia spostamento
    mov     ax,time         ; registra istante attuale
    mov     ttt,ax

    ns6:            call    assestatus      ; legge stato micro

    test    ah,00000010b    ; controlla micro 1
    jnz     nsoff           ; MICRO 1 PREMUTO !!!

    mov     ax,time         ; controlla tempo trascorso
    sub     ax,ttt
    jnc     ns7
    neg     ax              ; evita l'overflow del timer
    ns7:            cmp     ax,54
    jb      ns6             ; tempo inferiore a 3 sec.

    call    stop            ; arresta l'asse

    call    assestatus      ; legge stato micro

    test    ah,00000010b    ; controlla micro 1
    jnz     nsoff           ; MICRO 1 PREMUTO !!!

    test    ah,00000100b    ; controlla micro 2
    jz      nsok            ; micro 2 rilasciato

    inc     tnt_nosns       ; controlla tentativi
    cmp     tnt_nosns,3
    jae     nsoff           ; troppi: ERRORE !!!

    call    reset           ; resetta l'asse
    jmp     ns5             ; riprova

    nsoff:          mov     dx,ENABLE       ; disabilita l'asse
    mov    al,ENABLE_BIT
    call    setbit
    call    off        ; blocca l'asse
    stc                    ; ERRORE !!!
    ret

    nsok:        clc            ; tutto ok
    ret
    ENDP

    ;       inizializza l'asse
    ;
    ; output: carry-flag = reset se tutto ha funzionato a dovere
    ;      carry-flag = set   se si Š verificato un errore

    tt              DW      ?
    tnt_init        DW      ?

    asseinit    PROC    NEAR
    mov    dx,ENABLE    ; abilita l'asse
    mov    al,ENABLE_BIT
    call    resetbit

    call    reset           ; resetta l'asse

    call    nosns           ; sposta l'asse dai sensori 1 e 2
    jc      aierr           ; ERRORE !!!

    ; attende mcr_1 = 1

    mov     tnt_init,0      ; # tentativi

    aini1:          call    backward        ; inizia spostamento
    mov     ax,time         ; registra istante attuale
    mov     tt,ax

    aini2:          call    assestatus      ; legge stato micro
    test    ah,00000100b    ; controlla micro 2
    jnz     aierr           ; MICRO 2 PREMUTO !!!
    test    ah,00000010b    ; controlla micro 1
    jnz     aini4           ; micro 1 premuto

    mov     ax,time         ; controlla tempo trascorso
    sub     ax,tt
    jnc     aini3
    neg     ax              ; evita l'overflow del timer
    aini3:          cmp     ax,WAIT_1
    jb      aini2

    call    stop            ; arresta l'asse

    call    assestatus      ; legge stato micro
    test    ah,00000100b    ; controlla micro 2
    jnz     aierr           ; MICRO 2 PREMUTO !!!

    inc     tnt_init        ; controlla tentativi
    cmp     tnt_init,3
    jae     aierr           ; troppi: ERRORE !!!

    call    reset           ; resetta l'asse
    jmp     aini1           ; riprova

    aierr:          mov     dx,ENABLE       ; toglie l'abilitazione
    mov    al,ENABLE_BIT
    call    setbit
    call    off             ; blocca l'asse
    stc                     ; ERRORE !!!
    ret

    ; attende mcr_1 = 0

    aini4:          call    break           ; arresta l'asse

    push    SLOW_HIGH       ; salva bassa velocit…
    push    SLOW_LOW
    mov     ax,SSLOW_HIGH   ; imposta bassissima velocit…
    mov    SLOW_HIGH,ax
    mov    ax,SSLOW_LOW
    mov    SLOW_LOW,ax

    mov     tnt_init,0      ; # tentativi

    aini6:          call    forward         ; inizia spostamento
    mov     ax,time         ; registra istante attuale
    mov     tt,ax

    aini7:          call    assestatus      ; legge stato micro
    test    ah,00000100b    ; controlla micro 2
    jnz     _aierr          ; MICRO 2 PREMUTO !!!
    test    ah,00000010b    ; controlla micro 1
    jnz     aini8           ; micro 1 premuto

    mov     cx,WAIT_SNS     ; attende stabilit… segnale
    loop    $

    call    assestatus      ; legge stato micro
    test    ah,00000100b    ; controlla micro 2
    jnz     _aierr          ; MICRO 2 PREMUTO !!!
    test    ah,00000010b    ; controlla micro 1
    jz      aini10          ; micro 1 rilasciato

    aini8:          mov     ax,time         ; controlla tempo trascorso
    sub     ax,tt
    jnc     aini9
    neg     ax              ; evita l'overflow del timer
    aini9:          cmp     ax,182
    jb      aini7           ; tempo inferiore a 10 sec.

    call    stop            ; arresta l'asse

    call    assestatus      ; legge stato micro
    test    ah,00000100b    ; controlla micro 2
    jnz     _aierr          ; MICRO 2 PREMUTO !!!

    inc     tnt_init        ; controlla tentativi
    cmp     tnt_init,3
    jae     _aierr          ; troppi: ERRORE !!!

    call    reset           ; resetta l'asse
    jmp     aini6           ; riprova

    aini10:         mov     dx,CMD_PORT     ; fissa l'origine
    mov    al,DFH
    call    wrcmd

    pop     SLOW_LOW        ; recupera bassa velocit…
    pop    SLOW_HIGH

    call    stop            ; arresta l'asse

    clc                     ; tutto ok
    ret

    _aierr:         pop     SLOW_LOW        ; recupera bassa velocit…
    pop    SLOW_HIGH
    jmp     aierr
    ENDP

    ;       trova la distanza fra i due micro fine-corsa dell'asse
    ;
    ; output: DX:AX = valore trovato (0 in caso di errore)

    assedist        PROC    NEAR
    call    nosns           ; sposta l'asse dai sensori 1 e 2
    jc      aderr           ; ERRORE !!!

    ; attende mcr_2 = 1

    mov     tnt_init,0      ; # tentativi

    adis1:          call    forward         ; inizia spostamento
    mov     ax,time         ; registra istante attuale
    mov     tt,ax

    adis2:          call    assestatus      ; legge stato micro
    test    ah,00000010b    ; controlla micro 1
    jnz     aderr           ; MICRO 1 PREMUTO !!!
    test    ah,00000100b    ; controlla micro 2
    jnz     adis4           ; micro 2 premuto

    mov     ax,time         ; controlla tempo trascorso
    sub     ax,tt
    jnc     adis3
    neg     ax              ; evita l'overflow del timer
    adis3:          cmp     ax,WAIT_1
    jb      adis2

    call    stop            ; arresta l'asse

    call    assestatus      ; legge stato micro
    test    ah,00000010b    ; controlla micro 1
    jnz     aderr           ; MICRO 1 PREMUTO !!!

    inc     tnt_init        ; controlla tentativi
    cmp     tnt_init,3
    jae     aderr           ; troppi: ERRORE !!!

    jmp     adis1           ; riprova

    aderr:          mov     dx,ENABLE       ; toglie l'abilitazione
    mov    al,ENABLE_BIT
    call    setbit
    call    off             ; blocca l'asse
    xor     ax,ax           ; ERRORE !!!
    xor     dx,dx
    ret

    ; attende mcr_2 = 0

    adis4:          call    break           ; arresta l'asse

    push    SLOW_HIGH       ; salva bassa velocit…
    push    SLOW_LOW
    mov     ax,SSLOW_HIGH   ; imposta bassissima velocit…
    mov    SLOW_HIGH,ax
    mov    ax,SSLOW_LOW
    mov    SLOW_LOW,ax

    mov     tnt_init,0      ; # tentativi

    adis6:          call    backward        ; inizia spostamento
    mov     ax,time         ; registra istante attuale
    mov     tt,ax

    adis7:          call    assestatus      ; legge stato micro
    test    ah,00000010b    ; controlla micro 1
    jnz     _aderr          ; MICRO 1 PREMUTO !!!
    test    ah,00000100b    ; controlla micro 2
    jnz     adis8           ; micro 2 premuto

    mov     cx,WAIT_SNS     ; attende stabilit… segnale
    loop    $

    call    assestatus      ; legge stato micro
    test    ah,00000010b    ; controlla micro 1
    jnz     _aderr          ; MICRO 1 PREMUTO !!!
    test    ah,00000100b    ; controlla micro 2
    jz      adis10          ; micro 2 rilasciato

    adis8:          mov     ax,time         ; controlla tempo trascorso
    sub     ax,tt
    jnc     adis9
    neg     ax              ; evita l'overflow del timer
    adis9:          cmp     ax,182
    jb      adis7           ; tempo inferiore a 10 sec.

    call    stop            ; arresta l'asse

    call    assestatus      ; legge stato micro
    test    ah,00000010b    ; controlla micro 1
    jnz     _aderr          ; MICRO 1 PREMUTO !!!

    inc     tnt_init        ; controlla tentativi
    cmp     tnt_init,3
    jae     _aderr          ; troppi: ERRORE !!!

    jmp     adis6           ; riprova

    adis10:         call    stop            ; arresta l'asse
    pop     SLOW_LOW        ; recupera bassa velocit…
    pop    SLOW_HIGH

    mov     dx,CMD_PORT     ; legge la posizione attuale
    mov    al,RDRP
    call    wrcmd
    call    rdword
    push    ax
    call    rdword
    pop     dx              ; dx = MSW , ax = LSW
    ret                     ; tutto ok

    _aderr:         pop     SLOW_LOW        ; recupera bassa velocit…
    pop    SLOW_HIGH
    jmp     aderr
    ENDP

    ;       inizializza l'asse X
    ;
    ;   out: AL = esito ('0' -> ok, 'X' -> errore)

    __vbinitx       PROC    NEAR
    mov     di,OFFSET xport ; inizializza
    call    asseinit
    mov     al,'X'          ; ERRORE !!!
    jc      ixret
    mov     al,'0'          ; ok
    ixret:          ret
    ENDP

    ;       inizializza l'asse Z
    ;
    ;   out: AL = esito ('0' -> ok, 'Z' -> errore)

    __vbinitz       PROC    NEAR
    mov     di,OFFSET zport ; inizializza
    call    asseinit
    mov     al,'Z'          ; ERRORE !!!
    jc      izret
    mov     al,'0'          ; ok
    izret:          ret
    ENDP

    ;       trova la distanza fra i due micro fine-corsa dell'asse X
    ;
    ;   out: DX:AX = valore trovato (0 in caso di errore)

    __vbdisx        PROC    NEAR
    mov     di,OFFSET xport ; imposta asse x
    call    assedist        ; trova distanza
    ret
    ENDP

    ;       trova la distanza fra i due micro fine-corsa dell'asse Z
    ;
    ;   out: DX:AX = valore trovato (0 in caso di errore)

    __vbdisz        PROC    NEAR
    mov     di,OFFSET zport ; imposta asse z
    call    assedist        ; trova distanza
    ret
    ENDP

    ;*****************************************************************************
    ;
    ;    gestione del posizionamento degli assi
    ;
    ; input:  DATI.TXT = file con la posizione da raggiungere
    ;
    ; output: AL = '0' se tutto ok
    ;         AL = 'I' se pinza in stato errato
    ;         AL = 'F' se errore nel file
    ;         AL = 'P' se errore nello spostamento
    ;
    ;******************************************************************************

    posfile         DB      'DATI.TXT',0    ; file con la posizione

    time            DW      ?       ; contatori tempo
    old             DW      ?
    old1            DW      ?

    tnt_goto        DW      ?

    __vbgotoxz      PROC    NEAR

    ; controllo stato pinza

    call    statopinza
    jnc     go1             ; pinza ok
    mov     al,'I'          ; PINZA IN STATO ERRATO !!!
    ret

    ; lettura posizione da raggiungere

    go1:            mov     ax,3d00h        ; apertura file DATI.TXT
    mov    dx,OFFSET posfile
    int    21h
    jc      fileerrret      ; APERTURA FALLITA !!!

    mov     bx,ax           ; lettura posizione x
    mov    cx,4
    mov    dx,OFFSET xpos
    mov    ah,3fh
    int    21h
    jc      fileerr         ; LETTURA FALLITA !!!
    cmp    ax,4
    jne     fileerr         ; LETTURA ERRATA !!!

    mov     dx,OFFSET zpos  ; lettura posizione z
    mov     ah,3fh
    int    21h
    jc      fileerr         ; LETTURA FALLITA !!!
    cmp    ax,4
    jne     fileerr         ; LETTURA ERRATA !!!

    mov     ah,3eh          ; chiusura file
    int    21h
    jnc     go2             ; chiusura ok

    fileerr:        mov     ah,3eh          ; chiusura file
    int    21h
    fileerrret:     mov     al,'F'          ; ERRORE NEL FILE !!!
    ret

    ; inizia traiettoria

    go2:            mov     di,OFFSET ppen  ; attiva motori pinza
    call    motoreon
    mov    di,OFFSET tten
    call    motoreon

    mov     tnt_goto,0      ; # tentativi posizonamento

    _go2:           mov     di,OFFSET xport ; inizia spostamento
    call    position
    mov    di,OFFSET zport
    call    position

    mov     time,0          ; tempo trascorso
    mov     old,0           ; istante ultima lettura posizione

    ; attende completamento traiettoria e controlla errori

    gonext:         mov     ax,time         ; istante ultima constatazione assi
    mov     old1,ax         ;   non in quota

    gonext1:        cmp     time,182        ; controlla tempo trascorso con 10 s.
    jb      _gonext1

    inc     tnt_goto        ; controlla tentativi fatti
    cmp     tnt_goto,3
    jae     goerr           ; TIME-OUT: 3 tentativi fatti !!!

    in      al,61h          ; beep
    mov     cx,500
    ll22:           xor     al,00000010b
    out     61h,al
    push    cx
    mov     cx,200
    loop    $
    pop     cx
    loop    ll22

    jmp     _go2            ; riprova

    _gonext1:  ;    mov     di,OFFSET xport ; controlla fine-corsa x
    ;    call    assestatus
    ;    test    ah,00000110b
    ;    jz      go3             ; fine-corsa rilasciati

    ;    mov     cx,8000h        ; attende e ricontrolla fine-corsa x
    ;    loop    $
    ;    call    assestatus
    ;    test    ah,00000110b
    ;    jnz     goerr           ; FINE-CORSA PREMUTI !!!

    go3:       ;    mov     di,OFFSET zport ; controlla fine-corsa z
    ;    call    assestatus
    ;    test    ah,00000110b
    ;    jz      go4             ; fine-corsa rilasciati

    ;    mov     cx,8000h        ; attende e ricontrolla fine-corsa z
    ;    loop    $
    ;    call    assestatus
    ;    test    ah,00000110b
    ;    jnz     goerr           ; FINE-CORSA PREMUTI !!!

    go4:       ;    mov     dx,xport        ; controlla status byte LM628 x
    ;    in      al,dx
    ;    test    al,EX_POS_ERR
    ;    jnz     goerr           ; EXCESSIVE POSITION ERROR !!!

    ;    mov     dx,zport        ; controlla status byte LM628 z
    ;    in      al,dx
    ;    test    al,EX_POS_ERR
    ;    jnz     goerr           ; EXCESSIVE POSITION ERROE !!!

    jmp     SHORT go5

    goerr:          mov     dx,xenable      ; disabilita l'asse x
    mov    al,xenable_bit
    call    setbit
    mov     dx,zenable      ; disabilita l'asse z
    mov    al,zenable_bit
    call    setbit

    mov     di,OFFSET xport ; blocca l'asse x
    call    off
    mov     di,OFFSET zport ; blocca l'asse z
    call    off

    mov    al,'P'        ; POSIZIONE NON RAGGIUNTA !!!
    jmp     goret

    go5:            mov     dx,xport        ; controlla status byte LM628 x
    in    al,dx
    test    al,TRJ_COMP
    jz      gonextr         ; asse x in movimento

    mov     di,zport        ; controlla status byte LM628 z
    in    al,dx
    test    al,TRJ_COMP
    jz      gonextr         ; asse z in movimento

    mov     ax,time         ; intervalla le operazioni succesive
    sub     ax,old          ;   di 0.1 secondi
    cmp     ax,2
    jb      gonext1r

    mov     ax,time         ; istante ultima lettura posizione
    mov     old,ax

    mov     dx,xport        ; legge posizione x attuale
    mov    al,RDRP
    call    wrcmd
    call    rdword
    push    ax
    call    rdword
    pop     dx              ; dx = MSW , ax = LSW

    add    ax,100        ; somma epsilon
    adc    dx,0

    cmp    dx,xpos[2]    ; controlla limite inferiore
    jl      gonextr         ; quota non raggiunta
    jg      go6
    cmp    ax,xpos[0]
    jbe     gonextr         ; quota non raggiunta

    go6:            add     ax,-200         ; sottrae epsilon
    adc    dx,-1

    cmp    dx,xpos[2]    ; controlla limite superiore
    jg      gonextr         ; quota non raggiunta
    jl      go7             ; quota x raggiunta
    cmp    ax,xpos[0]
    jb      go7             ; quota x raggiunta

    gonextr:        jmp     gonext
    gonext1r:       jmp     gonext1

    go7:            mov     dx,zport        ; legge la posizione z attuale
    mov    al,RDRP
    call    wrcmd
    call    rdword
    push    ax
    call    rdword
    pop     dx              ; dx = MSW , ax = LSW

    add    ax,400        ; somma epsilon
    adc    dx,0

    cmp    dx,zpos[2]    ; controlla limite inferiore
    jl      gonextr         ; quota non raggiunta
    jg      go8
    cmp    ax,zpos[0]
    jbe     gonextr         ; quota non raggiunta

    go8:            add     ax,-800         ; sottrae epsilon
    adc    dx,-1

    cmp    dx,zpos[2]    ; controlla limte superiore
    jg      gonextr         ; quota non raggiunta
    jl      go9             ; quota z raggiunta
    cmp    ax,zpos[0]
    jae     gonextr         ; quota non raggiunta

    go9:            mov     ax,time         ; controllo tempo assi in quota
    sub     ax,old1
    cmp     ax,9
    jb      gonext1r        ; tempo inferiore a 0.5 secondi

    mov     al,'0'          ; ok

    goret:          push    ax              ; salva esito
    mov    di,OFFSET ppen    ; disattiva motori pinza
    call    motoreoff
    mov    di,OFFSET tten
    call    motoreoff
    pop     ax              ; recupera esito
    ret
    ENDP

    ;******************************************************************************
    ;
    ;    inizializzazione VIDEOBANK
    ;
    ; output: param = '0' se tutto ha funzionato a dovere
    ;      param = 'A' se si Š verificato un errore inizializzando la porta
    ;      param = 'B' se si Š verificato un errore inizializzando la pinza
    ;         param = 'C' se il tappeto Š in stato errato
    ;      param = 'X' se si Š verificato un errore inizializzando l'asse x
    ;         param = 'Z' se si Š verificato un errore inizializzando l'asse z
    ;
    ;******************************************************************************

    __vbinit        PROC    NEAR
    mov     dx,0310h        ; setta tutte le porta di output
    mov     al,11111111b
    call    setbit
    mov     dx,0312h
    mov     al,11111101b    ; (lo Z80 non deve essere resettato)
    call    setbit
    mov     dx,0314h
    mov     al,11111111b
    call    setbit
    mov     dx,0318h
    mov     al,11111111b
    call    setbit
    mov     dx,031Ch
    mov     al,11111111b
    call    setbit

    call    tappstatus      ; controlla stato tappeto
    cmp     ah,00000111b
    je      __i1
    mov     al,'C'          ; TAPPETO NON OK !!!
    ret

    __i1:           call    __vbdown        ; chiude porta
    cmp     al,'0'
    je      __i2
    mov     al,'A'          ; PORTA NON OK !!!
    ret

    ; inizializza gruppo pinza

    __i2:
    IF BARGP EQ 0                           ; se non ci sono le barriere
    mov     di,OFFSET tten          ; controlla presenza cassetta
    mov     tout0,FBR_ANT
    mov     tout0_bit,FBR_ANT_BIT
    mov     si,OFFSET tout0
    call    motore1
    jnc     pnzerr                  ; cassetta presente
    ENDIF

    mov     di,OFFSET ppen          ; preme il micro posteriore
    mov     si,OFFSET mcr_ant
    mov     mcr_ant_stat,0          ; prova 1 volta
    call    motore0
    mov     mcr_ant_stat,MCR_POS_BIT
    jnc     _i1                     ; ok
    mov     mcr_ant_stat,0          ; prova 1 volta
    call    motore0
    mov     mcr_ant_stat,MCR_POS_BIT
    jnc     _i1                     ; ok
    mov     mcr_ant_stat,0          ; prova 1 volta
    call    motore0
    mov     mcr_ant_stat,MCR_POS_BIT
    jnc     _i1                     ; ok

    pnzerr:         mov     al,'B'                  ; PINZA NON OK !!!
    ret

    _i1:            call    statopinza              ; completa inizializzazione
    jc      pnzerr                  ; PINZA NON OK !!!
    IF BARGP EQ 1
    jz      pnzerr                  ; PINZA NON OK !!!
    ENDIF
    mov     dx,MCR_CNT              ; controlla micro centrale
    in      al,dx
    test    al,MCR_CNT_BIT
    jnz     pnzerr                  ; micro rilasciato
    mov     dx,FBR_ANT              ; controlla fibra anteriore
    in      al,dx
    test    al,FBR_ANT_BIT
    jz      pnzerr                  ; fibra eccitata
    mov     dx,FBR_POS              ; controlla fibra posteriore
    in      al,dx
    test    al,FBR_POS_BIT
    jz      pnzerr                  ; fibra eccitata

    mov     di,OFFSET ppen  ; abilita trasporto
    call    motoreon
    mov     di,OFFSET tten  ; disattiva tappeto
    call    motoreoff

    mov     di,OFFSET zport ; inizializza asse z
    call    asseinit
    mov    al,'Z'
    jc      initret         ; ASSE Z NON OK !!!

    mov     di,OFFSET xport ; inizializza asse x
    call    asseinit
    mov    al,'X'
    jc      initret         ; ASSE X NON OK !!!

    mov     di,OFFSET ppen  ; disattiva trasporto
    call    motoreoff

    mov     al,'0'          ; tutto ok
    initret:        ret
    ENDP

    ;******************************************************************************
    ;
    ;    VIDEOBANK in errore
    ;
    ; output: param = '0' se tutto ha funzionato a dovere
    ;      param = 'A' se la porta non si Š chiusa
    ;
    ;******************************************************************************

    __vbleave       PROC    NEAR
    mov     dx,0310h        ; setta tutte le porta di output
    mov     al,11111111b
    call    setbit
    mov     dx,0312h
    mov     al,11111101b    ; (lo Z80 non deve essere resettato)
    call    setbit
    mov     dx,0314h
    mov     al,11111111b
    call    setbit
    mov     dx,0318h
    mov     al,11111111b
    call    setbit
    mov     dx,031Ch
    mov     al,11111111b
    call    setbit

    mov     di,OFFSET xport ; blocca gli assi
    call    off
    mov    di,OFFSET zport
    call    off

    call    __vbdown        ; chiude la porta
    cmp     al,'0'
    je      leaveret        ; porta chiusa
    mov     al,'A'          ; porta non chiusa
    leaveret:       ret
    ENDP

    ;       carica i parametri dal file C:\VBL\PARAM.TXT

    param           DB      'C:\VBL\PARAM.TXT',0    ; file con i parametri

    __lparam        PROC    NEAR
    mov     ax,3d00h        ; apre il file in lettura
    mov     dx,OFFSET param
    int     21h

    mov     bx,ax
    mov     cx,2

    mov     ah,3fh
    mov     dx,OFFSET VEL_REG
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET STEPS_INT
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET pstart_vel
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET steps_sns_up
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET steps_sns_down
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET ppstart_vel
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET ttstart_vel
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET vicino_ant
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET steps_sns_ravt
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET steps_sns_ind
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET steps_sns_aind
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET steps_sns_cavt
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET vicino_pos
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET steps_sns_rind
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET steps_sns_avt
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET steps_sns_pavt
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET steps_sns_cind
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET STEPS_ANT
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET STEPST
    int     21h

    mov     ah,3fh
    mov     dx,OFFSET STEPSP
    int     21h

    mov     ah,3eh  ; chiude il file
    int     21h

    mov     ax,ppstart_vel
    mov     ppvel,ax
    mov     ax,ttstart_vel
    mov     ttvel,ax
    ret
    ENDP

    ;******************************************************************************
    ;
    ;       gestione del lettore di banconote
    ;
    ; output: AL = 'G' -> lettore guasto
    ;              'T' -> time-out attendendo una banconota
    ;              '1' -> tasto ESC premuto
    ;              '2' -> tasto F9 premuto
    ;              'A' -> banconota da L. 10000
    ;              'B' -> banconota da L. 5000
    ;              'C' -> banconota da L. 50000
    ;
    ;******************************************************************************

    OOO             EQU     0314h
    OOO_BIT         EQU     01000000b
    LBUSY           EQU     0314h
    LBUSY_BIT       EQU     00100000b
    DATA_V          EQU     0314h
    DATA_V_BIT      EQU     00000010b
    DATA_1          EQU     0314h
    DATA_1_BIT      EQU     00000100b
    DATA_2          EQU     0314h
    DATA_2_BIT      EQU     00001000b
    DATA_3          EQU     0314h
    DATA_3_BIT      EQU     00010000b

    BLOCK           EQU     0314h
    BLOCK_BIT       EQU     00000010b
    AUX1            EQU     0318h
    AUX1_BIT        EQU     10000000b
    AUX2            EQU     0318h
    AUX2_BIT        EQU     00000010b

    __vbrdban       PROC    NEAR
    mov     dx,OOO          ; controlla stato lettore
    in      al,dx
    test    al,OOO_BIT
    jnz     ban0            ; lettore funzionante
    mov     al,'G'
    jmp     banret          ; lettore guasto

    ban0:           mov     dx,BLOCK        ; abilita ingresso banconote
    mov     al,BLOCK_BIT
    call    resetbit

    mov     time,0          ; registra istante attuale

    ban1:           mov     dx,DATA_V       ; banconota presente ?
    in      al,dx
    test    al,DATA_V_BIT
    jnz     ban2            ; no: attendi

    mov     cx,8000h        ; si: attendi un po' e ...
    loop    $
    in      al,dx           ; verifica banconota presente
    test    al,DATA_V_BIT
    jnz     ban2            ; no: attendi

    mov     dx,DATA_2       ; controlla se banconota da L. 5000
    in      al,dx
    test    al,DATA_2_BIT
    mov     al,'B'
    jz      ban4            ; L. 5000
    mov     dx,DATA_3       ; controlla se banconota da L. 10000
    in      al,dx
    test    al,DATA_3_BIT
    mov     al,'A'
    jz      ban4            ; L. 10000
    mov     dx,DATA_1       ; controlla se banconota da L. 50000
    in      al,dx
    test    al,DATA_1_BIT
    mov     al,'C'
    jz      ban4            ; L. 50000
    mov     al,'G'          ; lettore guasto
    jmp     ban4

    ban2:           mov     dx,LBUSY        ; controlla busy
    in      al,dx
    test    al,LBUSY_BIT
    jz      ban1            ; lettore occupato

    mov     ah,01h          ; controlla buffer tastiera
    int    16h
    jz      ban3            ; buffer vuoto
    xor     ah,ah           ; legge tasto
    int    16h
    mov     dx,ax
    cmp     dx,ESC_KEY
    mov    al,'1'
    je      ban4            ; tasto ESC
    cmp    dx,F9_KEY
    mov    al,'2'
    je      ban4            ; tasto F9

    ban3:           cmp     time,182        ; controlla tempo trascorso
    jb      ban1            ; continua
    mov     al,'T'          ; time-out

    ban4:           push    ax              ; salva esito

    mov     dx,BLOCK        ; disabilita ingresso banconote
    mov     al,BLOCK_BIT
    call    setbit

    mov     dx,LBUSY        ; attesa arresto motore
    ban5:           in      al,dx
    test    al,LBUSY_BIT
    jz      ban5            ; motore in movimento

    pop     ax              ; recupera esito
    banret:         ret
    ENDP

    ;       riporta in AL lo stato del tunnel
    ;
    ; out: bit0 = stato barriera esterna
    ;      bit1 = stato barriere interna e centrale (1->non interrotte,0->almeno 1 interrotta)
    ;      bit2 = stato barriera anteriore
    ;      bit3 = stato barriera posteriore

    __vbstatus      PROC    NEAR
    mov     ah,1111b        ; imposta barriere non interrotte

    mov     dx,SNS_EST      ; controlla barriere esterna
    in      al,dx
    test    al,SNS_EST_BIT
    jnz     __vbst1         ; barriera non interrotta
    and     ah,1110b        ; barriera interrotta

    __vbst1:        mov     dx,SNS_CNT      ; controlla barriere centrale
    in      al,dx
    test    al,SNS_CNT_BIT
    jnz     __vbst2         ; barriera non interrotta
    and     ah,1101b        ; barriera interrotta

    __vbst2:        mov     dx,SNS_INT      ; controlla barriere interna
    in      al,dx
    test    al,SNS_INT_BIT
    jnz     __vbst3         ; barriera non interrotta
    and     ah,1101b        ; barriera interrotta

    __vbst3:        mov     dx,BAR_ANT      ; controlla barriere anteriore
    in      al,dx
    test    al,BAR_ANT_BIT
    jnz     __vbst4         ; barriera non interrotta
    and     ah,1011b        ; barriera interrotta

    __vbst4:        mov     dx,BAR_POS      ; controlla barriere posteriore
    in      al,dx
    test    al,BAR_POS_BIT
    jnz     __vbst5         ; barriera non interrotta
    and     ah,0111b        ; barriera interrotta

    __vbst5:        mov     al,ah           ; ritorna il risultato in AL
    ret
    ENDP

    IF INT8 EQ 1

    oldint8         DD      ?
    inint8          DB      0

    total           DW      ?
    extra           DW      ?

    j00:            jmp     j0
    j11:            jmp     j1
    j22:            jmp     j2

    int8            PROC    FAR
    ;       push    ds              ; debug
    ;       push    bx
    ;       mov     bx,0b800h
    ;       mov     ds,bx
    ;       xor     bx,bx
    ;       inc     word ptr [bx]
    ;       pop     bx
    ;       pop     ds

    push    ds              ; salva DS
    push    cs              ; imposta DS=CS
    pop     ds

    inc     time            ; aggiorna i contatori
    inc     time1

    pushf                   ; esegue il precedente handler
    call    oldint8

    cmp     inint8,0        ; si Š gi… in questo handler ?
    ja      j00             ; si: esci !!!

    ;       push    ds              ; debug
    ;       push    bx
    ;       mov     bx,0b800h
    ;       mov     ds,bx
    ;       mov     bx,2
    ;       inc     word ptr [bx]
    ;       pop     bx
    ;       pop     ds

    inc     inint8          ; registra l'entrata

    sti                     ; interrupt ok

    cmp     status,0        ; stato teorico porta ?
    je      j11             ; aperta: esci

    push    ax              ; salva i registri usati
    push    bx
    push    cx
    push    dx

    mov     dx,318h         ; stato micro inferiore ?
    in      al,dx
    test    al,00100000b
    jz      j5              ; premuto: porta chiusa

    cmp     status,2        ; stato teorico porta ?
    je      j22             ; incastrata: esci

    IF DOORBCKGRD EQ 0    ; se non c'e' la chiusura in back-ground
    jmp     j4              ; spegni il motore
    ENDIF

    mov     dx,310h         ; abilita motore
    mov     al,00000100b
    call    resetbit
    mov     dx,31ch         ; direzione chiusura
    mov     al,01000000b
    call    resetbit

    mov     total,0         ; partenza
    mov     extra,0

    j7:             mov     dx,312h         ; un passo
    mov     al,00010000b
    call    reversebit
    inc     total

    mov     cx,pstart_vel   ; attesa per velocit…
    loop    $

    mov     dx,318h         ; stato micro inferiore ?
    in      al,dx
    test    al,00100000b
    jz      j6              ; premuto

    mov     extra,0           ; micro rilasciato
    mov     ax,total          ; passi fatti ?
    cmp     ax,max_steps_down
    jb      j7                ; pochi: ritenta
    mov     status,2          ; time-out: porta incastrata
    jmp     SHORT j4          ; disabilita ed esci

    j6:             inc     extra             ; micro premuto
    mov     ax,extra          ; stato reale porta ?
    cmp     ax,steps_sns_down 
    jb      j7                ; non chiusa: continua
    mov     time1,0           ; porta appena chiusa
    jmp     SHORT j2          ; esci

    j5:             cmp     status,2        ; stato teorico porta ?
    je      j3              ; incastrata: sblocca

    IF DOORBCKGRD EQ 0    ; se non c'e' la chiusura in back-ground
    jmp     j4              ; spegni il motore
    ENDIF

    cmp     time1,364       ; tempo di disabilitare ?
    jb      j2              ; no: esci

    dec     time1           ; disabilita motore porta
    j4:             mov     dx,310h
    mov     al,00000100b
    call    setbit
    jmp     SHORT j2        ; ed esci

    j3:             mov     status,1        ; sblocca ed esci
    mov     time1,364

    j2:             pop     dx              ; recupera i registri salvati
    pop     cx
    pop     bx
    pop     ax

    j1:             dec     inint8          ; registra l'uscita

    j0:             pop     ds              ; recupera DS
    iret
    ENDP

    ELSE

    oldint1c        DW      2 DUP (?)

    int1c           PROC    FAR
    inc     cs:time
    push    cs:[oldint1c+2]
    push    cs:[oldint1c+0]
    retf
    ENDP

    ENDIF

    int60           PROC    FAR
    sti
    push    bx              ; salva registri
    push    cx
    push    dx
    push    si
    push    di
    push    bp
    push    ds
    push    es

    mov     bx,cs
    mov     ds,bx
    mov     es,bx

    ah1:            dec     ah
    jnz     ah2
    call    __vbtapp
    jmp     SHORT intret

    ah2:            dec     ah
    jnz     ah3
    call    __vbesp
    jmp     SHORT intret

    ah3:            dec     ah
    jnz     ah4
    call    __vbdown
    jmp     SHORT intret

    ah4:            dec     ah
    jnz     ah5
    call    __vbup
    jmp     SHORT intret

    ah5:            dec     ah
    jnz     ah6
    call    __vbpick
    jmp     SHORT intret

    ah6:            dec     ah
    jnz     ah7
    call    __vbplace
    jmp     SHORT intret

    ah7:            dec     ah
    jnz     ah8
    call    __vbpicktp
    jmp     SHORT intret

    ah8:            dec     ah
    jnz     ah9
    call    __vbpltp
    jmp     SHORT intret

    ah9:            dec     ah
    jnz     ah10
    call    __vbgotoxz
    jmp     SHORT intret

    ah10:           dec     ah
    jnz     ah11
    call    __vbinit
    jmp     SHORT intret

    ah11:           dec     ah
    jnz     ah12
    call    __vbleave
    jmp     SHORT intret

    ah12:           dec     ah
    jnz     ah13
    call    __lparam
    jmp     SHORT intret

    ah13:           dec     ah
    jnz     ah14
    call    __vbrdban
    jmp     SHORT intret

    ah14:           dec     ah
    jnz     ah15
    call    __vbinitx
    jmp     SHORT intret

    ah15:           dec     ah
    jnz     ah16
    call    __vbinitz

    intret:         pop     es              ; recupera registri
    pop     ds
    pop     bp
    pop     di
    pop     si
    pop     dx
    pop     cx
    pop     bx
    iret

    ah16:           dec     ah
    jnz     ah17
    call    __vbdisx
    jmp     SHORT disret

    ah17:           dec     ah
    jnz     ah18
    call    __vbdisz
    jmp     SHORT disret

    ah18:           dec     ah
    jnz     ah19
    call    __vbespp
    jmp     SHORT intret

    ah19:           dec     ah
    jnz     ah20
    call    __vbstatus
    jmp     SHORT intret

    ah20:
    disret:         pop     es              ; recupera registri in caso di
    pop     ds              ; calcolo distanza micro fine-corsa
    pop     bp              ; asse
    pop     di
    pop     si
    pop     cx              ; non recupera DX
    pop     cx
    pop     bx
    iret
    ENDP

    fineparteres    LABEL   BYTE

    Z80             EQU     0312h           ; reset Z80
    Z80_BIT         EQU     00000010b

    installa        PROC    NEAR
    mov     dx,0310h        ; setta tutte le porta di output
    mov     al,11111111b
    call    setbit
    mov     dx,0312h
    mov     al,11111101b    ; (lo Z80 non deve essere resettato)
    call    setbit
    mov     dx,0314h
    mov     al,11111111b
    call    setbit
    mov     dx,0318h
    mov     al,11111111b
    call    setbit
    mov     dx,031Ch
    mov     al,11111111b
    call    setbit

    mov     ah,9            ; scrive intestazione
    mov     dx,OFFSET sign
    int     21h

    IF INT8 EQ 1

    mov     ax,3508h        ; memorizza vecchio int 08h
    int     21h
    mov     WORD PTR cs:[oldint8+0],bx
    mov     WORD PTR cs:[oldint8+2],es

    mov     ax,2508h        ; installa nuovo int 08h
    push    cs
    pop     ds
    mov     dx,OFFSET int8
    int     21h

    ELSE

    mov     ax,351ch        ; memorizza vecchio int 1ch
    int     21h
    mov     cs:[oldint1c+0],bx
    mov     cs:[oldint1c+2],es

    mov     ax,251ch        ; installa nuovo int 1ch
    push    cs
    pop     ds
    mov     dx,OFFSET int1c
    int     21h

    ENDIF

    mov     ax,2560h        ; installa l'interrupt 60h
    push    cs
    pop     ds
    mov     dx,OFFSET int60
    int     21h

    call    __lparam        ; carica la tabella

    mov     dx,Z80          ; resetta lo Z80
    mov     al,Z80_BIT
    call    setbit
    mov     time,0          ; registra instante attuale
    inst1:          mov     ax,time
    cmp     ax,9            ; tempo trascorso
    jb      inst1           ; poco: attendi
    mov     dx,Z80          ; riattiva lo Z80
    mov     al,Z80_BIT
    call    resetbit

    call    statopinza      ; controlla stato pinza
    jc      noinitassi      ; errato

    ; sposta l'asse z dai micro
    mov     di,OFFSET zport         ; imposta asse z
    mov     dx,ENABLE               ; abilita
    mov    al,ENABLE_BIT
    call    resetbit
    call    reset                   ; resetta
    call    nosns                   ; sposta

    ; sposta l'asse x dai micro
    mov     di,OFFSET xport         ; imposta asse x
    mov     dx,ENABLE               ; abilita
    mov    al,ENABLE_BIT
    call    resetbit
    call    reset                   ; resetta
    call    nosns                   ; sposta

    noinitassi:     mov     di,OFFSET ppen  ; spegne motori pinza
    call    motoreoff
    mov     di,OFFSET tten
    call    motoreoff

    mov     es,cs:[2ch]     ; libera l'environment
    mov     ah,49h
    int     21h

    lea     dx,fineparteres  ; esce e rimane in memoria
    int     27h
    ENDP

    ENDS

    END     start