Added ENABLE_TELNET_SERVER compile time option to the Webserver project to disable...
[pub/USBasp.git] / Projects / AVRISP-MKII / Lib / ISP / ISPProtocol.c
index 0349b2f..85b31fb 100644 (file)
@@ -1,13 +1,13 @@
 /*\r
              LUFA Library\r
-     Copyright (C) Dean Camera, 2009.\r
+     Copyright (C) Dean Camera, 2010.\r
               \r
   dean [at] fourwalledcubicle [dot] com\r
       www.fourwalledcubicle.com\r
 */\r
 \r
 /*\r
-  Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
+  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
 \r
   Permission to use, copy, modify, distribute, and sell this \r
   software and its documentation for any purpose is hereby granted\r
@@ -54,7 +54,7 @@ void ISPProtocol_EnterISPMode(void)
                uint8_t EnterProgBytes[4];\r
        } Enter_ISP_Params;\r
        \r
-       Endpoint_Read_Stream_LE(&Enter_ISP_Params, sizeof(Enter_ISP_Params));\r
+       Endpoint_Read_Stream_LE(&Enter_ISP_Params, sizeof(Enter_ISP_Params), NO_STREAM_CALLBACK);\r
 \r
        Endpoint_ClearOUT();\r
        Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);\r
@@ -62,11 +62,20 @@ void ISPProtocol_EnterISPMode(void)
        uint8_t ResponseStatus = STATUS_CMD_FAILED;\r
        \r
        CurrentAddress = 0;\r
+       \r
+       /* Set up the synchronous USART to generate the recovery clock on XCK pin */\r
+       UBRR1  = (F_CPU / 500000UL);\r
+       UCSR1B = (1 << TXEN1);\r
+       UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1);\r
+       DDRD  |= (1 << 5);\r
 \r
+       /* Perform execution delay, initialize SPI bus */\r
        ISPProtocol_DelayMS(Enter_ISP_Params.ExecutionDelayMS); \r
        SPI_Init(ISPTarget_GetSPIPrescalerMask() | SPI_SCK_LEAD_RISING | SPI_SAMPLE_LEADING | SPI_MODE_MASTER);\r
-               \r
-       while (Enter_ISP_Params.SynchLoops-- && (ResponseStatus == STATUS_CMD_FAILED))\r
+\r
+       /* Continuously attempt to synchronize with the target until either the number of attempts specified\r
+        * by the host has exceeded, or the the device sends back the expected response values */\r
+       while (Enter_ISP_Params.SynchLoops-- && (ResponseStatus == STATUS_CMD_FAILED) && TimeoutMSRemaining)\r
        {\r
                uint8_t ResponseBytes[4];\r
 \r
@@ -105,16 +114,23 @@ void ISPProtocol_LeaveISPMode(void)
                uint8_t PostDelayMS;\r
        } Leave_ISP_Params;\r
 \r
-       Endpoint_Read_Stream_LE(&Leave_ISP_Params, sizeof(Leave_ISP_Params));\r
+       Endpoint_Read_Stream_LE(&Leave_ISP_Params, sizeof(Leave_ISP_Params), NO_STREAM_CALLBACK);\r
        \r
        Endpoint_ClearOUT();\r
        Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);\r
 \r
+       /* Perform pre-exit delay, release the target /RESET, disable the SPI bus and perform the post-exit delay */\r
        ISPProtocol_DelayMS(Leave_ISP_Params.PreDelayMS);\r
        ISPTarget_ChangeTargetResetLine(false);\r
        SPI_ShutDown();\r
        ISPProtocol_DelayMS(Leave_ISP_Params.PostDelayMS);\r
 \r
+       /* Turn off the synchronous USART to terminate the recovery clock on XCK pin */\r
+       UBRR1  = (F_CPU / 500000UL);\r
+       UCSR1B = (1 << TXEN1);\r
+       UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1);\r
+       DDRD  &= ~(1 << 5);\r
+\r
        Endpoint_Write_Byte(CMD_LEAVE_PROGMODE_ISP);\r
        Endpoint_Write_Byte(STATUS_CMD_OK);\r
        Endpoint_ClearIN();\r
@@ -139,7 +155,7 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command)
        } Write_Memory_Params;      // whole page and ACK the packet as fast as possible to prevent it from aborting\r
        \r
        Endpoint_Read_Stream_LE(&Write_Memory_Params, (sizeof(Write_Memory_Params) -\r
-                                                      sizeof(Write_Memory_Params.ProgData)));\r
+                                                      sizeof(Write_Memory_Params.ProgData)), NO_STREAM_CALLBACK);\r
 \r
 \r
        Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite);\r
@@ -155,7 +171,7 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command)
                return;\r
        }\r
        \r
-       Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite);\r
+       Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite, NO_STREAM_CALLBACK);\r
 \r
        Endpoint_ClearOUT();\r
        Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);\r
@@ -166,6 +182,9 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command)
                                                                            Write_Memory_Params.PollValue2;\r
        uint8_t* NextWriteByte = Write_Memory_Params.ProgData;\r
 \r
+       /* Check to see if the host has issued a SET ADDRESS command and we haven't sent a\r
+        * LOAD EXTENDED ADDRESS command (if needed, used when operating beyond the 128KB\r
+        * FLASH barrier) */\r
        if (MustSetAddress)\r
        {\r
                if (CurrentAddress & (1UL << 31))\r
@@ -174,6 +193,7 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command)
                MustSetAddress = false;\r
        }\r
 \r
+       /* Check the programming mode desired by the host, either Paged or Word memory writes */\r
        if (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK)\r
        {\r
                uint16_t StartAddress = (CurrentAddress & 0xFFFF);\r
@@ -184,21 +204,22 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command)
                        bool    IsOddByte   = (CurrentByte & 0x01);\r
                        uint8_t ByteToWrite = *(NextWriteByte++);\r
                \r
-                       if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))\r
-                         Write_Memory_Params.ProgrammingCommands[0] |=  READ_WRITE_HIGH_BYTE_MASK;\r
-                       else\r
-                         Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;\r
-                         \r
                        SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);\r
                        SPI_SendByte(CurrentAddress >> 8);\r
                        SPI_SendByte(CurrentAddress & 0xFF);\r
                        SPI_SendByte(ByteToWrite);\r
                        \r
+                       /* AVR FLASH addressing requires us to modify the write command based on if we are writing a high\r
+                        * or low byte at the current word address */\r
+                       if (V2Command == CMD_PROGRAM_FLASH_ISP)\r
+                         Write_Memory_Params.ProgrammingCommands[0] ^= READ_WRITE_HIGH_BYTE_MASK;\r
+\r
+                       /* Check to see the write completion method, to see if we have a valid polling address */\r
                        if (!(PollAddress) && (ByteToWrite != PollValue))\r
                        {\r
                                if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))\r
                                  Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;\r
-                                 \r
+\r
                                PollAddress = (CurrentAddress & 0xFFFF);                                \r
                        }               \r
 \r
@@ -232,17 +253,17 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command)
                {\r
                        bool    IsOddByte   = (CurrentByte & 0x01);\r
                        uint8_t ByteToWrite = *(NextWriteByte++);\r
-               \r
-                       if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))\r
-                         Write_Memory_Params.ProgrammingCommands[0] |=  READ_WRITE_HIGH_BYTE_MASK;\r
-                       else\r
-                         Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;                     \r
                          \r
                        SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);\r
                        SPI_SendByte(CurrentAddress >> 8);\r
                        SPI_SendByte(CurrentAddress & 0xFF);\r
                        SPI_SendByte(ByteToWrite);\r
                        \r
+                       /* AVR FLASH addressing requires us to modify the write command based on if we are writing a high\r
+                        * or low byte at the current word address */\r
+                       if (V2Command == CMD_PROGRAM_FLASH_ISP)\r
+                         Write_Memory_Params.ProgrammingCommands[0] ^= READ_WRITE_HIGH_BYTE_MASK;\r
+\r
                        if (ByteToWrite != PollValue)\r
                        {\r
                                if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))\r
@@ -280,7 +301,7 @@ void ISPProtocol_ReadMemory(uint8_t V2Command)
                uint8_t  ReadMemoryCommand;\r
        } Read_Memory_Params;\r
        \r
-       Endpoint_Read_Stream_LE(&Read_Memory_Params, sizeof(Read_Memory_Params));\r
+       Endpoint_Read_Stream_LE(&Read_Memory_Params, sizeof(Read_Memory_Params), NO_STREAM_CALLBACK);\r
        Read_Memory_Params.BytesToRead = SwapEndian_16(Read_Memory_Params.BytesToRead);\r
        \r
        Endpoint_ClearOUT();\r
@@ -289,6 +310,9 @@ void ISPProtocol_ReadMemory(uint8_t V2Command)
        Endpoint_Write_Byte(V2Command);\r
        Endpoint_Write_Byte(STATUS_CMD_OK);\r
        \r
+       /* Check to see if the host has issued a SET ADDRESS command and we haven't sent a\r
+        * LOAD EXTENDED ADDRESS command (if needed, used when operating beyond the 128KB\r
+        * FLASH barrier) */\r
        if (MustSetAddress)\r
        {\r
                if (CurrentAddress & (1UL << 31))\r
@@ -297,28 +321,30 @@ void ISPProtocol_ReadMemory(uint8_t V2Command)
                MustSetAddress = false;\r
        }\r
 \r
+       /* Read each byte from the device and write them to the packet for the host */\r
        for (uint16_t CurrentByte = 0; CurrentByte < Read_Memory_Params.BytesToRead; CurrentByte++)\r
        {\r
-               bool IsOddByte = (CurrentByte & 0x01);\r
-\r
-               if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))\r
-                 Read_Memory_Params.ReadMemoryCommand |=  READ_WRITE_HIGH_BYTE_MASK;\r
-               else\r
-                 Read_Memory_Params.ReadMemoryCommand &= ~READ_WRITE_HIGH_BYTE_MASK;\r
-\r
+               /* Read the next byte from the desired memory space in the device */\r
                SPI_SendByte(Read_Memory_Params.ReadMemoryCommand);\r
                SPI_SendByte(CurrentAddress >> 8);\r
                SPI_SendByte(CurrentAddress & 0xFF);\r
                Endpoint_Write_Byte(SPI_ReceiveByte());\r
                \r
-               /* Check if the endpoint bank is currently full */\r
+               /* Check if the endpoint bank is currently full, if so send the packet */\r
                if (!(Endpoint_IsReadWriteAllowed()))\r
                {\r
                        Endpoint_ClearIN();\r
                        Endpoint_WaitUntilReady();\r
                }\r
                \r
-               if ((IsOddByte && (V2Command == CMD_READ_FLASH_ISP)) || (V2Command == CMD_READ_EEPROM_ISP))\r
+               /* AVR FLASH addressing requires us to modify the read command based on if we are reading a high\r
+                * or low byte at the current word address */\r
+               if (V2Command == CMD_READ_FLASH_ISP)\r
+                 Read_Memory_Params.ReadMemoryCommand ^= READ_WRITE_HIGH_BYTE_MASK;\r
+\r
+               /* Only increment the current address if we have read both bytes in the current word when in FLASH\r
+                * read mode, or for each byte when in EEPROM read mode */               \r
+               if (((CurrentByte & 0x01) && (V2Command == CMD_READ_FLASH_ISP)) || (V2Command == CMD_READ_EEPROM_ISP))\r
                  CurrentAddress++;\r
        }\r
 \r
@@ -346,16 +372,18 @@ void ISPProtocol_ChipErase(void)
                uint8_t EraseCommandBytes[4];\r
        } Erase_Chip_Params;\r
        \r
-       Endpoint_Read_Stream_LE(&Erase_Chip_Params, sizeof(Erase_Chip_Params));\r
+       Endpoint_Read_Stream_LE(&Erase_Chip_Params, sizeof(Erase_Chip_Params), NO_STREAM_CALLBACK);\r
        \r
        Endpoint_ClearOUT();\r
        Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);\r
        \r
        uint8_t ResponseStatus = STATUS_CMD_OK;\r
        \r
+       /* Send the chip erase commands as given by the host to the device */\r
        for (uint8_t SByte = 0; SByte < sizeof(Erase_Chip_Params.EraseCommandBytes); SByte++)\r
          SPI_SendByte(Erase_Chip_Params.EraseCommandBytes[SByte]);\r
 \r
+       /* Use appropriate command completion check as given by the host (delay or busy polling) */\r
        if (!(Erase_Chip_Params.PollMethod))\r
          ISPProtocol_DelayMS(Erase_Chip_Params.EraseDelayMS);\r
        else\r
@@ -379,13 +407,14 @@ void ISPProtocol_ReadFuseLockSigOSCCAL(uint8_t V2Command)
                uint8_t ReadCommandBytes[4];\r
        } Read_FuseLockSigOSCCAL_Params;\r
        \r
-       Endpoint_Read_Stream_LE(&Read_FuseLockSigOSCCAL_Params, sizeof(Read_FuseLockSigOSCCAL_Params));\r
+       Endpoint_Read_Stream_LE(&Read_FuseLockSigOSCCAL_Params, sizeof(Read_FuseLockSigOSCCAL_Params), NO_STREAM_CALLBACK);\r
 \r
        Endpoint_ClearOUT();\r
        Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);\r
 \r
        uint8_t ResponseBytes[4];\r
-               \r
+\r
+       /* Send the Fuse or Lock byte read commands as given by the host to the device, store response */\r
        for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)\r
          ResponseBytes[RByte] = SPI_TransferByte(Read_FuseLockSigOSCCAL_Params.ReadCommandBytes[RByte]);\r
                \r
@@ -408,11 +437,12 @@ void ISPProtocol_WriteFuseLock(uint8_t V2Command)
                uint8_t WriteCommandBytes[4];\r
        } Write_FuseLockSig_Params;\r
        \r
-       Endpoint_Read_Stream_LE(&Write_FuseLockSig_Params, sizeof(Write_FuseLockSig_Params));\r
+       Endpoint_Read_Stream_LE(&Write_FuseLockSig_Params, sizeof(Write_FuseLockSig_Params), NO_STREAM_CALLBACK);\r
 \r
        Endpoint_ClearOUT();\r
        Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);\r
 \r
+       /* Send the Fuse or Lock byte program commands as given by the host to the device */\r
        for (uint8_t SByte = 0; SByte < sizeof(Write_FuseLockSig_Params.WriteCommandBytes); SByte++)\r
          SPI_SendByte(Write_FuseLockSig_Params.WriteCommandBytes[SByte]);\r
                \r
@@ -433,8 +463,8 @@ void ISPProtocol_SPIMulti(void)
                uint8_t TxData[255];\r
        } SPI_Multi_Params;\r
        \r
-       Endpoint_Read_Stream_LE(&SPI_Multi_Params, sizeof(SPI_Multi_Params) - sizeof(SPI_Multi_Params.TxData));\r
-       Endpoint_Read_Stream_LE(&SPI_Multi_Params.TxData, SPI_Multi_Params.TxBytes);\r
+       Endpoint_Read_Stream_LE(&SPI_Multi_Params, (sizeof(SPI_Multi_Params) - sizeof(SPI_Multi_Params.TxData)), NO_STREAM_CALLBACK);\r
+       Endpoint_Read_Stream_LE(&SPI_Multi_Params.TxData, SPI_Multi_Params.TxBytes, NO_STREAM_CALLBACK);\r
        \r
        Endpoint_ClearOUT();\r
        Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);\r
@@ -463,12 +493,44 @@ void ISPProtocol_SPIMulti(void)
                  Endpoint_Write_Byte(SPI_TransferByte(SPI_Multi_Params.TxData[CurrTxPos++]));\r
                else\r
                  Endpoint_Write_Byte(SPI_ReceiveByte());\r
+                 \r
+               /* Check to see if we have filled the endpoint bank and need to send the packet */\r
+               if (!(Endpoint_IsReadWriteAllowed()))\r
+               {\r
+                       Endpoint_ClearIN();\r
+                       Endpoint_WaitUntilReady();\r
+               }\r
                \r
                CurrRxPos++;\r
        }       \r
        \r
        Endpoint_Write_Byte(STATUS_CMD_OK);\r
+\r
+       bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed());\r
        Endpoint_ClearIN();\r
+       \r
+       /* Ensure last packet is a short packet to terminate the transfer */\r
+       if (IsEndpointFull)\r
+       {\r
+               Endpoint_WaitUntilReady();      \r
+               Endpoint_ClearIN();\r
+               Endpoint_WaitUntilReady();      \r
+       }\r
+}\r
+\r
+/** Blocking delay for a given number of milliseconds.\r
+ *\r
+ *  \param[in] DelayMS  Number of milliseconds to delay for\r
+ */\r
+void ISPProtocol_DelayMS(uint8_t DelayMS)\r
+{\r
+       while (DelayMS-- && TimeoutMSRemaining)\r
+       {\r
+               if (TimeoutMSRemaining)\r
+                 TimeoutMSRemaining--;\r
+                 \r
+               _delay_ms(1);\r
+       }\r
 }\r
 \r
 #endif
\ No newline at end of file