diff options
Diffstat (limited to 'lib/lufa/Projects/AVRISP-MKII')
38 files changed, 8264 insertions, 0 deletions
diff --git a/lib/lufa/Projects/AVRISP-MKII/AVRISP-MKII.c b/lib/lufa/Projects/AVRISP-MKII/AVRISP-MKII.c new file mode 100644 index 0000000000..a734d960ba --- /dev/null +++ b/lib/lufa/Projects/AVRISP-MKII/AVRISP-MKII.c @@ -0,0 +1,164 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2017. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Main source file for the AVRISP project. This file contains the main tasks of + * the project and is responsible for the initial application hardware configuration. + */ + +#include "AVRISP-MKII.h" + +#if (BOARD != BOARD_NONE) + /* Some board hardware definitions (e.g. the Arduino Micro) have their LEDs defined on the same pins + as the ISP, PDI or TPI interfaces (see the accompanying project documentation). If a board other + than NONE is selected (to enable the LED driver with the programmer) you should double-check that + no conflicts will occur. If there is a conflict, turn off the LEDs (set BOARD to NONE in the makefile) + or define a custom board driver (see the LUFA manual) with alternative LED mappings. + */ + #warning Board specific drivers have been selected; make sure the board LED driver does not conflict with the programmer ISP/PDI/TPI interfaces. +#endif + +/** Main program entry point. This routine contains the overall program flow, including initial + * setup of all components and the main program loop. + */ +int main(void) +{ + SetupHardware(); + V2Protocol_Init(); + + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); + GlobalInterruptEnable(); + + for (;;) + { + #if (BOARD == BOARD_USBTINYMKII) + /* On the USBTINY-MKII target, there is a secondary LED which indicates the current selected power + mode - either VBUS, or sourced from the VTARGET pin of the programming connectors */ + LEDs_ChangeLEDs(LEDMASK_VBUSPOWER, (PIND & (1 << 0)) ? 0 : LEDMASK_VBUSPOWER); + #endif + + AVRISP_Task(); + USB_USBTask(); + } +} + +/** Configures the board hardware and chip peripherals for the demo's functionality. */ +void SetupHardware(void) +{ +#if (ARCH == ARCH_AVR8) + /* Disable watchdog if enabled by bootloader/fuses */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Disable clock division */ + clock_prescale_set(clock_div_1); +#endif + + /* Hardware Initialization */ + LEDs_Init(); + #if defined(RESET_TOGGLES_LIBUSB_COMPAT) + UpdateCurrentCompatibilityMode(); + #endif + + /* USB Stack Initialization */ + USB_Init(); +} + +/** Event handler for the library USB Connection event. */ +void EVENT_USB_Device_Connect(void) +{ + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); +} + +/** Event handler for the library USB Disconnection event. */ +void EVENT_USB_Device_Disconnect(void) +{ + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); +} + +/** Event handler for the library USB Configuration Changed event. */ +void EVENT_USB_Device_ConfigurationChanged(void) +{ + bool ConfigSuccess = true; + + /* Setup AVRISP Data OUT endpoint */ + ConfigSuccess &= Endpoint_ConfigureEndpoint(AVRISP_DATA_OUT_EPADDR, EP_TYPE_BULK, AVRISP_DATA_EPSIZE, 1); + + /* Setup AVRISP Data IN endpoint if it is using a physically different endpoint */ + if ((AVRISP_DATA_IN_EPADDR & ENDPOINT_EPNUM_MASK) != (AVRISP_DATA_OUT_EPADDR & ENDPOINT_EPNUM_MASK)) + ConfigSuccess &= Endpoint_ConfigureEndpoint(AVRISP_DATA_IN_EPADDR, EP_TYPE_BULK, AVRISP_DATA_EPSIZE, 1); + + /* Indicate endpoint configuration success or failure */ + LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR); +} + +/** Processes incoming V2 Protocol commands from the host, returning a response when required. */ +void AVRISP_Task(void) +{ + /* Device must be connected and configured for the task to run */ + if (USB_DeviceState != DEVICE_STATE_Configured) + return; + + V2Params_UpdateParamValues(); + + Endpoint_SelectEndpoint(AVRISP_DATA_OUT_EPADDR); + + /* Check to see if a V2 Protocol command has been received */ + if (Endpoint_IsOUTReceived()) + { + LEDs_SetAllLEDs(LEDMASK_BUSY); + + /* Pass off processing of the V2 Protocol command to the V2 Protocol handler */ + V2Protocol_ProcessCommand(); + + LEDs_SetAllLEDs(LEDMASK_USB_READY); + } +} + +/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" + * documentation) by the application code so that the address and size of a requested descriptor can be given + * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function + * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the + * USB host. + * + * \param[in] wValue Descriptor type and index to retrieve + * \param[in] wIndex Sub-index to retrieve (such as a localized string language) + * \param[out] DescriptorAddress Address of the retrieved descriptor + * + * \return Length of the retrieved descriptor in bytes, or NO_DESCRIPTOR if the descriptor was not found + */ +uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint16_t wIndex, + const void** const DescriptorAddress) +{ + return AVRISP_GetDescriptor(wValue, wIndex, DescriptorAddress); +} + diff --git a/lib/lufa/Projects/AVRISP-MKII/AVRISP-MKII.h b/lib/lufa/Projects/AVRISP-MKII/AVRISP-MKII.h new file mode 100644 index 0000000000..ae2d041484 --- /dev/null +++ b/lib/lufa/Projects/AVRISP-MKII/AVRISP-MKII.h @@ -0,0 +1,90 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2017. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for AVRISP.c. + */ + +#ifndef _AVRISP_H_ +#define _AVRISP_H_ + + /* Includes: */ + #include <avr/io.h> + #include <avr/wdt.h> + #include <avr/interrupt.h> + #include <avr/power.h> + + #include <LUFA/Drivers/Board/LEDs.h> + #include <LUFA/Drivers/USB/USB.h> + #include <LUFA/Platform/Platform.h> + + #if defined(ADC) + #include <LUFA/Drivers/Peripheral/ADC.h> + #endif + + #include "AVRISPDescriptors.h" + #include "Lib/V2Protocol.h" + #include "Config/AppConfig.h" + + /* Macros: */ + /** LED mask for the library LED driver, to indicate that the USB interface is not ready. */ + #define LEDMASK_USB_NOTREADY LEDS_LED1 + + /** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */ + #define LEDMASK_USB_ENUMERATING (LEDS_LED1 | LEDS_LED2) + + /** LED mask for the library LED driver, to indicate that the USB interface is ready. */ + #define LEDMASK_USB_READY LEDS_LED2 + + /** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */ + #define LEDMASK_USB_ERROR LEDS_LED1 + + /** LED mask for the library LED driver, to indicate that the USB interface is busy. */ + #define LEDMASK_BUSY (LEDS_LED1 | LEDS_LED2) + + /** LED mask for the library LED driver, to indicate that the target is being powered by VBUS. */ + #define LEDMASK_VBUSPOWER LEDS_LED3 + + /* Function Prototypes: */ + void SetupHardware(void); + void AVRISP_Task(void); + + void EVENT_USB_Device_Connect(void); + void EVENT_USB_Device_Disconnect(void); + void EVENT_USB_Device_ConfigurationChanged(void); + + uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint16_t wIndex, + const void** const DescriptorAddress) + ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + +#endif + diff --git a/lib/lufa/Projects/AVRISP-MKII/AVRISP-MKII.txt b/lib/lufa/Projects/AVRISP-MKII/AVRISP-MKII.txt new file mode 100644 index 0000000000..76d612ec05 --- /dev/null +++ b/lib/lufa/Projects/AVRISP-MKII/AVRISP-MKII.txt @@ -0,0 +1,346 @@ +/** \file + * + * This file contains special DoxyGen information for the generation of the main page and other special + * documentation pages. It is not a project source file. + */ + +/** \mainpage AVRISP MKII Programmer Project + * + * \section Sec_Compat Project Compatibility + * + * The following list indicates what microcontrollers are compatible with this project. + * + * \li Series 7 USB AVRs (AT90USBxxx7) + * \li Series 6 USB AVRs (AT90USBxxx6) + * \li Series 4 USB AVRs (ATMEGAxxU4) + * \li Series 2 USB AVRs (AT90USBxx2, ATMEGAxxU2) - <i>8KB versions with reduced features only</i> + * + * \section Sec_Info USB Information + * + * The following table gives a rundown of the USB utilization of this project. + * + * <table> + * <tr> + * <td><b>USB Mode:</b></td> + * <td>Device</td> + * </tr> + * <tr> + * <td><b>USB Class:</b></td> + * <td>Vendor Specific Class</td> + * </tr> + * <tr> + * <td><b>USB Subclass:</b></td> + * <td>N/A</td> + * </tr> + * <tr> + * <td><b>Relevant Standards:</b></td> + * <td>Atmel AVRISP MKII Protocol Specification</td> + * </tr> + * <tr> + * <td><b>Supported USB Speeds:</b></td> + * <td>Full Speed Mode</td> + * </tr> + * </table> + * + * \section Sec_Description Project Description + * + * Firmware for an Atmel Studio compatible AVRISP-MKII clone programmer. This project will enable the USB + * AVR series of microcontrollers to act as a clone of the official Atmel AVRISP-MKII programmer, usable within + * Atmel Studio or with any software capable of driving a real Atmel AVRISP-MKII programmer. In its most + * basic form, it allows for the programming of AVR TINY, MEGA and XMEGA devices at the programmer's VCC voltage from + * within Atmel Studio with no special hardware other than the USB AVR and the parts needed for the USB + * interface. If the user desires, more advanced circuits incorporating level conversion can be made to allow for the + * programming of target AVRs running at a different voltage to the programmer. + * + * This device spoofs Atmel's official AVRISP-MKII device PID so that it remains compatible with Atmel's AVRISP-MKII + * drivers. It is currently tested working under the following configurations: + * + * - <b>Windows:</b> Atmel Studio 7, with alternative driver + * - <b>Windows:</b> AVRDUDE 6.2, with alternative driver + * - <b>Linux:</b> AVRDUDE 6.1 + * + * <b>Note that this clone requires a libUSB based driver under Windows,</b> due to an incompatible change in the official + * Jungo based driver. The alternative driver given here will function with both real and clone AVRISP devices in Atmel + * Studio 7 onwards under Windows - and as a bonus, also provides AVRDude access to the programmer. + * + * As of Atmel Studio version 7.0.1417 the legacy Jungo driver has been deprecated in favor of an official libUSB based + * driver, making the driver packaged here superfluous. Use the driver packaged here only if you are still using an earlier + * Atmel Studio 7 build, otherwise the official Atmel libUSB driver should be used. + * + * Note that this design currently has the following limitations: + * - No reversed/shorted target connector detection and notification + * - A separate header is required for each of the ISP, PDI and TPI programming protocols that the user wishes to use + * + * On AVR models with an ADC converter, the USB AVR's AVCC pin should be tied to 5V (e.g. VBUS) and the + * \c VTARGET_ADC_CHANNEL token should be set to an appropriate ADC channel number in the project makefile for VTARGET + * detection to operate correctly. On models without an ADC converter, VTARGET will report a fixed 3.3V level at all times + * which should allow the programmer to remain compatible at the protocol level with all AVR devices. + * + * While this application can be compiled for USB AVRs with as little as 8KB of FLASH, for full functionality 16KB or more + * of FLASH is required. On 8KB devices, ISP or PDI/TPI protocol programming support can be disabled to reduce program size. + * + * \section Sec_KnownIssues Known Issues: + * + * \par XMEGA EEPROM programming fails in some cases. + * Several users have reported that XMEGA EEPROM programming fails unless the chip is erased first. If a non-blank EEPROM + * is present, writing further EEPROM data causes corruption. + * <a href="https://github.com/abcminiuser/lufa/issues/25">LUFA issue tracker entry</a>. + * + * \section Sec_Installation Installation + * The programmer supports multiple platforms, both Windows and Linux. + * + * \subsection SSec_LinuxInstallation Linux Installation + * On Linux systems, the programmer should be usable out of the box with no special setup other than (on some systems) + * editing of the system permissions to allow the programmer to be used from a non-elevated (root) context. The programmer + * is compatible with the free open source AVRDude programming software project. + * + * \subsection SSec_WindowsInstallation Windows Installation + * On Windows systems, due to an unfortunate limitation of the USB AVR devices and the Atmel Studio platform, the programmer + * requires an alternative libUSB based driver. Uninstall the existing Jungo driver for the device (if installed) and replace + * it with the driver that ships with this project, to enable access to the programmer in Atmel Studio and AVRDUDE. + * + * \section Sec_ISP ISP Connections + * Connections to the device for SPI programming (when enabled): + * + * <table> + * <tr> + * <th><b>Programmer Pin:</b></th> + * <th><b>Target Device Pin:</b></th> + * <th><b>ISP 6 Pin Layout:</b></th> + * </tr> + * <tr> + * <td>MISO</td> + * <td>PDO</td> + * <td>1</td> + * </tr> + * <tr> + * <td>ADCx <b><sup>1</sup></b></td> + * <td>VTARGET</td> + * <td>2</td> + * </tr> + * <tr> + * <td>SCLK</td> + * <td>SCLK</td> + * <td>3</td> + * </tr> + * <tr> + * <td>MOSI</td> + * <td>PDI</td> + * <td>4</td> + * </tr> + * <tr> + * <td>PORTx.y <b><sup>2</sup></b></td> + * <td>/RESET</td> + * <td>5</td> + * </tr> + * <tr> + * <td>GND</td> + * <td>GND</td> + * <td>6</td> + * </tr> + * </table> + * + * In addition, the AVR's OCR1A pin will generate a 4MHz clock, to act as an external rescue device clock if the + * fuses have been mis-set. To use the recovery clock, connect the OCR1A pin of the USB AVR to the target AVR's + * XTAL1 pin, and set the ISP programming speed to 125KHz (note: other ISP speeds will not work correctly). + * + * <b><sup>1</sup></b> <i>Optional, see \ref Sec_Options section - for USB AVRs with ADC modules only</i> \n + * <b><sup>2</sup></b> <i>See AUX line related tokens in the \ref Sec_Options section</i> + * + * \section Sec_PDI PDI Connections + * Connections to the device for PDI programming (when enabled): + * + * <table> + * <tr> + * <th><b>Programmer Pin:</b></th> + * <th><b>Target Device Pin:</b></th> + * <th><b>PDI 6 Pin Layout:</b></th> + * </tr> + * <tr> + * <td>Tx/Rx <b><sup>2</sup></b></td> + * <td>DATA</td> + * <td>1</td> + * </tr> + * <tr> + * <td>ADCx <b><sup>1</sup></b></td> + * <td>VTARGET</td> + * <td>2</td> + * </tr> + * <tr> + * <td>N/A</td> + * <td>N/A</td> + * <td>3</td> + * </tr> + * <tr> + * <td>N/A</td> + * <td>N/A</td> + * <td>4</td> + * </tr> + * <tr> + * <td>XCK</td> + * <td>CLOCK</td> + * <td>5</td> + * </tr> + * <tr> + * <td>GND</td> + * <td>GND</td> + * <td>6</td> + * </tr> + * </table> + * + * <b><sup>1</sup></b> <i>Optional, see \ref Sec_Options section - for USB AVRs with ADC modules only</i> \n + * <b><sup>2</sup></b> <i>The AVR's Tx and Rx become the DATA line when connected together via a pair of 220 ohm resistors</i> \n + * + * \section Sec_TPI TPI Connections + * Connections to the device for TPI programming (when enabled): + * + * <table> + * <tr> + * <th><b>Programmer Pin:</b></th> + * <th><b>Target Device Pin:</b></th> + * <th><b>TPI 6 Pin Layout:</b></th> + * </tr> + * <tr> + * <td>Tx/Rx <b><sup>2</sup></b></td> + * <td>DATA</td> + * <td>1</td> + * </tr> + * <tr> + * <td>ADCx <b><sup>1</sup></b></td> + * <td>VTARGET</td> + * <td>2</td> + * </tr> + * <tr> + * <td>XCK <b><sup>2</sup></b></td> + * <td>CLOCK</td> + * <td>3</td> + * </tr> + * <tr> + * <td>N/A</td> + * <td>N/A</td> + * <td>4</td> + * </tr> + * <tr> + * <td>PORTx.y <b><sup>3</sup></b></td> + * <td>/RESET</td> + * <td>5</td> + * </tr> + * <tr> + * <td>GND</td> + * <td>GND</td> + * <td>6</td> + * </tr> + * </table> + * + * <b><sup>1</sup></b> <i>Optional, see \ref Sec_Options section - for USB AVRs with ADC modules only</i> \n + * <b><sup>2</sup></b> <i>The AVR's Tx and Rx become the DATA line when connected together via a pair of 220 ohm resistors</i> \n + * <b><sup>3</sup></b> <i>See AUX line related tokens in the \ref Sec_Options section</i> + * + * \section Sec_Options Project Options + * + * The following defines can be found in this project, which can control the project behaviour when defined, or changed in value. + * + * <table> + * <tr> + * <th><b>Define Name:</b></th> + * <th><b>Location:</b></th> + * <th><b>Description:</b></th> + * </tr> + * <tr> + * <td>AUX_LINE_PORT</td> + * <td>AppConfig.h</td> + * <td>PORT register for the programmer's AUX target line. The use of this line varies between the programming protocols, + * but is generally used for the target's /RESET line. + * \n \n <i>Ignored when compiled for the XPLAIN board.</i></td> + * </tr> + * <tr> + * <td>AUX_LINE_PIN</td> + * <td>AppConfig.h</td> + * <td>PIN register for the programmer's AUX target line. The use of this line varies between the programming protocols, + * but is generally used for the target's /RESET line. + * \n \n <i>Ignored when compiled for the XPLAIN board.</i></td> + * </tr> + * <tr> + * <td>AUX_LINE_DDR</td> + * <td>AppConfig.h</td> + * <td>DDR register for the programmer's AUX target line. The use of this line varies between the programming protocols, + * but is generally used for the target's /RESET line. + * \n \n <i>Ignored when compiled for the XPLAIN board.</i></td> + * </tr> + * <tr> + * <td>AUX_LINE_MASK</td> + * <td>AppConfig.h</td> + * <td>Mask for the programmer's AUX target line. The use of this line varies between the programming protocols, + * but is generally used for the target's /RESET line. <b>Must not be the AVR's /SS pin</b>. + * \n \n <i>Ignored when compiled for the XPLAIN board.</i></td> + * </tr> + * <tr> + * <td>VTARGET_ADC_CHANNEL</td> + * <td>AppConfig.h</td> + * <td>ADC channel number (on supported AVRs) to use for VTARGET level detection, if NO_VTARGET_DETECT is not defined. + * \n \n <i>Ignored when compiled for targets lacking an ADC.</i></td> + * </tr> + * <tr> + * <td>ENABLE_ISP_PROTOCOL</td> + * <td>AppConfig.h</td> + * <td>Define to enable SPI programming protocol support. + * \n \n <i>Ignored when compiled for the XPLAIN board.</i></td> + * </tr> + * <tr> + * <td>ENABLE_XPROG_PROTOCOL</td> + * <td>AppConfig.h</td> + * <td>Define to enable PDI and TPI programming protocol support. + * \n \n <i>Ignored when compiled for the XPLAIN board.</i></td> + * </tr> + * <tr> + * <td>NO_VTARGET_DETECT</td> + * <td>AppConfig.h</td> + * <td>Define to disable VTARGET sampling and reporting on AVR models with an ADC converter. This will cause the programmer + * to report a fixed 3.3V target voltage to the host regardless of the real target voltage. + * \n \n <i>Ignored when compiled for targets lacking an ADC.</i></td> + * </tr> + * <tr> + * <td>VTARGET_REF_VOLTS</td> + * <td>AppConfig.h</td> + * <td>Indicates the programmer AVR's AVCC reference voltage when measuring the target's supply voltage. Note that the supply + * voltage should never exceed the reference voltage on the programmer AVR without some form of protection to prevent damage + * to the ADC. + * \n \n <i>Ignored when compiled for targets lacking an ADC, or when NO_VTARGET_DETECT is defined.</i></td> + * </tr> + * <tr> + * <td>VTARGET_USE_INTERNAL_REF</td> + * <td>AppConfig.h</td> + * <td>Selects the internal 2.56V ADC reference voltage, instead of using the AVR's VREF pin. When enabled, this option will + * override the VTARGET_REF_VOLTS configuration option. + * \n \n <i>Ignored when compiled for targets lacking an ADC, or when NO_VTARGET_DETECT is defined.</i></td> + * </tr> + * <tr> + * <td>VTARGET_SCALE_FACTOR</td> + * <td>AppConfig.h</td> + * <td>Indicates the target's supply voltage scale factor when applied to the ADC. A simple resistive divider can be used on the + * ADC pin for measuring the target's supply voltage, so that voltages above the programmer AVR's AVCC reference voltage can be + * measured. This should be the reciprocal of the division performed - e.g. if the VTARGET voltage is halved, this should be set + * to 2. + * \n \n <i>Ignored when compiled for targets lacking an ADC, or when NO_VTARGET_DETECT is defined.</i></td> + * </tr> + * <tr> + * <td>XCK_RESCUE_CLOCK_ENABLE</td> + * <td>AppConfig.h</td> + * <td>Define to move the ISP rescue clock to the AVR's XCK pin instead of the OCR1A output pin. This is useful for existing programming + * hardware that does not expose the OCR1A pin of the AVR, but <i>may</i> cause some issues with PDI programming mode.</td> + * </tr> + * <tr> + * <td>INVERTED_ISP_MISO</td> + * <td>AppConfig.h</td> + * <td>Define to invert the received data on the ISP MISO line. This is sometimes needed depending on the level translation hardware used, + * if the translator hardware inverts the received logic level.</td> + * </tr> + * <tr> + * <td>FIRMWARE_VERSION_MINOR</td> + * <td>AppConfig.h</td> + * <td>Define to set the minor firmware revision nunber reported to the host on request. By default this will use a firmware version compatible + * with the latest Atmel IDE version, however if desired the reported minor value can be adjusted here.</td> + * </tr> + * </table> + */ + |