Source file: /~heha/ewa/Ofen/rauch.zip/webusb~.i15

;******************
;* HID und WebUSB *
;******************
;Auch wenn sich das Datenblatt darüber auslässt, dass sich die
;„Buffer Descriptor Table“ ab der linearen Adresse 0x2000 befindet,
;befindet sie sich genauso im Bank 0 und belegt diese zwangsweise:
;Wenn man USB benutzt, dann geht effektiv die Bank 0 dafür drauf.

;So passt alles in Bank 0:
E0_SSH 		equ	4	; endpoint 0 buffer size = 16
E1I_SSH		equ	4	; endpoint 1 IN (HID Interrupt) buffer size = 16
E2I_SSH		equ	4	; endpoint 1 IN (WebUSB data) buffer size = 16

;Exy_STA bits (in Bank 0)
BSTALL		equ	2
DTSEN		equ	3
DTS		equ	6
UOWN		equ	7

;list of Bank0 RAM variables, starting with BDT
	cblock 0x20	;Bank 0 (geradeso voll)
E0O_STA
E0O_CNT
E0O_ADR:2
E0I_STA
E0I_CNT
E0I_ADR:2
E1O_STA		;unused
E1O_CNT		;unused
E1O_ADR:2	;unused
E1I_STA
E1I_CNT
E1I_ADR:2
E2O_STA		;unused
E2O_CNT		;unused
E2O_ADR:2	;unused
E2I_STA
E2I_CNT
E2I_ADR:2
; Normalerweise sind die Variablen E1O_xxx und E2O_xxx frei.
; Aber vielleicht will ja jemand später noch OUT-Endpoints dazufummeln.
USB_STATE	; some flags, see below
SETUPDAT_CNT	; remaining bytes to be sent
SETUPDAT_PTR:2	; pointer to descriptor to be sent
free:4

E0_BUF:1<<E0_SSH	; At address 0x40, length 0x10, shared buffer for EP0 Setup, Out, and In transfer
E1I_BUF:1<<E1I_SSH	; At address 0x50, length 0x10, HID interrupt data
E12_BUF:1<<E1I_SSH	; At address 0x60, length 0x10, WebUSB interrupt data
;Dadurch passt alles in die Bank 0, und die HID- und Interruptdaten können in einem Stück gesendet werden!
	endc
bmRequestType	equ	E0_BUF+0
bRequest	equ	E0_BUF+1
wValueL		equ	E0_BUF+2
wValueH		equ	E0_BUF+3
wIndexL		equ	E0_BUF+4
wIndexH		equ	E0_BUF+5
wLengthL	equ	E0_BUF+6
wLengthH	equ	E0_BUF+7
LIN_E0_BUF	equ	E0_BUF+0x1FE0	;0x2020 .. 0x202F
LIN_E1I_BUF	equ	E1I_BUF+0x1FE0	;0x2030 .. 0x203F
LIN_E2I_BUF	equ	E1I_BUF+0x1FE0	;0x2040 .. 0x204F

; USB_STATE bit flags
IS_CONTROL_READ	equ	7	; current EP0 transaction is a control read
CONFIGURED	equ	0	; the device is configured

usbPoll
	banksel	UIR		; Bank 29
	btfsc	UIR,URSTIF	; reset?
	 goto	usbReset	; if so, reset the USB interface
; service transactions
	btfss	UIR,TRNIF
	 return
	movfwf	USTAT,FSR1H	; store the status (endpoint number + direction)
	bcf	UIR,TRNIF	; clear flag and advance USTAT fifo
	banksel	E0O_STA		; Bank 0
	andlw	0x78		; endpoint number !=0 ?
	skpnz
	 return
; Handles a control transfer on endpoint 0.
; args:		BSR=0, FSR1H=USTAT
; clobbers:	W, FSR1H
	btfsc	FSR1H,DIR	; is it an IN transfer or an OUT/SETUP?
	 bra	_usb_ctrl_in
; it's an OUT or SETUP transfer
	movfw	E0O_STA		; All non-PID bits are zero here because SETUP comes with DATA0
	xorlw	13<<2		; 13=PID_SETUP — is it a SETUP packet?
	brnz	e0o_next	; if not, it's a DATA or STATUS OUT, ignore data and rearm buffer
;=============================
;= EP0 SETUP packet received =
;=============================
; Handles a SETUP control transfer on endpoint 0.
; BSR=0
	clrf	E0O_STA		; let start with DATA1
	clrf	E0I_STA		; let start with DATA1
	clrf	SETUPDAT_CNT	; No data phase as standard
	bcf	USB_STATE,IS_CONTROL_READ
; get bmRequestType, but don't bother checking whether it's standard/class/vendor...
; the CDC and standard requests we'll receive have distinct bRequest numbers
	movfw	bmRequestType
	bz	_bm00
	xorlw	0x01^0x00
	bz	_bm01
	xorlw	0x21^0x01
	bz	_bm21
	bsf	USB_STATE,IS_CONTROL_READ	; now it is device->host
	xorlw	0x80^0x21
	bz	_bm80
	xorlw	0x81^0x80
	bz	_bm81
	xorlw	0xA1^0x81
	bz	_bmA1
	xorlw	0xC0^0xA1
	bz	_bmC0
	goto	_setup_stall
	
	assume	0

_bm00	;OUT, STD, DEVICE
	movfw	bRequest
	xorlw	0x01^0x00
	bz	_setup_ok
	xorlw	0x03^0x01
	bz	_setup_ok
	xorlw	0x05^0x03
	bz	_setup_ok
	xorlw	0x09^0x05	; set_configuration
	bnz	_setup_stall
	movfw	wValueL		; darf nur 0 oder 1 sein
	addlw	-2
	bc	_setup_stall
	movfwf	wValueL,USB_STATE
;TODO: Endpoints hier konfigurieren oder totlegen
	movlw	1<<DTSEN	; expect DATA0 first
	call	arm_e1o_w
	movlwf	1<<DTS|1<<DTSEN,E1I_STA		; USB NAK and toggle bit set: Send first packet as DATA0
	movwf	E2I_STA
	goto	_setup_ok

_bm01	;OUT, STD, IFACE[wIndexL]
	movfw	bRequest
	xorlw	0x11		; Set Interface (ignorieren)
	bz	_setup_ok
	goto	_setup_stall

_bm21	;OUT, CLASS, IFACE[wIndexL]
	movfw	bRequest
	xorlw	9		; Set Report
	bnz	_setup_stall
	movfw	wValueL		; Report-ID
	goto	onEp0SetReport
	
_bm80	;IN, STD, DEVICE
	movfw	bRequest
	bz	_setup_zero2
	xorlw	6		; Get Descriptor?
	bz	_setup_getdesc
	xorlw	8^6		; Get Configuration?
	bnz	_setup_stall
	movlwf2	ROM01,FSR0
	btfsc	USB_STATE,0
	 addfsr	FSR0,1
	movlw	1
	goto	_setup_answer_w

_bm81	;IN, STD, IFACE[wIndexL]
	movfw	bRequest
	bz	_setup_zero2
	xorlw	6		; Get Descriptor?
	bz	_setup_gethidrepdesc
	xorlw	10^6		; Get AltSetting
	bnz	_setup_stall
	movlwf2	ROM00,FSR0
	movlw	1
	goto	_setup_answer_w	;1 Nullbyte als Antwort

_bmA1	;IN, CLASS, IFACE[wIndexL]
	movfw	bRequest
	xorlw	1
	bnz	_setup_stall
	movfw	wValueL
	goto	onEp0GetReport

_bmC0	;IN, VENDOR, DEVICE
	movfw	bRequest
	xorlw	1
	bz	_setup_getos20desc
	xorlw	2^1
	bnz	_setup_stall
	movlwf2	LandingPageDesc,FSR0
	goto	_setup_answer

_setup_getos20desc
	movlwf2	MsOs20Desc,FSR0
	movlw	MsOs20DescEnd-MsOs20Desc
	goto	_setup_answer_w

_setup_zero2
	movlwf2	ROM00,FSR0
	movlw	2
	goto	_setup_answer_w
	
_setup_gethidrepdesc
	movfw	wValueH
	xorlw	0x22		; HID?
	bnz	_setup_stall
	movlwf2	HidRepDesc,FSR0
	movlw	HidRepDescEnd-HidRepDesc
	goto	_setup_answer_w

_setup_getdesc	; „Get Descriptor“ behandeln: Davon gibt es viele!
	decfsz	wValueH,w		;1 = DeviceDesc
	 goto	_no_devicedesc
	movlwf2	DeviceDesc,FSR0	;Zeiger laden
	goto	_setup_answer
_no_devicedesc
	decfsz	WREG,w			;2 = ConfigDesc
	 goto	_no_configdesc
	movlwf2	ConfigDesc,FSR0
	movlw	ConfigDescEnd-ConfigDesc	; length includes all subordinate descriptors
	goto	_setup_answer_w
_no_configdesc
	decfsz	WREG,w			;3 = StringDesc
	 goto	_no_stringdesc
	movlwf2	StringDesc,FSR0
	movfw	wValueL
	bz	_lsf
	addlw	-5
	bc	_setup_stall
_lsd
	movfw	INDF0		; Längenbyte nach W
	addwf	FSR0L,f
	skpnc
	 incf	FSR0H,f
	loop	wValueL,_lsd
_lsf	goto	_setup_answer
_no_stringdesc
	xorlw	15-3
	bnz	_setup_stall
	movlwf2	BosDesc,FSR0
	movlw	BosDescEnd-BosDesc
	goto	_setup_answer_w
	 

;Daten von FSR0 abschicken, Länge = erstes Byte des Deskriptors
_setup_answer
	movfw	INDF0
;Daten von FSR0 abschicken, Länge = w (stets <= 255)
_setup_answer_w
	movwf	SETUPDAT_CNT
; If requested length is shorter, transfer less than descriptor size
	tstf	wLengthH
	brnz	_setup_complete	; more than 255 bytes requested (Windows 7: 0x109)
	subwf	wLengthL,w
	brc	_setup_complete	; if W <= f, no need to adjust
	movfw	wLengthL
	movwf	SETUPDAT_CNT
_setup_complete
	movfwf2	FSR0,SETUPDAT_PTR
; Finishes a successful SETUP transaction.
; SETUPDAT_CNT contains transfer length.
_setup_ok
	banksel	UCON
	bcf	UCON,PKTDIS		; reenable packet processing
	banksel	USB_STATE	; Bank 0
	btfss	bmRequestType,7
	 bra	_cwrite
; this is a control read; prepare the IN endpoint for the data stage
; and the OUT endpoint for the status stage
	call	ep0_send_in		; read data into IN buffer
	movlw	1<<DTS|1<<DTSEN		; make OUT buffer ready for status stage
; value in W is used to specify the EP0 OUT flags
_armbfs	movwf	E0O_STA
	movlwf	1<<E0_SSH,E0O_CNT	; reset the buffer count
	bsf	E0O_STA,UOWN	; arm the OUT endpoint

; Send next packet to Endpoint 0 In, size already set to E0I_CNT
e0i_next
	comf	E0I_STA,w	; toggle DTS
	andlw	1<<DTS
	iorlw	1<<DTSEN
	movwf	E0I_STA
	bsf	E0I_STA,UOWN
	return
; this is a control write: prepare the IN endpoint for the status stage
; and the OUT endpoint for the next SETUP transaction
_cwrite	bcf	E0I_STA,UOWN	; ensure we have ownership of the buffer
	clrf	E0I_CNT	; we'll be sending a zero-length packet
	movlw	1<<DTSEN|1<<BSTALL	; make OUT buffer ready for next SETUP packet
	bra	_armbfs			; arm OUT and IN buffers

; Finishes a rejected SETUP transaction: the endpoints are stalled
_setup_stall
	banksel	UCON
	bcf	UCON,PKTDIS	; reenable packet processing
	banksel	E0I_STA
	movlw	1<<DTSEN|1<<BSTALL
	movwf	E0I_STA
	bsf	E0I_STA,UOWN
e0o_stall	;for next SETUP
	movlw	1<<DTSEN|1<<BSTALL
	bra	e0o_arm
; Prepare reception of next Endpoint 0 Out Data (or Setup) packet
e0o_next
	comf	E0O_STA,w	; toggle DTS
	andlw	1<<DTS
	iorlw	1<<DTSEN
e0o_arm			; W specifies STAT flags
	movwf	E0O_STA
	movlwf	1<<E0_SSH,E0O_CNT	; reset the buffer count
	bsf	E0O_STA,UOWN	; arm the OUT endpoint
	return

; Handles an IN control transfer on endpoint 0.
; Can be (descriptor) data or an acknowledge packet
; BSR=0
_usb_ctrl_in
	btfss	USB_STATE,IS_CONTROL_READ	; is this a control read or write?
	 bra	_check_for_pending_address
; fetch more data and re-arm the IN endpoint
	call	ep0_send_in
	bra	e0i_next	; arm the IN buffer
	
; if this is the status stage of a Set Address request, assign the address here.
; The OUT buffer has already been armed for the next SETUP.
_check_for_pending_address
	movfw	bRequest
	xorlw	5
	skpz
	 return
; read the address out of the setup packed in the OUT buffer
	movfw	wValueL
	banksel	UADDR
	movwf	UADDR
	return

; Handle possibly multiple-chunk EP0 IN transfer:
; Reads data from SETUPDAT_PTR, copies it to the EP0 IN buffer,
; and decrements SETUPDAT_CNT.
; Cannot simply point EP0_ADDR to flash as it is not accessible by USB SIE
; args:		BSR=0
; returns:	SETUPDAT_PTR advanced
;		SETUPDAT_CNT decremented
; clobbers:	W, FSR0, FSR1
ep0_send_in
	clrf	E0I_CNT	; initialize transfer length to 0
	tstf	SETUPDAT_CNT	; do nothing if there are 0 bytes to send
	skpnz
	 return
	movfwf	SETUPDAT_PTR,FSR0	; set up source pointer
	movfwf	SETUPDAT_PTR+1,FSR0+1
	movlwf	E0_BUF,FSR1L	; Here: Banked address (not a problem), set up destination pointer
	clrf	FSR1H		; Bank 0
; byte copy loop, from FSR0 to FSR1 length SETUPDAT_CNT but max. 16 bytes
_bcopy	btfsc	E0I_CNT,E0_SSH	; 16 Bytes full?
	 bra	_bcdone
	moviw	FSR0++
	movwi	FSR1++
	incf	E0I_CNT,f	; increase number of bytes copied
	decfsz	SETUPDAT_CNT,f	; decrement number of bytes remaining
	 bra	_bcopy
; write back the updated source pointer
_bcdone	movfwf	FSR0,SETUPDAT_PTR
	movfwf	FSR0+1,SETUPDAT_PTR+1
	return

;Send data chunk to host.
;args:	W=Bytes (0..64)
;	EP1IN buffer filled with data
;clobbers: W,bank=0
usbTx	banksel	0
_u1	btfsc	E1I_STA,UOWN	; spinloop until previous buffer is read by USB host
	 bra	_u1		; (Bug: May hang if USB connection is somehow lost in between)
	movwf	E1I_CNT		; put transfer size
	comf	E1I_STA,w	; toggle DTS
	andlw	1<<DTS		; clear all other bits (STALL too)
	iorlw	1<<DTSEN	; 0↕001000 = use toggle bit
	movwf	E1I_STA
	bsf	E1I_STA,UOWN	; give to SIE
	return

arm_e1o_w
	;movwf	E1O_STA
	;movlwf	1<<E1O_SSH,E1O_CNT	; length = full size
	;bsf	E1O_STA,UOWN	; rearm OUT buffer
	retlw	1<<DTS|1<<DTSEN	; 01001000


usbInit
; Configure the oscillator (48MHz from INTOSC using 3x PLL)
	banksel	OSCCON		; bank 1
	movlwf	0xFC,OSCCON
; Wait for the oscillator and PLL to stabilize
_wosc	comf	OSCSTAT,w
	andlw	(1<<PLLRDY)|(1<<HFIOFR)|(1<<HFIOFS)
	brnz	_wosc
; Enable active clock tuning
	banksel	ACTCON		; Bank 7
	movlwf	(1<<ACTSRC)|(1<<ACTEN),ACTCON		; source = USB
; Initialize USB
	call	usbReset
; Attach to the bus (could be a subroutine, but inlining it saves 2 instructions)
	banksel	UCON		; Bank 29
	clrf	UCON		; reset UCON
	bsf	UCON,USBEN	; enable USB module and wait until ready
	return

; Initializes the USB system and resets all associated registers.
; clobbers:	W,BSR=0,FSR0,FSR1L
usbReset
; clear USB registers
	banksel	UIR		; Bank 29
	clrf	UIR
; set configuration
	movlwf	(1<<UPUEN)|(1<<FSEN),UCFG	; enable pullups, full speed, no ping-pong buffering
	;movlwf	(1<<TRNIE)|(1<<URSTIE),UIE	; TODO: Need interrupts for CPU wakeup later
; clear all BDT entries, variables, and buffers
	clrf	FSR0H
	movlwf	0x20,FSR0L	; BDT starts at 0x2000 aka 0x20, clear all Bank0 variables except RxBuf
	movwf	FSR1L		; use 0x20 as loop count
	clrw
_ramclr	movwi	FSR0++
	loop	FSR1L,_ramclr
; reset ping-pong buffers and address
	banksel	UCON		; Bank 29: All about USB
	bsf	UCON,PPBRST
	clrf	UADDR
	bcf	UCON,PKTDIS	; enable packet processing
	bcf	UCON,PPBRST	; clear ping-pong buffer reset flag
; flush pending transactions
_tflush	btfss	UIR,TRNIF
	 bra	_initep
	bcf	UIR,TRNIF
	nop
	nop
	nop
	nop			; need at least 6 cycles before checking TRNIF again
	bra	_tflush

; initialize endpoints:
; 0 for control
; 1 for HID interrupt
; 2 for WebUSB interrupt
_initep	movlwf	1<<EPHSHK|1<<EPOUTEN|1<<EPINEN,UEP0
	movlwf	1<<EPHSHK|1<<EPCONDIS|1<<EPINEN,UEP1
	movlwf	1<<EPHSHK|1<<EPCONDIS|1<<EPINEN,UEP2
; initialize endpoint buffers and counts
	banksel	E0O_ADR		; Bank 0
	movlwf	low LIN_E0_BUF, E0O_ADR	; set endpoint 0 address low
	movwf			E0I_ADR
	movlwf	low LIN_E1I_BUF,E1I_ADR	; set endpoint 1 IN address low
	movlwf	low LIN_E2I_BUF,E2I_ADR	; set endpoint 2 IN address low
	movlwf	high LIN_E0_BUF,E0O_ADR+1	; set all ADRH values to 0x20
	movwf			E0I_ADR+1
	movwf			E1I_ADR+1
	movwf			E2I_ADR+1
	goto	e0o_stall

; Descriptors 
dew macro x
	de	low(x),high(x)
 endm

; Es gibt folgende HID-Deskriptoren:
;Nr.1	Report-ID		8	(nur lesen: Interrupt)
;	Zustand Rauchmelder	1
;	Zustand Testalarm	1
;	A/D-Wert Gassensor	16
;	A/D-Wert Chiptemperatur	16
;	Wert vom Pyrosensor	16
;	Werte von DS18B20	4×16
;Nr.2	Report-ID		8	(schreiben/lesen: Feature)
;	Testalarm		1
;	Grenzwert Gassensor	16
;	Grenzwert Chiptemp.	16
;	Grenzwert Pyrosensor	16
;	Grenzwerte DS18B20	4×16
;Nr.3	Report-ID		8	(schreiben/lesen: Feature)
;	Cookies			15×8
;Nr.4	Report-ID		8	(schreiben/lesen: Feature)
;	Index DS18B20		2 (8)
;	ID der DS18B20		64 	(nur lesen)
; Die Größe ist auf 16 Bytes beschränkt.
; Die gleichen „Deskriptoren“ werden auch für WebUSB verwendet.
; Eine Umrechnung in °C muss das Anwendungsprogramm machen.
HidRepDesc
	de	0x06
	dew	65442		;G Usage Page: Unknown
	de	0x09,1		;L Usage: 1
	de	0xA1,1		;M Collection
	de	 0x75,8		;G  Report Size
	de	 0x95,15	;G  Report Count
	de	 0x15,0		;G  Logical Minimum
	de	 0x26,255,0	;G  Logical Maximum
;Nr.1
	de	 0x85,1		;M  Report ID (1)
	de	 0x09,1		;L  Usage: 1 (Byte-Array)
	de	 0x81,2		;M  Input: Variable
;Nr.2
	de	 0x85,2		;M  Report ID (2)
	de	 0x09,2		;L  Usage: 2 (Byte-Array)
	de	 0xB1,2		;M  Feature: Variable
;Nr.3
	de	 0x85,3		;M  Report ID (3)
	de	 0x09,3		;L  Usage: 3 (Byte-Array)
	de	 0xB1,2		;M  Feature: Variable
;Nr.4
	de	 0x85,4		;M  Report ID (3)
	de	 0x09,4		;L  Usage: 3 (Byte-Array)
	de	 0x95,9		;G  Report Count (hier nur 9 Bytes, Gesamtlänge 10)
	de	 0xB1,2		;M  Feature: Variable
	de	0xC0		;M End Collection
HidRepDescEnd

DeviceDesc
	de	18		; bLength
	de	1		; bDescriptorType
	dew	0x0210		; bcdUSB (USB 2.1)
	de	0		; bDeviceClass (see interface descriptor)
	de	0		; bDeviceSubclass
	de	0		; bDeviceProtocol
	de	1<<E0_SSH	; bMaxPacketSize0 (16 bytes)
	dew	0x16C0		; idVendor (Voti)
	dew	0x27D9		; idProduct (HID no keyboard/mouse/joystick)
	dew	0x0300		; bcdDevice
	de	1		; iVendor
	de	2		; iProduct
	de	3		; iSerialNo
	de	1		; bNumConfig

ConfigDesc
	de	9		; bLength
	de	2		; bDescriptorType
	dew	ConfigDescEnd-ConfigDesc	; wTotalLength
	de	2		; bNumInterfaces
	de	1		; bConfigValue
	de	0		; iConfig
	de	0x80		; bmAttributes	(BusPower)
	de	50		; bMaxPower	(100 mA)
;INTERFACE_DESCRIPTOR_0
	de	9		; bLength
	de	4		; bDescType	(IFACE)
ROM00
	de	0		; bInterfaceNumber
ROM01
	de	0		; bAlternateSetting
	de	1		; bNumEndpoints
	de	3		; bIClass	(HID)
	de	0		; bISubclass
	de	0		; bIProtocol
	de	4		; iIface
;HID descriptor
	de	9		; bLength
	de	0x21		; bDescType
	dew	0x0110		; bcdHID
	de	0		; bCountryCode
	de	1		; bNumDescriptors
	de	0x22		; bDescType	Report 
	dew	HidRepDescEnd-HidRepDesc; wDescriptorLength
;Endpoint
	de	7		; bLength
	de	5		; bDescriptorType (ENDPOINT)
	de	0x81		; bEndpointAddress (1 IN)
	de	0x03		; bmAttributes	(interrupt)
	dew	1<<E1I_SSH	; wMaxPacketSize (16)
	de	250		; bInterval	(250 ms)
;INTERFACE_DESCRIPTOR_1
	de	9		; bLength
	de	4		; bDescriptorType (IFACE)
	de	1		; bInterfaceNumber
	de	0		; bAlternateSetting
	de	1		; bNumEndpoints
	de	0xFF		; bIClass	(vendorspec)
	de	0		; bISubclass
	de	0		; bIProtocol
	de	5		; iIface
;ENDPOINT_DESCRIPTOR_1_IN
	de	7		; bLength
	de	5		; bDescriptorType (ENDPOINT)
	de	0x82		; bEndpointAddress (1 IN)
	de	0x03		; bmAttributes (interrupt)
	dew	1<<E2I_SSH	; wMaxPacketSize (64)
	de	250		; bInterval	(250 ms)
ConfigDescEnd

BosDesc
	de	5		; Length
	de	0x0F		; Binary Object Store descriptor
	dew	57		; Total length
	de	2		; Number of device capabilities
; WebUSB Platform Capability descriptor (bVendorCode == 0x01).
	de	0x18		; Length
	de	0x10		; Device Capability descriptor
	de	0x05		; Platform Capability descriptor
	de	0x00		; Reserved
	de	0x38,0xB6,0x08,0x34,0xA9,0x09,0xA0,0x47,0x8B,0xFD,0xA0,0x76,0x88,0x15,0xB6,0x65	; WebUSB GUID
	dew	0x0100		; Version 1.0
	de	0x01		; Vendor request code	(-> bRequest)
	de	0x01		; Landing page		(-> wValueL)
; Microsoft OS 2.0 Platform Capability Descriptor (MS_VendorCode == 0x02)
	de	0x1C		; Length
	de	0x10		; Device Capability descriptor
	de	0x05		; Platform Capability descriptor
	de	0x00		; Reserved
	de	0xDF,0x60,0xDD,0xD8,0x89,0x45,0xC7,0x4C,0x9C,0xD2,0x65,0x9D,0x9E,0x64,0x8A,0x9F	; MS OS 2.0 GUID
	de	0,0,3,6		; Windows version
	dew	0x00B2		; Descriptor set length
	de	0x02		; Vendor request code
	de	0x00		; Alternate enumeration code
BosDescEnd
	if	BosDescEnd-BosDesc !=57
	 error	"Wrong struct!"
	endif

MsOs20Desc
	dew	10		; Descriptor size (10 bytes)
	dew	0		; MS OS 2.0 descriptor set header
	de	0,0,3,6		; Windows version (8.1) (0x06030000)
	dew	0x00B2		; Size, MS OS 2.0 descriptor set
; Microsoft OS 2.0 configuration subset header
	dew	8		; Descriptor size (8 bytes)
	dew	1		; MS OS 2.0 configuration subset header
	dew	0		; bConfigurationValue
	dew	0x00A8		; Size, MS OS 2.0 configuration subset
; Microsoft OS 2.0 function subset header
	dew	8		; Descriptor size (8 bytes)
	dew	2		; MS OS 2.0 function subset header
	dew	1		; iface number
	dew	0x00A0		; Size, MS OS 2.0 function subset
; Microsoft OS 2.0 compatible ID descriptor (table 13)
	dew	20		; wLength
	dew	3		; MS_OS_20_FEATURE_COMPATIBLE_ID
	de	"WINUSB",0,0	; compatID[8]
	de	0,0,0,0,0,0,0,0	; subcompatID[8];
;CUSTOM_PROPERTY
	dew	4+21+1+40<<1	; wLength: 
	dew	4		; wDescType: MS_OS_20_FEATURE_REG_PROPERTY: 0x04 (Table 9)
	dew	7		; wPropertyDataType: REG_MULTI_SZ (Table 15)
	dew	21<<1		; wPropertyNameLength:
	de	'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,'I',0,'n',0,'t',0,'e',0,'r',0,'f',0,'a',0,'c',0,'e',0,'G',0,'U',0,'I',0,'D',0,'s',0,0,0	; bPropertyName
	dew	40<<1		; wPropertyDataLength
	de	'{',0,'9',0,'7',0,'5',0,'F',0,'4',0,'4',0,'D',0,'9',0,'-',0,'0',0,'D',0,'0',0,'8',0,'-',0,'4',0,'3',0,'F',0,'D',0,'-',0,'8',0,'B',0,'3',0,'E',0,'-',0
	de	'1',0,'2',0,'7',0,'C',0,'A',0,'8',0,'A',0,'F',0,'F',0,'F',0,'9',0,'D',0,'}',0,0,0,0,0	; bPropertyData
MsOs20DescEnd
	if	MsOs20DescEnd-MsOs20Desc != 23+66<<1
	 error	"Wrong struct!"
	endif

LandingPageDesc
	de	0x2E		; strlen(landingPageUrl)+3
	de	0x03		; descriptorType(String)
	de	0x01		; landingPageScheme(https://)
	de	"www.tu-chemnitz.de/~heha/ewa/Ofen/rauch.htm"
LandingPageDescEnd
	if	LandingPageDescEnd-LandingPageDesc != 0x2E
	 error	"Wrong struct!"
	endif

StringDesc		; High-Teil = DTYPE_String, Low-Teil = (String-Länge+1)*2
	dew	0x0304
	dew	0x0407		; (0) Länge 1: deutsch
	dew	0x0322
	de	'T',0,'U',0,' ',0,'C',0,'h',0,'e',0,'m',0,'n',0,'i',0,'t',0,'z',0,',',0,' ',0,'E',0,'W',0,'A',0	; (1) Länge 16
	dew	0x0318
	de	'R',0,'a',0,'u',0,'c',0,'h',0,'m',0,'e',0,'l',0,'d',0,'e',0,'r',0				; (2) Länge 11
	dew	0x0330
	de	'h',0,'e',0,'h',0,'a',0,'@',0,'h',0,'r',0,'z',0,'.',0,'t',0,'u',0,'-',0,'c',0,'h',0,'e',0,'m',0,'n',0,'i',0,'t',0,'z',0,'.',0,'d',0,'e',0	;(3) Länge 23
	dew	0x0308
	de	'H',0,'I',0,'D',0			; (4) Länge 3
	dew	0x030E
	de	'W',0,'e',0,'b',0,'U',0,'S',0,'B',0	; (5) Länge 6
StringDescEnd

	de	"ABCÄÖÜ"	; legt UTF-8 in die Low-Bytes ab, Nullen in die High-Bytes
	dt	"ABCÄÖÜ"	; wie oben, aber 0x34 ins High-Byte = retlw
	;de	L"ABCÄÖÜ"	; Syntaxfehler
	de	0x1234		; legt 0x0034 ab
	da	0x1234		; legt 0x1234 ab
	da	'1','2','3','4'	; legt effektiv UTF-16 ab, aber nicht bei Umlauten!
	;da	'12'		; Syntaxfehler
	;da	L'1',L'2',L'Ä'	; Syntaxfehler
	da	"1","2","3","4"	; Legt jedes Zeichen 7-Bit in den High-Teil ab, also '1'<<7, '2'<<7 usw.
	da	"1234"		; Legt '1'<<7|'2' und '3'<<7|'4' ab
	dw	1234
	db	0x12,0x34
;Leider keine Möglichkeit, UTF-16 (<0x4000) abzulegen! Würde für alle Buchstabenschriften reichen.
Detected encoding: UTF-80