diff --git a/etc/hotplug/usb/usbdux/usbdux_firmware.asm b/etc/hotplug/usb/usbdux/usbdux_firmware.asm index e9aa88b..3513b1c 100644 --- a/etc/hotplug/usb/usbdux/usbdux_firmware.asm +++ b/etc/hotplug/usb/usbdux/usbdux_firmware.asm @@ -1,5 +1,6 @@ ; usbdux_firmware.asm -; Copyright (C) 2004 Bernd Porr, Bernd.Porr@cn.stir.ac.uk +; Copyright (C) 2004 Bernd Porr, Bernd.Porr@f2s.com +; For usbdux.c 1.00pre2 ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by @@ -19,8 +20,8 @@ ; Firmware: usbdux_firmware.asm for usbdux.c ; Description: University of Stirling USB DAQ & INCITE Technology Limited ; Devices: [ITL] USB-DUX (usbdux.o) -; Author: Bernd Porr -; Updated: 25 Jan 2004 +; Author: Bernd Porr +; Updated: 23 Jul 2004 ; Status: testing ; ;;; @@ -31,11 +32,21 @@ .equ CHANNELLIST,80h ; channellist in indirect memory - .equ DIOFLAG,90h ; flag if next IN transf is DIO - + .equ CMD_FLAG,90h ; flag if next IN transf is DIO + .equ SGLCHANNEL,91h ; channel for INSN + + .equ DIOSTAT0,98h ; last status of the digital port + .equ DIOSTAT1,99h ; same for the second counter + + .equ CTR0,0A0H ; counter 0 + .equ CTR1,0A2H ; counter 1 + .org 0000h ; after reset the processor starts here ljmp main ; jump to the main loop + .org 000bh ; timer 0 irq + ljmp timer0_isr + .org 0043h ; the IRQ2-vector ljmp jmptbl ; irq service-routine @@ -164,18 +175,25 @@ ep2_isr: main: mov DPTR,#CPUCS ; CPU control register mov a,#00010000b ; 48Mhz - movx @DPTR,a ; do it - lcall syncdelay + lcall syncdelaywr + mov dptr,#REVCTL + mov a,#00000011b ; allows skip + lcall syncdelaywr + + mov IP,#0 ; all std 8051 int have low priority + mov EIP,#0FFH ; all FX2 interrupts have high priority + mov dptr,#INTSETUP ; IRQ setup register mov a,#08h ; enable autovector - movx @DPTR,a ; do it - lcall syncdelay + lcall syncdelaywr lcall initAD ; init the ports to the converters lcall initeps ; init the isochronous data-transfer + lcall init_timer + mloop2: nop nop nop @@ -184,7 +202,7 @@ mloop2: nop nop nop - sjmp mloop2 ; do nothing. The rest is done by the IRQs + sjmp mloop2 ; loop for ever ;;; initialise the ports for the AD-converter @@ -194,6 +212,16 @@ initAD: ret +;;; init the timer for the soft counters +init_timer: + ;; init the timer for 2ms sampling rate + mov CKCON,#00000001b; CLKOUT/12 for timer + mov TL0,#010H ; 16 + mov TH0,#0H ; 256 + mov IE,#82H ; switch on timer interrupt (80H for all IRQs) + mov TMOD,#00000000b ; 13 bit counters + setb TCON.4 ; enable timer 0 + ret ;;; from here it's only IRQ handling... @@ -264,82 +292,27 @@ zerob2: mov a,r5 ; get r5 in order to shift the mask -;;; aquires data from all 8 channels and stores it in the EP6 buffer -convlo: ;; - mov AUTOPTRH1,#0F8H ; EP6 +;;; aquires data from A/D channels and stores them in the EP6 buffer +conv_ad: + mov AUTOPTRH1,#0F8H ; auto pointer on EP6 mov AUTOPTRL1,#00H mov AUTOPTRSETUP,#7 mov r0,#CHANNELLIST ; points to the channellist - mov a,@r0 ;Ch0 - lcall readAD - mov a,R3 ; - mov DPTR,#XAUTODAT1 - movx @DPTR,A - mov a,R4 ; - movx @DPTR,A - inc r0 ; next channel - mov a,@r0 ;Ch1 - lcall readAD - mov a,R3 ; - mov DPTR,#XAUTODAT1 - movx @DPTR,A - mov a,R4 ; - movx @DPTR,A + mov a,@r0 ; number of channels + mov r1,a ; counter + mov DPTR,#XAUTODAT1 ; auto pointer +convloop: inc r0 - mov a,@r0 ;Ch2 + mov a,@r0 ; Channel lcall readAD mov a,R3 ; - mov DPTR,#XAUTODAT1 movx @DPTR,A mov a,R4 ; movx @DPTR,A + djnz r1,convloop - inc r0 - mov a,@r0 ;Ch3 - lcall readAD - mov a,R3 ; - mov DPTR,#XAUTODAT1 - movx @DPTR,A - mov a,R4 ; - movx @DPTR,A - - inc r0 - mov a,@r0 ;Ch4 - lcall readAD - mov a,R3 ; - mov DPTR,#XAUTODAT1 - movx @DPTR,A - mov a,R4 ; - movx @DPTR,A - - inc r0 - mov a,@r0 ;Ch5 - lcall readAD - mov a,R3 ; - mov DPTR,#XAUTODAT1 - movx @DPTR,A - mov a,R4 ; - movx @DPTR,A - - inc r0 - mov a,@r0 ;Ch6 - lcall readAD - mov a,R3 ; - mov DPTR,#XAUTODAT1 - movx @DPTR,A - mov a,R4 ; - movx @DPTR,A - - inc r0 - mov a,@r0 ;Ch7 - lcall readAD - mov a,R3 ; - mov DPTR,#XAUTODAT1 - movx @DPTR,A - mov a,R4 ; - movx @DPTR,A ret @@ -349,9 +322,17 @@ convlo: ;; ;;; It is assumed that the USB interface is in alternate setting 3 initeps: mov dptr,#FIFORESET - mov a,#0fh + mov a,#80H movx @dptr,a ; reset all fifos - mov a,#00h + mov a,#2 + movx @dptr,a ; + mov a,#4 + movx @dptr,a ; + mov a,#6 + movx @dptr,a ; + mov a,#8 + movx @dptr,a ; + mov a,#0 movx @dptr,a ; normal operat mov DPTR,#EP2CFG @@ -363,7 +344,7 @@ initeps: movx @dptr,a mov dptr,#EP2BCL ; "arm" it - mov a,#80h + mov a,#00h movx @DPTR,a ; can receive data lcall syncdelay ; wait to sync movx @DPTR,a ; can receive data @@ -380,7 +361,7 @@ initeps: movx @dptr,a mov dptr,#EP4BCL ; "arm" it - mov a,#80h + mov a,#00h movx @DPTR,a ; can receive data lcall syncdelay ; wait until we can write again movx @dptr,a ; make shure its really empty @@ -410,11 +391,103 @@ initeps: mov EIE,#00000001b ; enable INT2 in the 8051's SFR mov IE,#80h ; IE, enable all interrupts - lcall ep8_arm ; - ret +;;; counter +;;; r0: DIOSTAT +;;; r1: counter address +;;; r2: up/down-mask +;;; r3: reset-mask +;;; r4: clock-mask +counter: + mov a,IOB ; actual IOB input state + mov r5,a ; save in r5 + anl a,r3 ; bit mask for reset + jz no_reset ; reset if one + clr a ; set counter to zero + mov @r1,a + inc r4 + mov @r1,a + sjmp ctr_end +no_reset: + mov a,@r0 ; get last state + xrl a,r5 ; has it changed? + anl a,r5 ; is it now on? + anl a,r4 ; mask out the port + jz ctr_end ; no rising edge + mov a,r5 ; get port B again + anl a,r2 ; test if up or down + jnz ctr_up ; count up + mov a,@r1 + dec a + mov @r1,a + cjne a,#0ffh,ctr_end ; underflow? + inc r1 ; high byte + mov a,@r1 + dec a + mov @r1,a + sjmp ctr_end +ctr_up: ; count up + mov a,@r1 + inc a + mov @r1,a + jnz ctr_end + inc r1 ; high byte + mov a,@r1 + inc a + mov @r1,a +ctr_end: + mov a,r5 + mov @r0,a + ret + +;;; implements two soft counters with up/down and reset +timer0_isr: + push dps + push acc + push psw + push 00h ; R0 + push 01h ; R1 + push 02h ; R2 + push 03h ; R3 + push 04h ; R4 + push 05h ; R5 + + mov r0,#DIOSTAT0 ; status of port + mov r1,#CTR0 ; address of counter0 + mov a,#00000001b ; bit 0 + mov r4,a ; clock + rl a ; bit 1 + mov r2,a ; up/down + rl a ; bit 2 + mov r3,a ; reset mask + lcall counter + inc r0 ; to DISTAT1 + inc r1 ; to CTR1 + inc r1 + mov a,r3 + rl a ; bit 3 + rl a ; bit 4 + mov r4,a ; clock + rl a ; bit 5 + mov r2,a ; up/down + rl a ; bit 6 + mov r3,a ; reset + lcall counter + + pop 05h ; R5 + pop 04h ; R4 + pop 03h ; R3 + pop 02h ; R2 + pop 01h ; R1 + pop 00h ; R0 + pop psw + pop acc + pop dps + + reti + ;;; interrupt-routine for SOF ;;; is for full speed sof_isr: @@ -438,17 +511,15 @@ sof_isr: anl a,#20H ; full? jnz epfull ; EP6-buffer is full - lcall convlo ; conversion + lcall conv_ad ; conversion mov DPTR,#EP6BCH ; byte count H mov a,#0 ; is zero - movx @DPTR,a - lcall syncdelay ; wait until we can write again + lcall syncdelaywr ; wait until we can write again mov DPTR,#EP6BCL ; byte count L mov a,#10H ; is 8x word = 16 bytes - movx @DPTR,a - lcall syncdelay ; wait until we can write again + lcall syncdelaywr ; wait until we can write again epfull: ;; do the D/A conversion @@ -460,11 +531,9 @@ epfull: lcall dalo ; conversion mov dptr,#EP2BCL ; "arm" it - mov a,#80h - movx @DPTR,a ; can receive data - lcall syncdelay ; wait for the rec to sync - movx @dptr,a ; just to make sure that it's empty - lcall syncdelay ; wait for the rec to sync + mov a,#00h + lcall syncdelaywr ; wait for the rec to sync + lcall syncdelaywr ; wait for the rec to sync epempty: ;; clear INT2 @@ -495,9 +564,34 @@ nosof: reti +reset_ep8: + ;; erase all data in ep8 + mov dptr,#FIFORESET + mov a,#80H ; NAK + lcall syncdelaywr + mov dptr,#FIFORESET + mov a,#8 ; reset EP8 + lcall syncdelaywr + mov dptr,#FIFORESET + mov a,#0 ; normal operation + lcall syncdelaywr + ret +reset_ep6: + ;; throw out old data + mov dptr,#FIFORESET + mov a,#80H ; NAK + lcall syncdelaywr + mov dptr,#FIFORESET + mov a,#6 ; reset EP6 + lcall syncdelaywr + mov dptr,#FIFORESET + mov a,#0 ; normal operation + lcall syncdelaywr + ret + ;;; interrupt-routine for ep4 ;;; receives the channel list and other commands ep4_isr: @@ -519,25 +613,74 @@ ep4_isr: mov dptr,#0f400h ; FIFO buffer of EP4 movx a,@dptr ; get the first byte + mov r0,#CMD_FLAG ; pointer to the command byte + mov @r0,a ; store the command byte for ep8 mov dptr,#ep4_jmp ; jump table for the different functions rl a ; multiply by 2: sizeof sjmp jmp @a+dptr ; jump to the jump table + ;; jump table, corresponds to the command bytes defined + ;; in usbdux.c ep4_jmp: sjmp storechannellist; a=0 sjmp single_da ; a=1 sjmp config_digital_b; a=2 sjmp write_digital_b ; a=3 + sjmp storesglchannel ; a=4 + sjmp readcounter ; a=5 + sjmp writecounter ; a=6 + ;; read the counter +readcounter: + lcall reset_ep8 ; reset ep8 + lcall ep8_ops ; fill the counter data in there + sjmp over_da ; jump to the end -;;; Channellist: + ;; write zeroes to the counters +writecounter: + mov dptr,#0f401h ; buffer + mov r0,#CTR0 ; r0 points to counter 0 + movx a,@dptr ; channel number + jz wrctr0 ; first channel + mov r1,a ; counter +wrctrl: + inc r0 ; next counter + inc r0 ; next counter + djnz r1,wrctrl ; advance to the right counter +wrctr0: + inc dptr ; get to the value + movx a,@dptr ; get value + mov @r0,a ; save in ctr + inc r0 ; next byte + inc dptr + movx a,@dptr ; get value + mov @r0,a ; save in ctr + sjmp over_da ; jump to the end + +storesglchannel: + mov r0,#SGLCHANNEL ; the conversion bytes are now stored in 80h + mov dptr,#0f401h ; FIFO buffer of EP4 + movx a,@dptr ; + mov @r0,a + + lcall reset_ep8 ; reset FIFO + ;; Save new A/D data in EP8. This is the first byte + ;; the host will read during an INSN. If there are + ;; more to come they will be handled by the ISR of + ;; ep8. + lcall ep8_ops ; get A/D data + + sjmp over_da + + +;;; Channellist: ;;; the first byte is zero: ;;; we've just received the channel list -;;; the channel list is stored in the addresses from 80H which +;;; the channel list is stored in the addresses from CHANNELLIST which ;;; are _only_ reachable by indirect addressing storechannellist: mov r0,#CHANNELLIST ; the conversion bytes are now stored in 80h - mov r2,#8 ; counter + mov r2,#9 ; counter mov dptr,#0f401h ; FIFO buffer of EP4 chanlloop: movx a,@dptr ; @@ -545,9 +688,15 @@ chanlloop: inc dptr inc r0 djnz r2,chanlloop - clr a ; announce analogue transaction - mov r0,#DIOFLAG ; pointer to the command byte - mov @r0,a ; set the command byte + + lcall reset_ep6 ; reset FIFO + + ;; load new A/D data into EP6 + ;; This must be done. Otherwise the ISR is never called. + ;; The ISR is only called when data has _left_ the + ;; ep buffer here it has to be refilled. + lcall ep6_arm ; fill with the first data byte + sjmp over_da ;;; Single DA conversion. The 2 bytes are in the FIFO buffer @@ -556,7 +705,7 @@ single_da: lcall dalo ; conversion sjmp over_da -;;; configure the port B +;;; configure the port B as input or output (bitwise) config_digital_b: mov dptr,#0f401h ; FIFO buffer of EP4 movx a,@dptr ; get the second byte @@ -572,22 +721,25 @@ write_digital_b: inc dptr ; next byte movx a,@dptr ; bits mov IOB,a ; send the byte to the I/O port - mov a,#0ffh ; announce DIO transaction - mov r0,#DIOFLAG ; pointer to the command byte - mov @r0,a ; set the command byte - sjmp over_da -;;; more things here to come... - + lcall reset_ep8 ; reset FIFO of ep 8 + + ;; fill ep8 with new data from port B + ;; When the host requests the data it's already there. + ;; This must be so. Otherwise the ISR is not called. + ;; The ISR is only called when a packet has been delivered + ;; to the host. Thus, we need a packet here in the + ;; first instance. + lcall ep8_ops ; get digital data + + ;; + ;; for all commands the same over_da: mov dptr,#EP4BCL - mov a,#80h - movx @DPTR,a ; arm it - lcall syncdelay ; wait - movx @DPTR,a ; arm it - lcall syncdelay ; wait - movx @DPTR,a ; arm it - lcall syncdelay ; wait + mov a,#00h + lcall syncdelaywr ; arm + lcall syncdelaywr ; arm + lcall syncdelaywr ; arm ;; clear INT2 mov a,EXIF ; FIRST clear the USB (INT2) interrupt request @@ -678,29 +830,57 @@ noDA: ret ;;; arm ep6 ep6_arm: - lcall convlo + lcall conv_ad mov DPTR,#EP6BCH ; byte count H mov a,#0 ; is zero - movx @DPTR,a - lcall syncdelay ; wait until the length has arrived + lcall syncdelaywr ; wait until the length has arrived mov DPTR,#EP6BCL ; byte count L mov a,#10H ; is one - movx @DPTR,a - lcall syncdelay ; wait until the length has been proc + lcall syncdelaywr ; wait until the length has been proc ret ;;; converts one analog/digital channel and stores it in EP8 -;;; also gets the content of the digital ports B and D -ep8_adc: - mov r0,#DIOFLAG ; pointer to the DIO flag - mov a,@r0 ; get the flag - jnz ep8_dio ; nonzero means DIO +;;; also gets the content of the digital ports B and D depending on +;;; the COMMAND flag +ep8_ops: + mov r0,#CMD_FLAG + mov a,@r0 - mov r0,#CHANNELLIST ; points to the channellist + mov dptr,#ep8_jmp ; jump table for the different functions + rl a ; multiply by 2: sizeof sjmp + jmp @a+dptr ; jump to the jump table + ;; jump table, corresponds to the command bytes defined + ;; in usbdux.c +ep8_jmp: + sjmp ep8_err ; a=0, err + sjmp ep8_err ; a=1, err + sjmp ep8_err ; a=2, err + sjmp ep8_dio ; a=3, digital read + sjmp ep8_sglchannel ; a=4, analog A/D + sjmp ep8_readctr ; a=5, read counter + sjmp ep8_err ; a=6, write counter + + ;; reads all counters +ep8_readctr: + mov r0,#CTR0 ; points to counter0 + mov dptr,#0fc00h ; ep8 fifo buffer + mov r1,#8 ; transfer 4 16bit counters +ep8_ctrlp: + mov a,@r0 ; get the counter + movx @dptr,a ; save in the fifo buffer + inc r0 ; inc pointer to the counters + inc dptr ; inc pointer to the fifo buffer + djnz r1,ep8_ctrlp ; loop until ready + + sjmp ep8_send ; send the data + + ;; read one A/D channel +ep8_sglchannel: + mov r0,#SGLCHANNEL ; points to the channel mov a,@r0 ; Ch0 lcall readAD ; start the conversion @@ -714,6 +894,7 @@ ep8_adc: sjmp ep8_send ; send the data + ;; read the digital lines ep8_dio: mov DPTR,#0fc00h ; store the contents of port B mov a,IOB ; in the next @@ -726,29 +907,16 @@ ep8_dio: ep8_send: mov DPTR,#EP8BCH ; byte count H mov a,#0 ; is zero - movx @DPTR,a + lcall syncdelaywr mov DPTR,#EP8BCL ; byte count L mov a,#10H ; 16 bytes - movx @DPTR,a ; send the data over to the host + lcall syncdelaywr ; send the data over to the host + +ep8_err: ret - -;;; arms EP8 with one byte. This signals the Linux driver that -;;; the EP has been armed only with a dummy byte to make the -;;; IRQ work. The byte is not processed by the driver. -ep8_arm: - mov DPTR,#EP8BCH ; byte count H - mov a,#0 ; is zero - movx @DPTR,a - - mov DPTR,#EP8BCL ; byte count L - mov a,#1 ; 1 byte - movx @DPTR,a - ret - - ;;; EP8 interrupt: gets one measurement from the AD converter and ;;; sends it via EP8. The channel # is stored in address 80H. @@ -770,7 +938,7 @@ ep8_isr: push 06h ; R6 push 07h ; R7 - lcall ep8_adc + lcall ep8_ops ;; clear INT2 mov a,EXIF ; FIRST clear the USB (INT2) interrupt request @@ -807,6 +975,16 @@ syncdelay: nop nop nop + nop + nop + nop + nop + nop + ret + +syncdelaywr: + movx @dptr,a + lcall syncdelay ret diff --git a/etc/hotplug/usb/usbdux/usbdux_firmware.hex b/etc/hotplug/usb/usbdux/usbdux_firmware.hex index bb3da3e..366bff4 100644 --- a/etc/hotplug/usb/usbdux/usbdux_firmware.hex +++ b/etc/hotplug/usb/usbdux/usbdux_firmware.hex @@ -1,66 +1,80 @@ :030000000201A258 +:03000B000202F8F6 :03004300020100B7 -:1001000002017F000202EF0002017F0002017F0076 +:1001000002017F000203390002017F0002017F002B :1001100002017F0002017F0002017F0002017F00D7 :1001200002017F0002017F0002017F0002017F00C7 -:1001300002017F0002036C0002017F0002049900AB +:1001300002017F000203E40002017F0002055A0071 :1001400002017F0002017F0002017F0002017F00A7 :1001500002017F0002017F0002017F0002017F0097 :1001600002017F0002017F0002017F0002017F0087 :1001700002017F0002017F0002017F0002017FC0B7 :1001800086C082C083C084C085C0E0C0D0E591C273 :10019000E4F591D0D0D0E0D085D084D083D082D087 -:1001A000863290E6007410F01204E590E668740858 -:1001B000F01204E51201C3120288000000000000E2 -:1001C0000080F775B22775802222547C4481C28159 -:1001D0007A0830E704D2828002C282D280C28023B1 -:1001E000DAF0C2827A05D280C280DAFA7C007A0420 -:1001F0007D08D280C280E58030E403EC4DFCED0345 -:10020000FDDAEF7B007A087D80D280C280E5803005 -:10021000E403EB4DFBED03FDDAEFD28122759AF892 -:10022000759B0075AF077880E61201CAEB90E67BFC -:10023000F0ECF008E61201CAEB90E67BF0ECF00877 -:10024000E61201CAEB90E67BF0ECF008E61201CA78 -:10025000EB90E67BF0ECF008E61201CAEB90E67B4F -:10026000F0ECF008E61201CAEB90E67BF0ECF00847 -:10027000E61201CAEB90E67BF0ECF008E61201CA48 -:10028000EB90E67BF0ECF02290E604740FF0740043 -:10029000F090E6127492F090E6187400F090E691F7 -:1002A0007480F01204E5F01204E5F01204E590E623 -:1002B0001374A0F090E6197400F090E6957480F045 -:1002C0001204E5F01204E590E61474D2F090E615FD -:1002D00074E0F090E65E74A0F090E65F74A0F09099 -:1002E000E65C7402F075E80175A88012048C22C0E7 -:1002F00086C082C083C084C085C0E0C0D0C000C0BA -:1003000001C002C003C004C005C006C007E5AA546E -:1003100020701512021D90E6987400F01204E5900A -:10032000E6997410F01204E5E5AA5401701390F0F8 -:100330000012040B90E6917480F01204E5F01204B0 -:10034000E5E591C2E4F59190E65D7402F0D007D046 -:1003500006D005D004D003D002D001D000D0D0D038 -:10036000E0D085D084D083D082D08632C086C0824F -:10037000C083C084C085C0E0C0D0C000C001C0023E -:10038000C003C004C005C006C00790F400E090039D -:1003900093237380068017801D802378807A0890CD -:1003A000F401E0F6A308DAFAE47890F6802190F4FC -:1003B0000112040B801990F401E0F5B3801190F460 -:1003C00001E0F5B3A3E0F59074FF7890F68000901B -:1003D000E6957480F01204E5F01204E5F01204E5ED -:1003E000E591C2E4F59190E65F7420F0D007D00665 -:1003F000D005D004D003D002D001D000D0D0D0E0BE -:10040000D085D084D083D082D08632E0A3F8E0FBC0 -:10041000A3E0FCA3E0A312041CD8F32254C0443090 -:100420004CC2857A0830E704D2828002C282D28030 -:10043000C28023DAF0EB7A0830E704D2828002C26D -:1004400082D280C28023DAF0D2852212021D90E689 -:10045000987400F01204E590E6997410F01204E527 -:10046000227890E670107880E61201CA90FC00EBCA -:10047000F0A3ECF0800990FC00E590F0A3E4F0908C -:10048000E69C7400F090E69D7410F02290E69C7457 -:1004900000F090E69D7401F022C086C082C083C047 -:1004A00084C085C0E0C0D0C000C001C002C003C08D -:1004B00004C005C006C007120461E591C2E4F591CD -:1004C00090E65F7480F0D007D006D005D004D0034A -:1004D000D002D001D000D0D0D0E0D085D084D0835D -:0A04E000D082D08632000000002216 +:1001A000863290E60074101205B090E60B740312CC +:1001B00005B075B80075F8FF90E66874081205B0D0 +:1001C0001201D212025A1201D900000000000000F0 +:1001D00080F775B22775802222758E01758A107599 +:1001E0008C0075A882758900D28C22547C4481C20F +:1001F000817A0830E704D2828002C282D280C28033 +:1002000023DAF0C2827A05D280C280DAFA7C007AE0 +:10021000047D08D280C280E58030E403EC4DFCED23 +:1002200003FDDAEF7B007A087D80D280C280E58012 +:1002300030E403EB4DFBED03FDDAEFD28122759A3A +:10024000F8759B0075AF077880E6F990E67B08E6C5 +:100250001201EBEBF0ECF0D9F52290E6047480F09B +:100260007402F07404F07406F07408F07400F090F6 +:10027000E6127492F090E6187400F090E691740023 +:10028000F01205A6F01205A6F01205A690E613746A +:10029000A0F090E6197400F090E6957400F0120555 +:1002A000A6F01205A690E61474D2F090E61574E05C +:1002B000F090E65E74A0F090E65F74A0F090E65CCB +:1002C0007402F075E80175A88022E590FD5B600678 +:1002D000E4F70CF7801FE66D5D5C6019ED5A700C59 +:1002E000E714F7B4FF0F09E714F78009E704F77084 +:1002F0000409E704F7EDF622C086C0E0C0D0C000D4 +:10030000C001C002C003C004C005789879A0740180 +:10031000FC23FA23FB1202CA080909EB2323FC235E +:10032000FA23FB1202CAD005D004D003D002D001B8 +:10033000D000D0D0D0E0D08632C086C082C083C08A +:1003400084C085C0E0C0D0C000C001C002C003C0EE +:1003500004C005C006C007E5AA5420701312023E6F +:1003600090E69874001205B090E69974101205B0EA +:10037000E5AA5401701190F0001204B790E6917450 +:10038000001205B01205B0E591C2E4F59190E65D6A +:100390007402F0D007D006D005D004D003D002D02C +:1003A00001D000D0D0D0E0D085D084D083D082D00E +:1003B000863290E60474801205B090E60474081248 +:1003C00005B090E60474001205B02290E604748033 +:1003D0001205B090E60474061205B090E6047400AD +:1003E0001205B022C086C082C083C084C085C0E030 +:1003F000C0D0C000C001C002C003C004C005C00618 +:10040000C00790F400E07890F690040E23738039D2 +:10041000804C805280588022800280081203B212E1 +:10042000050B805A90F40178A0E06005F90808D91E +:10043000FCA3E0F608A3E0F68044789190F401E094 +:10044000F61203B212050B803578807A0990F40118 +:10045000E0F6A308DAFA1203CB1204F7802090F436 +:10046000011204B7801890F401E0F5B3801090F405 +:1004700001E0F5B3A3E0F5901203B212050B90E68C +:100480009574001205B01205B01205B0E591C2E4F2 +:10049000F59190E65F7420F0D007D006D005D00427 +:1004A000D003D002D001D000D0D0D0E0D085D0840D +:1004B000D083D082D08632E0A3F8E0FBA3E0FCA397 +:1004C000E0A31204C8D8F32254C044304CC2857A49 +:1004D0000830E704D2828002C282D280C28023DA4E +:1004E000F0EB7A0830E704D2828002C282D280C266 +:1004F0008023DAF0D2852212023E90E69874001230 +:1005000005B090E69974101205B0227890E6900537 +:1005100013237380448042804080258013800280B2 +:100520003878A090FC007908E6F008A3D9FA801981 +:100530007891E61201EB90FC00EBF0A3ECF080095F +:1005400090FC00E590F0A3E4F090E69C74001205A6 +:10055000B090E69D74101205B022C086C082C083A0 +:10056000C084C085C0E0C0D0C000C001C002C003CC +:10057000C004C005C006C00712050BE591C2E4F532 +:100580009190E65F7480F0D007D006D005D004D0FB +:1005900003D002D001D000D0D0D0E0D085D084D01C +:1005A00083D082D0863200000000000000000022CC +:0505B000F01205A62277 :00000001FF