From 597d389ae6cc75e681d6ee5dbf1cf55e26bbffb8 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Tue, 5 Sep 2017 10:37:32 +0700 Subject: [PATCH 1/4] Fixed bit mask indicating the transfer type when reading the attributes in an endpoint Fixes #313 --- BTD.cpp | 12 +++++------- adk.cpp | 2 +- cdcacm.cpp | 5 ++--- cdcftdi.cpp | 5 ++--- hidboot.h | 2 +- hidcomposite.cpp | 30 ++++++++++++++---------------- hiduniversal.cpp | 6 ++---- masstorage.cpp | 7 +++---- usbh_midi.cpp | 2 +- 9 files changed, 31 insertions(+), 40 deletions(-) diff --git a/BTD.cpp b/BTD.cpp index df1de1b8..07f03339 100644 --- a/BTD.cpp +++ b/BTD.cpp @@ -335,15 +335,13 @@ void BTD::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto bConfNum = conf; uint8_t index; - if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) { // Interrupt In endpoint found + if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) { // Interrupt In endpoint found index = BTD_EVENT_PIPE; epInfo[index].bmNakPower = USB_NAK_NOWAIT; - } else { - if((pep->bmAttributes & 0x02) == 2) // Bulk endpoint found - index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE; - else - return; - } + } else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) // Bulk endpoint found + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE; + else + return; // Fill the rest of endpoint data structure epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); diff --git a/adk.cpp b/adk.cpp index f9631ae8..a60bb85a 100644 --- a/adk.cpp +++ b/adk.cpp @@ -321,7 +321,7 @@ void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto bConfNum = conf; - if((pep->bmAttributes & 0x02) == 2) { + if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) { uint8_t index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; // Fill in the endpoint info structure epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); diff --git a/cdcacm.cpp b/cdcacm.cpp index 6611cd3c..548b4685 100644 --- a/cdcacm.cpp +++ b/cdcacm.cpp @@ -237,10 +237,9 @@ void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto uint8_t index; - if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) + if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) index = epInterruptInIndex; - else - if((pep->bmAttributes & 0x02) == 2) + else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; else return; diff --git a/cdcftdi.cpp b/cdcftdi.cpp index 14420847..fbdd033e 100644 --- a/cdcftdi.cpp +++ b/cdcftdi.cpp @@ -229,10 +229,9 @@ void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t prot uint8_t index; - if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) + if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) index = epInterruptInIndex; - else - if((pep->bmAttributes & 0x02) == 2) + else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; else return; diff --git a/hidboot.h b/hidboot.h index 6c192dac..df4fa421 100644 --- a/hidboot.h +++ b/hidboot.h @@ -546,7 +546,7 @@ void HIDBoot::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t bConfNum = conf; bIfaceNum = iface; - if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) { + if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) { if(pep->bInterval > bInterval) bInterval = pep->bInterval; // Fill in the endpoint info structure diff --git a/hidcomposite.cpp b/hidcomposite.cpp index 65cbb6ef..3f0a21c2 100644 --- a/hidcomposite.cpp +++ b/hidcomposite.cpp @@ -313,29 +313,27 @@ void HIDComposite::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint bNumIface++; } - if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) - index = epInterruptInIndex; - else - index = epInterruptOutIndex; + if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT) + index = (pep->bEndpointAddress & 0x80) == 0x80 ? epInterruptInIndex : epInterruptOutIndex; if(!SelectInterface(iface, proto)) - index = 0; + index = 0; if(index) { - // Fill in the endpoint info structure - epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F); - epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize; - epInfo[bNumEP].bmSndToggle = 0; - epInfo[bNumEP].bmRcvToggle = 0; - epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT; + // Fill in the endpoint info structure + epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize; + epInfo[bNumEP].bmSndToggle = 0; + epInfo[bNumEP].bmRcvToggle = 0; + epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT; - // Fill in the endpoint index list - piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F); + // Fill in the endpoint index list + piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F); - if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints - pollInterval = pep->bInterval; + if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints + pollInterval = pep->bInterval; - bNumEP++; + bNumEP++; } } diff --git a/hiduniversal.cpp b/hiduniversal.cpp index cef4b329..49309df4 100644 --- a/hiduniversal.cpp +++ b/hiduniversal.cpp @@ -315,10 +315,8 @@ void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint bNumIface++; } - if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) - index = epInterruptInIndex; - else - index = epInterruptOutIndex; + if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT) + index = (pep->bEndpointAddress & 0x80) == 0x80 ? epInterruptInIndex : epInterruptOutIndex; if(index) { // Fill in the endpoint info structure diff --git a/masstorage.cpp b/masstorage.cpp index 4c0c37ad..52b1275a 100644 --- a/masstorage.cpp +++ b/masstorage.cpp @@ -550,7 +550,7 @@ void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t uint8_t index; #if 1 - if((pep->bmAttributes & 0x02) == 2) { + if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) { index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; // Fill in the endpoint info structure epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); @@ -564,10 +564,9 @@ void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t } #else - if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) + if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) index = epInterruptInIndex; - else - if((pep->bmAttributes & 0x02) == 2) + else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; else return; diff --git a/usbh_midi.cpp b/usbh_midi.cpp index b4f12cf2..8bc4fd31 100644 --- a/usbh_midi.cpp +++ b/usbh_midi.cpp @@ -304,7 +304,7 @@ uint8_t USBH_MIDI::parseConfigDescr( uint8_t addr, uint8_t conf ) USBTRACE("-EPAddr:"), D_PrintHex(epDesc->bEndpointAddress, 0x80); USBTRACE(" bmAttr:"), D_PrintHex(epDesc->bmAttributes, 0x80); USBTRACE2(" MaxPktSz:", (uint8_t)epDesc->wMaxPacketSize); - if ((epDesc->bmAttributes & 0x02) == 2) {//bulk + if ((epDesc->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) {//bulk uint8_t index; if( isMidi ) index = ((epDesc->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; From 1308773eb89441a657dd87e5a3cb92e5f06b4257 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Wed, 6 Sep 2017 10:06:43 +0700 Subject: [PATCH 2/4] Release version 1.3.1 --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index f31f5836..f69007b1 100644 --- a/library.json +++ b/library.json @@ -31,7 +31,7 @@ "type": "git", "url": "https://github.com/felis/USB_Host_Shield_2.0.git" }, - "version": "1.3.0", + "version": "1.3.1", "license": "GPL-2.0", "examples": [ diff --git a/library.properties b/library.properties index dc8ac7e7..7eef52a1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=USB Host Shield Library 2.0 -version=1.3.0 +version=1.3.1 author=Oleg Mazurov (Circuits@Home) , Kristian Lauszus (TKJ Electronics) , Andrew Kroll , Alexei Glushchenko (Circuits@Home) maintainer=Oleg Mazurov (Circuits@Home) , Kristian Lauszus (TKJ Electronics) , Andrew Kroll sentence=Revision 2.0 of MAX3421E-based USB Host Shield Library. From 5107310499c25d8db4025e94ea324f0509ff464a Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 9 Nov 2017 19:13:42 +0100 Subject: [PATCH 3/4] Applied path for https://github.com/felis/USB_Host_Shield_2.0/commit/e7fa52925d4d3255159bdcb6e373df0d002215bd manually --- settings.h | 6 ++++++ usbhost.h | 62 +++++++++++++++++++++++++++--------------------------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/settings.h b/settings.h index ad407f8a..53202ff5 100644 --- a/settings.h +++ b/settings.h @@ -19,6 +19,12 @@ e-mail : support@circuitsathome.com #define USB_HOST_SHIELD_SETTINGS_H #include "macros.h" +//////////////////////////////////////////////////////////////////////////////// +// SPI Configuration +//////////////////////////////////////////////////////////////////////////////// +#define USB_SPI SPI +//#define USB_SPI SPI1 + //////////////////////////////////////////////////////////////////////////////// // DEBUGGING //////////////////////////////////////////////////////////////////////////////// diff --git a/usbhost.h b/usbhost.h index 8f97121e..9f17217f 100644 --- a/usbhost.h +++ b/usbhost.h @@ -41,7 +41,7 @@ public: } #elif defined(SPI_HAS_TRANSACTION) static void init() { - SPI.begin(); // The SPI library with transaction will take care of setting up the pins - settings is set in beginTransaction() + USB_SPI.begin(); // The SPI library with transaction will take care of setting up the pins - settings is set in beginTransaction() SPI_SS::SetDirWrite(); SPI_SS::Set(); } @@ -54,17 +54,17 @@ public: static void init() { SPI_SS::SetDirWrite(); SPI_SS::Set(); - SPI.begin(); + USB_SPI.begin(); #if defined(__MIPSEL__) - SPI.setClockDivider(1); + USB_SPI.setClockDivider(1); #elif defined(__ARDUINO_X86__) #ifdef SPI_CLOCK_1M // Hack used to check if setClockSpeed is available - SPI.setClockSpeed(12000000); // The MAX3421E can handle up to 26MHz, but in practice this was the maximum that I could reliably use + USB_SPI.setClockSpeed(12000000); // The MAX3421E can handle up to 26MHz, but in practice this was the maximum that I could reliably use #else - SPI.setClockDivider(SPI_CLOCK_DIV2); // This will set the SPI frequency to 8MHz - it could be higher, but it is not supported in the old API + USB_SPI.setClockDivider(SPI_CLOCK_DIV2); // This will set the SPI frequency to 8MHz - it could be higher, but it is not supported in the old API #endif #elif !defined(RBL_NRF51822) - SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz + USB_SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz #endif } #else @@ -167,7 +167,7 @@ template< typename SPI_SS, typename INTR > void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) { XMEM_ACQUIRE_SPI(); #if defined(SPI_HAS_TRANSACTION) - SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 + USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 #endif SPI_SS::Clear(); @@ -180,15 +180,15 @@ void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) { uint8_t c[2]; c[0] = reg | 0x02; c[1] = data; - SPI.transfer(c, 2); + USB_SPI.transfer(c, 2); #elif defined(STM32F4) uint8_t c[2]; c[0] = reg | 0x02; c[1] = data; HAL_SPI_Transmit(&SPI_Handle, c, 2, HAL_MAX_DELAY); #elif !defined(SPDR) // ESP8266 - SPI.transfer(reg | 0x02); - SPI.transfer(data); + USB_SPI.transfer(reg | 0x02); + USB_SPI.transfer(data); #else SPDR = (reg | 0x02); while(!(SPSR & (1 << SPIF))); @@ -198,7 +198,7 @@ void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) { SPI_SS::Set(); #if defined(SPI_HAS_TRANSACTION) - SPI.endTransaction(); + USB_SPI.endTransaction(); #endif XMEM_RELEASE_SPI(); return; @@ -210,7 +210,7 @@ template< typename SPI_SS, typename INTR > uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) { XMEM_ACQUIRE_SPI(); #if defined(SPI_HAS_TRANSACTION) - SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 + USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 #endif SPI_SS::Clear(); @@ -219,12 +219,12 @@ uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* spi4teensy3::send(data_p, nbytes); data_p += nbytes; #elif defined(SPI_HAS_TRANSACTION) && !defined(ESP8266) - SPI.transfer(reg | 0x02); - SPI.transfer(data_p, nbytes); + USB_SPI.transfer(reg | 0x02); + USB_SPI.transfer(data_p, nbytes); data_p += nbytes; #elif defined(__ARDUINO_X86__) - SPI.transfer(reg | 0x02); - SPI.transferBuffer(data_p, NULL, nbytes); + USB_SPI.transfer(reg | 0x02); + USB_SPI.transferBuffer(data_p, NULL, nbytes); data_p += nbytes; #elif defined(STM32F4) uint8_t data = reg | 0x02; @@ -232,9 +232,9 @@ uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* HAL_SPI_Transmit(&SPI_Handle, data_p, nbytes, HAL_MAX_DELAY); data_p += nbytes; #elif !defined(SPDR) // ESP8266 - SPI.transfer(reg | 0x02); + USB_SPI.transfer(reg | 0x02); while(nbytes) { - SPI.transfer(*data_p); + USB_SPI.transfer(*data_p); nbytes--; data_p++; // advance data pointer } @@ -251,7 +251,7 @@ uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* SPI_SS::Set(); #if defined(SPI_HAS_TRANSACTION) - SPI.endTransaction(); + USB_SPI.endTransaction(); #endif XMEM_RELEASE_SPI(); return ( data_p); @@ -273,7 +273,7 @@ template< typename SPI_SS, typename INTR > uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) { XMEM_ACQUIRE_SPI(); #if defined(SPI_HAS_TRANSACTION) - SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 + USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 #endif SPI_SS::Clear(); @@ -287,8 +287,8 @@ uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) { HAL_SPI_Receive(&SPI_Handle, &rv, 1, HAL_MAX_DELAY); SPI_SS::Set(); #elif !defined(SPDR) || defined(SPI_HAS_TRANSACTION) - SPI.transfer(reg); - uint8_t rv = SPI.transfer(0); // Send empty byte + USB_SPI.transfer(reg); + uint8_t rv = USB_SPI.transfer(0); // Send empty byte SPI_SS::Set(); #else SPDR = reg; @@ -300,7 +300,7 @@ uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) { #endif #if defined(SPI_HAS_TRANSACTION) - SPI.endTransaction(); + USB_SPI.endTransaction(); #endif XMEM_RELEASE_SPI(); return (rv); @@ -312,7 +312,7 @@ template< typename SPI_SS, typename INTR > uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) { XMEM_ACQUIRE_SPI(); #if defined(SPI_HAS_TRANSACTION) - SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 + USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0 #endif SPI_SS::Clear(); @@ -321,13 +321,13 @@ uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* spi4teensy3::receive(data_p, nbytes); data_p += nbytes; #elif defined(SPI_HAS_TRANSACTION) && !defined(ESP8266) - SPI.transfer(reg); + USB_SPI.transfer(reg); memset(data_p, 0, nbytes); // Make sure we send out empty bytes - SPI.transfer(data_p, nbytes); + USB_SPI.transfer(data_p, nbytes); data_p += nbytes; #elif defined(__ARDUINO_X86__) - SPI.transfer(reg); - SPI.transferBuffer(NULL, data_p, nbytes); + USB_SPI.transfer(reg); + USB_SPI.transferBuffer(NULL, data_p, nbytes); data_p += nbytes; #elif defined(STM32F4) HAL_SPI_Transmit(&SPI_Handle, ®, 1, HAL_MAX_DELAY); @@ -335,9 +335,9 @@ uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* HAL_SPI_Receive(&SPI_Handle, data_p, nbytes, HAL_MAX_DELAY); data_p += nbytes; #elif !defined(SPDR) // ESP8266 - SPI.transfer(reg); + USB_SPI.transfer(reg); while(nbytes) { - *data_p++ = SPI.transfer(0); + *data_p++ = USB_SPI.transfer(0); nbytes--; } #else @@ -363,7 +363,7 @@ uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* SPI_SS::Set(); #if defined(SPI_HAS_TRANSACTION) - SPI.endTransaction(); + USB_SPI.endTransaction(); #endif XMEM_RELEASE_SPI(); return ( data_p); From 1020c2162d7bc54fc47756d0a8cf4fb1a0252bbd Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 9 Nov 2017 19:14:51 +0100 Subject: [PATCH 4/4] Allows users to override SPI port via a build flag --- settings.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/settings.h b/settings.h index 53202ff5..48372aef 100644 --- a/settings.h +++ b/settings.h @@ -22,8 +22,10 @@ e-mail : support@circuitsathome.com //////////////////////////////////////////////////////////////////////////////// // SPI Configuration //////////////////////////////////////////////////////////////////////////////// +#ifndef USB_SPI #define USB_SPI SPI //#define USB_SPI SPI1 +#endif //////////////////////////////////////////////////////////////////////////////// // DEBUGGING