diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/.cproject b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/.cproject new file mode 100644 index 0000000..7a19556 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/.cproject @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/.project b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/.project new file mode 100644 index 0000000..67b1c40 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/.project @@ -0,0 +1,28 @@ + + + 12_m1284p_WIZNET_HTTPServer_SDCARD_pages + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + de.innot.avreclipse.core.avrnature + + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Application/loopback/loopback.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Application/loopback/loopback.c new file mode 100644 index 0000000..a921092 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Application/loopback/loopback.c @@ -0,0 +1,225 @@ +#include +#include "loopback.h" +#include "socket.h" +#include "wizchip_conf.h" + +#if LOOPBACK_MODE == LOOPBACK_MAIN_NOBLCOK + +int32_t loopback_tcps(uint8_t sn, uint8_t* buf, uint16_t port) +{ + int32_t ret; + uint16_t size = 0, sentsize=0; + +#ifdef _LOOPBACK_DEBUG_ + uint8_t destip[4]; + uint16_t destport; +#endif + + switch(getSn_SR(sn)) + { + case SOCK_ESTABLISHED : + if(getSn_IR(sn) & Sn_IR_CON) + { +#ifdef _LOOPBACK_DEBUG_ + getSn_DIPR(sn, destip); + destport = getSn_DPORT(sn); + + printf("%d:Connected - %d.%d.%d.%d : %d\r\n",sn, destip[0], destip[1], destip[2], destip[3], destport); +#endif + setSn_IR(sn,Sn_IR_CON); + } + if((size = getSn_RX_RSR(sn)) > 0) // Don't need to check SOCKERR_BUSY because it doesn't not occur. + { + if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE; + ret = recv(sn, buf, size); + + if(ret <= 0) return ret; // check SOCKERR_BUSY & SOCKERR_XXX. For showing the occurrence of SOCKERR_BUSY. + size = (uint16_t) ret; + sentsize = 0; + + while(size != sentsize) + { + ret = send(sn, buf+sentsize, size-sentsize); + if(ret < 0) + { + close(sn); + return ret; + } + sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero. + } + } + break; + case SOCK_CLOSE_WAIT : +#ifdef _LOOPBACK_DEBUG_ + //printf("%d:CloseWait\r\n",sn); +#endif + if((ret = disconnect(sn)) != SOCK_OK) return ret; +#ifdef _LOOPBACK_DEBUG_ + printf("%d:Socket Closed\r\n", sn); +#endif + break; + case SOCK_INIT : +#ifdef _LOOPBACK_DEBUG_ + printf("%d:Listen, TCP server loopback, port [%d]\r\n", sn, port); +#endif + if( (ret = listen(sn)) != SOCK_OK) return ret; + break; + case SOCK_CLOSED: +#ifdef _LOOPBACK_DEBUG_ + //printf("%d:TCP server loopback start\r\n",sn); +#endif + if((ret = socket(sn, Sn_MR_TCP, port, 0x00)) != sn) return ret; +#ifdef _LOOPBACK_DEBUG_ + //printf("%d:Socket opened\r\n",sn); +#endif + break; + default: + break; + } + return 1; +} + + +int32_t loopback_tcpc(uint8_t sn, uint8_t* buf, uint8_t* destip, uint16_t destport) +{ + int32_t ret; // return value for SOCK_ERRORs + uint16_t size = 0, sentsize=0; + + // Destination (TCP Server) IP info (will be connected) + // >> loopback_tcpc() function parameter + // >> Ex) + // uint8_t destip[4] = {192, 168, 0, 214}; + // uint16_t destport = 5000; + + // Port number for TCP client (will be increased) + static uint16_t any_port = 50000; + + // Socket Status Transitions + // Check the W5500 Socket n status register (Sn_SR, The 'Sn_SR' controlled by Sn_CR command or Packet send/recv status) + switch(getSn_SR(sn)) + { + case SOCK_ESTABLISHED : + if(getSn_IR(sn) & Sn_IR_CON) // Socket n interrupt register mask; TCP CON interrupt = connection with peer is successful + { +#ifdef _LOOPBACK_DEBUG_ + printf("%d:Connected to - %d.%d.%d.%d : %d\r\n",sn, destip[0], destip[1], destip[2], destip[3], destport); +#endif + setSn_IR(sn, Sn_IR_CON); // this interrupt should be write the bit cleared to '1' + } + + ////////////////////////////////////////////////////////////////////////////////////////////// + // Data Transaction Parts; Handle the [data receive and send] process + ////////////////////////////////////////////////////////////////////////////////////////////// + if((size = getSn_RX_RSR(sn)) > 0) // Sn_RX_RSR: Socket n Received Size Register, Receiving data length + { + if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE; // DATA_BUF_SIZE means user defined buffer size (array) + ret = recv(sn, buf, size); // Data Receive process (H/W Rx socket buffer -> User's buffer) + + if(ret <= 0) return ret; // If the received data length <= 0, receive failed and process end + size = (uint16_t) ret; + sentsize = 0; + + // Data sentsize control + while(size != sentsize) + { + ret = send(sn, buf+sentsize, size-sentsize); // Data send process (User's buffer -> Destination through H/W Tx socket buffer) + if(ret < 0) // Send Error occurred (sent data length < 0) + { + close(sn); // socket close + return ret; + } + sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero. + } + } + ////////////////////////////////////////////////////////////////////////////////////////////// + break; + + case SOCK_CLOSE_WAIT : +#ifdef _LOOPBACK_DEBUG_ + //printf("%d:CloseWait\r\n",sn); +#endif + if((ret=disconnect(sn)) != SOCK_OK) return ret; +#ifdef _LOOPBACK_DEBUG_ + printf("%d:Socket Closed\r\n", sn); +#endif + break; + + case SOCK_INIT : +#ifdef _LOOPBACK_DEBUG_ + printf("%d:Try to connect to the %d.%d.%d.%d : %d\r\n", sn, destip[0], destip[1], destip[2], destip[3], destport); +#endif + if( (ret = connect(sn, destip, destport)) != SOCK_OK) return ret; // Try to TCP connect to the TCP server (destination) + break; + + case SOCK_CLOSED: + close(sn); + if((ret=socket(sn, Sn_MR_TCP, any_port++, 0x00)) != sn){ + if(any_port == 0xffff) any_port = 50000; + return ret; // TCP socket open with 'any_port' port number + } +#ifdef _LOOPBACK_DEBUG_ + //printf("%d:TCP client loopback start\r\n",sn); + //printf("%d:Socket opened\r\n",sn); +#endif + break; + default: + break; + } + return 1; +} + + +int32_t loopback_udps(uint8_t sn, uint8_t* buf, uint16_t port) +{ + int32_t ret; + uint16_t size, sentsize; + uint8_t destip[4]; + uint16_t destport; + + switch(getSn_SR(sn)) + { + case SOCK_UDP : + if((size = getSn_RX_RSR(sn)) > 0) + { + if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE; + ret = recvfrom(sn, buf, size, destip, (uint16_t*)&destport); + if(ret <= 0) + { +#ifdef _LOOPBACK_DEBUG_ + printf("%d: recvfrom error. %ld\r\n",sn,ret); +#endif + return ret; + } + size = (uint16_t) ret; + sentsize = 0; + while(sentsize != size) + { + ret = sendto(sn, buf+sentsize, size-sentsize, destip, destport); + if(ret < 0) + { +#ifdef _LOOPBACK_DEBUG_ + printf("%d: sendto error. %ld\r\n",sn,ret); +#endif + return ret; + } + sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero. + } + } + break; + case SOCK_CLOSED: +#ifdef _LOOPBACK_DEBUG_ + //printf("%d:UDP loopback start\r\n",sn); +#endif + if((ret = socket(sn, Sn_MR_UDP, port, 0x00)) != sn) + return ret; +#ifdef _LOOPBACK_DEBUG_ + printf("%d:Opened, UDP loopback, port [%d]\r\n", sn, port); +#endif + break; + default : + break; + } + return 1; +} + +#endif diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Application/loopback/loopback.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Application/loopback/loopback.h new file mode 100644 index 0000000..8f5a3d6 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Application/loopback/loopback.h @@ -0,0 +1,38 @@ +#ifndef _LOOPBACK_H_ +#define _LOOPBACK_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Loopback test debug message printout enable */ +#define _LOOPBACK_DEBUG_ + +/* DATA_BUF_SIZE define for Loopback example */ +#ifndef DATA_BUF_SIZE + #define DATA_BUF_SIZE 2048 +#endif + +/************************/ +/* Select LOOPBACK_MODE */ +/************************/ +#define LOOPBACK_MAIN_NOBLOCK 0 +#define LOOPBACK_MODE LOOPBACK_MAIN_NOBLOCK + + +/* TCP server Loopback test example */ +int32_t loopback_tcps(uint8_t sn, uint8_t* buf, uint16_t port); + +/* TCP client Loopback test example */ +int32_t loopback_tcpc(uint8_t sn, uint8_t* buf, uint8_t* destip, uint16_t destport); + +/* UDP Loopback test example */ +int32_t loopback_udps(uint8_t sn, uint8_t* buf, uint16_t port); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/W5500/w5500.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/W5500/w5500.c new file mode 100644 index 0000000..68d4cb8 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/W5500/w5500.c @@ -0,0 +1,267 @@ +//***************************************************************************** +// +//! \file w5500.c +//! \brief W5500 HAL Interface. +//! \version 1.0.2 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2014/05/01> V1.0.2 +//! 1. Implicit type casting -> Explicit type casting. Refer to M20140501 +//! Fixed the problem on porting into under 32bit MCU +//! Issued by Mathias ClauBen, wizwiki forum ID Think01 and bobh +//! Thank for your interesting and serious advices. +//! <2013/12/20> V1.0.1 +//! 1. Remove warning +//! 2. WIZCHIP_READ_BUF WIZCHIP_WRITE_BUF in case _WIZCHIP_IO_MODE_SPI_FDM_ +//! for loop optimized(removed). refer to M20131220 +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * Redistributions in binary form must reproduce the above copyright +//! notice, this list of conditions and the following disclaimer in the +//! documentation and/or other materials provided with the distribution. +//! * Neither the name of the nor the names of its +//! contributors may be used to endorse or promote products derived +//! from this software without specific prior written permission. +//! +//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +//! THE POSSIBILITY OF SUCH DAMAGE. +// +//***************************************************************************** +//#include +#include "w5500.h" + +#define _W5500_SPI_VDM_OP_ 0x00 +#define _W5500_SPI_FDM_OP_LEN1_ 0x01 +#define _W5500_SPI_FDM_OP_LEN2_ 0x02 +#define _W5500_SPI_FDM_OP_LEN4_ 0x03 + +#if (_WIZCHIP_ == 5500) +//////////////////////////////////////////////////// + +uint8_t WIZCHIP_READ(uint32_t AddrSel) +{ + uint8_t ret; + uint8_t spi_data[3]; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_); + + if(!WIZCHIP.IF.SPI._read_burst || !WIZCHIP.IF.SPI._write_burst) // byte operation + { + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + } + else // burst operation + { + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + WIZCHIP.IF.SPI._write_burst(spi_data, 3); + } + ret = WIZCHIP.IF.SPI._read_byte(); + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); + return ret; +} + +void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb ) +{ + uint8_t spi_data[4]; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_); + + //if(!WIZCHIP.IF.SPI._read_burst || !WIZCHIP.IF.SPI._write_burst) // byte operation + if(!WIZCHIP.IF.SPI._write_burst) // byte operation + { + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + WIZCHIP.IF.SPI._write_byte(wb); + } + else // burst operation + { + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + spi_data[3] = wb; + WIZCHIP.IF.SPI._write_burst(spi_data, 4); + } + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + +void WIZCHIP_READ_BUF (uint32_t AddrSel, uint8_t* pBuf, uint16_t len) +{ + uint8_t spi_data[3]; + uint16_t i; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_); + + if(!WIZCHIP.IF.SPI._read_burst || !WIZCHIP.IF.SPI._write_burst) // byte operation + { + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + for(i = 0; i < len; i++) + pBuf[i] = WIZCHIP.IF.SPI._read_byte(); + } + else // burst operation + { + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + WIZCHIP.IF.SPI._write_burst(spi_data, 3); + WIZCHIP.IF.SPI._read_burst(pBuf, len); + } + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + +void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len) +{ + uint8_t spi_data[3]; + uint16_t i; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_); + + if(!WIZCHIP.IF.SPI._write_burst) // byte operation + { + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + for(i = 0; i < len; i++) + WIZCHIP.IF.SPI._write_byte(pBuf[i]); + } + else // burst operation + { + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + WIZCHIP.IF.SPI._write_burst(spi_data, 3); + WIZCHIP.IF.SPI._write_burst(pBuf, len); + } + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + + +uint16_t getSn_TX_FSR(uint8_t sn) +{ + uint16_t val=0,val1=0; + + do + { + val1 = WIZCHIP_READ(Sn_TX_FSR(sn)); + val1 = (val1 << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn),1)); + if (val1 != 0) + { + val = WIZCHIP_READ(Sn_TX_FSR(sn)); + val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn),1)); + } + }while (val != val1); + return val; +} + + +uint16_t getSn_RX_RSR(uint8_t sn) +{ + uint16_t val=0,val1=0; + + do + { + val1 = WIZCHIP_READ(Sn_RX_RSR(sn)); + val1 = (val1 << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn),1)); + if (val1 != 0) + { + val = WIZCHIP_READ(Sn_RX_RSR(sn)); + val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn),1)); + } + }while (val != val1); + return val; +} + +void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len) +{ + uint16_t ptr = 0; + uint32_t addrsel = 0; + + if(len == 0) return; + ptr = getSn_TX_WR(sn); + //M20140501 : implict type casting -> explict type casting + //addrsel = (ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3); + addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3); + // + WIZCHIP_WRITE_BUF(addrsel,wizdata, len); + + ptr += len; + setSn_TX_WR(sn,ptr); +} + +void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len) +{ + uint16_t ptr = 0; + uint32_t addrsel = 0; + + if(len == 0) return; + ptr = getSn_RX_RD(sn); + //M20140501 : implict type casting -> explict type casting + //addrsel = ((ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3); + addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3); + // + WIZCHIP_READ_BUF(addrsel, wizdata, len); + ptr += len; + + setSn_RX_RD(sn,ptr); +} + + +void wiz_recv_ignore(uint8_t sn, uint16_t len) +{ + uint16_t ptr = 0; + + ptr = getSn_RX_RD(sn); + ptr += len; + setSn_RX_RD(sn,ptr); +} + +#endif diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/W5500/w5500.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/W5500/w5500.h new file mode 100644 index 0000000..3afc16e --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/W5500/w5500.h @@ -0,0 +1,2163 @@ +//***************************************************************************** +// +//! \file w5500.h +//! \brief W5500 HAL Header File. +//! \version 1.0.0 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * Redistributions in binary form must reproduce the above copyright +//! notice, this list of conditions and the following disclaimer in the +//! documentation and/or other materials provided with the distribution. +//! * Neither the name of the nor the names of its +//! contributors may be used to endorse or promote products derived +//! from this software without specific prior written permission. +//! +//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +//! THE POSSIBILITY OF SUCH DAMAGE. +// +//***************************************************************************** + +// + +#ifndef _W5500_H_ +#define _W5500_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "wizchip_conf.h" + +/// @cond DOXY_APPLY_CODE +#if (_WIZCHIP_ == 5500) +/// @endcond + +#define _W5500_IO_BASE_ 0x00000000 + +#define _W5500_SPI_READ_ (0x00 << 2) //< SPI interface Read operation in Control Phase +#define _W5500_SPI_WRITE_ (0x01 << 2) //< SPI interface Write operation in Control Phase + +#define WIZCHIP_CREG_BLOCK 0x00 //< Common register block +#define WIZCHIP_SREG_BLOCK(N) (1+4*N) //< Socket N register block +#define WIZCHIP_TXBUF_BLOCK(N) (2+4*N) //< Socket N Tx buffer address block +#define WIZCHIP_RXBUF_BLOCK(N) (3+4*N) //< Socket N Rx buffer address block + +#define WIZCHIP_OFFSET_INC(ADDR, N) (ADDR + (N<<8)) //< Increase offset address + + +/////////////////////////////////////// +// Definition For Legacy Chip Driver // +/////////////////////////////////////// +#define IINCHIP_READ(ADDR) WIZCHIP_READ(ADDR) ///< The defined for legacy chip driver +#define IINCHIP_WRITE(ADDR,VAL) WIZCHIP_WRITE(ADDR,VAL) ///< The defined for legacy chip driver +#define IINCHIP_READ_BUF(ADDR,BUF,LEN) WIZCHIP_READ_BUF(ADDR,BUF,LEN) ///< The defined for legacy chip driver +#define IINCHIP_WRITE_BUF(ADDR,BUF,LEN) WIZCHIP_WRITE(ADDR,BUF,LEN) ///< The defined for legacy chip driver + +////////////////////////////// +//-------------------------- defgroup --------------------------------- +/** + * @defgroup W5500 W5500 + * + * @brief WHIZCHIP register defines and I/O functions of @b W5500. + * + * - @ref WIZCHIP_register : @ref Common_register_group and @ref Socket_register_group + * - @ref WIZCHIP_IO_Functions : @ref Basic_IO_function, @ref Common_register_access_function and @ref Socket_register_access_function + */ + + +/** + * @defgroup WIZCHIP_register WIZCHIP register + * @ingroup W5500 + * + * @brief WHIZCHIP register defines register group of @b W5500. + * + * - @ref Common_register_group : Common register group + * - @ref Socket_register_group : \c SOCKET n register group + */ + + +/** + * @defgroup WIZCHIP_IO_Functions WIZCHIP I/O functions + * @ingroup W5500 + * + * @brief This supports the basic I/O functions for @ref WIZCHIP_register. + * + * - Basic I/O function \n + * WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() \n\n + * + * - @ref Common_register_group access functions \n + * -# @b Mode \n + * getMR(), setMR() + * -# @b Interrupt \n + * getIR(), setIR(), getIMR(), setIMR(), getSIR(), setSIR(), getSIMR(), setSIMR(), getINTLEVEL(), setINTLEVEL() + * -# Network Information \n + * getSHAR(), setSHAR(), getGAR(), setGAR(), getSUBR(), setSUBR(), getSIPR(), setSIPR() + * -# @b Retransmission \n + * getRCR(), setRCR(), getRTR(), setRTR() + * -# @b PPPoE \n + * getPTIMER(), setPTIMER(), getPMAGIC(), getPMAGIC(), getPSID(), setPSID(), getPHAR(), setPHAR(), getPMRU(), setPMRU() + * -# ICMP packet \n + * getUIPR(), getUPORTR() + * -# @b etc. \n + * getPHYCFGR(), setPHYCFGR(), getVERSIONR() \n\n + * + * - \ref Socket_register_group access functions \n + * -# SOCKET control \n + * getSn_MR(), setSn_MR(), getSn_CR(), setSn_CR(), getSn_IMR(), setSn_IMR(), getSn_IR(), setSn_IR() + * -# SOCKET information \n + * getSn_SR(), getSn_DHAR(), setSn_DHAR(), getSn_PORT(), setSn_PORT(), getSn_DIPR(), setSn_DIPR(), getSn_DPORT(), setSn_DPORT() + * getSn_MSSR(), setSn_MSSR() + * -# SOCKET communication \n + * getSn_RXBUF_SIZE(), setSn_RXBUF_SIZE(), getSn_TXBUF_SIZE(), setSn_TXBUF_SIZE() \n + * getSn_TX_RD(), getSn_TX_WR(), setSn_TX_WR() \n + * getSn_RX_RD(), setSn_RX_RD(), getSn_RX_WR() \n + * getSn_TX_FSR(), getSn_RX_RSR(), getSn_KPALVTR(), setSn_KPALVTR() + * -# IP header field \n + * getSn_FRAG(), setSn_FRAG(), getSn_TOS(), setSn_TOS() \n + * getSn_TTL(), setSn_TTL() + */ + + + +/** + * @defgroup Common_register_group Common register + * @ingroup WIZCHIP_register + * + * @brief Common register group\n + * It set the basic for the networking\n + * It set the configuration such as interrupt, network information, ICMP, etc. + * @details + * @sa MR : Mode register. + * @sa GAR, SUBR, SHAR, SIPR + * @sa INTLEVEL, IR, IMR, SIR, SIMR : Interrupt. + * @sa _RTR_, _RCR_ : Data retransmission. + * @sa PTIMER, PMAGIC, PHAR, PSID, PMRU : PPPoE. + * @sa UIPR, UPORTR : ICMP message. + * @sa PHYCFGR, VERSIONR : etc. + */ + + + +/** + * @defgroup Socket_register_group Socket register + * @ingroup WIZCHIP_register + * + * @brief Socket register group.\n + * Socket register configures and control SOCKETn which is necessary to data communication. + * @details + * @sa Sn_MR, Sn_CR, Sn_IR, Sn_IMR : SOCKETn Control + * @sa Sn_SR, Sn_PORT, Sn_DHAR, Sn_DIPR, Sn_DPORT : SOCKETn Information + * @sa Sn_MSSR, Sn_TOS, Sn_TTL, Sn_KPALVTR, Sn_FRAG : Internet protocol. + * @sa Sn_RXBUF_SIZE, Sn_TXBUF_SIZE, Sn_TX_FSR, Sn_TX_RD, Sn_TX_WR, Sn_RX_RSR, Sn_RX_RD, Sn_RX_WR : Data communication + */ + + + + /** + * @defgroup Basic_IO_function Basic I/O function + * @ingroup WIZCHIP_IO_Functions + * @brief These are basic input/output functions to read values from register or write values to register. + */ + +/** + * @defgroup Common_register_access_function Common register access functions + * @ingroup WIZCHIP_IO_Functions + * @brief These are functions to access common registers. + */ + +/** + * @defgroup Socket_register_access_function Socket register access functions + * @ingroup WIZCHIP_IO_Functions + * @brief These are functions to access socket registers. + */ + +//------------------------------- defgroup end -------------------------------------------- +//----------------------------- W5500 Common Registers IOMAP ----------------------------- +/** + * @ingroup Common_register_group + * @brief Mode Register address(R/W)\n + * @ref MR is used for S/W reset, ping block mode, PPPoE mode and etc. + * @details Each bit of @ref MR defined as follows. + * + * + * + *
7 6 5 4 3 2 1 0
RST Reserved WOL PB PPPoE Reserved FARP Reserved
+ * - \ref MR_RST : Reset + * - \ref MR_WOL : Wake on LAN + * - \ref MR_PB : Ping block + * - \ref MR_PPPOE : PPPoE mode + * - \ref MR_FARP : Force ARP mode + */ +#define MR (_W5500_IO_BASE_ + (0x0000 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Gateway IP Register address(R/W) + * @details @ref GAR configures the default gateway address. + */ +#define GAR (_W5500_IO_BASE_ + (0x0001 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Subnet mask Register address(R/W) + * @details @ref SUBR configures the subnet mask address. + */ +#define SUBR (_W5500_IO_BASE_ + (0x0005 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Source MAC Register address(R/W) + * @details @ref SHAR configures the source hardware address. + */ +#define SHAR (_W5500_IO_BASE_ + (0x0009 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Source IP Register address(R/W) + * @details @ref SIPR configures the source IP address. + */ +#define SIPR (_W5500_IO_BASE_ + (0x000F << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Set Interrupt low level timer register address(R/W) + * @details @ref INTLEVEL configures the Interrupt Assert Time. + */ +#define INTLEVEL (_W5500_IO_BASE_ + (0x0013 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Interrupt Register(R/W) + * @details @ref IR indicates the interrupt status. Each bit of @ref IR will be still until the bit will be written to by the host. + * If @ref IR is not equal to x00 INTn PIN is asserted to low until it is x00\n\n + * Each bit of @ref IR defined as follows. + * + * + * + *
7 6 5 4 3 2 1 0
CONFLICT UNREACH PPPoE MP Reserved Reserved Reserved Reserved
+ * - \ref IR_CONFLICT : IP conflict + * - \ref IR_UNREACH : Destination unreachable + * - \ref IR_PPPoE : PPPoE connection close + * - \ref IR_MP : Magic packet + */ +#define IR (_W5500_IO_BASE_ + (0x0015 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Interrupt mask register(R/W) + * @details @ref _IMR_ is used to mask interrupts. Each bit of @ref _IMR_ corresponds to each bit of @ref IR. + * When a bit of @ref _IMR_ is and the corresponding bit of @ref IR is an interrupt will be issued. In other words, + * if a bit of @ref _IMR_ is an interrupt will not be issued even if the corresponding bit of @ref IR is \n\n + * Each bit of @ref _IMR_ defined as the following. + * + * + * + *
7 6 5 4 3 2 1 0
IM_IR7 IM_IR6 IM_IR5 IM_IR4 Reserved Reserved Reserved Reserved
+ * - \ref IM_IR7 : IP Conflict Interrupt Mask + * - \ref IM_IR6 : Destination unreachable Interrupt Mask + * - \ref IM_IR5 : PPPoE Close Interrupt Mask + * - \ref IM_IR4 : Magic Packet Interrupt Mask + */ +//M20150401 : Rename SYMBOE ( Re-define error in a compile) +//#define IMR (_W5500_IO_BASE_ + (0x0016 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +#define _IMR_ (_W5500_IO_BASE_ + (0x0016 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Socket Interrupt Register(R/W) + * @details @ref SIR indicates the interrupt status of Socket.\n + * Each bit of @ref SIR be still until @ref Sn_IR is cleared by the host.\n + * If @ref Sn_IR is not equal to x00 the n-th bit of @ref SIR is and INTn PIN is asserted until @ref SIR is x00 */ +#define SIR (_W5500_IO_BASE_ + (0x0017 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Socket Interrupt Mask Register(R/W) + * @details Each bit of @ref SIMR corresponds to each bit of @ref SIR. + * When a bit of @ref SIMR is and the corresponding bit of @ref SIR is Interrupt will be issued. + * In other words, if a bit of @ref SIMR is an interrupt will be not issued even if the corresponding bit of @ref SIR is + */ +#define SIMR (_W5500_IO_BASE_ + (0x0018 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Timeout register address( 1 is 100us )(R/W) + * @details @ref _RTR_ configures the retransmission timeout period. The unit of timeout period is 100us and the default of @ref _RTR_ is x07D0. + * And so the default timeout period is 200ms(100us X 2000). During the time configured by @ref _RTR_, W5500 waits for the peer response + * to the packet that is transmitted by \ref Sn_CR (CONNECT, DISCON, CLOSE, SEND, SEND_MAC, SEND_KEEP command). + * If the peer does not respond within the @ref _RTR_ time, W5500 retransmits the packet or issues timeout. + */ +//M20150401 : Rename SYMBOE ( Re-define error in a compile) +//#define RTR (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +#define _RTR_ (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Retry count register(R/W) + * @details @ref _RCR_ configures the number of time of retransmission. + * When retransmission occurs as many as ref _RCR_+1 Timeout interrupt is issued (@ref Sn_IR_TIMEOUT = '1'). + */ +//M20150401 : Rename SYMBOE ( Re-define error in a compile) +//#define RCR (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_CREG_BLOCK << 3)) +#define _RCR_ (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP LCP Request Timer register in PPPoE mode(R/W) + * @details @ref PTIMER configures the time for sending LCP echo request. The unit of time is 25ms. + */ +#define PTIMER (_W5500_IO_BASE_ + (0x001C << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP LCP Magic number register in PPPoE mode(R/W) + * @details @ref PMAGIC configures the 4bytes magic number to be used in LCP negotiation. + */ +#define PMAGIC (_W5500_IO_BASE_ + (0x001D << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Destination MAC Register address(R/W) + * @details @ref PHAR configures the PPPoE server hardware address that is acquired during PPPoE connection process. + */ +#define PHAR (_W5500_IO_BASE_ + (0x001E << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Session Identification Register(R/W) + * @details @ref PSID configures the PPPoE sever session ID acquired during PPPoE connection process. + */ +#define PSID (_W5500_IO_BASE_ + (0x0024 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Maximum Segment Size(MSS) register(R/W) + * @details @ref PMRU configures the maximum receive unit of PPPoE. + */ +#define PMRU (_W5500_IO_BASE_ + (0x0026 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Unreachable IP register address in UDP mode(R) + * @details W5500 receives an ICMP packet(Destination port unreachable) when data is sent to a port number + * which socket is not open and @ref IR_UNREACH bit of @ref IR becomes and @ref UIPR & @ref UPORTR indicates + * the destination IP address & port number respectively. + */ +#define UIPR (_W5500_IO_BASE_ + (0x0028 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Unreachable Port register address in UDP mode(R) + * @details W5500 receives an ICMP packet(Destination port unreachable) when data is sent to a port number + * which socket is not open and @ref IR_UNREACH bit of @ref IR becomes and @ref UIPR & @ref UPORTR + * indicates the destination IP address & port number respectively. + */ +#define UPORTR (_W5500_IO_BASE_ + (0x002C << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PHY Status Register(R/W) + * @details @ref PHYCFGR configures PHY operation mode and resets PHY. In addition, @ref PHYCFGR indicates the status of PHY such as duplex, Speed, Link. + */ +#define PHYCFGR (_W5500_IO_BASE_ + (0x002E << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +// Reserved (_W5500_IO_BASE_ + (0x002F << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0030 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0031 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0032 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0033 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0034 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0035 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0036 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0037 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0038 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief chip version register address(R) + * @details @ref VERSIONR always indicates the W5500 version as @b 0x04. + */ +#define VERSIONR (_W5500_IO_BASE_ + (0x0039 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + + +//----------------------------- W5500 Socket Registers IOMAP ----------------------------- +/** + * @ingroup Socket_register_group + * @brief socket Mode register(R/W) + * @details @ref Sn_MR configures the option or protocol type of Socket n.\n\n + * Each bit of @ref Sn_MR defined as the following. + * + * + * + *
7 6 5 4 3 2 1 0
MULTI/MFEN BCASTB ND/MC/MMB UCASTB/MIP6B Protocol[3] Protocol[2] Protocol[1] Protocol[0]
+ * - @ref Sn_MR_MULTI : Support UDP Multicasting + * - @ref Sn_MR_BCASTB : Broadcast block in UDP Multicasting + * - @ref Sn_MR_ND : No Delayed Ack(TCP) flag + * - @ref Sn_MR_MC : IGMP version used in UDP mulitcasting + * - @ref Sn_MR_MMB : Multicast Blocking in @ref Sn_MR_MACRAW mode + * - @ref Sn_MR_UCASTB : Unicast Block in UDP Multicating + * - @ref Sn_MR_MIP6B : IPv6 packet Blocking in @ref Sn_MR_MACRAW mode + * - Protocol + * + * + * + * + * + * + *
Protocol[3] Protocol[2] Protocol[1] Protocol[0] @b Meaning
0 0 0 0 Closed
0 0 0 1 TCP
0 0 1 0 UDP
0 1 0 0 MACRAW
+ * - @ref Sn_MR_MACRAW : MAC LAYER RAW SOCK \n + * - @ref Sn_MR_UDP : UDP + * - @ref Sn_MR_TCP : TCP + * - @ref Sn_MR_CLOSE : Unused socket + * @note MACRAW mode should be only used in Socket 0. + */ +#define Sn_MR(N) (_W5500_IO_BASE_ + (0x0000 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Socket command register(R/W) + * @details This is used to set the command for Socket n such as OPEN, CLOSE, CONNECT, LISTEN, SEND, and RECEIVE.\n + * After W5500 accepts the command, the @ref Sn_CR register is automatically cleared to 0x00. + * Even though @ref Sn_CR is cleared to 0x00, the command is still being processed.\n + * To check whether the command is completed or not, please check the @ref Sn_IR or @ref Sn_SR. + * - @ref Sn_CR_OPEN : Initialize or open socket. + * - @ref Sn_CR_LISTEN : Wait connection request in TCP mode(Server mode) + * - @ref Sn_CR_CONNECT : Send connection request in TCP mode(Client mode) + * - @ref Sn_CR_DISCON : Send closing request in TCP mode. + * - @ref Sn_CR_CLOSE : Close socket. + * - @ref Sn_CR_SEND : Update TX buffer pointer and send data. + * - @ref Sn_CR_SEND_MAC : Send data with MAC address, so without ARP process. + * - @ref Sn_CR_SEND_KEEP : Send keep alive message. + * - @ref Sn_CR_RECV : Update RX buffer pointer and receive data. + */ +#define Sn_CR(N) (_W5500_IO_BASE_ + (0x0001 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Socket interrupt register(R) + * @details @ref Sn_IR indicates the status of Socket Interrupt such as establishment, termination, receiving data, timeout).\n + * When an interrupt occurs and the corresponding bit of @ref Sn_IMR is the corresponding bit of @ref Sn_IR becomes \n + * In order to clear the @ref Sn_IR bit, the host should write the bit to \n + * + * + * + *
7 6 5 4 3 2 1 0
Reserved Reserved Reserved SEND_OK TIMEOUT RECV DISCON CON
+ * - \ref Sn_IR_SENDOK : SEND_OK Interrupt + * - \ref Sn_IR_TIMEOUT : TIMEOUT Interrupt + * - \ref Sn_IR_RECV : RECV Interrupt + * - \ref Sn_IR_DISCON : DISCON Interrupt + * - \ref Sn_IR_CON : CON Interrupt + */ +#define Sn_IR(N) (_W5500_IO_BASE_ + (0x0002 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Socket status register(R) + * @details @ref Sn_SR indicates the status of Socket n.\n + * The status of Socket n is changed by @ref Sn_CR or some special control packet as SYN, FIN packet in TCP. + * @par Normal status + * - @ref SOCK_CLOSED : Closed + * - @ref SOCK_INIT : Initiate state + * - @ref SOCK_LISTEN : Listen state + * - @ref SOCK_ESTABLISHED : Success to connect + * - @ref SOCK_CLOSE_WAIT : Closing state + * - @ref SOCK_UDP : UDP socket + * - @ref SOCK_MACRAW : MAC raw mode socket + *@par Temporary status during changing the status of Socket n. + * - @ref SOCK_SYNSENT : This indicates Socket n sent the connect-request packet (SYN packet) to a peer. + * - @ref SOCK_SYNRECV : It indicates Socket n successfully received the connect-request packet (SYN packet) from a peer. + * - @ref SOCK_FIN_WAIT : Connection state + * - @ref SOCK_CLOSING : Closing state + * - @ref SOCK_TIME_WAIT : Closing state + * - @ref SOCK_LAST_ACK : Closing state + */ +#define Sn_SR(N) (_W5500_IO_BASE_ + (0x0003 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief source port register(R/W) + * @details @ref Sn_PORT configures the source port number of Socket n. + * It is valid when Socket n is used in TCP/UDP mode. It should be set before OPEN command is ordered. + */ +#define Sn_PORT(N) (_W5500_IO_BASE_ + (0x0004 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Peer MAC register address(R/W) + * @details @ref Sn_DHAR configures the destination hardware address of Socket n when using SEND_MAC command in UDP mode or + * it indicates that it is acquired in ARP-process by CONNECT/SEND command. + */ +#define Sn_DHAR(N) (_W5500_IO_BASE_ + (0x0006 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Peer IP register address(R/W) + * @details @ref Sn_DIPR configures or indicates the destination IP address of Socket n. It is valid when Socket n is used in TCP/UDP mode. + * In TCP client mode, it configures an IP address of TCP serverbefore CONNECT command. + * In TCP server mode, it indicates an IP address of TCP clientafter successfully establishing connection. + * In UDP mode, it configures an IP address of peer to be received the UDP packet by SEND or SEND_MAC command. + */ +#define Sn_DIPR(N) (_W5500_IO_BASE_ + (0x000C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Peer port register address(R/W) + * @details @ref Sn_DPORT configures or indicates the destination port number of Socket n. It is valid when Socket n is used in TCP/UDP mode. + * In TCP clientmode, it configures the listen port number of TCP serverbefore CONNECT command. + * In TCP Servermode, it indicates the port number of TCP client after successfully establishing connection. + * In UDP mode, it configures the port number of peer to be transmitted the UDP packet by SEND/SEND_MAC command. + */ +#define Sn_DPORT(N) (_W5500_IO_BASE_ + (0x0010 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Maximum Segment Size(Sn_MSSR0) register address(R/W) + * @details @ref Sn_MSSR configures or indicates the MTU(Maximum Transfer Unit) of Socket n. + */ +#define Sn_MSSR(N) (_W5500_IO_BASE_ + (0x0012 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +// Reserved (_W5500_IO_BASE_ + (0x0014 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief IP Type of Service(TOS) Register(R/W) + * @details @ref Sn_TOS configures the TOS(Type Of Service field in IP Header) of Socket n. + * It is set before OPEN command. + */ +#define Sn_TOS(N) (_W5500_IO_BASE_ + (0x0015 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +/** + * @ingroup Socket_register_group + * @brief IP Time to live(TTL) Register(R/W) + * @details @ref Sn_TTL configures the TTL(Time To Live field in IP header) of Socket n. + * It is set before OPEN command. + */ +#define Sn_TTL(N) (_W5500_IO_BASE_ + (0x0016 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0017 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0018 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001A << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001D << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Receive memory size register(R/W) + * @details @ref Sn_RXBUF_SIZE configures the RX buffer block size of Socket n. + * Socket n RX Buffer Block size can be configured with 1,2,4,8, and 16 Kbytes. + * If a different size is configured, the data cannot be normally received from a peer. + * Although Socket n RX Buffer Block size is initially configured to 2Kbytes, + * user can re-configure its size using @ref Sn_RXBUF_SIZE. The total sum of @ref Sn_RXBUF_SIZE can not be exceed 16Kbytes. + * When exceeded, the data reception error is occurred. + */ +#define Sn_RXBUF_SIZE(N) (_W5500_IO_BASE_ + (0x001E << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory size register(R/W) + * @details @ref Sn_TXBUF_SIZE configures the TX buffer block size of Socket n. Socket n TX Buffer Block size can be configured with 1,2,4,8, and 16 Kbytes. + * If a different size is configured, the data can�t be normally transmitted to a peer. + * Although Socket n TX Buffer Block size is initially configured to 2Kbytes, + * user can be re-configure its size using @ref Sn_TXBUF_SIZE. The total sum of @ref Sn_TXBUF_SIZE can not be exceed 16Kbytes. + * When exceeded, the data transmission error is occurred. + */ +#define Sn_TXBUF_SIZE(N) (_W5500_IO_BASE_ + (0x001F << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit free memory size register(R) + * @details @ref Sn_TX_FSR indicates the free size of Socket n TX Buffer Block. It is initialized to the configured size by @ref Sn_TXBUF_SIZE. + * Data bigger than @ref Sn_TX_FSR should not be saved in the Socket n TX Buffer because the bigger data overwrites the previous saved data not yet sent. + * Therefore, check before saving the data to the Socket n TX Buffer, and if data is equal or smaller than its checked size, + * transmit the data with SEND/SEND_MAC command after saving the data in Socket n TX buffer. But, if data is bigger than its checked size, + * transmit the data after dividing into the checked size and saving in the Socket n TX buffer. + */ +#define Sn_TX_FSR(N) (_W5500_IO_BASE_ + (0x0020 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory read pointer register address(R) + * @details @ref Sn_TX_RD is initialized by OPEN command. However, if Sn_MR(P[3:0]) is TCP mode(001, it is re-initialized while connecting with TCP. + * After its initialization, it is auto-increased by SEND command. + * SEND command transmits the saved data from the current @ref Sn_TX_RD to the @ref Sn_TX_WR in the Socket n TX Buffer. + * After transmitting the saved data, the SEND command increases the @ref Sn_TX_RD as same as the @ref Sn_TX_WR. + * If its increment value exceeds the maximum value 0xFFFF, (greater than 0x10000 and the carry bit occurs), + * then the carry bit is ignored and will automatically update with the lower 16bits value. + */ +#define Sn_TX_RD(N) (_W5500_IO_BASE_ + (0x0022 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory write pointer register address(R/W) + * @details @ref Sn_TX_WR is initialized by OPEN command. However, if Sn_MR(P[3:0]) is TCP mode(001, it is re-initialized while connecting with TCP.\n + * It should be read or be updated like as follows.\n + * 1. Read the starting address for saving the transmitting data.\n + * 2. Save the transmitting data from the starting address of Socket n TX buffer.\n + * 3. After saving the transmitting data, update @ref Sn_TX_WR to the increased value as many as transmitting data size. + * If the increment value exceeds the maximum value 0xFFFF(greater than 0x10000 and the carry bit occurs), + * then the carry bit is ignored and will automatically update with the lower 16bits value.\n + * 4. Transmit the saved data in Socket n TX Buffer by using SEND/SEND command + */ +#define Sn_TX_WR(N) (_W5500_IO_BASE_ + (0x0024 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Received data size register(R) + * @details @ref Sn_RX_RSR indicates the data size received and saved in Socket n RX Buffer. + * @ref Sn_RX_RSR does not exceed the @ref Sn_RXBUF_SIZE and is calculated as the difference between + * �Socket n RX Write Pointer (@ref Sn_RX_WR)and �Socket n RX Read Pointer (@ref Sn_RX_RD) + */ +#define Sn_RX_RSR(N) (_W5500_IO_BASE_ + (0x0026 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Read point of Receive memory(R/W) + * @details @ref Sn_RX_RD is initialized by OPEN command. Make sure to be read or updated as follows.\n + * 1. Read the starting save address of the received data.\n + * 2. Read data from the starting address of Socket n RX Buffer.\n + * 3. After reading the received data, Update @ref Sn_RX_RD to the increased value as many as the reading size. + * If the increment value exceeds the maximum value 0xFFFF, that is, is greater than 0x10000 and the carry bit occurs, + * update with the lower 16bits value ignored the carry bit.\n + * 4. Order RECV command is for notifying the updated @ref Sn_RX_RD to W5500. + */ +#define Sn_RX_RD(N) (_W5500_IO_BASE_ + (0x0028 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Write point of Receive memory(R) + * @details @ref Sn_RX_WR is initialized by OPEN command and it is auto-increased by the data reception. + * If the increased value exceeds the maximum value 0xFFFF, (greater than 0x10000 and the carry bit occurs), + * then the carry bit is ignored and will automatically update with the lower 16bits value. + */ +#define Sn_RX_WR(N) (_W5500_IO_BASE_ + (0x002A << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief socket interrupt mask register(R) + * @details @ref Sn_IMR masks the interrupt of Socket n. + * Each bit corresponds to each bit of @ref Sn_IR. When a Socket n Interrupt is occurred and the corresponding bit of @ref Sn_IMR is + * the corresponding bit of @ref Sn_IR becomes When both the corresponding bit of @ref Sn_IMR and @ref Sn_IR are and the n-th bit of @ref IR is + * Host is interrupted by asserted INTn PIN to low. + */ +#define Sn_IMR(N) (_W5500_IO_BASE_ + (0x002C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Fragment field value in IP header register(R/W) + * @details @ref Sn_FRAG configures the FRAG(Fragment field in IP header). + */ +#define Sn_FRAG(N) (_W5500_IO_BASE_ + (0x002D << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Keep Alive Timer register(R/W) + * @details @ref Sn_KPALVTR configures the transmitting timer of �KEEP ALIVE(KA)packet of SOCKETn. It is valid only in TCP mode, + * and ignored in other modes. The time unit is 5s. + * KA packet is transmittable after @ref Sn_SR is changed to SOCK_ESTABLISHED and after the data is transmitted or received to/from a peer at least once. + * In case of '@ref Sn_KPALVTR > 0', W5500 automatically transmits KA packet after time-period for checking the TCP connection (Auto-keepalive-process). + * In case of '@ref Sn_KPALVTR = 0', Auto-keep-alive-process will not operate, + * and KA packet can be transmitted by SEND_KEEP command by the host (Manual-keep-alive-process). + * Manual-keep-alive-process is ignored in case of '@ref Sn_KPALVTR > 0'. + */ +#define Sn_KPALVTR(N) (_W5500_IO_BASE_ + (0x002F << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +//#define Sn_TSR(N) (_W5500_IO_BASE_ + (0x0030 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + + +//----------------------------- W5500 Register values ----------------------------- + +/* MODE register values */ +/** + * @brief Reset + * @details If this bit is All internal registers will be initialized. It will be automatically cleared as after S/W reset. + */ +#define MR_RST 0x80 + +/** + * @brief Wake on LAN + * @details 0 : Disable WOL mode\n + * 1 : Enable WOL mode\n + * If WOL mode is enabled and the received magic packet over UDP has been normally processed, the Interrupt PIN (INTn) asserts to low. + * When using WOL mode, the UDP Socket should be opened with any source port number. (Refer to Socket n Mode Register (@ref Sn_MR) for opening Socket.) + * @note The magic packet over UDP supported by W5500 consists of 6 bytes synchronization stream (xFFFFFFFFFFFF and + * 16 times Target MAC address stream in UDP payload. The options such like password are ignored. You can use any UDP source port number for WOL mode. + */ +#define MR_WOL 0x20 + +/** + * @brief Ping block + * @details 0 : Disable Ping block\n + * 1 : Enable Ping block\n + * If the bit is it blocks the response to a ping request. + */ +#define MR_PB 0x10 + +/** + * @brief Enable PPPoE + * @details 0 : DisablePPPoE mode\n + * 1 : EnablePPPoE mode\n + * If you use ADSL, this bit should be + */ +#define MR_PPPOE 0x08 + +/** + * @brief Enable UDP_FORCE_ARP CHECHK + * @details 0 : Disable Force ARP mode\n + * 1 : Enable Force ARP mode\n + * In Force ARP mode, It forces on sending ARP Request whenever data is sent. + */ +#define MR_FARP 0x02 + +/* IR register values */ +/** + * @brief Check IP conflict. + * @details Bit is set as when own source IP address is same with the sender IP address in the received ARP request. + */ +#define IR_CONFLICT 0x80 + +/** + * @brief Get the destination unreachable message in UDP sending. + * @details When receiving the ICMP (Destination port unreachable) packet, this bit is set as + * When this bit is Destination Information such as IP address and Port number may be checked with the corresponding @ref UIPR & @ref UPORTR. + */ +#define IR_UNREACH 0x40 + +/** + * @brief Get the PPPoE close message. + * @details When PPPoE is disconnected during PPPoE mode, this bit is set. + */ +#define IR_PPPoE 0x20 + +/** + * @brief Get the magic packet interrupt. + * @details When WOL mode is enabled and receives the magic packet over UDP, this bit is set. + */ +#define IR_MP 0x10 + + +/* PHYCFGR register value */ +#define PHYCFGR_RST ~(1<<7) //< For PHY reset, must operate AND mask. +#define PHYCFGR_OPMD (1<<6) // Configre PHY with OPMDC value +#define PHYCFGR_OPMDC_ALLA (7<<3) +#define PHYCFGR_OPMDC_PDOWN (6<<3) +#define PHYCFGR_OPMDC_NA (5<<3) +#define PHYCFGR_OPMDC_100FA (4<<3) +#define PHYCFGR_OPMDC_100F (3<<3) +#define PHYCFGR_OPMDC_100H (2<<3) +#define PHYCFGR_OPMDC_10F (1<<3) +#define PHYCFGR_OPMDC_10H (0<<3) +#define PHYCFGR_DPX_FULL (1<<2) +#define PHYCFGR_DPX_HALF (0<<2) +#define PHYCFGR_SPD_100 (1<<1) +#define PHYCFGR_SPD_10 (0<<1) +#define PHYCFGR_LNK_ON (1<<0) +#define PHYCFGR_LNK_OFF (0<<0) + +/* IMR register values */ +/** + * @brief IP Conflict Interrupt Mask. + * @details 0: Disable IP Conflict Interrupt\n + * 1: Enable IP Conflict Interrupt + */ +#define IM_IR7 0x80 + +/** + * @brief Destination unreachable Interrupt Mask. + * @details 0: Disable Destination unreachable Interrupt\n + * 1: Enable Destination unreachable Interrupt + */ +#define IM_IR6 0x40 + +/** + * @brief PPPoE Close Interrupt Mask. + * @details 0: Disable PPPoE Close Interrupt\n + * 1: Enable PPPoE Close Interrupt + */ +#define IM_IR5 0x20 + +/** + * @brief Magic Packet Interrupt Mask. + * @details 0: Disable Magic Packet Interrupt\n + * 1: Enable Magic Packet Interrupt + */ +#define IM_IR4 0x10 + +/* Sn_MR Default values */ +/** + * @brief Support UDP Multicasting + * @details 0 : disable Multicasting\n + * 1 : enable Multicasting\n + * This bit is applied only during UDP mode(P[3:0] = 010.\n + * To use multicasting, @ref Sn_DIPR & @ref Sn_DPORT should be respectively configured with the multicast group IP address & port number + * before Socket n is opened by OPEN command of @ref Sn_CR. + */ +#define Sn_MR_MULTI 0x80 + +/** + * @brief Broadcast block in UDP Multicasting. + * @details 0 : disable Broadcast Blocking\n + * 1 : enable Broadcast Blocking\n + * This bit blocks to receive broadcasting packet during UDP mode(P[3:0] = 010.\m + * In addition, This bit does when MACRAW mode(P[3:0] = 100 + */ +#define Sn_MR_BCASTB 0x40 + +/** + * @brief No Delayed Ack(TCP), Multicast flag + * @details 0 : Disable No Delayed ACK option\n + * 1 : Enable No Delayed ACK option\n + * This bit is applied only during TCP mode (P[3:0] = 001.\n + * When this bit is It sends the ACK packet without delay as soon as a Data packet is received from a peer.\n + * When this bit is It sends the ACK packet after waiting for the timeout time configured by @ref _RTR_. + */ +#define Sn_MR_ND 0x20 + +/** + * @brief Unicast Block in UDP Multicasting + * @details 0 : disable Unicast Blocking\n + * 1 : enable Unicast Blocking\n + * This bit blocks receiving the unicast packet during UDP mode(P[3:0] = 010 and MULTI = + */ +#define Sn_MR_UCASTB 0x10 + +/** + * @brief MAC LAYER RAW SOCK + * @details This configures the protocol mode of Socket n. + * @note MACRAW mode should be only used in Socket 0. + */ +#define Sn_MR_MACRAW 0x04 + +#define Sn_MR_IPRAW 0x03 /**< IP LAYER RAW SOCK */ + +/** + * @brief UDP + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_UDP 0x02 + +/** + * @brief TCP + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_TCP 0x01 + +/** + * @brief Unused socket + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_CLOSE 0x00 + +/* Sn_MR values used with Sn_MR_MACRAW */ +/** + * @brief MAC filter enable in @ref Sn_MR_MACRAW mode + * @details 0 : disable MAC Filtering\n + * 1 : enable MAC Filtering\n + * This bit is applied only during MACRAW mode(P[3:0] = 100.\n + * When set as W5500 can only receive broadcasting packet or packet sent to itself. + * When this bit is W5500 can receive all packets on Ethernet. + * If user wants to implement Hybrid TCP/IP stack, + * it is recommended that this bit is set as for reducing host overhead to process the all received packets. + */ +#define Sn_MR_MFEN Sn_MR_MULTI + +/** + * @brief Multicast Blocking in @ref Sn_MR_MACRAW mode + * @details 0 : using IGMP version 2\n + * 1 : using IGMP version 1\n + * This bit is applied only during UDP mode(P[3:0] = 010 and MULTI = + * It configures the version for IGMP messages (Join/Leave/Report). + */ +#define Sn_MR_MMB Sn_MR_ND + +/** + * @brief IPv6 packet Blocking in @ref Sn_MR_MACRAW mode + * @details 0 : disable IPv6 Blocking\n + * 1 : enable IPv6 Blocking\n + * This bit is applied only during MACRAW mode (P[3:0] = 100. It blocks to receiving the IPv6 packet. + */ +#define Sn_MR_MIP6B Sn_MR_UCASTB + +/* Sn_MR value used with Sn_MR_UDP & Sn_MR_MULTI */ +/** + * @brief IGMP version used in UDP mulitcasting + * @details 0 : disable Multicast Blocking\n + * 1 : enable Multicast Blocking\n + * This bit is applied only when MACRAW mode(P[3:0] = 100. It blocks to receive the packet with multicast MAC address. + */ +#define Sn_MR_MC Sn_MR_ND + +/* Sn_MR alternate values */ +/** + * @brief For Berkeley Socket API + */ +#define SOCK_STREAM Sn_MR_TCP + +/** + * @brief For Berkeley Socket API + */ +#define SOCK_DGRAM Sn_MR_UDP + + +/* Sn_CR values */ +/** + * @brief Initialize or open socket + * @details Socket n is initialized and opened according to the protocol selected in Sn_MR(P3:P0). + * The table below shows the value of @ref Sn_SR corresponding to @ref Sn_MR.\n + * + * + * + * + * + * + *
\b Sn_MR (P[3:0]) \b Sn_SR
Sn_MR_CLOSE (000)
Sn_MR_TCP (001) SOCK_INIT (0x13)
Sn_MR_UDP (010) SOCK_UDP (0x22)
S0_MR_MACRAW (100) SOCK_MACRAW (0x02)
+ */ +#define Sn_CR_OPEN 0x01 + +/** + * @brief Wait connection request in TCP mode(Server mode) + * @details This is valid only in TCP mode (\ref Sn_MR(P3:P0) = \ref Sn_MR_TCP). + * In this mode, Socket n operates as a TCP serverand waits for connection-request (SYN packet) from any TCP client + * The @ref Sn_SR changes the state from \ref SOCK_INIT to \ref SOCKET_LISTEN. + * When a TCP clientconnection request is successfully established, + * the @ref Sn_SR changes from SOCK_LISTEN to SOCK_ESTABLISHED and the @ref Sn_IR(0) becomes + * But when a TCP clientconnection request is failed, @ref Sn_IR(3) becomes and the status of @ref Sn_SR changes to SOCK_CLOSED. + */ +#define Sn_CR_LISTEN 0x02 + +/** + * @brief Send connection request in TCP mode(Client mode) + * @details To connect, a connect-request (SYN packet) is sent to TCP serverconfigured by @ref Sn_DIPR & Sn_DPORT(destination address & port). + * If the connect-request is successful, the @ref Sn_SR is changed to @ref SOCK_ESTABLISHED and the Sn_IR(0) becomes \n\n + * The connect-request fails in the following three cases.\n + * 1. When a @b ARPTO occurs (@ref Sn_IR[3] = ) because destination hardware address is not acquired through the ARP-process.\n + * 2. When a @b SYN/ACK packet is not received and @b TCPTO (Sn_IR(3) = )\n + * 3. When a @b RST packet is received instead of a @b SYN/ACK packet. In these cases, @ref Sn_SR is changed to @ref SOCK_CLOSED. + * @note This is valid only in TCP mode and operates when Socket n acts as TCP client + */ +#define Sn_CR_CONNECT 0x04 + +/** + * @brief Send closing request in TCP mode + * @details Regardless of TCP serveror TCP client the DISCON command processes the disconnect-process (b>Active closeor Passive close.\n + * @par Active close + * it transmits disconnect-request(FIN packet) to the connected peer\n + * @par Passive close + * When FIN packet is received from peer, a FIN packet is replied back to the peer.\n + * @details When the disconnect-process is successful (that is, FIN/ACK packet is received successfully), @ref Sn_SR is changed to @ref SOCK_CLOSED.\n + * Otherwise, TCPTO occurs (\ref Sn_IR(3)='1') and then @ref Sn_SR is changed to @ref SOCK_CLOSED. + * @note Valid only in TCP mode. + */ +#define Sn_CR_DISCON 0x08 + +/** + * @brief Close socket + * @details Sn_SR is changed to @ref SOCK_CLOSED. + */ +#define Sn_CR_CLOSE 0x10 + +/** + * @brief Update TX buffer pointer and send data + * @details SEND transmits all the data in the Socket n TX buffer.\n + * For more details, please refer to Socket n TX Free Size Register (@ref Sn_TX_FSR), Socket n, + * TX Write Pointer Register(@ref Sn_TX_WR), and Socket n TX Read Pointer Register(@ref Sn_TX_RD). + */ +#define Sn_CR_SEND 0x20 + +/** + * @brief Send data with MAC address, so without ARP process + * @details The basic operation is same as SEND.\n + * Normally SEND transmits data after destination hardware address is acquired by the automatic ARP-process(Address Resolution Protocol).\n + * But SEND_MAC transmits data without the automatic ARP-process.\n + * In this case, the destination hardware address is acquired from @ref Sn_DHAR configured by host, instead of APR-process. + * @note Valid only in UDP mode. + */ +#define Sn_CR_SEND_MAC 0x21 + +/** + * @brief Send keep alive message + * @details It checks the connection status by sending 1byte keep-alive packet.\n + * If the peer can not respond to the keep-alive packet during timeout time, the connection is terminated and the timeout interrupt will occur. + * @note Valid only in TCP mode. + */ +#define Sn_CR_SEND_KEEP 0x22 + +/** + * @brief Update RX buffer pointer and receive data + * @details RECV completes the processing of the received data in Socket n RX Buffer by using a RX read pointer register (@ref Sn_RX_RD).\n + * For more details, refer to Socket n RX Received Size Register (@ref Sn_RX_RSR), Socket n RX Write Pointer Register (@ref Sn_RX_WR), + * and Socket n RX Read Pointer Register (@ref Sn_RX_RD). + */ +#define Sn_CR_RECV 0x40 + +/* Sn_IR values */ +/** + * @brief SEND_OK Interrupt + * @details This is issued when SEND command is completed. + */ +#define Sn_IR_SENDOK 0x10 + +/** + * @brief TIMEOUT Interrupt + * @details This is issued when ARPTO or TCPTO occurs. + */ +#define Sn_IR_TIMEOUT 0x08 + +/** + * @brief RECV Interrupt + * @details This is issued whenever data is received from a peer. + */ +#define Sn_IR_RECV 0x04 + +/** + * @brief DISCON Interrupt + * @details This is issued when FIN or FIN/ACK packet is received from a peer. + */ +#define Sn_IR_DISCON 0x02 + +/** + * @brief CON Interrupt + * @details This is issued one time when the connection with peer is successful and then @ref Sn_SR is changed to @ref SOCK_ESTABLISHED. + */ +#define Sn_IR_CON 0x01 + +/* Sn_SR values */ +/** + * @brief Closed + * @details This indicates that Socket n is released.\n + * When DICON, CLOSE command is ordered, or when a timeout occurs, it is changed to @ref SOCK_CLOSED regardless of previous status. + */ +#define SOCK_CLOSED 0x00 + +/** + * @brief Initiate state + * @details This indicates Socket n is opened with TCP mode.\n + * It is changed to @ref SOCK_INIT when @ref Sn_MR(P[3:0]) = 001 and OPEN command is ordered.\n + * After @ref SOCK_INIT, user can use LISTEN /CONNECT command. + */ +#define SOCK_INIT 0x13 + +/** + * @brief Listen state + * @details This indicates Socket n is operating as TCP servermode and waiting for connection-request (SYN packet) from a peer TCP client.\n + * It will change to @ref SOCK_ESTALBLISHED when the connection-request is successfully accepted.\n + * Otherwise it will change to @ref SOCK_CLOSED after TCPTO @ref Sn_IR(TIMEOUT) = '1') is occurred. + */ +#define SOCK_LISTEN 0x14 + +/** + * @brief Connection state + * @details This indicates Socket n sent the connect-request packet (SYN packet) to a peer.\n + * It is temporarily shown when @ref Sn_SR is changed from @ref SOCK_INIT to @ref SOCK_ESTABLISHED by CONNECT command.\n + * If connect-accept(SYN/ACK packet) is received from the peer at SOCK_SYNSENT, it changes to @ref SOCK_ESTABLISHED.\n + * Otherwise, it changes to @ref SOCK_CLOSED after TCPTO (@ref Sn_IR[TIMEOUT] = '1') is occurred. + */ +#define SOCK_SYNSENT 0x15 + +/** + * @brief Connection state + * @details It indicates Socket n successfully received the connect-request packet (SYN packet) from a peer.\n + * If socket n sends the response (SYN/ACK packet) to the peer successfully, it changes to @ref SOCK_ESTABLISHED. \n + * If not, it changes to @ref SOCK_CLOSED after timeout (@ref Sn_IR[TIMEOUT] = '1') is occurred. + */ +#define SOCK_SYNRECV 0x16 + +/** + * @brief Success to connect + * @details This indicates the status of the connection of Socket n.\n + * It changes to @ref SOCK_ESTABLISHED when the TCP SERVERprocessed the SYN packet from the TCP CLIENTduring @ref SOCK_LISTEN, or + * when the CONNECT command is successful.\n + * During @ref SOCK_ESTABLISHED, DATA packet can be transferred using SEND or RECV command. + */ +#define SOCK_ESTABLISHED 0x17 + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and passive-close.\n + * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_FIN_WAIT 0x18 + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and passive-close.\n + * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_CLOSING 0x1A + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and passive-close.\n + * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_TIME_WAIT 0x1B + +/** + * @brief Closing state + * @details This indicates Socket n received the disconnect-request (FIN packet) from the connected peer.\n + * This is half-closing status, and data can be transferred.\n + * For full-closing, DISCON command is used. But For just-closing, CLOSE command is used. + */ +#define SOCK_CLOSE_WAIT 0x1C + +/** + * @brief Closing state + * @details This indicates Socket n is waiting for the response (FIN/ACK packet) to the disconnect-request (FIN packet) by passive-close.\n + * It changes to @ref SOCK_CLOSED when Socket n received the response successfully, or when timeout(@ref Sn_IR[TIMEOUT] = '1') is occurred. + */ +#define SOCK_LAST_ACK 0x1D + +/** + * @brief UDP socket + * @details This indicates Socket n is opened in UDP mode(@ref Sn_MR(P[3:0]) = '010').\n + * It changes to SOCK_UDP when @ref Sn_MR(P[3:0]) = '010' and @ref Sn_CR_OPEN command is ordered.\n + * Unlike TCP mode, data can be transfered without the connection-process. + */ +#define SOCK_UDP 0x22 + +#define SOCK_IPRAW 0x32 /**< IP raw mode socket */ + +/** + * @brief MAC raw mode socket + * @details This indicates Socket 0 is opened in MACRAW mode (S0_MR(P[3:0]) = 100and is valid only in Socket 0.\n + * It changes to SOCK_MACRAW when S0_MR(P[3:0] = 100and OPEN command is ordered.\n + * Like UDP mode socket, MACRAW mode Socket 0 can transfer a MAC packet (Ethernet frame) without the connection-process. + */ +#define SOCK_MACRAW 0x42 + +//#define SOCK_PPPOE 0x5F + +/* IP PROTOCOL */ +#define IPPROTO_IP 0 //< Dummy for IP +#define IPPROTO_ICMP 1 //< Control message protocol +#define IPPROTO_IGMP 2 //< Internet group management protocol +#define IPPROTO_GGP 3 //< Gateway^2 (deprecated) +#define IPPROTO_TCP 6 //< TCP +#define IPPROTO_PUP 12 //< PUP +#define IPPROTO_UDP 17 //< UDP +#define IPPROTO_IDP 22 //< XNS idp +#define IPPROTO_ND 77 //< UNOFFICIAL net disk protocol +#define IPPROTO_RAW 255 //< Raw IP packet + + +/** + * @brief Enter a critical section + * + * @details It is provided to protect your shared code which are executed without distribution. \n \n + * + * In non-OS environment, It can be just implemented by disabling whole interrupt.\n + * In OS environment, You can replace it to critical section api supported by OS. + * + * \sa WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() + * \sa WIZCHIP_CRITICAL_EXIT() + */ +#define WIZCHIP_CRITICAL_ENTER() WIZCHIP.CRIS._enter() + +#ifdef _exit +#undef _exit +#endif + +/** + * @brief Exit a critical section + * + * @details It is provided to protect your shared code which are executed without distribution. \n\n + * + * In non-OS environment, It can be just implemented by disabling whole interrupt. \n + * In OS environment, You can replace it to critical section api supported by OS. + * + * @sa WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() + * @sa WIZCHIP_CRITICAL_ENTER() + */ +#define WIZCHIP_CRITICAL_EXIT() WIZCHIP.CRIS._exit() + + +//////////////////////// +// Basic I/O Function // +//////////////////////// + +/** + * @ingroup Basic_IO_function + * @brief It reads 1 byte value from a register. + * @param AddrSel Register address + * @return The value of register + */ +uint8_t WIZCHIP_READ (uint32_t AddrSel); + +/** + * @ingroup Basic_IO_function + * @brief It writes 1 byte value to a register. + * @param AddrSel Register address + * @param wb Write data + * @return void + */ +void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb ); + +/** + * @ingroup Basic_IO_function + * @brief It reads sequence data from registers. + * @param AddrSel Register address + * @param pBuf Pointer buffer to read data + * @param len Data length + */ +void WIZCHIP_READ_BUF (uint32_t AddrSel, uint8_t* pBuf, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It writes sequence data to registers. + * @param AddrSel Register address + * @param pBuf Pointer buffer to write data + * @param len Data length + */ +void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len); + +///////////////////////////////// +// Common Register I/O function // +///////////////////////////////// +/** + * @ingroup Common_register_access_function + * @brief Set Mode Register + * @param (uint8_t)mr The value to be set. + * @sa getMR() + */ +#define setMR(mr) \ + WIZCHIP_WRITE(MR,mr) + + +/** + * @ingroup Common_register_access_function + * @brief Get Mode Register + * @return uint8_t. The value of Mode register. + * @sa setMR() + */ +#define getMR() \ + WIZCHIP_READ(MR) + +/** + * @ingroup Common_register_access_function + * @brief Set gateway IP address + * @param (uint8_t*)gar Pointer variable to set gateway IP address. It should be allocated 4 bytes. + * @sa getGAR() + */ +#define setGAR(gar) \ + WIZCHIP_WRITE_BUF(GAR,gar,4) + +/** + * @ingroup Common_register_access_function + * @brief Get gateway IP address + * @param (uint8_t*)gar Pointer variable to get gateway IP address. It should be allocated 4 bytes. + * @sa setGAR() + */ +#define getGAR(gar) \ + WIZCHIP_READ_BUF(GAR,gar,4) + +/** + * @ingroup Common_register_access_function + * @brief Set subnet mask address + * @param (uint8_t*)subr Pointer variable to set subnet mask address. It should be allocated 4 bytes. + * @sa getSUBR() + */ +#define setSUBR(subr) \ + WIZCHIP_WRITE_BUF(SUBR, subr,4) + + +/** + * @ingroup Common_register_access_function + * @brief Get subnet mask address + * @param (uint8_t*)subr Pointer variable to get subnet mask address. It should be allocated 4 bytes. + * @sa setSUBR() + */ +#define getSUBR(subr) \ + WIZCHIP_READ_BUF(SUBR, subr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Set local MAC address + * @param (uint8_t*)shar Pointer variable to set local MAC address. It should be allocated 6 bytes. + * @sa getSHAR() + */ +#define setSHAR(shar) \ + WIZCHIP_WRITE_BUF(SHAR, shar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Get local MAC address + * @param (uint8_t*)shar Pointer variable to get local MAC address. It should be allocated 6 bytes. + * @sa setSHAR() + */ +#define getSHAR(shar) \ + WIZCHIP_READ_BUF(SHAR, shar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Set local IP address + * @param (uint8_t*)sipr Pointer variable to set local IP address. It should be allocated 4 bytes. + * @sa getSIPR() + */ +#define setSIPR(sipr) \ + WIZCHIP_WRITE_BUF(SIPR, sipr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Get local IP address + * @param (uint8_t*)sipr Pointer variable to get local IP address. It should be allocated 4 bytes. + * @sa setSIPR() + */ +#define getSIPR(sipr) \ + WIZCHIP_READ_BUF(SIPR, sipr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Set INTLEVEL register + * @param (uint16_t)intlevel Value to set @ref INTLEVEL register. + * @sa getINTLEVEL() + */ +#define setINTLEVEL(intlevel) {\ + WIZCHIP_WRITE(INTLEVEL, (uint8_t)(intlevel >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(INTLEVEL,1), (uint8_t) intlevel); \ + } + + +/** + * @ingroup Common_register_access_function + * @brief Get INTLEVEL register + * @return uint16_t. Value of @ref INTLEVEL register. + * @sa setINTLEVEL() + */ +//M20150401 : Type explict declaration +/* +#define getINTLEVEL() \ + ((WIZCHIP_READ(INTLEVEL) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(INTLEVEL,1))) +*/ +#define getINTLEVEL() \ + (((uint16_t)WIZCHIP_READ(INTLEVEL) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(INTLEVEL,1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref IR register + * @param (uint8_t)ir Value to set @ref IR register. + * @sa getIR() + */ +#define setIR(ir) \ + WIZCHIP_WRITE(IR, (ir & 0xF0)) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref IR register + * @return uint8_t. Value of @ref IR register. + * @sa setIR() + */ +#define getIR() \ + (WIZCHIP_READ(IR) & 0xF0) +/** + * @ingroup Common_register_access_function + * @brief Set @ref _IMR_ register + * @param (uint8_t)imr Value to set @ref _IMR_ register. + * @sa getIMR() + */ +#define setIMR(imr) \ + WIZCHIP_WRITE(_IMR_, imr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref _IMR_ register + * @return uint8_t. Value of @ref _IMR_ register. + * @sa setIMR() + */ +#define getIMR() \ + WIZCHIP_READ(_IMR_) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref SIR register + * @param (uint8_t)sir Value to set @ref SIR register. + * @sa getSIR() + */ +#define setSIR(sir) \ + WIZCHIP_WRITE(SIR, sir) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref SIR register + * @return uint8_t. Value of @ref SIR register. + * @sa setSIR() + */ +#define getSIR() \ + WIZCHIP_READ(SIR) +/** + * @ingroup Common_register_access_function + * @brief Set @ref SIMR register + * @param (uint8_t)simr Value to set @ref SIMR register. + * @sa getSIMR() + */ +#define setSIMR(simr) \ + WIZCHIP_WRITE(SIMR, simr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref SIMR register + * @return uint8_t. Value of @ref SIMR register. + * @sa setSIMR() + */ +#define getSIMR() \ + WIZCHIP_READ(SIMR) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref _RTR_ register + * @param (uint16_t)rtr Value to set @ref _RTR_ register. + * @sa getRTR() + */ +#define setRTR(rtr) {\ + WIZCHIP_WRITE(_RTR_, (uint8_t)(rtr >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(_RTR_,1), (uint8_t) rtr); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref _RTR_ register + * @return uint16_t. Value of @ref _RTR_ register. + * @sa setRTR() + */ +//M20150401 : Type explict declaration +/* +#define getRTR() \ + ((WIZCHIP_READ(_RTR_) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(_RTR_,1))) +*/ +#define getRTR() \ + (((uint16_t)WIZCHIP_READ(_RTR_) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(_RTR_,1))) + + +/** + * @ingroup Common_register_access_function + * @brief Set @ref _RCR_ register + * @param (uint8_t)rcr Value to set @ref _RCR_ register. + * @sa getRCR() + */ +#define setRCR(rcr) \ + WIZCHIP_WRITE(_RCR_, rcr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref _RCR_ register + * @return uint8_t. Value of @ref _RCR_ register. + * @sa setRCR() + */ +#define getRCR() \ + WIZCHIP_READ(_RCR_) + +//================================================== test done =========================================================== + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PTIMER register + * @param (uint8_t)ptimer Value to set @ref PTIMER register. + * @sa getPTIMER() + */ +#define setPTIMER(ptimer) \ + WIZCHIP_WRITE(PTIMER, ptimer) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PTIMER register + * @return uint8_t. Value of @ref PTIMER register. + * @sa setPTIMER() + */ +#define getPTIMER() \ + WIZCHIP_READ(PTIMER) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PMAGIC register + * @param (uint8_t)pmagic Value to set @ref PMAGIC register. + * @sa getPMAGIC() + */ +#define setPMAGIC(pmagic) \ + WIZCHIP_WRITE(PMAGIC, pmagic) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PMAGIC register + * @return uint8_t. Value of @ref PMAGIC register. + * @sa setPMAGIC() + */ +#define getPMAGIC() \ + WIZCHIP_READ(PMAGIC) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PHAR address + * @param (uint8_t*)phar Pointer variable to set PPP destination MAC register address. It should be allocated 6 bytes. + * @sa getPHAR() + */ +#define setPHAR(phar) \ + WIZCHIP_WRITE_BUF(PHAR, phar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PHAR address + * @param (uint8_t*)phar Pointer variable to PPP destination MAC register address. It should be allocated 6 bytes. + * @sa setPHAR() + */ +#define getPHAR(phar) \ + WIZCHIP_READ_BUF(PHAR, phar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PSID register + * @param (uint16_t)psid Value to set @ref PSID register. + * @sa getPSID() + */ +#define setPSID(psid) {\ + WIZCHIP_WRITE(PSID, (uint8_t)(psid >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(PSID,1), (uint8_t) psid); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PSID register + * @return uint16_t. Value of @ref PSID register. + * @sa setPSID() + */ +//uint16_t getPSID(void); +//M20150401 : Type explict declaration +/* +#define getPSID() \ + ((WIZCHIP_READ(PSID) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PSID,1))) +*/ +#define getPSID() \ + (((uint16_t)WIZCHIP_READ(PSID) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PSID,1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PMRU register + * @param (uint16_t)pmru Value to set @ref PMRU register. + * @sa getPMRU() + */ +#define setPMRU(pmru) { \ + WIZCHIP_WRITE(PMRU, (uint8_t)(pmru>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(PMRU,1), (uint8_t) pmru); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PMRU register + * @return uint16_t. Value of @ref PMRU register. + * @sa setPMRU() + */ +//M20150401 : Type explict declaration +/* +#define getPMRU() \ + ((WIZCHIP_READ(PMRU) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PMRU,1))) +*/ +#define getPMRU() \ + (((uint16_t)WIZCHIP_READ(PMRU) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PMRU,1))) + +/** + * @ingroup Common_register_access_function + * @brief Get unreachable IP address + * @param (uint8_t*)uipr Pointer variable to get unreachable IP address. It should be allocated 4 bytes. + */ +//M20150401 : Size Error of UIPR (6 -> 4) +/* +#define getUIPR(uipr) \ + WIZCHIP_READ_BUF(UIPR,uipr,6) +*/ +#define getUIPR(uipr) \ + WIZCHIP_READ_BUF(UIPR,uipr,4) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref UPORTR register + * @return uint16_t. Value of @ref UPORTR register. + */ +//M20150401 : Type explict declaration +/* +#define getUPORTR() \ + ((WIZCHIP_READ(UPORTR) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(UPORTR,1))) +*/ +#define getUPORTR() \ + (((uint16_t)WIZCHIP_READ(UPORTR) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(UPORTR,1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PHYCFGR register + * @param (uint8_t)phycfgr Value to set @ref PHYCFGR register. + * @sa getPHYCFGR() + */ +#define setPHYCFGR(phycfgr) \ + WIZCHIP_WRITE(PHYCFGR, phycfgr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PHYCFGR register + * @return uint8_t. Value of @ref PHYCFGR register. + * @sa setPHYCFGR() + */ +#define getPHYCFGR() \ + WIZCHIP_READ(PHYCFGR) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref VERSIONR register + * @return uint8_t. Value of @ref VERSIONR register. + */ +#define getVERSIONR() \ + WIZCHIP_READ(VERSIONR) + +///////////////////////////////////// + +/////////////////////////////////// +// Socket N register I/O function // +/////////////////////////////////// +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)mr Value to set @ref Sn_MR + * @sa getSn_MR() + */ +#define setSn_MR(sn, mr) \ + WIZCHIP_WRITE(Sn_MR(sn),mr) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_MR. + * @sa setSn_MR() + */ +#define getSn_MR(sn) \ + WIZCHIP_READ(Sn_MR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_CR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)cr Value to set @ref Sn_CR + * @sa getSn_CR() + */ +#define setSn_CR(sn, cr) \ + WIZCHIP_WRITE(Sn_CR(sn), cr) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_CR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_CR. + * @sa setSn_CR() + */ +#define getSn_CR(sn) \ + WIZCHIP_READ(Sn_CR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_IR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)ir Value to set @ref Sn_IR + * @sa getSn_IR() + */ +#define setSn_IR(sn, ir) \ + WIZCHIP_WRITE(Sn_IR(sn), (ir & 0x1F)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_IR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_IR. + * @sa setSn_IR() + */ +#define getSn_IR(sn) \ + (WIZCHIP_READ(Sn_IR(sn)) & 0x1F) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_IMR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)imr Value to set @ref Sn_IMR + * @sa getSn_IMR() + */ +#define setSn_IMR(sn, imr) \ + WIZCHIP_WRITE(Sn_IMR(sn), (imr & 0x1F)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_IMR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_IMR. + * @sa setSn_IMR() + */ +#define getSn_IMR(sn) \ + (WIZCHIP_READ(Sn_IMR(sn)) & 0x1F) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_SR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_SR. + */ +#define getSn_SR(sn) \ + WIZCHIP_READ(Sn_SR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_PORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)port Value to set @ref Sn_PORT. + * @sa getSn_PORT() + */ +#define setSn_PORT(sn, port) { \ + WIZCHIP_WRITE(Sn_PORT(sn), (uint8_t)(port >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_PORT(sn),1), (uint8_t) port); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_PORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_PORT. + * @sa setSn_PORT() + */ +//M20150401 : Type explict declaration +/* +#define getSn_PORT(sn) \ + ((WIZCHIP_READ(Sn_PORT(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_PORT(sn),1))) +*/ +#define getSn_PORT(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_PORT(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_PORT(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DHAR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dhar Pointer variable to set socket n destination hardware address. It should be allocated 6 bytes. + * @sa getSn_DHAR() + */ +#define setSn_DHAR(sn, dhar) \ + WIZCHIP_WRITE_BUF(Sn_DHAR(sn), dhar, 6) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dhar Pointer variable to get socket n destination hardware address. It should be allocated 6 bytes. + * @sa setSn_DHAR() + */ +#define getSn_DHAR(sn, dhar) \ + WIZCHIP_READ_BUF(Sn_DHAR(sn), dhar, 6) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DIPR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dipr Pointer variable to set socket n destination IP address. It should be allocated 4 bytes. + * @sa getSn_DIPR() + */ +#define setSn_DIPR(sn, dipr) \ + WIZCHIP_WRITE_BUF(Sn_DIPR(sn), dipr, 4) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_DIPR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dipr Pointer variable to get socket n destination IP address. It should be allocated 4 bytes. + * @sa setSn_DIPR() + */ +#define getSn_DIPR(sn, dipr) \ + WIZCHIP_READ_BUF(Sn_DIPR(sn), dipr, 4) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DPORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)dport Value to set @ref Sn_DPORT + * @sa getSn_DPORT() + */ +#define setSn_DPORT(sn, dport) { \ + WIZCHIP_WRITE(Sn_DPORT(sn), (uint8_t) (dport>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_DPORT(sn),1), (uint8_t) dport); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_DPORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_DPORT. + * @sa setSn_DPORT() + */ +//M20150401 : Type explict declaration +/* +#define getSn_DPORT(sn) \ + ((WIZCHIP_READ(Sn_DPORT(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_DPORT(sn),1))) +*/ +#define getSn_DPORT(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_DPORT(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_DPORT(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_MSSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)mss Value to set @ref Sn_MSSR + * @sa setSn_MSSR() + */ +#define setSn_MSSR(sn, mss) { \ + WIZCHIP_WRITE(Sn_MSSR(sn), (uint8_t)(mss>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_MSSR(sn),1), (uint8_t) mss); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MSSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_MSSR. + * @sa setSn_MSSR() + */ +//M20150401 : Type explict declaration +/* +#define getSn_MSSR(sn) \ + ((WIZCHIP_READ(Sn_MSSR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_MSSR(sn),1))) +*/ +#define getSn_MSSR(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_MSSR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_MSSR(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TOS register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)tos Value to set @ref Sn_TOS + * @sa getSn_TOS() + */ +#define setSn_TOS(sn, tos) \ + WIZCHIP_WRITE(Sn_TOS(sn), tos) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TOS register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of Sn_TOS. + * @sa setSn_TOS() + */ +#define getSn_TOS(sn) \ + WIZCHIP_READ(Sn_TOS(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TTL register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)ttl Value to set @ref Sn_TTL + * @sa getSn_TTL() + */ +#define setSn_TTL(sn, ttl) \ + WIZCHIP_WRITE(Sn_TTL(sn), ttl) + + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TTL register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_TTL. + * @sa setSn_TTL() + */ +#define getSn_TTL(sn) \ + WIZCHIP_READ(Sn_TTL(sn)) + + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_RXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)rxbufsize Value to set @ref Sn_RXBUF_SIZE + * @sa getSn_RXBUF_SIZE() + */ +#define setSn_RXBUF_SIZE(sn, rxbufsize) \ + WIZCHIP_WRITE(Sn_RXBUF_SIZE(sn),rxbufsize) + + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_RXBUF_SIZE. + * @sa setSn_RXBUF_SIZE() + */ +#define getSn_RXBUF_SIZE(sn) \ + WIZCHIP_READ(Sn_RXBUF_SIZE(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)txbufsize Value to set @ref Sn_TXBUF_SIZE + * @sa getSn_TXBUF_SIZE() + */ +#define setSn_TXBUF_SIZE(sn, txbufsize) \ + WIZCHIP_WRITE(Sn_TXBUF_SIZE(sn), txbufsize) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_TXBUF_SIZE. + * @sa setSn_TXBUF_SIZE() + */ +#define getSn_TXBUF_SIZE(sn) \ + WIZCHIP_READ(Sn_TXBUF_SIZE(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_FSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_FSR. + */ +uint16_t getSn_TX_FSR(uint8_t sn); + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_RD. + */ +//M20150401 : Type explict declaration +/* +#define getSn_TX_RD(sn) \ + ((WIZCHIP_READ(Sn_TX_RD(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_RD(sn),1))) +*/ +#define getSn_TX_RD(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_TX_RD(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_RD(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)txwr Value to set @ref Sn_TX_WR + * @sa GetSn_TX_WR() + */ +#define setSn_TX_WR(sn, txwr) { \ + WIZCHIP_WRITE(Sn_TX_WR(sn), (uint8_t)(txwr>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn),1), (uint8_t) txwr); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_WR. + * @sa setSn_TX_WR() + */ +//M20150401 : Type explict declaration +/* +#define getSn_TX_WR(sn) \ + ((WIZCHIP_READ(Sn_TX_WR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn),1))) +*/ +#define getSn_TX_WR(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_TX_WR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn),1))) + + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_RSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_RX_RSR. + */ +uint16_t getSn_RX_RSR(uint8_t sn); + + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_RX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)rxrd Value to set @ref Sn_RX_RD + * @sa getSn_RX_RD() + */ +#define setSn_RX_RD(sn, rxrd) { \ + WIZCHIP_WRITE(Sn_RX_RD(sn), (uint8_t)(rxrd>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn),1), (uint8_t) rxrd); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_RX_RD. + * @sa setSn_RX_RD() + */ +//M20150401 : Type explict declaration +/* +#define getSn_RX_RD(sn) \ + ((WIZCHIP_READ(Sn_RX_RD(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn),1))) +*/ +#define getSn_RX_RD(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_RX_RD(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_RX_WR. + */ +//M20150401 : Type explict declaration +/* +#define getSn_RX_WR(sn) \ + ((WIZCHIP_READ(Sn_RX_WR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_WR(sn),1))) +*/ +#define getSn_RX_WR(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_RX_WR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_WR(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_FRAG register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)frag Value to set @ref Sn_FRAG + * @sa getSn_FRAD() + */ +#define setSn_FRAG(sn, frag) { \ + WIZCHIP_WRITE(Sn_FRAG(sn), (uint8_t)(frag >>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_FRAG(sn),1), (uint8_t) frag); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_FRAG register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_FRAG. + * @sa setSn_FRAG() + */ +//M20150401 : Type explict declaration +/* +#define getSn_FRAG(sn) \ + ((WIZCHIP_READ(Sn_FRAG(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_FRAG(sn),1))) +*/ +#define getSn_FRAG(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_FRAG(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_FRAG(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_KPALVTR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)kpalvt Value to set @ref Sn_KPALVTR + * @sa getSn_KPALVTR() + */ +#define setSn_KPALVTR(sn, kpalvt) \ + WIZCHIP_WRITE(Sn_KPALVTR(sn), kpalvt) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_KPALVTR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_KPALVTR. + * @sa setSn_KPALVTR() + */ +#define getSn_KPALVTR(sn) \ + WIZCHIP_READ(Sn_KPALVTR(sn)) + +////////////////////////////////////// + +///////////////////////////////////// +// Sn_TXBUF & Sn_RXBUF IO function // +///////////////////////////////////// +/** + * @brief Socket_register_access_function + * @brief Gets the max buffer size of socket sn passed as parameter. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of Socket n RX max buffer size. + */ +//M20150401 : Type explict declaration +/* +#define getSn_RxMAX(sn) \ + (getSn_RXBUF_SIZE(sn) << 10) +*/ +#define getSn_RxMAX(sn) \ + (((uint16_t)getSn_RXBUF_SIZE(sn)) << 10) + +/** + * @brief Socket_register_access_function + * @brief Gets the max buffer size of socket sn passed as parameters. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of Socket n TX max buffer size. + */ +//M20150401 : Type explict declaration +/* +#define getSn_TxMAX(sn) \ + (getSn_TXBUF_SIZE(sn) << 10) +*/ +#define getSn_TxMAX(sn) \ + (((uint16_t)getSn_TXBUF_SIZE(sn)) << 10) + +/** + * @ingroup Basic_IO_function + * @brief It copies data to internal TX memory + * + * @details This function reads the Tx write pointer register and after that, + * it copies the wizdata(pointer buffer) of the length of len(variable) bytes to internal TX memory + * and updates the Tx write pointer register. + * This function is being called by send() and sendto() function also. + * + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param wizdata Pointer buffer to write data + * @param len Data length + * @sa wiz_recv_data() + */ +void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It copies data to your buffer from internal RX memory + * + * @details This function read the Rx read pointer register and after that, + * it copies the received data from internal RX memory + * to wizdata(pointer variable) of the length of len(variable) bytes. + * This function is being called by recv() also. + * + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param wizdata Pointer buffer to read data + * @param len Data length + * @sa wiz_send_data() + */ +void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It discard the received data in RX memory. + * @details It discards the data of the length of len(variable) bytes in internal RX memory. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param len Data length + */ +void wiz_recv_ignore(uint8_t sn, uint16_t len); + +/// @cond DOXY_APPLY_CODE +#endif +/// @endcond + +#ifdef __cplusplus +} +#endif + +#endif // _W5500_H_ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/socket.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/socket.c new file mode 100644 index 0000000..961d9a4 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/socket.c @@ -0,0 +1,930 @@ +//***************************************************************************** +// +//! \file socket.c +//! \brief SOCKET APIs Implements file. +//! \details SOCKET APIs like as Berkeley Socket APIs. +//! \version 1.0.3 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2014/05/01> V1.0.3. Refer to M20140501 +//! 1. Implicit type casting -> Explicit type casting. +//! 2. replace 0x01 with PACK_REMAINED in recvfrom() +//! 3. Validation a destination ip in connect() & sendto(): +//! It occurs a fatal error on converting unint32 address if uint8* addr parameter is not aligned by 4byte address. +//! Copy 4 byte addr value into temporary uint32 variable and then compares it. +//! <2013/12/20> V1.0.2 Refer to M20131220 +//! Remove Warning. +//! <2013/11/04> V1.0.1 2nd Release. Refer to "20131104". +//! In sendto(), Add to clear timeout interrupt status (Sn_IR_TIMEOUT) +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * Redistributions in binary form must reproduce the above copyright +//! notice, this list of conditions and the following disclaimer in the +//! documentation and/or other materials provided with the distribution. +//! * Neither the name of the nor the names of its +//! contributors may be used to endorse or promote products derived +//! from this software without specific prior written permission. +//! +//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +//! THE POSSIBILITY OF SUCH DAMAGE. +// +//***************************************************************************** +#include "socket.h" + +//M20150401 : Typing Error +//#define SOCK_ANY_PORT_NUM 0xC000; +#define SOCK_ANY_PORT_NUM 0xC000 + +static uint16_t sock_any_port = SOCK_ANY_PORT_NUM; +static uint16_t sock_io_mode = 0; +static uint16_t sock_is_sending = 0; + +static uint16_t sock_remained_size[_WIZCHIP_SOCK_NUM_] = {0,0,}; + +//M20150601 : For extern decleation +//static uint8_t sock_pack_info[_WIZCHIP_SOCK_NUM_] = {0,}; +uint8_t sock_pack_info[_WIZCHIP_SOCK_NUM_] = {0,}; +// + +#if _WIZCHIP_ == 5200 + static uint16_t sock_next_rd[_WIZCHIP_SOCK_NUM_] ={0,}; +#endif + +//A20150601 : For integrating with W5300 +#if _WIZCHIP_ == 5300 + uint8_t sock_remained_byte[_WIZCHIP_SOCK_NUM_] = {0,}; // set by wiz_recv_data() +#endif + + +#define CHECK_SOCKNUM() \ + do{ \ + if(sn > _WIZCHIP_SOCK_NUM_) return SOCKERR_SOCKNUM; \ + }while(0); \ + +#define CHECK_SOCKMODE(mode) \ + do{ \ + if((getSn_MR(sn) & 0x0F) != mode) return SOCKERR_SOCKMODE; \ + }while(0); \ + +#define CHECK_SOCKINIT() \ + do{ \ + if((getSn_SR(sn) != SOCK_INIT)) return SOCKERR_SOCKINIT; \ + }while(0); \ + +#define CHECK_SOCKDATA() \ + do{ \ + if(len == 0) return SOCKERR_DATALEN; \ + }while(0); \ + + + +int8_t socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag) +{ + CHECK_SOCKNUM(); + switch(protocol) + { + case Sn_MR_TCP : + { + //M20150601 : Fixed the warning - taddr will never be NULL + /* + uint8_t taddr[4]; + getSIPR(taddr); + */ + uint32_t taddr; + getSIPR((uint8_t*)&taddr); + if(taddr == 0) return SOCKERR_SOCKINIT; + } + case Sn_MR_UDP : + case Sn_MR_MACRAW : + case Sn_MR_IPRAW : + break; + #if ( _WIZCHIP_ < 5200 ) + case Sn_MR_PPPoE : + break; + #endif + default : + return SOCKERR_SOCKMODE; + } + //M20150601 : For SF_TCP_ALIGN & W5300 + //if((flag & 0x06) != 0) return SOCKERR_SOCKFLAG; + if((flag & 0x04) != 0) return SOCKERR_SOCKFLAG; +#if _WIZCHIP_ == 5200 + if(flag & 0x10) return SOCKERR_SOCKFLAG; +#endif + + if(flag != 0) + { + switch(protocol) + { + case Sn_MR_TCP: + //M20150601 : For SF_TCP_ALIGN & W5300 + #if _WIZCHIP_ == 5300 + if((flag & (SF_TCP_NODELAY|SF_IO_NONBLOCK|SF_TCP_ALIGN))==0) return SOCKERR_SOCKFLAG; + #else + if((flag & (SF_TCP_NODELAY|SF_IO_NONBLOCK))==0) return SOCKERR_SOCKFLAG; + #endif + + break; + case Sn_MR_UDP: + if(flag & SF_IGMP_VER2) + { + if((flag & SF_MULTI_ENABLE)==0) return SOCKERR_SOCKFLAG; + } + #if _WIZCHIP_ == 5500 + if(flag & SF_UNI_BLOCK) + { + if((flag & SF_MULTI_ENABLE) == 0) return SOCKERR_SOCKFLAG; + } + #endif + break; + default: + break; + } + } + close(sn); + //M20150601 + #if _WIZCHIP_ == 5300 + setSn_MR(sn, ((uint16_t)(protocol | (flag & 0xF0))) | (((uint16_t)(flag & 0x02)) << 7) ); + #else + setSn_MR(sn, (protocol | (flag & 0xF0))); + #endif + if(!port) + { + port = sock_any_port++; + if(sock_any_port == 0xFFF0) sock_any_port = SOCK_ANY_PORT_NUM; + } + setSn_PORT(sn,port); + setSn_CR(sn,Sn_CR_OPEN); + while(getSn_CR(sn)); + //A20150401 : For release the previous sock_io_mode + sock_io_mode &= ~(1 < sn + //if( ((getSn_MR(s)& 0x0F) == Sn_MR_TCP) && (getSn_TX_FSR(s) != getSn_TxMAX(s)) ) + if( ((getSn_MR(sn)& 0x0F) == Sn_MR_TCP) && (getSn_TX_FSR(sn) != getSn_TxMAX(sn)) ) + { + uint8_t destip[4] = {0, 0, 0, 1}; + // TODO + // You can wait for completing to sending data; + // wait about 1 second; + // if you have completed to send data, skip the code of erratum 1 + // ex> wait_1s(); + // if (getSn_TX_FSR(s) == getSn_TxMAX(s)) continue; + // + //M20160503 : The socket() of close() calls close() itself again. It occures a infinite loop - close()->socket()->close()->socket()-> ~ + //socket(s,Sn_MR_UDP,0x3000,0); + //sendto(s,destip,1,destip,0x3000); // send the dummy data to an unknown destination(0.0.0.1). + setSn_MR(sn,Sn_MR_UDP); + setSn_PORTR(sn, 0x3000); + setSn_CR(sn,Sn_CR_OPEN); + while(getSn_CR(sn) != 0); + while(getSn_SR(sn) != SOCK_UDP); + sendto(sn,destip,1,destip,0x3000); // send the dummy data to an unknown destination(0.0.0.1). + }; +#endif + setSn_CR(sn,Sn_CR_CLOSE); + /* wait to process the command... */ + while( getSn_CR(sn) ); + /* clear all interrupt of the socket. */ + setSn_IR(sn, 0xFF); + //A20150401 : Release the sock_io_mode of socket n. + sock_io_mode &= ~(1< freesize) len = freesize; // check size not to exceed MAX size. + while(1) + { + freesize = getSn_TX_FSR(sn); + tmp = getSn_SR(sn); + if ((tmp != SOCK_ESTABLISHED) && (tmp != SOCK_CLOSE_WAIT)) + { + close(sn); + return SOCKERR_SOCKSTATUS; + } + if( (sock_io_mode & (1< freesize) ) return SOCK_BUSY; + if(len <= freesize) break; + } + wiz_send_data(sn, buf, len); + #if _WIZCHIP_ == 5200 + sock_next_rd[sn] = getSn_TX_RD(sn) + len; + #endif + + #if _WIZCHIP_ == 5300 + setSn_TX_WRSR(sn,len); + #endif + + setSn_CR(sn,Sn_CR_SEND); + /* wait to process the command... */ + while(getSn_CR(sn)); + sock_is_sending |= (1 << sn); + //M20150409 : Explicit Type Casting + //return len; + return (int32_t)len; +} + + +int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len) +{ + uint8_t tmp = 0; + uint16_t recvsize = 0; +//A20150601 : For integarating with W5300 +#if _WIZCHIP_ == 5300 + uint8_t head[2]; + uint16_t mr; +#endif +// + CHECK_SOCKNUM(); + CHECK_SOCKMODE(Sn_MR_TCP); + CHECK_SOCKDATA(); + + recvsize = getSn_RxMAX(sn); + if(recvsize < len) len = recvsize; + +//A20150601 : For Integrating with W5300 +#if _WIZCHIP_ == 5300 + //sock_pack_info[sn] = PACK_COMPLETED; // for clear + if(sock_remained_size[sn] == 0) + { +#endif +// + while(1) + { + recvsize = getSn_RX_RSR(sn); + tmp = getSn_SR(sn); + if (tmp != SOCK_ESTABLISHED) + { + if(tmp == SOCK_CLOSE_WAIT) + { + if(recvsize != 0) break; + else if(getSn_TX_FSR(sn) == getSn_TxMAX(sn)) + { + close(sn); + return SOCKERR_SOCKSTATUS; + } + } + else + { + close(sn); + return SOCKERR_SOCKSTATUS; + } + } + if((sock_io_mode & (1< sock_remained_size[sn]) len = sock_remained_size[sn]; + recvsize = len; + if(sock_pack_info[sn] & PACK_FIFOBYTE) + { + *buf = sock_remained_byte[sn]; + buf++; + sock_pack_info[sn] &= ~(PACK_FIFOBYTE); + recvsize -= 1; + sock_remained_size[sn] -= 1; + } + if(recvsize != 0) + { + wiz_recv_data(sn, buf, recvsize); + setSn_CR(sn,Sn_CR_RECV); + while(getSn_CR(sn)); + } + sock_remained_size[sn] -= recvsize; + if(sock_remained_size[sn] != 0) + { + sock_pack_info[sn] |= PACK_REMAINED; + if(recvsize & 0x1) sock_pack_info[sn] |= PACK_FIFOBYTE; + } + else sock_pack_info[sn] = PACK_COMPLETED; + if(getSn_MR(sn) & Sn_MR_ALIGN) sock_remained_size[sn] = 0; + //len = recvsize; +#else + if(recvsize < len) len = recvsize; + wiz_recv_data(sn, buf, len); + setSn_CR(sn,Sn_CR_RECV); + while(getSn_CR(sn)); +#endif + + //M20150409 : Explicit Type Casting + //return len; + return (int32_t)len; +} + +int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port) +{ + uint8_t tmp = 0; + uint16_t freesize = 0; + uint32_t taddr; + + CHECK_SOCKNUM(); + switch(getSn_MR(sn) & 0x0F) + { + case Sn_MR_UDP: + case Sn_MR_MACRAW: +// break; +// #if ( _WIZCHIP_ < 5200 ) + case Sn_MR_IPRAW: + break; +// #endif + default: + return SOCKERR_SOCKMODE; + } + CHECK_SOCKDATA(); + //M20140501 : For avoiding fatal error on memory align mismatched + //if(*((uint32_t*)addr) == 0) return SOCKERR_IPINVALID; + //{ + //uint32_t taddr; + taddr = ((uint32_t)addr[0]) & 0x000000FF; + taddr = (taddr << 8) + ((uint32_t)addr[1] & 0x000000FF); + taddr = (taddr << 8) + ((uint32_t)addr[2] & 0x000000FF); + taddr = (taddr << 8) + ((uint32_t)addr[3] & 0x000000FF); + //} + // + //if(*((uint32_t*)addr) == 0) return SOCKERR_IPINVALID; + if((taddr == 0) && ((getSn_MR(sn)&Sn_MR_MACRAW) != Sn_MR_MACRAW)) return SOCKERR_IPINVALID; + if((port == 0) && ((getSn_MR(sn)&Sn_MR_MACRAW) != Sn_MR_MACRAW)) return SOCKERR_PORTZERO; + tmp = getSn_SR(sn); +//#if ( _WIZCHIP_ < 5200 ) + if((tmp != SOCK_MACRAW) && (tmp != SOCK_UDP) && (tmp != SOCK_IPRAW)) return SOCKERR_SOCKSTATUS; +//#else +// if(tmp != SOCK_MACRAW && tmp != SOCK_UDP) return SOCKERR_SOCKSTATUS; +//#endif + + setSn_DIPR(sn,addr); + setSn_DPORT(sn,port); + freesize = getSn_TxMAX(sn); + if (len > freesize) len = freesize; // check size not to exceed MAX size. + while(1) + { + freesize = getSn_TX_FSR(sn); + if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED; + if( (sock_io_mode & (1< freesize) ) return SOCK_BUSY; + if(len <= freesize) break; + }; + wiz_send_data(sn, buf, len); + + #if _WIZCHIP_ < 5500 //M20150401 : for WIZCHIP Errata #4, #5 (ARP errata) + getSIPR((uint8_t*)&taddr); + if(taddr == 0) + { + getSUBR((uint8_t*)&taddr); + setSUBR((uint8_t*)"\x00\x00\x00\x00"); + } + else taddr = 0; + #endif + +//A20150601 : For W5300 +#if _WIZCHIP_ == 5300 + setSn_TX_WRSR(sn, len); +#endif +// + setSn_CR(sn,Sn_CR_SEND); + /* wait to process the command... */ + while(getSn_CR(sn)); + while(1) + { + tmp = getSn_IR(sn); + if(tmp & Sn_IR_SENDOK) + { + setSn_IR(sn, Sn_IR_SENDOK); + break; + } + //M:20131104 + //else if(tmp & Sn_IR_TIMEOUT) return SOCKERR_TIMEOUT; + else if(tmp & Sn_IR_TIMEOUT) + { + setSn_IR(sn, Sn_IR_TIMEOUT); + //M20150409 : Fixed the lost of sign bits by type casting. + //len = (uint16_t)SOCKERR_TIMEOUT; + //break; + #if _WIZCHIP_ < 5500 //M20150401 : for WIZCHIP Errata #4, #5 (ARP errata) + if(taddr) setSUBR((uint8_t*)&taddr); + #endif + return SOCKERR_TIMEOUT; + } + //////////// + } + #if _WIZCHIP_ < 5500 //M20150401 : for WIZCHIP Errata #4, #5 (ARP errata) + if(taddr) setSUBR((uint8_t*)&taddr); + #endif + //M20150409 : Explicit Type Casting + //return len; + return (int32_t)len; +} + + + +int32_t recvfrom(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port) +{ +//M20150601 : For W5300 +#if _WIZCHIP_ == 5300 + uint16_t mr; + uint16_t mr1; +#else + uint8_t mr; +#endif +// + uint8_t head[8]; + uint16_t pack_len=0; + + CHECK_SOCKNUM(); + //CHECK_SOCKMODE(Sn_MR_UDP); +//A20150601 +#if _WIZCHIP_ == 5300 + mr1 = getMR(); +#endif + + switch((mr=getSn_MR(sn)) & 0x0F) + { + case Sn_MR_UDP: + case Sn_MR_IPRAW: + case Sn_MR_MACRAW: + break; + #if ( _WIZCHIP_ < 5200 ) + case Sn_MR_PPPoE: + break; + #endif + default: + return SOCKERR_SOCKMODE; + } + CHECK_SOCKDATA(); + if(sock_remained_size[sn] == 0) + { + while(1) + { + pack_len = getSn_RX_RSR(sn); + if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED; + if( (sock_io_mode & (1< 1514) + { + close(sn); + return SOCKFATAL_PACKLEN; + } + sock_pack_info[sn] = PACK_FIRST; + } + if(len < sock_remained_size[sn]) pack_len = len; + else pack_len = sock_remained_size[sn]; + wiz_recv_data(sn,buf,pack_len); + break; + //#if ( _WIZCHIP_ < 5200 ) + case Sn_MR_IPRAW: + if(sock_remained_size[sn] == 0) + { + wiz_recv_data(sn, head, 6); + setSn_CR(sn,Sn_CR_RECV); + while(getSn_CR(sn)); + addr[0] = head[0]; + addr[1] = head[1]; + addr[2] = head[2]; + addr[3] = head[3]; + sock_remained_size[sn] = head[4]; + //M20150401 : For Typing Error + //sock_remaiend_size[sn] = (sock_remained_size[sn] << 8) + head[5]; + sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[5]; + sock_pack_info[sn] = PACK_FIRST; + } + // + // Need to packet length check + // + if(len < sock_remained_size[sn]) pack_len = len; + else pack_len = sock_remained_size[sn]; + wiz_recv_data(sn, buf, pack_len); // data copy. + break; + //#endif + default: + wiz_recv_ignore(sn, pack_len); // data copy. + sock_remained_size[sn] = pack_len; + break; + } + setSn_CR(sn,Sn_CR_RECV); + /* wait to process the command... */ + while(getSn_CR(sn)) ; + sock_remained_size[sn] -= pack_len; + //M20150601 : + //if(sock_remained_size[sn] != 0) sock_pack_info[sn] |= 0x01; + if(sock_remained_size[sn] != 0) + { + sock_pack_info[sn] |= PACK_REMAINED; + #if _WIZCHIP_ == 5300 + if(pack_len & 0x01) sock_pack_info[sn] |= PACK_FIFOBYTE; + #endif + } + else sock_pack_info[sn] = PACK_COMPLETED; +#if _WIZCHIP_ == 5300 + pack_len = len; +#endif + // + //M20150409 : Explicit Type Casting + //return pack_len; + return (int32_t)pack_len; +} + + +int8_t ctlsocket(uint8_t sn, ctlsock_type cstype, void* arg) +{ + uint8_t tmp = 0; + CHECK_SOCKNUM(); + switch(cstype) + { + case CS_SET_IOMODE: + tmp = *((uint8_t*)arg); + if(tmp == SOCK_IO_NONBLOCK) sock_io_mode |= (1< explict type casting + //*((uint8_t*)arg) = (sock_io_mode >> sn) & 0x0001; + *((uint8_t*)arg) = (uint8_t)((sock_io_mode >> sn) & 0x0001); + // + break; + case CS_GET_MAXTXBUF: + *((uint16_t*)arg) = getSn_TxMAX(sn); + break; + case CS_GET_MAXRXBUF: + *((uint16_t*)arg) = getSn_RxMAX(sn); + break; + case CS_CLR_INTERRUPT: + if( (*(uint8_t*)arg) > SIK_ALL) return SOCKERR_ARG; + setSn_IR(sn,*(uint8_t*)arg); + break; + case CS_GET_INTERRUPT: + *((uint8_t*)arg) = getSn_IR(sn); + break; + #if _WIZCHIP_ != 5100 + case CS_SET_INTMASK: + if( (*(uint8_t*)arg) > SIK_ALL) return SOCKERR_ARG; + setSn_IMR(sn,*(uint8_t*)arg); + break; + case CS_GET_INTMASK: + *((uint8_t*)arg) = getSn_IMR(sn); + break; + #endif + default: + return SOCKERR_ARG; + } + return SOCK_OK; +} + +int8_t setsockopt(uint8_t sn, sockopt_type sotype, void* arg) +{ + // M20131220 : Remove warning + //uint8_t tmp; + CHECK_SOCKNUM(); + switch(sotype) + { + case SO_TTL: + setSn_TTL(sn,*(uint8_t*)arg); + break; + case SO_TOS: + setSn_TOS(sn,*(uint8_t*)arg); + break; + case SO_MSS: + setSn_MSSR(sn,*(uint16_t*)arg); + break; + case SO_DESTIP: + setSn_DIPR(sn, (uint8_t*)arg); + break; + case SO_DESTPORT: + setSn_DPORT(sn, *(uint16_t*)arg); + break; +#if _WIZCHIP_ != 5100 + case SO_KEEPALIVESEND: + CHECK_SOCKMODE(Sn_MR_TCP); + #if _WIZCHIP_ > 5200 + if(getSn_KPALVTR(sn) != 0) return SOCKERR_SOCKOPT; + #endif + setSn_CR(sn,Sn_CR_SEND_KEEP); + while(getSn_CR(sn) != 0) + { + // M20131220 + //if ((tmp = getSn_IR(sn)) & Sn_IR_TIMEOUT) + if (getSn_IR(sn) & Sn_IR_TIMEOUT) + { + setSn_IR(sn, Sn_IR_TIMEOUT); + return SOCKERR_TIMEOUT; + } + } + break; + #if _WIZCHIP_ > 5200 + case SO_KEEPALIVEAUTO: + CHECK_SOCKMODE(Sn_MR_TCP); + setSn_KPALVTR(sn,*(uint8_t*)arg); + break; + #endif +#endif + default: + return SOCKERR_ARG; + } + return SOCK_OK; +} + +int8_t getsockopt(uint8_t sn, sockopt_type sotype, void* arg) +{ + CHECK_SOCKNUM(); + switch(sotype) + { + case SO_FLAG: + *(uint8_t*)arg = getSn_MR(sn) & 0xF0; + break; + case SO_TTL: + *(uint8_t*) arg = getSn_TTL(sn); + break; + case SO_TOS: + *(uint8_t*) arg = getSn_TOS(sn); + break; + case SO_MSS: + *(uint16_t*) arg = getSn_MSSR(sn); + break; + case SO_DESTIP: + getSn_DIPR(sn, (uint8_t*)arg); + break; + case SO_DESTPORT: + *(uint16_t*) arg = getSn_DPORT(sn); + break; + #if _WIZCHIP_ > 5200 + case SO_KEEPALIVEAUTO: + CHECK_SOCKMODE(Sn_MR_TCP); + *(uint16_t*) arg = getSn_KPALVTR(sn); + break; + #endif + case SO_SENDBUF: + *(uint16_t*) arg = getSn_TX_FSR(sn); + break; + case SO_RECVBUF: + *(uint16_t*) arg = getSn_RX_RSR(sn); + break; + case SO_STATUS: + *(uint8_t*) arg = getSn_SR(sn); + break; + case SO_REMAINSIZE: + if(getSn_MR(sn) & Sn_MR_TCP) + *(uint16_t*)arg = getSn_RX_RSR(sn); + else + *(uint16_t*)arg = sock_remained_size[sn]; + break; + case SO_PACKINFO: + //CHECK_SOCKMODE(Sn_MR_TCP); +#if _WIZCHIP_ != 5300 + if((getSn_MR(sn) == Sn_MR_TCP)) + return SOCKERR_SOCKMODE; +#endif + *(uint8_t*)arg = sock_pack_info[sn]; + break; + default: + return SOCKERR_SOCKOPT; + } + return SOCK_OK; +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/socket.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/socket.h new file mode 100644 index 0000000..7d703ba --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/socket.h @@ -0,0 +1,489 @@ +//***************************************************************************** +// +//! \file socket.h +//! \brief SOCKET APIs Header file. +//! \details SOCKET APIs like as berkeley socket api. +//! \version 1.0.2 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2014/05/01> V1.0.2. Refer to M20140501 +//! 1. Modify the comment : SO_REMAINED -> PACK_REMAINED +//! 2. Add the comment as zero byte udp data reception in getsockopt(). +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * Redistributions in binary form must reproduce the above copyright +//! notice, this list of conditions and the following disclaimer in the +//! documentation and/or other materials provided with the distribution. +//! * Neither the name of the nor the names of its +//! contributors may be used to endorse or promote products derived +//! from this software without specific prior written permission. +//! +//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +//! THE POSSIBILITY OF SUCH DAMAGE. +// +//***************************************************************************** +/** + * @defgroup WIZnet_socket_APIs 1. WIZnet socket APIs + * @brief WIZnet socket APIs are based on Berkeley socket APIs, thus it has much similar name and interface. + * But there is a little bit of difference. + * @details + * Comparison between WIZnet and Berkeley SOCKET APIs + * + * + * + * + * + * + * + * + * + * + * + * + *
API WIZnet Berkeley
socket() O O
bind() X O
listen() O O
connect() O O
accept() X O
recv() O O
send() O O
recvfrom() O O
sendto() O O
closesocket() O
close() & disconnect()
O
+ * There are @b bind() and @b accept() functions in @b Berkeley SOCKET API but, + * not in @b WIZnet SOCKET API. Because socket() of WIZnet is not only creating a SOCKET but also binding a local port number, + * and listen() of WIZnet is not only listening to connection request from client but also accepting the connection request. \n + * When you program "TCP SERVER" with Berkeley SOCKET API, you can use only one listen port. + * When the listen SOCKET accepts a connection request from a client, it keeps listening. + * After accepting the connection request, a new SOCKET is created and the new SOCKET is used in communication with the client. \n + * Following figure shows network flow diagram by Berkeley SOCKET API. + * @image html Berkeley_SOCKET.jpg "" + * But, When you program "TCP SERVER" with WIZnet SOCKET API, you can use as many as 8 listen SOCKET with same port number. \n + * Because there's no accept() in WIZnet SOCKET APIs, when the listen SOCKET accepts a connection request from a client, + * it is changed in order to communicate with the client. + * And the changed SOCKET is not listening any more and is dedicated for communicating with the client. \n + * If there're many listen SOCKET with same listen port number and a client requests a connection, + * the SOCKET which has the smallest SOCKET number accepts the request and is changed as communication SOCKET. \n + * Following figure shows network flow diagram by WIZnet SOCKET API. + * @image html WIZnet_SOCKET.jpg "" + */ +#ifndef _SOCKET_H_ +#define _SOCKET_H_ +#ifdef __cplusplus + extern "C" { +#endif + +#include "wizchip_conf.h" + +#define SOCKET uint8_t ///< SOCKET type define for legacy driver + +#define SOCK_OK 1 ///< Result is OK about socket process. +#define SOCK_BUSY 0 ///< Socket is busy on processing the operation. Valid only Non-block IO Mode. +#define SOCK_FATAL -1000 ///< Result is fatal error about socket process. + +#define SOCK_ERROR 0 +#define SOCKERR_SOCKNUM (SOCK_ERROR - 1) ///< Invalid socket number +#define SOCKERR_SOCKOPT (SOCK_ERROR - 2) ///< Invalid socket option +#define SOCKERR_SOCKINIT (SOCK_ERROR - 3) ///< Socket is not initialized or SIPR is Zero IP address when Sn_MR_TCP +#define SOCKERR_SOCKCLOSED (SOCK_ERROR - 4) ///< Socket unexpectedly closed. +#define SOCKERR_SOCKMODE (SOCK_ERROR - 5) ///< Invalid socket mode for socket operation. +#define SOCKERR_SOCKFLAG (SOCK_ERROR - 6) ///< Invalid socket flag +#define SOCKERR_SOCKSTATUS (SOCK_ERROR - 7) ///< Invalid socket status for socket operation. +#define SOCKERR_ARG (SOCK_ERROR - 10) ///< Invalid argument. +#define SOCKERR_PORTZERO (SOCK_ERROR - 11) ///< Port number is zero +#define SOCKERR_IPINVALID (SOCK_ERROR - 12) ///< Invalid IP address +#define SOCKERR_TIMEOUT (SOCK_ERROR - 13) ///< Timeout occurred +#define SOCKERR_DATALEN (SOCK_ERROR - 14) ///< Data length is zero or greater than buffer max size. +#define SOCKERR_BUFFER (SOCK_ERROR - 15) ///< Socket buffer is not enough for data communication. + +#define SOCKFATAL_PACKLEN (SOCK_FATAL - 1) ///< Invalid packet length. Fatal Error. + +/* + * SOCKET FLAG + */ +#define SF_ETHER_OWN (Sn_MR_MFEN) ///< In @ref Sn_MR_MACRAW, Receive only the packet as broadcast, multicast and own packet +#define SF_IGMP_VER2 (Sn_MR_MC) ///< In @ref Sn_MR_UDP with \ref SF_MULTI_ENABLE, Select IGMP version 2. +#define SF_TCP_NODELAY (Sn_MR_ND) ///< In @ref Sn_MR_TCP, Use to nodelayed ack. +#define SF_MULTI_ENABLE (Sn_MR_MULTI) ///< In @ref Sn_MR_UDP, Enable multicast mode. + +#if _WIZCHIP_ == 5500 + #define SF_BROAD_BLOCK (Sn_MR_BCASTB) ///< In @ref Sn_MR_UDP or @ref Sn_MR_MACRAW, Block broadcast packet. Valid only in W5500 + #define SF_MULTI_BLOCK (Sn_MR_MMB) ///< In @ref Sn_MR_MACRAW, Block multicast packet. Valid only in W5500 + #define SF_IPv6_BLOCK (Sn_MR_MIP6B) ///< In @ref Sn_MR_MACRAW, Block IPv6 packet. Valid only in W5500 + #define SF_UNI_BLOCK (Sn_MR_UCASTB) ///< In @ref Sn_MR_UDP with \ref SF_MULTI_ENABLE. Valid only in W5500 +#endif + +//A201505 : For W5300 +#if _WIZCHIP_ == 5300 + #define SF_TCP_ALIGN 0x02 ///< Valid only \ref Sn_MR_TCP and W5300, refer to \ref Sn_MR_ALIGN +#endif + +#define SF_IO_NONBLOCK 0x01 ///< Socket nonblock io mode. It used parameter in \ref socket(). + +/* + * UDP & MACRAW Packet Infomation + */ +#define PACK_FIRST 0x80 ///< In Non-TCP packet, It indicates to start receiving a packet. (When W5300, This flag can be applied) +#define PACK_REMAINED 0x01 ///< In Non-TCP packet, It indicates to remain a packet to be received. (When W5300, This flag can be applied) +#define PACK_COMPLETED 0x00 ///< In Non-TCP packet, It indicates to complete to receive a packet. (When W5300, This flag can be applied) +//A20150601 : For Integrating with W5300 +#define PACK_FIFOBYTE 0x02 ///< Valid only W5300, It indicate to have read already the Sn_RX_FIFOR. +// + +/** + * @ingroup WIZnet_socket_APIs + * @brief Open a socket. + * @details Initializes the socket with 'sn' passed as parameter and open. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param protocol Protocol type to operate such as TCP, UDP and MACRAW. + * @param port Port number to be bined. + * @param flag Socket flags as \ref SF_ETHER_OWN, \ref SF_IGMP_VER2, \ref SF_TCP_NODELAY, \ref SF_MULTI_ENABLE, \ref SF_IO_NONBLOCK and so on.\n + * Valid flags only in W5500 : @ref SF_BROAD_BLOCK, @ref SF_MULTI_BLOCK, @ref SF_IPv6_BLOCK, and @ref SF_UNI_BLOCK. + * @sa Sn_MR + * + * @return @b Success : The socket number @b 'sn' passed as parameter\n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number\n + * @ref SOCKERR_SOCKMODE - Not support socket mode as TCP, UDP, and so on. \n + * @ref SOCKERR_SOCKFLAG - Invaild socket flag. + */ +int8_t socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Close a socket. + * @details It closes the socket with @b'sn' passed as parameter. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * + * @return @b Success : @ref SOCK_OK \n + * @b Fail : @ref SOCKERR_SOCKNUM - Invalid socket number + */ +int8_t close(uint8_t sn); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Listen to a connection request from a client. + * @details It is listening to a connection request from a client. + * If connection request is accepted successfully, the connection is established. Socket sn is used in passive(server) mode. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @return @b Success : @ref SOCK_OK \n + * @b Fail :\n @ref SOCKERR_SOCKINIT - Socket is not initialized \n + * @ref SOCKERR_SOCKCLOSED - Socket closed unexpectedly. + */ +int8_t listen(uint8_t sn); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Try to connect a server. + * @details It requests connection to the server with destination IP address and port number passed as parameter.\n + * @note It is valid only in TCP client mode. + * In block io mode, it does not return until connection is completed. + * In Non-block io mode, it return @ref SOCK_BUSY immediately. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param addr Pointer variable of destination IP address. It should be allocated 4 bytes. + * @param port Destination port number. + * + * @return @b Success : @ref SOCK_OK \n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number\n + * @ref SOCKERR_SOCKMODE - Invalid socket mode\n + * @ref SOCKERR_SOCKINIT - Socket is not initialized\n + * @ref SOCKERR_IPINVALID - Wrong server IP address\n + * @ref SOCKERR_PORTZERO - Server port zero\n + * @ref SOCKERR_TIMEOUT - Timeout occurred during request connection\n + * @ref SOCK_BUSY - In non-block io mode, it returned immediately\n + */ +int8_t connect(uint8_t sn, uint8_t * addr, uint16_t port); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Try to disconnect a connection socket. + * @details It sends request message to disconnect the TCP socket 'sn' passed as parameter to the server or client. + * @note It is valid only in TCP server or client mode. \n + * In block io mode, it does not return until disconnection is completed. \n + * In Non-block io mode, it return @ref SOCK_BUSY immediately. \n + + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @return @b Success : @ref SOCK_OK \n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n + * @ref SOCKERR_TIMEOUT - Timeout occurred \n + * @ref SOCK_BUSY - Socket is busy. + */ +int8_t disconnect(uint8_t sn); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Send data to the connected peer in TCP socket. + * @details It is used to send outgoing data to the connected socket. + * @note It is valid only in TCP server or client mode. It can't send data greater than socket buffer size. \n + * In block io mode, It doesn't return until data send is completed - socket buffer size is greater than data. \n + * In non-block io mode, It return @ref SOCK_BUSY immediately when socket buffer is not enough. \n + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer containing data to be sent. + * @param len The byte length of data in buf. + * @return @b Success : The sent data size \n + * @b Fail : \n @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n + * @ref SOCKERR_TIMEOUT - Timeout occurred \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n + * @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCK_BUSY - Socket is busy. + */ +int32_t send(uint8_t sn, uint8_t * buf, uint16_t len); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Receive data from the connected peer. + * @details It is used to read incoming data from the connected socket.\n + * It waits for data as much as the application wants to receive. + * @note It is valid only in TCP server or client mode. It can't receive data greater than socket buffer size. \n + * In block io mode, it doesn't return until data reception is completed - data is filled as len in socket buffer. \n + * In non-block io mode, it return @ref SOCK_BUSY immediately when len is greater than data size in socket buffer. \n + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer to read incoming data. + * @param len The max data length of data in buf. + * @return @b Success : The real received data size \n + * @b Fail :\n + * @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n + * @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCK_BUSY - Socket is busy. + */ +int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Sends datagram to the peer with destination IP address and port number passed as parameter. + * @details It sends datagram of UDP or MACRAW to the peer with destination IP address and port number passed as parameter.\n + * Even if the connectionless socket has been previously connected to a specific address, + * the address and port number parameters override the destination address for that particular datagram only. + * @note In block io mode, It doesn't return until data send is completed - socket buffer size is greater than len. + * In non-block io mode, It return @ref SOCK_BUSY immediately when socket buffer is not enough. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer to send outgoing data. + * @param len The byte length of data in buf. + * @param addr Pointer variable of destination IP address. It should be allocated 4 bytes. + * @param port Destination port number. + * + * @return @b Success : The sent data size \n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n + * @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n + * @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCKERR_IPINVALID - Wrong server IP address\n + * @ref SOCKERR_PORTZERO - Server port zero\n + * @ref SOCKERR_SOCKCLOSED - Socket unexpectedly closed \n + * @ref SOCKERR_TIMEOUT - Timeout occurred \n + * @ref SOCK_BUSY - Socket is busy. + */ +int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Receive datagram of UDP or MACRAW + * @details This function is an application I/F function which is used to receive the data in other then TCP mode. \n + * This function is used to receive UDP and MAC_RAW mode, and handle the header as well. + * This function can divide to received the packet data. + * On the MACRAW SOCKET, the addr and port parameters are ignored. + * @note In block io mode, it doesn't return until data reception is completed - data is filled as len in socket buffer + * In non-block io mode, it return @ref SOCK_BUSY immediately when len is greater than data size in socket buffer. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer to read incoming data. + * @param len The max data length of data in buf. + * When the received packet size <= len, receives data as packet sized. + * When others, receives data as len. + * @param addr Pointer variable of destination IP address. It should be allocated 4 bytes. + * It is valid only when the first call recvfrom for receiving the packet. + * When it is valid, @ref packinfo[7] should be set as '1' after call @ref getsockopt(sn, SO_PACKINFO, &packinfo). + * @param port Pointer variable of destination port number. + * It is valid only when the first call recvform for receiving the packet. +* When it is valid, @ref packinfo[7] should be set as '1' after call @ref getsockopt(sn, SO_PACKINFO, &packinfo). + * + * @return @b Success : This function return real received data size for success.\n + * @b Fail : @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n + * @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKBUSY - Socket is busy. + */ +int32_t recvfrom(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port); + + +///////////////////////////// +// SOCKET CONTROL & OPTION // +///////////////////////////// +#define SOCK_IO_BLOCK 0 ///< Socket Block IO Mode in @ref setsockopt(). +#define SOCK_IO_NONBLOCK 1 ///< Socket Non-block IO Mode in @ref setsockopt(). + +/** + * @defgroup DATA_TYPE DATA TYPE + */ + +/** + * @ingroup DATA_TYPE + * @brief The kind of Socket Interrupt. + * @sa Sn_IR, Sn_IMR, setSn_IR(), getSn_IR(), setSn_IMR(), getSn_IMR() + */ +typedef enum +{ + SIK_CONNECTED = (1 << 0), ///< connected + SIK_DISCONNECTED = (1 << 1), ///< disconnected + SIK_RECEIVED = (1 << 2), ///< data received + SIK_TIMEOUT = (1 << 3), ///< timeout occurred + SIK_SENT = (1 << 4), ///< send ok + //M20150410 : Remove the comma of last member + //SIK_ALL = 0x1F, ///< all interrupt + SIK_ALL = 0x1F ///< all interrupt +}sockint_kind; + +/** + * @ingroup DATA_TYPE + * @brief The type of @ref ctlsocket(). + */ +typedef enum +{ + CS_SET_IOMODE, ///< set socket IO mode with @ref SOCK_IO_BLOCK or @ref SOCK_IO_NONBLOCK + CS_GET_IOMODE, ///< get socket IO mode + CS_GET_MAXTXBUF, ///< get the size of socket buffer allocated in TX memory + CS_GET_MAXRXBUF, ///< get the size of socket buffer allocated in RX memory + CS_CLR_INTERRUPT, ///< clear the interrupt of socket with @ref sockint_kind + CS_GET_INTERRUPT, ///< get the socket interrupt. refer to @ref sockint_kind +#if _WIZCHIP_ > 5100 + CS_SET_INTMASK, ///< set the interrupt mask of socket with @ref sockint_kind, Not supported in W5100 + CS_GET_INTMASK ///< get the masked interrupt of socket. refer to @ref sockint_kind, Not supported in W5100 +#endif +}ctlsock_type; + + +/** + * @ingroup DATA_TYPE + * @brief The type of socket option in @ref setsockopt() or @ref getsockopt() + */ +typedef enum +{ + SO_FLAG, ///< Valid only in getsockopt(), For set flag of socket refer to flag in @ref socket(). + SO_TTL, ///< Set TTL. @ref Sn_TTL ( @ref setSn_TTL(), @ref getSn_TTL() ) + SO_TOS, ///< Set TOS. @ref Sn_TOS ( @ref setSn_TOS(), @ref getSn_TOS() ) + SO_MSS, ///< Set MSS. @ref Sn_MSSR ( @ref setSn_MSSR(), @ref getSn_MSSR() ) + SO_DESTIP, ///< Set the destination IP address. @ref Sn_DIPR ( @ref setSn_DIPR(), @ref getSn_DIPR() ) + SO_DESTPORT, ///< Set the destination Port number. @ref Sn_DPORT ( @ref setSn_DPORT(), @ref getSn_DPORT() ) +#if _WIZCHIP_ != 5100 + SO_KEEPALIVESEND, ///< Valid only in setsockopt. Manually send keep-alive packet in TCP mode, Not supported in W5100 + #if _WIZCHIP_ > 5200 + SO_KEEPALIVEAUTO, ///< Set/Get keep-alive auto transmission timer in TCP mode, Not supported in W5100, W5200 + #endif +#endif + SO_SENDBUF, ///< Valid only in getsockopt. Get the free data size of Socekt TX buffer. @ref Sn_TX_FSR, @ref getSn_TX_FSR() + SO_RECVBUF, ///< Valid only in getsockopt. Get the received data size in socket RX buffer. @ref Sn_RX_RSR, @ref getSn_RX_RSR() + SO_STATUS, ///< Valid only in getsockopt. Get the socket status. @ref Sn_SR, @ref getSn_SR() + SO_REMAINSIZE, ///< Valid only in getsockopt. Get the remained packet size in other then TCP mode. + SO_PACKINFO ///< Valid only in getsockopt. Get the packet information as @ref PACK_FIRST, @ref PACK_REMAINED, and @ref PACK_COMPLETED in other then TCP mode. +}sockopt_type; + +/** + * @ingroup WIZnet_socket_APIs + * @brief Control socket. + * @details Control IO mode, Interrupt & Mask of socket and get the socket buffer information. + * Refer to @ref ctlsock_type. + * @param sn socket number + * @param cstype type of control socket. refer to @ref ctlsock_type. + * @param arg Data type and value is determined according to @ref ctlsock_type. \n + * + * + * + * + * + *
@b cstype @b data type@b value
@ref CS_SET_IOMODE \n @ref CS_GET_IOMODE uint8_t @ref SOCK_IO_BLOCK @ref SOCK_IO_NONBLOCK
@ref CS_GET_MAXTXBUF \n @ref CS_GET_MAXRXBUF uint16_t 0 ~ 16K
@ref CS_CLR_INTERRUPT \n @ref CS_GET_INTERRUPT \n @ref CS_SET_INTMASK \n @ref CS_GET_INTMASK @ref sockint_kind @ref SIK_CONNECTED, etc.
+ * @return @b Success @ref SOCK_OK \n + * @b fail @ref SOCKERR_ARG - Invalid argument\n + */ +int8_t ctlsocket(uint8_t sn, ctlsock_type cstype, void* arg); + +/** + * @ingroup WIZnet_socket_APIs + * @brief set socket options + * @details Set socket option like as TTL, MSS, TOS, and so on. Refer to @ref sockopt_type. + * + * @param sn socket number + * @param sotype socket option type. refer to @ref sockopt_type + * @param arg Data type and value is determined according to sotype. \n + * + * + * + * + * + * + * + * + * + *
@b sotype @b data type@b value
@ref SO_TTL uint8_t 0 ~ 255
@ref SO_TOS uint8_t 0 ~ 255
@ref SO_MSS uint16_t 0 ~ 65535
@ref SO_DESTIP uint8_t[4]
@ref SO_DESTPORT uint16_t 0 ~ 65535
@ref SO_KEEPALIVESEND null null
@ref SO_KEEPALIVEAUTO uint8_t 0 ~ 255
+ * @return + * - @b Success : @ref SOCK_OK \n + * - @b Fail + * - @ref SOCKERR_SOCKNUM - Invalid Socket number \n + * - @ref SOCKERR_SOCKMODE - Invalid socket mode \n + * - @ref SOCKERR_SOCKOPT - Invalid socket option or its value \n + * - @ref SOCKERR_TIMEOUT - Timeout occurred when sending keep-alive packet \n + */ +int8_t setsockopt(uint8_t sn, sockopt_type sotype, void* arg); + +/** + * @ingroup WIZnet_socket_APIs + * @brief get socket options + * @details Get socket option like as FLAG, TTL, MSS, and so on. Refer to @ref sockopt_type + * @param sn socket number + * @param sotype socket option type. refer to @ref sockopt_type + * @param arg Data type and value is determined according to sotype. \n + * + * + * + * + * + * + * + * + * + * + * + * + * + *
@b sotype @b data type@b value
@ref SO_FLAG uint8_t @ref SF_ETHER_OWN, etc...
@ref SO_TOS uint8_t 0 ~ 255
@ref SO_MSS uint16_t 0 ~ 65535
@ref SO_DESTIP uint8_t[4]
@ref SO_DESTPORT uint16_t
@ref SO_KEEPALIVEAUTO uint8_t 0 ~ 255
@ref SO_SENDBUF uint16_t 0 ~ 65535
@ref SO_RECVBUF uint16_t 0 ~ 65535
@ref SO_STATUS uint8_t @ref SOCK_ESTABLISHED, etc..
@ref SO_REMAINSIZE uint16_t 0~ 65535
@ref SO_PACKINFO uint8_t @ref PACK_FIRST, etc...
+ * @return + * - @b Success : @ref SOCK_OK \n + * - @b Fail + * - @ref SOCKERR_SOCKNUM - Invalid Socket number \n + * - @ref SOCKERR_SOCKOPT - Invalid socket option or its value \n + * - @ref SOCKERR_SOCKMODE - Invalid socket mode \n + * @note + * The option as PACK_REMAINED and SO_PACKINFO is valid only in NON-TCP mode and after call @ref recvfrom(). \n + * When SO_PACKINFO value is PACK_FIRST and the return value of recvfrom() is zero, + * This means the zero byte UDP data(UDP Header only) received. + */ +int8_t getsockopt(uint8_t sn, sockopt_type sotype, void* arg); + +#ifdef __cplusplus + } +#endif + +#endif // _SOCKET_H_ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/wizchip_conf.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/wizchip_conf.c new file mode 100644 index 0000000..6592b0c --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/wizchip_conf.c @@ -0,0 +1,903 @@ +//****************************************************************************/ +//! +//! \file wizchip_conf.c +//! \brief WIZCHIP Config Header File. +//! \version 1.0.1 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2014/05/01> V1.0.1 Refer to M20140501 +//! 1. Explicit type casting in wizchip_bus_readdata() & wizchip_bus_writedata() +// Issued by Mathias ClauBen. +//! uint32_t type converts into ptrdiff_t first. And then recoverting it into uint8_t* +//! For remove the warning when pointer type size is not 32bit. +//! If ptrdiff_t doesn't support in your complier, You should must replace ptrdiff_t into your suitable pointer type. +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * Redistributions in binary form must reproduce the above copyright +//! notice, this list of conditions and the following disclaimer in the +//! documentation and/or other materials provided with the distribution. +//! * Neither the name of the nor the names of its +//! contributors may be used to endorse or promote products derived +//! from this software without specific prior written permission. +//! +//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +//! THE POSSIBILITY OF SUCH DAMAGE. +// +//*****************************************************************************/ +//A20140501 : for use the type - ptrdiff_t +#include +// + +#include "wizchip_conf.h" + +///////////// +//M20150401 : Remove ; in the default callback function such as wizchip_cris_enter(), wizchip_cs_select() and etc. +///////////// + +/** + * @brief Default function to enable interrupt. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +//void wizchip_cris_enter(void) {}; +void wizchip_cris_enter(void) {} + +/** + * @brief Default function to disable interrupt. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +//void wizchip_cris_exit(void) {}; +void wizchip_cris_exit(void) {} + +/** + * @brief Default function to select chip. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +//void wizchip_cs_select(void) {}; +void wizchip_cs_select(void) {} + +/** + * @brief Default function to deselect chip. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +//void wizchip_cs_deselect(void) {}; +void wizchip_cs_deselect(void) {} + +/** + * @brief Default function to read in direct or indirect interface. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ + //M20150601 : Rename the function for integrating with W5300 +//uint8_t wizchip_bus_readbyte(uint32_t AddrSel) { return * ((volatile uint8_t *)((ptrdiff_t) AddrSel)); } +iodata_t wizchip_bus_readdata(uint32_t AddrSel) { return * ((volatile iodata_t *)((ptrdiff_t) AddrSel)); } + +/** + * @brief Default function to write in direct or indirect interface. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +//M20150601 : Rename the function for integrating with W5300 +//void wizchip_bus_writebyte(uint32_t AddrSel, uint8_t wb) { *((volatile uint8_t*)((ptrdiff_t)AddrSel)) = wb; } +void wizchip_bus_writedata(uint32_t AddrSel, iodata_t wb) { *((volatile iodata_t*)((ptrdiff_t)AddrSel)) = wb; } + +/** + * @brief Default function to read in SPI interface. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +//uint8_t wizchip_spi_readbyte(void) {return 0;}; +uint8_t wizchip_spi_readbyte(void) {return 0;} + +/** + * @brief Default function to write in SPI interface. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +//void wizchip_spi_writebyte(uint8_t wb) {}; +void wizchip_spi_writebyte(uint8_t wb) {} + +/** + * @brief Default function to burst read in SPI interface. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +//void wizchip_spi_readburst(uint8_t* pBuf, uint16_t len) {}; +void wizchip_spi_readburst(uint8_t* pBuf, uint16_t len) {} + +/** + * @brief Default function to burst write in SPI interface. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +//void wizchip_spi_writeburst(uint8_t* pBuf, uint16_t len) {}; +void wizchip_spi_writeburst(uint8_t* pBuf, uint16_t len) {} + +/** + * @\ref _WIZCHIP instance + */ +// +//M20150401 : For a compiler didnot support a member of structure +// Replace the assignment of struct members with the assingment of array +// +/* +_WIZCHIP WIZCHIP = + { + .id = _WIZCHIP_ID_, + .if_mode = _WIZCHIP_IO_MODE_, + .CRIS._enter = wizchip_cris_enter, + .CRIS._exit = wizchip_cris_exit, + .CS._select = wizchip_cs_select, + .CS._deselect = wizchip_cs_deselect, + .IF.BUS._read_byte = wizchip_bus_readbyte, + .IF.BUS._write_byte = wizchip_bus_writebyte +// .IF.SPI._read_byte = wizchip_spi_readbyte, +// .IF.SPI._write_byte = wizchip_spi_writebyte + }; +*/ +_WIZCHIP WIZCHIP = +{ + _WIZCHIP_IO_MODE_, + _WIZCHIP_ID_ , + { + wizchip_cris_enter, + wizchip_cris_exit + }, + { + wizchip_cs_select, + wizchip_cs_deselect + }, + { + { + //M20150601 : Rename the function + //wizchip_bus_readbyte, + //wizchip_bus_writebyte + wizchip_bus_readdata, + wizchip_bus_writedata + }, + + } +}; + + +static uint8_t _DNS_[4]; // DNS server ip address +static dhcp_mode _DHCP_; // DHCP mode + +void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void)) +{ + if(!cris_en || !cris_ex) + { + WIZCHIP.CRIS._enter = wizchip_cris_enter; + WIZCHIP.CRIS._exit = wizchip_cris_exit; + } + else + { + WIZCHIP.CRIS._enter = cris_en; + WIZCHIP.CRIS._exit = cris_ex; + } +} + +void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void)) +{ + if(!cs_sel || !cs_desel) + { + WIZCHIP.CS._select = wizchip_cs_select; + WIZCHIP.CS._deselect = wizchip_cs_deselect; + } + else + { + WIZCHIP.CS._select = cs_sel; + WIZCHIP.CS._deselect = cs_desel; + } +} + +//M20150515 : For integrating with W5300 +//void reg_wizchip_bus_cbfunc(uint8_t(*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, uint8_t wb)) +void reg_wizchip_bus_cbfunc(iodata_t(*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, iodata_t wb)) +{ + while(!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_BUS_)); + //M20150601 : Rename call back function for integrating with W5300 + /* + if(!bus_rb || !bus_wb) + { + WIZCHIP.IF.BUS._read_byte = wizchip_bus_readbyte; + WIZCHIP.IF.BUS._write_byte = wizchip_bus_writebyte; + } + else + { + WIZCHIP.IF.BUS._read_byte = bus_rb; + WIZCHIP.IF.BUS._write_byte = bus_wb; + } + */ + if(!bus_rb || !bus_wb) + { + WIZCHIP.IF.BUS._read_data = wizchip_bus_readdata; + WIZCHIP.IF.BUS._write_data = wizchip_bus_writedata; + } + else + { + WIZCHIP.IF.BUS._read_data = bus_rb; + WIZCHIP.IF.BUS._write_data = bus_wb; + } +} + +void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), void (*spi_wb)(uint8_t wb)) +{ + while(!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_SPI_)); + + if(!spi_rb || !spi_wb) + { + WIZCHIP.IF.SPI._read_byte = wizchip_spi_readbyte; + WIZCHIP.IF.SPI._write_byte = wizchip_spi_writebyte; + } + else + { + WIZCHIP.IF.SPI._read_byte = spi_rb; + WIZCHIP.IF.SPI._write_byte = spi_wb; + } +} + +// 20140626 Eric Added for SPI burst operations +void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t* pBuf, uint16_t len), void (*spi_wb)(uint8_t* pBuf, uint16_t len)) +{ + while(!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_SPI_)); + + if(!spi_rb || !spi_wb) + { + WIZCHIP.IF.SPI._read_burst = wizchip_spi_readburst; + WIZCHIP.IF.SPI._write_burst = wizchip_spi_writeburst; + } + else + { + WIZCHIP.IF.SPI._read_burst = spi_rb; + WIZCHIP.IF.SPI._write_burst = spi_wb; + } +} + +int8_t ctlwizchip(ctlwizchip_type cwtype, void* arg) +{ +#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5200 || _WIZCHIP_ == W5500 + uint8_t tmp = 0; +#endif + uint8_t* ptmp[2] = {0,0}; + switch(cwtype) + { + case CW_RESET_WIZCHIP: + wizchip_sw_reset(); + break; + case CW_INIT_WIZCHIP: + if(arg != 0) + { + ptmp[0] = (uint8_t*)arg; + ptmp[1] = ptmp[0] + _WIZCHIP_SOCK_NUM_; + } + return wizchip_init(ptmp[0], ptmp[1]); + case CW_CLR_INTERRUPT: + wizchip_clrinterrupt(*((intr_kind*)arg)); + break; + case CW_GET_INTERRUPT: + *((intr_kind*)arg) = wizchip_getinterrupt(); + break; + case CW_SET_INTRMASK: + wizchip_setinterruptmask(*((intr_kind*)arg)); + break; + case CW_GET_INTRMASK: + *((intr_kind*)arg) = wizchip_getinterruptmask(); + break; + //M20150601 : This can be supported by W5200, W5500 + //#if _WIZCHIP_ > W5100 + #if (_WIZCHIP_ == W5200 || _WIZCHIP_ == W5500) + case CW_SET_INTRTIME: + setINTLEVEL(*(uint16_t*)arg); + break; + case CW_GET_INTRTIME: + *(uint16_t*)arg = getINTLEVEL(); + break; + #endif + case CW_GET_ID: + ((uint8_t*)arg)[0] = WIZCHIP.id[0]; + ((uint8_t*)arg)[1] = WIZCHIP.id[1]; + ((uint8_t*)arg)[2] = WIZCHIP.id[2]; + ((uint8_t*)arg)[3] = WIZCHIP.id[3]; + ((uint8_t*)arg)[4] = WIZCHIP.id[4]; + ((uint8_t*)arg)[5] = 0; + break; + #if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5500 + case CW_RESET_PHY: + wizphy_reset(); + break; + case CW_SET_PHYCONF: + wizphy_setphyconf((wiz_PhyConf*)arg); + break; + case CW_GET_PHYCONF: + wizphy_getphyconf((wiz_PhyConf*)arg); + break; + case CW_GET_PHYSTATUS: + break; + case CW_SET_PHYPOWMODE: + return wizphy_setphypmode(*(uint8_t*)arg); + #endif + #if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5200 || _WIZCHIP_ == W5500 + case CW_GET_PHYPOWMODE: + tmp = wizphy_getphypmode(); + if((int8_t)tmp == -1) return -1; + *(uint8_t*)arg = tmp; + break; + case CW_GET_PHYLINK: + tmp = wizphy_getphylink(); + if((int8_t)tmp == -1) return -1; + *(uint8_t*)arg = tmp; + break; + #endif + default: + return -1; + } + return 0; +} + + +int8_t ctlnetwork(ctlnetwork_type cntype, void* arg) +{ + + switch(cntype) + { + case CN_SET_NETINFO: + wizchip_setnetinfo((wiz_NetInfo*)arg); + break; + case CN_GET_NETINFO: + wizchip_getnetinfo((wiz_NetInfo*)arg); + break; + case CN_SET_NETMODE: + return wizchip_setnetmode(*(netmode_type*)arg); + case CN_GET_NETMODE: + *(netmode_type*)arg = wizchip_getnetmode(); + break; + case CN_SET_TIMEOUT: + wizchip_settimeout((wiz_NetTimeout*)arg); + break; + case CN_GET_TIMEOUT: + wizchip_gettimeout((wiz_NetTimeout*)arg); + break; + default: + return -1; + } + return 0; +} + +void wizchip_sw_reset(void) +{ + uint8_t gw[4], sn[4], sip[4]; + uint8_t mac[6]; +//A20150601 +#if _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_ + uint16_t mr = (uint16_t)getMR(); + setMR(mr | MR_IND); +#endif +// + getSHAR(mac); + getGAR(gw); getSUBR(sn); getSIPR(sip); + setMR(MR_RST); + getMR(); // for delay +//A2015051 : For indirect bus mode +#if _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_ + setMR(mr | MR_IND); +#endif +// + setSHAR(mac); + setGAR(gw); + setSUBR(sn); + setSIPR(sip); +} + +int8_t wizchip_init(uint8_t* txsize, uint8_t* rxsize) +{ + int8_t i; +#if _WIZCHIP_ < W5200 + int8_t j; +#endif + int8_t tmp = 0; + wizchip_sw_reset(); + if(txsize) + { + tmp = 0; + //M20150601 : For integrating with W5300 + #if _WIZCHIP_ == W5300 + for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++) + { + if(txsize[i] >= 64) return -1; //No use 64KB even if W5300 support max 64KB memory allocation + tmp += txsize[i]; + if(tmp > 128) return -1; + } + if(tmp % 8) return -1; + #else + for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++) + { + tmp += txsize[i]; + + #if _WIZCHIP_ < W5200 //2016.10.28 peter add condition for w5100 and w5100s + if(tmp > 8) return -1; + #else + if(tmp > 16) return -1; + #endif + } + for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++) + { + #if _WIZCHIP_ < W5200 //2016.10.28 peter add condition for w5100 + j = 0; + while((txsize[i] >> j != 1)&&(txsize[i] !=0)){j++;} + setSn_TXBUF_SIZE(i, j); + #else + setSn_TXBUF_SIZE(i, txsize[i]); + #endif + } + + #endif + } + + if(rxsize) + { + tmp = 0; + #if _WIZCHIP_ == W5300 + for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++) + { + if(rxsize[i] >= 64) return -1; //No use 64KB even if W5300 support max 64KB memory allocation + tmp += rxsize[i]; + if(tmp > 128) return -1; + } + if(tmp % 8) return -1; + #else + for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++) + { + tmp += rxsize[i]; + #if _WIZCHIP_ < W5200 //2016.10.28 peter add condition for w5100 and w5100s + if(tmp > 8) return -1; + #else + if(tmp > 16) return -1; + #endif + } + + for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++) + { + #if _WIZCHIP_ < W5200 // add condition for w5100 + j = 0; + while((rxsize[i] >> j != 1)&&(txsize[i] !=0)){j++;} + setSn_RXBUF_SIZE(i, j); + #else + setSn_RXBUF_SIZE(i, rxsize[i]); + #endif + } + #endif + } + return 0; +} + +void wizchip_clrinterrupt(intr_kind intr) +{ + uint8_t ir = (uint8_t)intr; + uint8_t sir = (uint8_t)((uint16_t)intr >> 8); +#if _WIZCHIP_ < W5500 + ir |= (1<<4); // IK_WOL +#endif +#if _WIZCHIP_ == W5200 + ir |= (1 << 6); +#endif + +#if _WIZCHIP_ < W5200 + sir &= 0x0F; +#endif + +#if _WIZCHIP_ <= W5100S + ir |= sir; + setIR(ir); +//A20150601 : For integrating with W5300 +#elif _WIZCHIP_ == W5300 + setIR( ((((uint16_t)ir) << 8) | (((uint16_t)sir) & 0x00FF)) ); +#else + setIR(ir); + setSIR(sir); +#endif +} + +intr_kind wizchip_getinterrupt(void) +{ + uint8_t ir = 0; + uint8_t sir = 0; + uint16_t ret = 0; +#if _WIZCHIP_ <= W5100S + ir = getIR(); + sir = ir & 0x0F; +//A20150601 : For integrating with W5300 +#elif _WIZCHIP_ == W5300 + ret = getIR(); + ir = (uint8_t)(ret >> 8); + sir = (uint8_t)ret; +#else + ir = getIR(); + sir = getSIR(); +#endif + +//M20150601 : For Integrating with W5300 +//#if _WIZCHIP_ < W5500 +#if _WIZCHIP_ < W5200 + ir &= ~(1<<4); // IK_WOL +#endif +#if _WIZCHIP_ == W5200 + ir &= ~(1 << 6); +#endif + ret = sir; + ret = (ret << 8) + ir; + return (intr_kind)ret; +} + +void wizchip_setinterruptmask(intr_kind intr) +{ + uint8_t imr = (uint8_t)intr; + uint8_t simr = (uint8_t)((uint16_t)intr >> 8); +#if _WIZCHIP_ < W5500 + imr &= ~(1<<4); // IK_WOL +#endif +#if _WIZCHIP_ == W5200 + imr &= ~(1 << 6); +#endif + +#if _WIZCHIP_ < W5200 + simr &= 0x0F; + imr |= simr; + setIMR(imr); +//A20150601 : For integrating with W5300 +#elif _WIZCHIP_ == W5300 + setIMR( ((((uint16_t)imr) << 8) | (((uint16_t)simr) & 0x00FF)) ); +#else + setIMR(imr); + setSIMR(simr); +#endif +} + +intr_kind wizchip_getinterruptmask(void) +{ + uint8_t imr = 0; + uint8_t simr = 0; + uint16_t ret = 0; +#if _WIZCHIP_ < W5200 + imr = getIMR(); + simr = imr & 0x0F; +//A20150601 : For integrating with W5300 +#elif _WIZCHIP_ == W5300 + ret = getIMR(); + imr = (uint8_t)(ret >> 8); + simr = (uint8_t)ret; +#else + imr = getIMR(); + simr = getSIMR(); +#endif + +#if _WIZCHIP_ < W5500 + imr &= ~(1<<4); // IK_WOL +#endif +#if _WIZCHIP_ == W5200 + imr &= ~(1 << 6); // IK_DEST_UNREACH +#endif + ret = simr; + ret = (ret << 8) + imr; + return (intr_kind)ret; +} + +int8_t wizphy_getphylink(void) +{ + int8_t tmp = PHY_LINK_OFF; +#if _WIZCHIP_ == W5100S + if(getPHYSR() & PHYSR_LNK) + tmp = PHY_LINK_ON; +#elif _WIZCHIP_ == W5200 + if(getPHYSTATUS() & PHYSTATUS_LINK) + tmp = PHY_LINK_ON; +#elif _WIZCHIP_ == W5500 + if(getPHYCFGR() & PHYCFGR_LNK_ON) + tmp = PHY_LINK_ON; + +#else + tmp = -1; +#endif + return tmp; +} + +#if _WIZCHIP_ > W5100 + +int8_t wizphy_getphypmode(void) +{ + int8_t tmp = 0; + #if _WIZCHIP_ == W5200 + if(getPHYSTATUS() & PHYSTATUS_POWERDOWN) + tmp = PHY_POWER_DOWN; + else + tmp = PHY_POWER_NORM; + #elif _WIZCHIP_ == 5500 + if((getPHYCFGR() & PHYCFGR_OPMDC_ALLA) == PHYCFGR_OPMDC_PDOWN) + tmp = PHY_POWER_DOWN; + else + tmp = PHY_POWER_NORM; + #else + tmp = -1; + #endif + return tmp; +} +#endif + +#if _WIZCHIP_ == W5100S +void wizphy_reset(void) +{ + uint16_t tmp = wiz_mdio_read(PHYMDIO_BMCR); + tmp |= BMCR_RESET; + wiz_mdio_write(PHYMDIO_BMCR, tmp); + while(wiz_mdio_read(PHYMDIO_BMCR)&BMCR_RESET){} +} + +void wizphy_setphyconf(wiz_PhyConf* phyconf) +{ + uint16_t tmp = wiz_mdio_read(PHYMDIO_BMCR); + if(phyconf->mode == PHY_MODE_AUTONEGO) + tmp |= BMCR_AUTONEGO; + else + { + tmp &= ~BMCR_AUTONEGO; + if(phyconf->duplex == PHY_DUPLEX_FULL) + { + tmp |= BMCR_DUP; + } + else + { + tmp &= ~BMCR_DUP; + } + if(phyconf->speed == PHY_SPEED_100) + { + tmp |= BMCR_SPEED; + } + else + { + tmp &= ~BMCR_SPEED; + } + } + wiz_mdio_write(PHYMDIO_BMCR, tmp); +} + +void wizphy_getphyconf(wiz_PhyConf* phyconf) +{ + uint16_t tmp = 0; + tmp = wiz_mdio_read(PHYMDIO_BMCR); + phyconf->by = PHY_CONFBY_SW; + if(tmp & BMCR_AUTONEGO) + { + phyconf->mode = PHY_MODE_AUTONEGO; + } + else + { + phyconf->mode = PHY_MODE_MANUAL; + if(tmp&BMCR_DUP) phyconf->duplex = PHY_DUPLEX_FULL; + else phyconf->duplex = PHY_DUPLEX_HALF; + if(tmp&BMCR_SPEED) phyconf->speed = PHY_SPEED_100; + else phyconf->speed = PHY_SPEED_10; + } +} + +int8_t wizphy_setphypmode(uint8_t pmode) +{ + uint16_t tmp = 0; + tmp = wiz_mdio_read(PHYMDIO_BMCR); + if( pmode == PHY_POWER_DOWN) + { + tmp |= BMCR_PWDN; + } + else + { + tmp &= ~BMCR_PWDN; + } + wiz_mdio_write(PHYMDIO_BMCR, tmp); + tmp = wiz_mdio_read(PHYMDIO_BMCR); + if( pmode == PHY_POWER_DOWN) + { + if(tmp & BMCR_PWDN) return 0; + } + else + { + if((tmp & BMCR_PWDN) != BMCR_PWDN) return 0; + } + return -1; +} + +#endif +#if _WIZCHIP_ == W5500 +void wizphy_reset(void) +{ + uint8_t tmp = getPHYCFGR(); + tmp &= PHYCFGR_RST; + setPHYCFGR(tmp); + tmp = getPHYCFGR(); + tmp |= ~PHYCFGR_RST; + setPHYCFGR(tmp); +} + +void wizphy_setphyconf(wiz_PhyConf* phyconf) +{ + uint8_t tmp = 0; + if(phyconf->by == PHY_CONFBY_SW) + tmp |= PHYCFGR_OPMD; + else + tmp &= ~PHYCFGR_OPMD; + if(phyconf->mode == PHY_MODE_AUTONEGO) + tmp |= PHYCFGR_OPMDC_ALLA; + else + { + if(phyconf->duplex == PHY_DUPLEX_FULL) + { + if(phyconf->speed == PHY_SPEED_100) + tmp |= PHYCFGR_OPMDC_100F; + else + tmp |= PHYCFGR_OPMDC_10F; + } + else + { + if(phyconf->speed == PHY_SPEED_100) + tmp |= PHYCFGR_OPMDC_100H; + else + tmp |= PHYCFGR_OPMDC_10H; + } + } + setPHYCFGR(tmp); + wizphy_reset(); +} + +void wizphy_getphyconf(wiz_PhyConf* phyconf) +{ + uint8_t tmp = 0; + tmp = getPHYCFGR(); + phyconf->by = (tmp & PHYCFGR_OPMD) ? PHY_CONFBY_SW : PHY_CONFBY_HW; + switch(tmp & PHYCFGR_OPMDC_ALLA) + { + case PHYCFGR_OPMDC_ALLA: + case PHYCFGR_OPMDC_100FA: + phyconf->mode = PHY_MODE_AUTONEGO; + break; + default: + phyconf->mode = PHY_MODE_MANUAL; + break; + } + switch(tmp & PHYCFGR_OPMDC_ALLA) + { + case PHYCFGR_OPMDC_100FA: + case PHYCFGR_OPMDC_100F: + case PHYCFGR_OPMDC_100H: + phyconf->speed = PHY_SPEED_100; + break; + default: + phyconf->speed = PHY_SPEED_10; + break; + } + switch(tmp & PHYCFGR_OPMDC_ALLA) + { + case PHYCFGR_OPMDC_100FA: + case PHYCFGR_OPMDC_100F: + case PHYCFGR_OPMDC_10F: + phyconf->duplex = PHY_DUPLEX_FULL; + break; + default: + phyconf->duplex = PHY_DUPLEX_HALF; + break; + } +} + +void wizphy_getphystat(wiz_PhyConf* phyconf) +{ + uint8_t tmp = getPHYCFGR(); + phyconf->duplex = (tmp & PHYCFGR_DPX_FULL) ? PHY_DUPLEX_FULL : PHY_DUPLEX_HALF; + phyconf->speed = (tmp & PHYCFGR_SPD_100) ? PHY_SPEED_100 : PHY_SPEED_10; +} + +int8_t wizphy_setphypmode(uint8_t pmode) +{ + uint8_t tmp = 0; + tmp = getPHYCFGR(); + if((tmp & PHYCFGR_OPMD)== 0) return -1; + tmp &= ~PHYCFGR_OPMDC_ALLA; + if( pmode == PHY_POWER_DOWN) + tmp |= PHYCFGR_OPMDC_PDOWN; + else + tmp |= PHYCFGR_OPMDC_ALLA; + setPHYCFGR(tmp); + wizphy_reset(); + tmp = getPHYCFGR(); + if( pmode == PHY_POWER_DOWN) + { + if(tmp & PHYCFGR_OPMDC_PDOWN) return 0; + } + else + { + if(tmp & PHYCFGR_OPMDC_ALLA) return 0; + } + return -1; +} +#endif + + +void wizchip_setnetinfo(wiz_NetInfo* pnetinfo) +{ + setSHAR(pnetinfo->mac); + setGAR(pnetinfo->gw); + setSUBR(pnetinfo->sn); + setSIPR(pnetinfo->ip); + _DNS_[0] = pnetinfo->dns[0]; + _DNS_[1] = pnetinfo->dns[1]; + _DNS_[2] = pnetinfo->dns[2]; + _DNS_[3] = pnetinfo->dns[3]; + _DHCP_ = pnetinfo->dhcp; +} + +void wizchip_getnetinfo(wiz_NetInfo* pnetinfo) +{ + getSHAR(pnetinfo->mac); + getGAR(pnetinfo->gw); + getSUBR(pnetinfo->sn); + getSIPR(pnetinfo->ip); + pnetinfo->dns[0]= _DNS_[0]; + pnetinfo->dns[1]= _DNS_[1]; + pnetinfo->dns[2]= _DNS_[2]; + pnetinfo->dns[3]= _DNS_[3]; + pnetinfo->dhcp = _DHCP_; +} + +int8_t wizchip_setnetmode(netmode_type netmode) +{ + uint8_t tmp = 0; +#if _WIZCHIP_ != W5500 + if(netmode & ~(NM_WAKEONLAN | NM_PPPOE | NM_PINGBLOCK)) return -1; +#else + if(netmode & ~(NM_WAKEONLAN | NM_PPPOE | NM_PINGBLOCK | NM_FORCEARP)) return -1; +#endif + tmp = getMR(); + tmp |= (uint8_t)netmode; + setMR(tmp); + return 0; +} + +netmode_type wizchip_getnetmode(void) +{ + return (netmode_type) getMR(); +} + +void wizchip_settimeout(wiz_NetTimeout* nettime) +{ + setRCR(nettime->retry_cnt); + setRTR(nettime->time_100us); +} + +void wizchip_gettimeout(wiz_NetTimeout* nettime) +{ + nettime->retry_cnt = getRCR(); + nettime->time_100us = getRTR(); +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/wizchip_conf.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/wizchip_conf.h new file mode 100644 index 0000000..5d6c1c1 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Ethernet/wizchip_conf.h @@ -0,0 +1,660 @@ +//***************************************************************************** +// +//! \file wizchip_conf.h +//! \brief WIZCHIP Config Header File. +//! \version 1.0.0 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * Redistributions in binary form must reproduce the above copyright +//! notice, this list of conditions and the following disclaimer in the +//! documentation and/or other materials provided with the distribution. +//! * Neither the name of the nor the names of its +//! contributors may be used to endorse or promote products derived +//! from this software without specific prior written permission. +//! +//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +//! THE POSSIBILITY OF SUCH DAMAGE. +// +//***************************************************************************** + +/** + * @defgroup extra_functions 2. WIZnet Extra Functions + * + * @brief These functions is optional function. It could be replaced at WIZCHIP I/O function because they were made by WIZCHIP I/O functions. + * @details There are functions of configuring WIZCHIP, network, interrupt, phy, network information and timer. \n + * + */ + +#ifndef _WIZCHIP_CONF_H_ +#define _WIZCHIP_CONF_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +/** + * @brief Select WIZCHIP. + * @todo You should select one, \b W5100, \b W5100S, \b W5200, \b W5300, \b W5500 or etc. \n\n + * ex> #define \_WIZCHIP_ W5500 + */ + +#define W5100 5100 +#define W5100S 5100+5 +#define W5200 5200 +#define W5300 5300 +#define W5500 5500 + +#ifndef _WIZCHIP_ +#define _WIZCHIP_ W5500 // W5100, W5100S, W5200, W5300, W5500 +#endif + +#define _WIZCHIP_IO_MODE_NONE_ 0x0000 +#define _WIZCHIP_IO_MODE_BUS_ 0x0100 /**< Bus interface mode */ +#define _WIZCHIP_IO_MODE_SPI_ 0x0200 /**< SPI interface mode */ +//#define _WIZCHIP_IO_MODE_IIC_ 0x0400 +//#define _WIZCHIP_IO_MODE_SDIO_ 0x0800 +// Add to +// + +#define _WIZCHIP_IO_MODE_BUS_DIR_ (_WIZCHIP_IO_MODE_BUS_ + 1) /**< BUS interface mode for direct */ +#define _WIZCHIP_IO_MODE_BUS_INDIR_ (_WIZCHIP_IO_MODE_BUS_ + 2) /**< BUS interface mode for indirect */ + +#define _WIZCHIP_IO_MODE_SPI_VDM_ (_WIZCHIP_IO_MODE_SPI_ + 1) /**< SPI interface mode for variable length data*/ +#define _WIZCHIP_IO_MODE_SPI_FDM_ (_WIZCHIP_IO_MODE_SPI_ + 2) /**< SPI interface mode for fixed length data mode*/ +#define _WIZCHIP_IO_MODE_SPI_5500_ (_WIZCHIP_IO_MODE_SPI_ + 3) /**< SPI interface mode for fixed length data mode*/ + +#if (_WIZCHIP_ == W5100) + #define _WIZCHIP_ID_ "W5100\0" +/** + * @brief Define interface mode. + * @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref \_WIZCHIP_IO_MODE_BUS_INDIR_ + */ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_DIR_ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_ + #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_ + +//A20150601 : Define the unit of IO DATA. + typedef uint8_t iodata_t; +//A20150401 : Indclude W5100.h file + #include "W5100/w5100.h" + +#elif (_WIZCHIP_ == W5100S) +#define _WIZCHIP_ID_ "W5100S\0" +/** +* @brief Define interface mode. +* @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref \_WIZCHIP_IO_MODE_BUS_INDIR_ +*/ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_ + //#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_5500_ + #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_ + +//A20150601 : Define the unit of IO DATA. + typedef uint8_t iodata_t; +//A20150401 : Indclude W5100.h file + #include "W5100S/w5100s.h" +#elif (_WIZCHIP_ == W5200) + #define _WIZCHIP_ID_ "W5200\0" +/** + * @brief Define interface mode. + * @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ or @ref \ _WIZCHIP_IO_MODE_BUS_INDIR_ + */ +#ifndef _WIZCHIP_IO_MODE_ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_ + #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_ +#endif +//A20150601 : Define the unit of IO DATA. + typedef uint8_t iodata_t; + #include "W5200/w5200.h" +#elif (_WIZCHIP_ == W5500) + #define _WIZCHIP_ID_ "W5500\0" + +/** + * @brief Define interface mode. \n + * @todo Should select interface mode as chip. + * - @ref \_WIZCHIP_IO_MODE_SPI_ \n + * -@ref \_WIZCHIP_IO_MODE_SPI_VDM_ : Valid only in @ref \_WIZCHIP_ == W5500 \n + * -@ref \_WIZCHIP_IO_MODE_SPI_FDM_ : Valid only in @ref \_WIZCHIP_ == W5500 \n + * - @ref \_WIZCHIP_IO_MODE_BUS_ \n + * - @ref \_WIZCHIP_IO_MODE_BUS_DIR_ \n + * - @ref \_WIZCHIP_IO_MODE_BUS_INDIR_ \n + * - Others will be defined in future. \n\n + * ex> #define \_WIZCHIP_IO_MODE_ \_WIZCHIP_IO_MODE_SPI_VDM_ + * + */ +#ifndef _WIZCHIP_IO_MODE_ + //#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_FDM_ + #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_VDM_ +#endif +//A20150601 : Define the unit of IO DATA. + typedef uint8_t iodata_t; + #include "W5500/w5500.h" +#elif ( _WIZCHIP_ == W5300) + #define _WIZCHIP_ID_ "W5300\0" +/** + * @brief Define interface mode. + * @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref \_WIZCHIP_IO_MODE_BUS_INDIR_ + */ +#ifndef _WIZCHIP_IO_MODE_ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_DIR_ + #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_ +#endif + +//A20150601 : Define the unit and bus width of IO DATA. + /** + * @brief Select the data width 8 or 16 bits. + * @todo you should select the bus width. Select one of 8 or 16. + */ + #ifndef _WIZCHIP_IO_BUS_WIDTH_ + #define _WIZCHIP_IO_BUS_WIDTH_ 8 // 16 + #endif + #if _WIZCHIP_IO_BUS_WIDTH_ == 8 + typedef uint8_t iodata_t; + #elif _WIZCHIP_IO_BUS_WIDTH_ == 16 + typedef uint16_t iodata_t; + #else + #error "Unknown _WIZCHIP_IO_BUS_WIDTH_. It should be 8 or 16." + #endif +// + #include "W5300/w5300.h" +#else + #error "Unknown defined _WIZCHIP_. You should define one of 5100, 5200, and 5500 !!!" +#endif + +#ifndef _WIZCHIP_IO_MODE_ + #error "Undefined _WIZCHIP_IO_MODE_. You should define it !!!" +#endif + +/** + * @brief Define I/O base address when BUS IF mode. + * @todo Should re-define it to fit your system when BUS IF Mode (@ref \_WIZCHIP_IO_MODE_BUS_, + * @ref \_WIZCHIP_IO_MODE_BUS_DIR_, @ref \_WIZCHIP_IO_MODE_BUS_INDIR_). \n\n + * ex> #define \_WIZCHIP_IO_BASE_ 0x00008000 + */ +#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS_ + #define _WIZCHIP_IO_BASE_ 0x60000000 // for 5100S IND +#elif _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SPI_ + #define _WIZCHIP_IO_BASE_ 0x00000000 // for 5100S SPI +#endif + +#ifndef _WIZCHIP_IO_BASE_ +#define _WIZCHIP_IO_BASE_ 0x00000000 // 0x8000 +#endif + +//M20150401 : Typing Error +//#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS +#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS_ + #ifndef _WIZCHIP_IO_BASE_ + #error "You should be define _WIZCHIP_IO_BASE to fit your system memory map." + #endif +#endif + +#if _WIZCHIP_ >= W5200 + #define _WIZCHIP_SOCK_NUM_ 8 ///< The count of independant socket of @b WIZCHIP +#else + #define _WIZCHIP_SOCK_NUM_ 4 ///< The count of independant socket of @b WIZCHIP +#endif + + +/******************************************************** +* WIZCHIP BASIC IF functions for SPI, SDIO, I2C , ETC. +*********************************************************/ +/** + * @ingroup DATA_TYPE + * @brief The set of callback functions for W5500:@ref WIZCHIP_IO_Functions W5200:@ref WIZCHIP_IO_Functions_W5200 + */ +typedef struct __WIZCHIP +{ + uint16_t if_mode; ///< host interface mode + uint8_t id[6]; ///< @b WIZCHIP ID such as @b 5100, @b 5200, @b 5500, and so on. + /** + * The set of critical section callback func. + */ + struct _CRIS + { + void (*_enter) (void); ///< crtical section enter + void (*_exit) (void); ///< critial section exit + }CRIS; + /** + * The set of @ref \_WIZCHIP_ select control callback func. + */ + struct _CS + { + void (*_select) (void); ///< @ref \_WIZCHIP_ selected + void (*_deselect)(void); ///< @ref \_WIZCHIP_ deselected + }CS; + /** + * The set of interface IO callback func. + */ + union _IF + { + /** + * For BUS interface IO + */ + //M20156501 : Modify the function name for integrating with W5300 + //struct + //{ + // uint8_t (*_read_byte) (uint32_t AddrSel); + // void (*_write_byte) (uint32_t AddrSel, uint8_t wb); + //}BUS; + struct + { + iodata_t (*_read_data) (uint32_t AddrSel); + void (*_write_data) (uint32_t AddrSel, iodata_t wb); + }BUS; + + /** + * For SPI interface IO + */ + struct + { + uint8_t (*_read_byte) (void); + void (*_write_byte) (uint8_t wb); + void (*_read_burst) (uint8_t* pBuf, uint16_t len); + void (*_write_burst) (uint8_t* pBuf, uint16_t len); + }SPI; + // To be added + // + }IF; +}_WIZCHIP; + +extern _WIZCHIP WIZCHIP; + +/** + * @ingroup DATA_TYPE + * WIZCHIP control type enumration used in @ref ctlwizchip(). + */ +typedef enum +{ + CW_RESET_WIZCHIP, ///< Resets WIZCHIP by softly + CW_INIT_WIZCHIP, ///< Initializes to WIZCHIP with SOCKET buffer size 2 or 1 dimension array typed uint8_t. + CW_GET_INTERRUPT, ///< Get Interrupt status of WIZCHIP + CW_CLR_INTERRUPT, ///< Clears interrupt + CW_SET_INTRMASK, ///< Masks interrupt + CW_GET_INTRMASK, ///< Get interrupt mask + CW_SET_INTRTIME, ///< Set interval time between the current and next interrupt. + CW_GET_INTRTIME, ///< Set interval time between the current and next interrupt. + CW_GET_ID, ///< Gets WIZCHIP name. + +//D20150601 : For no modification your application code +//#if _WIZCHIP_ == W5500 + CW_RESET_PHY, ///< Resets internal PHY. Valid Only W5500 + CW_SET_PHYCONF, ///< When PHY configured by internal register, PHY operation mode (Manual/Auto, 10/100, Half/Full). Valid Only W5000 + CW_GET_PHYCONF, ///< Get PHY operation mode in internal register. Valid Only W5500 + CW_GET_PHYSTATUS, ///< Get real PHY status on operating. Valid Only W5500 + CW_SET_PHYPOWMODE, ///< Set PHY power mode as normal and down when PHYSTATUS.OPMD == 1. Valid Only W5500 +//#endif +//D20150601 : For no modification your application code +//#if _WIZCHIP_ == W5200 || _WIZCHIP_ == W5500 + CW_GET_PHYPOWMODE, ///< Get PHY Power mode as down or normal, Valid Only W5100, W5200 + CW_GET_PHYLINK ///< Get PHY Link status, Valid Only W5100, W5200 +//#endif +}ctlwizchip_type; + +/** + * @ingroup DATA_TYPE + * Network control type enumration used in @ref ctlnetwork(). + */ +typedef enum +{ + CN_SET_NETINFO, ///< Set Network with @ref wiz_NetInfo + CN_GET_NETINFO, ///< Get Network with @ref wiz_NetInfo + CN_SET_NETMODE, ///< Set network mode as WOL, PPPoE, Ping Block, and Force ARP mode + CN_GET_NETMODE, ///< Get network mode as WOL, PPPoE, Ping Block, and Force ARP mode + CN_SET_TIMEOUT, ///< Set network timeout as retry count and time. + CN_GET_TIMEOUT, ///< Get network timeout as retry count and time. +}ctlnetwork_type; + +/** + * @ingroup DATA_TYPE + * Interrupt kind when CW_SET_INTRRUPT, CW_GET_INTERRUPT, CW_SET_INTRMASK + * and CW_GET_INTRMASK is used in @ref ctlnetwork(). + * It can be used with OR operation. + */ +typedef enum +{ +#if _WIZCHIP_ == W5500 + IK_WOL = (1 << 4), ///< Wake On Lan by receiving the magic packet. Valid in W500. +#elif _WIZCHIP_ == W5300 + IK_FMTU = (1 << 4), ///< Received a ICMP message (Fragment MTU) +#endif + + IK_PPPOE_TERMINATED = (1 << 5), ///< PPPoE Disconnected + +#if _WIZCHIP_ != W5200 + IK_DEST_UNREACH = (1 << 6), ///< Destination IP & Port Unreachable, No use in W5200 +#endif + + IK_IP_CONFLICT = (1 << 7), ///< IP conflict occurred + + IK_SOCK_0 = (1 << 8), ///< Socket 0 interrupt + IK_SOCK_1 = (1 << 9), ///< Socket 1 interrupt + IK_SOCK_2 = (1 << 10), ///< Socket 2 interrupt + IK_SOCK_3 = (1 << 11), ///< Socket 3 interrupt +#if _WIZCHIP_ > W5100S + IK_SOCK_4 = (1 << 12), ///< Socket 4 interrupt, No use in 5100 + IK_SOCK_5 = (1 << 13), ///< Socket 5 interrupt, No use in 5100 + IK_SOCK_6 = (1 << 14), ///< Socket 6 interrupt, No use in 5100 + IK_SOCK_7 = (1 << 15), ///< Socket 7 interrupt, No use in 5100 +#endif + +#if _WIZCHIP_ > W5100S + IK_SOCK_ALL = (0xFF << 8) ///< All Socket interrupt +#else + IK_SOCK_ALL = (0x0F << 8) ///< All Socket interrupt +#endif +}intr_kind; + +#define PHY_CONFBY_HW 0 ///< Configured PHY operation mode by HW pin +#define PHY_CONFBY_SW 1 ///< Configured PHY operation mode by SW register +#define PHY_MODE_MANUAL 0 ///< Configured PHY operation mode with user setting. +#define PHY_MODE_AUTONEGO 1 ///< Configured PHY operation mode with auto-negotiation +#define PHY_SPEED_10 0 ///< Link Speed 10 +#define PHY_SPEED_100 1 ///< Link Speed 100 +#define PHY_DUPLEX_HALF 0 ///< Link Half-Duplex +#define PHY_DUPLEX_FULL 1 ///< Link Full-Duplex +#define PHY_LINK_OFF 0 ///< Link Off +#define PHY_LINK_ON 1 ///< Link On +#define PHY_POWER_NORM 0 ///< PHY power normal mode +#define PHY_POWER_DOWN 1 ///< PHY power down mode + + +#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5500 +/** + * @ingroup DATA_TYPE + * It configures PHY configuration when CW_SET PHYCONF or CW_GET_PHYCONF in W5500, + * and it indicates the real PHY status configured by HW or SW in all WIZCHIP. \n + * Valid only in W5500. + */ +typedef struct wiz_PhyConf_t +{ + uint8_t by; ///< set by @ref PHY_CONFBY_HW or @ref PHY_CONFBY_SW + uint8_t mode; ///< set by @ref PHY_MODE_MANUAL or @ref PHY_MODE_AUTONEGO + uint8_t speed; ///< set by @ref PHY_SPEED_10 or @ref PHY_SPEED_100 + uint8_t duplex; ///< set by @ref PHY_DUPLEX_HALF @ref PHY_DUPLEX_FULL + //uint8_t power; ///< set by @ref PHY_POWER_NORM or @ref PHY_POWER_DOWN + //uint8_t link; ///< Valid only in CW_GET_PHYSTATUS. set by @ref PHY_LINK_ON or PHY_DUPLEX_OFF + }wiz_PhyConf; +#endif + +/** + * @ingroup DATA_TYPE + * It used in setting dhcp_mode of @ref wiz_NetInfo. + */ +typedef enum +{ + NETINFO_STATIC = 1, ///< Static IP configuration by manually. + NETINFO_DHCP ///< Dynamic IP configruation from a DHCP sever +}dhcp_mode; + +/** + * @ingroup DATA_TYPE + * Network Information for WIZCHIP + */ +typedef struct wiz_NetInfo_t +{ + uint8_t mac[6]; ///< Source Mac Address + uint8_t ip[4]; ///< Source IP Address + uint8_t sn[4]; ///< Subnet Mask + uint8_t gw[4]; ///< Gateway IP Address + uint8_t dns[4]; ///< DNS server IP Address + dhcp_mode dhcp; ///< 1 - Static, 2 - DHCP +}wiz_NetInfo; + +/** + * @ingroup DATA_TYPE + * Network mode + */ +typedef enum +{ +#if _WIZCHIP_ == W5500 + NM_FORCEARP = (1<<1), ///< Force to APP send whenever udp data is sent. Valid only in W5500 +#endif + NM_WAKEONLAN = (1<<5), ///< Wake On Lan + NM_PINGBLOCK = (1<<4), ///< Block ping-request + NM_PPPOE = (1<<3), ///< PPPoE mode +}netmode_type; + +/** + * @ingroup DATA_TYPE + * Used in CN_SET_TIMEOUT or CN_GET_TIMEOUT of @ref ctlwizchip() for timeout configruation. + */ +typedef struct wiz_NetTimeout_t +{ + uint8_t retry_cnt; ///< retry count + uint16_t time_100us; ///< time unit 100us +}wiz_NetTimeout; + +/** + *@brief Registers call back function for critical section of I/O functions such as + *\ref WIZCHIP_READ, @ref WIZCHIP_WRITE, @ref WIZCHIP_READ_BUF and @ref WIZCHIP_WRITE_BUF. + *@param cris_en : callback function for critical section enter. + *@param cris_ex : callback function for critical section exit. + *@todo Describe @ref WIZCHIP_CRITICAL_ENTER and @ref WIZCHIP_CRITICAL_EXIT marco or register your functions. + *@note If you do not describe or register, default functions(@ref wizchip_cris_enter & @ref wizchip_cris_exit) is called. + */ +void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void)); + + +/** + *@brief Registers call back function for WIZCHIP select & deselect. + *@param cs_sel : callback function for WIZCHIP select + *@param cs_desel : callback fucntion for WIZCHIP deselect + *@todo Describe @ref wizchip_cs_select and @ref wizchip_cs_deselect function or register your functions. + *@note If you do not describe or register, null function is called. + */ +void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void)); + +/** + *@brief Registers call back function for bus interface. + *@param bus_rb : callback function to read byte data using system bus + *@param bus_wb : callback function to write byte data using system bus + *@todo Describe @ref wizchip_bus_readbyte and @ref wizchip_bus_writebyte function + *or register your functions. + *@note If you do not describe or register, null function is called. + */ +//M20150601 : For integrating with W5300 +//void reg_wizchip_bus_cbfunc(uint8_t (*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, uint8_t wb)); +void reg_wizchip_bus_cbfunc(iodata_t (*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, iodata_t wb)); + +/** + *@brief Registers call back function for SPI interface. + *@param spi_rb : callback function to read byte using SPI + *@param spi_wb : callback function to write byte using SPI + *@todo Describe \ref wizchip_spi_readbyte and \ref wizchip_spi_writebyte function + *or register your functions. + *@note If you do not describe or register, null function is called. + */ +void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), void (*spi_wb)(uint8_t wb)); + +/** + *@brief Registers call back function for SPI interface. + *@param spi_rb : callback function to burst read using SPI + *@param spi_wb : callback function to burst write using SPI + *@todo Describe \ref wizchip_spi_readbyte and \ref wizchip_spi_writebyte function + *or register your functions. + *@note If you do not describe or register, null function is called. + */ +void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t* pBuf, uint16_t len), void (*spi_wb)(uint8_t* pBuf, uint16_t len)); + +/** + * @ingroup extra_functions + * @brief Controls to the WIZCHIP. + * @details Resets WIZCHIP & internal PHY, Configures PHY mode, Monitor PHY(Link,Speed,Half/Full/Auto), + * controls interrupt & mask and so on. + * @param cwtype : Decides to the control type + * @param arg : arg type is dependent on cwtype. + * @return 0 : Success \n + * -1 : Fail because of invalid \ref ctlwizchip_type or unsupported \ref ctlwizchip_type in WIZCHIP + */ +int8_t ctlwizchip(ctlwizchip_type cwtype, void* arg); + +/** + * @ingroup extra_functions + * @brief Controls to network. + * @details Controls to network environment, mode, timeout and so on. + * @param cntype : Input. Decides to the control type + * @param arg : Inout. arg type is dependent on cntype. + * @return -1 : Fail because of invalid \ref ctlnetwork_type or unsupported \ref ctlnetwork_type in WIZCHIP \n + * 0 : Success + */ +int8_t ctlnetwork(ctlnetwork_type cntype, void* arg); + + +/* + * The following functions are implemented for internal use. + * but You can call these functions for code size reduction instead of ctlwizchip() and ctlnetwork(). + */ + +/** + * @ingroup extra_functions + * @brief Reset WIZCHIP by softly. + */ +void wizchip_sw_reset(void); + +/** + * @ingroup extra_functions + * @brief Initializes WIZCHIP with socket buffer size + * @param txsize Socket tx buffer sizes. If null, initialized the default size 2KB. + * @param rxsize Socket rx buffer sizes. If null, initialized the default size 2KB. + * @return 0 : succcess \n + * -1 : fail. Invalid buffer size + */ +int8_t wizchip_init(uint8_t* txsize, uint8_t* rxsize); + +/** + * @ingroup extra_functions + * @brief Clear Interrupt of WIZCHIP. + * @param intr : @ref intr_kind value operated OR. It can type-cast to uint16_t. + */ +void wizchip_clrinterrupt(intr_kind intr); + +/** + * @ingroup extra_functions + * @brief Get Interrupt of WIZCHIP. + * @return @ref intr_kind value operated OR. It can type-cast to uint16_t. + */ +intr_kind wizchip_getinterrupt(void); + +/** + * @ingroup extra_functions + * @brief Mask or Unmask Interrupt of WIZCHIP. + * @param intr : @ref intr_kind value operated OR. It can type-cast to uint16_t. + */ +void wizchip_setinterruptmask(intr_kind intr); + +/** + * @ingroup extra_functions + * @brief Get Interrupt mask of WIZCHIP. + * @return : The operated OR vaule of @ref intr_kind. It can type-cast to uint16_t. + */ +intr_kind wizchip_getinterruptmask(void); + +//todo +#if _WIZCHIP_ > W5100 + int8_t wizphy_getphylink(void); ///< get the link status of phy in WIZCHIP. No use in W5100 + int8_t wizphy_getphypmode(void); ///< get the power mode of PHY in WIZCHIP. No use in W5100 +#endif + +#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5500 + void wizphy_reset(void); ///< Reset phy. Vailid only in W5500 +/** + * @ingroup extra_functions + * @brief Set the phy information for WIZCHIP without power mode + * @param phyconf : @ref wiz_PhyConf + */ + void wizphy_setphyconf(wiz_PhyConf* phyconf); + /** + * @ingroup extra_functions + * @brief Get phy configuration information. + * @param phyconf : @ref wiz_PhyConf + */ + void wizphy_getphyconf(wiz_PhyConf* phyconf); + /** + * @ingroup extra_functions + * @brief Get phy status. + * @param phyconf : @ref wiz_PhyConf + */ + void wizphy_getphystat(wiz_PhyConf* phyconf); + /** + * @ingroup extra_functions + * @brief set the power mode of phy inside WIZCHIP. Refer to @ref PHYCFGR in W5500, @ref PHYSTATUS in W5200 + * @param pmode Settig value of power down mode. + */ + int8_t wizphy_setphypmode(uint8_t pmode); +#endif + +/** +* @ingroup extra_functions + * @brief Set the network information for WIZCHIP + * @param pnetinfo : @ref wizNetInfo + */ +void wizchip_setnetinfo(wiz_NetInfo* pnetinfo); + +/** + * @ingroup extra_functions + * @brief Get the network information for WIZCHIP + * @param pnetinfo : @ref wizNetInfo + */ +void wizchip_getnetinfo(wiz_NetInfo* pnetinfo); + +/** + * @ingroup extra_functions + * @brief Set the network mode such WOL, PPPoE, Ping Block, and etc. + * @param pnetinfo Value of network mode. Refer to @ref netmode_type. + */ +int8_t wizchip_setnetmode(netmode_type netmode); + +/** + * @ingroup extra_functions + * @brief Get the network mode such WOL, PPPoE, Ping Block, and etc. + * @return Value of network mode. Refer to @ref netmode_type. + */ +netmode_type wizchip_getnetmode(void); + +/** + * @ingroup extra_functions + * @brief Set retry time value(@ref _RTR_) and retry count(@ref _RCR_). + * @details @ref _RTR_ configures the retransmission timeout period and @ref _RCR_ configures the number of time of retransmission. + * @param nettime @ref _RTR_ value and @ref _RCR_ value. Refer to @ref wiz_NetTimeout. + */ +void wizchip_settimeout(wiz_NetTimeout* nettime); + +/** + * @ingroup extra_functions + * @brief Get retry time value(@ref _RTR_) and retry count(@ref _RCR_). + * @details @ref _RTR_ configures the retransmission timeout period and @ref _RCR_ configures the number of time of retransmission. + * @param nettime @ref _RTR_ value and @ref _RCR_ value. Refer to @ref wiz_NetTimeout. + */ +void wizchip_gettimeout(wiz_NetTimeout* nettime); +#ifdef __cplusplus + } +#endif + +#endif // _WIZCHIP_CONF_H_ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpParser.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpParser.c new file mode 100644 index 0000000..41ee2db --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpParser.c @@ -0,0 +1,402 @@ +/** + @file httpd.c + @brief functions associated http processing + */ + +#include +#include +#include "socket.h" +#include "httpParser.h" + +/***************************************************************************** + * Public types/enumerations/variables + ****************************************************************************/ +//uint8_t BUFPUB[2048]; +uint8_t BUFPUB[256]; + +/***************************************************************************** + * Private functions + ****************************************************************************/ +static void replacetochar(uint8_t * str, uint8_t oldchar, uint8_t newchar); /* Replace old character with new character in the string */ +static uint8_t C2D(uint8_t c); /* Convert a character to HEX */ + +/** + @brief convert escape characters(%XX) to ASCII character + */ +void unescape_http_url( + char * url /**< pointer to be converted ( escape characters )*/ + ) +{ + int x, y; + + for (x = 0, y = 0; url[y]; ++x, ++y) { + if ((url[x] = url[y]) == '%') { + url[x] = C2D(url[y+1])*0x10+C2D(url[y+2]); + y+=2; + } + } + url[x] = '\0'; +} + + +/** + @brief make response header such as html, gif, jpeg,etc. + */ +void make_http_response_head( + char * buf, /**< pointer to response header to be made */ + char type, /**< response type */ + uint32_t len /**< size of response header */ + ) +{ + const char * head; + char tmp[10]; + + /* file type*/ + if (type == PTYPE_HTML) head = PSTR(RES_HTMLHEAD_OK); + else if (type == PTYPE_GIF) head = PSTR(RES_GIFHEAD_OK); + else if (type == PTYPE_TEXT) head = PSTR(RES_TEXTHEAD_OK); + else if (type == PTYPE_JPEG) head = PSTR(RES_JPEGHEAD_OK); + else if (type == PTYPE_FLASH) head = PSTR(RES_FLASHHEAD_OK); + else if (type == PTYPE_XML) head = PSTR(RES_XMLHEAD_OK); + else if (type == PTYPE_CSS) head = PSTR(RES_CSSHEAD_OK); + else if (type == PTYPE_JSON) head = PSTR(RES_JSONHEAD_OK); + else if (type == PTYPE_JS) head = PSTR(RES_JSHEAD_OK); + else if (type == PTYPE_CGI) head = PSTR(RES_CGIHEAD_OK); + else if (type == PTYPE_PNG) head = PSTR(RES_PNGHEAD_OK); + else if (type == PTYPE_ICO) head = PSTR(RES_ICOHEAD_OK); + else if (type == PTYPE_TTF) head = PSTR(RES_TTFHEAD_OK); + else if (type == PTYPE_OTF) head = PSTR(RES_OTFHEAD_OK); + else if (type == PTYPE_WOFF) head = PSTR(RES_WOFFHEAD_OK); + else if (type == PTYPE_EOT) head = PSTR(RES_EOTHEAD_OK); + else if (type == PTYPE_SVG) head = PSTR(RES_SVGHEAD_OK); +#ifdef _HTTPPARSER_DEBUG_ + else + { + head = NULL; + PRINTF("\r\n\r\n-MAKE HEAD UNKNOWN-\r\n"); + } +#else + else head = NULL; +#endif + + sprintf(tmp, "%ld", len); + strcpy_P(buf, head); + strcat(buf, tmp); + strcat(buf, "\r\n\r\n"); +} + + +/** + @brief find MIME type of a file + */ +void find_http_uri_type( + uint8_t * type, /**< type to be returned */ + uint8_t * buff /**< file name */ + ) +{ + /* Decide type according to extension*/ + + char * buf; + buf = (char *)buff; + + if (strcasestr_P(buf, PSTR(".htm")) || strcasestr_P(buf, PSTR(".html"))) *type = PTYPE_HTML; + else if (strcasestr_P(buf, PSTR(".gif"))) *type = PTYPE_GIF; + else if (strcasestr_P(buf, PSTR(".text")) || strstr_P(buf,PSTR(".txt"))) *type = PTYPE_TEXT; + else if (strcasestr_P(buf, PSTR(".jpeg")) || strstr_P(buf,PSTR(".jpg"))) *type = PTYPE_JPEG; + else if (strcasestr_P(buf, PSTR(".swf"))) *type = PTYPE_FLASH; + else if (strstr_P(buf, PSTR(".cgi")) || strstr_P(buf,PSTR(".CGI"))) *type = PTYPE_CGI; + else if (strstr_P(buf, PSTR(".json")) || strstr_P(buf,PSTR(".JSON"))) *type = PTYPE_JSON; + else if (strstr_P(buf, PSTR(".js")) || strstr_P(buf,PSTR(".JS"))) *type = PTYPE_JS; + else if (strstr_P(buf, PSTR(".CGI")) || strstr_P(buf,PSTR(".cgi"))) *type = PTYPE_CGI; + else if (strstr_P(buf, PSTR(".xml")) || strstr_P(buf,PSTR(".XML"))) *type = PTYPE_XML; + else if (strstr_P(buf, PSTR(".css")) || strstr_P(buf,PSTR(".CSS"))) *type = PTYPE_CSS; + else if (strstr_P(buf, PSTR(".png")) || strstr_P(buf,PSTR(".PNG"))) *type = PTYPE_PNG; + else if (strstr_P(buf, PSTR(".ico")) || strstr_P(buf,PSTR(".ICO"))) *type = PTYPE_ICO; + else if (strstr_P(buf, PSTR(".ttf")) || strstr_P(buf,PSTR(".TTF"))) *type = PTYPE_TTF; + else if (strstr_P(buf, PSTR(".otf")) || strstr_P(buf,PSTR(".OTF"))) *type = PTYPE_OTF; + else if (strstr_P(buf, PSTR(".woff")) || strstr_P(buf,PSTR(".WOFF"))) *type = PTYPE_WOFF; + else if (strstr_P(buf, PSTR(".eot")) || strstr_P(buf,PSTR(".EOT"))) *type = PTYPE_EOT; + else if (strstr_P(buf, PSTR(".svg")) || strstr_P(buf,PSTR(".SVG"))) *type = PTYPE_SVG; + else *type = PTYPE_ERR; +} + + +/** + @brief parse http request from a peer + */ +void parse_http_request( + st_http_request * request, /**< request to be returned */ + uint8_t * buf /**< pointer to be parsed */ + ) +{ + char * nexttok; + nexttok = strtok((char*)buf," "); + if(!nexttok) + { + request->METHOD = METHOD_ERR; + return; + } + if(!strcmp_P(nexttok, PSTR("GET")) || !strcmp_P(nexttok,PSTR("get"))) + { + request->METHOD = METHOD_GET; + nexttok = strtok(NULL," "); + + } + else if (!strcmp_P(nexttok, PSTR("HEAD")) || !strcmp_P(nexttok,PSTR("head"))) + { + request->METHOD = METHOD_HEAD; + nexttok = strtok(NULL," "); + + } + else if (!strcmp_P(nexttok, PSTR("POST")) || !strcmp_P(nexttok,PSTR("post"))) + { + nexttok = strtok(NULL,"\0"); + request->METHOD = METHOD_POST; + } + else + { + request->METHOD = METHOD_ERR; + } + + if(!nexttok) + { + request->METHOD = METHOD_ERR; + return; + } + strcpy((char *)request->URI, nexttok); +} + +#ifdef _OLD_ +/** + @brief get next parameter value in the request + */ +uint8_t * get_http_param_value( + char* uri, + char* param_name + ) +{ + char tempURI[MAX_URI_SIZE]; + uint8_t * name = 0; + + + if(!uri || !param_name) return 0; + + strcpy((char*)tempURI,uri); + if((name = (uint8_t*)strstr(tempURI, param_name))) + { + name += strlen(param_name) + 1; // strlen(para_name) + strlen("=") + if((name = (uint8_t*)strtok((char *)name,"& \r\n\t\0"))) + { + unescape_http_url((char *)name); + replacetochar(name, '+', ' '); + } + } +#ifdef _HTTPPARSER_DEBUG_ + printf(" %s=%s",param_name,name); +#endif + + return name; +} +#else +/** + @brief get next parameter value in the request + */ +uint8_t * get_http_param_value(char* uri, char* param_name) +{ + + uint8_t * name = 0; + uint8_t * ret = BUFPUB; + uint8_t * pos2; + uint16_t len = 0, content_len = 0; + uint8_t tmp_buf[10]={0x00, }; + + if(!uri || !param_name) return 0; + + /***************/ + mid(uri, "Content-Length: ", "\r\n", (char *)tmp_buf); + content_len = ATOI(tmp_buf, 10); + uri = strstr(uri, "\r\n\r\n"); + uri += 4; + uri[content_len] = 0; + /***************/ + + if((name = (uint8_t *)strstr(uri, param_name))) + { + name += strlen(param_name) + 1; + pos2 = (uint8_t*)strstr((char*)name, "&"); + if(!pos2) + { + pos2 = name + strlen((char*)name); + } + len = pos2 - name; + + if(len) + { + ret[len] = 0; + strncpy((char*)ret,(char*)name, len); + unescape_http_url((char *)ret); + replacetochar(ret, '+' ,' '); + //ret[len] = 0; + //ret[strlen((int8*)ret)] = 0; + //printf("len=%d\r\n",len); + } + else + { + ret[0] = 0; + } + } + else + { + return 0; + } +#ifdef _HTTPPARSER_DEBUG_ + printf(" %s=%s\r\n", param_name, ret); +#endif + return ret; +} +#endif + +#ifdef _OLD_ +uint8_t * get_http_uri_name(uint8_t * uri) +{ + char tempURI[MAX_URI_SIZE]; + uint8_t * uri_name; + + if(!uri) return 0; + + strcpy(tempURI, (char *)uri); + + uri_name = (uint8_t *)strtok(tempURI, " ?"); + + if(strcmp((char *)uri_name,"/")) uri_name++; + +#ifdef _HTTPPARSER_DEBUG_ + printf(" uri_name = %s\r\n", uri_name); +#endif + + return uri_name; +} +#else + +uint8_t get_http_uri_name(uint8_t * uri, uint8_t * uri_buf) +{ + uint8_t * uri_ptr; + if(!uri) return 0; + + strcpy((char *)uri_buf, (char *)uri); + + uri_ptr = (uint8_t *)strtok((char *)uri_buf, " ?"); + + if(strcmp((char *)uri_ptr,"/")) uri_ptr++; + strcpy((char *)uri_buf, (char *)uri_ptr); + +#ifdef _HTTPPARSER_DEBUG_ + PRINTF(" uri_name = %s\r\n", uri_buf); +#endif + + return 1; +} + +#endif + +void inet_addr_(uint8_t * addr, uint8_t *ip) +{ + uint8_t i; + uint8_t taddr[30]; + uint8_t * nexttok; + uint8_t num; + + strcpy((char *)taddr, (char *)addr); + + nexttok = taddr; + for(i = 0; i < 4 ; i++) + { + nexttok = (uint8_t *)strtok((char *)nexttok, "."); + if(nexttok[0] == '0' && nexttok[1] == 'x') num = ATOI(nexttok+2,0x10); + else num = ATOI(nexttok,10); + ip[i] = num; + nexttok = NULL; + } +} + + +/** +@brief CONVERT STRING INTO INTEGER +@return a integer number +*/ +uint16_t ATOI( + uint8_t * str, /**< is a pointer to convert */ + uint8_t base /**< is a base value (must be in the range 2 - 16) */ + ) +{ + unsigned int num = 0; +// debug_2013_11_25 +// while (*str !=0) + while ((*str !=0) && (*str != 0x20)) // not include the space(0x020) + num = num * base + C2D(*str++); + return num; +} + +/** + * @brief Check strings and then execute callback function by each string. + * @param src The information of URI + * @param s1 The start string to be researched + * @param s2 The end string to be researched + * @param sub The string between s1 and s2 + * @return The length value atfer working + */ +void mid(char* src, char* s1, char* s2, char* sub) +{ + char* sub1; + char* sub2; + uint16_t n; + + sub1=strstr((char*)src,(char*)s1); + sub1+=strlen((char*)s1); + sub2=strstr((char*)sub1,(char*)s2); + + n=sub2-sub1; + strncpy((char*)sub,(char*)sub1,n); + sub[n]='\0'; +} + +//////////////////////////////////////////////////////////////////// +// Static functions +//////////////////////////////////////////////////////////////////// + +/** +@brief replace the specified character in a string with new character +*/ +static void replacetochar( + uint8_t * str, /**< pointer to be replaced */ + uint8_t oldchar, /**< old character */ + uint8_t newchar /**< new character */ + ) +{ + int x; + for (x = 0; str[x]; x++) + if (str[x] == oldchar) str[x] = newchar; +} + +/** +@brief CONVERT CHAR INTO HEX +@return HEX + +This function converts HEX(0-F) to a character +*/ +static uint8_t C2D( + uint8_t c /**< is a character('0'-'F') to convert to HEX */ + ) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return 10 + c -'a'; + if (c >= 'A' && c <= 'F') + return 10 + c -'A'; + + return (char)c; +} + + + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpParser.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpParser.h new file mode 100644 index 0000000..c289c2e --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpParser.h @@ -0,0 +1,159 @@ +/** + @file httpd.h + @brief Define Constants and fucntions associated with HTTP protocol. + */ + +#include +#include "../../globals.h" + +#ifndef __HTTPPARSER_H__ +#define __HTTPPARSER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//#define _HTTPPARSER_DEBUG_ + +#define HTTP_SERVER_PORT 80 /**< HTTP server well-known port number */ + +/* HTTP Method */ +#define METHOD_ERR 0 /**< Error Method. */ +#define METHOD_GET 1 /**< GET Method. */ +#define METHOD_HEAD 2 /**< HEAD Method. */ +#define METHOD_POST 3 /**< POST Method. */ + +/* HTTP GET Method */ +#define PTYPE_ERR 0 /**< Error file. */ +#define PTYPE_HTML 1 /**< HTML file. */ +#define PTYPE_GIF 2 /**< GIF file. */ +#define PTYPE_TEXT 3 /**< TEXT file. */ +#define PTYPE_JPEG 4 /**< JPEG file. */ +#define PTYPE_FLASH 5 /**< FLASH file. */ +#define PTYPE_MPEG 6 /**< MPEG file. */ +#define PTYPE_PDF 7 /**< PDF file. */ +#define PTYPE_CGI 8 /**< CGI file. */ +#define PTYPE_XML 9 /**< XML file. */ +#define PTYPE_CSS 10 /**< CSS file. */ +#define PTYPE_JS 11 /**< JavaScript file. */ +#define PTYPE_JSON 12 /**< JSON (JavaScript Standard Object Notation) file. */ +#define PTYPE_PNG 13 /**< PNG file. */ +#define PTYPE_ICO 14 /**< ICON file. */ + +#define PTYPE_TTF 20 /**< Font type: TTF file. */ +#define PTYPE_OTF 21 /**< Font type: OTF file. */ +#define PTYPE_WOFF 22 /**< Font type: WOFF file. */ +#define PTYPE_EOT 23 /**< Font type: EOT file. */ +#define PTYPE_SVG 24 /**< Font type: SVG file. */ + + +/* HTTP response */ +#define STATUS_OK 200 +#define STATUS_CREATED 201 +#define STATUS_ACCEPTED 202 +#define STATUS_NO_CONTENT 204 +#define STATUS_MV_PERM 301 +#define STATUS_MV_TEMP 302 +#define STATUS_NOT_MODIF 304 +#define STATUS_BAD_REQ 400 +#define STATUS_UNAUTH 401 +#define STATUS_FORBIDDEN 403 +#define STATUS_NOT_FOUND 404 +#define STATUS_INT_SERR 500 +#define STATUS_NOT_IMPL 501 +#define STATUS_BAD_GATEWAY 502 +#define STATUS_SERV_UNAVAIL 503 + +/* HTML Doc. for ERROR */ +static const char PROGMEM ERROR_HTML_PAGE[] = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\nContent-Length: 78\r\n\r\n\r\n\r\nSorry, the page you requested was not found.\r\n\r\n\r\n\0"; +static const char PROGMEM ERROR_REQUEST_PAGE[] = "HTTP/1.1 400 OK\r\nContent-Type: text/html\r\nContent-Length: 50\r\n\r\n\r\n\r\nInvalid request.\r\n\r\n\r\n\0"; + +/* HTML Doc. for CGI result */ +#define HTML_HEADER "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: " + +/* Response header for HTML*/ +#define RES_HTMLHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: keep-alive\r\nContent-Length: " + +/* Response head for TEXT */ +#define RES_TEXTHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: " + +/* Response head for GIF */ +#define RES_GIFHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: image/gif\r\nContent-Length: " + +/* Response head for JPEG */ +#define RES_JPEGHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\nContent-Length: " + +/* Response head for PNG */ +#define RES_PNGHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: image/png\r\nContent-Length: " + +/* Response head for FLASH */ +#define RES_FLASHHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: application/x-shockwave-flash\r\nContent-Length: " + +/* Response head for XML */ +#define RES_XMLHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\nConnection: keep-alive\r\nContent-Length: " + +/* Response head for CSS */ +#define RES_CSSHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: text/css\r\nContent-Length: " + +/* Response head for JavaScript */ +#define RES_JSHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: application/javascript\r\nContent-Length: " + +/* Response head for JSON */ +#define RES_JSONHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: " + +/* Response head for ICO */ +#define RES_ICOHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: image/x-icon\r\nContent-Length: " + +/* Response head for CGI */ +#define RES_CGIHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: " + +/* Response head for TTF, Font */ +#define RES_TTFHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: application/x-font-truetype\r\nContent-Length: " + +/* Response head for OTF, Font */ +#define RES_OTFHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: application/x-font-opentype\r\nContent-Length: " + +/* Response head for WOFF, Font */ +#define RES_WOFFHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: application/font-woff\r\nContent-Length: " + +/* Response head for EOT, Font */ +#define RES_EOTHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.ms-fontobject\r\nContent-Length: " + +/* Response head for SVG, Font */ +#define RES_SVGHEAD_OK "HTTP/1.1 200 OK\r\nContent-Type: image/svg+xml\r\nContent-Length: " + +/** + @brief Structure of HTTP REQUEST + */ + +//#define MAX_URI_SIZE 1461 +#define MAX_URI_SIZE 512 + +typedef struct _st_http_request +{ + uint8_t METHOD; /**< request method(METHOD_GET...). */ + uint8_t TYPE; /**< request type(PTYPE_HTML...). */ + uint8_t URI[MAX_URI_SIZE]; /**< request file name. */ +}st_http_request; + +// HTTP Parsing functions +void unescape_http_url(char * url); /* convert escape character to ascii */ +void parse_http_request(st_http_request *, uint8_t *); /* parse request from peer */ +void find_http_uri_type(uint8_t *, uint8_t *); /* find MIME type of a file */ +void make_http_response_head(char *, char, uint32_t); /* make response header */ +uint8_t * get_http_param_value(char* uri, char* param_name); /* get the user-specific parameter value */ +uint8_t get_http_uri_name(uint8_t * uri, uint8_t * uri_buf); /* get the requested URI name */ +#ifdef _OLD_ +uint8_t * get_http_uri_name(uint8_t * uri); +#endif + +// Utility functions +uint16_t ATOI(uint8_t * str, uint8_t base); +void mid(char* src, char* s1, char* s2, char* sub); +void inet_addr_(uint8_t * addr, uint8_t * ip); + +#ifdef __cplusplus +} +#endif + +#endif /* end of __HTTPPARSER_H__ */ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpServer.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpServer.c new file mode 100644 index 0000000..d3e38f4 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpServer.c @@ -0,0 +1,878 @@ +#include +#include +#include + +#include "socket.h" +#include "wizchip_conf.h" + +#include "httpServer.h" +#include "httpParser.h" +#include "httpUtil.h" + +#include "../../globals.h" //add AVR specific useful headers + + +#define DATA_BUF_SIZE HTTPD_MAX_BUF_SIZE +/***************************************************************************** + * Private types/enumerations/variables + ****************************************************************************/ +static uint8_t HTTPSock_Num[_WIZCHIP_SOCK_NUM_] = {0, }; +static st_http_request * http_request; /**< Pointer to received HTTP request */ +static st_http_request * parsed_http_request; /**< Pointer to parsed HTTP request */ +static uint8_t * http_response; /**< Pointer to HTTP response */ + +// ## For Debugging +//static uint8_t uri_buf[128]; +// Number of registered web content in code flash memory +static uint16_t total_content_cnt = 0; +/***************************************************************************** + * Public types/enumerations/variables + ****************************************************************************/ +uint8_t * pHTTP_TX; +uint8_t * pHTTP_RX; + +volatile uint32_t httpServer_tick_1s = 0; +st_http_socket HTTPSock_Status[_WIZCHIP_SOCK_NUM_] = { {STATE_HTTP_IDLE, }, }; +httpServer_webContent web_content[MAX_CONTENT_CALLBACK]; + +#ifdef _USE_SDCARD_ +//static FIL fs; // FatFs: File object +static FRESULT fr; // FatFs: File function return code +#endif +/***************************************************************************** + * Private functions + ****************************************************************************/ +void httpServer_Sockinit(uint8_t cnt, uint8_t * socklist); +static uint8_t getHTTPSocketNum(uint8_t seqnum); +static int8_t getHTTPSequenceNum(uint8_t socket); +static int8_t http_disconnect(uint8_t sn); + +static void http_process_handler_avr(uint8_t s, st_http_request * p_http_request); + +static void send_http_response_header(uint8_t s, uint8_t content_type, uint32_t body_len, uint16_t http_status); + +static void send_http_response_body_avr(uint8_t s, uint8_t * uri_name, uint8_t * buf, uint32_t start_addr, uint32_t file_len); + +static void send_http_response_cgi(uint8_t s, uint8_t * buf, uint8_t * http_body, uint16_t file_len); + +/***************************************************************************** + * Public functions + ****************************************************************************/ +// Callback functions definition: MCU Reset / WDT Reset +void default_mcu_reset(void) {;} +void default_wdt_reset(void) {;} +void (*HTTPServer_ReStart)(void) = default_mcu_reset; +void (*HTTPServer_WDT_Reset)(void) = default_wdt_reset; + +void httpServer_Sockinit(uint8_t cnt, uint8_t * socklist) +{ + uint8_t i; + + for(i = 0; i < cnt; i++) + { + // Mapping the H/W socket numbers to the sequential index numbers + HTTPSock_Num[i] = socklist[i]; + } +} + +static uint8_t getHTTPSocketNum(uint8_t seqnum) +{ + // Return the 'H/W socket number' corresponding to the index number + return HTTPSock_Num[seqnum]; +} + +static int8_t getHTTPSequenceNum(uint8_t socket) +{ + uint8_t i; + + for(i = 0; i < _WIZCHIP_SOCK_NUM_; i++) + if(HTTPSock_Num[i] == socket) return i; + + return -1; +} + +void httpServer_init(uint8_t * tx_buf, uint8_t * rx_buf, uint8_t cnt, uint8_t * socklist) +{ + // User's shared buffer + pHTTP_TX = tx_buf; + pHTTP_RX = rx_buf; + + // H/W Socket number mapping + httpServer_Sockinit(cnt, socklist); +} + + +/* Register the call back functions for HTTP Server */ +void reg_httpServer_cbfunc(void(*mcu_reset)(void), void(*wdt_reset)(void)) +{ + // Callback: HW Reset and WDT reset function for each MCU platforms + if(mcu_reset) HTTPServer_ReStart = mcu_reset; + if(wdt_reset) HTTPServer_WDT_Reset = wdt_reset; +} + + + +void httpServer_run_avr(uint8_t seqnum) +{ + uint8_t s; // socket number + uint16_t len; + uint32_t gettime = 0; + +#ifdef _HTTPSERVER_DEBUG_ + uint8_t destip[4] = {0, }; + uint16_t destport = 0; +#endif + + http_request = (st_http_request *)pHTTP_RX; // Structure of HTTP Request + parsed_http_request = (st_http_request *)pHTTP_TX; + + // Get the H/W socket number + s = getHTTPSocketNum(seqnum); + + /* HTTP Service Start */ + switch(getSn_SR(s)) + { + case SOCK_ESTABLISHED: + // Interrupt clear + if(getSn_IR(s) & Sn_IR_CON) + { + setSn_IR(s, Sn_IR_CON); + } + + // HTTP Process states + switch(HTTPSock_Status[seqnum].sock_status) + { + + case STATE_HTTP_IDLE : + if ((len = getSn_RX_RSR(s)) > 0) + { + if (len > DATA_BUF_SIZE) len = DATA_BUF_SIZE; + len = recv(s, (uint8_t *)http_request, len); + + *(((uint8_t *)http_request) + len) = '\0'; + + parse_http_request(parsed_http_request, (uint8_t *)http_request); +#ifdef _HTTPSERVER_DEBUG_ + getSn_DIPR(s, destip); + destport = getSn_DPORT(s); + PRINTF("\r\n"); + PRINTF("> HTTPSocket[%d] : HTTP Request received ", s); + PRINTF("from %d.%d.%d.%d : %u\r\n", destip[0], destip[1], destip[2], destip[3], destport); +#endif +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : [State] STATE_HTTP_REQ_DONE\r\n", s); +#endif + // HTTP 'response' handler; includes send_http_response_header / body function + http_process_handler_avr(s, parsed_http_request); + + gettime = get_httpServer_timecount(); + // Check the TX socket buffer for End of HTTP response sends + while(getSn_TX_FSR(s) != (getSn_TXBUF_SIZE(s)*1024)) + { + if((get_httpServer_timecount() - gettime) > 3) + { +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : [State] STATE_HTTP_REQ_DONE: TX Buffer clear timeout\r\n", s); +#endif + break; + } + } + + if(HTTPSock_Status[seqnum].file_len > 0) HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_INPROC; + else HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; // Send the 'HTTP response' end + } + break; + + case STATE_HTTP_RES_INPROC : + /* Repeat: Send the remain parts of HTTP responses */ +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : [State] STATE_HTTP_RES_INPROC\r\n", s); + PRINTF("\r\n> HTTPSocket[%d] : Re-Open the requested content\r\n", s); //_delay_ms(200); +#endif +/* +#ifdef _USE_SDCARD_ +#ifdef _HTTPSERVER_DEBUG_ + //PRINTF("++SDFLASH FIND..\r\n"); //_delay_ms(200); +#endif + + if((fr = f_open(&fs, (const char *)HTTPSock_Status[seqnum].file_name, FA_READ)) == 0) + { +#ifdef _HTTPSERVER_DEBUG_ + //PRINTF("++Content found on SDCARD\r\n"); + if((fr = f_lseek(&fs, HTTPSock_Status[seqnum].file_offset)) != 0) + { + HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; + break; + } +#endif + } + else + { + HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; + break; + } +#endif +*/ + // Repeatedly send remaining data to client + send_http_response_body_avr(s, 0, http_response, 0, 0); + + if(HTTPSock_Status[seqnum].file_len == 0) HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; + break; + + case STATE_HTTP_RES_DONE : +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : [State] STATE_HTTP_RES_DONE\r\n", s); +#endif + // Socket file info structure re-initialize + HTTPSock_Status[seqnum].file_len = 0; + HTTPSock_Status[seqnum].file_offset = 0; + HTTPSock_Status[seqnum].file_start = 0; + HTTPSock_Status[seqnum].sock_status = STATE_HTTP_IDLE; + +#ifdef _USE_SDCARD_ + f_close(&HTTPSock_Status[seqnum].fs); +#endif +#ifdef _USE_WATCHDOG_ + HTTPServer_WDT_Reset(); +#endif + http_disconnect(s); + break; + + default : + break; + } + break; + + case SOCK_CLOSE_WAIT: +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : ClOSE_WAIT\r\n", s); // if a peer requests to close the current connection +#endif + disconnect(s); + break; + + case SOCK_CLOSED: +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : CLOSED\r\n", s); +#endif + if(socket(s, Sn_MR_TCP, HTTP_SERVER_PORT, 0x00) == s) /* Reinitialize the socket */ + { +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : OPEN\r\n", s); +#endif + } + break; + + case SOCK_INIT: + listen(s); + break; + + case SOCK_LISTEN: + break; + + default : + break; + + } // end of switch + +#ifdef _USE_WATCHDOG_ + HTTPServer_WDT_Reset(); +#endif +} + +//////////////////////////////////////////// +// Private Functions +//////////////////////////////////////////// +static void send_http_response_header(uint8_t s, uint8_t content_type, uint32_t body_len, uint16_t http_status) +{ + switch(http_status) + { + case STATUS_OK: // HTTP/1.1 200 OK + if((content_type != PTYPE_CGI) && (content_type != PTYPE_XML)) // CGI/XML type request does not respond HTTP header + { +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : HTTP Response Header - STATUS_OK\r\n", s); +#endif + make_http_response_head((char*)http_response, content_type, body_len); + } + else + { +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : HTTP Response Header - NONE / CGI or XML\r\n", s); +#endif + // CGI/XML type request does not respond HTTP header to client + http_status = 0; + } + break; + case STATUS_BAD_REQ: // HTTP/1.1 400 OK +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : HTTP Response Header - STATUS_BAD_REQ\r\n", s); +#endif + memcpy_P(http_response, ERROR_REQUEST_PAGE, sizeof(ERROR_REQUEST_PAGE)); + break; + case STATUS_NOT_FOUND: // HTTP/1.1 404 Not Found +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : HTTP Response Header - STATUS_NOT_FOUND\r\n", s); +#endif + memcpy_P(http_response, ERROR_HTML_PAGE, sizeof(ERROR_HTML_PAGE)); + break; + default: + break; + } + + // Send the HTTP Response 'header' + if(http_status) + { +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : [Send] HTTP Response Header [ %d ]byte\r\n", s, (uint16_t)strlen((char *)http_response)); +#endif + send(s, http_response, strlen((char *)http_response)); + } +} + + +static void send_http_response_body_avr(uint8_t s, uint8_t * uri_name, uint8_t * buf, uint32_t start_addr, uint32_t file_len) +{ + int8_t get_seqnum; + uint32_t send_len; + + uint8_t flag_datasend_end = 0; + +#ifdef _USE_SDCARD_ + uint16_t blocklen; +#endif +#ifdef _USE_FLASH_ + uint32_t addr = 0; +#endif + + if((get_seqnum = getHTTPSequenceNum(s)) == -1) return; // exception handling; invalid number + + // Send the HTTP Response 'body'; requested file + if(!HTTPSock_Status[get_seqnum].file_len) // ### Send HTTP response body: First part ### + { + if (file_len > DATA_BUF_SIZE - 1) + { + HTTPSock_Status[get_seqnum].file_start = start_addr; + HTTPSock_Status[get_seqnum].file_len = file_len; + send_len = DATA_BUF_SIZE - 1; + +///////////////////////////////////////////////////////////////////////////////////////////////// +// ## 20141219 Eric added, for 'File object structure' (fs) allocation reduced (8 -> 1) + memset(HTTPSock_Status[get_seqnum].file_name, 0x00, MAX_CONTENT_NAME_LEN); + strcpy((char *)HTTPSock_Status[get_seqnum].file_name, (char *)uri_name); +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : HTTP Response body - file name [ %s ]\r\n", s, HTTPSock_Status[get_seqnum].file_name); +#endif +///////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : HTTP Response body - file len [ %ld ]byte\r\n", s, file_len); +#endif + } + else + { + // Send process end + send_len = file_len; + +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : (1)HTTP Response end - file len [ %ld ]byte\r\n", s, send_len); +#endif + } +#ifdef _USE_FLASH_ + if(HTTPSock_Status[get_seqnum]->storage_type == DATAFLASH) addr = start_addr; +#endif + } + else // remained parts + { +#ifdef _USE_FLASH_ + if(HTTPSock_Status[get_seqnum]->storage_type == DATAFLASH) + { + addr = HTTPSock_Status[get_seqnum].file_start + HTTPSock_Status[get_seqnum].file_offset; + } +#endif + send_len = HTTPSock_Status[get_seqnum].file_len - HTTPSock_Status[get_seqnum].file_offset; + + if(send_len > DATA_BUF_SIZE - 1) + { + send_len = DATA_BUF_SIZE - 1; + //HTTPSock_Status[get_seqnum]->file_offset += send_len; + } + else + { +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : (2)HTTP Response end - file len [ %ld ]byte\r\n", s, HTTPSock_Status[get_seqnum].file_len); +#endif + // Send process end + flag_datasend_end = 1; + } +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : HTTP Response body - send len [ %ld ]byte\r\n", s, send_len); +#endif + } + +/*****************************************************/ + //HTTPSock_Status[get_seqnum]->storage_type == NONE + //HTTPSock_Status[get_seqnum]->storage_type == CODEFLASH + //HTTPSock_Status[get_seqnum]->storage_type == SDCARD + //HTTPSock_Status[get_seqnum]->storage_type == DATAFLASH +/*****************************************************/ + + if(HTTPSock_Status[get_seqnum].storage_type == CODEFLASH) + { + if(HTTPSock_Status[get_seqnum].file_len) start_addr = HTTPSock_Status[get_seqnum].file_start; + read_userReg_webContent_avr(start_addr, &buf[0], HTTPSock_Status[get_seqnum].file_offset, send_len); + } +#ifdef _USE_SDCARD_ + else if(HTTPSock_Status[get_seqnum].storage_type == SDCARD) + { + // Data read from SD Card + //PRINTF("++SDCARD f_read(..)\r\n"); + fr = f_read(&HTTPSock_Status[get_seqnum].fs, &buf[0], send_len, (void *)&blocklen); + if(fr != FR_OK) + { + send_len = 0; +#ifdef _HTTPSERVER_DEBUG_ + printf("> HTTPSocket[%d] : [FatFs] Error code return: %d (File Read) / HTTP Send Failed - %s\r\n", s, fr, HTTPSock_Status[get_seqnum].file_name); +#endif + } + else + { + *(buf+send_len+1) = 0; // Insert '/0' for indicates the 'End of String' (null terminated) + } + } +#endif + +#ifdef _USE_FLASH_ + else if(HTTPSock_Status[get_seqnum]->storage_type == DATAFLASH) + { + // Data read from external data flash memory + read_from_flashbuf(addr, &buf[0], send_len); + *(buf+send_len+1) = 0; // Insert '/0' for indicates the 'End of String' (null terminated) + } +#endif + else + { + send_len = 0; + } + // Requested content send to HTTP client +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : [Send] HTTP Response body [ %ld ]byte\r\n", s, send_len); +#endif + + if(send_len) send(s, buf, send_len); + else flag_datasend_end = 1; + + if(flag_datasend_end) + { + HTTPSock_Status[get_seqnum].file_start = 0; + HTTPSock_Status[get_seqnum].file_len = 0; + HTTPSock_Status[get_seqnum].file_offset = 0; + flag_datasend_end = 0; + } + else + { + HTTPSock_Status[get_seqnum].file_offset += send_len; +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : HTTP Response body - offset [ %ld ]\r\n", s, HTTPSock_Status[get_seqnum].file_offset); +#endif + } + +// ## 20141219 Eric added, for 'File object structure' (fs) allocation reduced (8 -> 1) +#ifdef _USE_SDCARD_ + //Should not close here + //f_close(&fs); +#endif +// ## 20141219 added end +} + + +static void send_http_response_cgi(uint8_t s, uint8_t * buf, uint8_t * http_body, uint16_t file_len) +{ + uint16_t send_len = 0; + +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : HTTP Response Header + Body - CGI\r\n", s); +#endif + //send_len = sprintf((char *)buf, "%s%d\r\n\r\n%s", RES_CGIHEAD_OK, file_len, http_body); + send_len = sprintf_P((char *)buf, PSTR("%S%d\r\n\r\n%s"), PSTR(RES_CGIHEAD_OK), file_len, http_body); +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : HTTP Response Header + Body - send len [ %d ]byte\r\n", s, send_len); +#endif + + send(s, buf, send_len); +} + + +static int8_t http_disconnect(uint8_t sn) +{ + setSn_CR(sn,Sn_CR_DISCON); + /* wait to process the command... */ + while(getSn_CR(sn)); + + return SOCK_OK; +} + + +static void http_process_handler_avr(uint8_t s, st_http_request * p_http_request) +{ + uint8_t * uri_name; + uint32_t content_addr = 0; + uint16_t content_num = 0; + uint32_t file_len = 0; + + uint8_t uri_buf[MAX_URI_SIZE]={0x00, }; + + uint16_t http_status; + int8_t get_seqnum; + uint8_t content_found; + + if((get_seqnum = getHTTPSequenceNum(s)) == -1) return; // exception handling; invalid number + + http_status = 0; + http_response = pHTTP_RX; + file_len = 0; + + //method Analyze + switch (p_http_request->METHOD) + { + case METHOD_ERR : + http_status = STATUS_BAD_REQ; + send_http_response_header(s, 0, 0, http_status); + break; + + case METHOD_HEAD : + case METHOD_GET : + get_http_uri_name(p_http_request->URI, uri_buf); + uri_name = uri_buf; + + if (!strcmp((char *)uri_name, "/")) strcpy((char *)uri_name, INITIAL_WEBPAGE); // If URI is "/", respond by index.html + if (!strcmp((char *)uri_name, "m")) strcpy((char *)uri_name, M_INITIAL_WEBPAGE); + if (!strcmp((char *)uri_name, "mobile")) strcpy((char *)uri_name, MOBILE_INITIAL_WEBPAGE); + find_http_uri_type(&p_http_request->TYPE, uri_name); // Checking requested file types (HTML, TEXT, GIF, JPEG and Etc. are included) + +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("\r\n> HTTPSocket[%d] : HTTP Method GET\r\n", s); + PRINTF("> HTTPSocket[%d] : Request Type = %d\r\n", s, p_http_request->TYPE); + PRINTF("> HTTPSocket[%d] : Request URI = %s\r\n", s, uri_name); +#endif + + if (p_http_request->TYPE == PTYPE_ERR) + { + http_status = STATUS_BAD_REQ; + send_http_response_header(s, 0, 0, http_status); + return; + } + else if(p_http_request->TYPE == PTYPE_CGI) + { + content_found = http_get_cgi_handler(uri_name, pHTTP_TX, &file_len); + if(content_found && (file_len <= (DATA_BUF_SIZE-(strlen(RES_CGIHEAD_OK)+8)))) + { + send_http_response_cgi(s, http_response, pHTTP_TX, (uint16_t)file_len); + } + else + { + send_http_response_header(s, PTYPE_CGI, 0, STATUS_NOT_FOUND); + } + } + else + { +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("\r\n> HTTPSocket[%d] : Searching the requested content\r\n", s); //_delay_ms(200); + //PRINTF("++CODEFLASH FIND..\r\n"); //_delay_ms(200); +#endif + // Find the User registered index for web content + if(find_userReg_webContent_avr(uri_buf, &content_num, &file_len)) + { + content_found = 1; // Web content found in code flash memory + content_addr = (uint32_t)content_num; + HTTPSock_Status[get_seqnum].storage_type = CODEFLASH; +#ifdef _HTTPSERVER_DEBUG_ + //PRINTF("++Content found on CODEFLASH\r\n"); +#endif + } + // Not CGI request, Web content in 'SD card' or 'Data flash' requested +#ifdef _USE_SDCARD_ +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("\r\n> HTTPSocket[%d] : Searching the requested content\r\n", s); //_delay_ms(200); + //PRINTF("++SDFLASH FIND..\r\n"); //_delay_ms(200); +#endif + if((fr = f_open(&HTTPSock_Status[get_seqnum].fs, (const char *)uri_name, FA_READ)) == 0) + { + content_found = 1; // file open succeed + + file_len = HTTPSock_Status[get_seqnum].fs.fsize; + //content_addr = fs.sclust; //? + content_addr = HTTPSock_Status[get_seqnum].fs.fptr; //much better + HTTPSock_Status[get_seqnum].storage_type = SDCARD; +#ifdef _HTTPSERVER_DEBUG_ + //PRINTF("++Content found on SDCARD\r\n"); +#endif + } +#elif _USE_FLASH_ + else if(/* Read content from Dataflash */) + { + content_found = 1; + HTTPSock_Status[get_seqnum]->storage_type = DATAFLASH; + ; // To do + } +#endif + else + { + content_found = 0; // fail to find content + } + + if(!content_found) + { +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : Unknown Page Request\r\n", s); +#endif + http_status = STATUS_NOT_FOUND; + } + else + { +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : Find Content [%s] ok - Start [%ld] len [ %ld ]byte\r\n", s, uri_name, content_addr, file_len); +#endif + http_status = STATUS_OK; + } + + // Send HTTP header + if(http_status) + { +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : Requested content len = [ %ld ]byte\r\n", s, file_len); +#endif + send_http_response_header(s, p_http_request->TYPE, file_len, http_status); + } + + // Send HTTP body (content) + if(http_status == STATUS_OK) + { + send_http_response_body_avr(s, uri_name, http_response, content_addr, file_len); + } + } + break; + + case METHOD_POST : + mid((char *)p_http_request->URI, "/", " HTTP", (char *)uri_buf); + uri_name = uri_buf; + find_http_uri_type(&p_http_request->TYPE, uri_name); // Check file type (HTML, TEXT, GIF, JPEG are included) + +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("\r\n> HTTPSocket[%d] : HTTP Method POST\r\n", s); + PRINTF("> HTTPSocket[%d] : Request URI = %s ", s, uri_name); + PRINTF("Type = %d\r\n", p_http_request->TYPE); +#endif + + if(p_http_request->TYPE == PTYPE_CGI) // HTTP POST Method; CGI Process + { + content_found = http_post_cgi_handler(uri_name, p_http_request, http_response, &file_len); +#ifdef _HTTPSERVER_DEBUG_ + PRINTF("> HTTPSocket[%d] : [CGI: %s] / Response len [ %ld ]byte\r\n", s, content_found?"Content found":"Content not found", file_len); +#endif + if(content_found && (file_len <= (DATA_BUF_SIZE-(strlen(RES_CGIHEAD_OK)+8)))) + { + send_http_response_cgi(s, pHTTP_TX, http_response, (uint16_t)file_len); + + // Reset the H/W for apply to the change configuration information + if(content_found == HTTP_RESET) HTTPServer_ReStart(); + } + else + { + send_http_response_header(s, PTYPE_CGI, 0, STATUS_NOT_FOUND); + } + } + else // HTTP POST Method; Content not found + { + send_http_response_header(s, 0, 0, STATUS_NOT_FOUND); + } + break; + + default : + http_status = STATUS_BAD_REQ; + send_http_response_header(s, 0, 0, http_status); + break; + } +} + + +void httpServer_time_handler(void) +{ + httpServer_tick_1s++; +} + +uint32_t get_httpServer_timecount(void) +{ + return httpServer_tick_1s; +} +void reg_httpServer_webContent_avr(const uint8_t * content_name,const uint8_t * content) +{ + uint16_t name_len; + uint32_t content_len; + + if(content_name == NULL || content == NULL) + { + return; + } + else if(total_content_cnt >= MAX_CONTENT_CALLBACK) + { + return; + } + + name_len = strlen_P((const char *)content_name); + content_len = strlen_P((const char *)content); + + web_content[total_content_cnt].content_name = malloc(name_len+1); + strcpy_P((char *)web_content[total_content_cnt].content_name, (const char *)content_name); + web_content[total_content_cnt].content_len = content_len; + web_content[total_content_cnt].content = content; + + total_content_cnt++; +} + +void reg_httpServer_binContent_avr(const uint8_t * content_name,const uint8_t * content, const uint32_t content_len) +{ + uint16_t name_len; + //uint32_t content_len; + + if(content_name == NULL || content == NULL) + { + return; + } + else if(total_content_cnt >= MAX_CONTENT_CALLBACK) + { + return; + } + + name_len = strlen_P((const char *)content_name); + //content_len = (uint32_t) sizeof(content); + + web_content[total_content_cnt].content_name = malloc(name_len+1); + strcpy_P((char *)web_content[total_content_cnt].content_name, (const char *)content_name); + web_content[total_content_cnt].content_len = content_len; + web_content[total_content_cnt].content = content; + + total_content_cnt++; +} + +uint8_t display_reg_webContent_list_avr(void) +{ + uint16_t i; + uint8_t ret; + + if(total_content_cnt == 0) + { + PRINTF(">> Web content file not found\r\n"); + ret = 0; + } + else + { + PRINTF("\r\n=== List of Web content in code flash ===\r\n"); + for(i = 0; i < total_content_cnt; i++) + { + PRINTF(" [%d] ", i+1); + PRINTF("%s, ", web_content[i].content_name); + PRINTF("%ld byte\r\n", web_content[i].content_len); + + + if(web_content[i].content_len < 30) + { + PRINTF("[%s]\r\n", web_content[i].content); + } + else + { + PRINTF("[ ... ]\r\n"); + } + //Dump head 16 bytes every file.. + /* + else + { + const char PROGMEM * tst_char = web_content[i].content; + if(strstr_P(web_content[i].content_name,PSTR("favicon.ico"))==NULL) + { + //ASCII Dump first 0x10 symbols, for all files without + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:%c]\r\n",tst_char, pgm_read_byte(tst_char++)); + } + else + { + //HEX dump first 0x10 symbols, for + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + PRINTF("[0x%04X:0x%02X]\r\n",tst_char, pgm_read_byte(tst_char++)); + } + } + */ + wdt_reset(); // WDT reset at least every sec + + } + PRINTF("=========================================\r\n\r\n"); + ret = 1; + } + + return ret; +} + +uint8_t find_userReg_webContent_avr(uint8_t * content_name, uint16_t * content_num, uint32_t * file_len) +{ + uint16_t i; + uint8_t ret = 0; // '0' means 'File Not Found' + + for(i = 0; i < total_content_cnt; i++) + { + if(!strcmp((const char *)content_name, (const char *)web_content[i].content_name)) + { + *file_len = web_content[i].content_len; + *content_num = i; + ret = 1; // If the requested content found, ret set to '1' (Found) + break; + } + } + return ret; +} + + +uint16_t read_userReg_webContent_avr(uint16_t content_num, uint8_t * buf, uint32_t offset, uint16_t size) +{ + uint16_t ret = 0; + uint8_t * ptr; + + if(content_num > total_content_cnt) return 0; + + ptr = web_content[content_num].content; + if(offset) ptr += offset; + + //strncpy_P((char *)buf, (const char *)ptr, size); //not suit for case binary data + memcpy_P((char *)buf, (const char *)ptr, size); + *(buf+size) = 0; // Insert '/0' for indicates the 'End of String' (null terminated) + + //ret = strlen((void *)buf); //Useless for memcpy_P + ret = 0; //All ok + return ret; +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpServer.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpServer.h new file mode 100644 index 0000000..094d869 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpServer.h @@ -0,0 +1,125 @@ +/** + @file httpServer.h + @brief Define constants and functions related HTTP Web server. + */ + +#include + +#ifndef __HTTPSERVER_H__ +#define __HTTPSERVER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +// HTTP Server debug message enable +#define _HTTPSERVER_DEBUG_ + +//#define INITIAL_WEBPAGE "index.html" +#define INITIAL_WEBPAGE "index.htm" +#define M_INITIAL_WEBPAGE "m/index.html" +#define MOBILE_INITIAL_WEBPAGE "mobile/index.html" + +/* Web Server Content Storage Select */ +#define _USE_SDCARD_ +#ifndef _USE_SDCARD_ +//#define _USE_FLASH_ +#endif + +#ifdef _USE_SDCARD_ +#include "ff.h" // header file for FatFs library (FAT file system) +#endif + +#if !defined(_USE_SDCARD_) && !defined(_USE_FLASH_) +#define _NOTUSED_STORAGE_ +#endif + + +/* Watchdog timer */ +//#define _USE_WATCHDOG_ + +/********************************************* +* HTTP Process states list +*********************************************/ +#define STATE_HTTP_IDLE 0 /* IDLE, Waiting for data received (TCP established) */ +#define STATE_HTTP_REQ_INPROC 1 /* Received HTTP request from HTTP client */ +#define STATE_HTTP_REQ_DONE 2 /* The end of HTTP request parse */ +#define STATE_HTTP_RES_INPROC 3 /* Sending the HTTP response to HTTP client (in progress) */ +#define STATE_HTTP_RES_DONE 4 /* The end of HTTP response send (HTTP transaction ended) */ + +/********************************************* +* HTTP Simple Return Value +*********************************************/ +#define HTTP_FAILED 0 +#define HTTP_OK 1 +#define HTTP_RESET 2 + +/********************************************* +* HTTP Content NAME length +*********************************************/ +//#define MAX_CONTENT_NAME_LEN 128 ? Wastefull +#define MAX_CONTENT_NAME_LEN 16 + +/********************************************* +* HTTP Timeout +*********************************************/ +#define HTTP_MAX_TIMEOUT_SEC 3 // Sec. + +typedef enum +{ + NONE, ///< Web storage none + CODEFLASH, ///< Code flash memory + SDCARD, ///< SD card + DATAFLASH ///< External data flash memory +}StorageType; + +typedef struct _st_http_socket +{ + uint8_t sock_status; + uint8_t file_name[MAX_CONTENT_NAME_LEN]; + uint32_t file_start; + uint32_t file_len; + uint32_t file_offset; // (start addr + sent size...) + uint8_t storage_type; // Storage type; Code flash, SDcard, Data flash ... + FIL fs; // FatFs: File object +}st_http_socket; + +// Web content structure for file in code flash memory +#define MAX_CONTENT_CALLBACK 20 + +typedef struct _httpServer_webContent +{ + uint8_t * content_name; + uint32_t content_len; + uint8_t * content; +}httpServer_webContent; + + +void httpServer_init(uint8_t * tx_buf, uint8_t * rx_buf, uint8_t cnt, uint8_t * socklist); +void reg_httpServer_cbfunc(void(*mcu_reset)(void), void(*wdt_reset)(void)); + +void httpServer_run_avr(uint8_t seqnum); + +void reg_httpServer_webContent_avr(const uint8_t * content_name,const uint8_t * content); + +void reg_httpServer_binContent_avr(const uint8_t * content_name,const uint8_t * content, const uint32_t content_len); + +uint8_t find_userReg_webContent_avr(uint8_t * content_name, uint16_t * content_num, uint32_t * file_len); + +uint16_t read_userReg_webContent_avr(uint16_t content_num, uint8_t * buf, uint32_t offset, uint16_t size); + +uint8_t display_reg_webContent_list_avr(void); + +/* + * @brief HTTP Server 1sec Tick Timer handler + * @note SHOULD BE register to your system 1s Tick timer handler + */ +void httpServer_time_handler(void); +uint32_t get_httpServer_timecount(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpUtil.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpUtil.c new file mode 100644 index 0000000..77c9a9d --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpUtil.c @@ -0,0 +1,65 @@ +/** + * @file httpUtil.c + * @brief HTTP Server Utilities + * @version 1.0 + * @date 2014/07/15 + * @par Revision + * 2014/07/15 - 1.0 Release + * @author + * \n\n @par Copyright (C) 1998 - 2014 WIZnet. All rights reserved. + */ + +#include +#include +#include +#include "httpUtil.h" + +uint8_t http_get_cgi_handler(uint8_t * uri_name, uint8_t * buf, uint32_t * file_len) +{ + uint8_t ret = HTTP_OK; + uint16_t len = 0; + + if(predefined_get_cgi_processor(uri_name, buf, &len)) + { + ; + } + else if(strcmp((const char *)uri_name, "example.cgi") == 0) + { + // To do + ; + } + else + { + // CGI file not found + ret = HTTP_FAILED; + } + + if(ret) *file_len = len; + return ret; +} + +uint8_t http_post_cgi_handler(uint8_t * uri_name, st_http_request * p_http_request, uint8_t * buf, uint32_t * file_len) +{ + uint8_t ret = HTTP_OK; + uint16_t len = 0; + uint8_t val = 0; + + if(predefined_set_cgi_processor(uri_name, p_http_request->URI, buf, &len)) + { + ; + } + else if(strcmp((const char *)uri_name, "example.cgi") == 0) + { + // To do + val = 1; + len = sprintf((char *)buf, "%d", val); + } + else + { + // CGI file not found + ret = HTTP_FAILED; + } + + if(ret) *file_len = len; + return ret; +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpUtil.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpUtil.h new file mode 100644 index 0000000..f2c384a --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/Internet/httpServer_avr/httpUtil.h @@ -0,0 +1,32 @@ +/** + * @file httpUtil.h + * @brief Header File for HTTP Server Utilities + * @version 1.0 + * @date 2014/07/15 + * @par Revision + * 2014/07/15 - 1.0 Release + * @author + * \n\n @par Copyright (C) 1998 - 2014 WIZnet. All rights reserved. + */ + +#ifndef __HTTPUTIL_H__ +#define __HTTPUTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "httpServer.h" +#include "httpParser.h" + +uint8_t http_get_cgi_handler(uint8_t * uri_name, uint8_t * buf, uint32_t * file_len); +uint8_t http_post_cgi_handler(uint8_t * uri_name, st_http_request * p_http_request, uint8_t * buf, uint32_t * file_len); + +uint8_t predefined_get_cgi_processor(uint8_t * uri_name, uint8_t * buf, uint16_t * len); +uint8_t predefined_set_cgi_processor(uint8_t * uri_name, uint8_t * uri, uint8_t * buf, uint16_t * len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain.htm b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain.htm new file mode 100644 index 0000000..c8c7178 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain.htm @@ -0,0 +1,43 @@ + + + + + W5500-AtMEGA1284p Web Server Analog Input + + + + + + + + + +
+ + +
+ +
+ +
+
+ + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain.js b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain.js new file mode 100644 index 0000000..b5974d3 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain.js @@ -0,0 +1,57 @@ +function AinCallback(o) +{ + var pin = o.ain_p; + $('txtain_v'+pin).value = o.ain_v; + AinDrawgraph(o); +} +function getAin(o) +{ + var p = o.attributes['pin'].value; + var oUpdate; + setTimeout(function() + { + oUpdate = new AJAX('get_ain'+p+'.cgi', + function(t) + { + try + { + eval(t); + } + catch(e) + { + alert(e); + } + } + ); + oUpdate.doGet(); + } + , 300); +} +function AinDrawgraph(o) +{ + var pin = o.ain_p; + var val = o.ain_v; + $('ain_v'+pin).style.width = val*500/1023+'px'; +} +function getAin6_update() +{ + var oUpdate; + setTimeout(function() + { + oUpdate = new AJAX('get_ain6.cgi', + function(t) + { + try + { + eval(t); + } + catch(e) + { + alert(e); + } + } + ); + oUpdate.doGet(); + } + , 300); setTimeout('getAin6_update()', 500); +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain_gaug.htm b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain_gaug.htm new file mode 100644 index 0000000..ee671fb --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain_gaug.htm @@ -0,0 +1,27 @@ + + + + + W5500-AtMEGA1284p Web Server Analog Input Gauge + + + + + + + + + +
+ + +
+ + +
+
+ + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain_gaug.js b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain_gaug.js new file mode 100644 index 0000000..7c309a7 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ain_gaug.js @@ -0,0 +1,87 @@ +google.load('visualization', '1', + { + packages:['gauge'] + } +); google.setOnLoadCallback(AinDrawGoogleGauge); + +function AinCallback(o) +{ + var pin = o.ain_p; + $('txtain_v'+pin).value = o.ain_v; + AinDrawGoogleGauge(o); +} + +function getAin(o) +{ + var p = o.attributes['pin'].value; + var oUpdate; + setTimeout(function() + { + oUpdate = new AJAX('get_ain'+p+'.cgi', + function(t) + { + try + { + eval(t); + } + catch(e) + { + alert(e); + } + } + ); + oUpdate.doGet(); + } + , 300); +} + +function AinDrawGoogleGauge(o) +{ + var val = o.ain_v; + //var temp_val = Number(((((val*3300)/1023)-500)/10).toFixed(2)); + var temp_val = Number(val); //here in range 0..1023 + if(isNaN(temp_val)) temp_val = 0; + var data = google.visualization.arrayToDataTable([['Label', 'Value'],['ADC6', 80]]); + var options = + { + width: 400, + height: 120, + max: 1023, + min: 0, + greenFrom: 0, + greenTo: 512, + redFrom: 918, + redTo: 1023, + yellowFrom: 714, + yellowTo: 918, + majorTicks: ['0', '512', '1023'], + minorTicks: 5 + }; + var chart = new google.visualization.Gauge(document.getElementById('chart_div')); + data.setValue(0, 1, temp_val); + chart.draw(data, options); +} + +function getAin6_update() +{ + var oUpdate; + setTimeout(function() + { + oUpdate = new AJAX('get_ain6.cgi', + function(t) + { + try + { + eval(t); + } + catch(e) + { + alert(e); + } + } + ); + oUpdate.doGet(); + } + , 300); + setTimeout('getAin6_update()', 500); +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ajax.js b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ajax.js new file mode 100644 index 0000000..01c6bb7 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/ajax.js @@ -0,0 +1,68 @@ +function AJAX(a, e) +{ + var c = d(); + c.onreadystatechange = b; + function d() + { + if(window.XMLHttpRequest) + { + return new XMLHttpRequest() + } + else + { + if(window.ActiveXObject) + { + return new ActiveXObject("Microsoft.XMLHTTP") + } + } + } + function b() + { + if(c.readyState==4) + { + if(c.status==200) + { + if(e) + { + e(c.responseText) + } + } + } + } + this.doGet = function() + { + c.open("GET", a, true); c.send(null) + }; + this.doPost = function(f) + { + c.open("POST", a, true); + c.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + c.setRequestHeader("ISAJAX", "yes"); + c.send(f) + } +} +function $(a) +{ + return document.getElementById(a) +} +function $$(a) +{ + return document.getElementsByName(a) +} +function $$_ie(a, c) +{ + if(!a) + { + a = "*" + } + var b = document.getElementsByTagName(a); + var e = []; for(var d = 0; d +#(c) Ibragimov M. Russia Togliatty 19/08/2014 +# .PS used for build <***.h> from images(*.gif, *.jpg), *.css, static htm(l) pages, javascript etc.. +import sys, os +if len(sys.argv) < 2: + sys.exit('Usage: %s file-name' % sys.argv[0]) + +file_name = sys.argv[1] +if not os.path.exists(sys.argv[1]): + sys.exit('ERROR: Filename %s was not found!' % file_name) +else: + print('File %s is OK!' % file_name) +file_out = file_name.replace(".", "_") + ".h" +print('File_to_write is: %s' % file_out) +fhex = open(file_out, "w") +fhex_str = 'const char %s[] PROGMEM = {' % file_name.replace(".", "_") +print(fhex_str) +fhex.write(fhex_str + '\n') +with open(file_name, "rb") as f: + byte = f.read(1) + i = 0 + fhex_size = 0 + _str = "" + while byte != "": + # Do stuff with byte. + _byte = f.read(1) + fhex_size = fhex_size + 1 + if _byte != "": + #print ('%s, ' % hex(ord(byte))) + _str = _str + "%s," % hex(ord(byte)) + else: + #Last byte wo <,> + #print hex(ord(byte)) + _str = _str + "%s" % hex(ord(byte)) + if i < 15: + print _str + fhex.write(_str + '\n') + byte = _byte; + i = i + 1; + if i > 15: + i = 0; + print _str + fhex.write(_str + '\n') + _str = "" +print'};' +fhex.write('};\n') +_str = '%s: %d bytes' % (file_name, fhex_size) +print(_str); +fhex.write('//' + _str + '\n'); +fhex.close() diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/brd_wiz.png b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/brd_wiz.png new file mode 100644 index 0000000..90d075a Binary files /dev/null and b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/brd_wiz.png differ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/dio.htm b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/dio.htm new file mode 100644 index 0000000..191f317 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/dio.htm @@ -0,0 +1,24 @@ + + + + + W5500-AtMEGA1284p Web Server Digital I/O v1.1 + + + + + + + + +

LED1: unknown..

+ +
+ +
+
+ + + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/dio.js b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/dio.js new file mode 100644 index 0000000..5d1d164 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/dio.js @@ -0,0 +1,93 @@ +function DioCallback(o) +{ + var pin = o.dio_p; + $('txtdio_s'+pin).value = o.dio_s; + $('txtdio_d'+pin).value = o.dio_d; +} +function led1Callback(o) +{ + $('led1_txt').innerHTML = o.led1_txt; +} +function getDio(o) +{ + var p = o.attributes['pin'].value; + var oUpdate; + oUpdate = new AJAX('get_dio'+p+'.cgi', + function(t) + { + try + { + eval(t); + } + catch(e) + { + alert(e); + } + } + ); + oUpdate.doGet(); +} +function setDiostate(o) +{ + var p = o.attributes['pin'].value; + /*var v=$('txtdio_s'+p).value;*/ + var v = o.attributes['s'].value; + dout = new AJAX('set_diostate.cgi', + function(t) + { + try + { + /*eval(t);*/ + document.getElementById('led1_txt').innerHTML = t; + } + catch(e) + { + alert(e); + } + } + ); + dout.doPost('pin='+p+'&val='+v); +} +function setDiodir(o) +{ + var p = o.attributes['pin'].value; + /*var v=$('txtdio_d'+p).value;*/ + var v = o.attributes['d'].value; + dout = new AJAX('set_diodir.cgi', + function(t) + { + try + { + eval(t); + } + catch(e) + { + alert(e); + } + } + ); + dout.doPost('pin='+p+'&val='+v); +} +function getled1() +{ + var oUpdate; + setTimeout(function() + { + oUpdate = new AJAX('get_led1.cgi', + function(t) + { + try + { + eval(t); + } + catch(e) + { + alert(e); + } + } + ); + oUpdate.doGet(); + } + , 300); + setTimeout('getled1()', 3000); +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/favicon.ico b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/favicon.ico new file mode 100644 index 0000000..f63da06 Binary files /dev/null and b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/favicon.ico differ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/img.htm b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/img.htm new file mode 100644 index 0000000..f609e83 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/img.htm @@ -0,0 +1,14 @@ + + + + + W5500-AtMEGA1284p Web Server Image + + + + + + +
wizwebserver.png
+ + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/index.htm b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/index.htm new file mode 100644 index 0000000..758f904 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/index.htm @@ -0,0 +1,25 @@ + + + + + W5500-AtMEGA1284p Web Server + + + + +
+ W5500-AtMEGA1284p Web Server Demopage +

+ Network Information
+ Base64 Image Data
+
+ Board Schematic
+ Mounting Scheme
+
+ Ex1> Digital I/O
+ Ex2> Analog Input
+ Ex3> Analog Input: Google Gauge Chart
+
+ Device Information
+ + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/info.htm b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/info.htm new file mode 100644 index 0000000..fdc64f6 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/info.htm @@ -0,0 +1,18 @@ + + + + + W5500-AtMEGA1284p Device Info + + + + + + +
+ W5500-AtMEGA1284p Device Information +

+

..

+ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/info.js b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/info.js new file mode 100644 index 0000000..145be40 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/info.js @@ -0,0 +1,21 @@ +function getInfo() +{ + var oUpdate; + setTimeout(function() + { + oUpdate = new AJAX('get_info.cgi', function(t) + { + try + { + //*eval(t); + document.getElementById('info_txt').innerHTML = t; + } + catch(e) + { + alert(e); + } + } + ); oUpdate.doGet(); + } + , 300); setTimeout('getInfo()', 3000); +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/m1284p.png b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/m1284p.png new file mode 100644 index 0000000..a6dc8a3 Binary files /dev/null and b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/m1284p.png differ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/netinfo.htm b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/netinfo.htm new file mode 100644 index 0000000..581ba6e --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/netinfo.htm @@ -0,0 +1,33 @@ + + + + + W5500-AtMEGA1284p Web Server Network Info + + + + + + + +
+ W5500-AtMEGA1284p Web Server Network Information +

+ +
    +
  • + +
  • + +
  • + +
  • + +
  • +
+ + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/netinfo.js b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/netinfo.js new file mode 100644 index 0000000..ca5ca0a --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/WWW/netinfo.js @@ -0,0 +1,37 @@ +function NetinfoCallback(o) +{ + $('txtmac').value = o.mac; + $('txtip').value = o.ip; + $('txtgw').value = o.gw; + $('txtsn').value = o.sn; + $('txtdns').value = o.dns; + if(typeof(window.external)!='undefined') + { + obj = $$_ie('input', 'dhcp'); + } + else + { + obj = $$('dhcp'); + } +} +function getNetinfo() +{ + var oUpdate; + setTimeout(function() + { + oUpdate = new AJAX('get_netinfo.cgi', function(t) + { + try + { + eval(t); + } + catch(e) + { + alert(e); + } + } + ); + oUpdate.doGet(); + } + , 1500); +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/clean.bat b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/clean.bat new file mode 100644 index 0000000..9977613 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/clean.bat @@ -0,0 +1,3 @@ +del *.b#* +del *.s#* +pause diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ccsbcs.c.unicode b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ccsbcs.c.unicode new file mode 100644 index 0000000..42e8a57 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ccsbcs.c.unicode @@ -0,0 +1,348 @@ +/*------------------------------------------------------------------------*/ +/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */ +/* (SBCS code pages) */ +/*------------------------------------------------------------------------*/ +/* 437 U.S. +/ 720 Arabic +/ 737 Greek +/ 771 KBL +/ 775 Baltic +/ 850 Latin 1 +/ 852 Latin 2 +/ 855 Cyrillic +/ 857 Turkish +/ 860 Portuguese +/ 861 Icelandic +/ 862 Hebrew +/ 863 Canadian French +/ 864 Arabic +/ 865 Nordic +/ 866 Russian +/ 869 Greek 2 +*/ + +#include "ff.h" + + +#if _CODE_PAGE == 437 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 720 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */ + 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, + 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 737 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */ + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, + 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, + 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 771 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 775 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */ + 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, + 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, + 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, + 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 850 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 852 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, + 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, + 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 855 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */ + 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, + 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, + 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, + 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, + 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 857 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 860 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, + 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 861 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 862 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */ + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 863 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, + 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, + 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 864 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */ + 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, + 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, + 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F, + 0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9, + 0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9, + 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, + 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000 +}; + +#elif _CODE_PAGE == 865 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 866 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 869 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */ + 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, + 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, + 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3, + 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580, + 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, + 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 +}; + +#endif + + +#if !_TBLDEF || !_USE_LFN +#error This file is not needed at current configuration. Remove from the project. +#endif + + + + +WCHAR ff_convert ( /* Converted character, Returns zero on error */ + WCHAR chr, /* Character code to be converted */ + UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */ +) +{ + WCHAR c; + + + if (chr < 0x80) { /* ASCII */ + c = chr; + + } else { + if (dir) { /* OEM code to Unicode */ + c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80]; + + } else { /* Unicode to OEM code */ + for (c = 0; c < 0x80; c++) { + if (chr == Tbl[c]) break; + } + c = (c + 0x80) & 0xFF; + } + } + + return c; +} + + + + +WCHAR ff_wtoupper ( /* Returns upper converted character */ + WCHAR chr /* Unicode character to be upper converted */ +) +{ + static const WCHAR lower[] = { /* Lower case characters to be converted */ + /* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, + /* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E, + /* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217, + /* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB, + /* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9, + /* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586, + /* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9, + /* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F, + /* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A + }; + static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178, + 0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D, + 0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216, + 0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA, + 0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8, + 0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556, + 0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8, + 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F, + 0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A + }; + UINT i, n, hi, li; + + + if (chr < 0x80) { /* ASCII characters (acceleration) */ + if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20; + + } else { /* Non ASCII characters (table search) */ + n = 12; li = 0; hi = sizeof lower / sizeof lower[0]; + do { + i = li + (hi - li) / 2; + if (chr == lower[i]) break; + if (chr > lower[i]) li = i; else hi = i; + } while (--n); + if (n) chr = upper[i]; + } + + return chr; +} + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/diskio.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/diskio.h new file mode 100644 index 0000000..e7164ea --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/diskio.h @@ -0,0 +1,95 @@ +/*----------------------------------------------------------------------- +/ Low level disk interface modlue include file (C)ChaN, 2014 +/-----------------------------------------------------------------------*/ + +#ifndef _DISKIO_DEFINED +#define _DISKIO_DEFINED + +#ifdef __cplusplus +extern "C" { +#endif + +#define _USE_WRITE 1 /* 1: Enable disk_write function */ +#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */ + +#include "integer.h" + + +/* Status of Disk Functions */ +typedef BYTE DSTATUS; + +/* Results of Disk Functions */ +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ +} DRESULT; + + +/*---------------------------------------*/ +/* Prototypes for disk control functions */ + + +DSTATUS disk_initialize (BYTE pdrv); +DSTATUS disk_status (BYTE pdrv); +DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); +#if _USE_WRITE +DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); +#endif +#if _USE_IOCTL +DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); +#endif +void disk_timerproc (void); + + +/* Disk Status Bits (DSTATUS) */ +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + + +/* Command code for disk_ioctrl fucntion */ + +/* Generic command (Used by FatFs) */ +#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ +#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ + +/* Generic command (Not used by FatFs) */ +#define CTRL_FORMAT 5 /* Create physical format on the media */ +#define CTRL_POWER_IDLE 6 /* Put the device idle state */ +#define CTRL_POWER_OFF 7 /* Put the device off state */ +#define CTRL_LOCK 8 /* Lock media removal */ +#define CTRL_UNLOCK 9 /* Unlock media removal */ +#define CTRL_EJECT 10 /* Eject media */ + +/* MMC/SDC specific command (Not used by FatFs) */ +#define MMC_GET_TYPE 50 /* Get card type */ +#define MMC_GET_CSD 51 /* Get CSD */ +#define MMC_GET_CID 52 /* Get CID */ +#define MMC_GET_OCR 53 /* Get OCR */ +#define MMC_GET_SDSTAT 54 /* Get SD status */ + +/* ATA/CF specific command (Not used by FatFs) */ +#define ATA_GET_REV 60 /* Get F/W revision */ +#define ATA_GET_MODEL 61 /* Get model name */ +#define ATA_GET_SN 62 /* Get serial number */ + + +/* MMC card type flags (MMC_GET_TYPE) */ +#define CT_MMC 0x01 /* MMC ver 3 */ +#define CT_SD1 0x02 /* SD ver 1 */ +#define CT_SD2 0x04 /* SD ver 2 */ +#define CT_SDC (CT_SD1|CT_SD2) /* SD */ +#define CT_BLOCK 0x08 /* Block addressing */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ff.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ff.c new file mode 100644 index 0000000..e4199c3 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ff.c @@ -0,0 +1,4635 @@ +/*----------------------------------------------------------------------------/ +/ FatFs - FAT file system module R0.11 (C)ChaN, 2015 +/-----------------------------------------------------------------------------/ +/ FatFs module is a free software that opened under license policy of +/ following conditions. +/ +/ Copyright (C) 2015, ChaN, all right reserved. +/ +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +/----------------------------------------------------------------------------*/ + + +#include "ff.h" /* Declarations of FatFs API */ +#include "diskio.h" /* Declarations of disk I/O functions */ + + +/*-------------------------------------------------------------------------- + + Module Private Definitions + +---------------------------------------------------------------------------*/ + +#if _FATFS != 32020 /* Revision ID */ +#error Wrong include file (ff.h). +#endif + + +/* Reentrancy related */ +#if _FS_REENTRANT +#if _USE_LFN == 1 +#error Static LFN work area cannot be used at thread-safe configuration +#endif +#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } +#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#else +#define ENTER_FF(fs) +#define LEAVE_FF(fs, res) return res +#endif + +#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } + + +/* Definitions of sector size */ +#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) +#error Wrong sector size configuration +#endif +#if _MAX_SS == _MIN_SS +#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ +#else +#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#endif + + +/* Timestamp feature */ +#if _FS_NORTC == 1 +#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 +#error Invalid _FS_NORTC settings +#endif +#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) +#else +#define GET_FATTIME() get_fattime() +#endif + + +/* File access control feature */ +#if _FS_LOCK +#if _FS_READONLY +#error _FS_LOCK must be 0 at read-only configuration +#endif +typedef struct { + FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, directory (0:root) */ + WORD idx; /* Object ID 3, directory index */ + WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +} FILESEM; +#endif + + + +/* DBCS code ranges and SBCS extend character conversion table */ + +#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ +#define _DF1S 0x81 /* DBC 1st byte range 1 start */ +#define _DF1E 0x9F /* DBC 1st byte range 1 end */ +#define _DF2S 0xE0 /* DBC 1st byte range 2 start */ +#define _DF2E 0xFC /* DBC 1st byte range 2 end */ +#define _DS1S 0x40 /* DBC 2nd byte range 1 start */ +#define _DS1E 0x7E /* DBC 2nd byte range 1 end */ +#define _DS2S 0x80 /* DBC 2nd byte range 2 start */ +#define _DS2E 0xFC /* DBC 2nd byte range 2 end */ + +#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0x80 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 949 /* Korean */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x41 +#define _DS1E 0x5A +#define _DS2S 0x61 +#define _DS2E 0x7A +#define _DS3S 0x81 +#define _DS3E 0xFE + +#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0xA1 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 437 /* U.S. (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 720 /* Arabic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 737 /* Greek (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 775 /* Baltic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} + +#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ + 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ + 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 857 /* Turkish (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 862 /* Hebrew (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 866 /* Russian (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} + +#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ + 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF} + +#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} + +#elif _CODE_PAGE == 1253 /* Greek (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \ + 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF} + +#elif _CODE_PAGE == 1254 /* Turkish (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} + +#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1256 /* Arabic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1257 /* Baltic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} + +#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F} + +#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ +#if _USE_LFN +#error Cannot use LFN feature without valid code page. +#endif +#define _DF1S 0 + +#else +#error Unknown code page + +#endif + + +/* Character code support macros */ +#define IsUpper(c) (((c)>='A')&&((c)<='Z')) +#define IsLower(c) (((c)>='a')&&((c)<='z')) +#define IsDigit(c) (((c)>='0')&&((c)<='9')) + +#if _DF1S /* Code page is DBCS */ + +#ifdef _DF2S /* Two 1st byte areas */ +#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) +#else /* One 1st byte area */ +#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) +#endif + +#ifdef _DS3S /* Three 2nd byte areas */ +#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) +#else /* Two 2nd byte areas */ +#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) +#endif + +#else /* Code page is SBCS */ + +#define IsDBCS1(c) 0 +#define IsDBCS2(c) 0 + +#endif /* _DF1S */ + + +/* Name status flags */ +#define NSFLAG 11 /* Index of name status byte in fn[] */ +#define NS_LOSS 0x01 /* Out of 8.3 format */ +#define NS_LFN 0x02 /* Force to create LFN entry */ +#define NS_LAST 0x04 /* Last segment */ +#define NS_BODY 0x08 /* Lower case flag (body) */ +#define NS_EXT 0x10 /* Lower case flag (ext) */ +#define NS_DOT 0x20 /* Dot entry */ + + +/* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */ +#define MIN_FAT16 4086U /* Minimum number of clusters as FAT16 */ +#define MIN_FAT32 65526U /* Minimum number of clusters as FAT32 */ + + +/* FatFs refers the members in the FAT structures as byte array instead of +/ structure member because the structure is not binary compatible between +/ different platforms */ + +#define BS_jmpBoot 0 /* x86 jump instruction (3) */ +#define BS_OEMName 3 /* OEM name (8) */ +#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */ +#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */ +#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */ +#define BPB_NumFATs 16 /* Number of FAT copies (1) */ +#define BPB_RootEntCnt 17 /* Number of root directory entries for FAT12/16 (2) */ +#define BPB_TotSec16 19 /* Volume size [sector] (2) */ +#define BPB_Media 21 /* Media descriptor (1) */ +#define BPB_FATSz16 22 /* FAT size [sector] (2) */ +#define BPB_SecPerTrk 24 /* Track size [sector] (2) */ +#define BPB_NumHeads 26 /* Number of heads (2) */ +#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ +#define BPB_TotSec32 32 /* Volume size [sector] (4) */ +#define BS_DrvNum 36 /* Physical drive number (2) */ +#define BS_BootSig 38 /* Extended boot signature (1) */ +#define BS_VolID 39 /* Volume serial number (4) */ +#define BS_VolLab 43 /* Volume label (8) */ +#define BS_FilSysType 54 /* File system type (1) */ +#define BPB_FATSz32 36 /* FAT size [sector] (4) */ +#define BPB_ExtFlags 40 /* Extended flags (2) */ +#define BPB_FSVer 42 /* File system version (2) */ +#define BPB_RootClus 44 /* Root directory first cluster (4) */ +#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */ +#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */ +#define BS_DrvNum32 64 /* Physical drive number (2) */ +#define BS_BootSig32 66 /* Extended boot signature (1) */ +#define BS_VolID32 67 /* Volume serial number (4) */ +#define BS_VolLab32 71 /* Volume label (8) */ +#define BS_FilSysType32 82 /* File system type (1) */ +#define FSI_LeadSig 0 /* FSI: Leading signature (4) */ +#define FSI_StrucSig 484 /* FSI: Structure signature (4) */ +#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */ +#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */ +#define MBR_Table 446 /* MBR: Partition table offset (2) */ +#define SZ_PTE 16 /* MBR: Size of a partition table entry */ +#define BS_55AA 510 /* Signature word (2) */ + +#define DIR_Name 0 /* Short file name (11) */ +#define DIR_Attr 11 /* Attribute (1) */ +#define DIR_NTres 12 /* Lower case flag (1) */ +#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */ +#define DIR_CrtTime 14 /* Created time (2) */ +#define DIR_CrtDate 16 /* Created date (2) */ +#define DIR_LstAccDate 18 /* Last accessed date (2) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */ +#define DIR_WrtTime 22 /* Modified time (2) */ +#define DIR_WrtDate 24 /* Modified date (2) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */ +#define DIR_FileSize 28 /* File size (4) */ +#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ +#define LDIR_Attr 11 /* LFN attribute (1) */ +#define LDIR_Type 12 /* LFN type (1) */ +#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */ +#define LDIR_FstClusLO 26 /* Must be zero (0) */ +#define SZ_DIRE 32 /* Size of a directory entry */ +#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ +#define DDEM 0xE5 /* Deleted directory entry mark at DIR_Name[0] */ +#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ + + + + +/*------------------------------------------------------------*/ +/* Module private work area */ +/*------------------------------------------------------------*/ +/* Remark: Uninitialized variables with static duration are +/ guaranteed zero/null at start-up. If not, either the linker +/ or start-up routine being used is out of ANSI-C standard. +*/ + +#if _VOLUMES < 1 || _VOLUMES > 9 +#error Wrong _VOLUMES setting +#endif +static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ +static WORD Fsid; /* File system mount ID */ + +#if _FS_RPATH && _VOLUMES >= 2 +static BYTE CurrVol; /* Current drive */ +#endif + +#if _FS_LOCK +static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ +#endif + +#if _USE_LFN == 0 /* Non LFN feature */ +#define DEFINE_NAMEBUF BYTE sfn[12] +#define INIT_BUF(dobj) (dobj).fn = sfn +#define FREE_BUF() +#else +#if _MAX_LFN < 12 || _MAX_LFN > 255 +#error Wrong _MAX_LFN setting +#endif +#if _USE_LFN == 1 /* LFN feature with static working buffer */ +static WCHAR LfnBuf[_MAX_LFN + 1]; +#define DEFINE_NAMEBUF BYTE sfn[12] +#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; } +#define FREE_BUF() +#elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */ +#define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN + 1] +#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; } +#define FREE_BUF() +#elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */ +#define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR *lfn +#define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); (dobj).lfn = lfn; (dobj).fn = sfn; } +#define FREE_BUF() ff_memfree(lfn) +#else +#error Wrong _USE_LFN setting +#endif +#endif + +#ifdef _EXCVT +static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for extended characters */ +#endif + + + + + + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* String functions */ +/*-----------------------------------------------------------------------*/ + +/* Copy memory to memory */ +static +void mem_cpy (void* dst, const void* src, UINT cnt) { + BYTE *d = (BYTE*)dst; + const BYTE *s = (const BYTE*)src; + +#if _WORD_ACCESS == 1 + while (cnt >= sizeof (int)) { + *(int*)d = *(int*)s; + d += sizeof (int); s += sizeof (int); + cnt -= sizeof (int); + } +#endif + while (cnt--) + *d++ = *s++; +} + +/* Fill memory */ +static +void mem_set (void* dst, int val, UINT cnt) { + BYTE *d = (BYTE*)dst; + + while (cnt--) + *d++ = (BYTE)val; +} + +/* Compare memory to memory */ +static +int mem_cmp (const void* dst, const void* src, UINT cnt) { + const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; + int r = 0; + + while (cnt-- && (r = *d++ - *s++) == 0) ; + return r; +} + +/* Check if chr is contained in the string */ +static +int chk_chr (const char* str, int chr) { + while (*str && *str != chr) str++; + return *str; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Request/Release grant to access the volume */ +/*-----------------------------------------------------------------------*/ +#if _FS_REENTRANT +static +int lock_fs ( + FATFS* fs /* File system object */ +) +{ + return ff_req_grant(fs->sobj); +} + + +static +void unlock_fs ( + FATFS* fs, /* File system object */ + FRESULT res /* Result code to be returned */ +) +{ + if (fs && + res != FR_NOT_ENABLED && + res != FR_INVALID_DRIVE && + res != FR_INVALID_OBJECT && + res != FR_TIMEOUT) { + ff_rel_grant(fs->sobj); + } +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* File lock control functions */ +/*-----------------------------------------------------------------------*/ +#if _FS_LOCK + +static +FRESULT chk_lock ( /* Check if the file can be accessed */ + DIR* dp, /* Directory object pointing the file to be checked */ + int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */ +) +{ + UINT i, be; + + /* Search file semaphore table */ + for (i = be = 0; i < _FS_LOCK; i++) { + if (Files[i].fs) { /* Existing entry */ + if (Files[i].fs == dp->fs && /* Check if the object matched with an open object */ + Files[i].clu == dp->sclust && + Files[i].idx == dp->index) break; + } else { /* Blank entry */ + be = 1; + } + } + if (i == _FS_LOCK) /* The object is not opened */ + return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */ + + /* The object has been opened. Reject any open against writing file and all write mode open */ + return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; +} + + +static +int enq_lock (void) /* Check if an entry is available for a new object */ +{ + UINT i; + + for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; + return (i == _FS_LOCK) ? 0 : 1; +} + + +static +UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ + DIR* dp, /* Directory object pointing the file to register or increment */ + int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ +) +{ + UINT i; + + + for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ + if (Files[i].fs == dp->fs && + Files[i].clu == dp->sclust && + Files[i].idx == dp->index) break; + } + + if (i == _FS_LOCK) { /* Not opened. Register it as new. */ + for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; + if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */ + Files[i].fs = dp->fs; + Files[i].clu = dp->sclust; + Files[i].idx = dp->index; + Files[i].ctr = 0; + } + + if (acc && Files[i].ctr) return 0; /* Access violation (int err) */ + + Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ + + return i + 1; +} + + +static +FRESULT dec_lock ( /* Decrement object open counter */ + UINT i /* Semaphore index (1..) */ +) +{ + WORD n; + FRESULT res; + + + if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ + n = Files[i].ctr; + if (n == 0x100) n = 0; /* If write mode open, delete the entry */ + if (n) n--; /* Decrement read mode open count */ + Files[i].ctr = n; + if (!n) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + res = FR_OK; + } else { + res = FR_INT_ERR; /* Invalid index nunber */ + } + return res; +} + + +static +void clear_lock ( /* Clear lock entries of the volume */ + FATFS *fs +) +{ + UINT i; + + for (i = 0; i < _FS_LOCK; i++) { + if (Files[i].fs == fs) Files[i].fs = 0; + } +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Move/Flush disk access window in the file system object */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT sync_window ( + FATFS* fs /* File system object */ +) +{ + DWORD wsect; + UINT nf; + FRESULT res = FR_OK; + + + if (fs->wflag) { /* Write back the sector if it is dirty */ + wsect = fs->winsect; /* Current sector number */ + if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) { + res = FR_DISK_ERR; + } else { + fs->wflag = 0; + if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */ + for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */ + wsect += fs->fsize; + disk_write(fs->drv, fs->win, wsect, 1); + } + } + } + } + return res; +} +#endif + + +static +FRESULT move_window ( + FATFS* fs, /* File system object */ + DWORD sector /* Sector number to make appearance in the fs->win[] */ +) +{ + FRESULT res = FR_OK; + + + if (sector != fs->winsect) { /* Window offset changed? */ +#if !_FS_READONLY + res = sync_window(fs); /* Write-back changes */ +#endif + if (res == FR_OK) { /* Fill sector window with new data */ + if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) { + sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */ + res = FR_DISK_ERR; + } + fs->winsect = sector; + } + } + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Synchronize file system and strage device */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */ + FATFS* fs /* File system object */ +) +{ + FRESULT res; + + + res = sync_window(fs); + if (res == FR_OK) { + /* Update FSINFO sector if needed */ + if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { + /* Create FSINFO structure */ + mem_set(fs->win, 0, SS(fs)); + ST_WORD(fs->win + BS_55AA, 0xAA55); + ST_DWORD(fs->win + FSI_LeadSig, 0x41615252); + ST_DWORD(fs->win + FSI_StrucSig, 0x61417272); + ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust); + ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust); + /* Write it into the FSINFO sector */ + fs->winsect = fs->volbase + 1; + disk_write(fs->drv, fs->win, fs->winsect, 1); + fs->fsi_flag = 0; + } + /* Make sure that no pending write process in the physical drive */ + if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) + res = FR_DISK_ERR; + } + + return res; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Get sector# from cluster# */ +/*-----------------------------------------------------------------------*/ +/* Hidden API for hacks and disk tools */ + +DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to be converted */ +) +{ + clst -= 2; + if (clst >= fs->n_fatent - 2) return 0; /* Invalid cluster# */ + return clst * fs->csize + fs->database; +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT access - Read value of a FAT entry */ +/*-----------------------------------------------------------------------*/ +/* Hidden API for hacks and disk tools */ + +DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */ + FATFS* fs, /* File system object */ + DWORD clst /* FAT index number (cluster number) to get the value */ +) +{ + UINT wc, bc; + BYTE *p; + DWORD val; + + + if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + val = 1; /* Internal error */ + + } else { + val = 0xFFFFFFFF; /* Default value falls on disk error */ + + switch (fs->fs_type) { + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; + wc = fs->win[bc++ % SS(fs)]; + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; + wc |= fs->win[bc % SS(fs)] << 8; + val = clst & 1 ? wc >> 4 : (wc & 0xFFF); + break; + + case FS_FAT16 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; + p = &fs->win[clst * 2 % SS(fs)]; + val = LD_WORD(p); + break; + + case FS_FAT32 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + p = &fs->win[clst * 4 % SS(fs)]; + val = LD_DWORD(p) & 0x0FFFFFFF; + break; + + default: + val = 1; /* Internal error */ + } + } + + return val; +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT access - Change value of a FAT entry */ +/*-----------------------------------------------------------------------*/ +/* Hidden API for hacks and disk tools */ + +#if !_FS_READONLY +FRESULT put_fat ( + FATFS* fs, /* File system object */ + DWORD clst, /* FAT index number (cluster number) to be changed */ + DWORD val /* New value to be set to the entry */ +) +{ + UINT bc; + BYTE *p; + FRESULT res; + + + if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + res = FR_INT_ERR; + + } else { + switch (fs->fs_type) { + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = &fs->win[bc++ % SS(fs)]; + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; + fs->wflag = 1; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = &fs->win[bc % SS(fs)]; + *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); + fs->wflag = 1; + break; + + case FS_FAT16 : + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); + if (res != FR_OK) break; + p = &fs->win[clst * 2 % SS(fs)]; + ST_WORD(p, (WORD)val); + fs->wflag = 1; + break; + + case FS_FAT32 : + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); + if (res != FR_OK) break; + p = &fs->win[clst * 4 % SS(fs)]; + val |= LD_DWORD(p) & 0xF0000000; + ST_DWORD(p, val); + fs->wflag = 1; + break; + + default : + res = FR_INT_ERR; + } + } + + return res; +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Remove a cluster chain */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT remove_chain ( + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to remove a chain from */ +) +{ + FRESULT res; + DWORD nxt; +#if _USE_TRIM + DWORD scl = clst, ecl = clst, rt[2]; +#endif + + if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + res = FR_INT_ERR; + + } else { + res = FR_OK; + while (clst < fs->n_fatent) { /* Not a last link? */ + nxt = get_fat(fs, clst); /* Get cluster status */ + if (nxt == 0) break; /* Empty cluster? */ + if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */ + if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */ + res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */ + if (res != FR_OK) break; + if (fs->free_clust != 0xFFFFFFFF) { /* Update FSINFO */ + fs->free_clust++; + fs->fsi_flag |= 1; + } +#if _USE_TRIM + if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ + ecl = nxt; + } else { /* End of contiguous clusters */ + rt[0] = clust2sect(fs, scl); /* Start sector */ + rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ + disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Erase the block */ + scl = ecl = nxt; + } +#endif + clst = nxt; /* Next cluster */ + } + } + + return res; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Stretch or Create a cluster chain */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to stretch. 0 means create a new chain. */ +) +{ + DWORD cs, ncl, scl; + FRESULT res; + + + if (clst == 0) { /* Create a new chain */ + scl = fs->last_clust; /* Get suggested start point */ + if (!scl || scl >= fs->n_fatent) scl = 1; + } + else { /* Stretch the current chain */ + cs = get_fat(fs, clst); /* Check the cluster status */ + if (cs < 2) return 1; /* Invalid value */ + if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ + if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ + scl = clst; + } + + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Check wrap around */ + ncl = 2; + if (ncl > scl) return 0; /* No free cluster */ + } + cs = get_fat(fs, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster */ + if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */ + return cs; + if (ncl == scl) return 0; /* No free cluster */ + } + + res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */ + if (res == FR_OK && clst != 0) { + res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */ + } + if (res == FR_OK) { + fs->last_clust = ncl; /* Update FSINFO */ + if (fs->free_clust != 0xFFFFFFFF) { + fs->free_clust--; + fs->fsi_flag |= 1; + } + } else { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; + } + + return ncl; /* Return new cluster number or error code */ +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Convert offset into cluster with link map table */ +/*-----------------------------------------------------------------------*/ + +#if _USE_FASTSEEK +static +DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ + FIL* fp, /* Pointer to the file object */ + DWORD ofs /* File offset to be converted to cluster# */ +) +{ + DWORD cl, ncl, *tbl; + + + tbl = fp->cltbl + 1; /* Top of CLMT */ + cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */ + for (;;) { + ncl = *tbl++; /* Number of cluters in the fragment */ + if (!ncl) return 0; /* End of table? (error) */ + if (cl < ncl) break; /* In this fragment? */ + cl -= ncl; tbl++; /* Next fragment */ + } + return cl + *tbl; /* Return the cluster number */ +} +#endif /* _USE_FASTSEEK */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Set directory index */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_sdi ( + DIR* dp, /* Pointer to directory object */ + UINT idx /* Index of directory table */ +) +{ + DWORD clst, sect; + UINT ic; + + + dp->index = (WORD)idx; /* Current index */ + clst = dp->sclust; /* Table start cluster (0:root) */ + if (clst == 1 || clst >= dp->fs->n_fatent) /* Check start cluster range */ + return FR_INT_ERR; + if (!clst && dp->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ + clst = dp->fs->dirbase; + + if (clst == 0) { /* Static table (root-directory in FAT12/16) */ + if (idx >= dp->fs->n_rootdir) /* Is index out of range? */ + return FR_INT_ERR; + sect = dp->fs->dirbase; + } + else { /* Dynamic table (root-directory in FAT32 or sub-directory) */ + ic = SS(dp->fs) / SZ_DIRE * dp->fs->csize; /* Entries per cluster */ + while (idx >= ic) { /* Follow cluster chain */ + clst = get_fat(dp->fs, clst); /* Get next cluster */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst < 2 || clst >= dp->fs->n_fatent) /* Reached to end of table or internal error */ + return FR_INT_ERR; + idx -= ic; + } + sect = clust2sect(dp->fs, clst); + } + dp->clust = clst; /* Current cluster# */ + if (!sect) return FR_INT_ERR; + dp->sect = sect + idx / (SS(dp->fs) / SZ_DIRE); /* Sector# of the directory entry */ + dp->dir = dp->fs->win + (idx % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Ptr to the entry in the sector */ + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Move directory table index next */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ + DIR* dp, /* Pointer to the directory object */ + int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ +) +{ + DWORD clst; + UINT i; +#if !_FS_READONLY + UINT c; +#endif + + + i = dp->index + 1; + if (!(i & 0xFFFF) || !dp->sect) /* Report EOT when index has reached 65535 */ + return FR_NO_FILE; + + if (!(i % (SS(dp->fs) / SZ_DIRE))) { /* Sector changed? */ + dp->sect++; /* Next sector */ + + if (!dp->clust) { /* Static table */ + if (i >= dp->fs->n_rootdir) /* Report EOT if it reached end of static table */ + return FR_NO_FILE; + } + else { /* Dynamic table */ + if (((i / (SS(dp->fs) / SZ_DIRE)) & (dp->fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(dp->fs, dp->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; + if (clst >= dp->fs->n_fatent) { /* If it reached end of dynamic table, */ +#if !_FS_READONLY + if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT */ + clst = create_chain(dp->fs, dp->clust); /* Stretch cluster chain */ + if (clst == 0) return FR_DENIED; /* No free cluster */ + if (clst == 1) return FR_INT_ERR; + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; + /* Clean-up stretched table */ + if (sync_window(dp->fs)) return FR_DISK_ERR;/* Flush disk access window */ + mem_set(dp->fs->win, 0, SS(dp->fs)); /* Clear window buffer */ + dp->fs->winsect = clust2sect(dp->fs, clst); /* Cluster start sector */ + for (c = 0; c < dp->fs->csize; c++) { /* Fill the new cluster with 0 */ + dp->fs->wflag = 1; + if (sync_window(dp->fs)) return FR_DISK_ERR; + dp->fs->winsect++; + } + dp->fs->winsect -= c; /* Rewind window offset */ +#else + if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT (this is to suppress warning) */ + return FR_NO_FILE; /* Report EOT */ +#endif + } + dp->clust = clst; /* Initialize data for new cluster */ + dp->sect = clust2sect(dp->fs, clst); + } + } + } + + dp->index = (WORD)i; /* Current index */ + dp->dir = dp->fs->win + (i % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Current entry in the window */ + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Reserve directory entry */ +/*-----------------------------------------------------------------------*/ + +#if !_FS_READONLY +static +FRESULT dir_alloc ( + DIR* dp, /* Pointer to the directory object */ + UINT nent /* Number of contiguous entries to allocate (1-21) */ +) +{ + FRESULT res; + UINT n; + + + res = dir_sdi(dp, 0); + if (res == FR_OK) { + n = 0; + do { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) break; + if (dp->dir[0] == DDEM || dp->dir[0] == 0) { /* Is it a free entry? */ + if (++n == nent) break; /* A block of contiguous free entries is found */ + } else { + n = 0; /* Not a blank entry. Restart to search */ + } + res = dir_next(dp, 1); /* Next entry with table stretch enabled */ + } while (res == FR_OK); + } + if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ + return res; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Load/Store start cluster number */ +/*-----------------------------------------------------------------------*/ + +static +DWORD ld_clust ( + FATFS* fs, /* Pointer to the fs object */ + BYTE* dir /* Pointer to the directory entry */ +) +{ + DWORD cl; + + cl = LD_WORD(dir + DIR_FstClusLO); + if (fs->fs_type == FS_FAT32) + cl |= (DWORD)LD_WORD(dir + DIR_FstClusHI) << 16; + + return cl; +} + + +#if !_FS_READONLY +static +void st_clust ( + BYTE* dir, /* Pointer to the directory entry */ + DWORD cl /* Value to be set */ +) +{ + ST_WORD(dir + DIR_FstClusLO, cl); + ST_WORD(dir + DIR_FstClusHI, cl >> 16); +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */ +/*-----------------------------------------------------------------------*/ +#if _USE_LFN +static +const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ + + +static +int cmp_lfn ( /* 1:Matched, 0:Not matched */ + WCHAR* lfnbuf, /* Pointer to the LFN to be compared */ + BYTE* dir /* Pointer to the directory entry containing a part of LFN */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Get offset in the LFN buffer */ + s = 0; wc = 1; + do { + uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ + if (wc) { /* Last character has not been processed */ + wc = ff_wtoupper(uc); /* Convert it to upper case */ + if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */ + return 0; /* Not matched */ + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } while (++s < 13); /* Repeat until all characters in the entry are checked */ + + if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */ + return 0; + + return 1; /* The part of LFN matched */ +} + + + +static +int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ + WCHAR* lfnbuf, /* Pointer to the Unicode-LFN buffer */ + BYTE* dir /* Pointer to the directory entry */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + + s = 0; wc = 1; + do { + uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ + if (wc) { /* Last character has not been processed */ + if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i++] = wc = uc; /* Store it */ + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } while (++s < 13); /* Read all character in the entry */ + + if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ + if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i] = 0; + } + + return 1; +} + + +#if !_FS_READONLY +static +void fit_lfn ( + const WCHAR* lfnbuf, /* Pointer to the LFN buffer */ + BYTE* dir, /* Pointer to the directory entry */ + BYTE ord, /* LFN order (1-20) */ + BYTE sum /* SFN sum */ +) +{ + UINT i, s; + WCHAR wc; + + + dir[LDIR_Chksum] = sum; /* Set check sum */ + dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ + dir[LDIR_Type] = 0; + ST_WORD(dir + LDIR_FstClusLO, 0); + + i = (ord - 1) * 13; /* Get offset in the LFN buffer */ + s = wc = 0; + do { + if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */ + ST_WORD(dir+LfnOfs[s], wc); /* Put it */ + if (!wc) wc = 0xFFFF; /* Padding characters following last character */ + } while (++s < 13); + if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLEF; /* Bottom LFN part is the start of LFN sequence */ + dir[LDIR_Ord] = ord; /* Set the LFN order */ +} + +#endif +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Create numbered name */ +/*-----------------------------------------------------------------------*/ +#if _USE_LFN +static +void gen_numname ( + BYTE* dst, /* Pointer to the buffer to store numbered SFN */ + const BYTE* src, /* Pointer to SFN */ + const WCHAR* lfn, /* Pointer to LFN */ + UINT seq /* Sequence number */ +) +{ + BYTE ns[8], c; + UINT i, j; + WCHAR wc; + DWORD sr; + + + mem_cpy(dst, src, 11); + + if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */ + sr = seq; + while (*lfn) { /* Create a CRC */ + wc = *lfn++; + for (i = 0; i < 16; i++) { + sr = (sr << 1) + (wc & 1); + wc >>= 1; + if (sr & 0x10000) sr ^= 0x11021; + } + } + seq = (UINT)sr; + } + + /* itoa (hexdecimal) */ + i = 7; + do { + c = (seq % 16) + '0'; + if (c > '9') c += 7; + ns[i--] = c; + seq /= 16; + } while (seq); + ns[i] = '~'; + + /* Append the number */ + for (j = 0; j < i && dst[j] != ' '; j++) { + if (IsDBCS1(dst[j])) { + if (j == i - 1) break; + j++; + } + } + do { + dst[j++] = (i < 8) ? ns[i++] : ' '; + } while (j < 8); +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Calculate sum of an SFN */ +/*-----------------------------------------------------------------------*/ +#if _USE_LFN +static +BYTE sum_sfn ( + const BYTE* dir /* Pointer to the SFN entry */ +) +{ + BYTE sum = 0; + UINT n = 11; + + do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); + return sum; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Find an object in the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_find ( + DIR* dp /* Pointer to the directory object linked to the file name */ +) +{ + FRESULT res; + BYTE c, *dir; +#if _USE_LFN + BYTE a, ord, sum; +#endif + + res = dir_sdi(dp, 0); /* Rewind directory object */ + if (res != FR_OK) return res; + +#if _USE_LFN + ord = sum = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ +#endif + do { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) break; + dir = dp->dir; /* Ptr to the directory entry of current index */ + c = dir[DIR_Name]; + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ +#if _USE_LFN /* LFN configuration */ + a = dir[DIR_Attr] & AM_MASK; + if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (dp->lfn) { + if (c & LLEF) { /* Is it start of LFN sequence? */ + sum = dir[LDIR_Chksum]; + c &= ~LLEF; ord = c; /* LFN start order */ + dp->lfn_idx = dp->index; /* Start index of LFN */ + } + /* Check validity of the LFN entry and compare it with given name */ + ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; + } + } else { /* An SFN entry is found */ + if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */ + if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dir, dp->fn, 11)) break; /* SFN matched? */ + ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + } + } +#else /* Non LFN configuration */ + if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dp->fn, 11)) /* Is it a valid entry? */ + break; +#endif + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read an object from the directory */ +/*-----------------------------------------------------------------------*/ +#if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 +static +FRESULT dir_read ( + DIR* dp, /* Pointer to the directory object */ + int vol /* Filtered by 0:file/directory or 1:volume label */ +) +{ + FRESULT res; + BYTE a, c, *dir; +#if _USE_LFN + BYTE ord = 0xFF, sum = 0xFF; +#endif + + res = FR_NO_FILE; + while (dp->sect) { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) break; + dir = dp->dir; /* Ptr to the directory entry of current index */ + c = dir[DIR_Name]; + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ + a = dir[DIR_Attr] & AM_MASK; +#if _USE_LFN /* LFN configuration */ + if (c == DDEM || (!_FS_RPATH && c == '.') || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (c & LLEF) { /* Is it start of LFN sequence? */ + sum = dir[LDIR_Chksum]; + c &= ~LLEF; ord = c; + dp->lfn_idx = dp->index; + } + /* Check LFN validity and capture it */ + ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; + } else { /* An SFN entry is found */ + if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */ + dp->lfn_idx = 0xFFFF; /* It has no LFN. */ + break; + } + } +#else /* Non LFN configuration */ + if (c != DDEM && (_FS_RPATH || c != '.') && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) /* Is it a valid entry? */ + break; +#endif + res = dir_next(dp, 0); /* Next entry */ + if (res != FR_OK) break; + } + + if (res != FR_OK) dp->sect = 0; + + return res; +} +#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ + + + + +/*-----------------------------------------------------------------------*/ +/* Register an object to the directory */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */ + DIR* dp /* Target directory with object name to be created */ +) +{ + FRESULT res; +#if _USE_LFN /* LFN configuration */ + UINT n, nent; + BYTE sn[12], *fn, sum; + WCHAR *lfn; + + + fn = dp->fn; lfn = dp->lfn; + mem_cpy(sn, fn, 12); + + if (_FS_RPATH && (sn[NSFLAG] & NS_DOT)) /* Cannot create dot entry */ + return FR_INVALID_NAME; + + if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ + fn[NSFLAG] = 0; dp->lfn = 0; /* Find only SFN */ + for (n = 1; n < 100; n++) { + gen_numname(fn, sn, lfn, n); /* Generate a numbered name */ + res = dir_find(dp); /* Check if the name collides with existing SFN */ + if (res != FR_OK) break; + } + if (n == 100) return FR_DENIED; /* Abort if too many collisions */ + if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ + fn[NSFLAG] = sn[NSFLAG]; dp->lfn = lfn; + } + + if (sn[NSFLAG] & NS_LFN) { /* When LFN is to be created, allocate entries for an SFN + LFNs. */ + for (n = 0; lfn[n]; n++) ; + nent = (n + 25) / 13; + } else { /* Otherwise allocate an entry for an SFN */ + nent = 1; + } + res = dir_alloc(dp, nent); /* Allocate entries */ + + if (res == FR_OK && --nent) { /* Set LFN entry if needed */ + res = dir_sdi(dp, dp->index - nent); + if (res == FR_OK) { + sum = sum_sfn(dp->fn); /* Sum value of the SFN tied to the LFN */ + do { /* Store LFN entries in bottom first */ + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) break; + fit_lfn(dp->lfn, dp->dir, (BYTE)nent, sum); + dp->fs->wflag = 1; + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK && --nent); + } + } +#else /* Non LFN configuration */ + res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ +#endif + + if (res == FR_OK) { /* Set SFN entry */ + res = move_window(dp->fs, dp->sect); + if (res == FR_OK) { + mem_set(dp->dir, 0, SZ_DIRE); /* Clean the entry */ + mem_cpy(dp->dir, dp->fn, 11); /* Put SFN */ +#if _USE_LFN + dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ +#endif + dp->fs->wflag = 1; + } + } + + return res; +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Remove an object from the directory */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY && !_FS_MINIMIZE +static +FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ + DIR* dp /* Directory object pointing the entry to be removed */ +) +{ + FRESULT res; +#if _USE_LFN /* LFN configuration */ + UINT i; + + i = dp->index; /* SFN index */ + res = dir_sdi(dp, (dp->lfn_idx == 0xFFFF) ? i : dp->lfn_idx); /* Goto the SFN or top of the LFN entries */ + if (res == FR_OK) { + do { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) break; + mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */ + *dp->dir = DDEM; + dp->fs->wflag = 1; + if (dp->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */ + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR; + } + +#else /* Non LFN configuration */ + res = dir_sdi(dp, dp->index); + if (res == FR_OK) { + res = move_window(dp->fs, dp->sect); + if (res == FR_OK) { + mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */ + *dp->dir = DDEM; + dp->fs->wflag = 1; + } + } +#endif + + return res; +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Get file information from directory entry */ +/*-----------------------------------------------------------------------*/ +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +static +void get_fileinfo ( /* No return code */ + DIR* dp, /* Pointer to the directory object */ + FILINFO* fno /* Pointer to the file information to be filled */ +) +{ + UINT i; + TCHAR *p, c; + BYTE *dir; +#if _USE_LFN + WCHAR w, *lfn; +#endif + + p = fno->fname; + if (dp->sect) { /* Get SFN */ + dir = dp->dir; + i = 0; + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dir[i++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ + if (i == 9) *p++ = '.'; /* Insert a . if extension is exist */ +#if _USE_LFN + if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) + c += 0x20; /* To lower */ +#if _LFN_UNICODE + if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i])) + c = c << 8 | dir[i++]; + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) c = '?'; +#endif +#endif + *p++ = c; + } + fno->fattrib = dir[DIR_Attr]; /* Attribute */ + fno->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */ + fno->fdate = LD_WORD(dir + DIR_WrtDate); /* Date */ + fno->ftime = LD_WORD(dir + DIR_WrtTime); /* Time */ + } + *p = 0; /* Terminate SFN string by a \0 */ + +#if _USE_LFN + if (fno->lfname) { + i = 0; p = fno->lfname; + if (dp->sect && fno->lfsize && dp->lfn_idx != 0xFFFF) { /* Get LFN if available */ + lfn = dp->lfn; + while ((w = *lfn++) != 0) { /* Get an LFN character */ +#if !_LFN_UNICODE + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (!w) { i = 0; break; } /* No LFN if it could not be converted */ + if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */ + p[i++] = (TCHAR)(w >> 8); +#endif + if (i >= fno->lfsize - 1) { i = 0; break; } /* No LFN if buffer overflow */ + p[i++] = (TCHAR)w; + } + } + p[i] = 0; /* Terminate LFN string by a \0 */ + } +#endif +} +#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ + + + + +/*-----------------------------------------------------------------------*/ +/* Pattern matching */ +/*-----------------------------------------------------------------------*/ +#if _USE_FIND && _FS_MINIMIZE <= 1 +static +WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */ + const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ +) +{ + WCHAR chr; + +#if !_LFN_UNICODE + chr = (BYTE)*(*ptr)++; /* Get a byte */ + if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ + if (IsDBCS1(chr) && IsDBCS2(**ptr)) /* Get DBC 2nd byte if needed */ + chr = chr << 8 | (BYTE)*(*ptr)++; +#ifdef _EXCVT + if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ +#endif +#else + chr = ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ +#endif + return chr; +} + + +static +int pattern_matching ( /* Return value: 0:mismatched, 1:matched */ + const TCHAR* pat, /* Matching pattern */ + const TCHAR* nam, /* String to be tested */ + int skip, /* Number of pre-skip chars (number of ?s) */ + int inf /* Infinite search (* specified) */ +) +{ + const TCHAR *pp, *np; + WCHAR pc, nc; + int nm, nx; + + + while (skip--) { /* Pre-skip name chars */ + if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ + } + if (!*pat && inf) return 1; /* (short circuit) */ + + do { + pp = pat; np = nam; /* Top of pattern and name to match */ + for (;;) { + if (*pp == '?' || *pp == '*') { /* Wildcard? */ + nm = nx = 0; + do { /* Analyze the wildcard chars */ + if (*pp++ == '?') nm++; else nx = 1; + } while (*pp == '?' || *pp == '*'); + if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ + nc = *np; break; /* Branch mismatched */ + } + pc = get_achar(&pp); /* Get a pattern char */ + nc = get_achar(&np); /* Get a name char */ + if (pc != nc) break; /* Branch mismatched? */ + if (!pc) return 1; /* Branch matched? (matched at end of both strings) */ + } + get_achar(&nam); /* nam++ */ + } while (inf && nc); /* Retry until end of name if infinite search is specified */ + + return 0; +} +#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ + + + + +/*-----------------------------------------------------------------------*/ +/* Pick a segment and create the object name in directory form */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT create_name ( + DIR* dp, /* Pointer to the directory object */ + const TCHAR** path /* Pointer to pointer to the segment in the path string */ +) +{ +#if _USE_LFN /* LFN configuration */ + BYTE b, cf; + WCHAR w, *lfn; + UINT i, ni, si, di; + const TCHAR *p; + + /* Create LFN in Unicode */ + for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ + lfn = dp->lfn; + si = di = 0; + for (;;) { + w = p[si++]; /* Get a character */ + if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */ + if (di >= _MAX_LFN) /* Reject too long name */ + return FR_INVALID_NAME; +#if !_LFN_UNICODE + w &= 0xFF; + if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ + b = (BYTE)p[si++]; /* Get 2nd byte */ + w = (w << 8) + b; /* Create a DBC */ + if (!IsDBCS2(b)) + return FR_INVALID_NAME; /* Reject invalid sequence */ + } + w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ + if (!w) return FR_INVALID_NAME; /* Reject invalid code */ +#endif + if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal characters for LFN */ + return FR_INVALID_NAME; + lfn[di++] = w; /* Store the Unicode character */ + } + *path = &p[si]; /* Return pointer to the next segment */ + cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ +#if _FS_RPATH + if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */ + (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { + lfn[di] = 0; + for (i = 0; i < 11; i++) + dp->fn[i] = (i < di) ? '.' : ' '; + dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ + return FR_OK; + } +#endif + while (di) { /* Strip trailing spaces and dots */ + w = lfn[di - 1]; + if (w != ' ' && w != '.') break; + di--; + } + if (!di) return FR_INVALID_NAME; /* Reject nul string */ + + lfn[di] = 0; /* LFN is created */ + + /* Create SFN in directory form */ + mem_set(dp->fn, ' ', 11); + for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */ + if (si) cf |= NS_LOSS | NS_LFN; + while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ + + b = i = 0; ni = 8; + for (;;) { + w = lfn[si++]; /* Get an LFN character */ + if (!w) break; /* Break on end of the LFN */ + if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */ + cf |= NS_LOSS | NS_LFN; continue; + } + + if (i >= ni || si == di) { /* Extension or end of SFN */ + if (ni == 11) { /* Long extension */ + cf |= NS_LOSS | NS_LFN; break; + } + if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */ + if (si > di) break; /* No extension */ + si = di; i = 8; ni = 11; /* Enter extension section */ + b <<= 2; continue; + } + + if (w >= 0x80) { /* Non ASCII character */ +#ifdef _EXCVT + w = ff_convert(w, 0); /* Unicode -> OEM code */ + if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */ +#else + w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */ +#endif + cf |= NS_LFN; /* Force create LFN entry */ + } + + if (_DF1S && w >= 0x100) { /* DBC (always false at SBCS cfg) */ + if (i >= ni - 1) { + cf |= NS_LOSS | NS_LFN; i = ni; continue; + } + dp->fn[i++] = (BYTE)(w >> 8); + } else { /* SBC */ + if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */ + w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ + } else { + if (IsUpper(w)) { /* ASCII large capital */ + b |= 2; + } else { + if (IsLower(w)) { /* ASCII small capital */ + b |= 1; w -= 0x20; + } + } + } + } + dp->fn[i++] = (BYTE)w; + } + + if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with deleted mark, replace it with RDDEM */ + + if (ni == 8) b <<= 2; + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ + cf |= NS_LFN; + if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ + if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ + if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ + } + + dp->fn[NSFLAG] = cf; /* SFN is created */ + + return FR_OK; + + +#else /* Non-LFN configuration */ + BYTE b, c, d, *sfn; + UINT ni, si, i; + const char *p; + + /* Create file name in directory form */ + for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ + sfn = dp->fn; + mem_set(sfn, ' ', 11); + si = i = b = 0; ni = 8; +#if _FS_RPATH + if (p[si] == '.') { /* Is this a dot entry? */ + for (;;) { + c = (BYTE)p[si++]; + if (c != '.' || si >= 3) break; + sfn[i++] = c; + } + if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; + *path = &p[si]; /* Return pointer to the next segment */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */ + return FR_OK; + } +#endif + for (;;) { + c = (BYTE)p[si++]; + if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */ + if (c == '.' || i >= ni) { + if (ni != 8 || c != '.') return FR_INVALID_NAME; + i = 8; ni = 11; + b <<= 2; continue; + } + if (c >= 0x80) { /* Extended character? */ + b |= 3; /* Eliminate NT flag */ +#ifdef _EXCVT + c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ +#else +#if !_DF1S + return FR_INVALID_NAME; /* Reject extended characters (ASCII cfg) */ +#endif +#endif + } + if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ + d = (BYTE)p[si++]; /* Get 2nd byte */ + if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ + return FR_INVALID_NAME; + sfn[i++] = c; + sfn[i++] = d; + } else { /* SBC */ + if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */ + return FR_INVALID_NAME; + if (IsUpper(c)) { /* ASCII large capital? */ + b |= 2; + } else { + if (IsLower(c)) { /* ASCII small capital? */ + b |= 1; c -= 0x20; + } + } + sfn[i++] = c; + } + } + *path = &p[si]; /* Return pointer to the next segment */ + c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ + + if (!i) return FR_INVALID_NAME; /* Reject nul string */ + if (sfn[0] == DDEM) sfn[0] = RDDEM; /* When first character collides with DDEM, replace it with RDDEM */ + + if (ni == 8) b <<= 2; + if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */ + if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */ + + sfn[NSFLAG] = c; /* Store NT flag, File name is created */ + + return FR_OK; +#endif +} + + + + +/*-----------------------------------------------------------------------*/ +/* Follow a file path */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ + DIR* dp, /* Directory object to return last directory and found object */ + const TCHAR* path /* Full-path string to find a file or directory */ +) +{ + FRESULT res; + BYTE *dir, ns; + + +#if _FS_RPATH + if (*path == '/' || *path == '\\') { /* There is a heading separator */ + path++; dp->sclust = 0; /* Strip it and start from the root directory */ + } else { /* No heading separator */ + dp->sclust = dp->fs->cdir; /* Start from the current directory */ + } +#else + if (*path == '/' || *path == '\\') /* Strip heading separator if exist */ + path++; + dp->sclust = 0; /* Always start from the root directory */ +#endif + + if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ + res = dir_sdi(dp, 0); + dp->dir = 0; + } else { /* Follow path */ + for (;;) { + res = create_name(dp, &path); /* Get a segment name of the path */ + if (res != FR_OK) break; + res = dir_find(dp); /* Find an object with the sagment name */ + ns = dp->fn[NSFLAG]; + if (res != FR_OK) { /* Failed to find the object */ + if (res == FR_NO_FILE) { /* Object is not found */ + if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, */ + dp->sclust = 0; dp->dir = 0; /* it is the root directory and stay there */ + if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ + res = FR_OK; /* Ended at the root directroy. Function completed. */ + } else { /* Could not find the object */ + if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ + } + } + break; + } + if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ + dir = dp->dir; /* Follow the sub-directory */ + if (!(dir[DIR_Attr] & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + res = FR_NO_PATH; break; + } + dp->sclust = ld_clust(dp->fs, dir); + } + } + + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Get logical drive number from path name */ +/*-----------------------------------------------------------------------*/ + +static +int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ + const TCHAR** path /* Pointer to pointer to the path name */ +) +{ + const TCHAR *tp, *tt; + UINT i; + int vol = -1; +#if _STR_VOLUME_ID /* Find string drive id */ + static const char* const str[] = {_VOLUME_STRS}; + const char *sp; + char c; + TCHAR tc; +#endif + + + if (*path) { /* If the pointer is not a null */ + for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */ + if (*tt == ':') { /* If a ':' is exist in the path name */ + tp = *path; + i = *tp++ - '0'; + if (i < 10 && tp == tt) { /* Is there a numeric drive id? */ + if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ + vol = (int)i; + *path = ++tt; + } + } +#if _STR_VOLUME_ID + else { /* No numeric drive number, find string drive id */ + i = 0; tt++; + do { + sp = str[i]; tp = *path; + do { /* Compare a string drive id with path name */ + c = *sp++; tc = *tp++; + if (IsLower(tc)) tc -= 0x20; + } while (c && (TCHAR)c == tc); + } while ((c || tp != tt) && ++i < _VOLUMES); /* Repeat for each id until pattern match */ + if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ + vol = (int)i; + *path = tt; + } + } +#endif + return vol; + } +#if _FS_RPATH && _VOLUMES >= 2 + vol = CurrVol; /* Current drive */ +#else + vol = 0; /* Drive 0 */ +#endif + } + return vol; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Load a sector and check if it is an FAT boot sector */ +/*-----------------------------------------------------------------------*/ + +static +BYTE check_fs ( /* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a boot sector, 3:Disk error */ + FATFS* fs, /* File system object */ + DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ +) +{ + fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ + if (move_window(fs, sect) != FR_OK) /* Load boot record */ + return 3; + + if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ + return 2; + + if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ + return 0; + if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ + return 0; + + return 1; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Find logical drive and check if the volume is mounted */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ + FATFS** rfs, /* Pointer to pointer to the found file system object */ + const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ + BYTE wmode /* !=0: Check write protection for write access */ +) +{ + BYTE fmt, *pt; + int vol; + DSTATUS stat; + DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; + WORD nrsv; + FATFS *fs; + UINT i; + + + /* Get logical drive number from the path name */ + *rfs = 0; + vol = get_ldnumber(path); + if (vol < 0) return FR_INVALID_DRIVE; + + /* Check if the file system object is valid or not */ + fs = FatFs[vol]; /* Get pointer to the file system object */ + if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */ + + ENTER_FF(fs); /* Lock the volume */ + *rfs = fs; /* Return pointer to the file system object */ + + if (fs->fs_type) { /* If the volume has been mounted */ + stat = disk_status(fs->drv); + if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ + if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */ + return FR_WRITE_PROTECTED; + return FR_OK; /* The file system object is valid */ + } + } + + /* The file system object is not valid. */ + /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */ + + fs->fs_type = 0; /* Clear the file system object */ + fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */ + stat = disk_initialize(fs->drv); /* Initialize the physical drive */ + if (stat & STA_NOINIT) /* Check if the initialization succeeded */ + return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ + if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */ + return FR_WRITE_PROTECTED; +#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ + if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK + || SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) return FR_DISK_ERR; +#endif + /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ + bsect = 0; + fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */ + if (fmt == 1 || (!fmt && (LD2PT(vol)))) { /* Not an FAT boot sector or forced partition number */ + for (i = 0; i < 4; i++) { /* Get partition offset */ + pt = fs->win + MBR_Table + i * SZ_PTE; + br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0; + } + i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ + if (i) i--; + do { /* Find an FAT volume */ + bsect = br[i]; + fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */ + } while (!LD2PT(vol) && fmt && ++i < 4); + } + if (fmt == 3) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */ + + /* An FAT volume is found. Following code initializes the file system object */ + + if (LD_WORD(fs->win + BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */ + return FR_NO_FILESYSTEM; + + fasize = LD_WORD(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + if (!fasize) fasize = LD_DWORD(fs->win + BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ + if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */ + return FR_NO_FILESYSTEM; + fasize *= fs->n_fats; /* Number of sectors for FAT area */ + + fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ + if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */ + return FR_NO_FILESYSTEM; + + fs->n_rootdir = LD_WORD(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ + if (fs->n_rootdir % (SS(fs) / SZ_DIRE)) /* (Must be sector aligned) */ + return FR_NO_FILESYSTEM; + + tsect = LD_WORD(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + if (!tsect) tsect = LD_DWORD(fs->win + BPB_TotSec32); + + nrsv = LD_WORD(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (!nrsv) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + + /* Determine the FAT sub type */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIRE); /* RSV + FAT + DIR */ + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = FS_FAT12; + if (nclst >= MIN_FAT16) fmt = FS_FAT16; + if (nclst >= MIN_FAT32) fmt = FS_FAT32; + + /* Boundaries and Limits */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ + if (fmt == FS_FAT32) { + if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + fs->dirbase = LD_DWORD(fs->win + BPB_RootClus); /* Root directory start cluster */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + } else { + if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); + } + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than the size needed) */ + return FR_NO_FILESYSTEM; + +#if !_FS_READONLY + /* Initialize cluster allocation information */ + fs->last_clust = fs->free_clust = 0xFFFFFFFF; + + /* Get fsinfo if available */ + fs->fsi_flag = 0x80; +#if (_FS_NOFSINFO & 3) != 3 + if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo is 1 */ + && LD_WORD(fs->win + BPB_FSInfo) == 1 + && move_window(fs, bsect + 1) == FR_OK) + { + fs->fsi_flag = 0; + if (LD_WORD(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ + && LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252 + && LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272) + { +#if (_FS_NOFSINFO & 1) == 0 + fs->free_clust = LD_DWORD(fs->win + FSI_Free_Count); +#endif +#if (_FS_NOFSINFO & 2) == 0 + fs->last_clust = LD_DWORD(fs->win + FSI_Nxt_Free); +#endif + } + } +#endif +#endif + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* File system mount ID */ +#if _FS_RPATH + fs->cdir = 0; /* Set current directory to root */ +#endif +#if _FS_LOCK /* Clear file lock semaphores */ + clear_lock(fs); +#endif + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Check if the file/directory object is valid or not */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */ + void* obj /* Pointer to the object FIL/DIR to check validity */ +) +{ + FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */ + + + if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id) + return FR_INVALID_OBJECT; + + ENTER_FF(fil->fs); /* Lock file system */ + + if (disk_status(fil->fs->drv) & STA_NOINIT) + return FR_NOT_READY; + + return FR_OK; +} + + + + +/*-------------------------------------------------------------------------- + + Public Functions + +--------------------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------------*/ +/* Mount/Unmount a Logical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mount ( + FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/ + const TCHAR* path, /* Logical drive number to be mounted/unmounted */ + BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */ +) +{ + FATFS *cfs; + int vol; + FRESULT res; + const TCHAR *rp = path; + + + vol = get_ldnumber(&rp); + if (vol < 0) return FR_INVALID_DRIVE; + cfs = FatFs[vol]; /* Pointer to fs object */ + + if (cfs) { +#if _FS_LOCK + clear_lock(cfs); +#endif +#if _FS_REENTRANT /* Discard sync object of the current volume */ + if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; +#endif + cfs->fs_type = 0; /* Clear old fs object */ + } + + if (fs) { + fs->fs_type = 0; /* Clear new fs object */ +#if _FS_REENTRANT /* Create sync object for the new volume */ + if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; +#endif + } + FatFs[vol] = fs; /* Register new fs object */ + + if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */ + + res = find_volume(&fs, &path, 0); /* Force mounted the volume */ + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Open or Create a File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_open ( + FIL* fp, /* Pointer to the blank file object */ + const TCHAR* path, /* Pointer to the file name */ + BYTE mode /* Access mode and file open mode flags */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir; + DEFINE_NAMEBUF; +#if !_FS_READONLY + DWORD dw, cl; +#endif + + + if (!fp) return FR_INVALID_OBJECT; + fp->fs = 0; /* Clear file object */ + + /* Get logical drive number */ +#if !_FS_READONLY + mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; + res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ)); +#else + mode &= FA_READ; + res = find_volume(&dj.fs, &path, 0); +#endif + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + dir = dj.dir; +#if !_FS_READONLY /* R/W configuration */ + if (res == FR_OK) { + if (!dir) /* Default directory itself */ + res = FR_INVALID_NAME; +#if _FS_LOCK + else + res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); +#endif + } + /* Create or Open a file */ + if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { + if (res != FR_OK) { /* No file, create new */ + if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ +#if _FS_LOCK + res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#else + res = dir_register(&dj); +#endif + mode |= FA_CREATE_ALWAYS; /* File is created */ + dir = dj.dir; /* New entry */ + } + else { /* Any object is already existing */ + if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + res = FR_DENIED; + } else { + if (mode & FA_CREATE_NEW) /* Cannot create as new file */ + res = FR_EXIST; + } + } + if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ + dw = GET_FATTIME(); /* Created time */ + ST_DWORD(dir + DIR_CrtTime, dw); + dir[DIR_Attr] = 0; /* Reset attribute */ + ST_DWORD(dir + DIR_FileSize, 0);/* size = 0 */ + cl = ld_clust(dj.fs, dir); /* Get start cluster */ + st_clust(dir, 0); /* cluster = 0 */ + dj.fs->wflag = 1; + if (cl) { /* Remove the cluster chain if exist */ + dw = dj.fs->winsect; + res = remove_chain(dj.fs, cl); + if (res == FR_OK) { + dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ + res = move_window(dj.fs, dw); + } + } + } + } + else { /* Open an existing file */ + if (res == FR_OK) { /* Follow succeeded */ + if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ + res = FR_NO_FILE; + } else { + if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ + res = FR_DENIED; + } + } + } + if (res == FR_OK) { + if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ + mode |= FA__WRITTEN; + fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dir; +#if _FS_LOCK + fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + if (!fp->lockid) res = FR_INT_ERR; +#endif + } + +#else /* R/O configuration */ + if (res == FR_OK) { /* Follow succeeded */ + dir = dj.dir; + if (!dir) { /* Current directory itself */ + res = FR_INVALID_NAME; + } else { + if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ + res = FR_NO_FILE; + } + } +#endif + FREE_BUF(); + + if (res == FR_OK) { + fp->flag = mode; /* File access mode */ + fp->err = 0; /* Clear error flag */ + fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */ + fp->fsize = LD_DWORD(dir + DIR_FileSize); /* File size */ + fp->fptr = 0; /* File pointer */ + fp->dsect = 0; +#if _USE_FASTSEEK + fp->cltbl = 0; /* Normal seek mode */ +#endif + fp->fs = dj.fs; /* Validate file object */ + fp->id = fp->fs->id; + } + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_read ( + FIL* fp, /* Pointer to the file object */ + void* buff, /* Pointer to data buffer */ + UINT btr, /* Number of bytes to read */ + UINT* br /* Pointer to number of bytes read */ +) +{ + FRESULT res; + DWORD clst, sect, remain; + UINT rcnt, cc; + BYTE csect, *rbuff = (BYTE*)buff; + + + *br = 0; /* Clear read byte counter */ + + res = validate(fp); /* Check validity */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + if (!(fp->flag & FA_READ)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + remain = fp->fsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + for ( ; btr; /* Repeat until all data read */ + rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if (!csect) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->sclust; /* Follow from the origin */ + } else { /* Middle or end of the file */ +#if _USE_FASTSEEK + if (fp->cltbl) + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + else +#endif + clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */ + } + if (clst < 2) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect += csect; + cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Read maximum contiguous sectors directly */ + if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - csect; + if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); +#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ +#if _FS_TINY + if (fp->fs->wflag && fp->fs->winsect - sect < cc) + mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs)); +#else + if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) + mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs)); +#endif +#endif + rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + continue; + } +#if !_FS_TINY + if (fp->dsect != sect) { /* Load data sector if not in cache */ +#if !_FS_READONLY + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */ + ABORT(fp->fs, FR_DISK_ERR); + } +#endif + fp->dsect = sect; + } + rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */ + if (rcnt > btr) rcnt = btr; +#if _FS_TINY + if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ +#else + mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ +#endif + } + + LEAVE_FF(fp->fs, FR_OK); +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Write File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_write ( + FIL* fp, /* Pointer to the file object */ + const void *buff, /* Pointer to the data to be written */ + UINT btw, /* Number of bytes to write */ + UINT* bw /* Pointer to number of bytes written */ +) +{ + FRESULT res; + DWORD clst, sect; + UINT wcnt, cc; + const BYTE *wbuff = (const BYTE*)buff; + BYTE csect; + + + *bw = 0; /* Clear write byte counter */ + + res = validate(fp); /* Check validity */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + if (!(fp->flag & FA_WRITE)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + if (fp->fptr + btw < fp->fptr) btw = 0; /* File size cannot reach 4GB */ + + for ( ; btw; /* Repeat until all data written */ + wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if (!csect) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->sclust; /* Follow from the origin */ + if (clst == 0) /* When no cluster is allocated, */ + clst = create_chain(fp->fs, 0); /* Create a new cluster chain */ + } else { /* Middle or end of the file */ +#if _USE_FASTSEEK + if (fp->cltbl) + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + else +#endif + clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */ + } + if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ + if (clst == 1) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + if (fp->sclust == 0) fp->sclust = clst; /* Set start cluster if the first write */ + } +#if _FS_TINY + if (fp->fs->winsect == fp->dsect && sync_window(fp->fs)) /* Write-back sector cache */ + ABORT(fp->fs, FR_DISK_ERR); +#else + if (fp->flag & FA__DIRTY) { /* Write-back sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect += csect; + cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Write maximum contiguous sectors directly */ + if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - csect; + if (disk_write(fp->fs->drv, wbuff, sect, cc) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); +#if _FS_MINIMIZE <= 2 +#if _FS_TINY + if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs)); + fp->fs->wflag = 0; + } +#else + if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs)); + fp->flag &= ~FA__DIRTY; + } +#endif +#endif + wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + continue; + } +#if _FS_TINY + if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */ + if (sync_window(fp->fs)) ABORT(fp->fs, FR_DISK_ERR); + fp->fs->winsect = sect; + } +#else + if (fp->dsect != sect) { /* Fill sector cache with file data */ + if (fp->fptr < fp->fsize && + disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + } +#endif + fp->dsect = sect; + } + wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */ + if (wcnt > btw) wcnt = btw; +#if _FS_TINY + if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ + fp->fs->wflag = 1; +#else + mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ + fp->flag |= FA__DIRTY; +#endif + } + + if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ + fp->flag |= FA__WRITTEN; /* Set file change flag */ + + LEAVE_FF(fp->fs, FR_OK); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Synchronize the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_sync ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + DWORD tm; + BYTE *dir; + + + res = validate(fp); /* Check validity of the object */ + if (res == FR_OK) { + if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ + /* Write-back dirty buffer */ +#if !_FS_TINY + if (fp->flag & FA__DIRTY) { + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + LEAVE_FF(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + /* Update the directory entry */ + res = move_window(fp->fs, fp->dir_sect); + if (res == FR_OK) { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ + ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */ + st_clust(dir, fp->sclust); /* Update start cluster */ + tm = GET_FATTIME(); /* Update updated time */ + ST_DWORD(dir + DIR_WrtTime, tm); + ST_WORD(dir + DIR_LstAccDate, 0); + fp->flag &= ~FA__WRITTEN; + fp->fs->wflag = 1; + res = sync_fs(fp->fs); + } + } + } + + LEAVE_FF(fp->fs, res); +} + +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Close File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_close ( + FIL *fp /* Pointer to the file object to be closed */ +) +{ + FRESULT res; + + +#if !_FS_READONLY + res = f_sync(fp); /* Flush cached data */ + if (res == FR_OK) +#endif + { + res = validate(fp); /* Lock volume */ + if (res == FR_OK) { +#if _FS_REENTRANT + FATFS *fs = fp->fs; +#endif +#if _FS_LOCK + res = dec_lock(fp->lockid); /* Decrement file open counter */ + if (res == FR_OK) +#endif + fp->fs = 0; /* Invalidate file object */ +#if _FS_REENTRANT + unlock_fs(fs, FR_OK); /* Unlock volume */ +#endif + } + } + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Current Directory or Current Drive, Get Current Directory */ +/*-----------------------------------------------------------------------*/ + +#if _FS_RPATH >= 1 +#if _VOLUMES >= 2 +FRESULT f_chdrive ( + const TCHAR* path /* Drive number */ +) +{ + int vol; + + + vol = get_ldnumber(&path); + if (vol < 0) return FR_INVALID_DRIVE; + + CurrVol = (BYTE)vol; + + return FR_OK; +} +#endif + + +FRESULT f_chdir ( + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + DEFINE_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 0); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the path */ + FREE_BUF(); + if (res == FR_OK) { /* Follow completed */ + if (!dj.dir) { + dj.fs->cdir = dj.sclust; /* Start directory itself */ + } else { + if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ + dj.fs->cdir = ld_clust(dj.fs, dj.dir); + else + res = FR_NO_PATH; /* Reached but a file */ + } + } + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + + LEAVE_FF(dj.fs, res); +} + + +#if _FS_RPATH >= 2 +FRESULT f_getcwd ( + TCHAR* buff, /* Pointer to the directory path */ + UINT len /* Size of path */ +) +{ + FRESULT res; + DIR dj; + UINT i, n; + DWORD ccl; + TCHAR *tp; + FILINFO fno; + DEFINE_NAMEBUF; + + + *buff = 0; + /* Get logical drive number */ + res = find_volume(&dj.fs, (const TCHAR**)&buff, 0); /* Get current volume */ + if (res == FR_OK) { + INIT_BUF(dj); + i = len; /* Bottom of buffer (directory stack base) */ + dj.sclust = dj.fs->cdir; /* Start to follow upper directory from current directory */ + while ((ccl = dj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ + res = dir_sdi(&dj, 1); /* Get parent directory */ + if (res != FR_OK) break; + res = dir_read(&dj, 0); + if (res != FR_OK) break; + dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */ + res = dir_sdi(&dj, 0); + if (res != FR_OK) break; + do { /* Find the entry links to the child directory */ + res = dir_read(&dj, 0); + if (res != FR_OK) break; + if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */ + res = dir_next(&dj, 0); + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res != FR_OK) break; +#if _USE_LFN + fno.lfname = buff; + fno.lfsize = i; +#endif + get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ + tp = fno.fname; +#if _USE_LFN + if (*buff) tp = buff; +#endif + for (n = 0; tp[n]; n++) ; + if (i < n + 3) { + res = FR_NOT_ENOUGH_CORE; break; + } + while (n) buff[--i] = tp[--n]; + buff[--i] = '/'; + } + tp = buff; + if (res == FR_OK) { +#if _VOLUMES >= 2 + *tp++ = '0' + CurrVol; /* Put drive number */ + *tp++ = ':'; +#endif + if (i == len) { /* Root-directory */ + *tp++ = '/'; + } else { /* Sub-directroy */ + do /* Add stacked path str */ + *tp++ = buff[i++]; + while (i < len); + } + } + *tp = 0; + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} +#endif /* _FS_RPATH >= 2 */ +#endif /* _FS_RPATH >= 1 */ + + + +#if _FS_MINIMIZE <= 2 +/*-----------------------------------------------------------------------*/ +/* Seek File R/W Pointer */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_lseek ( + FIL* fp, /* Pointer to the file object */ + DWORD ofs /* File pointer from top of file */ +) +{ + FRESULT res; + DWORD clst, bcs, nsect, ifptr; +#if _USE_FASTSEEK + DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; +#endif + + + res = validate(fp); /* Check validity of the object */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + +#if _USE_FASTSEEK + if (fp->cltbl) { /* Fast seek */ + if (ofs == CREATE_LINKMAP) { /* Create CLMT */ + tbl = fp->cltbl; + tlen = *tbl++; ulen = 2; /* Given table size and required table size */ + cl = fp->sclust; /* Top of the chain */ + if (cl) { + do { + /* Get a fragment */ + tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ + do { + pcl = cl; ncl++; + cl = get_fat(fp->fs, cl); + if (cl <= 1) ABORT(fp->fs, FR_INT_ERR); + if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + } while (cl == pcl + 1); + if (ulen <= tlen) { /* Store the length and top of the fragment */ + *tbl++ = ncl; *tbl++ = tcl; + } + } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */ + } + *fp->cltbl = ulen; /* Number of items used */ + if (ulen <= tlen) + *tbl = 0; /* Terminate table */ + else + res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ + + } else { /* Fast seek */ + if (ofs > fp->fsize) /* Clip offset at the file size */ + ofs = fp->fsize; + fp->fptr = ofs; /* Set file pointer */ + if (ofs) { + fp->clust = clmt_clust(fp, ofs - 1); + dsc = clust2sect(fp->fs, fp->clust); + if (!dsc) ABORT(fp->fs, FR_INT_ERR); + dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1); + if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */ +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */ + ABORT(fp->fs, FR_DISK_ERR); +#endif + fp->dsect = dsc; + } + } + } + } else +#endif + + /* Normal Seek */ + { + if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ +#if !_FS_READONLY + && !(fp->flag & FA_WRITE) +#endif + ) ofs = fp->fsize; + + ifptr = fp->fptr; + fp->fptr = nsect = 0; + if (ofs) { + bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */ + if (ifptr > 0 && + (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ + fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ + ofs -= fp->fptr; + clst = fp->clust; + } else { /* When seek to back cluster, */ + clst = fp->sclust; /* start from the first cluster */ +#if !_FS_READONLY + if (clst == 0) { /* If no cluster chain, create a new chain */ + clst = create_chain(fp->fs, 0); + if (clst == 1) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->sclust = clst; + } +#endif + fp->clust = clst; + } + if (clst != 0) { + while (ofs > bcs) { /* Cluster following loop */ +#if !_FS_READONLY + if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ + clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */ + if (clst == 0) { /* When disk gets full, clip file size */ + ofs = bcs; break; + } + } else +#endif + clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */ + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR); + fp->clust = clst; + fp->fptr += bcs; + ofs -= bcs; + } + fp->fptr += ofs; + if (ofs % SS(fp->fs)) { + nsect = clust2sect(fp->fs, clst); /* Current sector */ + if (!nsect) ABORT(fp->fs, FR_INT_ERR); + nsect += ofs / SS(fp->fs); + } + } + } + if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */ +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */ + ABORT(fp->fs, FR_DISK_ERR); +#endif + fp->dsect = nsect; + } +#if !_FS_READONLY + if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */ + fp->fsize = fp->fptr; + fp->flag |= FA__WRITTEN; + } +#endif + } + + LEAVE_FF(fp->fs, res); +} + + + +#if _FS_MINIMIZE <= 1 +/*-----------------------------------------------------------------------*/ +/* Create a Directory Object */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_opendir ( + DIR* dp, /* Pointer to directory object to create */ + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + FATFS* fs; + DEFINE_NAMEBUF; + + + if (!dp) return FR_INVALID_OBJECT; + + /* Get logical drive number */ + res = find_volume(&fs, &path, 0); + if (res == FR_OK) { + dp->fs = fs; + INIT_BUF(*dp); + res = follow_path(dp, path); /* Follow the path to the directory */ + FREE_BUF(); + if (res == FR_OK) { /* Follow completed */ + if (dp->dir) { /* It is not the origin directory itself */ + if (dp->dir[DIR_Attr] & AM_DIR) /* The object is a sub directory */ + dp->sclust = ld_clust(fs, dp->dir); + else /* The object is a file */ + res = FR_NO_PATH; + } + if (res == FR_OK) { + dp->id = fs->id; + res = dir_sdi(dp, 0); /* Rewind directory */ +#if _FS_LOCK + if (res == FR_OK) { + if (dp->sclust) { + dp->lockid = inc_lock(dp, 0); /* Lock the sub directory */ + if (!dp->lockid) + res = FR_TOO_MANY_OPEN_FILES; + } else { + dp->lockid = 0; /* Root directory need not to be locked */ + } + } +#endif + } + } + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + if (res != FR_OK) dp->fs = 0; /* Invalidate the directory object if function faild */ + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Close Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_closedir ( + DIR *dp /* Pointer to the directory object to be closed */ +) +{ + FRESULT res; + + + res = validate(dp); + if (res == FR_OK) { +#if _FS_REENTRANT + FATFS *fs = dp->fs; +#endif +#if _FS_LOCK + if (dp->lockid) /* Decrement sub-directory open counter */ + res = dec_lock(dp->lockid); + if (res == FR_OK) +#endif + dp->fs = 0; /* Invalidate directory object */ +#if _FS_REENTRANT + unlock_fs(fs, FR_OK); /* Unlock volume */ +#endif + } + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read Directory Entries in Sequence */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_readdir ( + DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to file information to return */ +) +{ + FRESULT res; + DEFINE_NAMEBUF; + + + res = validate(dp); /* Check validity of the object */ + if (res == FR_OK) { + if (!fno) { + res = dir_sdi(dp, 0); /* Rewind the directory object */ + } else { + INIT_BUF(*dp); + res = dir_read(dp, 0); /* Read an item */ + if (res == FR_NO_FILE) { /* Reached end of directory */ + dp->sect = 0; + res = FR_OK; + } + if (res == FR_OK) { /* A valid entry is found */ + get_fileinfo(dp, fno); /* Get the object information */ + res = dir_next(dp, 0); /* Increment index for next */ + if (res == FR_NO_FILE) { + dp->sect = 0; + res = FR_OK; + } + } + FREE_BUF(); + } + } + + LEAVE_FF(dp->fs, res); +} + + + +#if _USE_FIND +/*-----------------------------------------------------------------------*/ +/* Find next file */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_findnext ( + DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to the file information structure */ +) +{ + FRESULT res; + + + for (;;) { + res = f_readdir(dp, fno); /* Get a directory item */ + if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ +#if _USE_LFN + if (fno->lfname && pattern_matching(dp->pat, fno->lfname, 0, 0)) break; /* Test for LFN if exist */ +#endif + if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for SFN */ + } + return res; + +} + + + +/*-----------------------------------------------------------------------*/ +/* Find first file */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_findfirst ( + DIR* dp, /* Pointer to the blank directory object */ + FILINFO* fno, /* Pointer to the file information structure */ + const TCHAR* path, /* Pointer to the directory to open */ + const TCHAR* pattern /* Pointer to the matching pattern */ +) +{ + FRESULT res; + + + dp->pat = pattern; /* Save pointer to pattern string */ + res = f_opendir(dp, path); /* Open the target directory */ + if (res == FR_OK) + res = f_findnext(dp, fno); /* Find the first item */ + return res; +} + +#endif /* _USE_FIND */ + + + +#if _FS_MINIMIZE == 0 +/*-----------------------------------------------------------------------*/ +/* Get File Status */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_stat ( + const TCHAR* path, /* Pointer to the file path */ + FILINFO* fno /* Pointer to file information to return */ +) +{ + FRESULT res; + DIR dj; + DEFINE_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 0); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.dir) { /* Found an object */ + if (fno) get_fileinfo(&dj, fno); + } else { /* It is root directory */ + res = FR_INVALID_NAME; + } + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Get Number of Free Clusters */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getfree ( + const TCHAR* path, /* Path name of the logical drive number */ + DWORD* nclst, /* Pointer to a variable to return number of free clusters */ + FATFS** fatfs /* Pointer to return pointer to corresponding file system object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD n, clst, sect, stat; + UINT i; + BYTE fat, *p; + + + /* Get logical drive number */ + res = find_volume(fatfs, &path, 0); + fs = *fatfs; + if (res == FR_OK) { + /* If free_clust is valid, return it without full cluster scan */ + if (fs->free_clust <= fs->n_fatent - 2) { + *nclst = fs->free_clust; + } else { + /* Get number of free clusters */ + fat = fs->fs_type; + n = 0; + if (fat == FS_FAT12) { + clst = 2; + do { + stat = get_fat(fs, clst); + if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (stat == 1) { res = FR_INT_ERR; break; } + if (stat == 0) n++; + } while (++clst < fs->n_fatent); + } else { + clst = fs->n_fatent; + sect = fs->fatbase; + i = 0; p = 0; + do { + if (!i) { + res = move_window(fs, sect++); + if (res != FR_OK) break; + p = fs->win; + i = SS(fs); + } + if (fat == FS_FAT16) { + if (LD_WORD(p) == 0) n++; + p += 2; i -= 2; + } else { + if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++; + p += 4; i -= 4; + } + } while (--clst); + } + fs->free_clust = n; + fs->fsi_flag |= 1; + *nclst = n; + } + } + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Truncate File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_truncate ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + DWORD ncl; + + + res = validate(fp); /* Check validity of the object */ + if (res == FR_OK) { + if (fp->err) { /* Check error */ + res = (FRESULT)fp->err; + } else { + if (!(fp->flag & FA_WRITE)) /* Check access mode */ + res = FR_DENIED; + } + } + if (res == FR_OK) { + if (fp->fsize > fp->fptr) { + fp->fsize = fp->fptr; /* Set file size to current R/W point */ + fp->flag |= FA__WRITTEN; + if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ + res = remove_chain(fp->fs, fp->sclust); + fp->sclust = 0; + } else { /* When truncate a part of the file, remove remaining clusters */ + ncl = get_fat(fp->fs, fp->clust); + res = FR_OK; + if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (ncl == 1) res = FR_INT_ERR; + if (res == FR_OK && ncl < fp->fs->n_fatent) { + res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF); + if (res == FR_OK) res = remove_chain(fp->fs, ncl); + } + } +#if !_FS_TINY + if (res == FR_OK && (fp->flag & FA__DIRTY)) { + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + res = FR_DISK_ERR; + else + fp->flag &= ~FA__DIRTY; + } +#endif + } + if (res != FR_OK) fp->err = (FRESULT)res; + } + + LEAVE_FF(fp->fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Delete a File or Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_unlink ( + const TCHAR* path /* Pointer to the file or directory path */ +) +{ + FRESULT res; + DIR dj, sdj; + BYTE *dir; + DWORD dclst = 0; + DEFINE_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) + res = FR_INVALID_NAME; /* Cannot remove dot entry */ +#if _FS_LOCK + if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open object */ +#endif + if (res == FR_OK) { /* The object is accessible */ + dir = dj.dir; + if (!dir) { + res = FR_INVALID_NAME; /* Cannot remove the origin directory */ + } else { + if (dir[DIR_Attr] & AM_RDO) + res = FR_DENIED; /* Cannot remove R/O object */ + } + if (res == FR_OK) { + dclst = ld_clust(dj.fs, dir); + if (dclst && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-directory ? */ +#if _FS_RPATH + if (dclst == dj.fs->cdir) { /* Is it the current directory? */ + res = FR_DENIED; + } else +#endif + { + mem_cpy(&sdj, &dj, sizeof (DIR)); /* Open the sub-directory */ + sdj.sclust = dclst; + res = dir_sdi(&sdj, 2); + if (res == FR_OK) { + res = dir_read(&sdj, 0); /* Read an item (excluding dot entries) */ + if (res == FR_OK) res = FR_DENIED; /* Not empty? (cannot remove) */ + if (res == FR_NO_FILE) res = FR_OK; /* Empty? (can remove) */ + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK && dclst) /* Remove the cluster chain if exist */ + res = remove_chain(dj.fs, dclst); + if (res == FR_OK) res = sync_fs(dj.fs); + } + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create a Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mkdir ( + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir, n; + DWORD dsc, dcl, pcl, tm = GET_FATTIME(); + DEFINE_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ + if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_NO_FILE) { /* Can create a new directory */ + dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */ + res = FR_OK; + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ + if (dcl == 1) res = FR_INT_ERR; + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) /* Flush FAT */ + res = sync_window(dj.fs); + if (res == FR_OK) { /* Initialize the new directory table */ + dsc = clust2sect(dj.fs, dcl); + dir = dj.fs->win; + mem_set(dir, 0, SS(dj.fs)); + mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ + dir[DIR_Name] = '.'; + dir[DIR_Attr] = AM_DIR; + ST_DWORD(dir + DIR_WrtTime, tm); + st_clust(dir, dcl); + mem_cpy(dir + SZ_DIRE, dir, SZ_DIRE); /* Create ".." entry */ + dir[SZ_DIRE + 1] = '.'; pcl = dj.sclust; + if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase) + pcl = 0; + st_clust(dir + SZ_DIRE, pcl); + for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */ + dj.fs->winsect = dsc++; + dj.fs->wflag = 1; + res = sync_window(dj.fs); + if (res != FR_OK) break; + mem_set(dir, 0, SS(dj.fs)); + } + } + if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ + if (res != FR_OK) { + remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */ + } else { + dir = dj.dir; + dir[DIR_Attr] = AM_DIR; /* Attribute */ + ST_DWORD(dir + DIR_WrtTime, tm); /* Created time */ + st_clust(dir, dcl); /* Table start cluster */ + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Attribute */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_chmod ( + const TCHAR* path, /* Pointer to the file path */ + BYTE attr, /* Attribute bits */ + BYTE mask /* Attribute mask to change */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir; + DEFINE_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + FREE_BUF(); + if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_OK) { + dir = dj.dir; + if (!dir) { /* Is it a root directory? */ + res = FR_INVALID_NAME; + } else { /* File or sub directory */ + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ + dir[DIR_Attr] = (attr & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Rename File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_rename ( + const TCHAR* path_old, /* Pointer to the object to be renamed */ + const TCHAR* path_new /* Pointer to the new name */ +) +{ + FRESULT res; + DIR djo, djn; + BYTE buf[21], *dir; + DWORD dw; + DEFINE_NAMEBUF; + + + /* Get logical drive number of the source object */ + res = find_volume(&djo.fs, &path_old, 1); + if (res == FR_OK) { + djn.fs = djo.fs; + INIT_BUF(djo); + res = follow_path(&djo, path_old); /* Check old object */ + if (_FS_RPATH && res == FR_OK && (djo.fn[NSFLAG] & NS_DOT)) + res = FR_INVALID_NAME; +#if _FS_LOCK + if (res == FR_OK) res = chk_lock(&djo, 2); +#endif + if (res == FR_OK) { /* Old object is found */ + if (!djo.dir) { /* Is root dir? */ + res = FR_NO_FILE; + } else { + mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about object except name */ + mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ + if (get_ldnumber(&path_new) >= 0) /* Snip drive number off and ignore it */ + res = follow_path(&djn, path_new); /* and make sure if new object name is not conflicting */ + else + res = FR_INVALID_DRIVE; + if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */ + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { +/* Start of critical section where any interruption can cause a cross-link */ + dir = djn.dir; /* Copy information about object except name */ + mem_cpy(dir + 13, buf + 2, 19); + dir[DIR_Attr] = buf[0] | AM_ARC; + djo.fs->wflag = 1; + if ((dir[DIR_Attr] & AM_DIR) && djo.sclust != djn.sclust) { /* Update .. entry in the sub-directory if needed */ + dw = clust2sect(djo.fs, ld_clust(djo.fs, dir)); + if (!dw) { + res = FR_INT_ERR; + } else { + res = move_window(djo.fs, dw); + dir = djo.fs->win + SZ_DIRE * 1; /* Ptr to .. entry */ + if (res == FR_OK && dir[1] == '.') { + st_clust(dir, djn.sclust); + djo.fs->wflag = 1; + } + } + } + if (res == FR_OK) { + res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) + res = sync_fs(djo.fs); + } +/* End of critical section */ + } + } + } + } + FREE_BUF(); + } + + LEAVE_FF(djo.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Timestamp */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_utime ( + const TCHAR* path, /* Pointer to the file/directory name */ + const FILINFO* fno /* Pointer to the time stamp to be set */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir; + DEFINE_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + FREE_BUF(); + if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_OK) { + dir = dj.dir; + if (!dir) { /* Root directory */ + res = FR_INVALID_NAME; + } else { /* File or sub-directory */ + ST_WORD(dir + DIR_WrtTime, fno->ftime); + ST_WORD(dir + DIR_WrtDate, fno->fdate); + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + } + + LEAVE_FF(dj.fs, res); +} + +#endif /* !_FS_READONLY */ +#endif /* _FS_MINIMIZE == 0 */ +#endif /* _FS_MINIMIZE <= 1 */ +#endif /* _FS_MINIMIZE <= 2 */ + + + + +#if _USE_LABEL +/*-----------------------------------------------------------------------*/ +/* Get volume label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getlabel ( + const TCHAR* path, /* Path name of the logical drive number */ + TCHAR* label, /* Pointer to a buffer to return the volume label */ + DWORD* vsn /* Pointer to a variable to return the volume serial number */ +) +{ + FRESULT res; + DIR dj; + UINT i, j; +#if _USE_LFN && _LFN_UNICODE + WCHAR w; +#endif + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 0); + + /* Get volume label */ + if (res == FR_OK && label) { + dj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ + if (res == FR_OK) { /* A volume label is exist */ +#if _USE_LFN && _LFN_UNICODE + i = j = 0; + do { + w = (i < 11) ? dj.dir[i++] : ' '; + if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i])) + w = w << 8 | dj.dir[i++]; + label[j++] = ff_convert(w, 1); /* OEM -> Unicode */ + } while (j < 11); +#else + mem_cpy(label, dj.dir, 11); +#endif + j = 11; + do { + label[j] = 0; + if (!j) break; + } while (label[--j] == ' '); + } + if (res == FR_NO_FILE) { /* No label, return nul string */ + label[0] = 0; + res = FR_OK; + } + } + } + + /* Get volume serial number */ + if (res == FR_OK && vsn) { + res = move_window(dj.fs, dj.fs->volbase); + if (res == FR_OK) { + i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID; + *vsn = LD_DWORD(&dj.fs->win[i]); + } + } + + LEAVE_FF(dj.fs, res); +} + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Set volume label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_setlabel ( + const TCHAR* label /* Pointer to the volume label to set */ +) +{ + FRESULT res; + DIR dj; + BYTE vn[11]; + UINT i, j, sl; + WCHAR w; + DWORD tm; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &label, 1); + if (res) LEAVE_FF(dj.fs, res); + + /* Create a volume label in directory form */ + vn[0] = 0; + for (sl = 0; label[sl]; sl++) ; /* Get name length */ + for ( ; sl && label[sl - 1] == ' '; sl--) ; /* Remove trailing spaces */ + if (sl) { /* Create volume label in directory form */ + i = j = 0; + do { +#if _USE_LFN && _LFN_UNICODE + w = ff_convert(ff_wtoupper(label[i++]), 0); +#else + w = (BYTE)label[i++]; + if (IsDBCS1(w)) + w = (j < 10 && i < sl && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; +#if _USE_LFN + w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); +#else + if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ +#ifdef _EXCVT + if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ +#else + if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ +#endif +#endif +#endif + if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid characters for volume label */ + LEAVE_FF(dj.fs, FR_INVALID_NAME); + if (w >= 0x100) vn[j++] = (BYTE)(w >> 8); + vn[j++] = (BYTE)w; + } while (i < sl); + while (j < 11) vn[j++] = ' '; /* Fill remaining name field */ + if (vn[0] == DDEM) LEAVE_FF(dj.fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + } + + /* Set volume label */ + dj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ + if (res == FR_OK) { /* A volume label is found */ + if (vn[0]) { + mem_cpy(dj.dir, vn, 11); /* Change the volume label name */ + tm = GET_FATTIME(); + ST_DWORD(dj.dir + DIR_WrtTime, tm); + } else { + dj.dir[0] = DDEM; /* Remove the volume label */ + } + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } else { /* No volume label is found or error */ + if (res == FR_NO_FILE) { + res = FR_OK; + if (vn[0]) { /* Create volume label as new */ + res = dir_alloc(&dj, 1); /* Allocate an entry for volume label */ + if (res == FR_OK) { + mem_set(dj.dir, 0, SZ_DIRE); /* Set volume label */ + mem_cpy(dj.dir, vn, 11); + dj.dir[DIR_Attr] = AM_VOL; + tm = GET_FATTIME(); + ST_DWORD(dj.dir + DIR_WrtTime, tm); + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + } + } + } + + LEAVE_FF(dj.fs, res); +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_LABEL */ + + + +/*-----------------------------------------------------------------------*/ +/* Forward data to the stream directly (available on only tiny cfg) */ +/*-----------------------------------------------------------------------*/ +#if _USE_FORWARD && _FS_TINY + +FRESULT f_forward ( + FIL* fp, /* Pointer to the file object */ + UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ + UINT btf, /* Number of bytes to forward */ + UINT* bf /* Pointer to number of bytes forwarded */ +) +{ + FRESULT res; + DWORD remain, clst, sect; + UINT rcnt; + BYTE csect; + + + *bf = 0; /* Clear transfer byte counter */ + + res = validate(fp); /* Check validity of the object */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + if (!(fp->flag & FA_READ)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + + remain = fp->fsize - fp->fptr; + if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ + + for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */ + fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + if (!csect) { /* On the cluster boundary? */ + clst = (fp->fptr == 0) ? /* On the top of the file? */ + fp->sclust : get_fat(fp->fs, fp->clust); + if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + } + sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */ + if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect += csect; + if (move_window(fp->fs, sect) != FR_OK) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + fp->dsect = sect; + rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */ + if (rcnt > btf) rcnt = btf; + rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt); + if (!rcnt) ABORT(fp->fs, FR_INT_ERR); + } + + LEAVE_FF(fp->fs, FR_OK); +} +#endif /* _USE_FORWARD */ + + + +#if _USE_MKFS && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Create file system on the logical drive */ +/*-----------------------------------------------------------------------*/ +#define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */ +#define N_FATS 1 /* Number of FATs (1 or 2) */ + + +FRESULT f_mkfs ( + const TCHAR* path, /* Logical drive number */ + BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */ + UINT au /* Size of allocation unit in unit of byte or sector */ +) +{ + static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0}; + static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512}; + int vol; + BYTE fmt, md, sys, *tbl, pdrv, part; + DWORD n_clst, vs, n, wsect; + UINT i; + DWORD b_vol, b_fat, b_dir, b_data; /* LBA */ + DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */ + FATFS *fs; + DSTATUS stat; +#if _USE_TRIM + DWORD eb[2]; +#endif + + + /* Check mounted drive and clear work area */ + if (sfd > 1) return FR_INVALID_PARAMETER; + vol = get_ldnumber(&path); + if (vol < 0) return FR_INVALID_DRIVE; + fs = FatFs[vol]; + if (!fs) return FR_NOT_ENABLED; + fs->fs_type = 0; + pdrv = LD2PD(vol); /* Physical drive */ + part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/ + + /* Get disk statics */ + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; +#if _MAX_SS != _MIN_SS /* Get disk sector size */ + if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS) + return FR_DISK_ERR; +#endif + if (_MULTI_PARTITION && part) { + /* Get partition information from partition table in the MBR */ + if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR; + if (LD_WORD(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; + tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; + if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */ + b_vol = LD_DWORD(tbl + 8); /* Volume start sector */ + n_vol = LD_DWORD(tbl + 12); /* Volume size */ + } else { + /* Create a partition in this function */ + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) + return FR_DISK_ERR; + b_vol = (sfd) ? 0 : 63; /* Volume start sector */ + n_vol -= b_vol; /* Volume size */ + } + + if (au & (au - 1)) au = 0; + if (!au) { /* AU auto selection */ + vs = n_vol / (2000 / (SS(fs) / 512)); + for (i = 0; vs < vst[i]; i++) ; + au = cst[i]; + } + if (au >= _MIN_SS) au /= SS(fs); /* Number of sectors per cluster */ + if (!au) au = 1; + if (au > 128) au = 128; + + /* Pre-compute number of clusters and FAT sub-type */ + n_clst = n_vol / au; + fmt = FS_FAT12; + if (n_clst >= MIN_FAT16) fmt = FS_FAT16; + if (n_clst >= MIN_FAT32) fmt = FS_FAT32; + + /* Determine offset and size of FAT structure */ + if (fmt == FS_FAT32) { + n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); + n_rsv = 32; + n_dir = 0; + } else { + n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; + n_fat = (n_fat + SS(fs) - 1) / SS(fs); + n_rsv = 1; + n_dir = (DWORD)N_ROOTDIR * SZ_DIRE / SS(fs); + } + b_fat = b_vol + n_rsv; /* FAT area start sector */ + b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ + b_data = b_dir + n_dir; /* Data area start sector */ + if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ + + /* Align data start sector to erase block boundary (for flash memory media) */ + if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1; + n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */ + n = (n - b_data) / N_FATS; + if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */ + n_rsv += n; + b_fat += n; + } else { /* FAT12/16: Expand FAT size */ + n_fat += n; + } + + /* Determine number of clusters and final check of validity of the FAT sub-type */ + n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; + if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16) + || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) + return FR_MKFS_ABORTED; + + /* Determine system ID in the partition table */ + if (fmt == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else { + if (fmt == FS_FAT12 && n_vol < 0x10000) { + sys = 0x01; /* FAT12(<65536) */ + } else { + sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */ + } + } + + if (_MULTI_PARTITION && part) { + /* Update system ID in the partition table */ + tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; + tbl[4] = sys; + if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to teh MBR */ + return FR_DISK_ERR; + md = 0xF8; + } else { + if (sfd) { /* No partition table (SFD) */ + md = 0xF0; + } else { /* Create partition table (FDISK) */ + mem_set(fs->win, 0, SS(fs)); + tbl = fs->win + MBR_Table; /* Create partition table for single partition in the drive */ + tbl[1] = 1; /* Partition start head */ + tbl[2] = 1; /* Partition start sector */ + tbl[3] = 0; /* Partition start cylinder */ + tbl[4] = sys; /* System type */ + tbl[5] = 254; /* Partition end head */ + n = (b_vol + n_vol) / 63 / 255; + tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */ + tbl[7] = (BYTE)n; /* End cylinder */ + ST_DWORD(tbl + 8, 63); /* Partition start in LBA */ + ST_DWORD(tbl + 12, n_vol); /* Partition size in LBA */ + ST_WORD(fs->win + BS_55AA, 0xAA55); /* MBR signature */ + if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR */ + return FR_DISK_ERR; + md = 0xF8; + } + } + + /* Create BPB in the VBR */ + tbl = fs->win; /* Clear sector */ + mem_set(tbl, 0, SS(fs)); + mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */ + i = SS(fs); /* Sector size */ + ST_WORD(tbl + BPB_BytsPerSec, i); + tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ + ST_WORD(tbl + BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ + tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ + i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */ + ST_WORD(tbl + BPB_RootEntCnt, i); + if (n_vol < 0x10000) { /* Number of total sectors */ + ST_WORD(tbl + BPB_TotSec16, n_vol); + } else { + ST_DWORD(tbl + BPB_TotSec32, n_vol); + } + tbl[BPB_Media] = md; /* Media descriptor */ + ST_WORD(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */ + ST_WORD(tbl + BPB_NumHeads, 255); /* Number of heads */ + ST_DWORD(tbl + BPB_HiddSec, b_vol); /* Hidden sectors */ + n = GET_FATTIME(); /* Use current time as VSN */ + if (fmt == FS_FAT32) { + ST_DWORD(tbl + BS_VolID32, n); /* VSN */ + ST_DWORD(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */ + ST_DWORD(tbl + BPB_RootClus, 2); /* Root directory start cluster (2) */ + ST_WORD(tbl + BPB_FSInfo, 1); /* FSINFO record offset (VBR + 1) */ + ST_WORD(tbl + BPB_BkBootSec, 6); /* Backup boot record offset (VBR + 6) */ + tbl[BS_DrvNum32] = 0x80; /* Drive number */ + tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ + mem_cpy(tbl + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + } else { + ST_DWORD(tbl + BS_VolID, n); /* VSN */ + ST_WORD(tbl + BPB_FATSz16, n_fat); /* Number of sectors per FAT */ + tbl[BS_DrvNum] = 0x80; /* Drive number */ + tbl[BS_BootSig] = 0x29; /* Extended boot signature */ + mem_cpy(tbl + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + } + ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ + if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */ + return FR_DISK_ERR; + if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR + 6) */ + disk_write(pdrv, tbl, b_vol + 6, 1); + + /* Initialize FAT area */ + wsect = b_fat; + for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */ + mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ + n = md; /* Media descriptor byte */ + if (fmt != FS_FAT32) { + n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; + ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */ + } else { + n |= 0xFFFFFF00; + ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */ + ST_DWORD(tbl + 4, 0xFFFFFFFF); + ST_DWORD(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */ + } + if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) + return FR_DISK_ERR; + mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ + for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */ + if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) + return FR_DISK_ERR; + } + } + + /* Initialize root directory */ + i = (fmt == FS_FAT32) ? au : (UINT)n_dir; + do { + if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) + return FR_DISK_ERR; + } while (--i); + +#if _USE_TRIM /* Erase data area if needed */ + { + eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1; + disk_ioctl(pdrv, CTRL_TRIM, eb); + } +#endif + + /* Create FSINFO if needed */ + if (fmt == FS_FAT32) { + ST_DWORD(tbl + FSI_LeadSig, 0x41615252); + ST_DWORD(tbl + FSI_StrucSig, 0x61417272); + ST_DWORD(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + ST_DWORD(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + ST_WORD(tbl + BS_55AA, 0xAA55); + disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */ + disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */ + } + + return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; +} + + + +#if _MULTI_PARTITION +/*-----------------------------------------------------------------------*/ +/* Create partition table on the physical drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_fdisk ( + BYTE pdrv, /* Physical drive number */ + const DWORD szt[], /* Pointer to the size table for each partitions */ + void* work /* Pointer to the working buffer */ +) +{ + UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; + BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; + DSTATUS stat; + DWORD sz_disk, sz_part, s_part; + + + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; + + /* Determine CHS in the table regardless of the drive geometry */ + for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; + if (n == 256) n--; + e_hd = n - 1; + sz_cyl = 63 * n; + tot_cyl = sz_disk / sz_cyl; + + /* Create partition table */ + mem_set(buf, 0, _MAX_SS); + p = buf + MBR_Table; b_cyl = 0; + for (i = 0; i < 4; i++, p += SZ_PTE) { + p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; + if (!p_cyl) continue; + s_part = (DWORD)sz_cyl * b_cyl; + sz_part = (DWORD)sz_cyl * p_cyl; + if (i == 0) { /* Exclude first track of cylinder 0 */ + s_hd = 1; + s_part += 63; sz_part -= 63; + } else { + s_hd = 0; + } + e_cyl = b_cyl + p_cyl - 1; + if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; + + /* Set partition table */ + p[1] = s_hd; /* Start head */ + p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ + p[3] = (BYTE)b_cyl; /* Start cylinder */ + p[4] = 0x06; /* System type (temporary setting) */ + p[5] = e_hd; /* End head */ + p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ + p[7] = (BYTE)e_cyl; /* End cylinder */ + ST_DWORD(p + 8, s_part); /* Start sector in LBA */ + ST_DWORD(p + 12, sz_part); /* Partition size */ + + /* Next partition */ + b_cyl += p_cyl; + } + ST_WORD(p, 0xAA55); + + /* Write it to the MBR */ + return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK; +} + + +#endif /* _MULTI_PARTITION */ +#endif /* _USE_MKFS && !_FS_READONLY */ + + + + +#if _USE_STRFUNC +/*-----------------------------------------------------------------------*/ +/* Get a string from the file */ +/*-----------------------------------------------------------------------*/ + +TCHAR* f_gets ( + TCHAR* buff, /* Pointer to the string buffer to read */ + int len, /* Size of string buffer (characters) */ + FIL* fp /* Pointer to the file object */ +) +{ + int n = 0; + TCHAR c, *p = buff; + BYTE s[2]; + UINT rc; + + + while (n < len - 1) { /* Read characters until buffer gets filled */ +#if _USE_LFN && _LFN_UNICODE +#if _STRF_ENCODE == 3 /* Read a character in UTF-8 */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = s[0]; + if (c >= 0x80) { + if (c < 0xC0) continue; /* Skip stray trailer */ + if (c < 0xE0) { /* Two-byte sequence */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = (c & 0x1F) << 6 | (s[0] & 0x3F); + if (c < 0x80) c = '?'; + } else { + if (c < 0xF0) { /* Three-byte sequence */ + f_read(fp, s, 2, &rc); + if (rc != 2) break; + c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); + if (c < 0x800) c = '?'; + } else { /* Reject four-byte sequence */ + c = '?'; + } + } + } +#elif _STRF_ENCODE == 2 /* Read a character in UTF-16BE */ + f_read(fp, s, 2, &rc); + if (rc != 2) break; + c = s[1] + (s[0] << 8); +#elif _STRF_ENCODE == 1 /* Read a character in UTF-16LE */ + f_read(fp, s, 2, &rc); + if (rc != 2) break; + c = s[0] + (s[1] << 8); +#else /* Read a character in ANSI/OEM */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = s[0]; + if (IsDBCS1(c)) { + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = (c << 8) + s[0]; + } + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) c = '?'; +#endif +#else /* Read a character without conversion */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = s[0]; +#endif + if (_USE_STRFUNC == 2 && c == '\r') continue; /* Strip '\r' */ + *p++ = c; + n++; + if (c == '\n') break; /* Break on EOL */ + } + *p = 0; + return n ? buff : 0; /* When no data read (eof or error), return with error. */ +} + + + + +#if !_FS_READONLY +#include +/*-----------------------------------------------------------------------*/ +/* Put a character to the file */ +/*-----------------------------------------------------------------------*/ + +typedef struct { + FIL* fp; + int idx, nchr; + BYTE buf[64]; +} putbuff; + + +static +void putc_bfd ( + putbuff* pb, + TCHAR c +) +{ + UINT bw; + int i; + + + if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */ + putc_bfd(pb, '\r'); + + i = pb->idx; /* Buffer write index (-1:error) */ + if (i < 0) return; + +#if _USE_LFN && _LFN_UNICODE +#if _STRF_ENCODE == 3 /* Write a character in UTF-8 */ + if (c < 0x80) { /* 7-bit */ + pb->buf[i++] = (BYTE)c; + } else { + if (c < 0x800) { /* 11-bit */ + pb->buf[i++] = (BYTE)(0xC0 | c >> 6); + } else { /* 16-bit */ + pb->buf[i++] = (BYTE)(0xE0 | c >> 12); + pb->buf[i++] = (BYTE)(0x80 | (c >> 6 & 0x3F)); + } + pb->buf[i++] = (BYTE)(0x80 | (c & 0x3F)); + } +#elif _STRF_ENCODE == 2 /* Write a character in UTF-16BE */ + pb->buf[i++] = (BYTE)(c >> 8); + pb->buf[i++] = (BYTE)c; +#elif _STRF_ENCODE == 1 /* Write a character in UTF-16LE */ + pb->buf[i++] = (BYTE)c; + pb->buf[i++] = (BYTE)(c >> 8); +#else /* Write a character in ANSI/OEM */ + c = ff_convert(c, 0); /* Unicode -> OEM */ + if (!c) c = '?'; + if (c >= 0x100) + pb->buf[i++] = (BYTE)(c >> 8); + pb->buf[i++] = (BYTE)c; +#endif +#else /* Write a character without conversion */ + pb->buf[i++] = (BYTE)c; +#endif + + if (i >= (int)(sizeof pb->buf) - 3) { /* Write buffered characters to the file */ + f_write(pb->fp, pb->buf, (UINT)i, &bw); + i = (bw == (UINT)i) ? 0 : -1; + } + pb->idx = i; + pb->nchr++; +} + + + +int f_putc ( + TCHAR c, /* A character to be output */ + FIL* fp /* Pointer to the file object */ +) +{ + putbuff pb; + UINT nw; + + + pb.fp = fp; /* Initialize output buffer */ + pb.nchr = pb.idx = 0; + + putc_bfd(&pb, c); /* Put a character */ + + if ( pb.idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK + && (UINT)pb.idx == nw) return pb.nchr; + return EOF; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a string to the file */ +/*-----------------------------------------------------------------------*/ + +int f_puts ( + const TCHAR* str, /* Pointer to the string to be output */ + FIL* fp /* Pointer to the file object */ +) +{ + putbuff pb; + UINT nw; + + + pb.fp = fp; /* Initialize output buffer */ + pb.nchr = pb.idx = 0; + + while (*str) /* Put the string */ + putc_bfd(&pb, *str++); + + if ( pb.idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK + && (UINT)pb.idx == nw) return pb.nchr; + return EOF; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a formatted string to the file */ +/*-----------------------------------------------------------------------*/ + +int f_printf ( + FIL* fp, /* Pointer to the file object */ + const TCHAR* fmt, /* Pointer to the format string */ + ... /* Optional arguments... */ +) +{ + va_list arp; + BYTE f, r; + UINT nw, i, j, w; + DWORD v; + TCHAR c, d, s[16], *p; + putbuff pb; + + + pb.fp = fp; /* Initialize output buffer */ + pb.nchr = pb.idx = 0; + + va_start(arp, fmt); + + for (;;) { + c = *fmt++; + if (c == 0) break; /* End of string */ + if (c != '%') { /* Non escape character */ + putc_bfd(&pb, c); + continue; + } + w = f = 0; + c = *fmt++; + if (c == '0') { /* Flag: '0' padding */ + f = 1; c = *fmt++; + } else { + if (c == '-') { /* Flag: left justified */ + f = 2; c = *fmt++; + } + } + while (IsDigit(c)) { /* Precision */ + w = w * 10 + c - '0'; + c = *fmt++; + } + if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ + f |= 4; c = *fmt++; + } + if (!c) break; + d = c; + if (IsLower(d)) d -= 0x20; + switch (d) { /* Type is... */ + case 'S' : /* String */ + p = va_arg(arp, TCHAR*); + for (j = 0; p[j]; j++) ; + if (!(f & 2)) { + while (j++ < w) putc_bfd(&pb, ' '); + } + while (*p) putc_bfd(&pb, *p++); + while (j++ < w) putc_bfd(&pb, ' '); + continue; + case 'C' : /* Character */ + putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; + case 'B' : /* Binary */ + r = 2; break; + case 'O' : /* Octal */ + r = 8; break; + case 'D' : /* Signed decimal */ + case 'U' : /* Unsigned decimal */ + r = 10; break; + case 'X' : /* Hexdecimal */ + r = 16; break; + default: /* Unknown type (pass-through) */ + putc_bfd(&pb, c); continue; + } + + /* Get an argument and put it in numeral */ + v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); + if (d == 'D' && (v & 0x80000000)) { + v = 0 - v; + f |= 8; + } + i = 0; + do { + d = (TCHAR)(v % r); v /= r; + if (d > 9) d += (c == 'x') ? 0x27 : 0x07; + s[i++] = d + '0'; + } while (v && i < sizeof s / sizeof s[0]); + if (f & 8) s[i++] = '-'; + j = i; d = (f & 1) ? '0' : ' '; + while (!(f & 2) && j++ < w) putc_bfd(&pb, d); + do putc_bfd(&pb, s[--i]); while (i); + while (j++ < w) putc_bfd(&pb, d); + } + + va_end(arp); + + if ( pb.idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK + && (UINT)pb.idx == nw) return pb.nchr; + return EOF; +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_STRFUNC */ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ff.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ff.h new file mode 100644 index 0000000..28537b6 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ff.h @@ -0,0 +1,350 @@ +/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015 +/----------------------------------------------------------------------------/ +/ FatFs module is a free software that opened under license policy of +/ following conditions. +/ +/ Copyright (C) 2015, ChaN, all right reserved. +/ +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +/---------------------------------------------------------------------------*/ + + +#ifndef _FATFS +#define _FATFS 32020 /* Revision ID */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "integer.h" /* Basic integer types */ +#include "ffconf.h" /* FatFs configuration options */ +#if _FATFS != _FFCONF +#error Wrong configuration file (ffconf.h). +#endif + + + +/* Definitions of volume management */ + +#if _MULTI_PARTITION /* Multiple partition configuration */ +typedef struct { + BYTE pd; /* Physical drive number */ + BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ +} PARTITION; +extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ +#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ +#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ + +#else /* Single partition configuration */ +#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ +#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ + +#endif + + + +/* Type of path name strings on FatFs API */ + +#if _LFN_UNICODE /* Unicode string */ +#if !_USE_LFN +#error _LFN_UNICODE must be 0 at non-LFN cfg. +#endif +#ifndef _INC_TCHAR +typedef WCHAR TCHAR; +#define _T(x) L ## x +#define _TEXT(x) L ## x +#endif + +#else /* ANSI/OEM string */ +#ifndef _INC_TCHAR +typedef char TCHAR; +#define _T(x) x +#define _TEXT(x) x +#endif + +#endif + + + +/* File system object structure (FATFS) */ + +typedef struct { + BYTE fs_type; /* FAT sub-type (0:Not mounted) */ + BYTE drv; /* Physical drive number */ + BYTE csize; /* Sectors per cluster (1,2,4...128) */ + BYTE n_fats; /* Number of FAT copies (1 or 2) */ + BYTE wflag; /* win[] flag (b0:dirty) */ + BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ + WORD id; /* File system mount ID */ + WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ +#if _MAX_SS != _MIN_SS + WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ +#endif +#if _FS_REENTRANT + _SYNC_t sobj; /* Identifier of sync object */ +#endif +#if !_FS_READONLY + DWORD last_clust; /* Last allocated cluster */ + DWORD free_clust; /* Number of free clusters */ +#endif +#if _FS_RPATH + DWORD cdir; /* Current directory start cluster (0:root) */ +#endif + DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ + DWORD fsize; /* Sectors per FAT */ + DWORD volbase; /* Volume start sector */ + DWORD fatbase; /* FAT start sector */ + DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ + DWORD database; /* Data start sector */ + DWORD winsect; /* Current sector appearing in the win[] */ + BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ +} FATFS; + + + +/* File object structure (FIL) */ + +typedef struct { + FATFS* fs; /* Pointer to the related file system object (**do not change order**) */ + WORD id; /* Owner file system mount ID (**do not change order**) */ + BYTE flag; /* Status flags */ + BYTE err; /* Abort flag (error code) */ + DWORD fptr; /* File read/write pointer (Zeroed on file open) */ + DWORD fsize; /* File size */ + DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */ + DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ + DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ +#if !_FS_READONLY + DWORD dir_sect; /* Sector number containing the directory entry */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ +#endif +#if _USE_FASTSEEK + DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ +#endif +#if _FS_LOCK + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ +#endif +#if !_FS_TINY + BYTE buf[_MAX_SS]; /* File private data read/write window */ +#endif +} FIL; + + + +/* Directory object structure (DIR) */ + +typedef struct { + FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */ + WORD id; /* Owner file system mount ID (**do not change order**) */ + WORD index; /* Current read/write index number */ + DWORD sclust; /* Table start cluster (0:Root dir) */ + DWORD clust; /* Current cluster */ + DWORD sect; /* Current sector */ + BYTE* dir; /* Pointer to the current SFN entry in the win[] */ + BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ +#if _FS_LOCK + UINT lockid; /* File lock ID (index of file semaphore table Files[]) */ +#endif +#if _USE_LFN + WCHAR* lfn; /* Pointer to the LFN working buffer */ + WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ +#endif +#if _USE_FIND + const TCHAR* pat; /* Pointer to the name matching pattern */ +#endif +} DIR; + + + +/* File information structure (FILINFO) */ + +typedef struct { + DWORD fsize; /* File size */ + WORD fdate; /* Last modified date */ + WORD ftime; /* Last modified time */ + BYTE fattrib; /* Attribute */ + TCHAR fname[13]; /* Short file name (8.3 format) */ +#if _USE_LFN + TCHAR* lfname; /* Pointer to the LFN buffer */ + UINT lfsize; /* Size of LFN buffer in TCHAR */ +#endif +} FILINFO; + + + +/* File function return code (FRESULT) */ + +typedef enum { + FR_OK = 0, /* (0) Succeeded */ + FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ + FR_INT_ERR, /* (2) Assertion failed */ + FR_NOT_READY, /* (3) The physical drive cannot work */ + FR_NO_FILE, /* (4) Could not find the file */ + FR_NO_PATH, /* (5) Could not find the path */ + FR_INVALID_NAME, /* (6) The path name format is invalid */ + FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ + FR_EXIST, /* (8) Access denied due to prohibited access */ + FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ + FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ + FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ + FR_NOT_ENABLED, /* (12) The volume has no work area */ + FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ + FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ + FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ + FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ + FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ + FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ + FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ +} FRESULT; + + + +/*--------------------------------------------------------------*/ +/* FatFs module application interface */ + +FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ +FRESULT f_close (FIL* fp); /* Close an open file object */ +FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ +FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ +FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ +FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */ +FRESULT f_truncate (FIL* fp); /* Truncate file */ +FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ +FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ +FRESULT f_closedir (DIR* dp); /* Close an open directory */ +FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ +FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ +FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ +FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ +FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ +FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ +FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ +FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ +FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */ +FRESULT f_chdir (const TCHAR* path); /* Change current directory */ +FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ +FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ +FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ +FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ +FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ +FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ +FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ +FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ +int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ +int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ +int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ +TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ + +#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize)) +#define f_error(fp) ((fp)->err) +#define f_tell(fp) ((fp)->fptr) +#define f_size(fp) ((fp)->fsize) +#define f_rewind(fp) f_lseek((fp), 0) +#define f_rewinddir(dp) f_readdir((dp), 0) + +#ifndef EOF +#define EOF (-1) +#endif + + + + +/*--------------------------------------------------------------*/ +/* Additional user defined functions */ + +/* RTC function */ +#if !_FS_READONLY && !_FS_NORTC +DWORD get_fattime (void); +#endif + +/* Unicode support functions */ +#if _USE_LFN /* Unicode - OEM code conversion */ +WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ +WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ +#if _USE_LFN == 3 /* Memory functions */ +void* ff_memalloc (UINT msize); /* Allocate memory block */ +void ff_memfree (void* mblock); /* Free memory block */ +#endif +#endif + +/* Sync functions */ +#if _FS_REENTRANT +int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ +int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ +void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ +int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ +#endif + + + + +/*--------------------------------------------------------------*/ +/* Flags and offset address */ + + +/* File access control and file status flags (FIL.flag) */ + +#define FA_READ 0x01 +#define FA_OPEN_EXISTING 0x00 + +#if !_FS_READONLY +#define FA_WRITE 0x02 +#define FA_CREATE_NEW 0x04 +#define FA_CREATE_ALWAYS 0x08 +#define FA_OPEN_ALWAYS 0x10 +#define FA__WRITTEN 0x20 +#define FA__DIRTY 0x40 +#endif + + +/* FAT sub type (FATFS.fs_type) */ + +#define FS_FAT12 1 +#define FS_FAT16 2 +#define FS_FAT32 3 + + +/* File attribute bits for directory entry */ + +#define AM_RDO 0x01 /* Read only */ +#define AM_HID 0x02 /* Hidden */ +#define AM_SYS 0x04 /* System */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_DIR 0x10 /* Directory */ +#define AM_ARC 0x20 /* Archive */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + +/* Fast seek feature */ +#define CREATE_LINKMAP 0xFFFFFFFF + + + +/*--------------------------------*/ +/* Multi-byte word access macros */ + +#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ +#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) +#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) +#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) +#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) +#else /* Use byte-by-byte access to the FAT structure */ +#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) +#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) +#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) +#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _FATFS */ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ffconf.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ffconf.h new file mode 100644 index 0000000..bcaba72 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/ffconf.h @@ -0,0 +1,266 @@ +/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 +/---------------------------------------------------------------------------*/ + +#define _FFCONF 32020 /* Revision ID */ + +/*---------------------------------------------------------------------------/ +/ Functions and Buffer Configurations +/---------------------------------------------------------------------------*/ + +#define _FS_TINY 1 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS +/ bytes. Instead of private sector buffer eliminated from the file object, +/ common sector buffer in the file system object (FATFS) is used for the file +/ data transfer. */ + + +#define _FS_READONLY 1 +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes writing API functions, f_write(), f_sync(), +/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() +/ and optional writing functions as well. */ + + +#define _FS_MINIMIZE 0 +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: All basic functions are enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), +/ f_truncate() and f_rename() function are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + + +#define _USE_STRFUNC 0 +/* This option switches string functions, f_gets(), f_putc(), f_puts() and +/ f_printf(). +/ +/ 0: Disable string functions. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. */ + + +#define _USE_FIND 0 +/* This option switches filtered directory read feature and related functions, +/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ + + +#define _USE_MKFS 0 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ + + +#define _USE_FASTSEEK 0 +/* This option switches fast seek feature. (0:Disable or 1:Enable) */ + + +#define _USE_LABEL 1 +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + + +#define _USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) +/ To enable it, also _FS_TINY need to be set to 1. */ + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/---------------------------------------------------------------------------*/ + +#define _CODE_PAGE 437 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect setting of the code page can cause a file open failure. +/ +/ 1 - ASCII (No extended character. Non-LFN cfg. only) +/ 437 - U.S. +/ 720 - Arabic +/ 737 - Greek +/ 775 - Baltic +/ 850 - Multilingual Latin 1 +/ 852 - Latin 2 +/ 855 - Cyrillic +/ 857 - Turkish +/ 858 - Multilingual Latin 1 + Euro +/ 862 - Hebrew +/ 866 - Russian +/ 874 - Thai +/ 932 - Japanese Shift_JIS (DBCS) +/ 936 - Simplified Chinese GBK (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese Big5 (DBCS) +*/ + + +#define _USE_LFN 0 +#define _MAX_LFN 128 +/* The _USE_LFN option switches the LFN feature. +/ +/ 0: Disable LFN feature. _MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must +/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree(), must be added to the project. */ + + +#define _LFN_UNICODE 0 +/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) +/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE +/ to 1. This option also affects behavior of string I/O functions. */ + + +#define _STRF_ENCODE 3 +/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to +/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). +/ +/ 0: ANSI/OEM +/ 1: UTF-16LE +/ 2: UTF-16BE +/ 3: UTF-8 +/ +/ When _LFN_UNICODE is 0, this option has no effect. */ + + +#define _FS_RPATH 2 +/* This option configures relative path feature. +/ +/ 0: Disable relative path feature and remove related functions. +/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +/ +/ Note that directory items read via f_readdir() are affected by this option. */ + + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ + +#define _VOLUMES 1 +/* Number of volumes (logical drives) to be used. */ + + +#define _STR_VOLUME_ID 0 +#define _VOLUME_STRS "CF","SD" +/* _STR_VOLUME_ID option switches string volume ID feature. +/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive +/ number in the path name. _VOLUME_STRS defines the drive ID strings for each +/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for +/ the drive ID strings are: A-Z and 0-9. */ + + +#define _MULTI_PARTITION 0 +/* This option switches multi-partition feature. By default (0), each logical drive +/ number is bound to the same physical drive number and only an FAT volume found on +/ the physical drive will be mounted. When multi-partition feature is enabled (1), +/ each logical drive number is bound to arbitrary physical drive and partition +/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */ + + +#define _MIN_SS 512 +#define _MAX_SS 512 +/* These options configure the range of sector size to be supported. (512, 1024, +/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and +/ harddisk. But a larger value may be required for on-board flash memory and some +/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured +/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the +/ disk_ioctl() function. */ + + +#define _USE_TRIM 0 +/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) +/ To enable Trim feature, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + + +#define _FS_NOFSINFO 0 +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/---------------------------------------------------------------------------*/ + +#define _FS_NORTC 1 +#define _NORTC_MON 2 +#define _NORTC_MDAY 1 +#define _NORTC_YEAR 2015 +/* The _FS_NORTC option switches timestamp feature. If the system does not have +/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable +/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp +/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. +/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need +/ to be added to the project to read current time form RTC. _NORTC_MON, +/ _NORTC_MDAY and _NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (_FS_READONLY == 1). */ + + +#define _FS_LOCK 0 +/* The _FS_LOCK option switches file lock feature to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when _FS_READONLY +/ is 1. +/ +/ 0: Disable file lock feature. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock feature. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock feature is independent of re-entrancy. */ + + +#define _FS_REENTRANT 0 +#define _FS_TIMEOUT 1000 +#define _SYNC_t HANDLE +/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk() function, are always not re-entrant. Only file/directory access +/ to the same volume is under control of this feature. +/ +/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() +/ function, must be added to the project. Samples are available in +/ option/syscall.c. +/ +/ The _FS_TIMEOUT defines timeout period in unit of time tick. +/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ SemaphoreHandle_t and etc.. */ + + +#define _WORD_ACCESS 1 +/* The _WORD_ACCESS option is an only platform dependent option. It defines +/ which access method is used to the word data on the FAT volume. +/ +/ 0: Byte-by-byte access. Always compatible with all platforms. +/ 1: Word access. Do not choose this unless under both the following conditions. +/ +/ * Address misaligned memory access is always allowed to ALL instructions. +/ * Byte order on the memory is little-endian. +/ +/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. +/ Following table shows allowable settings of some processor types. +/ +/ ARM7TDMI 0 ColdFire 0 V850E 0 +/ Cortex-M3 0 Z80 0/1 V850ES 0/1 +/ Cortex-M0 0 x86 0/1 TLCS-870 0/1 +/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 +/ AVR32 0 RL78 0 R32C 0 +/ PIC18 0/1 SH-2 0 M16C 0/1 +/ PIC24 0 H8S 0 MSP430 0 +/ PIC32 0 H8/300H 0 8051 0/1 +*/ + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/integer.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/integer.h new file mode 100644 index 0000000..074a46b --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/ff/integer.h @@ -0,0 +1,33 @@ +/*-------------------------------------------*/ +/* Integer type definitions for FatFs module */ +/*-------------------------------------------*/ + +#ifndef _FF_INTEGER +#define _FF_INTEGER + +#ifdef _WIN32 /* FatFs development platform */ + +#include +#include + +#else /* Embedded platform */ + +/* This type MUST be 8 bit */ +typedef unsigned char BYTE; + +/* These types MUST be 16 bit */ +typedef short SHORT; +typedef unsigned short WORD; +typedef unsigned short WCHAR; + +/* These types MUST be 16 bit or 32 bit */ +typedef int INT; +typedef unsigned int UINT; + +/* These types MUST be 32 bit */ +typedef long LONG; +typedef unsigned long DWORD; + +#endif + +#endif diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/globals.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/globals.h new file mode 100644 index 0000000..70dcf20 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/globals.h @@ -0,0 +1,57 @@ +/* + * globals.h + * + * Created on: 29 íîÿá. 2018 ã. + * Author: maxx + */ + +#ifndef GLOBALS_H_ +#define GLOBALS_H_ + +#include +#include +#include +#include "avr/wdt.h" // WatchDog + +//******************************* Fat FS declare related: BEGIN +#include "string.h" +#include "ff.h" +#include "diskio.h" +#include "integer.h" +#include "Internet/httpServer_avr/httpParser.h" +//******************************* Fat FS declare related: END + + +#define HTTPD_MAX_BUF_SIZE 2048 //For Mega1284p(16kb RAM)/Mega2560(8kb RAM) +//#define HTTPD_MAX_BUF_SIZE MAX_URI_SIZE+10 //For Mega644p(4kb RAM)/Mega128(4kb RAM) (ie. 512+10=522 bytes look at httpParser.h <_st_http_request> definition) + +#define PRINTF_EN 1 +#if PRINTF_EN +#define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args) +#else +#define PRINTF(...) +#endif + +extern unsigned long millis(void); +extern int freeRam (void); + +//M644P/M1284p Users LEDS: +//LED1/PORTC.4- m644p/m1284p maxxir +#define led1_conf() DDRC |= (1<= 2 */ +//static FIL File; /* File object. there are _FS_LOCK file objects available, >= 2. */ + +#endif /* GLOBALS_H_ */ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/m1284p_png.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/m1284p_png.h new file mode 100644 index 0000000..c1be58d --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/m1284p_png.h @@ -0,0 +1,815 @@ +const char m1284p_png[] PROGMEM = { +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52, +0x0,0x0,0x4,0xf8,0x0,0x0,0x3,0x3b,0x1,0x3,0x0,0x0,0x0,0xed,0x52,0xbc, +0x4d,0x0,0x0,0x0,0x6,0x50,0x4c,0x54,0x45,0x0,0x0,0x0,0xff,0xff,0xff,0xa5, +0xd9,0x9f,0xdd,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0x12,0x74,0x0, +0x0,0x12,0x74,0x1,0xde,0x66,0x1f,0x78,0x0,0x0,0x20,0x0,0x49,0x44,0x41,0x54, +0x78,0xda,0xed,0xdd,0x5f,0x8c,0x23,0xc7,0x9d,0x1f,0xf0,0x59,0x4f,0x20,0x26,0xb0, +0xb5,0xf4,0x21,0x2f,0x6,0xbc,0xbb,0xf4,0xc5,0x4f,0x79,0x73,0x5e,0x6e,0x25,0x68, +0xb5,0xb4,0x90,0x7,0x3f,0xfa,0xf1,0x2,0x8,0xd2,0x2a,0x2f,0xf9,0x3,0x45,0x4b, +0x19,0x86,0x96,0xbb,0xe2,0x72,0x7a,0xd6,0x3,0x64,0x1e,0x12,0xdc,0xdc,0x21,0x2f, +0x39,0x48,0xde,0x31,0x70,0x7,0xf8,0xe1,0x60,0xad,0x2,0x45,0xa2,0x6c,0x2e,0xa7, +0x39,0x98,0xb3,0x6,0xc1,0x59,0xe2,0x19,0x4e,0x30,0xb6,0x29,0xb2,0x38,0x37,0x97, +0xa3,0x90,0x11,0xbb,0x38,0x1e,0x2f,0xab,0x67,0x8a,0x5d,0x95,0xfe,0x57,0xfd,0xb7, +0xba,0xd9,0xff,0x48,0xb6,0x70,0x43,0xdc,0x59,0xda,0x9d,0xdd,0x99,0x8f,0xaa,0xbb, +0xab,0xbe,0xfd,0xab,0xea,0xea,0x15,0x9a,0xef,0xcf,0xca,0x85,0xef,0xc2,0xe7,0xfe, +0xf4,0x4b,0xc5,0x5c,0xfb,0x7a,0x12,0xca,0xb5,0xaf,0x3b,0xc9,0xb9,0x8f,0x5e,0xf8, +0xd2,0xf9,0x60,0xce,0x7d,0x60,0x91,0xbe,0xc1,0x5a,0x71,0x73,0x73,0x73,0x5a,0xda, +0x23,0xd7,0xae,0x14,0x89,0x2c,0xcc,0xf6,0x21,0x71,0x91,0x3e,0xd8,0x42,0xb5,0x5a, +0x4d,0xa1,0x2d,0x65,0x34,0x42,0xd3,0x8,0x3f,0xbb,0x7,0x85,0x85,0xfa,0xba,0x58, +0xf5,0x61,0xc3,0x77,0x1e,0xc1,0xd7,0xbf,0x56,0x58,0xac,0x8f,0xaa,0x40,0xb9,0xdc, +0x52,0xe0,0x8,0x11,0xba,0xc0,0x63,0x17,0xd9,0xb7,0xaf,0xb6,0x1f,0xc8,0xaf,0x6f, +0x4f,0x6d,0x3f,0xaa,0xf9,0x3e,0x2d,0x12,0x2a,0xe4,0xcf,0x87,0x71,0xed,0xcd,0x12, +0x68,0x3d,0xd,0x5b,0xd3,0x9b,0x84,0xe6,0xd0,0x57,0x33,0x8f,0x6f,0x9d,0x12,0x25, +0x7f,0x3e,0xbd,0x7f,0xc1,0x62,0x4b,0x91,0x14,0x4a,0xf0,0xec,0xbf,0xd2,0x3e,0x3c, +0x1c,0xb4,0x6f,0x81,0x45,0xf9,0xcc,0xfe,0xf9,0xf9,0x3d,0x72,0xe5,0x69,0x4a,0xc6, +0xe5,0x99,0x7f,0x85,0xf4,0xfb,0x10,0x83,0x85,0xf9,0x62,0x7f,0x94,0x7e,0x1f,0x60, +0x28,0xe6,0xd9,0xb7,0x9b,0x67,0x1f,0x3e,0xec,0xf7,0x31,0xa,0xe8,0x87,0xc6,0xfe, +0x13,0x93,0x90,0xc3,0x8,0xa3,0x7a,0x86,0xbe,0x7e,0x9f,0x4,0xfa,0x10,0xe0,0xf8, +0xfa,0xc9,0x13,0x45,0x52,0xdf,0x79,0xc0,0xb1,0x87,0x9c,0x3,0x5f,0x17,0x2b,0x60, +0x81,0x3e,0xd4,0x57,0x8f,0x6f,0x90,0x6f,0xc0,0xf5,0x41,0xba,0x58,0x5f,0xf,0x2b, +0x41,0xed,0x57,0xf5,0x1f,0xf8,0xe6,0x7c,0x7c,0x2d,0x24,0x15,0x8a,0x9c,0x5b,0x5d, +0x74,0x78,0x78,0x18,0xe4,0x1b,0x94,0x17,0xe7,0xbb,0x81,0x3a,0x93,0xb8,0xb7,0x92, +0xa,0x7d,0xd3,0xff,0x9b,0x7,0x73,0xf1,0x91,0x56,0xf5,0x91,0x14,0xdb,0x7,0xb9, +0xbe,0xb9,0x5c,0x1f,0xad,0x6a,0x5,0xc6,0xf6,0x49,0x9c,0x3,0xf,0xe7,0xd3,0xbf, +0xb4,0x1a,0x15,0x80,0x38,0xe7,0xdf,0x8a,0xfd,0xf1,0x7,0xfd,0x31,0xcf,0x37,0x9f, +0xfe,0xb9,0xf5,0x1,0x4,0xbc,0x52,0x4b,0xa8,0x6f,0x81,0xe3,0x5b,0xeb,0xff,0x40, +0xd0,0x9f,0xa3,0x4f,0xbe,0x1e,0xe1,0xb0,0x7,0xf9,0x56,0xd5,0x1b,0xba,0xff,0x5d, +0x10,0x77,0x38,0xbe,0x92,0xfd,0xaf,0xfb,0x69,0x7c,0xe8,0x0,0x95,0x13,0xfb,0xea, +0xa7,0xb4,0x35,0x84,0xe2,0xda,0x3c,0x7d,0x5d,0x29,0x79,0xfb,0xad,0x1d,0xab,0xfd, +0x33,0xdc,0x29,0xf8,0xaf,0xf,0xe8,0xf0,0x7d,0x54,0x4e,0xe3,0x8b,0x12,0xd2,0x2, +0x7d,0x81,0x41,0xbf,0xe3,0xf0,0xfd,0x3c,0x4d,0x8a,0x96,0x15,0x30,0xf,0xdf,0x23, +0xe7,0xf1,0x4d,0x95,0xf2,0xaf,0xc6,0xf6,0xb5,0x3d,0xbe,0x31,0xe7,0x6f,0xc0,0xcc, +0x7c,0x7d,0x31,0xae,0x6f,0xdd,0x38,0x9f,0x8a,0x44,0x30,0x7c,0x3,0x61,0x2b,0xdc, +0x17,0xe9,0xfc,0x1b,0x6,0xe5,0xa0,0xb8,0x3e,0xb2,0x62,0xfc,0xec,0x55,0xe6,0x1b, +0x92,0x62,0x6,0xed,0x77,0x18,0x14,0xb5,0x85,0x38,0xbe,0x35,0xf5,0x6,0xb3,0x6c, +0x70,0xbe,0x41,0x84,0xba,0xe1,0x93,0xb3,0xf0,0xc9,0x1,0xbf,0x5d,0x8e,0xe5,0x6b, +0xb5,0x94,0xcf,0x69,0xc7,0x48,0x56,0x37,0x85,0x55,0xc3,0x77,0xd8,0xe1,0xf8,0x88, +0x1e,0x9e,0xb1,0x54,0x8e,0x78,0xfd,0x4e,0x53,0xf4,0x42,0x2e,0xdf,0x67,0x6a,0x87, +0xab,0x75,0xb9,0xe5,0xcb,0xe6,0x78,0x3e,0xdc,0x34,0x7d,0x53,0xc1,0xea,0x90,0x2d, +0xdf,0x8,0x58,0xfd,0xdf,0x54,0xf0,0xf7,0xde,0x47,0xf6,0xf,0x29,0x66,0xe1,0xeb, +0x2a,0x54,0xf3,0x6d,0x68,0xbe,0xb6,0xf9,0xf3,0xfe,0xbe,0xd4,0x61,0xc7,0xc2,0xf8, +0xe7,0x86,0x2e,0xb8,0xa3,0x47,0xa9,0x2e,0xb4,0xc6,0xf,0xd9,0x6a,0x21,0xfb,0x84, +0xdd,0xcd,0x64,0x98,0xb1,0x7d,0x43,0x45,0x3d,0x91,0x8f,0xe8,0x25,0xcd,0x37,0x36, +0x7d,0x3,0xc1,0xf4,0x8d,0xcd,0x66,0xb9,0xc4,0xf7,0x8d,0xad,0x56,0x9b,0x5a,0x91, +0x61,0x7d,0xd6,0x5,0xd2,0xd6,0x23,0x46,0x39,0xb2,0xf,0xd3,0x5f,0xd2,0xc1,0xca, +0xec,0x8f,0xc3,0xd7,0x5e,0x89,0xf4,0xb9,0x94,0x85,0xaf,0x8b,0x8a,0xff,0x23,0x62, +0xfb,0xbd,0xa3,0x1f,0xc9,0x66,0x82,0xf6,0x1b,0x8,0x89,0x7d,0x2d,0x48,0xef,0xa9, +0x5d,0xa9,0x7e,0xfe,0xb1,0x6f,0xf3,0xf7,0x65,0xee,0xf9,0xe7,0xf3,0x45,0x3e,0xff, +0x9c,0x23,0x9a,0xfe,0xbb,0x24,0xba,0xf,0x10,0x99,0x5d,0xbf,0xff,0x99,0x5d,0xbf, +0x45,0xff,0xf5,0xab,0xfa,0xfa,0x46,0x4,0x3,0xd6,0xf,0x9e,0x71,0xfd,0xda,0x83, +0x90,0x8,0x12,0xfb,0xd6,0x1e,0x4c,0xbf,0xa2,0xf6,0x7f,0xda,0xad,0xe0,0xcd,0x6b, +0x2,0xac,0xe3,0xbd,0x3d,0x3c,0xdc,0x33,0x7d,0xac,0xec,0xb,0x1d,0xbe,0xb5,0xb2, +0xe5,0x73,0x54,0x85,0xad,0x6,0xb2,0x93,0x23,0xb1,0x7b,0x74,0xb1,0x6f,0xfd,0x97, +0x94,0x4c,0x5f,0x31,0xfa,0xf8,0x36,0x55,0x87,0x5b,0x4d,0xf0,0xcc,0x9a,0xd0,0x79, +0xfe,0xb4,0xd5,0x3a,0x1d,0x8e,0xb9,0x3e,0xdf,0x81,0xb,0xf7,0x39,0x5a,0xd7,0xf6, +0x11,0x68,0xfa,0x4,0xed,0xa4,0xbd,0xb4,0xdb,0x7e,0xa5,0x3c,0x7b,0xfc,0xbd,0x59, +0xd2,0x5,0x7f,0x48,0x84,0x47,0x2f,0x1d,0xb7,0x5a,0xc7,0xc3,0x69,0x31,0x3,0x9f, +0x63,0x7c,0x73,0xf8,0xcc,0xe3,0x7b,0x53,0xeb,0xa,0xb0,0xb0,0x3,0x94,0x68,0xf9, +0x45,0x13,0x14,0x88,0x0,0x5f,0xea,0xb6,0x5a,0x5d,0x2b,0x1f,0xa4,0xf2,0x1d,0x72, +0x7d,0xdb,0xfb,0xac,0x49,0xa2,0xfb,0xda,0x86,0x40,0xcd,0x57,0xf0,0x35,0xdd,0xc7, +0x4e,0xed,0x54,0x3e,0x47,0xbe,0x5a,0xbf,0x66,0xf9,0x2a,0xa6,0xf,0xea,0x3e,0x31, +0x92,0xcf,0x14,0xa8,0x3f,0x3,0xbe,0xd6,0x6c,0xb5,0x9a,0x94,0x4d,0xf5,0xa6,0xf2, +0xb9,0x4e,0x21,0xdf,0xf9,0xa7,0xfb,0x2e,0xed,0xb7,0xeb,0xd1,0x7d,0xda,0x3f,0xde, +0xa8,0xb5,0x5a,0x35,0xfb,0xdb,0xce,0xd5,0x37,0x2d,0x8,0x72,0x9c,0xf6,0xd3,0x7d, +0x97,0x5a,0xad,0x4b,0x72,0x29,0xe3,0xf6,0x73,0x1c,0x5f,0xe8,0x38,0xbe,0x40,0x20, +0x71,0x7d,0xf7,0x70,0xab,0x85,0x31,0xec,0x64,0xdc,0x7e,0x3b,0xbe,0xfe,0x4f,0xbb, +0x3e,0x60,0xc4,0xeb,0xc3,0xe1,0xd3,0xfb,0x67,0x8c,0x1e,0x65,0xeb,0x23,0x6b,0x76, +0x5f,0xb8,0xdf,0x2e,0xd3,0x75,0x7d,0xfc,0x50,0x50,0x6c,0x9f,0xf1,0xc1,0xa8,0x92, +0xad,0xef,0x8c,0x38,0x7c,0xeb,0x45,0xba,0x72,0x53,0xf7,0x61,0xb5,0x7f,0xae,0xe7, +0xc1,0x37,0x24,0xce,0xdc,0x55,0x24,0xee,0xdc,0x16,0xdf,0x37,0xc9,0xf8,0xfa,0x0, +0xdc,0xf6,0x8b,0x53,0x3f,0x70,0xfb,0x9e,0x4,0xf8,0x64,0xf4,0xeb,0x72,0xba,0xeb, +0x37,0x76,0x7e,0xe1,0xfa,0x7e,0x5f,0xe0,0xfb,0xd0,0xf7,0xbb,0x20,0x5d,0xff,0x97, +0x8d,0xf,0x6,0xb4,0x1f,0x7c,0xbf,0xb,0x53,0xfa,0x80,0xdd,0xbf,0x24,0xf6,0x5, +0xf6,0xcf,0xf0,0x49,0x32,0xdf,0xe7,0x6a,0xff,0x22,0xdc,0xbd,0x79,0x59,0xfd,0xd7, +0x6d,0xbb,0x7f,0x26,0xc5,0x4d,0x51,0x48,0xe2,0xb,0x1c,0xdf,0xa4,0x3f,0x4a,0xe6, +0xeb,0xa9,0xfd,0xf3,0xcd,0x6a,0x6f,0x62,0xfb,0xf4,0xf1,0x17,0xd5,0x76,0x68,0xa6, +0x3e,0xd8,0x78,0x31,0x91,0xaf,0xa5,0xe6,0xab,0x9b,0x95,0x91,0xe6,0xbb,0xe5,0xf0, +0x4d,0x94,0x56,0x7e,0x7c,0x2f,0x55,0x46,0xc4,0xe1,0xdb,0x56,0x7d,0x84,0x36,0xb3, +0xf5,0xa1,0xea,0x5b,0x89,0xae,0x5f,0x51,0xf7,0x49,0x6a,0x68,0x26,0xc0,0x6e,0x3f, +0x35,0x44,0x37,0xb2,0xf5,0x25,0xed,0xff,0x34,0xdf,0xab,0x15,0xf8,0x91,0x76,0x4d, +0xd8,0x3e,0xfa,0x11,0xfd,0xab,0x6c,0x7d,0x49,0xc7,0xf,0xd3,0x37,0xb1,0xfb,0x17, +0xed,0xfa,0xa5,0x13,0xfa,0xc3,0x7c,0xf8,0xb4,0xfb,0xf3,0x57,0x8d,0xeb,0xc3,0xd1, +0xff,0x65,0x7f,0x7d,0x24,0xf5,0x69,0x85,0x89,0xaa,0xd1,0xbf,0xb8,0xf2,0x55,0x84, +0xfe,0x45,0xae,0x45,0xf4,0x71,0xe6,0xb7,0xa2,0x8f,0x1f,0xea,0xa7,0x6a,0xf4,0xcf, +0x8e,0x7c,0x10,0xa9,0x7f,0x46,0x8d,0x85,0xf8,0x12,0xe7,0x2b,0x33,0x2a,0x43,0x3a, +0xbe,0x59,0x9a,0x6b,0xfb,0x25,0xcc,0x57,0x68,0xdb,0x14,0xa0,0x1e,0xc,0xf5,0xe9, +0x1f,0x85,0xfb,0x65,0xb7,0xef,0x50,0x19,0x87,0xfa,0xe2,0xe5,0x17,0x73,0xb2,0x53, +0xf5,0x8d,0x78,0xbe,0x43,0xdd,0x0,0x49,0x49,0x6f,0xb3,0x93,0x91,0xf7,0xcb,0xac, +0x88,0x21,0xca,0x77,0x4b,0xa6,0xaf,0x7f,0x16,0xba,0x92,0x36,0xb1,0xf,0xf2,0x7c, +0xfd,0xa9,0xfe,0x55,0xc5,0xf8,0x91,0xd2,0x6b,0xde,0x2f,0xb3,0x5,0x45,0x22,0x32, +0x6b,0x68,0x88,0x8a,0x6f,0x84,0xf9,0xd8,0xfd,0x9b,0x18,0xdf,0xc7,0x3b,0xff,0x44, +0x7d,0xe1,0x3,0xc4,0x13,0xe3,0x4f,0xfd,0xc4,0xfb,0xe5,0xa,0x6b,0x3f,0x68,0xd6, +0x20,0x55,0x9f,0x12,0xb2,0x5a,0xd4,0xba,0x3f,0x57,0x1b,0x50,0x51,0x3e,0xbc,0x59, +0x9c,0xe5,0x1b,0xaf,0x86,0xb6,0x9f,0x38,0x31,0x7c,0x46,0xc5,0x8,0x7e,0xec,0xfd, +0x32,0xb4,0x7c,0x34,0x92,0x8f,0xb2,0xfb,0x73,0xf5,0x4f,0x4f,0xcf,0x1a,0x3d,0x14, +0xb9,0x7f,0x9e,0xe1,0xd3,0xbf,0x11,0xf2,0x9e,0x7f,0xe2,0x67,0xb6,0x4f,0xb0,0x7c, +0xbc,0xd5,0xac,0xc8,0xed,0x2b,0x1b,0xbe,0x2e,0x9e,0xe5,0x3b,0xa5,0xa1,0xd7,0x87, +0x28,0x19,0x3e,0xf3,0xfb,0x7b,0xaf,0x5f,0x71,0x28,0x78,0x7d,0x50,0x54,0x94,0xa0, +0xcb,0xc2,0x31,0xbe,0xa9,0x3e,0xe5,0x8d,0x6,0x9e,0xe9,0x33,0xab,0x9c,0x41,0xfd, +0x8b,0xd8,0xf,0xf7,0x41,0x8e,0xaf,0xce,0xfb,0xa1,0x9b,0x3c,0xdf,0x87,0xb3,0x7d, +0x66,0xa9,0x2f,0xa8,0x7f,0x16,0xbf,0x2d,0x18,0xd7,0x47,0x80,0xaf,0x62,0xf9,0xfa, +0xe6,0x71,0xdc,0xe8,0x2b,0x9c,0x93,0xca,0x2a,0x46,0x8b,0xe,0xdf,0x4f,0xc4,0xaf, +0xcf,0xf6,0x19,0x7,0x18,0x6e,0xf3,0xc7,0xb7,0xbe,0xd1,0xff,0x29,0x12,0xe4,0xfa, +0xfa,0x56,0xfb,0x21,0x73,0xa8,0x47,0xf0,0x50,0x19,0xf8,0xaf,0xf,0x6b,0xa9,0x8e, +0xe0,0xf2,0x75,0x23,0xb7,0x5f,0x80,0xcf,0xea,0x9f,0x8b,0x5c,0xdf,0xe1,0xd8,0xea, +0x9f,0xd7,0x98,0x8f,0xfb,0x3,0xd9,0x9f,0xb3,0xf2,0xa9,0xee,0x8b,0x70,0x7d,0x98, +0xff,0x61,0x41,0xbe,0x4,0xe3,0x1b,0xf7,0xb3,0xc7,0xab,0x5f,0xf5,0x22,0xf4,0x2f, +0xc6,0x1f,0x18,0xf0,0x63,0x44,0x7c,0xdf,0x20,0x60,0x71,0x51,0x91,0x57,0xbf,0xea, +0x45,0xe8,0x9f,0x8d,0xf6,0x6b,0x67,0xe5,0x6b,0xaf,0xac,0x66,0x9b,0xaf,0x8c,0xf3, +0xaf,0xb3,0x4f,0xb3,0xf1,0x75,0x58,0x87,0x1a,0xa1,0xfd,0xa2,0xd5,0x37,0xf4,0xef, +0xd7,0xd9,0x98,0xb3,0x6f,0x3f,0x71,0x7d,0x68,0xcb,0xf4,0xc9,0xcf,0xe1,0xfd,0x4b, +0x68,0xf7,0x50,0x99,0x8b,0xef,0x30,0xa9,0xcf,0x18,0x3f,0x3a,0xdf,0xa4,0xe8,0x37, +0xa7,0x4d,0x38,0x4,0x7d,0xc7,0x12,0xe2,0x81,0x7a,0xae,0x68,0xdf,0x4c,0x3d,0x4b, +0x78,0x3e,0xf3,0xcb,0xda,0x49,0xbc,0xc2,0x4e,0xbb,0xa0,0xf3,0x4f,0x4e,0xea,0x33, +0xff,0x73,0xff,0xa5,0xe6,0x13,0xe0,0x81,0x28,0xbe,0x39,0x17,0x9f,0xbd,0x98,0x23, +0x51,0xfd,0x8f,0xfc,0x47,0x8a,0xce,0x8f,0x5,0x88,0x36,0xc4,0x74,0xed,0x17,0x9c, +0x4b,0x13,0xfa,0x8c,0xfe,0x85,0xfc,0x27,0x2a,0x9f,0x1f,0x7f,0x7,0xa2,0x96,0x88, +0xc2,0xc2,0x79,0xf2,0xe7,0x6c,0x36,0x53,0xe5,0xfb,0xe9,0xe7,0x94,0x7e,0xfd,0xc5, +0xe7,0x20,0x52,0xe6,0xe5,0x1b,0xa6,0xf3,0x49,0x2,0xed,0xbe,0x58,0xd3,0x7c,0x83, +0xf2,0x5c,0x7c,0xe9,0xee,0x8f,0xce,0x24,0x1,0xe9,0xbe,0x96,0x58,0x11,0xd3,0x5d, +0x1f,0x97,0xe6,0xe1,0x3b,0x81,0x65,0xd4,0x6d,0xaa,0xbe,0x66,0xdf,0xf1,0x24,0x47, +0x7e,0x7c,0xa7,0xb0,0x2c,0x3f,0xd7,0xdc,0x84,0x68,0xef,0x30,0x67,0x3e,0xe3,0xfe, +0xed,0x8,0x66,0x96,0xf,0x32,0xf6,0xd1,0x6c,0xf3,0xd5,0x6c,0x5f,0xcc,0xf5,0x43, +0xec,0x2f,0xcd,0xd5,0x7,0x3e,0xb5,0xd7,0xbb,0x24,0xf2,0xc1,0xd9,0xf5,0xb5,0x54, +0xbe,0xae,0xbd,0x62,0x3e,0x91,0x8f,0x66,0xe5,0xa3,0xa7,0x87,0x87,0xb4,0xed,0xed, +0xe2,0x61,0x63,0x84,0x63,0x75,0x92,0x91,0x7d,0x68,0x4f,0x5b,0x91,0x6,0xa7,0x65, +0xa4,0xaf,0x56,0xf3,0xfa,0xf6,0xf6,0xcc,0x5,0x6b,0xe2,0x98,0x2,0xdd,0x75,0xda, +0xef,0xfb,0x1f,0xa4,0x87,0x8d,0x98,0x1d,0x7b,0x64,0xdf,0xb0,0xa5,0x2f,0x3b,0xc1, +0x60,0xa8,0xdf,0xa9,0x78,0x7d,0xad,0x96,0xd9,0x72,0xea,0x8d,0xfa,0xb6,0xee,0x3a, +0xea,0xf7,0xfb,0x3e,0x1f,0xaa,0xce,0xcb,0x77,0xd0,0x6a,0x19,0xbe,0x83,0xbf,0xac, +0x72,0x7d,0x2d,0xcb,0xf7,0xf2,0x9f,0x69,0xae,0xd3,0x59,0x3e,0x54,0x58,0xa5,0x47, +0xf,0xba,0x30,0xa3,0xe3,0xcb,0x7c,0xe8,0xcf,0x1b,0x1c,0x9f,0xa2,0xd8,0xbe,0xfe, +0xbf,0x63,0xbe,0xb6,0xf7,0xfb,0x9c,0x23,0xfb,0x2f,0x4e,0x70,0x9d,0xf6,0x76,0x7e, +0x93,0x9d,0xef,0x81,0xe1,0x6b,0xbe,0x5b,0xe6,0xfa,0x1e,0x58,0x3e,0xa9,0x1d,0xd4, +0x7e,0xe7,0xc8,0xbe,0x3e,0x34,0x9f,0xb8,0xf3,0xdb,0xcc,0xdb,0xaf,0xc9,0x6b,0x3f, +0x8c,0x1d,0xed,0x27,0x5,0x1e,0x5f,0x5,0xdb,0xfd,0xcb,0x84,0x2e,0xd0,0x87,0x50, +0x34,0xdf,0xd4,0xee,0x9f,0x51,0xa9,0x4e,0xff,0x62,0xa7,0x5b,0x59,0x88,0xf,0x42, +0x8e,0xef,0x53,0x10,0xf6,0xa3,0xd1,0xd1,0x2a,0xfd,0xe1,0x83,0xec,0x7c,0x3f,0xd, +0xf3,0x1,0xf0,0x53,0xaf,0xef,0xf0,0xf0,0xef,0xc2,0x7d,0x58,0xa0,0x2d,0xb1,0xfb, +0x28,0xab,0xfe,0xf9,0xe7,0x9a,0x6f,0xfa,0x3c,0xdf,0xf7,0xe0,0xc1,0xcf,0x4d,0xdf, +0x18,0x19,0xbe,0x99,0xf3,0x33,0x93,0x4c,0x7d,0x59,0xd5,0xaf,0x7c,0xbe,0x4e,0x5e, +0x7d,0xa8,0x20,0xd0,0x3d,0x31,0xab,0xfe,0x39,0x7b,0x5f,0xb6,0xe3,0xdb,0x3f,0x4a, +0xdf,0xca,0x45,0xfb,0x5d,0xf8,0xbe,0x38,0xbe,0x76,0xce,0x7d,0xda,0xe3,0x83,0x39, +0xf6,0x11,0xad,0x4a,0x91,0x57,0xdf,0xda,0x1e,0x7d,0xac,0xad,0x2d,0xc8,0xab,0x4f, +0xbd,0x1,0xbb,0xa1,0x4d,0xd9,0xe5,0xd7,0x47,0x1e,0x6b,0x25,0x1b,0xfe,0xfc,0x8c, +0xf3,0xf9,0x23,0xa3,0x50,0xc5,0xfd,0x32,0x75,0x94,0x97,0x33,0xf6,0x75,0x15,0xfa, +0xa1,0xf6,0x4c,0x13,0x7f,0x7e,0xc6,0xf9,0xfc,0x96,0x51,0xed,0x12,0x78,0x5f,0x76, +0x3e,0xbf,0x95,0xb1,0x6f,0xa8,0xd0,0x9f,0x6a,0x3e,0x7e,0xd5,0xc9,0xf9,0xfc,0x9b, +0x51,0xe7,0x2a,0xf3,0xbe,0xec,0x7c,0xfe,0x2d,0x6b,0x1f,0x56,0x7d,0xe3,0x95,0xec, +0x3e,0x85,0x8c,0x8f,0x2f,0x2a,0xfe,0x54,0x9b,0xa3,0xc9,0xac,0xfd,0x68,0xc6,0xd7, +0x7,0x34,0x8e,0x6f,0x66,0xe7,0x5f,0xd6,0x3e,0x40,0x1f,0x6b,0x73,0x13,0x99,0x5d, +0xbf,0x19,0xfb,0xd6,0x1e,0xd0,0xc7,0x31,0x1e,0xd4,0x5d,0xd4,0x3e,0x6d,0xce,0xf1, +0x6d,0x5a,0xde,0xcc,0xb5,0x8f,0xc4,0xd8,0x58,0x77,0x19,0x3e,0xb6,0xfd,0x41,0x6e, +0x7d,0x6d,0x9a,0x6f,0x1f,0xbd,0xf0,0x5d,0xf8,0x2e,0x7c,0x17,0xbe,0xb,0xdf,0x85, +0xef,0xc2,0x77,0xe1,0xcb,0x81,0x6f,0xaa,0xdf,0xec,0xad,0xe6,0xdd,0x27,0x5f,0xdd, +0xc1,0x74,0x33,0xbf,0x3e,0x3c,0x7a,0x78,0x4a,0x6b,0x79,0xf4,0xe9,0xb7,0x7e,0x47, +0x78,0xf4,0xce,0x71,0x2b,0xdf,0x3e,0xdc,0xcd,0xa9,0x6f,0x5f,0xf7,0x7d,0x80,0xbb, +0xdf,0xcf,0x91,0x4f,0x2e,0x15,0x91,0xe9,0x6b,0xaa,0x3e,0xf9,0xea,0x7,0x78,0xf8, +0x5f,0x32,0xf3,0xd,0x56,0x56,0x84,0x74,0x3e,0x2c,0xa1,0xa1,0xc3,0x87,0x95,0x9f, +0xe1,0x21,0xce,0xcc,0xd7,0x9e,0xb9,0x30,0x69,0xa6,0x6f,0x84,0xf,0x3c,0xbe,0x6e, +0x76,0xbe,0xf4,0x1f,0x3c,0x32,0x9e,0x49,0x56,0x7d,0xef,0xe9,0xbe,0xc7,0xb8,0x5b, +0xcd,0xa7,0xef,0x6f,0xe4,0xb2,0xea,0xdb,0xc1,0xad,0xad,0x1c,0xf9,0xe4,0xab,0xb4, +0x6a,0xfa,0x30,0x2,0x47,0x59,0x8f,0x6f,0xe9,0xdb,0x4f,0x21,0xd6,0xf5,0xb,0x61, +0xd6,0xbe,0x5d,0xf8,0x6e,0xda,0xeb,0x43,0x39,0x5f,0x65,0xfd,0x1f,0x40,0x59,0xfb, +0x76,0x86,0xd,0x90,0x2,0x77,0xa2,0xfa,0x8,0x62,0xed,0x47,0x45,0x9c,0xb5,0x4f, +0x78,0xb5,0x91,0xe6,0x25,0x3e,0x3,0xd5,0x47,0x8b,0xf3,0xf4,0x1d,0xa7,0xf3,0xb9, +0x4b,0xfd,0xe5,0xec,0x7d,0xa3,0xb4,0xed,0xe7,0xcc,0x7,0xd9,0xb7,0xdf,0xdd,0xd7, +0xf2,0xed,0x13,0x6e,0xdb,0x3e,0x61,0x75,0x6d,0x90,0xce,0x97,0xfd,0xf5,0xeb,0xf0, +0x11,0x1,0xd7,0x81,0x90,0xc6,0xb7,0x9f,0x7d,0xff,0xb7,0x3,0xaf,0xb3,0xfe,0x45, +0x11,0x50,0x4d,0xfc,0x9f,0x5b,0x71,0x7d,0x6a,0xbe,0xda,0x60,0xfd,0x73,0xf6,0xe3, +0x87,0xa3,0x7f,0xc6,0x2,0xaa,0x8a,0xef,0x5d,0x8f,0xdd,0xbf,0x48,0xe6,0x3,0x27, +0xaa,0x4f,0x1d,0x7f,0xe7,0x37,0xbe,0x61,0x1,0x56,0xc4,0x46,0x35,0xb6,0x6f,0x84, +0x5,0x47,0xbe,0x9a,0x9f,0xf,0x9,0xf0,0x8f,0x13,0xf9,0x68,0xc1,0x91,0xef,0xe7, +0xe7,0x83,0x2,0x7c,0x2e,0x99,0xaf,0xb6,0x90,0xe3,0x3b,0x28,0x83,0x5a,0x2,0x9f, +0x9a,0xaf,0xf0,0xfc,0xae,0xf,0x57,0x5f,0x3,0xea,0xa0,0x1a,0xbf,0xfd,0x14,0xdb, +0x97,0x7d,0xff,0xe2,0xfc,0xd4,0xc0,0xda,0x0,0x25,0xf0,0xe1,0xda,0xfc,0xf2,0x55, +0xda,0x73,0x42,0xcf,0x57,0xd5,0xf9,0x8d,0x6f,0x19,0xf8,0x68,0x71,0x73,0xde,0xbe, +0x69,0x6e,0xf3,0x95,0xf1,0x31,0x9f,0xc5,0x5f,0x99,0xfd,0x50,0xa8,0xbf,0xfd,0xd8, +0xce,0xb4,0xf3,0x6c,0x3f,0xe3,0x59,0x7c,0x12,0xb8,0x3,0x75,0xe8,0xf1,0x45,0xf3, +0xf7,0x6d,0x9a,0x1,0x86,0xd2,0xb3,0xd8,0x3e,0x84,0x3b,0x73,0xcc,0x57,0x6,0xac, +0x94,0x8d,0x6f,0x63,0x4e,0xfd,0x9f,0xb9,0xaa,0x24,0xb5,0xf,0xcd,0x69,0xfc,0x18, +0xd3,0x8c,0x7c,0x73,0x1a,0x7f,0xd9,0x6a,0x2d,0x41,0x7f,0x2e,0x74,0xc5,0x7a,0x48, +0x34,0xae,0xf,0xce,0x29,0xbf,0xf8,0xda,0xcf,0x88,0xfc,0x8f,0x67,0x6c,0x79,0x64, +0xf8,0xc6,0xab,0x73,0xf7,0xf9,0xce,0x3f,0xc3,0xd7,0x4,0xe5,0x8,0x3e,0x4a,0x6d, +0xdf,0x9c,0x8e,0xaf,0xf9,0x6c,0xac,0xd7,0xd7,0x90,0xc4,0x78,0x3e,0x30,0xaf,0x7c, +0x55,0xf4,0xf4,0xcf,0xa6,0x8f,0xc6,0x3c,0xbe,0x60,0x5e,0xf9,0x6a,0x3f,0x85,0x8f, +0xa2,0x8e,0x7e,0x8,0x34,0xdf,0xbc,0xf2,0x95,0xf7,0xbb,0xc6,0xf2,0x75,0x34,0xdf, +0xb4,0x34,0xcf,0xf1,0x6d,0x9c,0xc6,0xa7,0xbf,0x3a,0x41,0x2e,0x2e,0x32,0x5f,0x99, +0x3e,0x18,0xc5,0x37,0x75,0xbc,0xfc,0xa2,0x3c,0xef,0x7c,0x2a,0x1b,0xef,0x1,0x64, +0xfd,0x4b,0x14,0x1f,0xa6,0xf3,0x6f,0x3f,0xfb,0x1e,0xdd,0xd8,0x15,0x2b,0x7e,0xff, +0x3c,0xdf,0xf3,0x8f,0xef,0x8b,0x5a,0x1f,0xb2,0xae,0x5f,0x3a,0xf7,0xfb,0x23,0x8c, +0x12,0xfa,0xa8,0x30,0x9f,0xfa,0x55,0x7a,0x9f,0xb2,0x65,0xf9,0x9a,0x73,0x9f,0xff, +0x90,0x8b,0xd0,0xf6,0xf1,0x97,0x93,0x17,0xbd,0xd7,0x47,0xc3,0xf2,0x89,0x73,0x19, +0x7f,0x15,0x65,0xcf,0xea,0xff,0xb0,0xb1,0xa7,0x23,0x64,0xc3,0xc9,0xac,0xe5,0xee, +0x5a,0xbe,0x6a,0x5a,0xbe,0x1f,0xcf,0x25,0xbf,0x28,0x4a,0xcb,0xda,0x5e,0x12,0x1b, +0x5d,0xa,0x64,0x71,0x81,0xf3,0x19,0x6,0xfb,0xde,0xe2,0xf9,0x48,0x9b,0xa4,0xf3, +0x11,0xbc,0x66,0x75,0x74,0xd8,0x90,0xc6,0xf2,0x61,0xfb,0xfc,0xe3,0x1d,0x5f,0x2, +0xee,0x27,0xf0,0x4d,0xbf,0x2a,0xd8,0x3e,0x1,0xd8,0xfd,0x4b,0x21,0x8d,0x8f,0x77, +0x7d,0x10,0xf0,0x66,0x3a,0x1f,0xad,0xda,0x3e,0x7b,0x7c,0x23,0xc1,0xbe,0x93,0xa3, +0x20,0x1f,0xaf,0x7f,0x21,0xe0,0x4e,0x86,0x3e,0xb2,0xba,0x3e,0x18,0x7c,0xab,0xa8, +0xd,0xab,0x81,0x3e,0xa9,0xc7,0xb9,0x3f,0x17,0x82,0xea,0x57,0xe9,0x7d,0x8f,0x9c, +0x3e,0x45,0x4,0x15,0x2,0x43,0x7d,0xa4,0xc7,0xa9,0x6f,0x8,0x41,0xe3,0x1b,0x69, +0x4b,0x69,0x7d,0xf6,0xf5,0x61,0xfb,0xce,0xa3,0xfa,0xcc,0x4f,0xb0,0xf,0xf4,0x53, +0xfa,0x80,0xdd,0xbf,0xe8,0x3e,0x38,0xc3,0x77,0xc6,0xf3,0x5,0xe6,0x2b,0x9,0xe8, +0x9b,0xb3,0xa4,0xf1,0xd9,0xfd,0xb3,0xea,0x5b,0x3f,0x1a,0x68,0x5b,0x89,0x4f,0xe8, +0x53,0xb1,0xda,0x2f,0xb0,0x3e,0x24,0x1,0x92,0xb2,0xfd,0x5c,0x47,0x63,0x55,0x9c, +0xea,0xc7,0x77,0xbc,0x76,0x9e,0x8d,0xef,0x24,0x5b,0x9f,0x9a,0x99,0x75,0x1f,0x51, +0xa6,0x2,0x29,0xac,0x6e,0x7e,0xc9,0xac,0x8,0xa2,0xbb,0xe5,0x6b,0x5f,0xde,0x85, +0x5,0xdf,0xf5,0xeb,0xf4,0x65,0x97,0xaf,0x2,0x7d,0x48,0xbb,0x3e,0xf6,0xb5,0x5e, +0x9b,0x8,0x6a,0xcf,0x5d,0x63,0xd7,0xb6,0xd4,0xec,0xc3,0x5e,0xff,0x0,0xfa,0xfa, +0x3f,0x87,0x6f,0x2f,0xbb,0x7c,0x15,0xe8,0xc3,0x9a,0x4f,0x9b,0xf0,0x43,0x5e,0xdf, +0x8,0x99,0x3e,0x6f,0xfe,0xa3,0x73,0xb8,0x3f,0xf,0xf4,0x29,0x6a,0xff,0x7c,0xf3, +0x92,0xe5,0x13,0x98,0xaf,0xdf,0x1c,0xd1,0x9d,0xfe,0x1,0xf0,0xfb,0x88,0xe5,0xe3, +0xe6,0x2b,0x73,0x77,0xa7,0x88,0x3e,0x2b,0x34,0x7d,0x95,0x13,0x9d,0x4,0xb6,0xa, +0x52,0xcf,0x51,0x44,0x3f,0xff,0x56,0x4d,0x5f,0xaf,0xab,0xfa,0x76,0x9b,0x40,0x2f, +0x89,0x97,0x9c,0xbe,0xa9,0xe5,0xdb,0xe4,0xe5,0x97,0x98,0xbe,0xb0,0xf6,0xb3,0x7e, +0x8b,0xb5,0x1f,0x14,0xac,0xec,0xf0,0xe9,0xd7,0x55,0x1f,0xd8,0xe0,0xb4,0xdf,0xd8, +0xf2,0x35,0x17,0xe5,0x63,0xe7,0x1f,0xb2,0xcf,0x3f,0xb5,0xfd,0xd0,0x1a,0x68,0x8a, +0x7e,0xdf,0x91,0xe5,0xc3,0xbc,0xe3,0x6b,0xee,0xce,0x96,0xa9,0x4f,0xfb,0x9e,0xd8, +0xed,0xeb,0x1e,0xf7,0xe1,0x1a,0xa8,0x73,0x7c,0xfb,0xb6,0x8f,0x77,0x7d,0xcc,0xc3, +0xa7,0xc7,0x6a,0xb5,0xff,0xc3,0xf6,0xf9,0x77,0xfc,0x59,0xb9,0x54,0x37,0x7c,0x27, +0xc8,0xe5,0xb3,0xe7,0x3f,0xb8,0xf9,0x6a,0x5f,0xfb,0x99,0x73,0xf0,0x11,0xf7,0xf8, +0xa1,0x45,0x56,0xc5,0xcc,0x57,0x5a,0x13,0xb6,0xb1,0x6c,0xf8,0x8c,0xe2,0xa1,0x7e, +0xff,0xeb,0xca,0x57,0x1b,0x87,0x10,0x18,0xbe,0xe9,0x5c,0x7c,0x9e,0xf1,0x57,0x6b, +0x33,0x6c,0x8e,0x6f,0xda,0x7a,0x49,0xf0,0x86,0xb6,0xed,0xe6,0x80,0x15,0x5f,0xfd, +0xf5,0x83,0x7a,0xdf,0x28,0xdf,0xec,0xab,0x51,0x63,0x2e,0xbe,0xe0,0x7c,0x85,0x74, +0x1f,0x34,0xeb,0x1b,0xe6,0x8d,0xa9,0xcf,0x67,0xee,0x14,0x3e,0xaf,0xe3,0x1b,0x92, +0xaf,0xdc,0xbe,0x80,0xf9,0x41,0xc1,0xd8,0x28,0x3e,0x91,0x4f,0x11,0xd2,0xb7,0xdf, +0xed,0xcf,0xc2,0xdb,0x6f,0x4b,0x1c,0x59,0xbe,0x8d,0xc5,0xfb,0xda,0xd2,0x30,0xfc, +0xfc,0x3b,0x11,0xff,0x9f,0xe5,0xab,0xc7,0xf4,0x91,0x95,0xd8,0x3e,0x35,0x5f,0x95, +0xbe,0xbe,0xb,0xb7,0xb4,0xeb,0x57,0x6f,0xbf,0x76,0xc5,0xf0,0x19,0x93,0x77,0xfe, +0xfa,0x95,0x62,0xee,0xf4,0xaf,0xfa,0xd4,0x4f,0xcc,0xf3,0x4f,0x6d,0xbf,0xd7,0x57, +0x63,0xf9,0xd4,0x7c,0x25,0x8d,0xfa,0x7,0x55,0xd6,0xff,0x1,0x60,0xfa,0xcc,0xc9, +0x4f,0xed,0xfe,0x3,0x39,0xfb,0x3f,0xfd,0xfa,0x38,0xd2,0x7d,0xa,0x5d,0x8b,0x7b, +0x7d,0x98,0x9d,0x85,0xfe,0x29,0xa0,0x48,0xbe,0xd1,0x44,0xe9,0x1f,0x8,0x6c,0xfc, +0x0,0xe2,0x23,0xc1,0x39,0xbe,0x69,0xbe,0xa1,0x73,0xfc,0xd0,0xfb,0x97,0x5d,0x7d, +0xfc,0xc0,0x74,0x27,0xa6,0xef,0x81,0x63,0xe1,0x3d,0xc1,0xc3,0x8,0x3e,0x35,0x5f, +0x91,0x87,0xfd,0x83,0xef,0xda,0xbe,0x77,0x5d,0xf9,0x40,0xf7,0x39,0xc7,0x5f,0xbd, +0x7f,0x5e,0x4f,0xe8,0x5b,0x73,0xd5,0x87,0xe,0x22,0xf8,0xd4,0x7c,0x40,0x6e,0xef, +0x36,0xaf,0x7b,0x96,0x1c,0x68,0x97,0x6,0x42,0xc5,0x3d,0xdd,0x77,0xe0,0xc8,0x2f, +0xce,0xea,0xd7,0x6a,0x4a,0x5f,0x94,0xe3,0xab,0xe6,0x2b,0x22,0x81,0x8d,0x2a,0x27, +0x3f,0xa3,0x9,0x6a,0xf9,0x7c,0xc6,0x27,0x9b,0xf6,0x43,0xd1,0xda,0x6f,0x22,0x81, +0x26,0xcf,0x87,0x47,0x78,0x4d,0xf7,0x35,0x7c,0xf9,0x2a,0xe9,0xf9,0xd7,0xd2,0xde, +0xf5,0x19,0xcb,0xa7,0xe6,0x2b,0x49,0x2,0x75,0xbe,0x4f,0xfd,0x9b,0x9a,0x6f,0xc3, +0x97,0xaf,0xf4,0xeb,0x97,0xc6,0xbf,0x7e,0xd5,0x84,0xce,0xd6,0x5d,0x44,0xf4,0x69, +0xf9,0xea,0x2a,0xa8,0x6f,0x71,0xee,0xdf,0x94,0x9e,0xe9,0x43,0xbe,0x7c,0x85,0x74, +0x5f,0xfc,0xfe,0x4f,0xfb,0xab,0xac,0x83,0x51,0x8e,0xa3,0xf8,0x9c,0xf9,0xaa,0xa7, +0xe7,0xab,0xb1,0xe0,0xf3,0xf9,0xee,0x7f,0xd,0x5f,0xec,0xf1,0xc3,0xe5,0x23,0xa7, +0x51,0x7c,0xce,0x7c,0xa5,0x18,0xf9,0x8a,0xb5,0x1f,0x69,0x99,0x3e,0x7f,0xfd,0xc0, +0xf4,0xc5,0x1d,0x7f,0xc9,0x1f,0x3a,0x7c,0xf4,0x9f,0x45,0xf1,0x39,0xc7,0x5f,0xc5, +0x99,0x5f,0x34,0x9f,0x79,0x7d,0x4,0xfa,0x62,0xe7,0x97,0xbe,0xd3,0x17,0x3b,0x5f, +0x61,0xdd,0x37,0xb0,0xee,0xcf,0xd7,0xd4,0xfe,0x85,0x5f,0xbf,0x4a,0xe1,0xc3,0x28, +0x71,0x7e,0xd1,0x7d,0xb7,0x21,0x3b,0xff,0xa8,0xa0,0xf6,0xcf,0x34,0xeb,0xf6,0x9b, +0x16,0x53,0xe6,0x2b,0x2a,0xcc,0xae,0x5f,0xa5,0xf0,0xd1,0xf8,0xf9,0xea,0xcb,0xbb, +0x70,0x53,0xbb,0x7e,0xa1,0x9e,0xaf,0x4,0x61,0x76,0xfd,0x2a,0xa1,0x4f,0xbb,0x3e, +0x62,0xfa,0xb4,0xfa,0x55,0xbd,0x7f,0xa0,0xdf,0x5f,0xee,0xba,0xf2,0x95,0xed,0xdb, +0xf,0xe8,0xff,0x12,0xdc,0x7f,0x24,0xf0,0x79,0xf3,0xd5,0x3b,0xd4,0x5c,0xdf,0xbe, +0x56,0x64,0xf7,0xbf,0xbe,0xf1,0x23,0x1b,0x9f,0x3c,0x58,0x29,0x94,0x22,0xe4,0xab, +0x6b,0xfd,0x83,0xa2,0x2f,0x5f,0x61,0x69,0x27,0xb8,0xbe,0x81,0x92,0xd6,0x5f,0x62, +0xfb,0xb4,0x7c,0x25,0xed,0xaa,0xf9,0xc0,0x9b,0xaf,0xb0,0xd4,0xb2,0x7c,0xbe,0xfc, +0x12,0xc7,0x37,0x2e,0xa7,0xf1,0x69,0xf5,0x2b,0x35,0x5f,0x21,0x5f,0x3e,0xc0,0xd2, +0xe3,0x92,0xe9,0x1b,0xa6,0xf2,0xe9,0xe5,0x6,0xc3,0x37,0x75,0xff,0x69,0xf9,0x88, +0xee,0x47,0x68,0x3f,0xa4,0xe6,0x2b,0x8e,0x6f,0x64,0xbc,0x86,0x2c,0xe8,0xf8,0x46, +0xae,0x9f,0x2,0x68,0x5f,0xbf,0x34,0xb6,0x2f,0x30,0x5f,0xc9,0x57,0x1,0xc,0xac, +0x5f,0xc5,0xf3,0x95,0xed,0xfb,0x37,0x57,0xa5,0x4a,0xf3,0x5d,0x11,0xdc,0xbf,0x3b, +0x16,0x22,0xe6,0x2b,0x6c,0xce,0xb9,0x73,0xeb,0x57,0x49,0x7d,0xae,0xcf,0x99,0xe6, +0xfb,0xba,0xe8,0xf6,0x91,0x99,0xf9,0x8a,0x98,0x3e,0x3c,0x62,0xbe,0x7d,0x5e,0xff, +0x3c,0x7e,0xae,0xae,0x6d,0x53,0x9f,0xc2,0xf7,0x44,0x3f,0xbe,0x33,0x7c,0xfe,0x7c, +0x35,0x35,0x7d,0xe8,0x9,0x8,0x1b,0xdf,0x50,0xf7,0x79,0xba,0x9d,0xca,0xa7,0xf0, +0x7c,0xca,0xcc,0x7c,0x75,0xce,0x7c,0x93,0x52,0xb8,0xef,0xa5,0xda,0xad,0x28,0xbe, +0x76,0x31,0xd4,0x27,0x44,0xf6,0x9d,0x9d,0xea,0x3e,0xed,0x3d,0x8b,0xb3,0xd6,0xb7, +0x1b,0xbe,0x6,0x88,0x36,0xff,0xe1,0xf0,0x9d,0xa7,0xf0,0x19,0xed,0x77,0x7b,0x42, +0x23,0xe5,0x17,0xd4,0x7d,0x2d,0xa1,0x6f,0x8c,0x1c,0xbe,0x6b,0x9e,0xab,0x1a,0xcf, +0xf0,0xb5,0x25,0x29,0x9a,0x6f,0xfc,0xdc,0x6b,0x1d,0x10,0xfb,0xf8,0x4e,0x2f,0xa9, +0x97,0x64,0xd5,0xe1,0xbb,0xca,0xf1,0x29,0xe3,0xa7,0xad,0xe,0x43,0xcb,0x57,0xdd, +0x5d,0x8,0xd9,0xf5,0xb,0xda,0x2f,0xd3,0x48,0xf9,0xa,0xe1,0x37,0xa2,0xf9,0xa8, +0xb6,0x1c,0x97,0x6d,0x40,0xa8,0x39,0x61,0xc3,0xe1,0xfb,0x5a,0xd9,0xfd,0xa,0x19, +0xcd,0x47,0xe0,0x9b,0xb0,0xe7,0xc8,0x57,0x3f,0xec,0x1f,0x74,0x58,0xff,0x7,0xc0, +0xb7,0xa3,0xe5,0x2b,0xd5,0x17,0xf1,0xf8,0x6a,0x6f,0x48,0x95,0x1d,0x6,0x78,0xe0, +0x1e,0x3f,0xa6,0x25,0xcf,0xf8,0xa1,0xf9,0x14,0x3b,0x5f,0x21,0xd3,0x67,0xe6,0x97, +0x1d,0x96,0xaf,0x4,0x10,0x96,0xaf,0x10,0xbe,0x17,0xcd,0x37,0xd5,0xce,0x3f,0x6b, +0x3,0xcc,0x55,0xd5,0x37,0x74,0xfb,0xe4,0xa2,0x77,0x7c,0xbb,0x65,0xfb,0xb4,0xf9, +0xc1,0x97,0xfb,0x7,0x8f,0x7c,0x3e,0x2c,0x89,0xdb,0x61,0xe3,0x2f,0xc2,0xf5,0x5a, +0x24,0xdf,0x29,0x75,0xbc,0x1c,0x50,0x3b,0xc7,0xd5,0xfb,0x5e,0xb3,0xca,0xa4,0xfa, +0xb8,0xd3,0x85,0x62,0xb5,0x82,0xed,0x7c,0x40,0x5f,0xde,0x6d,0x3e,0xe2,0xe4,0x2b, +0xf1,0x56,0x58,0xbe,0x8a,0x3c,0xbe,0x41,0x67,0xfb,0x11,0xc5,0x11,0x14,0x82,0xdb, +0xef,0x75,0xcb,0xa7,0xd5,0xaf,0xfa,0x60,0xa3,0xc2,0xc9,0x57,0x3b,0xec,0xf8,0x22, +0x9e,0x8f,0xb4,0xf5,0x2d,0x42,0x23,0x5e,0xbf,0xec,0xfc,0xe3,0xf9,0x38,0xe7,0x5f, +0xb5,0x82,0x1c,0xf5,0xab,0xcb,0xa0,0x59,0xe0,0xe4,0xab,0xbe,0xe5,0xe3,0x1d,0x5f, +0x2,0xaa,0xd1,0xda,0x4f,0xef,0xff,0xac,0xd,0x44,0x6b,0xda,0x62,0x35,0xb7,0xcf, +0xf3,0xa,0x28,0xcd,0x57,0x79,0x4,0xed,0x7c,0x5,0xfb,0xa0,0xe,0x39,0xf9,0xaa, +0xc7,0x7c,0x90,0x77,0x7d,0x10,0x50,0x89,0xe1,0x23,0x56,0x79,0xb3,0xac,0xbd,0xb8, +0xd4,0xe5,0xf3,0xde,0xa,0x8,0xa,0xaa,0xfc,0xe8,0x5,0x47,0xbe,0xea,0x19,0xbe, +0x13,0xec,0xce,0x57,0x5f,0x66,0x3e,0xc0,0xeb,0x5f,0x8,0x78,0x25,0x9a,0x6f,0x52, +0xf6,0x8c,0xbf,0x10,0xcd,0xf0,0x5,0xe5,0xab,0x53,0xa3,0x7e,0xc5,0xf2,0xd5,0x67, +0xec,0xfe,0x6d,0x83,0xd7,0x3f,0x13,0xfd,0x46,0x34,0x82,0x4f,0x2,0x69,0x7c,0xce, +0x7c,0x65,0xe4,0x3,0xb3,0xbe,0x81,0x11,0xa,0xcd,0x57,0xa4,0x4d,0xa3,0xf9,0xfa, +0xce,0x7c,0x35,0xfd,0xd7,0x31,0x7d,0xce,0xf1,0xf7,0x38,0x96,0xf,0x24,0xf1,0xe1, +0x56,0x72,0xdf,0x99,0xe1,0xd3,0xeb,0x2f,0xb3,0xf3,0x95,0x4,0x60,0x34,0x1f,0xf0, +0xfa,0x66,0x5e,0x1f,0x41,0xed,0xd7,0xd5,0xf3,0x95,0x1c,0x2d,0xbf,0x48,0x20,0xe2, +0xfa,0x3a,0x9f,0x4f,0x2e,0x25,0xf4,0xed,0xc6,0xa9,0x5f,0x9d,0x80,0x71,0x42,0x9f, +0xb7,0x7f,0xe,0xbf,0x3e,0x1c,0xf3,0x83,0x38,0x4e,0xfd,0x2a,0xfa,0xf8,0x6,0xa8, +0xfb,0xfa,0xe0,0xfb,0x84,0xc0,0xfa,0x95,0x35,0x3f,0x88,0x3,0xea,0x57,0x30,0xd5, +0xfd,0x25,0xaf,0xbe,0xc1,0xf1,0x55,0x3,0xeb,0x57,0x48,0xf5,0x21,0xdf,0xfc,0xa0, +0x9a,0xaf,0xd8,0xfd,0x51,0x27,0xd5,0xfd,0x39,0xaf,0x72,0x40,0x5c,0xf5,0x97,0x30, +0x9f,0x96,0xaf,0x24,0x97,0xcf,0xae,0x5f,0xb1,0xfb,0xdf,0x47,0x99,0xd7,0xaf,0xa2, +0xfb,0xb4,0x7c,0xf5,0x70,0xb7,0xd9,0x9,0xab,0x5f,0xc1,0x54,0xf5,0xa1,0x74,0xbe, +0x90,0xfa,0xd5,0x3c,0x7c,0xf2,0xa5,0xa0,0x72,0x60,0x35,0x7e,0xfd,0x8a,0x9d,0x7f, +0x90,0x77,0x7c,0x93,0xd5,0x4f,0x15,0x2a,0x7f,0x83,0xef,0xb3,0xf6,0x3b,0x8b,0x5c, +0xbf,0xfa,0x14,0x86,0xe5,0xab,0x64,0x3e,0x12,0xe8,0x63,0xd,0x1c,0x32,0x3f,0x78, +0xe8,0xce,0x57,0x4f,0xc3,0xb0,0xfe,0x25,0xd9,0xfa,0x1c,0xea,0xf0,0x89,0x57,0x15, +0xd1,0xf7,0x7,0x91,0x10,0x9c,0xaf,0xa0,0x3b,0x5f,0x59,0xf5,0x2b,0xc8,0x9f,0x5f, +0x98,0xa6,0xf4,0xdd,0xfc,0xfc,0xcc,0xe1,0x33,0x5f,0x78,0xe0,0xf5,0x39,0xf3,0x15, +0x70,0xe7,0x97,0x27,0x30,0x7c,0x7e,0xe6,0x3c,0x9d,0x8f,0xb4,0xa6,0x67,0x7f,0x61, +0x2f,0x36,0x1,0xfc,0xf6,0x73,0x8e,0xbf,0x7b,0x6e,0x5f,0x78,0xfd,0x2a,0xfd,0xf1, +0x6d,0x29,0x6f,0xfc,0x10,0x79,0x7d,0xf2,0x8c,0xf5,0xed,0x91,0xf3,0x55,0x6,0xbe, +0xab,0x6f,0xb4,0xec,0x27,0xb6,0x3a,0xb3,0xdb,0xcf,0xa8,0x5f,0x45,0x9e,0x7f,0x8b, +0xbf,0xfe,0xca,0xed,0x7b,0x3c,0xfa,0x89,0xc3,0x17,0x70,0xfe,0xf9,0xeb,0x57,0x84, +0x46,0xf6,0xd5,0xd3,0xb5,0x9f,0xea,0x3,0xbc,0xf3,0x4f,0xab,0x5f,0x21,0x4e,0xbe, +0x32,0xea,0x57,0x75,0x1a,0x71,0x7e,0x90,0x24,0x5a,0x7f,0xa0,0xfb,0xf4,0xdb,0x61, +0xae,0x4f,0x36,0xeb,0x43,0x43,0x4e,0xbe,0x32,0xea,0x57,0x35,0xbf,0x2f,0xa0,0xff, +0x4b,0xb4,0xfe,0x4a,0xf7,0xe9,0xe5,0x84,0xd6,0xa8,0xd7,0x12,0x5d,0x1d,0x9d,0xa3, +0x7e,0x75,0x10,0x98,0xaf,0x1a,0x7e,0x5f,0xc0,0xf8,0x11,0x7f,0xfd,0xb,0xf3,0xe9, +0xe5,0x98,0x9d,0xab,0xbd,0x96,0xdd,0xbf,0xb4,0xcb,0xae,0xfa,0x15,0xa,0xcc,0x57, +0x3f,0xf2,0x5f,0x1f,0x1,0xe3,0x6f,0x1c,0x9f,0xdd,0x19,0x7c,0x63,0xd6,0x8b,0x71, +0xf4,0xfa,0x95,0xa3,0xfe,0x42,0xfb,0xbb,0x4d,0xe8,0x5f,0x7f,0xe5,0xf0,0xf9,0xf2, +0xcb,0x38,0xee,0xfa,0x2b,0xca,0x69,0xbf,0xa0,0xff,0x14,0xbd,0x7e,0x85,0x1c,0xf9, +0xaa,0xf,0x36,0x42,0x9f,0x5f,0xa0,0xbc,0xf5,0xed,0xf1,0xda,0x8f,0x72,0xce,0xbf, +0x40,0x9f,0xa7,0x7e,0x85,0x76,0x40,0x13,0x2c,0xd6,0x37,0x15,0xc2,0x7d,0x95,0x47, +0xc8,0x51,0xbf,0xe2,0xaf,0x6f,0x9f,0xed,0x8b,0x71,0xfd,0x7a,0x7c,0x9e,0xcf,0xdf, +0x95,0x5c,0xf9,0x4f,0xab,0x5f,0x55,0xed,0x7c,0x75,0xed,0x69,0x50,0x2f,0x84,0x3d, +0x3f,0x13,0xe4,0x8b,0xd1,0xff,0x85,0xfb,0xb4,0x99,0x5c,0x71,0x76,0xfd,0xca,0x98, +0x1f,0x54,0x22,0xfb,0x62,0x8c,0x1f,0xb3,0x7d,0x60,0x76,0xfd,0xca,0xc8,0x57,0x67, +0xd1,0x7d,0x1b,0x19,0xfa,0x22,0xd4,0x37,0x7e,0xa5,0xfb,0x9e,0x78,0x7c,0x1,0xfb, +0xb7,0xc7,0xcb,0xf7,0xe1,0x3e,0x10,0xc9,0x77,0xf6,0xb1,0xee,0x53,0x16,0xef,0x1b, +0x6e,0x47,0x6a,0x3f,0x3d,0x1f,0xdc,0x9e,0xbf,0xcf,0x78,0x43,0xfc,0x9e,0x67,0xa5, +0x98,0x18,0xc9,0xd7,0x96,0x3c,0xbe,0xa0,0x4f,0xa,0x9f,0xf1,0x86,0xf8,0xd6,0xe9, +0x30,0x68,0xfc,0xf0,0xd4,0xaf,0x9a,0xbb,0x10,0x4,0xe6,0x2b,0xfa,0x79,0xb1,0x98, +0xb9,0x4f,0x7b,0x43,0xfc,0xda,0xf1,0x81,0x85,0x10,0x3,0x7d,0xda,0xfc,0xe0,0xf3, +0xfd,0x83,0x6d,0x3b,0x5f,0x79,0x7d,0xa3,0x9,0xca,0xd2,0xa7,0xf5,0x69,0xfa,0x1b, +0xe2,0x5,0xfb,0xf8,0x42,0x10,0xe2,0x1b,0x4d,0x5a,0xfd,0x83,0x5b,0x76,0x7e,0x69, +0x2d,0xc2,0x27,0xb5,0x9d,0x3e,0xed,0xfa,0x5d,0x17,0x2,0xeb,0x57,0xce,0xe7,0x7, +0x39,0x3e,0xc4,0xf5,0xc5,0xab,0xbf,0xf8,0x7c,0xc0,0xeb,0x13,0xc4,0xc0,0xfa,0x95, +0xf5,0xfc,0x20,0x2f,0x5f,0x65,0xec,0x93,0x4b,0x2e,0x9f,0x5c,0x9a,0xe1,0xb,0x7e, +0x7e,0xd0,0xbe,0x3e,0x60,0x86,0x3e,0x4,0x99,0x6f,0x4d,0xf3,0x21,0x38,0xbb,0xfd, +0xc2,0xf3,0x15,0x1d,0x51,0x10,0xf2,0xf3,0xe2,0xfa,0xb4,0xe0,0xae,0xf9,0x7e,0x50, +0x6c,0x69,0x3e,0x23,0xc7,0x43,0xf0,0x83,0x62,0x80,0x4f,0xcb,0x57,0x3b,0xa0,0x1e, +0xec,0x23,0xa3,0xd0,0xed,0x8a,0xe2,0xfb,0xb6,0xa9,0xf6,0x86,0xf8,0x1f,0x14,0xf7, +0xc,0xdf,0xb6,0x5e,0xa2,0xfe,0x41,0xd1,0xb8,0x3e,0xa6,0x77,0x39,0xf5,0xab,0x96, +0xe1,0xd3,0xd7,0x77,0xf2,0x7c,0x42,0xc6,0x3e,0xed,0xf3,0x83,0x22,0xef,0x97,0x14, +0x37,0x42,0xea,0x57,0xd8,0x59,0xbf,0xb2,0x3e,0x57,0x9,0xf7,0x95,0x99,0x91,0xd7, +0x5f,0xc5,0xf2,0xd1,0x46,0x48,0xfd,0xa,0x3b,0xeb,0x43,0x33,0x4f,0xf4,0xa8,0xeb, +0xaf,0xd2,0xf9,0x9c,0xe3,0x2f,0x8a,0xe7,0x8b,0xb8,0xfe,0xca,0xfd,0x19,0x14,0x5c, +0x20,0xcf,0x2f,0x29,0xbd,0x23,0xcc,0x7c,0x7e,0x30,0xb2,0xaf,0x1,0x92,0xec,0xff, +0xe2,0x1,0x79,0x7e,0x79,0x6f,0x56,0xfb,0xdd,0x8e,0xec,0x7b,0x6d,0xe,0x3e,0x42, +0x43,0x7c,0x7a,0x7d,0x57,0x8a,0xe8,0x8b,0xbc,0xfe,0x2a,0xd6,0xf1,0x55,0xf4,0xfa, +0xda,0xe3,0xcb,0x4f,0x15,0x39,0xf5,0x2b,0x63,0x7d,0x7b,0x25,0x62,0xfb,0x45,0x5e, +0x7f,0xe5,0xb9,0x40,0xdc,0x20,0xcf,0x2f,0xe5,0x67,0xb4,0xfe,0xef,0xa5,0x9,0xa1, +0x9c,0xfa,0x95,0xee,0x3,0xd1,0x7d,0x89,0x8e,0xef,0xb6,0x1b,0xe4,0xf9,0xa5,0x31, +0x7e,0xb8,0x7c,0xa3,0x89,0xe9,0x33,0xf3,0xcb,0xa3,0xa8,0xbe,0x7b,0x49,0x7c,0x44, +0x70,0x81,0x3c,0xbf,0xf4,0xfb,0xb4,0xf5,0xed,0x92,0xcb,0xf7,0x6e,0xb4,0xfb,0x8f, +0xc8,0xeb,0xaf,0xdc,0x9f,0x33,0xba,0xae,0x7f,0xc3,0x2f,0x19,0x9b,0x6e,0xb9,0x7f, +0x69,0xd6,0xaf,0xc8,0xe7,0x97,0x9f,0x2a,0xd9,0xf9,0x80,0xbf,0xbe,0xdd,0xe3,0xcb, +0xea,0xfd,0x5b,0xc8,0x75,0xc1,0x42,0x44,0x39,0xed,0x47,0x9e,0xee,0x13,0x47,0xbe, +0xa,0x7a,0x7e,0xd0,0xe5,0xf3,0xbd,0x7f,0x8b,0xb4,0xe5,0x24,0x3e,0xf7,0x5,0xb, +0x7d,0xfd,0xb3,0xee,0x1b,0x49,0xc4,0x91,0xaf,0x82,0x9e,0x1f,0x74,0xd5,0xf,0x7c, +0xef,0xdf,0x22,0xa0,0x2a,0xd0,0xb4,0xfd,0x1f,0xa4,0xbc,0xf6,0x53,0x9e,0xd8,0xbe, +0x90,0xe7,0x7,0xbd,0x3e,0xf7,0xfb,0xb7,0x62,0xac,0xbf,0x8a,0xe1,0x9b,0xbe,0xae, +0xd5,0xef,0x9f,0x4c,0x9e,0x72,0xe6,0x2b,0x73,0x7e,0x30,0xd0,0xc7,0x7d,0xff,0x56, +0x42,0x1f,0x2e,0xb9,0x7c,0xee,0x5f,0xaa,0x5f,0xde,0x9,0xae,0x5f,0xb9,0x7d,0x72, +0x69,0xad,0x64,0xfa,0xb8,0xef,0xdf,0x22,0xe0,0x3f,0x24,0xba,0x3e,0x2a,0xee,0xeb, +0xa3,0xe2,0x39,0xbe,0x3b,0xc1,0xf5,0x2b,0xb7,0xf,0x4b,0x2d,0xe8,0xf0,0xf9,0xde, +0xbf,0x45,0xda,0xc3,0x24,0xe7,0x1f,0xac,0xba,0x7c,0xee,0x5f,0x52,0xed,0x9,0xd7, +0x88,0xfb,0xaf,0x71,0x7c,0xae,0xf7,0x6f,0x91,0xa8,0xeb,0x9b,0xe2,0xf9,0xea,0xd1, +0x7d,0x22,0xf3,0x71,0xdf,0xbf,0x25,0x25,0xf4,0x21,0xb7,0xf,0x25,0xf6,0x8d,0x0, +0x3b,0xff,0xb8,0xef,0xdf,0x9a,0x8f,0x8f,0xe0,0xa8,0xbe,0xd0,0xe7,0x67,0x68,0x8c, +0xf5,0x57,0x7c,0xdf,0x4a,0x11,0x43,0x8e,0x4f,0xd1,0x7d,0x8d,0x4f,0xd7,0xca,0x33, +0xdb,0x2f,0xec,0xf9,0x99,0x14,0xe3,0x9b,0x71,0xb3,0x4f,0xbe,0x64,0xf8,0xcc,0x5f, +0xda,0xf9,0xea,0x39,0xcd,0xf7,0xc7,0xdd,0x16,0x98,0xe9,0xb,0x7b,0x7e,0x26,0xb9, +0xcf,0x28,0x68,0x50,0xa5,0xd6,0xed,0x6a,0x3e,0xb9,0xc4,0xab,0xff,0xbd,0xd8,0xe8, +0xc2,0x99,0xbe,0xb0,0xf5,0x7,0xc9,0x7d,0xec,0x63,0xfa,0xf8,0xf5,0xc9,0x17,0x1b, +0x78,0xf6,0xf5,0x11,0xb6,0xfe,0x20,0x5d,0xfd,0xca,0xf0,0xfd,0xba,0x68,0xf9,0xdc, +0x5b,0x8a,0xa,0xe4,0x78,0xa6,0x6f,0xf6,0xfb,0x21,0x52,0xfb,0x1c,0xed,0x47,0xdc, +0xed,0x47,0x9e,0xae,0xce,0x6e,0x3f,0x67,0x3e,0x10,0x17,0xec,0x1b,0x55,0x67,0x9f, +0x7f,0xb3,0x7c,0x29,0xea,0xa7,0xb3,0x7c,0xca,0x4,0xcf,0xbe,0x7e,0x9d,0x3e,0xde, +0xf5,0x9b,0xda,0xf7,0x16,0xcf,0xa7,0xd7,0xaf,0x94,0xc9,0x94,0xd7,0xff,0x9d,0x4, +0xe6,0xab,0xf4,0xfb,0x5f,0xf9,0x3e,0xf7,0x6f,0xbc,0xc8,0xf3,0xe1,0x90,0xfa,0x8b, +0x44,0xc7,0xf7,0x9f,0xc7,0xbc,0x7c,0xe5,0x1c,0x3f,0x84,0xdb,0xc6,0x7b,0xb9,0xe2, +0xad,0xbf,0xa,0x1a,0x4d,0x7c,0xc7,0x37,0xac,0x3e,0x44,0x61,0xb3,0x87,0x78,0xf9, +0xc5,0xb9,0xfe,0xe0,0xe6,0x6b,0xa8,0x6e,0xf8,0xce,0x17,0xef,0x6b,0x18,0x63,0x6, +0x27,0x5f,0x39,0x7c,0xc6,0xcd,0x69,0xca,0xe3,0x1b,0xe4,0xbb,0x1b,0x32,0x3f,0xa8, +0xe,0x87,0xa,0xe0,0xe4,0x2b,0xd7,0xfb,0xb7,0x5e,0x7a,0x8d,0xa4,0xf7,0xad,0x9b, +0x3b,0x4e,0xfb,0x7d,0xd5,0xb0,0xf6,0x3b,0x41,0x8a,0xe8,0xc8,0x57,0xdc,0xe3,0xfb, +0xd2,0xed,0x9b,0x96,0x6f,0x23,0x73,0x1f,0x9,0x5b,0x7f,0x45,0xc9,0x75,0xe5,0x96, +0x23,0x5f,0x1,0xde,0xf5,0xf1,0x6a,0xe5,0x23,0xcb,0x57,0xcf,0xdc,0x67,0xd4,0xaf, +0xc4,0x6b,0xd8,0xaa,0x29,0xbf,0x2b,0xa3,0x4e,0xa1,0xa0,0xef,0x2f,0xaa,0x9e,0x9d, +0x53,0xe8,0xc8,0x57,0x22,0x2f,0x5f,0xbd,0x5a,0xb1,0xce,0xbf,0x44,0xeb,0xf,0x5c, +0xbe,0x7d,0xaf,0xcf,0xa8,0x5f,0xbd,0x2c,0xd5,0xac,0x5b,0xd9,0x4a,0xb5,0xda,0xa8, +0xd5,0xf4,0xe7,0x7b,0xdc,0xd7,0x87,0xb9,0xa7,0xb5,0x37,0x5f,0xbd,0xaa,0x5d,0x1f, +0xb1,0xf7,0xbf,0xa,0xf0,0x6d,0x70,0xc7,0xf,0xfa,0xd2,0xa4,0x59,0xb7,0x7c,0x95, +0x46,0xd5,0xf0,0x51,0x77,0xff,0x82,0x26,0xdc,0xf1,0xad,0xaa,0xf5,0x2f,0xbb,0xc9, +0xd7,0xbf,0xb8,0x7c,0x97,0x2,0x7c,0xc4,0xf2,0x11,0x8,0x27,0xb8,0x56,0x33,0xe6, +0x67,0x9c,0xfd,0x33,0x46,0xbf,0x2f,0x72,0x7d,0x5a,0xff,0xbc,0x9e,0xdc,0xd7,0xe6, +0x2d,0xb9,0x32,0x2a,0xb2,0x56,0xbe,0x1a,0x7d,0xd4,0xb5,0x7c,0x63,0xf8,0x4,0x17, +0x56,0x9d,0xf3,0x83,0xa1,0xf9,0x2a,0xe1,0xfe,0x57,0xf6,0x7,0x70,0xda,0xcf,0xbe, +0x15,0x37,0xf3,0xd5,0xe4,0xd8,0xf2,0xd1,0xca,0xef,0xb0,0x50,0x3,0xf1,0xf2,0x4b, +0x8a,0xf6,0x3,0x9c,0xf3,0xcf,0xeb,0x1b,0x39,0x7c,0xb0,0xd2,0xa8,0x9,0x35,0x31, +0x9e,0x6f,0x37,0x23,0xdf,0x3e,0xd7,0xa7,0x4c,0xa4,0xd3,0x9a,0xe5,0xab,0x56,0x9b, +0xb3,0x7c,0xbe,0x7c,0x75,0x94,0x7c,0xfd,0x95,0xcb,0x47,0xf9,0x3e,0xe4,0xe8,0xff, +0x5e,0x97,0xd1,0x81,0x50,0x10,0xc3,0xf2,0xd5,0x46,0xfa,0xfd,0xaf,0x62,0xf9,0x5c, +0xbf,0x2b,0x98,0x5f,0xd0,0xfa,0x67,0x38,0xda,0xd5,0x1f,0x4a,0x35,0x9f,0x9f,0x61, +0xfd,0x33,0xa,0x7a,0x3e,0xa0,0xbe,0x0,0x9f,0x68,0x8e,0x32,0xda,0xf8,0x36,0xfc, +0x78,0xc7,0xd8,0x3c,0xd4,0xc8,0x7,0x65,0xe6,0xb,0x7a,0xbe,0x62,0x23,0xa9,0x2f, +0xa0,0x34,0xcd,0xf3,0x39,0xc7,0x5f,0xd5,0x67,0xc,0xba,0xc6,0xf3,0x3d,0xac,0xfd, +0xb8,0xcf,0xa7,0x24,0xcd,0xf7,0xc9,0x7d,0xa,0x3d,0xfe,0x89,0xe8,0xf0,0x89,0x73, +0xf5,0x29,0xa4,0x94,0xc0,0xb7,0x6f,0xfb,0x46,0xc0,0xf2,0xa5,0x7f,0x7e,0x86,0xe3, +0x53,0x60,0x4c,0x1f,0xa6,0xa3,0xd7,0x64,0xcb,0xa7,0xe6,0x2b,0xe6,0x3,0xe9,0x9f, +0x9f,0x49,0xec,0x3b,0xc7,0xaf,0xcb,0xb0,0x50,0xd0,0xea,0xe3,0x48,0xf5,0x11,0xbb, +0xfd,0xec,0x7c,0x5,0xd2,0xef,0x2f,0xc5,0xf1,0xd1,0x48,0xbe,0xc9,0xf7,0xd5,0x80, +0x55,0xab,0x69,0xf3,0xb,0x3,0xd5,0xe7,0xb8,0x3e,0x30,0xb4,0x7c,0xe9,0xf7,0xe7, +0x4a,0xe3,0x53,0x7,0xb8,0x9a,0xb1,0xff,0x95,0x34,0x72,0xf4,0x2f,0xc8,0x7a,0x7f, +0x72,0x6,0xfb,0x9b,0xf1,0x7c,0x20,0x8a,0x4f,0xfa,0xab,0xa,0x6c,0xd6,0x6a,0xdf, +0x35,0x7d,0x76,0xff,0x3c,0xcb,0x97,0xb4,0xfe,0x62,0xfb,0xc4,0x68,0xbe,0xd7,0x61, +0xb3,0xb0,0x7a,0x3d,0x6a,0xbe,0xca,0xd0,0x27,0x44,0xf3,0x9,0x15,0x35,0x1f,0x54, +0xe3,0xe5,0x97,0x2c,0x7c,0x84,0x46,0x3c,0xbe,0xc9,0x7c,0x49,0xeb,0xa7,0xcc,0x37, +0xfd,0x27,0x91,0xc6,0x5f,0xa9,0x5b,0xa9,0xd6,0x66,0xf9,0x52,0x3d,0x9f,0x1c,0x6b, +0x7c,0x23,0xde,0xfd,0xaf,0x26,0x5d,0x35,0x60,0x9,0x7a,0xff,0x87,0xa3,0xd7,0xaf, +0xe6,0xe6,0x9b,0xf2,0xf6,0x97,0x32,0xf3,0xd5,0x29,0x85,0xb0,0xb0,0xb,0x66,0xd4, +0xaf,0xd8,0xdf,0x4a,0xb8,0xfe,0x6a,0x86,0xef,0xdc,0xeb,0xc3,0xd4,0xca,0x57,0xc7, +0x74,0xf8,0x9,0xde,0x1,0xfe,0xfa,0x90,0xc8,0xdd,0xff,0x25,0xd9,0xfa,0xab,0x59, +0xc7,0x57,0x9,0x1b,0x7f,0x87,0x1f,0x2b,0x3c,0xdf,0x8f,0x79,0xf9,0x25,0xee,0xfa, +0xab,0xed,0xc,0x7c,0xc7,0x3f,0x51,0x44,0x8e,0xef,0xad,0x0,0x5f,0x9c,0xf5,0x25, +0x56,0x9a,0x4a,0xe9,0xdb,0xb7,0xf3,0x55,0x8f,0x5b,0xbf,0xb2,0x7d,0xb1,0xd6,0x5f, +0xc9,0x42,0x34,0x1f,0xe,0xcf,0x57,0x8a,0x6c,0xe7,0x2b,0xdb,0xc7,0xbf,0x3e,0x62, +0xad,0xbf,0x1a,0xd3,0x64,0xbe,0x73,0xbc,0xbf,0xf7,0xa8,0x50,0xd8,0x64,0x3e,0x62, +0xe7,0xab,0xa7,0x43,0xf7,0xd7,0x8b,0xb9,0xfe,0x6a,0x8f,0xfd,0x8b,0x35,0x47,0x6b, +0xdd,0x2e,0x6a,0xfb,0xe7,0xc8,0x41,0xbe,0xc9,0xf7,0x9b,0x2d,0x35,0xbf,0x88,0xcc, +0x67,0x5f,0x1f,0x33,0xf6,0xd7,0x8b,0xb9,0xfe,0xca,0x62,0x15,0x7c,0x7d,0xac,0xb6, +0xff,0xd0,0x58,0x8,0xcc,0x57,0xf5,0x96,0x9d,0xaf,0x24,0x47,0xff,0x32,0xe3,0xf9, +0xe4,0x78,0xeb,0xaf,0xac,0xcb,0x83,0x58,0x2b,0xa5,0xda,0xcc,0xa1,0xed,0xdf,0xa4, +0x3d,0xbd,0x1a,0x30,0xfe,0xd6,0x45,0x35,0x5f,0x19,0xfb,0x8b,0x4a,0x8e,0xfe,0x79, +0xe6,0xfe,0x7a,0xb1,0xd6,0x5f,0x91,0x95,0xe8,0x1f,0xaf,0x6f,0x4f,0xcd,0x57,0xae, +0xf5,0x57,0x91,0xf2,0x55,0xbc,0xf1,0x2d,0x4d,0xfb,0x29,0x6a,0x7e,0x41,0xb1,0xf3, +0xb,0x69,0xf,0x4,0x3a,0xff,0xf3,0x4f,0xf5,0xb5,0x92,0xf9,0x80,0x10,0xc7,0xb7, +0x1f,0xed,0xfa,0xe5,0xe4,0xab,0x66,0xab,0x99,0x24,0x5f,0x11,0xb0,0x16,0x27,0xbf, +0x1c,0xfa,0xfa,0x3f,0xec,0x2c,0x1,0x29,0xcc,0x27,0xfb,0xf2,0xd5,0xfe,0x5e,0xc3, +0xc8,0x57,0xa,0xe,0xf0,0xed,0xf1,0xf7,0xbf,0x8a,0xe5,0x93,0x23,0xfa,0x70,0x70, +0xbe,0xd2,0xf7,0x9f,0x54,0xcf,0x2a,0xc1,0x18,0x3f,0xae,0x14,0x8b,0x61,0xf7,0xe7, +0x44,0x7f,0x10,0x28,0xb2,0x6f,0x2a,0x44,0xf3,0xa1,0xe0,0x7c,0x65,0xec,0x8f,0x59, +0xd9,0x11,0xcc,0xf1,0xd7,0x78,0xae,0x27,0x28,0x5f,0x91,0xb6,0x12,0xc7,0xe7,0xcf, +0x7,0x7c,0xdf,0x38,0x78,0xfc,0x7d,0xa2,0xef,0x2f,0x55,0x69,0xf9,0x7c,0x9b,0xdc, +0xfd,0xeb,0x40,0x2c,0x9f,0x3f,0x5f,0x5,0xb4,0x9f,0x30,0xcb,0xd7,0xf4,0xf9,0x9a, +0x3c,0x9f,0x4,0x70,0xba,0x7c,0xcf,0xf7,0x85,0xac,0x1f,0x1f,0xe9,0xfb,0x5f,0xbd, +0x52,0x33,0x7d,0x9f,0x5f,0x66,0x3e,0xee,0xfe,0x89,0x8b,0xf7,0xd,0xf4,0xfd,0xaf, +0x60,0xc3,0xbc,0x3e,0xae,0x5a,0xed,0xc7,0xdd,0xbf,0xf8,0x64,0x3e,0x3e,0x7d,0x7f, +0x6,0x54,0x72,0xac,0x44,0xfb,0xf5,0xdd,0x4a,0xa1,0x0,0x59,0xff,0x2,0xa0,0xb9, +0x3e,0x1b,0x2b,0xf6,0xf1,0x9d,0xcb,0xfd,0x9b,0xcb,0x67,0xf5,0xcf,0xb2,0x3e,0xbf, +0x0,0x1d,0x2b,0xf9,0x1a,0xd,0x35,0xbf,0x74,0x6c,0xdf,0x8f,0xca,0x5e,0xdf,0xfe, +0x5c,0xee,0x7f,0x5d,0x3e,0xd7,0xf8,0x46,0x46,0x13,0xcc,0xf1,0x19,0x7f,0x1d,0x8a, +0xbe,0xf6,0x9b,0x4b,0xfd,0xc0,0xed,0x73,0xe5,0x3,0x32,0x72,0xd6,0x3e,0xaa,0x8, +0xd7,0x6a,0xf6,0xfe,0xa2,0xac,0x7f,0xc6,0xd3,0x62,0x31,0xb3,0xfa,0x8b,0xf8,0xe1, +0x5a,0x78,0xff,0x37,0x70,0xad,0xbf,0x72,0xf9,0xee,0xde,0xad,0x15,0x56,0xbd,0xfb, +0x8b,0x66,0x5c,0xbf,0x12,0x1b,0xd6,0x4e,0x2a,0x11,0xda,0x8f,0xbe,0xe4,0xf4,0x9, +0xa2,0x9a,0xf,0x2a,0xf3,0xad,0x5f,0x81,0x4a,0x17,0x45,0x3f,0xff,0xe8,0x4b,0xce, +0xf3,0xaf,0xda,0x50,0x7d,0x85,0xd8,0xbe,0x58,0xf5,0x53,0x60,0xed,0xb7,0x3a,0xeb, +0xfa,0xd5,0x7d,0x3b,0xce,0xeb,0x57,0xf7,0xc1,0xd8,0xf9,0x2a,0x96,0x4f,0x82,0x38, +0x5a,0xff,0x67,0x3c,0x3f,0x28,0x3a,0xfb,0xbf,0xf,0xef,0x56,0x5,0xa3,0xff,0xb, +0xda,0x9f,0x1,0xa5,0xde,0xff,0x2a,0xb2,0x8f,0xb3,0xfe,0x4a,0xb4,0xf2,0x95,0xfe, +0xfc,0xf9,0xe0,0xae,0x95,0xaf,0x80,0xe9,0x1b,0xf2,0xe7,0x3f,0x62,0xac,0xbf,0x7a, +0x12,0xd5,0xc7,0x59,0xdf,0x4,0xac,0x7c,0xa5,0xef,0x8f,0x54,0x69,0x88,0x66,0x3e, +0x30,0x96,0xfe,0x7a,0xdf,0xbf,0x65,0xfb,0xce,0xe3,0xf8,0x66,0x5c,0x1f,0x21,0x3e, +0x3b,0xbf,0x78,0x7d,0xb7,0x4c,0xdf,0x1,0x7f,0xfe,0x2d,0xc6,0xf1,0xc5,0x68,0x46, +0xff,0xc2,0x7c,0x24,0x64,0xfd,0xd5,0x13,0x23,0x9f,0x8a,0x96,0xf,0x64,0xe7,0x93, +0xd7,0x4a,0xa9,0xdb,0x6f,0xa4,0xb7,0xdf,0x2b,0xf7,0x59,0xbe,0xb2,0xce,0xbf,0x6, +0xff,0xf8,0xc6,0x5d,0x7f,0x75,0xa8,0x9e,0xea,0xeb,0x9a,0x6f,0x5a,0x46,0x74,0x5c, +0xd2,0x7c,0x9b,0x44,0xbb,0x21,0x8e,0xe8,0x1b,0xe8,0xfb,0x5f,0x41,0xb3,0xfd,0xe4, +0xab,0x56,0xfb,0x6d,0xf0,0xaf,0x8f,0xb8,0xeb,0xaf,0xfa,0xb4,0xac,0xa,0x81,0xb6, +0xc1,0xb2,0x36,0xd9,0xa7,0xf9,0x6a,0x53,0xed,0x28,0x84,0x5e,0xbf,0xd5,0x46,0xdf, +0x9c,0x1f,0x54,0x7a,0x46,0x3e,0x30,0x8f,0xaf,0x62,0xf9,0x82,0xfa,0x97,0x98,0xeb, +0xf,0xfa,0xa4,0xf5,0x4d,0xd3,0x77,0xf0,0x97,0x55,0xc3,0x77,0xfe,0xfb,0x3f,0xe1, +0xf4,0x7f,0xce,0xfb,0x96,0xe3,0xf7,0x3e,0x45,0xc6,0xfc,0xa0,0xde,0xff,0x1,0xd8, +0xf0,0xfb,0x2,0xf6,0xe7,0x8a,0xb9,0x7e,0xa3,0x4f,0x1f,0x7f,0x6c,0xfa,0xd0,0x9f, +0x37,0xc,0x1f,0x39,0xfd,0x23,0x4f,0x7e,0xf6,0xf9,0xde,0xff,0xad,0xea,0xb3,0xf7, +0x97,0xe2,0xf8,0x82,0xc6,0xb7,0x98,0xeb,0x5f,0xfa,0xb4,0xd5,0x7b,0x60,0xfa,0x9a, +0xef,0x96,0xd,0x1f,0xba,0x53,0x8,0xf5,0x29,0xc7,0xef,0xf7,0xb1,0xd3,0xc7,0xfa, +0x67,0x35,0x5f,0xcd,0xc1,0xc7,0xda,0xaf,0xc9,0xda,0xf,0xdd,0xd1,0xdb,0x6f,0x1a, +0x54,0xbf,0x52,0x7a,0x1f,0xf4,0x71,0x61,0xb5,0x13,0x2f,0x5f,0x25,0xda,0xff,0x2a, +0xcc,0x17,0x38,0xbf,0xa5,0xec,0x36,0x5e,0xc6,0xb1,0xeb,0x43,0x34,0xeb,0xf6,0xb, +0xf6,0xf5,0x72,0xee,0xdb,0x69,0x3c,0xc4,0xb1,0xeb,0x57,0x34,0xc9,0xfa,0xab,0x43, +0x68,0xfa,0xa6,0xcf,0x33,0xdf,0xe6,0xce,0x2c,0x1f,0xd9,0x69,0xf4,0xcd,0xf9,0xc1, +0xc0,0x7c,0x15,0xb0,0xbe,0x3d,0xc5,0xfa,0x2b,0xdf,0xf8,0x16,0xec,0x73,0xd4,0xaf, +0xbc,0xf9,0x2a,0xf8,0xfd,0x5b,0x34,0xe5,0xfa,0xab,0xe8,0x3e,0xed,0x8b,0x1,0xf9, +0x6a,0x12,0x5c,0xdf,0xa0,0x19,0xac,0xbf,0x8a,0xe8,0xb,0xce,0x57,0xb6,0x2f,0x68, +0x7f,0x2e,0xba,0x58,0x1f,0xf6,0xe4,0x2b,0xe6,0x1b,0xe6,0xc3,0x37,0xd2,0x7d,0xaf, +0x8,0x22,0xcb,0x57,0x33,0x8f,0xef,0x62,0x7d,0x3,0x64,0xe4,0x2b,0x56,0xbf,0x42, +0xa1,0xcf,0xf,0x26,0xf3,0xa9,0xe3,0x98,0xb9,0x66,0x77,0x7d,0xc5,0xdc,0x51,0x4f, +0x1d,0x8b,0xa,0x21,0xbe,0x6a,0xe3,0xd3,0x8a,0x99,0xaf,0xf4,0xfd,0xf,0x20,0x7b, +0x7f,0x8a,0x9d,0xf,0x2,0xde,0x1f,0xbf,0x10,0x9f,0x9a,0xaf,0xba,0xd,0x33,0x5f, +0xe9,0xef,0x1f,0x84,0x2d,0xcb,0x27,0x6,0xd6,0xaf,0x16,0xe9,0x7b,0x5f,0xf3,0x39, +0xf2,0x55,0xd3,0xf2,0x9,0x33,0xc6,0xb7,0xf4,0xcf,0xa7,0xf0,0x8a,0x62,0xbe,0x7c, +0xd5,0x6d,0xba,0xf2,0xd5,0xeb,0x66,0xfd,0x6f,0x7a,0xb9,0x10,0xe6,0x4b,0xf9,0xfc, +0x5b,0x64,0x5f,0xef,0x83,0x6e,0xb3,0xb0,0xa,0xe3,0xe5,0xab,0x5,0xfa,0x76,0x1b, +0x2f,0xce,0xac,0xbf,0x64,0xd7,0x7e,0xb1,0xcf,0x3f,0x35,0x5f,0x69,0x3e,0x10,0xdb, +0x97,0xac,0x7e,0x1a,0xdf,0xb7,0xd3,0x78,0x2b,0xfe,0xfa,0xf6,0xb9,0xf9,0x88,0xec, +0xcf,0x57,0x9f,0x56,0x5,0xfd,0xf9,0x1e,0x5,0xc5,0xc9,0x57,0xd9,0xd6,0x9f,0x99, +0x6f,0xea,0x9d,0x3f,0x72,0xe6,0xab,0xa1,0x9e,0xaf,0xd6,0x68,0xa4,0x7c,0x95,0x7a, +0xfd,0x15,0xd7,0x77,0xee,0x9b,0xdf,0x72,0xe4,0xab,0x3,0x3d,0x1f,0x3c,0xa6,0x91, +0xf2,0x55,0xea,0xf5,0x57,0x5c,0x5f,0xd8,0xf3,0x65,0x4f,0xf4,0xfd,0x9b,0x2a,0x3f, +0xda,0x2e,0x9e,0xf,0x0,0x0,0x12,0x4f,0x49,0x44,0x41,0x54,0xa3,0x91,0xf2,0x55, +0xc2,0xfd,0xaf,0x66,0xf9,0x42,0xf6,0x6f,0x37,0x7d,0x6c,0xfc,0xb5,0xf3,0x15,0xa, +0xf0,0x35,0xc0,0x42,0xdb,0x6f,0xa4,0xfb,0x5e,0x31,0xcf,0x3f,0x35,0x5f,0x6d,0x31, +0x1f,0xff,0xf8,0xc6,0xdf,0xff,0x6a,0xf,0x1f,0x9a,0x3e,0xf9,0x7e,0xd9,0xf4,0x15, +0x37,0xa3,0xfa,0xcc,0x7c,0xc5,0xde,0x4f,0x77,0xd5,0x6a,0x3f,0xc8,0xbf,0x3e,0xe2, +0xef,0x7f,0xd5,0x3a,0xed,0x9b,0x3e,0xd4,0x34,0xa6,0x17,0x55,0x50,0x6d,0x86,0x6f, +0x7c,0x19,0x16,0xa,0x80,0xf5,0x2f,0xce,0x7c,0xc5,0x7c,0x80,0xd7,0xbf,0x24,0xd9, +0xff,0x6a,0xed,0x98,0xf9,0x60,0xd7,0xf4,0x29,0xd8,0xf2,0x1d,0xf1,0xcf,0x3f,0x78, +0x1f,0xd5,0x6a,0xdb,0x1c,0x9f,0x75,0x7d,0x6c,0xf0,0xfa,0xe7,0x24,0xfb,0x5f,0x9, +0xd8,0xf2,0x61,0xe6,0xa3,0x96,0x6f,0x97,0x9f,0x9f,0xe1,0x9b,0xaa,0xcf,0xde,0x5f, +0x94,0xe3,0xe3,0x8e,0x6f,0x49,0xf6,0xbf,0x72,0xfa,0xb6,0x99,0xcf,0x3a,0xff,0xd6, +0xf9,0x3e,0xb0,0x66,0x3d,0x3f,0xa8,0xe7,0x2b,0x76,0x7d,0x84,0xcd,0xf,0xd2,0x64, +0xfb,0x5f,0x39,0x7c,0xd3,0x5b,0xbe,0xf6,0x5b,0xe7,0xd5,0xaf,0x74,0x9f,0xfb,0xf9, +0xc1,0x68,0xf9,0x2a,0xc9,0xf8,0xe6,0xf0,0x51,0xff,0xf1,0xd,0x6e,0xbf,0x24,0xf9, +0x85,0xb4,0xe3,0xef,0xaf,0xb2,0x66,0xfb,0x80,0xff,0xfa,0xd8,0xcd,0xd6,0x17,0xf5, +0xfd,0x74,0xce,0xfe,0x5,0xdb,0xfd,0x8b,0xe8,0xeb,0x5f,0x8e,0x12,0xfb,0x78,0xd7, +0x6f,0x12,0x9f,0xb3,0x7f,0x16,0xb8,0xfd,0x33,0xe7,0xfd,0x24,0x70,0xd,0x9,0x46, +0xff,0x17,0x54,0xbf,0x82,0xbc,0xfe,0x2f,0x89,0x2f,0xc2,0xfd,0xb9,0xbf,0x7f,0x86, +0x81,0xf5,0x2b,0x76,0x7f,0xde,0xe1,0x8d,0x1f,0x4,0xbc,0x4e,0xe7,0xe1,0xf3,0xb5, +0x1f,0xb2,0xf2,0x55,0xcf,0x5d,0x1f,0x42,0x1d,0xd3,0xf7,0x88,0x37,0xfe,0x92,0x36, +0x9c,0x47,0xfb,0xfd,0x3e,0x24,0xbf,0x78,0x7d,0x8f,0xd8,0xf1,0xe5,0xe5,0x97,0x84, +0xfb,0x5f,0xcd,0xf2,0x9d,0xa,0xd1,0x7d,0x95,0x30,0x9f,0x34,0x1f,0x5f,0x58,0xbe, +0xd2,0x7d,0xaf,0x54,0xad,0xfa,0x95,0xe5,0xe3,0x1d,0xdf,0xc5,0xfb,0x6,0xfa,0xf5, +0xc1,0xe6,0x8f,0xe4,0xab,0x13,0x18,0x96,0xaf,0x12,0xee,0x7f,0x15,0xc9,0xb7,0x55, +0x77,0x3c,0xf8,0x3d,0xfe,0x4a,0xc5,0x35,0x3f,0x68,0xcd,0x6f,0x3d,0x81,0x61,0xfd, +0x4b,0xf6,0xf7,0x6f,0x47,0x56,0xff,0x57,0x7d,0xbe,0xe5,0xe8,0x5f,0x6a,0xd,0xfe, +0xfc,0xe0,0xef,0x59,0xfd,0x5,0x66,0xb8,0xff,0x55,0x88,0xcf,0x1a,0xdf,0x8,0x7e, +0x69,0x87,0xe3,0x33,0xf3,0x95,0x3d,0x3f,0x38,0x97,0xfd,0xaf,0x82,0x7d,0x56,0x3e, +0x20,0xd4,0xe9,0x3,0xb5,0xa6,0xd3,0xe7,0x98,0x1f,0x84,0xf3,0xa8,0x5f,0x85,0xf8, +0xac,0xf5,0x57,0x47,0xaf,0xb9,0x7d,0x9e,0xf5,0xed,0x73,0xad,0x5f,0x45,0x69,0x3f, +0xfc,0x86,0xdb,0x17,0xfb,0xf9,0xbc,0xb9,0xf8,0x76,0x33,0xf5,0x65,0x5f,0xbf,0xb7, +0xf3,0x55,0xf5,0x5e,0x2b,0x96,0x2f,0xcb,0xfd,0xaf,0x66,0xd4,0x87,0xf4,0xf5,0x7, +0xae,0xfe,0xf,0xde,0xaf,0x1a,0xf3,0x83,0xc1,0xbe,0x2c,0xf7,0xbf,0xa,0xf7,0x71, +0xd6,0x5f,0x59,0xf9,0x2a,0xd8,0xe7,0xda,0xff,0xea,0xee,0xcd,0xcb,0x86,0x6f,0x3a, +0x8f,0xf9,0x19,0xbf,0xcf,0xca,0x57,0xc1,0x3e,0xd7,0xfe,0x57,0xd5,0xde,0xc4,0xf0, +0x9d,0x2f,0xc6,0x67,0x8d,0xbf,0xc1,0x3e,0xd7,0xfe,0x57,0x95,0xd1,0x64,0x7e,0xc7, +0x97,0xdc,0x49,0xeb,0x7b,0xa9,0x32,0x22,0xf3,0xf3,0xd1,0x9f,0xa6,0xf7,0x49,0x37, +0x99,0x6f,0xe,0xf3,0xbf,0x62,0x5a,0xdf,0xab,0x15,0xf8,0x11,0xf3,0xd5,0x17,0x71, +0xfd,0xc6,0xf7,0xb1,0xf3,0x2f,0xdd,0xfa,0x3,0xd7,0xf3,0x47,0xec,0x67,0x4c,0xef, +0xd2,0xd4,0x3e,0xf5,0xfa,0x48,0xb1,0xff,0x15,0xf0,0xfd,0xc,0xed,0xf9,0xad,0x90, +0xfa,0x41,0x4c,0x5f,0x55,0xeb,0x5f,0xd2,0xee,0x3f,0xa4,0xf,0xe0,0xcc,0x21,0x17, +0x43,0xeb,0x2f,0xb3,0x7c,0x9e,0xfd,0xdb,0xab,0x5a,0xff,0x9c,0xf5,0xfe,0x57,0xc1, +0xcf,0xf,0xc6,0xf5,0xa5,0xde,0xff,0x8a,0xce,0xb9,0xfd,0xd8,0xb7,0x4a,0xb5,0xbf, +0x59,0x86,0xe7,0x1f,0xf7,0xb3,0x9b,0x81,0x8f,0x7b,0xfd,0x66,0xe4,0x4b,0xb1,0xff, +0x55,0xf0,0x67,0xd6,0xfa,0xd,0xfe,0xfb,0x7,0xa9,0xb9,0x8e,0xd7,0xfb,0xad,0x92, +0xae,0xbf,0x4a,0xee,0xd3,0xdf,0x5f,0xe6,0xf7,0x99,0xeb,0xc8,0x39,0xbe,0xe4,0xfb, +0x27,0x26,0xf2,0x11,0x10,0xe0,0xbb,0x15,0xe4,0xdb,0x58,0xac,0xef,0x57,0x1,0xbe, +0xa0,0xe3,0xbb,0x88,0xf5,0x1b,0xe,0x9f,0xf2,0x71,0xce,0x7d,0xbd,0x98,0xd7,0xc7, +0x82,0x7d,0x38,0xe0,0xfa,0xa0,0x4b,0xf4,0xad,0x7f,0x6f,0x2c,0xcb,0xfd,0xe2,0x96, +0xb6,0xfe,0x0,0x71,0x7d,0x64,0xa9,0xbe,0x9a,0x4,0xab,0xd5,0xdb,0xa8,0xaa,0xad, +0x7f,0x19,0x1c,0xe5,0xd0,0x7,0x2a,0x15,0xf1,0xf6,0x4,0x7,0xaf,0xcf,0xa1,0x57, +0x97,0xe8,0x23,0x18,0x54,0x20,0xbd,0x33,0xa1,0x20,0xde,0xf8,0x86,0x16,0xb4,0xbe, +0x49,0xf5,0xbd,0xe,0xc9,0xe4,0x32,0x35,0xe6,0x7,0x4b,0x39,0xf4,0x9,0x15,0x32, +0x21,0x39,0x6e,0xbf,0x4a,0xa5,0x35,0x21,0x58,0xc,0xf5,0x61,0xf9,0x2b,0x45,0x7a, +0xa9,0xfd,0xca,0xda,0x83,0x31,0xad,0x6f,0x6e,0xa6,0x7a,0x7e,0x35,0xa6,0x4f,0xbd, +0x7e,0x6b,0x13,0x5a,0x9d,0xe1,0xc3,0xa,0xa2,0x6b,0x0,0xee,0xec,0xc0,0xb5,0xba, +0xb6,0xb5,0xf0,0xa2,0x7c,0xb4,0x76,0x32,0x96,0xc7,0xb7,0xe9,0x96,0xbe,0xbf,0xe8, +0x61,0x88,0xf,0x6b,0xbe,0xde,0xe,0x68,0xd5,0x16,0xea,0x13,0x8c,0xa,0x96,0x91, +0xaf,0x60,0x4,0x1f,0xae,0xe1,0x5a,0xaa,0xfd,0xaf,0xe2,0xf9,0x44,0xeb,0x96,0x2f, +0x30,0x5f,0xe9,0xe7,0xdf,0xd3,0xaa,0xaf,0x5d,0x71,0xfa,0x92,0xae,0xbf,0x4a,0x91, +0xaf,0xf6,0x42,0xdb,0xef,0x12,0x80,0xdd,0x7,0x0,0x55,0x51,0x2d,0xd1,0xfe,0x57, +0x73,0xcb,0x2f,0xcc,0x57,0x55,0x7d,0x22,0x80,0x55,0x58,0x4b,0xb2,0xff,0x55,0x16, +0x3e,0x25,0xd4,0x57,0xd3,0x7d,0x3f,0xba,0xe,0x6a,0x49,0xf6,0xbf,0xca,0x22,0x5f, +0xf1,0x7c,0x97,0x54,0x18,0xd2,0xfb,0x97,0xba,0x36,0xb5,0x4,0x85,0x8a,0x58,0x4b, +0xb2,0xff,0x55,0x8a,0x7c,0xa5,0xa8,0xf9,0x6a,0x2b,0x28,0x5f,0xad,0x9d,0x92,0x1a, +0x94,0xff,0xa9,0xda,0x3f,0xaf,0xb5,0x5f,0xa9,0x8a,0x63,0x5a,0x59,0xdd,0x4c,0xb2, +0xff,0x55,0x8a,0x7c,0x75,0x4f,0x42,0xd5,0x6a,0x50,0xbe,0x5a,0x3b,0x56,0x6a,0xfd, +0xab,0xdf,0xf4,0x7f,0xab,0xa4,0xef,0x1f,0x8c,0x9f,0xaf,0xde,0x97,0x26,0x58,0x8, +0x1a,0x3f,0xd6,0xd4,0xe3,0xdb,0xfa,0xfc,0x63,0x9e,0xef,0x5e,0xb6,0xbe,0x75,0x73, +0x65,0xaf,0x2f,0x5f,0x29,0x93,0x9,0xfd,0x6e,0x98,0xaf,0x3e,0xea,0x51,0x72,0xc9, +0xe7,0x4b,0xf4,0xfe,0xc1,0xe0,0xf,0xdb,0xc6,0xdd,0x97,0xaf,0x14,0x35,0x5f,0x5d, +0xf,0xca,0x57,0xea,0xf5,0xf1,0x66,0x6b,0xd4,0xe3,0x1f,0x8a,0x6c,0xc7,0x37,0x1a, +0x90,0xaf,0x14,0x35,0x5f,0x5,0xce,0x6f,0x55,0x31,0xbd,0xd7,0xf3,0xfa,0xc6,0xd7, +0x93,0xad,0xbf,0x4a,0xe2,0x33,0xf2,0x55,0xa0,0xaf,0xa6,0x1e,0x5f,0xd5,0xa7,0x25, +0x2c,0x7b,0x78,0x86,0x7,0xc9,0xd7,0xf,0xc5,0xf4,0xa9,0xd7,0x6f,0x5d,0xcd,0x57, +0x81,0xbe,0xba,0xea,0x1b,0xa9,0x3e,0xb5,0x7,0xec,0x58,0xbf,0x9,0x86,0xb,0xf2, +0xe9,0xf9,0x4a,0x91,0xa8,0xde,0xff,0x9d,0xe0,0x80,0xeb,0x63,0x72,0x55,0xf3,0xe1, +0x47,0xec,0xf7,0x4e,0xe7,0xe2,0x2b,0xec,0xb4,0x67,0xe4,0x2b,0x7d,0xff,0x2b,0xf9, +0x7e,0xc9,0xdc,0x5f,0xb4,0x88,0xdc,0x23,0x1c,0xf4,0xf8,0x6e,0x67,0xea,0x23,0xf8, +0x21,0x10,0xc2,0xf3,0x95,0xbe,0xbf,0x40,0x95,0x3d,0x7f,0x24,0xa1,0xa1,0x3b,0x61, +0x79,0x7c,0xed,0x93,0x4c,0x7d,0x8a,0xf2,0x8e,0xb1,0x61,0x77,0x70,0xbe,0x32,0xf6, +0x97,0xea,0x9a,0xbe,0x11,0x3e,0x8,0x6f,0x3f,0x9a,0xad,0x8f,0xce,0xf2,0x29,0x86, +0x4f,0x2e,0x9b,0x3e,0xda,0xf0,0xf8,0x36,0x69,0xd9,0xf0,0xb5,0xb,0xda,0xfa,0xa6, +0xac,0x7d,0x1f,0xcc,0xf2,0xe9,0xfb,0x5f,0x55,0x30,0x70,0xfb,0xb4,0x19,0x85,0x82, +0xee,0x7b,0xc0,0x7c,0xc6,0xfe,0x57,0x52,0xa6,0xfd,0x9f,0x72,0x38,0xcb,0x87,0x8d, +0xfd,0xaf,0x28,0x30,0xd7,0x5f,0x51,0x63,0x93,0x98,0xa9,0xfe,0x7a,0x58,0x6d,0xb9, +0xce,0x9f,0xa,0xe,0xdf,0x9,0x38,0xc9,0xd6,0xa7,0xfc,0x2c,0xc8,0x47,0x8a,0x5b, +0xda,0xfe,0xa2,0xc8,0xd8,0x5f,0xca,0xf4,0x61,0x85,0x18,0xd7,0xef,0x54,0x13,0x69, +0x9,0xb,0x3e,0x2c,0x39,0x8e,0x6f,0xd6,0xe3,0x5b,0x98,0xf,0xe9,0xf7,0xbf,0x3, +0xc3,0xd7,0x65,0xbe,0xf3,0x55,0xdb,0xa7,0xff,0xdb,0xf6,0x26,0x6b,0xbf,0x83,0xec, +0x7d,0x4,0x3f,0xe6,0xf4,0x2f,0xc6,0x97,0x1c,0xf9,0xa,0xa0,0xa6,0x68,0xf8,0x8, +0x42,0x5e,0xdf,0x80,0xf9,0xae,0xcf,0x21,0x1f,0x70,0xfb,0x67,0xd3,0x47,0x8b,0x96, +0x4f,0xbe,0x6f,0x5e,0xbf,0xb4,0xe8,0xf3,0xc9,0xa6,0x6f,0x3a,0x97,0xfa,0xb,0xd, +0xba,0xff,0x20,0x97,0x69,0xd8,0xfa,0x2b,0x6a,0xbf,0x5a,0xc7,0x9c,0x17,0x3c,0x5d, +0xb0,0x8f,0xd0,0xe0,0xfd,0xf,0x78,0xed,0x7,0x17,0xed,0xc3,0xd1,0x7c,0x63,0xc7, +0xf5,0x9b,0x7d,0xfd,0x34,0xd8,0x17,0x92,0xaf,0x5c,0xbe,0x3d,0x47,0xff,0xb7,0x50, +0x9f,0x91,0xaf,0xf8,0xf3,0x83,0x53,0x6b,0xfa,0x77,0xbb,0xe8,0xf2,0x91,0x45,0xf9, +0xcc,0xf1,0x43,0x9f,0x1f,0x6c,0xcb,0xe6,0xf3,0xf1,0x1c,0xdf,0xdb,0x65,0xd3,0x37, +0xb9,0x9e,0xd1,0xfb,0x7,0x63,0xf9,0x88,0xbe,0xff,0x41,0x55,0x2c,0x7,0xd5,0x77, +0xff,0x94,0x8d,0xbf,0xd2,0x41,0x46,0xef,0x1f,0x4c,0xe0,0xab,0xf4,0xc5,0x20,0xdf, +0x6,0xf3,0xf5,0x87,0xcb,0x38,0xbe,0x8a,0xb1,0xff,0x95,0x12,0xe8,0xdb,0x5c,0xb2, +0x4f,0x99,0xe1,0x3,0xce,0x7c,0x9a,0xea,0xfd,0x83,0x89,0x7c,0xd8,0xd8,0xff,0xa, +0x8b,0xb3,0xe6,0x17,0x2c,0x5f,0x7d,0x41,0xfd,0x4b,0x71,0xb,0xb2,0xfa,0x15,0x80, +0x28,0xd8,0x87,0xdd,0xbe,0x8c,0xd7,0x1f,0x4,0xfb,0x50,0xb5,0xc3,0xea,0x57,0x0, +0xfe,0x6d,0x29,0xc8,0x67,0x15,0x30,0xe1,0x41,0xca,0xf7,0xf,0xc6,0xf4,0x4d,0xb0, +0xbd,0xbf,0x28,0x12,0x3,0xdb,0x8f,0x10,0x47,0x7d,0x23,0xf5,0xfa,0x97,0x38,0x3e, +0x6a,0xef,0x2f,0xea,0xed,0x9f,0x9d,0xeb,0x87,0x84,0x7f,0x6f,0xd7,0x87,0x16,0xe9, +0xbb,0x4c,0xbd,0xfb,0x8b,0xf2,0x7d,0xef,0x6d,0xb2,0x6,0xcc,0x60,0xfd,0x55,0xac, +0x7c,0x55,0x89,0xb4,0xfe,0x6a,0x6f,0xd3,0xfe,0xfd,0x45,0xb6,0x1f,0xc1,0x85,0x48, +0xeb,0xff,0xf6,0xa,0xcb,0xf1,0xd1,0x2a,0x8c,0xe4,0x7b,0xb0,0xe1,0xf2,0x2d,0xec, +0xfa,0xa5,0x7a,0xff,0x77,0x12,0xf0,0xfc,0x20,0xb2,0xde,0xaf,0xbb,0x7b,0xe8,0xf2, +0x2d,0xaa,0xff,0x73,0xe7,0x2b,0xf3,0xfe,0x48,0x2e,0x15,0x37,0xd,0xdf,0xd0,0xda, +0xdf,0x7b,0x8a,0x5d,0xbe,0x45,0x8d,0x1f,0xee,0x7c,0xd5,0x4,0xac,0x7e,0x55,0x33, +0x7c,0x7,0x81,0xfb,0x4b,0x6d,0x2c,0x23,0x5f,0xb1,0xfb,0xf3,0x11,0x36,0x7d,0x28, +0xd3,0xfd,0xaf,0x52,0xe4,0x17,0x63,0xff,0x2b,0x6a,0xd5,0x87,0xb0,0xe9,0xd3,0xf6, +0x67,0x90,0xaf,0xee,0x60,0xa,0x37,0x73,0xe0,0x23,0x56,0x7d,0x6d,0x9f,0xf9,0xe4, +0xf2,0x11,0x1e,0x3d,0x3c,0xa5,0x9d,0xda,0x32,0x7d,0x18,0x79,0xea,0x57,0xac,0xfd, +0xb4,0xe7,0x7,0xf1,0xe8,0x9d,0xe3,0xd6,0xa3,0xe5,0xf8,0x88,0x39,0x3f,0x8,0xdd, +0xf5,0x2b,0xcb,0xa7,0xed,0xcf,0xa0,0xfa,0x70,0x17,0xe2,0xe5,0xf8,0xcc,0xf9,0xc1, +0x5d,0x77,0xfd,0xca,0xba,0x3e,0xb4,0xfd,0x19,0xf0,0xe8,0x83,0xe5,0xf9,0x26,0x76, +0xfd,0x0,0x20,0xd6,0xbf,0x10,0xd6,0xbf,0xe8,0xcf,0x6f,0xc9,0x57,0x3f,0xc0,0x43, +0x88,0x96,0xe4,0xb3,0xeb,0x2f,0xce,0xfa,0xd5,0xa6,0xc3,0x87,0x95,0x9f,0xa9,0x3e, +0xc7,0x2b,0x17,0x17,0x5b,0xbf,0x9a,0xb9,0xbf,0xa8,0xe6,0xeb,0x42,0xb0,0x1c,0x5f, +0x58,0xfd,0xca,0x6a,0xbf,0xc7,0xaa,0x4f,0x5c,0x92,0xf,0x47,0xf0,0xed,0xe0,0x16, +0x5c,0xf5,0x7d,0xb7,0xa5,0xd7,0xaf,0xb2,0xdd,0xff,0x2a,0x55,0xfd,0x2a,0x60,0xff, +0x2b,0x9c,0xe9,0xf3,0xd3,0x29,0xf2,0xd5,0x90,0x9f,0xaf,0x4e,0x3b,0x59,0xee,0x7f, +0x95,0x22,0xbf,0x1c,0xf0,0xf3,0xd5,0xf1,0xa3,0x2c,0xf7,0xbf,0x4a,0xe1,0x43,0xfc, +0x7c,0x85,0x61,0x96,0xfb,0x5f,0xa5,0xc8,0x2f,0x88,0x9f,0xaf,0x2,0x7d,0xd,0x90, +0x13,0x5f,0x56,0xfb,0x5f,0x65,0x93,0xaf,0x44,0x96,0xaf,0x10,0xf3,0x65,0xb5,0xff, +0x55,0xca,0x7c,0x65,0xec,0x2f,0xa5,0xbf,0x2e,0x44,0xcf,0x57,0x30,0xac,0x7f,0xc9, +0x7e,0xfd,0xd5,0xcc,0x7c,0x65,0xf8,0xfa,0x94,0xe5,0x2b,0xc0,0x7c,0x59,0xed,0x7f, +0x95,0x49,0xbe,0x62,0xeb,0xf,0x48,0xc8,0xfb,0x93,0xe9,0x1c,0xd6,0x5f,0x45,0xcd, +0x57,0x77,0x4b,0x2c,0x5f,0xad,0x86,0xfb,0x32,0x5e,0x7f,0x15,0x9a,0xaf,0xe0,0x42, +0xf6,0xbf,0x4a,0x9e,0xaf,0xe0,0x82,0xf6,0xef,0x4c,0x9a,0xaf,0x40,0xae,0x7d,0x61, +0xeb,0xdb,0xf3,0x91,0xaf,0xa,0xa1,0xf5,0xab,0x9c,0xe4,0x2b,0x73,0x7e,0x50,0x60, +0xf9,0xa,0xb2,0xfa,0x15,0x6f,0xfc,0x58,0xbc,0x8f,0xe8,0xf3,0x1f,0x55,0xf6,0xfe, +0x41,0x89,0xed,0x7f,0x75,0xd0,0xe4,0x8d,0xbf,0xcb,0xf2,0x55,0x7a,0x2,0xcb,0x57, +0xe6,0xfe,0x57,0xa8,0xc9,0xcb,0x2f,0x8b,0xf7,0x19,0xfb,0x23,0x55,0xd8,0xf8,0x3b, +0x62,0xe3,0x6f,0xfe,0x7d,0xf9,0x38,0xbe,0xd8,0xd8,0xff,0xca,0xf4,0xa9,0xf9,0xca, +0xf2,0x2d,0xf9,0xfa,0x50,0xf3,0x15,0xb0,0xe7,0x7,0x7d,0xf9,0xa,0x35,0x97,0xdc, +0xbf,0xa8,0xf9,0x6a,0xdb,0x9e,0x1f,0x4,0xcc,0x87,0x99,0x6f,0x7f,0xd9,0xfd,0xf3, +0x4,0xdf,0x72,0xcc,0xf,0xa,0x2c,0x5f,0xcd,0x65,0xff,0xab,0x64,0xf9,0xa,0x38, +0xe6,0x7,0x5,0x96,0xaf,0x72,0xe3,0x63,0xcf,0xf,0xe6,0x37,0x5f,0x81,0x8b,0x7c, +0x95,0x2a,0x5f,0x81,0x9c,0xe7,0x2b,0xcd,0x87,0x63,0xbd,0x1f,0x67,0xf1,0xe3,0xc7, +0x69,0xc0,0xfc,0x20,0xcd,0x49,0xbe,0x3a,0xee,0xf1,0xeb,0x57,0x34,0x4f,0xe3,0x2f, +0xa7,0x7e,0x45,0x73,0x92,0x5f,0xf0,0x6f,0xa8,0x7b,0xfd,0x38,0xf3,0xbd,0x97,0x13, +0xdf,0xff,0xd,0xf0,0xfd,0x4d,0x4e,0x8e,0xaf,0xb9,0xfe,0xa,0xb0,0x7c,0xc5,0x7c, +0x78,0xf9,0xf9,0x6a,0xcb,0x3a,0xff,0x98,0xf,0x2b,0x96,0x2f,0x7,0xf9,0xaa,0xca, +0xfa,0x3f,0xce,0xfc,0x20,0xcd,0x41,0xbe,0xaa,0xce,0x9a,0x1f,0x5c,0x72,0xbe,0xaa, +0xce,0x9a,0x1f,0x5c,0x72,0xbe,0xaa,0xe6,0x3c,0x5f,0x55,0x73,0x9e,0xaf,0xaa,0x39, +0xcf,0x57,0x5f,0x84,0xf9,0xc1,0x40,0x5f,0x4e,0xf2,0x95,0xdb,0x27,0x5f,0xb1,0xea, +0xcf,0x39,0xc9,0x57,0x6e,0x1f,0x1e,0x21,0x9c,0xaf,0x7c,0xe5,0xf5,0x61,0x94,0xaf, +0x7c,0x15,0xe8,0xdb,0xcf,0xa9,0xf,0xe6,0xf9,0xf8,0xca,0x57,0x6d,0x5f,0x2e,0xaf, +0xf,0xc5,0xf6,0xe5,0xb1,0x7f,0xb1,0xe7,0x7,0x97,0x9e,0xaf,0x2,0x7c,0x21,0xef, +0x77,0xce,0x83,0x2f,0xec,0xfd,0xce,0x4b,0xf7,0xe5,0x2a,0x5f,0x71,0xdb,0x2f,0x47, +0xf9,0xe5,0xb,0xef,0xcb,0xc7,0xf5,0x1b,0x58,0xbf,0xda,0xc8,0x53,0xfd,0x6a,0x70, +0xb7,0xc4,0xf2,0x95,0xb9,0xbe,0x98,0xa2,0x9c,0xd4,0xaf,0x80,0x5e,0xdf,0x10,0x59, +0x7d,0x43,0x9b,0xd7,0xa,0x7e,0x3f,0xdd,0x12,0x8e,0xef,0xaf,0x74,0x9f,0xf6,0x94, +0xba,0x91,0xf,0x4,0xd3,0x7,0x73,0x52,0x1f,0xfa,0x38,0xe7,0x3e,0xa3,0xfe,0xc7, +0xe6,0x8f,0x46,0xf8,0x3b,0xcc,0x97,0xab,0xf9,0x41,0xd3,0xa7,0xe6,0xab,0xe7,0x4c, +0x1f,0x58,0xe6,0xf5,0xf1,0x3d,0x59,0xee,0x5f,0x2e,0x16,0xec,0xfa,0x95,0x3d,0xff, +0xc6,0xea,0x2f,0x60,0x89,0xfd,0xb,0x91,0x50,0xf5,0xf6,0x4,0x41,0xbb,0x7e,0x65, +0xaf,0xbf,0xb2,0x7c,0x4b,0xec,0x9f,0x9,0x70,0xef,0x2f,0xea,0x7c,0x7f,0x63,0x1e, +0xea,0x57,0xa,0xa8,0xd0,0x3b,0x13,0xcc,0x7d,0xff,0xe0,0x66,0x3e,0x7c,0x64,0x72, +0x19,0xe7,0x76,0x7e,0x50,0xf7,0xe5,0x78,0xfe,0x4d,0xf5,0x85,0xef,0x2f,0xba,0x6c, +0x9f,0x84,0x6a,0x13,0x6d,0x29,0x62,0x4e,0xf3,0x15,0x39,0x91,0xc7,0xb7,0x49,0x51, +0xf3,0xe1,0xc3,0x1c,0xd6,0xaf,0xb4,0x47,0x8e,0xcd,0xfd,0xaf,0x4e,0xa1,0x9e,0xaf, +0xd6,0xca,0x2c,0x5f,0x6d,0xe4,0xe1,0xfe,0x5c,0xb0,0xf6,0xbf,0x32,0xf3,0x55,0xcb, +0xca,0x57,0xa2,0xe9,0x13,0x73,0x32,0xfe,0xee,0x51,0xf7,0xfe,0x57,0x2c,0xbf,0xfc, +0x38,0x57,0xf9,0xc5,0xf6,0xb1,0xf7,0xbf,0xbd,0x95,0x13,0x9f,0xf1,0xfc,0xe5,0x6f, +0xcb,0xbe,0xf9,0xd5,0x5c,0xcd,0xf,0xfe,0x6,0xb0,0x7c,0x85,0xf3,0x70,0x7d,0x9c, +0x9f,0xc,0xd4,0x7c,0xe5,0x98,0x1f,0xb4,0xe7,0xdf,0x70,0x1e,0xea,0x57,0x13,0x9, +0xaa,0xf9,0x2a,0xbf,0xf3,0x83,0x13,0x50,0xb9,0xed,0xdc,0xff,0xa,0xb2,0xf9,0x41, +0x5,0x55,0xf3,0x50,0x3f,0x90,0x0,0x54,0xf3,0xd5,0x77,0xed,0x7c,0xc5,0xe6,0x7, +0xf3,0x91,0xaf,0x54,0xdf,0x40,0xcd,0x57,0xd7,0x73,0x3b,0x3f,0xa8,0xb6,0xdf,0x24, +0xcf,0xf3,0x6f,0x12,0xa8,0xe4,0xdb,0x27,0xa9,0xed,0x87,0xf2,0x3b,0x3f,0x38,0x39, +0x81,0x12,0x31,0xfa,0x3f,0x1c,0xe0,0xdb,0x5b,0x66,0xff,0x87,0xec,0x7c,0xa5,0xef, +0x2f,0x3a,0xb8,0x6f,0xd5,0xaf,0x50,0x1e,0xee,0xcf,0xb1,0x9d,0xaf,0x8c,0xfd,0x9b, +0xd8,0xf3,0x3d,0x23,0x63,0x7f,0xd1,0x1c,0xe5,0x2b,0xee,0xfe,0xa2,0xaa,0x6f,0x33, +0x27,0xf9,0xc5,0xf0,0xfd,0xda,0xca,0x2f,0xd,0x36,0xfe,0xe6,0xc4,0x67,0xec,0x2f, +0x6a,0xaf,0x5f,0x63,0x3e,0x9c,0x93,0xe3,0x6b,0xec,0x2f,0xa,0xac,0x7c,0xc5,0xc6, +0xdf,0x65,0xae,0xbf,0xfa,0x70,0xba,0xa6,0xa8,0xf9,0x6a,0x93,0xf5,0x2f,0x80,0xf9, +0xb0,0x72,0x8e,0x72,0x90,0xaf,0xaa,0xb5,0xc7,0xe7,0xd2,0x44,0xbf,0xff,0xc5,0xdc, +0xfd,0x45,0x97,0x9c,0xaf,0x2a,0x8d,0xdf,0x9e,0x4b,0xee,0x7c,0x25,0xb2,0x7c,0x85, +0x96,0x3f,0xbe,0x11,0xd8,0x20,0xe7,0x93,0x9,0x2e,0xf2,0xf2,0x55,0x4e,0x7c,0xe8, +0xce,0x65,0x9c,0xd7,0xf5,0x57,0x9a,0x6f,0x7c,0x27,0xc2,0xfe,0x7,0xcb,0xf3,0xf5, +0x51,0x9e,0x7d,0xa8,0xb6,0x3,0x3f,0xc8,0x71,0xbe,0xba,0x3b,0x5d,0x83,0xef,0x98, +0xf9,0x2a,0x68,0x7e,0x10,0x2d,0xb1,0xff,0x13,0x1c,0xf5,0x2b,0x63,0x7e,0xd0,0xdc, +0xbf,0x4e,0xcd,0x57,0xec,0xfe,0x68,0xb8,0xc4,0xf1,0x43,0xab,0x51,0xb1,0x7c,0x65, +0xd4,0x37,0x44,0x96,0xf,0xac,0xfa,0xfd,0x30,0x47,0xf5,0xd,0x6b,0x7f,0x51,0x47, +0xfd,0xe5,0x20,0x27,0xf9,0xc5,0xc8,0xa7,0x3d,0xcb,0x87,0x73,0xe6,0x53,0x3c,0x3e, +0x36,0x3f,0xdd,0xc8,0x55,0xfd,0xaa,0x2b,0x7a,0xeb,0x57,0x1b,0x4b,0xbc,0x3e,0xbe, +0x27,0x2b,0x5a,0xfd,0xa,0xda,0xf5,0xab,0x3,0xd1,0x5b,0xbf,0x5a,0x62,0xff,0x42, +0x24,0x74,0x4f,0xab,0x5f,0x75,0xec,0xfa,0x95,0xb9,0xbf,0xa8,0xa3,0x7e,0x85,0x96, +0xd7,0x3f,0x13,0x50,0x79,0x5f,0xf5,0x39,0xf6,0x17,0x85,0xa2,0x98,0xa3,0xf9,0x41, +0x5,0x54,0x14,0xad,0x7e,0x65,0xef,0x2f,0xca,0xfa,0xe7,0x7c,0xd4,0xaf,0x34,0xdf, +0x40,0xcd,0x57,0x8f,0x72,0x9a,0xaf,0x8c,0xf6,0x23,0xb8,0x92,0xd3,0xfc,0xa2,0x4d, +0xf,0x6a,0xbe,0x42,0x5e,0x7d,0x12,0xaa,0xab,0x3e,0x4,0x73,0x9a,0xaf,0xc8,0x89, +0xda,0xff,0x49,0xa4,0x8,0x73,0xfa,0xfc,0xa0,0xbe,0x23,0xb1,0x3b,0x5f,0xb1,0xe7, +0x7,0xaf,0xe4,0xe2,0xf9,0x41,0xc1,0x97,0xaf,0x58,0xfd,0xde,0xce,0x57,0x38,0x57, +0xf9,0xca,0xff,0xfc,0x20,0xce,0x49,0x7e,0x31,0xf6,0xef,0x4,0xc0,0x9b,0xaf,0x86, +0xb9,0xf2,0xf5,0xcb,0x5e,0x5f,0x5e,0x8e,0x2f,0xf2,0xd4,0xaf,0x50,0xe,0xea,0x57, +0xa4,0xf1,0xb7,0x57,0xd9,0xfc,0x20,0x74,0xd7,0xaf,0x72,0xb1,0xbe,0x5d,0x79,0xaf, +0x7f,0x26,0x99,0xf3,0x83,0xde,0xfd,0x45,0x41,0xe,0xea,0x57,0xca,0xfb,0xfd,0x27, +0x92,0x73,0xff,0x2b,0xc7,0xfc,0xa0,0xb8,0xfc,0xf1,0x8d,0xe2,0xf7,0xfb,0xca,0xc4, +0xe9,0x73,0xd4,0xaf,0x56,0xf3,0xe0,0xfb,0x40,0xf5,0x5d,0xc6,0x9d,0xbc,0xce,0xf, +0xe2,0xc6,0xcb,0xca,0x24,0xbf,0xf5,0xa1,0x2f,0x80,0xef,0xa1,0x92,0xe7,0xf9,0x41, +0xa5,0xd1,0x57,0xd8,0xfc,0x20,0xcc,0x5f,0xbe,0xa2,0x8a,0x23,0x5f,0x75,0x3c,0xf9, +0x2a,0xf,0xcf,0x47,0x11,0x47,0xbe,0x7a,0xe4,0xc9,0x57,0x9d,0x9c,0x8d,0xbf,0xd0, +0x93,0xaf,0x1e,0xe5,0x2c,0x5f,0x41,0x4f,0xbe,0x62,0xc7,0x17,0xe5,0xdd,0x97,0xa3, +0xe3,0xab,0xe6,0x2b,0xd1,0xfb,0xfc,0x20,0x5c,0x6e,0xbe,0xfa,0x9a,0x27,0x5f,0x9, +0xde,0x7c,0x5,0x96,0x9b,0xaf,0x10,0x5b,0x7f,0x65,0xf8,0xec,0xf5,0xed,0xcc,0xb7, +0xb1,0xdc,0x7c,0xa5,0xfa,0x9c,0xf9,0x8a,0xad,0x3f,0x50,0x72,0xb1,0xff,0x95,0x9a, +0xaf,0xd0,0x1d,0x57,0xbe,0xba,0x5b,0x62,0xf9,0x2a,0x17,0xbe,0xf,0xfa,0xda,0xfc, +0x20,0xcc,0x71,0xbe,0xd2,0xe6,0xdf,0x60,0x8e,0xf3,0x95,0xe6,0x3,0x39,0xce,0x57, +0xaa,0x2f,0xbf,0xeb,0xdb,0xd5,0x7c,0x25,0xab,0xf9,0xaa,0x10,0x56,0xbf,0x82,0x39, +0xc9,0x57,0xe6,0xfc,0xa0,0xe0,0xad,0x5f,0x75,0x72,0x92,0xaf,0x8c,0xf5,0xd9,0x6c, +0x7f,0x51,0xbb,0x7e,0xf5,0x28,0x57,0xfb,0x5f,0xd9,0xfb,0x8b,0x32,0x5f,0x5e,0x9f, +0xcf,0xfb,0xc2,0xf8,0x96,0x79,0x7c,0xdb,0xa5,0x17,0xd4,0xfc,0x2,0x78,0xcf,0xf, +0xd6,0x72,0x90,0xaf,0x68,0x4b,0xea,0x4b,0x13,0xb4,0x1d,0xf6,0xfc,0xe0,0x52,0xdf, +0xf,0xd1,0x92,0xc0,0x6d,0x63,0xff,0x4e,0x7c,0x14,0xe4,0x5b,0xe6,0xfa,0xd8,0xfa, +0x13,0xe0,0x7a,0x3e,0xf,0xb2,0xfd,0x45,0xf3,0xf1,0xfc,0x20,0xad,0x63,0x70,0xe7, +0xb2,0xf3,0xf9,0x41,0xb6,0xbf,0x68,0x4e,0xd6,0xb7,0x6b,0xed,0x47,0xf2,0xfb,0xfc, +0x20,0xad,0x4b,0x20,0xcf,0xf9,0x45,0xf5,0xf5,0x27,0x4,0xe5,0xd7,0xd7,0x2,0x2f, +0xa8,0xf9,0x25,0xbf,0xfb,0x8b,0x8a,0x56,0x7e,0x39,0x9,0xf4,0x2d,0xb3,0xff,0x3, +0x56,0x7e,0x91,0xa8,0xb3,0x7e,0xe5,0xf4,0xe5,0x63,0x7f,0x6,0xdd,0x67,0xd5,0xaf, +0x9c,0xbe,0x7c,0xe4,0x2b,0xd3,0xd7,0x5,0x81,0xef,0xbf,0x5c,0xae,0xef,0xf3,0x9c, +0xfb,0x7e,0x97,0x4b,0xdf,0xb7,0xc1,0xb,0x66,0x7d,0x48,0x9f,0x4b,0x6f,0xc3,0x7c, +0xf9,0x8,0xb8,0xdd,0x37,0xe7,0xdf,0x8c,0xf3,0x2f,0x7f,0x3e,0x2d,0x5f,0x55,0x59, +0xff,0x97,0x37,0x9f,0x2,0xde,0xd0,0xf2,0x55,0xd5,0x37,0x3f,0x98,0x17,0x5f,0x5b, +0xcf,0x57,0x55,0xdf,0xfc,0xa0,0xe5,0x73,0xbc,0x9f,0x78,0x19,0xbe,0x9e,0x9e,0xaf, +0xaa,0x91,0xde,0xef,0xbc,0xc,0x5f,0x5f,0x32,0x7c,0x51,0xde,0xef,0xbc,0x1c,0x5f, +0xdf,0x3f,0xff,0x76,0x12,0xf9,0xbb,0xcd,0xff,0xfa,0xbd,0xf5,0x82,0x39,0xff,0x96, +0xe8,0xb3,0xc0,0xfd,0xf,0x2,0x3e,0x9f,0x17,0x8b,0x4b,0xf4,0x39,0xf6,0x3f,0x8, +0xf8,0x8c,0x26,0x68,0x99,0x3e,0x7b,0xfc,0xfd,0xa2,0xfa,0x50,0xde,0x7d,0x5b,0xb9, +0xf6,0x7d,0x5e,0xcc,0x79,0xfb,0xd1,0x5c,0xfb,0xc8,0x88,0x5c,0xf8,0xd2,0x1c,0xdf, +0xab,0x74,0xc1,0xfd,0x33,0xbf,0x6,0x54,0xc8,0xcd,0xf8,0x96,0x73,0x5f,0xb6,0x9f, +0xb,0xdf,0x85,0x2f,0xe6,0x7,0xad,0x83,0x5f,0x17,0xb,0x8,0x9f,0x4c,0xae,0x95, +0xbe,0xa7,0x28,0x68,0xe7,0x5a,0x9,0xe4,0xc9,0x77,0x8c,0x3a,0x6f,0x11,0x7c,0x7c, +0x2a,0x3d,0x19,0xc1,0xdb,0x67,0x67,0xe8,0xf9,0x11,0xdc,0xce,0x9b,0x4f,0x51,0x8e, +0x8f,0xc1,0x68,0x24,0x81,0x27,0x4f,0xa4,0xd6,0x8,0xde,0xca,0x97,0xef,0xe0,0x45, +0x85,0x1e,0x63,0x0,0xa1,0xa4,0x1a,0xa1,0xa8,0x32,0xf3,0xe4,0xeb,0xa1,0x83,0x7f, +0xf3,0x34,0xed,0xe1,0x5f,0xc2,0x92,0xf4,0x4b,0xcd,0x27,0x5d,0xcb,0x99,0xef,0xb7, +0x5d,0xe5,0xb0,0x87,0x3f,0x1,0xb0,0xf7,0x49,0xaf,0x7,0xc4,0xde,0x28,0x57,0xbe, +0x75,0xcd,0xa7,0xac,0xe3,0x3e,0x80,0xad,0x7e,0xab,0x5,0xc4,0xd6,0x71,0xae,0x7c, +0x3b,0xba,0x6f,0x7,0xf7,0x7b,0xb0,0xde,0x5f,0x5f,0x7,0x62,0xfd,0xb3,0x62,0x9e, +0x7c,0x42,0xb5,0xd7,0x25,0x58,0xa8,0xf5,0x5b,0x12,0xee,0x2b,0x8a,0xb8,0xa3,0x40, +0x90,0x33,0x9f,0xda,0x3f,0xb,0xb5,0xc3,0x9d,0x2b,0x5f,0x3e,0x54,0x7d,0x8f,0x2f, +0xe7,0xab,0x7f,0xbe,0x18,0x7f,0x2f,0x7c,0x17,0xbe,0xb,0xdf,0x85,0xef,0xc2,0x77, +0xe1,0xbb,0xf0,0x5d,0xf8,0x2e,0x7c,0x5f,0x28,0x1f,0x21,0x14,0x62,0xfd,0xc9,0x79, +0xee,0x7,0xd2,0xc3,0xe5,0xfa,0xa6,0xf7,0xe9,0xd6,0x29,0x11,0xa8,0xfe,0x7c,0x99, +0x59,0xe,0x3e,0x33,0xbe,0xd4,0xd1,0xff,0xbf,0xbd,0x64,0xdf,0x33,0xa4,0x78,0x34, +0xd,0xf4,0x6d,0xd1,0xff,0x2a,0x2c,0xd7,0xf7,0xd5,0x69,0x79,0xcf,0xe5,0x1b,0x3a, +0x7d,0x45,0x7a,0x6d,0xc9,0xbe,0x75,0x99,0x6e,0xc8,0x2,0x6d,0xb,0x9d,0xdd,0xe9, +0xb5,0xfa,0x58,0xa0,0x7b,0x54,0x2e,0xe,0x48,0xf1,0x4c,0x2e,0x52,0x48,0x8a,0xf4, +0xc6,0x92,0x7d,0x7f,0x7d,0x42,0xff,0xf9,0xef,0x54,0xdf,0x8d,0xcd,0x75,0xf9,0xf2, +0xf7,0x6,0xcf,0x9e,0x3e,0xa0,0x72,0xa1,0x7d,0xbf,0xf0,0xad,0x71,0x91,0xe,0xdf, +0xfe,0x2e,0x7d,0x66,0xc9,0xbe,0xe9,0xe0,0xe6,0xea,0xa0,0x4c,0x3b,0x57,0x4a,0x6f, +0xb,0x1f,0xbd,0xb0,0xff,0xec,0xa9,0x7a,0x7c,0x8f,0x3e,0x29,0x1f,0xad,0x1e,0x75, +0xe8,0x70,0xbb,0x43,0xbf,0xb5,0x6c,0x5f,0xfb,0x2b,0x97,0xda,0x25,0xda,0x79,0xbb, +0xbc,0x72,0xff,0xa9,0xc2,0x96,0xee,0x3b,0xdd,0xba,0xb9,0x5a,0xdc,0xef,0xd0,0x23, +0xd5,0xf7,0x2f,0x96,0xed,0xeb,0x18,0xfd,0xcb,0xdb,0xc2,0xca,0xdd,0xa7,0x4a,0xdb, +0x86,0x6f,0xfb,0xc6,0x6a,0xa9,0xd3,0xa1,0xa7,0xe5,0xe,0x7d,0x6a,0xe9,0xbe,0x8e, +0xe1,0xa3,0xe5,0x93,0x7f,0x28,0x5a,0x3e,0x95,0xd6,0xa1,0x67,0xe5,0xce,0xf0,0xf2, +0xb2,0x7d,0xfb,0xcc,0x57,0x3a,0xfa,0x87,0xef,0x6c,0x3d,0x73,0x7a,0xa4,0x1d,0xdf, +0x67,0x4e,0xcb,0xea,0xf1,0x95,0x85,0xce,0xde,0xb5,0xa5,0x5f,0x1f,0x45,0xcd,0xd7, +0xbe,0x42,0x37,0xc6,0x4f,0xfd,0xdb,0xf6,0x8d,0xd5,0x13,0x2a,0xaf,0xaa,0xff,0x28, +0xf,0x8a,0x74,0xba,0xb6,0xba,0xb7,0xbe,0x6c,0xdf,0xb8,0xa4,0xfb,0x6e,0xd0,0x7, +0xf2,0x53,0xf7,0xd4,0x8b,0xf9,0x4c,0xef,0x5f,0x56,0xcb,0x6a,0xff,0x32,0xbd,0x7f, +0x69,0x6f,0xc9,0xe3,0x9b,0xe3,0x3,0xb4,0xff,0x31,0x5a,0xb,0x12,0x23,0x3c,0x5c, +0xe4,0xab,0xb,0xdf,0x85,0xef,0xc2,0x77,0xe1,0xcb,0x9b,0xaf,0x9c,0x17,0xdf,0x86, +0x5c,0x56,0x73,0xc0,0x26,0xa5,0x85,0xb1,0x0,0xd4,0x31,0x64,0xcf,0xe9,0x23,0xca, +0xd2,0xef,0x7f,0x57,0x6,0xc5,0xb3,0xc1,0xb5,0x4b,0xf4,0xa1,0x9a,0x52,0xb7,0xa7, +0x25,0xfa,0x60,0xdb,0xe1,0x9b,0xde,0x5b,0xb6,0x6f,0xfa,0xcc,0xde,0xd6,0xd9,0xde, +0x95,0x7f,0x45,0xdf,0xfe,0xde,0xe6,0xb5,0x92,0x5c,0x52,0x33,0xbd,0xf3,0xab,0x7f, +0xb0,0xf4,0xf6,0x9b,0xc2,0xce,0x69,0xe7,0xda,0x19,0x2d,0x9f,0x6d,0x5f,0x29,0x9d, +0xa8,0xb7,0x97,0xeb,0x74,0x7b,0x4f,0x2e,0xad,0x3d,0x27,0xdf,0x24,0x74,0x7a,0x69, +0xe9,0xe7,0xdf,0x94,0x76,0x8e,0x3e,0x29,0x9d,0x91,0xf2,0xd9,0xc3,0x2b,0xdb,0x47, +0x9a,0xef,0x5e,0xf1,0xc1,0xf8,0xf2,0x8d,0x3f,0x18,0x5f,0xbb,0x4f,0xa7,0xbb,0x4b, +0xf7,0xc9,0xa4,0xb8,0xff,0x49,0x69,0x77,0x2a,0x9c,0xbc,0x5d,0xda,0x6e,0xb,0x74, +0xf8,0xf0,0x99,0xb2,0x7c,0xda,0xb9,0xb1,0x7e,0xf4,0x27,0xaa,0xef,0x6c,0xe9,0xbe, +0x93,0x69,0xa9,0xf3,0x8b,0xed,0x8d,0x29,0x3d,0xfa,0xef,0xdb,0xdb,0xeb,0x65,0xf5, +0xfc,0x7b,0x46,0x98,0x1e,0x75,0x6e,0xfc,0xf5,0xfe,0x27,0xcf,0xe6,0xc1,0x77,0x44, +0xb7,0xb6,0xfe,0xd7,0xf6,0x89,0x4c,0xf7,0xff,0x6c,0x7b,0x7b,0x5b,0xbb,0x3e,0x9e, +0xa1,0xed,0x61,0xe7,0xc6,0x2f,0x3a,0x9d,0x5c,0xf8,0xb6,0x68,0xa7,0xb4,0xbb,0x7d, +0x76,0x42,0xb7,0x36,0x54,0xdf,0xb6,0xee,0x5b,0x37,0x7c,0xff,0x2d,0xf,0xbe,0x12, +0xec,0x94,0xf7,0x1e,0x9e,0x9d,0xd2,0xd2,0xa6,0xe9,0x7b,0x96,0x5e,0x31,0x7c,0x1b, +0xaa,0x6f,0xb8,0xec,0xfe,0xe5,0xd2,0xe0,0xb2,0xd0,0xbe,0x76,0x69,0x48,0x56,0xd7, +0xaf,0xac,0xae,0x97,0xe8,0xde,0xfa,0xb3,0x5a,0x9f,0x7d,0xe5,0x17,0xed,0xe2,0xbe, +0xea,0xdb,0x5b,0x76,0xff,0xbc,0xa2,0xfa,0xd4,0xf1,0x63,0x38,0xbd,0xd4,0xfe,0x9a, +0x56,0xe8,0x78,0xb0,0xfe,0x2c,0x5d,0x19,0x5f,0xfe,0xca,0x2f,0x6,0xb9,0xf0,0x51, +0x8a,0x45,0x8a,0x5,0xed,0xf5,0x2e,0x48,0xd0,0xfe,0x4f,0xbb,0x69,0x3,0x5a,0xed, +0xf,0x8b,0x30,0xbf,0xf9,0xa5,0x93,0xef,0x7c,0x45,0x8a,0xf9,0xf6,0xa9,0x39,0xe6, +0x22,0x3f,0xff,0xa3,0xf3,0xfd,0x7f,0x6e,0x69,0x1,0x55,0x8,0x9e,0xa1,0x2b,0x0, +0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; +//m1284p.png: 12987 bytes diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/main.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/main.c new file mode 100644 index 0000000..34c752d --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/main.c @@ -0,0 +1,777 @@ +/* + * main.c + * + * Created on: 22 íîÿá. 2018 ã. + * Author: maxx + */ +#include +#include +#include +#include +#include //sbi, cbi etc.. +#include "avr/wdt.h" // WatchDog +#include // printf etc.. +#include "uart_extd.h" +#include "spi.h" + +#include "globals.h" //Global definitions for project + +#include "stdbool.h" +#include "Ethernet/socket.h" +#include "Ethernet/wizchip_conf.h" +#include "Internet/httpServer_avr/httpServer.h" +//#include "webpage.h" + +#define _MAIN_DEBUG_ + +//NIC metrics +wiz_NetInfo netInfo = { .mac = {0x00, 0x08, 0xdc, 0xab, 0xcd, 0xef}, // Mac address + .ip = {192, 168, 0, 199}, // IP address + .sn = {255, 255, 255, 0}, // Subnet mask + .dns = {8,8,8,8}, // DNS address (google dns) + .gw = {192, 168, 0, 1}, // Gateway address + .dhcp = NETINFO_STATIC}; //Dynamic IP configuration from a DHCP sever + + +//#include "Application/loopback/loopback.h" +//#include "Application/webserver_simple/webserver_simple.h" + +/* + * (12) Try move pages to SD-CARD reader FatFS + * TODO + * OK 1) Try create minimal to SD-READER, include FatFS from <02_m1284p_FATFS_Chang_tst> and test working + * OK 2) Read all pages from (11) to folder this project, then move it in root folder SD-Reader and test working + * OK 3) Clean code (done on v2.4b) + * OK 4) Remove unused files from project (done on v2.4b) + * OK 5) Need to handle for every opened socket!! Because without this server is freeze, while download several large files + * at once from SD-CARD. (done on v2.4c) + * Add and debug f_open(&fs, ..)/??f_close(&fs, ..) to: + * http_process_handler_avr (here actually already implemented..) + * OK + add f_open(&fs, ..) in STATE_HTTP_RES_INPROC before + * f_close(&fs) add to and comment out in + * Works stable but download speed slow (~40-50kb/sec ~80kb/sec with SPI 4MHZ && _HTTPSERVER_DEBUG_ = ON), because on every download file for every transfer TCP-IP packet proceed sequence: f_open(&fs, ..)/f_lseek(&fs, /f_close(&fs, ..) + * OK 6) Optimize (5) - Add to <_st_http_socket> structure to avoid multiple re-open downloaded file + * Works faster: ~80kb/sec with SPI 4MHZ && _HTTPSERVER_DEBUG_ = ON, ~110kb/sec SPI 4MHZ && _HTTPSERVER_DEBUG_ = OFF, ~150kb/sec ~80kb/sec with SPI 8MHZ && _HTTPSERVER_DEBUG_ = OFF + * (done on v2.4d) + * + * (11) Try move all pages saved at from RAM to FLASH address space + * Example of flash data access look at: + * <01_m1284p_bb00_minimum_PSTR_webpage_test> + * <09_m1284p_WIZNET_simple_webserver> + * + * Success initial porting on 10/12/2018 - FREE RAM on webserver: 7936 bytes (From total 16kbytes)! + * NEED further optimization to AVR_RAM->AVR_FLASH point (damn Harvard architecture :( )! + * + * It works on AtMega1284p(16kbytes RAM), but need TODO finish (DONE on v2.3b 12/12/2018)!! + * + * TODO DONE: + * After v2.3 optimization: + * (+4kb HTTP Buffers READ-WRITE(with HTTPD_MAX_BUF_SIZE 2048 see )) : FREE RAM on webserver: 10372 bytes - much better! (RAM enough for AtMega1284/AtMega2560 ie. AVR with 8-16Kb RAM) + * (+1kb HTTP Buffers READ-WRITE(with HTTPD_MAX_BUF_SIZE 512 see )) : FREE RAM on webserver: 13444 bytes - awesome! (RAM enough for AtMega644/AtMega128 ie. AVR with 4Kb RAM) + * + * OK 1) Father optimization / (v2.3 12/12/2018) + * OK 2) Father optimization / (v2.3 12/12/2018) + * OK 3) Rename httpServer.*->httpServer_avr.*, httpParser.*->httpParser_avr.*, httpUtil.*->httpUtil_avr.* (v2.3b 12/12/2018) + * Actually made another way: rename parent folder to + * OK 4) Fix not correct showed value on (v2.2 12/12/2018) + * OK 5) Correct indentation in all <*.html> and <*.js> sources and repack it again in . (v2.2 12/12/2018) + * OK 6) Add to webserver (v2.1 12/12/2018) + also added binary files support in webserver via: , bin2hex_v2.py + * 7) Publish sources in my github, wiznetmuseim, avrfreaks etc.. (optional) + * + * (10) Try repeat example HTTPServer_LPC11E36_LPCXpresso on AVR Mega1284p (All pages still in RAM) + * Here used to WEB-server handle cgi-like requests, with AJAX + JSON + * Description here: + * http://wiznetmuseum.com/portfolio-items/w5500-evb-web-server/ + * + * To better undestand AJAX look here (actually here used AJAX + XHTML): + * https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/web-server-read-switch-using-AJAX/ + * https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/web-server-read-switch-automatically-using-AJAX/ + * https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/AJAX-read-switches-analog/ + * https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/SD-card-AJAX-web-server/ + * https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/SD-card-AJAX-XML-web-server/ + * https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/SD-card-gauge/ + * https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/SD-card-IO/ + * + * To online encode text file to C source use online utility (Text->Cpp): + * https://tomeko.net/online_tools/cpp_text_escape.php?lang=en + * add option (this is for good reading into browser, as source code) + * after that insert in any text editor and replace <\n"> sequence to <\n"\> (this is for recognize multiple string into C-source headers) + * + * For prepare binary data (some image data, like favicon.ico) use script. + * Example usage: + * >bin2hex_v2.py favicon.ico + * >out favicon_ico.h + * After that insert into end content from favicon.ico; + * Then use this resource in www server like (look in ): + * reg_httpServer_binContent_avr(PSTR("favicon.ico"),favicon_ico, (uint32_t)sizeof(favicon_ico)); // favicon.ico : webserver icon + * + * + * + * Also can use File->HEX (BIN2HEX) - for prepare images for example (bin2hex_v2.py BETTER SUIT for AVR!!): + * https://tomeko.net/online_tools/file_to_hex.php?lang=en + * + * (9) Simple webserver, based on code from: + * http://www.ermicro.com/blog/?p=1773 + * Article: Integrating Wiznet W5100, WIZ811MJ network module with Atmel AVR Microcontroller + * + * (3) Trying WIZNET5500 init with using official Wiznet ioLibrary_Driver + * working ping on static IP + * LED1 = ON when phy_link detected + * and loopback test on TCP-IP:5000 and UDP:3000 ports. + * use Hercules terminal utility to check network connection see: + * + * https://wizwiki.net/wiki/doku.php?id=osh:cookie:loopback_test + * https://www.hw-group.com/software/hercules-setup-utility + * + * + * Author of porting to AVR Mega: + * Ibragimov Maxim, Russia Togliatty ~10..12.2018 + */ + +//***********Prologue for fast WDT disable & and save reason of reset/power-up: END +uint8_t mcucsr_mirror __attribute__ ((section (".noinit"))); + +// This is for fast WDT disable & and save reason of reset/power-up +void get_mcusr(void) \ + __attribute__((naked)) \ + __attribute__((section(".init3"))); +void get_mcusr(void) +{ + mcucsr_mirror = MCUSR; + MCUSR = 0; + wdt_disable(); +} +//***********Prologue for fast WDT disable & and save reason of reset/power-up: END + + +//*********Program metrics +const char compile_date[] PROGMEM = __DATE__; // Mmm dd yyyy - Äàòà êîìïèëÿöèè +const char compile_time[] PROGMEM = __TIME__; // hh:mm:ss - Âðåìÿ êîìïèëÿöèè +const char str_prog_name[] PROGMEM = "\r\nAtMega1284p v2.4d Static IP HTTP_server SDCARD Pages WIZNET_5500 ETHERNET 19/12/2018\r\n"; // Program name + +/* + * m1284p minimum template, with one button & one led + */ + +//M644P/M1284p Users LEDS: +//LED1/PORTC.4- m644p/m1284p maxxir +#define led1_conf() DDRC |= (1< 9 ) + { + //Here every 10ms + fatfs_10ms = 0; + //Timer++; /* Performance counter for this module (for FatFS test) */ + disk_timerproc(); // FAT FS timing func + } +} + +inline unsigned long millis(void) +{ + unsigned long i; + cli(); + // Atomic tick reading + i = _millis; + sei(); + return i; +} +//******************* MILLIS ENGINE: END + +//***************** UART0: BEGIN +// Assign I/O stream to UART +/* define CPU frequency in Mhz here if not defined in Makefile */ +//#ifndef F_CPU +//#define F_CPU 16000000UL +//#endif + +/* 19200 baud */ +//#define UART_BAUD_RATE 19200 +//#define UART_BAUD_RATE 38400 +#define UART_BAUD_RATE 115200 + +static int uart0_putchar(char ch,FILE *stream); +static void uart0_rx_flash(void); + +static FILE uart0_stdout = FDEV_SETUP_STREAM(uart0_putchar, NULL, _FDEV_SETUP_WRITE); +//PS. stdin íå ïåðåíàçíà÷àþ, ò.ê. óäîáíåå ñ íèì ðàáîòàòü ÷åðåç uart.h - api: + +/* + * Ò.å. íàïðèìåð òàê + c = uart1_getc(); + if (( c & UART_NO_DATA ) == 0) + { + uart1_putc( (unsigned char)c ); + } + Ïðè ýòîì ÷åêàåì ÷òî áóôåð ïðèåìà íå ïóñò è îïðîñ èäåò íåáëîêèðóþùèé (+ ðàáîòàåì ÷åðåç UART RX RINGBUFFER), + à åñëè ðàáîòàåì â ñòèëå stdin->getchar() òàì îïðîñ áëîêèðóåòñÿ ïîêà ñèìâîë íå áóäåò ïðèíÿò (ïîëëèíã) + ÷åðåç UART1_RX, ò.å. íåóäîáíî. + */ + +// STDOUT UART0 TX handler +static int uart0_putchar(char ch,FILE *stream) +{ + uart_putc(ch); + return 0; +} + +// Î÷èùàåì áóôåð ïðèåìà UART1 RX (èíîãäà íóæíî) +static void uart0_rx_flash(void) +{ + // Ñ÷èòûâàåì âñå èç ring-buffer UART1 RX + unsigned int c; + do + { + c = uart_getc(); + } while (( c & UART_NO_DATA ) == 0); // Check RX1 none-empty + +} +//***************** UART0: END + +//***************** ADC: BEGIN + +#ifndef ADC_DIV +//12.5MHz or over use this ADC reference clock +#define ADC_DIV (1<> 9) + 1980, (_Finfo.fdate >> 5) & 15, _Finfo.fdate & 31, + (_Finfo.ftime >> 11), (_Finfo.ftime >> 5) & 63, + _Finfo.fsize, &(_Finfo.fname[0])); +#if _USE_LFN + for (p2 = strlen(_Finfo.fname); p2 < 14; p2++) + xputc(' '); + xprintf(PSTR("%s\r\n"), Lfname); +#else + PRINTF("\r\n"); +#endif + } + f_closedir(&Dir); +} + +void fatfs_head_file(const char * fn) +{ + FRESULT f_err_code; + FIL fil_obj; + //trying to open and read file.. + f_chdir("/"); + f_err_code=f_open(&fil_obj, fn,FA_READ); //Open *fn - for reading + if(f_err_code==0) + { + DWORD file_len = fil_obj.fsize; + UINT br; + uint8_t _buf[128] = {0, }; + PRINTF("++Content <%s> = %lu bytes found on SDCARD\r\n", fn, file_len); + PRINTF("++Trying to read head file..\r\n"); + f_err_code = f_read(&fil_obj,&_buf[0], 128, &br); + if(f_err_code == 0) + { + if(br < 128) + _buf[br] = 0x0; + else + _buf[127] = 0x0; + PRINTF ("OK\r\n"); + PRINTF("text contents reading %u bytes:\r\n", br); + PRINTF("%s", _buf); + } + else + { + PRINTF ("ERROR "); + put_rc(f_err_code); + PRINTF("But anyway text contents:\r\n"); + PRINTF("%s", _buf); + } + f_close(&fil_obj); + } + else + { + PRINTF ("ERROR opening file <%s> ", fn); + put_rc(f_err_code); + } +} + +void fatfs_init(void) +{ + if( disk_status (0) == STA_NOINIT ) // Initialise the SD Card here, before we do anything else. + { + if( disk_initialize (0) ) // If it didn't initialise, or the card is write protected, try again. + { + if( disk_initialize (0) ) // If it didn't initialise, or the card is write protected, then call it out. + { + PRINTF("\r\nSDCard initialization failed..!\r\nPlease power cycle the SDCard.\r\nCheck write protect.\r\n"); + PRINTF("\r\nReboot the Board"); + while(1) + { + _delay_ms(1000); + PRINTF("."); + } + } + else + { + PRINTF("\r\nSDCard initialization OK\r\n"); + } + } + else + { + PRINTF("\r\nSDCard initialization OK\r\n"); + } + PRINTF(">>FS MOUNT "); + put_rc(f_mount(&Fatfs, (const TCHAR *)"", 1)); + PRINTF(">>GO ROOT DIRECTORY "); + put_rc(f_chdir((const TCHAR *)"/") ); + + PRINTF ("\r\n\r\nSD-Card root file list:\r\n"); + PRINTF ("===============================================\r\n"); + ls_dir("/"); + PRINTF ("===============================================\r\n\r\n"); + + } +} + +// Blocking (~3.5sec) receive one symbol from uart +/* +char uart0_receive(void) +{ + unsigned int c; + uint32_t wait_start = millis(); + do + { + wdt_reset(); + c = uart_getc(); + if (( c & UART_NO_DATA ) == 0) + { + uart_putc( (unsigned char)c ); + return (char)c ; + } + //After 3.5 sec waiting return with no symbol + if((millis()-wait_start) > 3500) + { + return 0; + } + } + while(( c & UART_NO_DATA )); + return 0; +} +*/ + + +//****************************FAT FS initialize: END + +int main() +{ + uint8_t prev_sw1 = 1; // VAR for sw1 pressing detect + + // INIT MCU + avr_init(); + spi_init(); //SPI Master, MODE0, 4Mhz(DIV4), CS_PB.3=HIGH - suitable for WIZNET 5x00(1/2/5) + + + // Print program metrics + PRINTF("%S", str_prog_name);// Íàçâàíèå ïðîãðàììû + PRINTF("Compiled at: %S %S\r\n", compile_time, compile_date);// Âðåìÿ Äàòà êîìïèëÿöèè + PRINTF(">> MCU is: %S; CLK is: %luHz\r\n", str_mcu, F_CPU);// MCU Name && FREQ + PRINTF(">> Free RAM is: %d bytes\r\n", freeRam()); + + //Short Blink LED 3 times on startup + unsigned char i = 3; + while(i--) + { + led1_high(); + _delay_ms(100); + led1_low(); + _delay_ms(400); + wdt_reset(); + } + + + //FAT_FS init and quick test(root directory list && print out head index.htm) + fatfs_init(); + fatfs_head_file("index.htm"); + + //Wizchip WIZ5500 Ethernet initialize + IO_LIBRARY_Init(); //After that ping must working + print_network_information(); + +//**************************************HTTPD init: BEGIN + /* HTTP Server Initialization */ + httpServer_init(TX_BUF, RX_BUF, MAX_HTTPSOCK, socknumlist); // Tx/Rx buffers (1kB) / The number of W5500 chip H/W sockets in use + //reg_httpServer_cbfunc(NVIC_SystemReset, NULL); // Callback: NXP MCU Reset + reg_httpServer_cbfunc(NULL, NULL); // Callback: Still not used here ARV System reset, AVR WDT reset + //In this demo all www content saved onto SD-Card (you must copy all from folder to ROOT SD-Card) +//**************************************HTTPD init: END + + /* Loopback Test: TCP Server and UDP */ + // Test for Ethernet data transfer validation + //uint32_t timer_link_1sec = millis(); + uint32_t timer_httpd_1sec = millis(); + bool run_user_applications = true; + while(1) + { + //Here at least every 1sec + wdt_reset(); // WDT reset at least every sec + + /* HTTPD */ + /*HTTPD timer 1 sec interval tick*/ + if((millis()-timer_httpd_1sec)> 1000) + { + //here every 1 sec + timer_httpd_1sec = millis(); + //////////////////////////////////////////////////////// + // SHOULD BE Added HTTP Server Time Handler to your 1s tick timer + httpServer_time_handler(); // for HTTP server time counter + //////////////////////////////////////////////////////// + //Printout RAM usage every 1 minute + static uint16_t j_ram = 0; + if(j_ram++%60 == 0) + { + PRINTF(">> Free RAM is: %d bytes\r\n", freeRam()); + } + } + + // TODO: insert user's code here + if(run_user_applications) + { + //for(i = 0; i < MAX_HTTPSOCK; i++) httpServer_run(i); // HTTP Server handler + for(i = 0; i < MAX_HTTPSOCK; i++) httpServer_run_avr(i); // HTTP Server handler avr optimized + + //loopback_tcps(SOCK_TCPS, RX_BUF, 5000); //not used here + + } // End of user's code + + //Use Hercules Terminal to check loopback tcp:5000 and udp:3000 + /* + * https://www.hw-group.com/software/hercules-setup-utility + * */ + //loopback_tcps(0,ethBuf0,5000); + //loopback_udps(1, ethBuf1, 3000); + + //Use WEBbrowser to connect to webserver: http://192.168.0.199/index.html + //websrv_simple(2, ethBuf2_WEBSRV, 80); + + + //loopback_ret = loopback_tcpc(SOCK_TCPS, gDATABUF, destip, destport); + //if(loopback_ret < 0) printf("loopback ret: %ld\r\n", loopback_ret); // TCP Socket Error code + + //Not used here, because led1 handle via websrv + /* + if((millis()-timer_link_1sec)> 1000) + { + //here every 1 sec + timer_link_1sec = millis(); + if(wizphy_getphylink() == PHY_LINK_ON) + { + led1_high(); + } + else + { + led1_low(); + } + } + */ + + } + return 0; +} + +// Timer0 +// 1ms IRQ +// Used for millis() timing +void timer0_init(void) +{ + /* + * + * For M128 + TCCR0 = (1<250kHz:250-=>1kHz) + TIMSK |= 1<250kHz:250-=>1kHz) + TIMSK0 |= 1< + */ +/*-----------------------------------------------------------------------*/ +/* MMCv3/SDv1/SDv2 (in SPI mode) control module */ +/*-----------------------------------------------------------------------*/ +/* +/ Copyright (C) 2014, ChaN, all right reserved. +/ +/ * This software is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/-------------------------------------------------------------------------*/ + +#include +#include "diskio.h" + + +/* Port controls (Platform dependent) */ + +//!! M128 +//#define SCK 1 /* - Output: SPI Serial Clock (SCLK) - ATMEGA128 PORTB, PIN1 */ +//#define MOSI 2 /* - Output: SPI Master out - slave in (MOSI) - ATMEGA128 PORTB, PIN2 */ +//#define MISO 3 /* - Input: SPI Master in - slave out (MISO) - ATMEGA128 PORTB, PIN3 */ +//#define CSN 0 /*SPI - SS*/ +//#define SD_CS 6 /* PB.6 Output as CS*/ + +//!! ATMEGA644/1284 +#define SCK 7 /* - Output: SPI Serial Clock (SCLK) - ATMEGA644/1284 PORTB, PIN7 */ +#define MOSI 5 /* - Output: SPI Master out - slave in (MOSI) - ATMEGA644/1284 PORTB, PIN5 */ +#define MISO 6 /* - Input: SPI Master in - slave out (MISO) - ATMEGA644/1284 PORTB, PIN6 */ +#define CSN 4 /*SPI - SS*/ +//#define SD_CS 2 /* PB.2 Output as CS*/ +#define SD_CS 0 /* PB.0 Output as CS*/ + + +#define CS_LOW() PORTB &= ~(1< is the command sequense of CMD55-CMD */ + cmd &= 0x7F; + res = send_cmd(CMD55, 0); + if (res > 1) return res; + } + + /* Select the card and wait for ready except to stop multiple block read */ + if (cmd != CMD12) { + deselect(); + if (!select()) return 0xFF; + } + + /* Send command packet */ + xchg_spi(0x40 | cmd); /* Start + Command index */ + xchg_spi((BYTE)(arg >> 24)); /* Argument[31..24] */ + xchg_spi((BYTE)(arg >> 16)); /* Argument[23..16] */ + xchg_spi((BYTE)(arg >> 8)); /* Argument[15..8] */ + xchg_spi((BYTE)arg); /* Argument[7..0] */ + n = 0x01; /* Dummy CRC + Stop */ + if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) + Stop */ + if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) Stop */ + xchg_spi(n); + + /* Receive command response */ + if (cmd == CMD12) xchg_spi(0xFF); /* Skip a stuff byte when stop reading */ + n = 10; /* Wait for a valid response in timeout of 10 attempts */ + do + res = xchg_spi(0xFF); + while ((res & 0x80) && --n); + + return res; /* Return with the response value */ +} + + + +/*-------------------------------------------------------------------------- + + Public Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* Initialize Disk Drive */ +/*-----------------------------------------------------------------------*/ + +DSTATUS disk_initialize ( + BYTE pdrv /* Physical drive nmuber (0) */ +) +{ + BYTE n, cmd, ty, ocr[4]; + + + if (pdrv) return STA_NOINIT; /* Supports only single drive */ + power_off(); /* Turn off the socket power to reset the card */ + if (Stat & STA_NODISK) return Stat; /* No card in the socket */ + power_on(); /* Turn on the socket power */ + FCLK_SLOW(); + for (n = 10; n; n--) xchg_spi(0xFF); /* 80 dummy clocks */ + + ty = 0; + if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ + Timer1 = 100; /* Initialization timeout of 1000 msec */ + if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */ + for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get trailing return value of R7 resp */ + if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ + while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */ + if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ + for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); + ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */ + } + } + } else { /* SDv1 or MMCv3 */ + if (send_cmd(ACMD41, 0) <= 1) { + ty = CT_SD1; cmd = ACMD41; /* SDv1 */ + } else { + ty = CT_MMC; cmd = CMD1; /* MMCv3 */ + } + while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */ + if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ + ty = 0; + } + } + CardType = ty; + deselect(); + + if (ty) { /* Initialization succeded */ + Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */ + FCLK_FAST(); + } else { /* Initialization failed */ + power_off(); + } + + return Stat; +} + + + +/*-----------------------------------------------------------------------*/ +/* Get Disk Status */ +/*-----------------------------------------------------------------------*/ + +DSTATUS disk_status ( + BYTE pdrv /* Physical drive nmuber (0) */ +) +{ + if (pdrv) return STA_NOINIT; /* Supports only single drive */ + return Stat; +} + + + +/*-----------------------------------------------------------------------*/ +/* Read Sector(s) */ +/*-----------------------------------------------------------------------*/ + +DRESULT disk_read ( + BYTE pdrv, /* Physical drive nmuber (0) */ + BYTE *buff, /* Pointer to the data buffer to store read data */ + DWORD sector, /* Start sector number (LBA) */ + UINT count /* Sector count (1..128) */ +) +{ + BYTE cmd; + + + if (pdrv || !count) return RES_PARERR; + if (Stat & STA_NOINIT) return RES_NOTRDY; + + if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ + + cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */ + if (send_cmd(cmd, sector) == 0) { + do { + if (!rcvr_datablock(buff, 512)) break; + buff += 512; + } while (--count); + if (cmd == CMD18) send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ + } + deselect(); + + return count ? RES_ERROR : RES_OK; +} + + + +/*-----------------------------------------------------------------------*/ +/* Write Sector(s) */ +/*-----------------------------------------------------------------------*/ + +#if _USE_WRITE +DRESULT disk_write ( + BYTE pdrv, /* Physical drive nmuber (0) */ + const BYTE *buff, /* Pointer to the data to be written */ + DWORD sector, /* Start sector number (LBA) */ + UINT count /* Sector count (1..128) */ +) +{ + if (pdrv || !count) return RES_PARERR; + if (Stat & STA_NOINIT) return RES_NOTRDY; + if (Stat & STA_PROTECT) return RES_WRPRT; + + if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ + + if (count == 1) { /* Single block write */ + if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */ + && xmit_datablock(buff, 0xFE)) + count = 0; + } + else { /* Multiple block write */ + if (CardType & CT_SDC) send_cmd(ACMD23, count); + if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */ + do { + if (!xmit_datablock(buff, 0xFC)) break; + buff += 512; + } while (--count); + if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */ + count = 1; + } + } + deselect(); + + return count ? RES_ERROR : RES_OK; +} +#endif + + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous Functions */ +/*-----------------------------------------------------------------------*/ + +#if _USE_IOCTL +DRESULT disk_ioctl ( + BYTE pdrv, /* Physical drive nmuber (0) */ + BYTE cmd, /* Control code */ + void *buff /* Buffer to send/receive control data */ +) +{ + DRESULT res; + BYTE n, csd[16], *ptr = buff; + DWORD csize; + + + if (pdrv) return RES_PARERR; + + res = RES_ERROR; + + if (Stat & STA_NOINIT) return RES_NOTRDY; + + switch (cmd) { + case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */ + if (select()) res = RES_OK; + break; + + case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ + if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { + if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ + csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1; + *(DWORD*)buff = csize << 10; + } else { /* SDC ver 1.XX or MMC*/ + n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; + csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; + *(DWORD*)buff = csize << (n - 9); + } + res = RES_OK; + } + break; + + case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ + if (CardType & CT_SD2) { /* SDv2? */ + if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */ + xchg_spi(0xFF); + if (rcvr_datablock(csd, 16)) { /* Read partial block */ + for (n = 64 - 16; n; n--) xchg_spi(0xFF); /* Purge trailing data */ + *(DWORD*)buff = 16UL << (csd[10] >> 4); + res = RES_OK; + } + } + } else { /* SDv1 or MMCv3 */ + if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */ + if (CardType & CT_SD1) { /* SDv1 */ + *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1); + } else { /* MMCv3 */ + *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1); + } + res = RES_OK; + } + } + break; + + /* Following commands are never used by FatFs module */ + + case MMC_GET_TYPE : /* Get card type flags (1 byte) */ + *ptr = CardType; + res = RES_OK; + break; + + case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */ + if (send_cmd(CMD9, 0) == 0 /* READ_CSD */ + && rcvr_datablock(ptr, 16)) + res = RES_OK; + break; + + case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */ + if (send_cmd(CMD10, 0) == 0 /* READ_CID */ + && rcvr_datablock(ptr, 16)) + res = RES_OK; + break; + + case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */ + if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */ + for (n = 4; n; n--) *ptr++ = xchg_spi(0xFF); + res = RES_OK; + } + break; + + case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */ + if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */ + xchg_spi(0xFF); + if (rcvr_datablock(ptr, 64)) + res = RES_OK; + } + break; + + case CTRL_POWER_OFF : /* Power off */ + power_off(); + Stat |= STA_NOINIT; + res = RES_OK; + break; + + default: + res = RES_PARERR; + } + + deselect(); + + return res; +} +#endif + + +/*-----------------------------------------------------------------------*/ +/* Device Timer Interrupt Procedure */ +/*-----------------------------------------------------------------------*/ +/* This function must be called in period of 10ms */ + +void disk_timerproc (void) +{ + BYTE n, s; + + + n = Timer1; /* 100Hz decrement timer */ + if (n) Timer1 = --n; + n = Timer2; + if (n) Timer2 = --n; + + s = Stat; + + if (MMC_WP) /* Write protected */ + s |= STA_PROTECT; + else /* Write enabled */ + s &= ~STA_PROTECT; + + if (MMC_CD) /* Card inserted */ + s &= ~STA_NODISK; + else /* Socket empty */ + s |= (STA_NODISK | STA_NOINIT); + + Stat = s; /* Update MMC status */ +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/spi.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/spi.c new file mode 100644 index 0000000..dfed60f --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/spi.c @@ -0,0 +1,31 @@ +#include +#include "spi.h" + +/* + * Initialize SPI bus. + */ + +void +spi_init(void) +{ + // CS PIN for WIZNET ETHERNET + DDRB |= _BV(WIZNET_CS); // CS to OUT && Disable + SPI_WIZNET_DISABLE(); + + // CS PIN for SDCARD + DDRB |= _BV(SD_CS); // CS to OUT && Disable + SPI_SD_DISABLE(); + + + /* Initalize ports for communication with SPI units. */ + /* CSN=SS and must be output when master! */ + DDRB |= _BV(MOSI) | _BV(SCK) | _BV(CSN); + PORTB |= _BV(MOSI) | _BV(SCK); + + /* Enables SPI, selects "master", clock rate FCK / 4 - 4Mhz, and SPI mode 0 */ + SPCR = _BV(SPE) | _BV(MSTR); + SPSR = 0x0; + //SPSR = _BV(SPI2X); //FCK / 2 - 8Mhz + + +} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/spi.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/spi.h new file mode 100644 index 0000000..7c1da0e --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/spi.h @@ -0,0 +1,92 @@ +#ifndef SPI_H_ +#define SPI_H_ + +/* SPI input/output registers. */ +#define SPI_TXBUF SPDR +#define SPI_RXBUF SPDR + +#define BV(bitno) _BV(bitno) + +#define SPI_WAITFOREOTx() do { while (!(SPSR & BV(SPIF))); } while (0) +#define SPI_WAITFOREORx() do { while (!(SPSR & BV(SPIF))); } while (0) + +//M128 +//#define SCK 1 /* - Output: SPI Serial Clock (SCLK) - ATMEGA128 PORTB, PIN1 */ +//#define MOSI 2 /* - Output: SPI Master out - slave in (MOSI) - ATMEGA128 PORTB, PIN2 */ +//#define MISO 3 /* - Input: SPI Master in - slave out (MISO) - ATMEGA128 PORTB, PIN3 */ +//#define CSN 0 /*SPI - SS*/ +//#define FLASH_CS 6 /* PB.6 Output as CS*/ + +//M644p/M1284p +#define SCK 7 /* - Output: SPI Serial Clock (SCLK) - ATMEGA644/1284 PORTB, PIN7 */ +#define MOSI 5 /* - Output: SPI Master out - slave in (MOSI) - ATMEGA644/1284 PORTB, PIN5 */ +#define MISO 6 /* - Input: SPI Master in - slave out (MISO) - ATMEGA644/1284 PORTB, PIN6 */ +#define CSN 4 /*SPI - SS*/ + +//#define FLASH_CS 3 /* PB.2 Output as CS*/ +//#define FLASH_CS 2 /* PB.2 Output as CS*/ +//#define CAN_CS 1 /* PB.1 Output as CS for CAN MCP2515*/ + +//#define SPI_FLASH_ENABLE() ( PORTB &= ~BV(FLASH_CS) ) +//#define SPI_FLASH_DISABLE() ( PORTB |= BV(FLASH_CS) ) + +#define WIZNET_CS 3 /* PB.3 Output as CS for Wiznet ETHERNET*/ +#define SPI_WIZNET_ENABLE() ( PORTB &= ~BV(WIZNET_CS) ) +#define SPI_WIZNET_DISABLE() ( PORTB |= BV(WIZNET_CS) ) + +#define SD_CS 0 /* PB.0 Output as CS for SD-reader*/ +#define SPI_SD_ENABLE() ( PORTB &= ~BV(SD_CS) ) +#define SPI_SD_DISABLE() ( PORTB |= BV(SD_CS) ) + + + + +/* Define macros to use for checking SPI transmission status depending + on if it is possible to wait for TX buffer ready. This is possible + on for example MSP430 but not on AVR. */ +#ifdef SPI_WAITFORTxREADY +#define SPI_WAITFORTx_BEFORE() SPI_WAITFORTxREADY() +#define SPI_WAITFORTx_AFTER() +#define SPI_WAITFORTx_ENDED() SPI_WAITFOREOTx() +#else /* SPI_WAITFORTxREADY */ +#define SPI_WAITFORTx_BEFORE() +#define SPI_WAITFORTx_AFTER() SPI_WAITFOREOTx() +#define SPI_WAITFORTx_ENDED() +#endif /* SPI_WAITFORTxREADY */ + +void spi_init(void); + +/* Write one character to SPI */ +#define SPI_WRITE(data) \ + do { \ + SPI_WAITFORTx_BEFORE(); \ + SPI_TXBUF = data; \ + SPI_WAITFOREOTx(); \ + } while(0) + +/* Write one character to SPI - will not wait for end + useful for multiple writes with wait after final */ +#define SPI_WRITE_FAST(data) \ + do { \ + SPI_WAITFORTx_BEFORE(); \ + SPI_TXBUF = data; \ + SPI_WAITFORTx_AFTER(); \ + } while(0) + +/* Read one character from SPI */ +#define SPI_READ(data) \ + do { \ + SPI_TXBUF = 0; \ + SPI_WAITFOREORx(); \ + data = SPI_RXBUF; \ + } while(0) + +/* Flush the SPI read register */ +#ifndef SPI_FLUSH +#define SPI_FLUSH() \ + do { \ + SPI_RXBUF; \ + } while(0); +#endif + +#endif /* SPI_H_ */ diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/uart_extd.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/uart_extd.c new file mode 100644 index 0000000..f4ad484 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/uart_extd.c @@ -0,0 +1,706 @@ +/* + * Modified for different BUFFER_SIZE for UART0 && UART1 + * see below: UART0_RX_BUFFER_SIZE/UART1_RX_BUFFER_SIZE && UART0_TX_BUFFER_SIZE/UART1_TX_BUFFER_SIZE + * Ibragimov M. 7/03/2015 +*/ +/************************************************************************* +Title: Interrupt UART library with receive/transmit circular buffers +Author: Peter Fleury http://jump.to/fleury +File: $Id: uart.c,v 1.12 2014/01/08 21:58:12 peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher +Hardware: any AVR with built-in UART, +License: GNU General Public License + +DESCRIPTION: + An interrupt is generated when the UART has finished transmitting or + receiving a byte. The interrupt handling routines use circular buffers + for buffering received and transmitted data. + + The UART0[1]_RX_BUFFER_SIZE and UART0[1]_TX_BUFFER_SIZE variables define + the buffer size in bytes. Note that these variables must be a + power of 2. + +USAGE: + Refere to the header file uart.h for a description of the routines. + See also example test_uart.c. + +NOTES: + Based on Atmel Application Note AVR306 + +LICENSE: + Copyright (C) 2006 Peter Fleury + + 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 + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*************************************************************************/ +#include +#include +#include +#include "uart_extd.h" + + +/* + * constants and macros + */ + +/* size of RX0/TX0 buffers */ +#define UART0_RX_BUFFER_MASK ( UART0_RX_BUFFER_SIZE - 1) +#define UART0_TX_BUFFER_MASK ( UART0_TX_BUFFER_SIZE - 1) + +#if ( UART0_RX_BUFFER_SIZE & UART0_RX_BUFFER_MASK ) +#error RX0 buffer size is not a power of 2 +#endif +#if ( UART0_TX_BUFFER_SIZE & UART0_TX_BUFFER_MASK ) +#error TX0 buffer size is not a power of 2 +#endif + +/* size of RX1/TX1 buffers */ +#define UART1_RX_BUFFER_MASK ( UART1_RX_BUFFER_SIZE - 1) +#define UART1_TX_BUFFER_MASK ( UART1_TX_BUFFER_SIZE - 1) + +#if ( UART1_RX_BUFFER_SIZE & UART1_RX_BUFFER_MASK ) +#error RX1 buffer size is not a power of 2 +#endif +#if ( UART1_TX_BUFFER_SIZE & UART1_TX_BUFFER_MASK ) +#error TX1 buffer size is not a power of 2 +#endif + + +#if defined(__AVR_AT90S2313__) \ + || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \ + || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \ + || defined(__AVR_ATmega103__) + /* old AVR classic or ATmega103 with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT UART_RX_vect + #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect + #define UART0_STATUS USR + #define UART0_CONTROL UCR + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__) + /* old AVR classic with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT UART_RX_vect + #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ + || defined(__AVR_ATmega323__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART_RXC_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined (__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega163__) + /* ATmega163 with one UART */ + #define ATMEGA_UART + #define UART0_RECEIVE_INTERRUPT UART_RX_vect + #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega162__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RXC_vect + #define UART1_RECEIVE_INTERRUPT USART1_RXC_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART1_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega161__) + /* ATmega with UART */ + #error "AVR ATmega161 currently not supported by this libaray !" +#elif defined(__AVR_ATmega169__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) \ + || defined(__AVR_ATmega3250__) || defined(__AVR_ATmega3290__) ||defined(__AVR_ATmega6450__) || defined(__AVR_ATmega6490__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT USART_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATtiny2313__) + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega329__) || \ + defined(__AVR_ATmega649__) || \ + defined(__AVR_ATmega325__) || \ + defined(__AVR_ATmega645__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega640__) +/* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART1_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega644__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART1_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1287__) + /* AT90USBxx with one USART */ + #define AT90USB_USART + #define UART0_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR1A + #define UART0_CONTROL UCSR1B + #define UART0_DATA UDR1 + #define UART0_UDRIE UDRIE1 +#else + #error "no UART definition for MCU available" +#endif + + +/* + * module global variables + */ +static volatile unsigned char UART_TxBuf[UART0_TX_BUFFER_SIZE]; +static volatile unsigned char UART_RxBuf[UART0_RX_BUFFER_SIZE]; +static volatile unsigned char UART_TxHead; +static volatile unsigned char UART_TxTail; +static volatile unsigned char UART_RxHead; +static volatile unsigned char UART_RxTail; +static volatile unsigned char UART_LastRxError; + +#if defined( ATMEGA_USART1 ) +static volatile unsigned char UART1_TxBuf[UART1_TX_BUFFER_SIZE]; +static volatile unsigned char UART1_RxBuf[UART1_RX_BUFFER_SIZE]; +static volatile unsigned char UART1_TxHead; +static volatile unsigned char UART1_TxTail; +static volatile unsigned char UART1_RxHead; +static volatile unsigned char UART1_RxTail; +static volatile unsigned char UART1_LastRxError; +#endif + + + +ISR (UART0_RECEIVE_INTERRUPT) +/************************************************************************* +Function: UART Receive Complete interrupt +Purpose: called when the UART has received a character +**************************************************************************/ +{ + unsigned char tmphead; + unsigned char data; + unsigned char usr; + unsigned char lastRxError; + + + /* read UART status register and UART data register */ + usr = UART0_STATUS; + data = UART0_DATA; + + /* */ +#if defined( AT90_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART0 ) + lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); +#elif defined ( ATMEGA_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( AT90USB_USART ) + lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) ); +#endif + + /* calculate buffer index */ + tmphead = ( UART_RxHead + 1) & UART0_RX_BUFFER_MASK; + + if ( tmphead == UART_RxTail ) { + /* error: receive buffer overflow */ + lastRxError = UART_BUFFER_OVERFLOW >> 8; + }else{ + /* store new index */ + UART_RxHead = tmphead; + /* store received data in buffer */ + UART_RxBuf[tmphead] = data; + } + UART_LastRxError |= lastRxError; +} + + +ISR (UART0_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART Data Register Empty interrupt +Purpose: called when the UART is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART_TxHead != UART_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART_TxTail + 1) & UART0_TX_BUFFER_MASK; + UART_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART0_CONTROL &= ~_BV(UART0_UDRIE); + } +} + + +/************************************************************************* +Function: uart_init() +Purpose: initialize UART and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart_init(unsigned int baudrate) +{ + UART_TxHead = 0; + UART_TxTail = 0; + UART_RxHead = 0; + UART_RxTail = 0; + +#if defined( AT90_UART ) + /* set baud rate */ + UBRR = (unsigned char)baudrate; + + /* enable UART receiver and transmmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN); + +#elif defined (ATMEGA_USART) + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART0_STATUS = (1<>8); + UBRRL = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<>8); + UBRR0L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE0)|(1<>8); + UBRR = (unsigned char) baudrate; + + /* Enable UART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<>8); + UBRR1L = (unsigned char) baudrate; + + /* Enable UART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE1)|(1<> 8; + }else{ + /* store new index */ + UART1_RxHead = tmphead; + /* store received data in buffer */ + UART1_RxBuf[tmphead] = data; + } + UART1_LastRxError |= lastRxError; +} + + +ISR(UART1_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART1 Data Register Empty interrupt +Purpose: called when the UART1 is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART1_TxHead != UART1_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART1_TxTail + 1) & UART1_TX_BUFFER_MASK; + UART1_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART1_CONTROL &= ~_BV(UART1_UDRIE); + } +} + + +/************************************************************************* +Function: uart1_init() +Purpose: initialize UART1 and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart1_init(unsigned int baudrate) +{ + UART1_TxHead = 0; + UART1_TxTail = 0; + UART1_RxHead = 0; + UART1_RxTail = 0; + + + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART1_STATUS = (1<>8); + UBRR1L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART1_CONTROL = _BV(RXCIE1)|(1< http://jump.to/fleury +File: $Id: uart.h,v 1.12 2012/11/19 19:52:27 peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4 +Hardware: any AVR with built-in UART, tested on AT90S8515 & ATmega8 at 4 Mhz +License: GNU General Public License +Usage: see Doxygen manual + +LICENSE: + Copyright (C) 2006 Peter Fleury + + 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 + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +************************************************************************/ + +/** + * @defgroup pfleury_uart UART Library + * @code #include @endcode + * + * @brief Interrupt UART library using the built-in UART with transmit and receive circular buffers. + * + * This library can be used to transmit and receive data through the built in UART. + * + * An interrupt is generated when the UART has finished transmitting or + * receiving a byte. The interrupt handling routines use circular buffers + * for buffering received and transmitted data. + * + * The UART0[1]_RX_BUFFER_SIZE and UART0[1]_TX_BUFFER_SIZE constants define + * the size of the circular buffers in bytes. Note that these constants must be a power of 2. + * You may need to adapt this constants to your target and your application by adding + * CDEFS += -DUART0[1]_RX_BUFFER_SIZE=nn -DUART0[1]_RX_BUFFER_SIZE=nn to your Makefile. + * + * @note Based on Atmel Application Note AVR306 + * @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + */ + +/**@{*/ + + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 +#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" +#endif + + +/* +** constants and macros +*/ + +/** @brief UART Baudrate Expression + * @param xtalcpu system clock in Mhz, e.g. 4000000UL for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT(baudRate,xtalCpu) (((xtalCpu) + 8UL * (baudRate)) / (16UL * (baudRate)) -1UL) + +/** @brief UART Baudrate Expression for ATmega double speed mode + * @param xtalcpu system clock in Mhz, e.g. 4000000UL for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) ( ((((xtalCpu) + 4UL * (baudRate)) / (8UL * (baudRate)) -1UL)) | 0x8000) + + +/** Size of the circular receive buffer UART0, must be power of 2 */ +#ifndef UART0_RX_BUFFER_SIZE +#define UART0_RX_BUFFER_SIZE 128 +#endif +/** Size of the circular transmit buffer UART0, must be power of 2 */ +#ifndef UART0_TX_BUFFER_SIZE +#define UART0_TX_BUFFER_SIZE 128 +#endif + +/** Size of the circular receive buffer UART1, must be power of 2 */ +#ifndef UART1_RX_BUFFER_SIZE +#define UART1_RX_BUFFER_SIZE 128 +#endif +/** Size of the circular transmit buffer UART1, must be power of 2 */ +#ifndef UART1_TX_BUFFER_SIZE +#define UART1_TX_BUFFER_SIZE 128 +#endif + +/* test if the size of the circular buffers fits into SRAM */ +#if ( (UART0_RX_BUFFER_SIZE+UART0_TX_BUFFER_SIZE+UART1_RX_BUFFER_SIZE+UART1_TX_BUFFER_SIZE) >= (RAMEND-0x60 ) ) +#error "size of UART0[1]_RX_BUFFER_SIZE + UART0[1]_TX_BUFFER_SIZE larger than size of SRAM" +#endif + +/* +** high byte error return code of uart_getc() +*/ +#define UART_FRAME_ERROR 0x1000 /* Framing Error by UART */ +#define UART_OVERRUN_ERROR 0x0800 /* Overrun condition by UART */ +#define UART_PARITY_ERROR 0x0400 /* Parity Error by UART */ +#define UART_BUFFER_OVERFLOW 0x0200 /* receive ringbuffer overflow */ +#define UART_NO_DATA 0x0100 /* no receive data available */ + + +/* +** function prototypes +*/ + +/** + @brief Initialize UART and set baudrate + @param baudrate Specify baudrate using macro UART_BAUD_SELECT() + @return none +*/ +extern void uart_init(unsigned int baudrate); + + +/** + * @brief Get received byte from ringbuffer + * + * Returns in the lower byte the received character and in the + * higher byte the last receive error. + * UART_NO_DATA is returned when no data is available. + * + * @param void + * @return lower byte: received byte from ringbuffer + * @return higher byte: last receive status + * - \b 0 successfully received data from UART + * - \b UART_NO_DATA + *
no receive data available + * - \b UART_BUFFER_OVERFLOW + *
Receive ringbuffer overflow. + * We are not reading the receive buffer fast enough, + * one or more received character have been dropped + * - \b UART_OVERRUN_ERROR + *
Overrun condition by UART. + * A character already present in the UART UDR register was + * not read by the interrupt handler before the next character arrived, + * one or more received characters have been dropped. + * - \b UART_FRAME_ERROR + *
Framing Error by UART + */ +extern unsigned int uart_getc(void); + + +/** + * @brief Put byte to ringbuffer for transmitting via UART + * @param data byte to be transmitted + * @return none + */ +extern void uart_putc(unsigned char data); + + +/** + * @brief Put string to ringbuffer for transmitting via UART + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s string to be transmitted + * @return none + */ +extern void uart_puts(const char *s ); + + +/** + * @brief Put string from program memory to ringbuffer for transmitting via UART. + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s program memory string to be transmitted + * @return none + * @see uart_puts_P + */ +extern void uart_puts_p(const char *s ); + +/** + * @brief Macro to automatically put a string constant into program memory + */ +#define uart_puts_P(__s) uart_puts_p(PSTR(__s)) + + + +/** @brief Initialize USART1 (only available on selected ATmegas) @see uart_init */ +extern void uart1_init(unsigned int baudrate); +/** @brief Get received byte of USART1 from ringbuffer. (only available on selected ATmega) @see uart_getc */ +extern unsigned int uart1_getc(void); +/** @brief Put byte to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_putc */ +extern void uart1_putc(unsigned char data); +/** @brief Put string to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts */ +extern void uart1_puts(const char *s ); +/** @brief Put string from program memory to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts_p */ +extern void uart1_puts_p(const char *s ); +/** @brief Macro to automatically put a string constant into program memory */ +#define uart1_puts_P(__s) uart1_puts_p(PSTR(__s)) + +/**@}*/ + + +#endif // UART_H + diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/userHandler.c b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/userHandler.c new file mode 100644 index 0000000..6d0e5d1 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/userHandler.c @@ -0,0 +1,327 @@ +/** + * @file userHandler.c + * @brief User Control Example + * @version 1.0 + * @date 2014/07/15 + * @par Revision + * 2014/07/15 - 1.0 Release + * @author + * \n\n @par Copyright (C) 1998 - 2014 WIZnet. All rights reserved. + */ + +#include +#include +#include +//#include "board.h" +#include "httpUtil.h" +#include "userHandler.h" +//#include "adcHandler.h" +#include "wizchip_conf.h" +#include "globals.h" + +/* Unavailable Pins (W5500-EVB component preempted) */ +// >> UART Rx/Tx : D0 (Rx), D1 (Tx) +// >> W5500 SPI(SPI0) : D11 (MOSI), D12 (MISO), D13 (SCK) + +/* On-board Devices */ +// >> Input : D14 (SW1) / D15 (SW2) +// >> Input : AIN (Potentiometer / TEMP.Sensor) +// >> Output : D8 (LED R) / D9 (LED G) / D10 (LED B) + +/* NXP LPC11Exx GPIO functions */ +// GPIO: Pin state +//Chip_GPIO_GetPinState(LPC_GPIO, dio_ports[pin], dio_pins[pin]); +//Chip_GPIO_SetPinState(LPC_GPIO, dio_ports[pin], dio_pins[pin], true); +//Chip_GPIO_SetPinState(LPC_GPIO, dio_ports[pin], dio_pins[pin], false); + +// GPIO: Pin direction +//Chip_GPIO_GetPinDIR((LPC_GPIO, dio_ports[pin], dio_pins[pin]); +//Chip_GPIO_SetPinDIROutput(LPC_GPIO, dio_ports[pin], dio_pins[pin]); +//Chip_GPIO_SetPinDIRInput(LPC_GPIO, dio_ports[pin], dio_pins[pin]); + +// Pre-defined Get CGI functions +//void make_json_dio(uint8_t * buf, uint16_t * len, uint8_t pin); +void make_json_ain(uint8_t * buf, uint16_t * len, uint8_t pin); +void make_json_netinfo(uint8_t * buf, uint16_t * len); +void make_json_led1(uint8_t * buf, uint16_t * len); +void make_info(uint8_t * buf, uint16_t * len); + +// Pre-defined Set CGI functions +int8_t set_diodir(uint8_t * uri); +int8_t set_diostate(uint8_t * uri); + +uint8_t predefined_get_cgi_processor(uint8_t * uri_name, uint8_t * buf, uint16_t * len) +{ + //return 0; //Just a stub, not used yet.. + //uint8_t ret = 1; // ret = 1 means 'uri_name' matched + uint8_t ret = 0; // ret = 0 means 'uri_name' not matched + uint8_t cgibuf[14] = {0, }; + int8_t cgi_dio = -1; + int8_t cgi_ain = -1; + + uint8_t i; + + if(strcmp_P((const char *)uri_name,PSTR("todo.cgi")) == 0) + { +// // to do +// ;//make_json_todo(buf, len); + } + else if(strcmp_P((const char *)uri_name,PSTR("get_netinfo.cgi")) == 0) + { + make_json_netinfo(buf, len); + ret = 1; // ret = 1 means 'uri_name' matched + } + else if(strcmp_P((const char *)uri_name,PSTR("get_led1.cgi")) == 0) + { + make_json_led1(buf, len); + ret = 1; // ret = 1 means 'uri_name' matched + } + else if(strcmp_P((const char *)uri_name,PSTR("get_info.cgi")) == 0) + { + make_info(buf, len); + ret = 1; // ret = 1 means 'uri_name' matched + } + else + { +// // get_dio0.cgi ~ get_dio15.cgi +// for(i = 0; i < DIOn; i++) +// { +// memset(cgibuf, 0x00, 14); +// sprintf((char *)cgibuf, "get_dio%d.cgi", i); +// if(strcmp((const char *)uri_name, (const char *)cgibuf) == 0) +// { +// make_json_dio(buf, len, i); +// cgi_dio = i; +// break; +// } +// } +// +// if(cgi_dio < 0) + //Analog Ins reading get_ain0.cgi ~ get_ain7.cgi + if(1) + { + // get_ain0.cgi ~ get_ain5.cgi (A0 - A5), get_ain6.cgi for on-board potentiometer / Temp.Sensor - LPC11Exx + //for(i = 0; i < AINn; i++) //for LPC11xx + for(i = 0; i < 8; i++) //for AVR Mega1284p, available AIN0..AIN7 + { + memset(cgibuf, 0x00, 14); + sprintf((char *)cgibuf, "get_ain%d.cgi", i); + if(strcmp((const char *)uri_name, (const char *)cgibuf) == 0) + { + make_json_ain(buf, len, i); + cgi_ain = i; + ret = 1; + break; + } + } + } + +// if((cgi_dio < 0) && (cgi_ain < 0)) ret = 0; + } + + return ret; +} + + +uint8_t predefined_set_cgi_processor(uint8_t * uri_name, uint8_t * uri, uint8_t * buf, uint16_t * len) +{ +// return 0; //Just a stub, not used yet.. + uint8_t ret = 0; // ret = 0 means 'uri_name' not matched +// uint8_t ret = 1; // ret = '1' means 'uri_name' matched + uint8_t val = 0; + + if(strcmp_P((const char *)uri_name,PSTR("todo.cgi")) == 0) + { + // to do + ;//val = todo(uri); + //*len = sprintf((char *)buf, "%d", val); + } +// // Digital I/O; dio_s, dio_d +// else if(strcmp_P((const char *)uri_name,PSTR("set_diodir.cgi")) == 0) +// { +// //val = set_diodir(uri); +// //printf_P(PSTR("+++set_diodir.cgi uri_name: %s; uri: %s;\r\n")); +// *len = sprintf_P((char *)buf, PSTR("%d"), val); +// ret = 1; +// } + else if(strcmp((const char *)uri_name, "set_diostate.cgi") == 0) + { + //When uri_name=set_diostate.cgi, and uri HTTP POST request which contains something like: + //pin=8&val=1; or pin=8&val=1; (look && ) + + /* + This is LPC11xx handler + val = set_diostate(uri); + len = sprintf((char *)buf, "%d", val); + len ret = 1; + */ + + + //!!Just for debug + PRINTF("\r\n+++set_diostate.cgi uri_name: %s\r\nuri: %s\r\n", uri_name, uri); + + //Parse URI (Very dirty!!) + if(strstr_P(uri,PSTR("pin=LED1&val=0"))) + { + led1_low(); + *len = sprintf_P((char *)buf, PSTR("LED1: OFF")); + ret = 1; + } + else if(strstr_P(uri,PSTR("pin=LED1&val=1"))) + { + led1_high(); + *len = sprintf_P((char *)buf, PSTR("LED1: ON")); + ret = 1; + } + else + { + //*len = sprintf_P((char *)buf, PSTR("%d"), -1); + *len = sprintf_P((char *)buf, PSTR("???")); + ret = 1; + } + } +// else +// { +// ret = 0; +// } +// + return ret; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Pre-defined Get CGI functions +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//void make_json_dio(uint8_t * buf, uint16_t * len, uint8_t pin) +//{ +// uint8_t pin_state = Chip_GPIO_GetPinState(LPC_GPIO, dio_ports[pin], dio_pins[pin]); +// uint8_t pin_dir = Chip_GPIO_GetPinDIR(LPC_GPIO, dio_ports[pin], dio_pins[pin]); +// +// *len = sprintf((char *)buf, "DioCallback({\"dio_p\":\"%d\",\ +// \"dio_s\":\"%d\",\ +// \"dio_d\":\"%d\"\ +// });", +// pin, // Digital io pin number +// pin_state, // Digital io status +// pin_dir // Digital io directions +// ); +//} +// +void make_json_led1(uint8_t * buf, uint16_t * len) +{ + if(led1_read()) + { + *len = sprintf_P((char *)buf,PSTR( "led1Callback({\"led1_txt\":\"LED1: ON\"});")); //Send back LED1 state via call-back function + } + else + { + *len = sprintf_P((char *)buf,PSTR( "led1Callback({\"led1_txt\":\"LED1: OFF\"});")); //Send back LED1 state via call-back function + } + +} + +void make_info(uint8_t * buf, uint16_t * len) +{ + /* + * Send program metrics: + * Program name + * time-date compile + * MCU info + * free ram info + * uptime device + */ + *len = sprintf_P((char *)buf,PSTR(\ + "
%S"\
+			"Compiled at: %S %S\r\n"\
+			"MCU is: %S; CLK is: %luHz\r\n"\
+			"Free RAM: %dbytes\r\n"\
+			"Uptime: %lusec\r\n
"),\ + str_prog_name,\ + compile_time, compile_date,\ + str_mcu, F_CPU,\ + freeRam(),\ + millis()/1000); +} + +void make_json_ain(uint8_t * buf, uint16_t * len, uint8_t pin) +{ + *len = sprintf_P((char *)buf,PSTR( "AinCallback({\"ain_p\":\"%d\",\ + \"ain_v\":\"%d\"\ + });"), + pin, // ADC input pin number + //get_ADC_val(pin) // ADC input value for LPC11xx + adc_read(pin) // ADC input value for AVR + ); +} + +void make_json_netinfo(uint8_t * buf, uint16_t * len) +{ + wiz_NetInfo netinfo; + ctlnetwork(CN_GET_NETINFO, (void*) &netinfo); + + // DHCP: 1 - Static, 2 - DHCP + *len = sprintf_P((char *)buf,PSTR( "NetinfoCallback({\"mac\":\"%.2X:%.2X:%.2X:%.2X:%.2X:%.2X\",\ + \"ip\":\"%d.%d.%d.%d\",\ + \"gw\":\"%d.%d.%d.%d\",\ + \"sn\":\"%d.%d.%d.%d\",\ + \"dns\":\"%d.%d.%d.%d\",\ + \"dhcp\":\"%d\"\ + });"), + netinfo.mac[0], netinfo.mac[1], netinfo.mac[2], netinfo.mac[3], netinfo.mac[4], netinfo.mac[5], + netinfo.ip[0], netinfo.ip[1], netinfo.ip[2], netinfo.ip[3], + netinfo.gw[0], netinfo.gw[1], netinfo.gw[2], netinfo.gw[3], + netinfo.sn[0], netinfo.sn[1], netinfo.sn[2], netinfo.sn[3], + netinfo.dns[0], netinfo.dns[1], netinfo.dns[2], netinfo.dns[3], + netinfo.dhcp + ); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Pre-defined Set CGI functions +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//int8_t set_diodir(uint8_t * uri) +//{ +// uint8_t * param; +// uint8_t pin = 0, val = 0; +// +// if((param = get_http_param_value((char *)uri, "pin"))) // GPIO; D0 ~ D15 +// { +// pin = (uint8_t)ATOI(param, 10); +// if(pin > 15) return -1; +// +// if((param = get_http_param_value((char *)uri, "val"))) // Direction; NotUsed/Input/Output +// { +// val = (uint8_t)ATOI(param, 10); +// if(val > Output) val = Output; +// } +// } +// +// if(val == Input) Chip_GPIO_SetPinDIRInput(LPC_GPIO, dio_ports[pin], dio_pins[pin]); // Input +// else Chip_GPIO_SetPinDIROutput(LPC_GPIO, dio_ports[pin], dio_pins[pin]); // Output +// +// return pin; +//} +// +//int8_t set_diostate(uint8_t * uri) +//{ +// uint8_t * param; +// uint8_t pin = 0, val = 0; +// +// if((param = get_http_param_value((char *)uri, "pin"))) // GPIO; D0 ~ D15 +// { +// pin = (uint8_t)ATOI(param, 10); +// if(pin > 15) return -1; +// +// if((param = get_http_param_value((char *)uri, "val"))) // State; high(on)/low(off) +// { +// val = (uint8_t)ATOI(param, 10); +// if(val > On) val = On; +// } +// +// if(val == On) Chip_GPIO_SetPinState(LPC_GPIO, dio_ports[pin], dio_pins[pin], true); // High +// else Chip_GPIO_SetPinState(LPC_GPIO, dio_ports[pin], dio_pins[pin], false); // Low +// } +// +// return pin; +//} diff --git a/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/userHandler.h b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/userHandler.h new file mode 100644 index 0000000..1f9af30 --- /dev/null +++ b/12_m1284p_WIZNET_HTTPServer_SDCARD_pages/userHandler.h @@ -0,0 +1,42 @@ +/** + * @file userHandler.h + * @brief Header File for User Control Example + * @version 1.0 + * @date 2014/07/15 + * @par Revision + * 2014/07/15 - 1.0 Release + * @author + * \n\n @par Copyright (C) 1998 - 2014 WIZnet. All rights reserved. + */ + +#ifndef __USERHANDLER_H +#define __USERHANDLER_H + +#include +//#define _WEB_DEBUG_ + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Public Functions +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// to do + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Pre-defined CGI Interface Functions Handler +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +uint8_t predefined_get_cgi_processor(uint8_t * uri_name, uint8_t * buf, uint16_t * len); +uint8_t predefined_set_cgi_processor(uint8_t * uri_name, uint8_t * uri, uint8_t * buf, uint16_t * len); + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// HTTP GET Method CGI Functions +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// to do + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// HTTP POST Method CGI Functions +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// to do + + +#endif +